├── protocol.proto ├── companion_reg.proto ├── adv.proto ├── README.md ├── LICENSE ├── mms_retry.proto ├── vesta.proto ├── vname_cert.proto ├── create-proto-repo.sh ├── proto_test.proto ├── cert.proto ├── biz.proto ├── backup.proto ├── server_sync.proto ├── wa5.proto ├── history_sync.proto ├── sync_action.proto ├── web.proto ├── google └── protobuf │ └── descriptor.proto └── e2e.proto /protocol.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | 3 | option java_package = "com.whatsapp.proto"; 4 | 5 | import "google/protobuf/descriptor.proto"; 6 | 7 | // FieldOptions to annotate our string fields that contain JIDs 8 | extend google.protobuf.FieldOptions { 9 | optional bool jid = 50000; 10 | } 11 | 12 | message MessageKey { 13 | optional string remote_jid = 1 [(jid) = true]; 14 | optional bool from_me = 2; 15 | optional string id = 3; 16 | optional string participant = 4 [(jid) = true]; // set this only if participant is part of the message key, ie. on iphone 17 | } 18 | -------------------------------------------------------------------------------- /companion_reg.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | 3 | option java_package = "com.whatsapp.proto"; 4 | 5 | message CompanionProps { 6 | enum PlatformType { 7 | UNKNOWN = 0; 8 | CHROME = 1; 9 | FIREFOX = 2; 10 | IE = 3; 11 | OPERA = 4; 12 | SAFARI = 5; 13 | EDGE = 6; 14 | DESKTOP = 7; 15 | IPAD = 8; 16 | ANDROID_TABLET = 9; 17 | // Portal devices 18 | OHANA = 10; 19 | ALOHA = 11; 20 | CATALINA = 12; 21 | TCL_TV = 13; 22 | } 23 | 24 | message AppVersion { 25 | optional uint32 primary = 1; 26 | optional uint32 secondary = 2; 27 | optional uint32 tertiary = 3; 28 | optional uint32 quaternary = 4; 29 | optional uint32 quinary = 5; 30 | } 31 | 32 | optional string os = 1; 33 | optional AppVersion version = 2; 34 | optional PlatformType platform_type = 3; 35 | optional bool require_full_sync = 4; 36 | } 37 | -------------------------------------------------------------------------------- /adv.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | 3 | option java_package = "com.whatsapp.proto"; 4 | 5 | message ADVKeyIndexList { 6 | optional uint32 raw_id = 1; 7 | optional uint64 timestamp = 2; 8 | optional uint32 current_index = 3; 9 | repeated uint32 valid_indexes = 4 [packed=true]; 10 | } 11 | 12 | message ADVSignedKeyIndexList { 13 | optional bytes details = 1; // encoded ADVKeyIndexList 14 | optional bytes account_signature = 2; 15 | } 16 | 17 | message ADVDeviceIdentity { 18 | optional uint32 raw_id = 1; 19 | optional uint64 timestamp = 2; 20 | optional uint32 key_index = 3; 21 | } 22 | 23 | message ADVSignedDeviceIdentity { 24 | optional bytes details = 1; // encoded ADVDeviceIdentity 25 | optional bytes account_signature_key = 2; 26 | optional bytes account_signature = 3; 27 | optional bytes device_signature = 4; 28 | } 29 | 30 | message ADVSignedDeviceIdentityHMAC { 31 | optional bytes details = 1; // encoded ADVSignedDeviceIdentity 32 | optional bytes hmac = 2; 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Whatsapp protocol definitions 2 | 3 | These `.proto` files were found in whatsapp .apk files from versions from 2.22.6.7 until 2.22.13.5. 4 | 5 | I think it was an accidental inclusion of these files by whatsapp. 6 | But interesting for research purposes none the less. 7 | 8 | I used the [create-proto-repo.sh](create-proto-repo.sh) script to create this repo from the .apk files. It takes care that the apk files are processed in the right order, and sets the commit timestamps according the the timestamps from the apk files. 9 | So you can see the development progress by whatsapp in it's protocol by looking at the git history. 10 | 11 | The apk files were downloaded from [https://apkcombo.com/](https://apkcombo.com/) 12 | 13 | # whatsmeow 14 | 15 | Another way of getting the whatsapp protocol files, is from the web.whatsapp.com site. 16 | By using [this](https://github.com/tulir/whatsmeow/tree/main/binary/proto/extract) method by [whatsmeow](https://github.com/tulir/whatsmeow/), (originally by [sigalor](https://github.com/sigalor/whatsapp-web-reveng)). 17 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Willem Hengeveld 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /mms_retry.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | 3 | option java_package = "com.whatsapp.proto"; 4 | 5 | message MediaRetryNotification { 6 | enum ResultType { 7 | // Upload error occurred or the stanza ID in the server-error receipt 8 | // stanza does not match the stanza ID in the server-error receipt 9 | // protobuf. 10 | // this is retriable for MD 11 | GENERAL_ERROR = 0; 12 | // Reupload was successful, direct path will be set 13 | SUCCESS = 1; 14 | // Referenced message or the media for that message is not found. 15 | // Value will be sent in an error child for the mediaretry notification 16 | // when the message cannot be found. 17 | // this is not retriable for MD 18 | NOT_FOUND = 2; 19 | // Failed to decrypt the server-error receipt payload 20 | // Value will be sent in an error child for the mediaretry notification 21 | // this is not retriable for MD 22 | DECRYPTION_ERROR = 3; 23 | } 24 | optional string stanza_id = 1; 25 | optional string direct_path = 2; 26 | optional ResultType result = 3; 27 | } 28 | 29 | message ServerErrorReceipt { 30 | optional string stanza_id = 1; 31 | } 32 | -------------------------------------------------------------------------------- /vesta.proto: -------------------------------------------------------------------------------- 1 | // Android copy of Vesta proto. Ground truth here: 2 | // - https://www.internalfb.com/code/fbsource/xplat/rust/vesta_client/proto/src/messages.proto 3 | package whatsapp; 4 | option java_package = "com.whatsapp.proto"; 5 | 6 | // Payload stored by successful registration (by `finish_register_request`). 7 | message RegistrationPayload { 8 | // The secret data to be protected by the HSM system. 9 | // Holds serialized `WaBackupKeyData` proto. 10 | optional bytes backup_key_data = 1; 11 | // OPAQUE protocol third registration message. 12 | optional bytes r3 = 2; 13 | // Registration nonce. 14 | // Deprecated and soon to be removed. Replaced by `transcript` (see protocol spec). 15 | optional bytes opaque_challenge = 3; 16 | // History of registration messages: `SHA256(R1, R2, opaque_challenge)` 17 | optional bytes transcript = 4; 18 | } 19 | 20 | // Payload returned on successful account login (by `finish_login_request`). 21 | message LoginPayload { 22 | // `backup_key_data` from `RegistrationPayload` AES-GCM-128 encrypted with 23 | // OPAQUE `shared_key`. 24 | optional bytes backup_key_data_encrypted = 1; 25 | // Nonce used for AES-GCM-128 encryption of `backup_key_data`. 26 | optional bytes rk_nonce = 2; 27 | } 28 | 29 | // WA-specific proto serialized to/from Vesta `backup_key_data` field. 30 | message WaBackupKeyData { 31 | // User's backup key AES-GCM-128 encrypted with OPAQUE export key. 32 | optional bytes aes_k = 1; 33 | // Nonce used to AES-GCM-128 encrypt `aes_k`. 34 | optional bytes k_nonce = 2; 35 | } 36 | -------------------------------------------------------------------------------- /vname_cert.proto: -------------------------------------------------------------------------------- 1 | // Uncomment syntax = "proto2"; for erlang protobuf code generator 2 | syntax = "proto2"; 3 | 4 | package whatsapp; 5 | 6 | option java_package = "com.whatsapp.proto"; 7 | 8 | message LocalizedName { 9 | optional string lg = 1; 10 | optional string lc = 2; 11 | optional string verified_name = 3; 12 | } 13 | 14 | message VerifiedNameCertificate { 15 | message Details { 16 | optional uint64 serial = 1; 17 | optional string issuer = 2; 18 | optional string verified_name = 4; 19 | repeated LocalizedName localized_names = 8; 20 | optional uint64 issue_time = 10; // for server use, do not modify on clients 21 | } 22 | 23 | // this set as bytes to match what we do in wa.proto 24 | optional bytes details = 1; 25 | optional bytes signature = 2; 26 | optional bytes server_signature = 3; // for server use, do not modify on clients 27 | } 28 | 29 | message BizAccountPayload { 30 | optional VerifiedNameCertificate vname_cert = 1; 31 | // biz_acct_link_info stores encrypted BizAccountLinkInfo as bytes. 32 | optional bytes biz_acct_link_info = 2; 33 | } 34 | 35 | message BizAccountLinkInfo { 36 | optional uint64 whatsapp_biz_acct_fbid = 1; 37 | optional string whatsapp_acct_number = 2; 38 | optional uint64 issue_time = 3; 39 | } 40 | 41 | message BizIdentityInfo { 42 | enum VerifiedLevelValue { 43 | unknown = 0; 44 | low = 1; 45 | high = 2; 46 | } 47 | // more details for vlevel(verified_level) in EntSchema https://fburl.com/diffusion/cgbffvib 48 | optional VerifiedLevelValue vlevel = 1; 49 | optional VerifiedNameCertificate vname_cert = 2; 50 | optional bool signed = 3; 51 | optional bool revoked = 4; 52 | } 53 | -------------------------------------------------------------------------------- /create-proto-repo.sh: -------------------------------------------------------------------------------- 1 | rm -rf .git 2 | git init 3 | files=(adv.proto backup.proto biz.proto cert.proto companion_reg.proto e2e.proto google/protobuf/descriptor.proto history_sync.proto mms_retry.proto proto_test.proto protocol.proto server_sync.proto sync_action.proto vesta.proto vname_cert.proto wa5.proto web.proto) 4 | versions=(2.22.6.7 2.22.6.8 2.22.6.9 2.22.6.10 2.22.6.70 2.22.6.71 2.22.6.72 2.22.6.73 2.22.7.1 2.22.7.2 2.22.7.4 2.22.7.6 2.22.7.8 2.22.7.10 2.22.7.11 2.22.7.13 2.22.7.72 2.22.7.74 2.22.8.1 2.22.8.3 2.22.8.4 2.22.8.5 2.22.8.6 2.22.8.7 2.22.8.8 2.22.8.9 2.22.8.10 2.22.8.11 2.22.8.78 2.22.9.7 2.22.9.8 2.22.9.10 2.22.9.11 2.22.9.12 2.22.9.13 2.22.9.14 2.22.9.77 2.22.9.78 2.22.10.2 2.22.10.3 2.22.10.6 2.22.10.7 2.22.10.8 2.22.10.9 2.22.10.10 2.22.10.11 2.22.10.12 2.22.10.14 2.22.10.73 2.22.11.3 2.22.11.4 2.22.11.6 2.22.11.7 2.22.11.8 2.22.11.10 2.22.11.11 2.22.11.12 2.22.11.13 2.22.11.14 2.22.11.70 2.22.11.75 2.22.11.78 2.22.11.82 2.22.11.83 2.22.11.16 2.22.12.3 2.22.12.4 2.22.12.5 2.22.12.6 2.22.12.7 2.22.12.8 2.22.12.9 2.22.12.10 2.22.12.11 2.22.12.14 2.22.12.73 2.22.12.75 2.22.12.76 2.22.13.4 2.22.13.5) 5 | 6 | rm -f "${files[@]}" 7 | for v in "${versions[@]}"; do 8 | for t in Messenger Business; do 9 | f="../dn/WhatsApp ${t}_${v}_apkcombo.com.apk" 10 | if [[ -e "$f" ]]; then 11 | unzip -o "$f" "${files[@]}" 12 | realfiles=($(ls "${files[@]}")) 13 | git add "${realfiles[@]}" 14 | timestamp=$(ls -dalt --full-time "${realfiles[@]}" | head -1 | perl -ne 'print $1 if (/^\S+\s+\d+\s\S+\s+\S+\s+\d+\s(\S+ \S+ \S+)/)') 15 | export GIT_COMMITTER_DATE=$timestamp 16 | git commit --date "$timestamp" -m "v${v}" "${realfiles[@]}" 17 | fi 18 | done 19 | done 20 | -------------------------------------------------------------------------------- /proto_test.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | option java_package = "com.whatsapp.proto"; 3 | option optimize_for = LITE_RUNTIME; 4 | 5 | message EnumValues { 6 | enum Planet { 7 | PLUTO = 1; 8 | MERCURY = 2; 9 | } 10 | 11 | enum Color { 12 | RED = 1; 13 | GREEN = 2; 14 | BLUE = 3; 15 | } 16 | optional Planet planet = 1; 17 | repeated Color colors = 2; 18 | } 19 | 20 | message NestedClasses { 21 | message Universe { 22 | message SolarSystem { 23 | message Earth { 24 | optional string country = 1; 25 | } 26 | repeated Earth earth = 1; 27 | } 28 | optional SolarSystem solarSystem = 1; 29 | } 30 | optional Universe universe = 1; 31 | } 32 | 33 | message NonRepeatedValues { 34 | optional bool bool_value = 1; 35 | optional double double_value = 2; 36 | optional string string_value = 3; 37 | optional bytes bytes_value = 4; 38 | optional float float_value = 5; 39 | optional sfixed64 sfixed64_value = 6; 40 | optional sint64 sint64_value = 7; 41 | optional int64 int64_value = 8; 42 | optional fixed64 fixed64_value = 9; 43 | optional uint64 uint64_value = 10; 44 | optional fixed32 fixed32_value = 11; 45 | optional uint32 uint32_value = 12; 46 | optional sfixed32 sfixed32_value = 13; 47 | optional sint32 sint32_value = 14; 48 | optional int32 int32_value = 15; 49 | } 50 | 51 | message RepeatedValues { 52 | repeated bool bool_value = 1; 53 | repeated double double_value = 2; 54 | repeated string string_value = 3; 55 | repeated bytes bytes_value = 4; 56 | repeated float float_value = 5; 57 | repeated sfixed64 sfixed64_value = 6; 58 | repeated sint64 sint64_value = 7; 59 | repeated int64 int64_value = 8; 60 | repeated fixed64 fixed64_value = 9; 61 | repeated uint64 uint64_value = 10; 62 | repeated fixed32 fixed32_value = 11; 63 | repeated uint32 uint32_value = 12; 64 | repeated sfixed32 sfixed32_value = 13; 65 | repeated sint32 sint32_value = 14; 66 | repeated int32 int32_value = 15; 67 | } 68 | 69 | message OneOf { 70 | message FirstPayload { 71 | optional string x = 1; 72 | } 73 | message SecondPayload { 74 | optional int64 y = 1; 75 | } 76 | oneof choice { 77 | FirstPayload first = 1; 78 | SecondPayload second = 2; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /cert.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | 3 | option java_package = "com.whatsapp.proto"; 4 | 5 | // certs are passed as the bytes for ServerHello payload 6 | // the reason why certs are opaque bytes to ServerHello is because payload is encrypted while the other fields are not 7 | 8 | // DEPRECATED: this was the certificate message used in wap v5 and prior, and 9 | // is kept here for generated-code compatibility with ../v5/wa5.proto only. It 10 | // should not be used in v6 communications; use CertChain below instead. This 11 | // message will be safe to delete when there are no remaining uses of v5. 12 | message NoiseCertificate { 13 | message Details { 14 | optional uint32 serial = 1; 15 | optional string issuer = 2; 16 | optional uint64 expires = 3; 17 | optional string subject = 4; 18 | optional bytes key = 5; 19 | } 20 | 21 | optional bytes details = 1; 22 | optional bytes signature = 2; 23 | } 24 | 25 | // Cert chain upper bound should be 240 bytes + protobuf overhead, well below most county's MTU. As such, handshake should remain reliable 26 | // in practice, total size will be exactly 240 bytes due to varint encoding compensating for the protobuf overhead 27 | message CertChain { 28 | message NoiseCertificate { 29 | message Details { 30 | // identifier for this specific cert 31 | // size <= 4 bytes (varint encoded) 32 | optional uint32 serial = 1; 33 | // the serial of the cert whose private key signed the current cert 34 | // size <= 4 bytes (varint encoded) 35 | optional uint32 issuer_serial = 2; 36 | // point-compressed public xed25519 key. This means it's an ed25519 0-bit sign key, converted to x25519 37 | // size = 32 bytes 38 | optional bytes key = 3; 39 | // the date, in Unix time, on which the certificate becomes valid 40 | // size <= 8 bytes (varint encoded) 41 | optional uint64 not_before = 4; 42 | // the date, in Unix time, on which the certificate becomes invalid 43 | // size <= 8 bytes (varint encoded) 44 | optional uint64 not_after = 5; 45 | } 46 | // protbuf-encoded Details message. Sent as bytes so that only signer needs to serialize, as protobuf is not canonical 47 | // the exact size will vary, but upper bound is 4 + 4 + 32 + 8 + 8 = 56 bytes plus protobuf overhead 48 | // in practice, total size will be ~50 bytes 49 | // size <= 56 + overhead bytes 50 | optional bytes details = 1; 51 | // details signed with the private-key associated with key from the certificate identified by issuer_serial 52 | // size = 64 bytes 53 | optional bytes signature = 2; 54 | } 55 | // the exact size will vary, but upper bound is 56 + 64 bytes plus protobuf overhead 56 | // size <= 120 bytes + overhead bytes 57 | optional NoiseCertificate leaf = 1; 58 | // size <= 120 bytes + overhead bytes 59 | optional NoiseCertificate intermediate = 2; 60 | } -------------------------------------------------------------------------------- /biz.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | package whatsapp; 3 | 4 | option java_package = "com.whatsapp.proto"; 5 | 6 | // The contents here should stay consistent with the corresponding enttity defined in 7 | // https://fburl.com/wb90jsw3 8 | 9 | message HighlyStructuredMessagePack { 10 | message HighlyStructuredMessageTranslation { 11 | message HighlyStructuredMessageTextElement { 12 | enum Type { 13 | TITLE = 0; 14 | CONTENT = 1; 15 | FOOTER = 2; 16 | BUTTON = 3; 17 | } 18 | enum Format { 19 | TEXT = 0; 20 | IMAGE = 1; 21 | DOCUMENT = 2; 22 | VIDEO = 3; 23 | LOCATION = 4; 24 | } 25 | enum ButtonField { 26 | DISPLAY_TEXT = 0; 27 | URL = 1; 28 | PHONE_NUMBER = 2; 29 | } 30 | 31 | optional string namespace = 1 [deprecated=true]; 32 | optional string element_name = 2 [deprecated=true]; 33 | optional uint32 num_params = 3; 34 | optional Type type = 4; 35 | optional Format format = 5; 36 | optional uint32 buttonIndex = 6 [deprecated=true]; 37 | optional ButtonField buttonField = 7 [deprecated=true]; 38 | optional string translated_text = 8; 39 | } 40 | message TranslationPluralException { 41 | enum PluralQuantityType { 42 | ZERO = 0; 43 | ONE = 1; 44 | TWO = 2; 45 | FEW = 3; 46 | MANY = 4; 47 | OTHER = 5; 48 | } 49 | optional PluralQuantityType qty = 1; 50 | optional string translated_text = 2; 51 | } 52 | message HighlyStructuredMessageButtonElement { 53 | message QuickReplyButton { 54 | optional string display_text = 1; 55 | } 56 | 57 | message URLButton { 58 | optional string display_text = 1; 59 | optional string url = 2; 60 | } 61 | 62 | message CallButton { 63 | optional string display_text = 1; 64 | optional string phone_number = 2; 65 | } 66 | 67 | oneof button { 68 | QuickReplyButton quick_reply_button = 1; 69 | URLButton url_button = 2; 70 | CallButton call_button = 3; 71 | } 72 | optional uint32 index = 4; 73 | } 74 | 75 | optional string translated_text = 2 [deprecated=true]; 76 | optional uint32 plural_param_no = 3; 77 | repeated TranslationPluralException plural_exceptions = 4; 78 | optional string name = 5; 79 | oneof hsm_element { 80 | HighlyStructuredMessageTextElement text_element = 1; 81 | HighlyStructuredMessageButtonElement button_element = 6; 82 | } 83 | optional string template_id = 7; 84 | } 85 | message Constraints { 86 | optional uint32 max_body_length = 1; 87 | optional uint32 max_header_length = 2; 88 | optional uint32 max_button_payload_length = 3; 89 | optional uint32 max_button_url_length = 4; 90 | } 91 | optional string namespace = 1; 92 | optional string lg = 2; 93 | optional string lc = 3; 94 | optional uint32 version = 4 [deprecated=true]; // Can have a different version for each namespace, lg, lc tuple 95 | repeated HighlyStructuredMessageTranslation translations = 5; 96 | optional Constraints constraints = 6; 97 | } 98 | -------------------------------------------------------------------------------- /backup.proto: -------------------------------------------------------------------------------- 1 | // This file is Android specific 2 | package whatsapp; 3 | option java_package = "com.whatsapp.proto"; 4 | 5 | message BackupPrefix { 6 | enum KeyType { 7 | WA_PROVIDED = 0; 8 | HSM_CONTROLLED = 1; 9 | } 10 | optional KeyType key_type = 1; 11 | optional WaProvidedKeyData wa_provided_key_data = 2; 12 | optional HsmControlledKeyData hsm_controlled_key_data = 3; 13 | optional BackupMetadata backup_metadata = 4; 14 | } 15 | 16 | message WaProvidedKeyData { 17 | optional bytes backup_cipher_header = 1; // 2 bytes. Specifies the version of the file. 18 | optional string key_version = 2; // 1 byte 19 | optional bytes server_salt = 3; // 32 bytes 20 | optional bytes google_id_salt = 4; // 16 bytes 21 | optional bytes encryption_iv = 5; // 16 bytes 22 | 23 | } 24 | 25 | message HsmControlledKeyData { 26 | optional bytes encryption_iv = 1; // 16 bytes 27 | } 28 | 29 | message BackupMetadata { 30 | optional string app_version = 1; 31 | optional string device_model = 2; 32 | optional string jid_suffix = 3; // last 2 digits of jid user 33 | 34 | // Number that represents the version of the backup schema. 35 | optional int32 backup_version = 4; 36 | 37 | // migration specific fields 38 | // v1 migrations fields 39 | optional bool call_log_migration_finished = 5; 40 | optional bool labeled_jid_migration_finished = 6; 41 | optional bool message_fts_migration_finished = 7; 42 | optional bool blank_me_jid_migration_finished = 8; 43 | optional bool message_link_migration_finished = 9; 44 | optional bool message_main_migration_finished = 10; 45 | optional bool message_text_migration_finished = 11; 46 | optional bool missed_calls_migration_finished = 12; 47 | optional bool receipt_user_migration_finished = 13; 48 | optional bool message_media_migration_finished = 14; 49 | optional bool message_vcard_migration_finished = 15; 50 | optional bool message_future_migration_finished = 16; 51 | optional bool message_quoted_migration_finished = 17; 52 | optional bool message_system_migration_finished = 18; 53 | optional bool receipt_device_migration_finished = 19; 54 | optional bool message_mention_migration_finished = 20; 55 | optional bool message_revoked_migration_finished = 21; 56 | optional bool broadcast_me_jid_migration_finished = 22; 57 | optional bool message_frequent_migration_finished = 23; 58 | optional bool message_location_migration_finished = 24; 59 | optional bool participant_user_migration_finished = 25; 60 | optional bool message_thumbnail_migration_finished = 26; 61 | optional bool message_send_count_migration_finished = 27; 62 | optional bool migration_jid_store_migration_finished = 28; 63 | optional bool payment_transaction_migration_finished = 29; 64 | optional bool migration_chat_store_migration_finished = 30; 65 | optional bool quoted_order_message_migration_finished = 31; 66 | optional bool media_migration_fixer_migration_finished = 32; 67 | optional bool quoted_order_message_v2_migration_finished = 33; 68 | optional bool message_main_verification_migration_finished = 34; 69 | optional bool quoted_ui_elements_reply_message_migration_finished = 35; 70 | optional bool alter_message_ephemeral_to_message_ephemeral_remove_column_migration_finished = 36; 71 | optional bool alter_message_ephemeral_setting_to_message_ephemeral_setting_remove_column_migration_finished = 37; 72 | // end of v1 migrations fields 73 | } 74 | -------------------------------------------------------------------------------- /server_sync.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | option java_package = "com.whatsapp.proto"; 3 | 4 | /************************ 5 | * Common structs 6 | ************************/ 7 | 8 | message SyncdVersion { 9 | optional uint64 version = 1; 10 | } 11 | 12 | message ExitCode { 13 | // Unique code to identify the type of error that occured. 14 | optional uint64 code = 1; 15 | 16 | // Optional error message with more details about what went wrong 17 | optional string text = 2; 18 | } 19 | 20 | // Lookup key part of a SyncdRecord. 21 | // 'index' is used instead of 'key' to distinguish from 'encryption key' 22 | message SyncdIndex { 23 | // Optional: 24 | // Index which has been binary encoded on the client side, 25 | // see https://fb.quip.com/1u2DAnQGKkCD for discussion 26 | optional bytes blob = 1; 27 | } 28 | 29 | message SyncdValue { 30 | optional bytes blob = 1; // Value which has been binary encoded by client 31 | } 32 | 33 | message KeyId { 34 | optional bytes id = 1; 35 | } 36 | 37 | // Represents a single index/value within a snapshot or mutation 38 | message SyncdRecord { 39 | // Contains the HMAC of the encoded mutation index. Used by the server to compact mutations 40 | // applied to the same record. 41 | optional SyncdIndex index = 1; 42 | // Contains the encrypted and authenticated record data. 43 | optional SyncdValue value = 2; 44 | // ID of the encryption key that was used to encrypt this record. 45 | optional KeyId key_id = 3; 46 | } 47 | 48 | // Meta-data about an encrypted snapshot or mutations blob stored in Everstore 49 | message ExternalBlobReference { 50 | // 'media key', used to derive cipher key, IV, and HMAC key. 51 | // See section 4A of WACOMMON/doc/end_to_end_encryption/media.txt 52 | optional bytes media_key = 1; 53 | optional string direct_path = 2; // direct_path returned from upload service 54 | optional string handle = 3; // handle returned from upload service 55 | optional uint64 file_size_bytes = 4; // length of plain text in bytes 56 | optional bytes file_sha256 = 5; // sha256 hash of plain text 57 | optional bytes file_enc_sha256 = 6; // sha256 hash of cipher text 58 | } 59 | 60 | /************************ 61 | * Snapshots 62 | ************************/ 63 | 64 | // Versioned collection of distinct index/value pairs, 65 | // e.g. representing all stared messages for a user. 66 | message SyncdSnapshot { 67 | optional SyncdVersion version = 1; 68 | repeated SyncdRecord records = 2; 69 | optional bytes mac = 3; 70 | optional KeyId key_id = 4; 71 | } 72 | 73 | /************************ 74 | * Patches 75 | ************************/ 76 | 77 | // Concrete mutations, which will either be passed inline inside a SyncdPatch, 78 | // or will be stored externally in Everstore. 79 | message SyncdMutations { 80 | repeated SyncdMutation mutations = 1; 81 | } 82 | 83 | message SyncdMutation { 84 | enum SyncdOperation { 85 | SET = 0; 86 | REMOVE = 1; 87 | } 88 | optional SyncdOperation operation = 1; 89 | optional SyncdRecord record = 2; 90 | } 91 | 92 | // Used when submitting patches to and receiving patches from server 93 | // Serialized SyncdPatch goes into tag within IQ. 94 | message SyncdPatch { 95 | // Clients should leave this field blank when creating new patches for submission to server. 96 | optional SyncdVersion version = 1; 97 | 98 | // For mutations passed inline, this field will be popualted when clients receive SyncdPatch in IQ response. 99 | repeated SyncdMutation mutations = 2; 100 | 101 | // For external patches, this field should be populated with a reference to 102 | // an encrypted SyncdMutations blob uploaded to Everstore. 103 | optional ExternalBlobReference external_mutations = 3; 104 | optional bytes snapshot_mac = 4; 105 | optional bytes patch_mac = 5; 106 | // ID of the encryption key used to generate snapshot and patch MACs. It should match the `SET` mutations 107 | // included in the patch (unless there are none). 108 | optional KeyId key_id = 6; 109 | 110 | // This field should only be set if this is a 'terminal patch'. 111 | // Generally only the server will write such patches. 112 | // Once a terminal patch has been written, no further patches can be written 113 | // to the collection, and clients should treat receiving the terminal patch 114 | // the same as if they received a fatal error. 115 | // Important: anti-tampering checks should be skipped if a terminal patch is received. 116 | optional ExitCode exit_code = 7; 117 | 118 | // The index of the device submitting the patch (12345550001:@s.whatsapp.net). 119 | optional uint32 device_index = 8; 120 | } 121 | -------------------------------------------------------------------------------- /wa5.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | 3 | option java_package = "com.whatsapp.proto"; 4 | option optimize_for = LITE_RUNTIME; 5 | 6 | message HandshakeMessage { 7 | message ClientHello { 8 | optional bytes ephemeral = 1; 9 | optional bytes static = 2; 10 | optional bytes payload = 3; 11 | } 12 | 13 | message ServerHello { 14 | optional bytes ephemeral = 1; 15 | optional bytes static = 2; 16 | optional bytes payload = 3; 17 | } 18 | 19 | message ClientFinish { 20 | optional bytes static = 1; 21 | optional bytes payload = 2; 22 | } 23 | 24 | optional ClientHello client_hello = 2; 25 | optional ServerHello server_hello = 3; 26 | optional ClientFinish client_finish = 4; 27 | } 28 | 29 | message ClientPayload { 30 | message UserAgent { 31 | enum Platform { 32 | ANDROID = 0; 33 | IOS = 1; 34 | WINDOWS_PHONE = 2; 35 | BLACKBERRY = 3; 36 | BLACKBERRYX = 4; 37 | S40 = 5; 38 | S60 = 6; 39 | PYTHON_CLIENT = 7; 40 | TIZEN = 8; 41 | ENTERPRISE = 9; 42 | SMB_ANDROID = 10; 43 | KAIOS = 11; 44 | SMB_IOS = 12; 45 | WINDOWS = 13; 46 | WEB = 14; 47 | PORTAL = 15; 48 | GREEN_ANDROID = 16; 49 | GREEN_IPHONE = 17; 50 | BLUE_ANDROID = 18; 51 | BLUE_IPHONE = 19; 52 | FBLITE_ANDROID = 20; 53 | MLITE_ANDROID = 21; 54 | IGLITE_ANDROID = 22; 55 | PAGE = 23; 56 | MACOS = 24; 57 | OCULUS_MSG = 25; 58 | OCULUS_CALL = 26; 59 | MILAN = 27; // FB wearable 60 | CAPI = 28; 61 | } 62 | enum ReleaseChannel { 63 | RELEASE = 0; 64 | BETA = 1; 65 | ALPHA = 2; 66 | DEBUG = 3; 67 | } 68 | message AppVersion { 69 | optional uint32 primary = 1; 70 | optional uint32 secondary = 2; 71 | optional uint32 tertiary = 3; 72 | optional uint32 quaternary = 4; 73 | optional uint32 quinary = 5; 74 | } 75 | optional Platform platform = 1; 76 | optional AppVersion app_version = 2; 77 | optional string mcc = 3; 78 | optional string mnc = 4; 79 | optional string os_version = 5; 80 | optional string manufacturer = 6; 81 | optional string device = 7; 82 | optional string os_build_number = 8; 83 | optional string phone_id = 9; 84 | optional ReleaseChannel release_channel = 10; 85 | optional string locale_language_iso_639_1 = 11; 86 | optional string locale_country_iso_3166_1_alpha_2 = 12; 87 | optional string device_board = 13; 88 | } 89 | message WebInfo { 90 | enum WebSubPlatform { 91 | WEB_BROWSER = 0; 92 | APP_STORE = 1; 93 | WIN_STORE = 2; 94 | DARWIN = 3; 95 | WIN32 = 4; 96 | } 97 | message WebdPayload { 98 | optional bool uses_participant_in_key = 1; 99 | optional bool supports_starred_messages = 2 [deprecated=true]; // assumed to be true with web v7 100 | optional bool supports_document_messages = 3 [deprecated=true]; // deprecated in favour of e2e_document 101 | optional bool supports_url_messages = 4 [deprecated=true]; // true with v10 102 | optional bool supports_media_retry = 5 [deprecated=true]; // true with v7 103 | optional bool supports_e2e_image = 6 [deprecated=true]; // assumed to be true with web v11 104 | optional bool supports_e2e_video = 7 [deprecated=true]; // assumed to be true with web v11 105 | optional bool supports_e2e_audio = 8 [deprecated=true]; // assumed to be true with web v11 106 | optional bool supports_e2e_document = 9 [deprecated=true]; // assumed to be true with web v11 107 | optional string document_types = 10 [deprecated=true]; // web gets directly with web v12 108 | optional bytes features = 11; 109 | } 110 | optional string ref_token = 1; 111 | optional string version = 2; 112 | optional WebdPayload webd_payload = 3; 113 | optional WebSubPlatform web_sub_platform = 4; 114 | } 115 | enum IOSAppExtension { 116 | SHARE_EXTENSION = 0; 117 | SERVICE_EXTENSION = 1; // apns-handler 118 | INTENTS_EXTENSION = 2; // siri-kit 119 | } 120 | enum ConnectReason { 121 | PUSH = 0; 122 | USER_ACTIVATED = 1; 123 | SCHEDULED = 2; 124 | ERROR_RECONNECT = 3; 125 | NETWORK_SWITCH = 4; 126 | PING_RECONNECT = 5; 127 | } 128 | enum ConnectType { 129 | CELLULAR_UNKNOWN = 0; 130 | WIFI_UNKNOWN = 1; 131 | CELLULAR_EDGE = 100; 132 | CELLULAR_IDEN = 101; 133 | CELLULAR_UMTS = 102; 134 | CELLULAR_EVDO = 103; 135 | CELLULAR_GPRS = 104; 136 | CELLULAR_HSDPA = 105; 137 | CELLULAR_HSUPA = 106; 138 | CELLULAR_HSPA = 107; 139 | CELLULAR_CDMA = 108; 140 | CELLULAR_1XRTT = 109; 141 | CELLULAR_EHRPD = 110; 142 | CELLULAR_LTE = 111; 143 | CELLULAR_HSPAP = 112; 144 | } 145 | message DNSSource { 146 | enum DNSResolutionMethod { 147 | SYSTEM = 0; 148 | GOOGLE = 1; 149 | HARDCODED = 2; 150 | OVERRIDE = 3; 151 | FALLBACK = 4; 152 | } 153 | 154 | optional DNSResolutionMethod dns_method = 15; 155 | optional bool app_cached = 16; 156 | } 157 | message DevicePairingRegistrationData { 158 | optional bytes e_regid = 1; 159 | optional bytes e_keytype = 2; 160 | optional bytes e_ident = 3; 161 | optional bytes e_skey_id = 4; 162 | optional bytes e_skey_val = 5; 163 | optional bytes e_skey_sig = 6; 164 | optional bytes build_hash = 7; 165 | optional bytes device_props = 8; 166 | } 167 | enum Product { 168 | WHATSAPP = 0; 169 | MESSENGER = 1; 170 | } 171 | 172 | optional uint64 username = 1; // phone number for WhatsApp, FBID for Messenger/IG 173 | // optional bytes legacy_password = 2 [deprecated=true]; 174 | optional bool passive = 3; 175 | // repeated ClientFeature client_features = 4 [deprecated=true]; 176 | optional UserAgent user_agent = 5; 177 | optional WebInfo web_info = 6; 178 | optional string push_name = 7; 179 | // optional uint32 session_id = 8 [deprecated=true]; // replaced by 9 180 | optional sfixed32 session_id = 9; 181 | optional bool short_connect = 10; // Set to true by clients that are clients relying on a push system to wake them up as opposed to intending to stay connected to chatd indefinitely 182 | // optional string connect_reason = 11; // replaced by 13 183 | optional ConnectType connect_type = 12; 184 | optional ConnectReason connect_reason = 13; // Requested as debugging tool 185 | // Used only by sharded enterprise clients to list which client shards this connection will handle. 186 | repeated int32 shards = 14; 187 | optional DNSSource dns_source = 15; // Requested as a debugging tool - optional 188 | optional uint32 connect_attempt_count = 16; 189 | optional uint32 agent = 17; 190 | optional uint32 device = 18; 191 | // Used only for device pairing (either WA companion registration or Trust Circle device onboarding) 192 | optional DevicePairingRegistrationData device_pairing_data = 19; 193 | optional Product product = 20; 194 | optional bytes fb_cat = 21; // Crypto Auth Token 195 | optional bytes fb_user_agent = 22; 196 | // Is this an official client? (may not be reliable) 197 | optional bool oc = 23; 198 | // Login counter 199 | optional int32 lc = 24; 200 | optional IOSAppExtension ios_app_extension = 30; 201 | // https://www.internalfb.com/intern/wiki/Appids/ 202 | optional uint64 fb_app_id = 31; 203 | // 128-bit UUID https://www.internalfb.com/intern/wiki/How-do-we-uniquely-identify-devices/device-id/ 204 | optional bytes fb_device_id = 32; 205 | } 206 | 207 | // NOTE: when you make any change, please update both wa5.proto and wa5_chatd.proto 208 | -------------------------------------------------------------------------------- /history_sync.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | option java_package = "com.whatsapp.proto"; 3 | 4 | import "web.proto"; 5 | import "e2e.proto"; 6 | import "protocol.proto"; 7 | 8 | message HistorySync { 9 | enum HistorySyncType { 10 | INITIAL_BOOTSTRAP = 0; 11 | INITIAL_STATUS_V3 = 1; 12 | FULL = 2; 13 | RECENT = 3; 14 | PUSH_NAME = 4; 15 | } 16 | required HistorySyncType sync_type = 1; 17 | repeated Conversation conversations = 2; 18 | repeated WebMessageInfo status_v3_messages = 3; 19 | optional uint32 chunk_order = 5; 20 | optional uint32 progress = 6; 21 | repeated Pushname pushnames = 7; 22 | // For cross-platform migration only - not needed for M-D. 23 | optional GlobalSettings global_settings = 8; 24 | // Initial sync only, send the chat thread logging attributes to companion devices 25 | // Please refer to doc/chat_message_counts.md 26 | optional bytes thread_id_user_secret = 9; 27 | optional uint32 thread_ds_timeframe_offset = 10; 28 | } 29 | 30 | message Conversation { 31 | enum EndOfHistoryTransferType { 32 | COMPLETE_BUT_MORE_MESSAGES_REMAIN_ON_PRIMARY = 0; 33 | COMPLETE_AND_NO_MORE_MESSAGE_REMAIN_ON_PRIMARY = 1; 34 | } 35 | // Note: Conversation id is always required. 36 | // This will be the protocol string representation of a chat jid, usually a user jid or group jid. 37 | // If the id is not recognized as a valid jid by the receiving device, 38 | // this should be logged and the conversation (and any associated messages) can be discarded. 39 | required string id = 1 [(jid) = true]; 40 | // Note: HistorySyncMsg messages is required when transferring msgs. 41 | repeated HistorySyncMsg messages = 2; 42 | // All fields below are optional except during initial_bootstrap 43 | /* 44 | new_jid and old_jid indicate what a user's old/new number is after a 45 | change_number v2 operation, for displaying the persistent notification in the chat 46 | */ 47 | optional string new_jid = 3 [(jid) = true]; 48 | optional string old_jid = 4 [(jid) = true]; 49 | optional uint64 last_msg_timestamp = 5 [deprecated=true]; 50 | optional uint32 unread_count = 6; 51 | optional bool read_only = 7; 52 | optional bool end_of_history_transfer = 8 [deprecated=true]; 53 | optional uint32 ephemeral_expiration = 9; // in seconds, only sent for ephemeral conversations 54 | optional int64 ephemeral_setting_timestamp = 10; // in seconds, only sent for ephemeral conversations 55 | optional EndOfHistoryTransferType end_of_history_transfer_type = 11; 56 | optional uint64 conversation_timestamp = 12; // in seconds 57 | // Set for all group chats, with the group name. Only for initial sync 58 | optional string name = 13; 59 | // Set for all group chat, with pHash (version 1 hash of users in the group). Only for initial sync 60 | optional string p_hash = 14; 61 | // Initial sync only, set to true for chat that is not suspicious / spam 62 | optional bool not_spam = 15; 63 | // Specifies if chat is archived 64 | optional bool archived = 16; 65 | // Disappearing mode metadata 66 | optional DisappearingMode disappearing_mode = 17; 67 | // Unread mention count of messages that have mentions 68 | optional uint32 unread_mention_count = 18; 69 | // User marked the chat as unread 70 | optional bool marked_as_unread = 19; 71 | // For group conversation specifies list of participants; used for cross-platform migration. 72 | repeated GroupParticipant participant = 20; 73 | // For 1:1 conversation, we might have a tctoken associated; used for online presence subscription. Initial sync and cross-platform migration 74 | optional bytes tc_token = 21; 75 | // in unixtime, the server timestamp when the client received the token for the last time; used to delete the expired tctoken. Initial sync and cross-platform migration 76 | optional uint64 tc_token_timestamp = 22; 77 | // For 1:1 conversation, primary should include the contact's primary identity key; used for adv. Only for initial sync 78 | // Note: contact_primary_identity_key does not contain the "key type" (0x05) prefix 79 | optional bytes contact_primary_identity_key = 23; 80 | // Indicates if chat is pinned - null means chat is not pinned, 1 is top, 2 is middle, 3 is bottom. 81 | // If number of pinned will be increased, greater one is the bottom one. (used for Cross Platform migration only) 82 | optional uint32 pinned = 24; 83 | // Indicates if chat is muted, and time (in seconds, as other timestamps) when mute will be ended. Null means chat is not muted. (used for Cross Platform migration only) 84 | optional uint64 mute_end_time = 25; 85 | // Custom wallpaper settings (used for Cross Platform migration only) 86 | optional WallpaperSettings wallpaper = 26; 87 | // Specifies if media from chat should be visible in Gallery / Camera Roll (used for Cross Platform migration only) 88 | optional MediaVisibility media_visibility = 27; 89 | // in unixtime, the server timestamp when the client asked the server to generated a token for the conversation partner; Only for initial sync 90 | optional uint64 tc_token_sender_timestamp = 28; 91 | // For group conversation, specifies whether group is suspended 92 | optional bool suspended = 29; 93 | } 94 | 95 | message HistorySyncMsg { 96 | // We use WebMessageInfo vs the standard Message 97 | // from e2e proto so we can include additional info like receipt status, starred etc 98 | optional WebMessageInfo message = 1; 99 | // this is primary's row id 100 | optional uint64 msg_order_id = 2; 101 | } 102 | 103 | message Pushname { 104 | optional string id = 1 [(jid) = true]; 105 | optional string pushname = 2; 106 | } 107 | 108 | message GroupParticipant { 109 | enum Rank { 110 | REGULAR = 0; 111 | ADMIN = 1; 112 | SUPERADMIN = 2; 113 | } 114 | 115 | // UserJid of participant 116 | required string user_jid = 1 [(jid) = true]; 117 | // Rank - if not specified, assumed as REGULAR user 118 | optional Rank rank = 2; 119 | } 120 | 121 | message WallpaperSettings { 122 | // Relative path to custom wallpaper file 123 | optional string filename = 1; 124 | // If opacity is missed assume it is equal to default value 125 | optional uint32 opacity = 2; 126 | } 127 | 128 | enum MediaVisibility { 129 | DEFAULT = 0; 130 | OFF = 1; 131 | ON = 2; 132 | } 133 | 134 | message GlobalSettings { 135 | // Default wallpaper to be used by default for all chats; 136 | // could be individually overridden for chat; 137 | // light theme 138 | optional WallpaperSettings light_theme_wallpaper = 1; 139 | 140 | // Default value to specify if chat media should be visible in Gallery / Camera Roll; 141 | // could be individually overridden for chat 142 | optional MediaVisibility media_visibility = 2; 143 | 144 | // Default wallpaper to be used by default for all chats; 145 | // could be individually overridden for chat; 146 | // dark theme 147 | optional WallpaperSettings dark_theme_wallpaper = 3; 148 | 149 | // Auto-download settings 150 | optional AutoDownloadSettings auto_download_WiFi = 4; 151 | optional AutoDownloadSettings auto_download_cellular = 5; 152 | optional AutoDownloadSettings auto_download_roaming = 6; 153 | 154 | // Notifications 155 | optional bool show_individual_notifications_preview = 7; 156 | optional bool show_group_notifications_preview = 8; 157 | 158 | // Disappearing mode 159 | optional int32 disappearing_mode_duration = 9; 160 | optional int64 disappearing_mode_timestamp = 10; 161 | } 162 | 163 | message AutoDownloadSettings { 164 | optional bool download_images = 1; 165 | optional bool download_audio = 2; 166 | optional bool download_video = 3; 167 | optional bool download_documents = 4; 168 | } 169 | -------------------------------------------------------------------------------- /sync_action.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | 3 | option java_package = "com.whatsapp.proto"; 4 | option optimize_for = LITE_RUNTIME; 5 | 6 | import "protocol.proto"; 7 | 8 | message RecentStickerWeight { 9 | // the filehash of the sticker file 10 | optional string filehash = 1; 11 | optional float weight = 2; 12 | } 13 | 14 | message RecentEmojiWeight { 15 | optional string emoji = 1; 16 | optional float weight = 2; 17 | } 18 | 19 | message SyncActionValue { 20 | /* server timestamp when the action happened in milliseconds */ 21 | optional int64 timestamp = 1; 22 | 23 | message StarAction { 24 | optional bool starred = 1; 25 | } 26 | 27 | message ContactAction { 28 | /* full_name must always appear as non empty string */ 29 | optional string full_name = 1; 30 | optional string first_name = 2; 31 | } 32 | 33 | message MuteAction { 34 | optional bool muted = 1; 35 | /* server timestamp + mute duration in milliseconds */ 36 | optional int64 mute_end_timestamp = 2; 37 | } 38 | 39 | message PinAction { 40 | optional bool pinned = 1; 41 | } 42 | 43 | message SecurityNotificationSetting { 44 | optional bool show_notification = 1; 45 | } 46 | 47 | message PushNameSetting { 48 | optional string name = 1; 49 | } 50 | 51 | message LocaleSetting { 52 | optional string locale = 1; 53 | } 54 | 55 | message QuickReplyAction { 56 | optional string shortcut = 1; 57 | optional string message = 2; 58 | repeated string keywords = 3; 59 | optional int32 count = 4; 60 | optional bool deleted = 5; 61 | } 62 | 63 | message LabelAssociationAction { 64 | optional bool labeled = 1; 65 | } 66 | 67 | message LabelEditAction { 68 | optional string name = 1; 69 | optional int32 color = 2; 70 | optional int32 predefinedId = 3; 71 | optional bool deleted = 4; 72 | } 73 | 74 | message RecentStickerWeightsAction { 75 | repeated RecentStickerWeight weights = 1; 76 | } 77 | 78 | message RecentStickerMetadata { 79 | optional string directPath = 1; 80 | optional string encFilehash = 2; 81 | optional string mediaKey = 3; 82 | optional string stanzaId = 4; 83 | optional string chatJid = 5; 84 | optional string participant = 6; 85 | optional bool isSentByMe = 7; 86 | } 87 | 88 | message RecentEmojiWeightsAction { 89 | repeated RecentEmojiWeight weights = 1; 90 | } 91 | 92 | message FavoriteStickerAction { 93 | optional string directPath = 1; 94 | optional string lastUploadTimestamp = 2; 95 | optional string handle = 3; 96 | optional string encFilehash = 4; 97 | optional string stickerHashWithoutMeta = 5; 98 | optional string mediaKey = 6; 99 | optional int64 mediaKeyTimestamp = 7; 100 | optional bool isFavorite = 8; 101 | } 102 | 103 | message ArchiveChatAction { 104 | optional bool archived = 1; 105 | optional SyncActionMessageRange message_range = 2; 106 | } 107 | 108 | message DeleteMessageForMeAction { 109 | optional bool delete_media = 1; 110 | optional int64 message_timestamp = 2; 111 | } 112 | 113 | message MarkChatAsReadAction { 114 | optional bool read = 1; 115 | optional SyncActionMessageRange message_range = 2; 116 | } 117 | 118 | message ClearChatAction { 119 | optional SyncActionMessageRange message_range = 1; 120 | } 121 | 122 | message DeleteChatAction { 123 | optional SyncActionMessageRange message_range = 1; 124 | } 125 | 126 | message UnarchiveChatsSetting { 127 | optional bool unarchive_chats = 1; 128 | } 129 | 130 | /* MessageRange specification: https://our.internmc.facebook.com/intern/diffusion/WACOMMON/browse/master/doc/md_client_to_client_sync/message_ranges_for_bulk_operations.md */ 131 | message SyncActionMessageRange { 132 | /* in seconds */ 133 | optional int64 last_message_timestamp = 1; 134 | /* in seconds */ 135 | optional int64 last_system_message_timestamp = 2; 136 | repeated SyncActionMessage messages = 3; 137 | } 138 | 139 | message SyncActionMessage { 140 | optional MessageKey key = 1; 141 | /* in seconds */ 142 | optional int64 timestamp = 2; 143 | } 144 | 145 | message KeyExpiration { 146 | optional int32 expired_key_epoch = 1; 147 | } 148 | 149 | message PrimaryFeature { 150 | /* all flags: 151 | 'contact_except' 152 | 'reactions_send' - shows if primary client able to deal with reaction sends (including future proofed) 153 | 'ddm_settings' - primary supports ddm duration changes on companion 154 | 'pnh_ctwa' - phone number hiding, clicks to WhatsApp ads 155 | */ 156 | repeated string flags = 1; 157 | } 158 | 159 | message AndroidUnsupportedActions { 160 | optional bool allowed = 1; 161 | } 162 | 163 | message AgentAction { 164 | optional string name = 1; 165 | // deviceID is an id range from 1-99 166 | optional int32 deviceID = 2; 167 | // it means this agent is deleted, practically hidden from the UI. We still keep it in agents table for history display 168 | optional bool isDeleted = 3; 169 | } 170 | 171 | message SubscriptionAction { 172 | // boolean flag, when true the subscription is no longer active 173 | optional bool isDeactivated = 1; 174 | // boolean flag, true indicates that the subscription is active and beeing renewed 175 | // false means that the subscription will not be renewed at the end of the current billing cycle 176 | // it might be canceled or there's a problem charging customer's payment method 177 | optional bool isAutoRenewing = 2; 178 | // date/time when the subscription is expiring, might be empty when expiration date is not known 179 | optional int64 expirationDate = 3; 180 | } 181 | 182 | message UserStatusMuteAction { 183 | optional bool muted = 1; 184 | } 185 | 186 | message TimeFormatAction { 187 | optional bool is_twenty_four_hour_format_enabled = 1; 188 | } 189 | 190 | optional StarAction star_action = 2; 191 | optional ContactAction contact_action = 3; 192 | optional MuteAction mute_action = 4; 193 | optional PinAction pin_action = 5; 194 | optional SecurityNotificationSetting security_notification_setting = 6; 195 | optional PushNameSetting push_name_setting = 7; 196 | optional QuickReplyAction quick_reply_action = 8; 197 | optional RecentStickerWeightsAction recent_sticker_weights_action = 9; 198 | optional RecentStickerMetadata recent_sticker_metadata = 10; 199 | optional RecentEmojiWeightsAction recent_emoji_weights_action = 11; 200 | /* optional LabelContactAction label_contact_action = 12; */ 201 | /* optional LabelMessageAction label_message_action = 13; */ 202 | optional LabelEditAction label_edit_action = 14; 203 | optional LabelAssociationAction label_association_action = 15; 204 | optional LocaleSetting locale_setting = 16; 205 | optional ArchiveChatAction archive_chat_action = 17; 206 | optional DeleteMessageForMeAction delete_message_for_me_action = 18; 207 | /* Used for key rotation. Only set for `SyncActionData` with index = "expired_key_epoch". */ 208 | optional KeyExpiration key_expiration = 19; 209 | optional MarkChatAsReadAction mark_chat_as_read_action = 20; 210 | optional ClearChatAction clear_chat_action = 21; 211 | optional DeleteChatAction delete_chat_action = 22; 212 | optional UnarchiveChatsSetting unarchive_chats_setting = 23; 213 | optional PrimaryFeature primary_feature = 24; 214 | optional FavoriteStickerAction favorite_sticker_action = 25; 215 | optional AndroidUnsupportedActions android_unsupported_actions = 26; 216 | optional AgentAction agent_action = 27; 217 | optional SubscriptionAction subscription_action = 28; 218 | optional UserStatusMuteAction user_status_mute_action = 29; 219 | optional TimeFormatAction time_format_action = 30; 220 | } 221 | 222 | message SyncActionData { 223 | optional bytes index = 1; 224 | optional SyncActionValue value = 2; 225 | optional bytes padding = 3; 226 | 227 | /** 228 | * Version number and associated actions 229 | * 0 - invalid, no action exist on this version 230 | * 1 - PushNameSetting 231 | * 2 - ContactAction, StarAction, MuteAction, SecurityNotificationSetting, QuickReplyAction 232 | * 3 - RecentStickerMetadata 233 | RecentEmojiWeightsAction 234 | LabelEditAction 235 | LabelAssociationAction 236 | LocaleSetting 237 | ArchiveChatAction 238 | DeleteMessageForMeAction 239 | MarkChatAsReadAction 240 | KeyExpiration 241 | 4 - UnarchiveChatsSetting 242 | AndroidUnsupportedActions 243 | 5 - PinAction 244 | 6 - ClearChatAction 245 | DeleteChatAction 246 | 7 - FavoriteStickerAction 247 | PrimaryFeature 248 | AgentAction 249 | SubscriptionAction 250 | UserStatusMuteAction 251 | TimeFormatAction 252 | */ 253 | optional int32 version = 4; 254 | } 255 | -------------------------------------------------------------------------------- /web.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | 3 | option java_package = "com.whatsapp.proto"; 4 | 5 | import "e2e.proto"; 6 | import "protocol.proto"; 7 | 8 | message WebMessageInfo { 9 | enum Status { 10 | ERROR = 0; 11 | PENDING = 1; // clock 12 | SERVER_ACK = 2; // single check 13 | DELIVERY_ACK = 3; // double check 14 | READ = 4; // blue check 15 | PLAYED = 5; // PTT played and VOM viewed, both send/receive 16 | } 17 | 18 | enum StubType { 19 | UNKNOWN = 0; // shouldn't be used 20 | REVOKE = 1; // message was revoked by original message sender 21 | CIPHERTEXT = 2; // undecrypted message 22 | FUTUREPROOF = 3; // message was decrypted but phone doesnt understand it 23 | 24 | // notification message templates 25 | 26 | // OLD biz system messages 27 | NON_VERIFIED_TRANSITION = 4; // 1 raw string param, business name used in alert when notification clicked 28 | UNVERIFIED_TRANSITION = 5; // 1 raw string param, business name used in alert when notification clicked 29 | VERIFIED_TRANSITION = 6; // 1 raw string param, business name used in alert when notification clicked 30 | VERIFIED_LOW_UNKNOWN = 7; // 1 raw string param, business name used in alert when notification clicked 31 | VERIFIED_HIGH = 8; // 1 raw string param, business name used in alert when notification clicked 32 | 33 | // spec: doc/biz/privacy_transparency.md 34 | // NEW biz system messages 35 | VERIFIED_INITIAL_UNKNOWN = 9; // 0 params 36 | VERIFIED_INITIAL_LOW = 10; // 1 raw string param, business name used in notification and alert 37 | VERIFIED_INITIAL_HIGH = 11; // 1 raw string param, business name used in notification and alert 38 | VERIFIED_TRANSITION_ANY_TO_NONE = 12; // 0 params 39 | VERIFIED_TRANSITION_ANY_TO_HIGH = 13; // 1 raw string param, business name used in notification and alert 40 | VERIFIED_TRANSITION_HIGH_TO_LOW = 14; // 1 raw string param, business name used in notification and alert 41 | VERIFIED_TRANSITION_HIGH_TO_UNKNOWN = 15; // 1 raw string param, business name used in notification and alert 42 | VERIFIED_TRANSITION_UNKNOWN_TO_LOW = 16; // 1 raw string param, business name used in notification and alert 43 | VERIFIED_TRANSITION_LOW_TO_UNKNOWN = 17; // 1 raw string param, business name used in notification and alert 44 | VERIFIED_TRANSITION_NONE_TO_LOW = 18; // 1 raw string param, business name used in alert 45 | VERIFIED_TRANSITION_NONE_TO_UNKNOWN = 19; // 0 params 46 | 47 | // group notification's author is WebMessageInfo.participant 48 | GROUP_CREATE = 20; // 1 raw string param, group subject 49 | GROUP_CHANGE_SUBJECT = 21; // 1 raw string param, group subject 50 | GROUP_CHANGE_ICON = 22; // 1 raw string param, arbitrary, or the literal "remove" 51 | GROUP_CHANGE_INVITE_LINK = 23; // 0 params 52 | GROUP_CHANGE_DESCRIPTION = 24; // 0 params 53 | GROUP_CHANGE_RESTRICT = 25; // 1 param, literal string "on" or "off" 54 | GROUP_CHANGE_ANNOUNCE = 26; // 1 param, literal string "on" or "off" 55 | GROUP_PARTICIPANT_ADD = 27; // any number of jid params, list of participants added 56 | GROUP_PARTICIPANT_REMOVE = 28; // any number of jid params, list of participants removed 57 | GROUP_PARTICIPANT_PROMOTE = 29; // any number of jid params, list of participants promoted to admin 58 | GROUP_PARTICIPANT_DEMOTE = 30; // any number of jid params, list of participants demoted 59 | GROUP_PARTICIPANT_INVITE = 31; // any number of jid params, list of participants joined through invite link 60 | GROUP_PARTICIPANT_LEAVE = 32; // any number of jid params, list of participants that left the group 61 | GROUP_PARTICIPANT_CHANGE_NUMBER = 33; // 1 jid param, user's new jid after change_number 62 | 63 | BROADCAST_CREATE = 34; // 1 raw string param, count of participants in the bclist 64 | BROADCAST_ADD = 35; // any number of jid params, list of participants added 65 | BROADCAST_REMOVE = 36; // any number of jid params, list of participants removed 66 | 67 | GENERIC_NOTIFICATION = 37; // 1 raw string param, entire text content of the custom system message 68 | 69 | E2E_IDENTITY_CHANGED = 38; // 1 jid param, user whose identity key changed 70 | E2E_ENCRYPTED = 39; // 0 params 71 | 72 | CALL_MISSED_VOICE = 40; // 0 params (send missed call time as WebMessageInfo.messageTimestamp) 73 | CALL_MISSED_VIDEO = 41; // 0 params (send missed call time as WebMessageInfo.messageTimestamp) 74 | 75 | INDIVIDUAL_CHANGE_NUMBER = 42; // 2 params, [OLD_JID, NEW_JID] 76 | 77 | GROUP_DELETE = 43; // 0 params 78 | GROUP_ANNOUNCE_MODE_MESSAGE_BOUNCE = 44; // 0 params 79 | 80 | CALL_MISSED_GROUP_VOICE = 45; // 0 params (send missed call time as WebMessageInfo.messageTimestamp) 81 | CALL_MISSED_GROUP_VIDEO = 46; // 0 params (send missed call time as WebMessageInfo.messageTimestamp) 82 | 83 | PAYMENT_CIPHERTEXT = 47; // 0 params 84 | PAYMENT_FUTUREPROOF = 48; // 0 params 85 | PAYMENT_TRANSACTION_STATUS_UPDATE_FAILED = 49; // 1 param, receiver jid (send transaction time as WebMessageInfo.messageTimestamp) 86 | PAYMENT_TRANSACTION_STATUS_UPDATE_REFUNDED = 50; // 1 param, receiver jid (send transaction time as WebMessageInfo.messageTimestamp) 87 | PAYMENT_TRANSACTION_STATUS_UPDATE_REFUND_FAILED = 51; // 1 param, receiver jid (send transaction time as WebMessageInfo.messageTimestamp) 88 | PAYMENT_TRANSACTION_STATUS_RECEIVER_PENDING_SETUP = 52; // 3 params, sender jid, 3-character ISO 4217 currency code, amount*1000 formatted as string 89 | PAYMENT_TRANSACTION_STATUS_RECEIVER_SUCCESS_AFTER_HICCUP = 53; // 1 param, sender jid (send relative time as WebMessageInfo.messageTimestamp) 90 | PAYMENT_ACTION_ACCOUNT_SETUP_REMINDER = 54; // 1 param, sender jid 91 | PAYMENT_ACTION_SEND_PAYMENT_REMINDER = 55; // 1 param, receiver jid 92 | PAYMENT_ACTION_SEND_PAYMENT_INVITATION = 56; // 1 param, receiver jid 93 | PAYMENT_ACTION_REQUEST_DECLINED = 57; // 3 params, jid, 3-character ISO 4217 currency code, amount*1000 94 | PAYMENT_ACTION_REQUEST_EXPIRED = 58; // 4 params, request sender jid, request receiver jid, 3-character ISO 4217 currency code, amount*1000 95 | PAYMENT_ACTION_REQUEST_CANCELLED = 59; // 3 params, jid, 3-character ISO 4217 currency code, amount*1000 96 | 97 | // spec: doc/biz/privacy_transparency.md 98 | // NEWER 2 tier verification level system messages 99 | BIZ_VERIFIED_TRANSITION_TOP_TO_BOTTOM = 60; // 1 param, business name 100 | BIZ_VERIFIED_TRANSITION_BOTTOM_TO_TOP = 61; // 1 param, business name 101 | BIZ_INTRO_TOP = 62; // 1 param, business name 102 | BIZ_INTRO_BOTTOM = 63; // 0 params 103 | BIZ_NAME_CHANGE = 64; // 1 param, new business name 104 | BIZ_MOVE_TO_CONSUMER_APP = 65; // 0 params 105 | BIZ_TWO_TIER_MIGRATION_TOP = 66; // 1 param, business name 106 | BIZ_TWO_TIER_MIGRATION_BOTTOM = 67; // 1 param, business name 107 | 108 | OVERSIZED = 68; // message is too big to send to web (size limit specified by server prop) 109 | GROUP_CHANGE_NO_FREQUENTLY_FORWARDED = 69; // 1 param, literal string "on" or "off" 110 | GROUP_V4_ADD_INVITE_SENT = 70; // any number of jid params, list of participants invited via an add request. 111 | GROUP_PARTICIPANT_ADD_REQUEST_JOIN = 71; // any number of jid params, list of participants joined through group v4 add request 112 | 113 | CHANGE_EPHEMERAL_SETTING = 72; // 1 or 2 params, new ephemeral duration, jid of whom changed the setting (omitted if setting is turned on prior to user joining the group) 114 | 115 | E2E_DEVICE_CHANGED = 73; // 3 params, user whose device changed, devicesAdded, devicesRemoved 116 | 117 | VIEWED_ONCE = 74 [deprecated=true]; // deprecated, using `PLAYED` in the `status` attribute instead 118 | 119 | E2E_ENCRYPTED_NOW = 75; // 0 params, this is similar to E2E_ENCRYPTED, just appears inbetween messages when privacy state changes instead of at the top 120 | 121 | // spec: doc/biz/privacy_transparency.md 122 | // These are system messages to show the business privacy state 123 | // chat state variances: 124 | // - verified: a business can be verified (high) or not 125 | // - host_storage: can be FB or PREMISE 126 | // - actual_actor: can be BSP(business solution provider) or SELF 127 | BLUE_MSG_BSP_FB_TO_BSP_PREMISE = 76 [deprecated=true]; // 0 or 1 param, business name if contact is verified when this message is created 128 | BLUE_MSG_BSP_FB_TO_SELF_FB = 77 [deprecated=true]; // 0 or 1 param, business name if contact is verified when this message is created 129 | BLUE_MSG_BSP_FB_TO_SELF_PREMISE = 78 [deprecated=true]; // 0 or 1 param, business name if contact is verified when this message is created 130 | BLUE_MSG_BSP_FB_UNVERIFIED = 79 [deprecated=true]; 131 | BLUE_MSG_BSP_FB_UNVERIFIED_TO_SELF_PREMISE_VERIFIED = 80 [deprecated=true]; // 1 param, business name 132 | BLUE_MSG_BSP_FB_VERIFIED = 81 [deprecated=true]; // 1 param, business name 133 | BLUE_MSG_BSP_FB_VERIFIED_TO_SELF_PREMISE_UNVERIFIED = 82 [deprecated=true]; 134 | BLUE_MSG_BSP_PREMISE_TO_SELF_PREMISE = 83 [deprecated=true]; // 0 or 1 param, business name if contact is verified when this message is created 135 | BLUE_MSG_BSP_PREMISE_UNVERIFIED = 84 [deprecated=true]; 136 | BLUE_MSG_BSP_PREMISE_UNVERIFIED_TO_SELF_PREMISE_VERIFIED = 85 [deprecated=true]; // 1 param, business name 137 | BLUE_MSG_BSP_PREMISE_VERIFIED = 86 [deprecated=true]; // 1 param, business name 138 | BLUE_MSG_BSP_PREMISE_VERIFIED_TO_SELF_PREMISE_UNVERIFIED = 87 [deprecated=true]; 139 | BLUE_MSG_CONSUMER_TO_BSP_FB_UNVERIFIED = 88 [deprecated=true]; 140 | BLUE_MSG_CONSUMER_TO_BSP_PREMISE_UNVERIFIED = 89 [deprecated=true]; 141 | BLUE_MSG_CONSUMER_TO_SELF_FB_UNVERIFIED = 90 [deprecated=true]; 142 | BLUE_MSG_CONSUMER_TO_SELF_PREMISE_UNVERIFIED = 91 [deprecated=true]; 143 | BLUE_MSG_SELF_FB_TO_BSP_PREMISE = 92 [deprecated=true]; // 0 or 1 param, business name if contact is verified when this message is created 144 | BLUE_MSG_SELF_FB_TO_SELF_PREMISE = 93 [deprecated=true]; // 0 or 1 param, business name if contact is verified when this message is created 145 | BLUE_MSG_SELF_FB_UNVERIFIED = 94 [deprecated=true]; 146 | BLUE_MSG_SELF_FB_UNVERIFIED_TO_SELF_PREMISE_VERIFIED = 95 [deprecated=true]; // 1 param, business name 147 | BLUE_MSG_SELF_FB_VERIFIED = 96 [deprecated=true]; // 1 param, business name 148 | BLUE_MSG_SELF_FB_VERIFIED_TO_SELF_PREMISE_UNVERIFIED = 97 [deprecated=true]; 149 | BLUE_MSG_SELF_PREMISE_TO_BSP_PREMISE = 98 [deprecated=true]; // 0 or 1 param, business name if contact is verified when this message is created 150 | BLUE_MSG_SELF_PREMISE_UNVERIFIED = 99 [deprecated=true]; 151 | BLUE_MSG_SELF_PREMISE_VERIFIED = 100 [deprecated=true]; // 1 param, business name 152 | BLUE_MSG_TO_BSP_FB = 101 [deprecated=true]; // 0 or 1 param, business name if contact is verified when this message is created 153 | BLUE_MSG_TO_CONSUMER = 102 [deprecated=true]; 154 | BLUE_MSG_TO_SELF_FB = 103 [deprecated=true]; // 1 param, business name 155 | BLUE_MSG_UNVERIFIED_TO_BSP_FB_VERIFIED = 104 [deprecated=true]; // 1 param, business name 156 | BLUE_MSG_UNVERIFIED_TO_BSP_PREMISE_VERIFIED = 105 [deprecated=true]; // 1 param, business name 157 | BLUE_MSG_UNVERIFIED_TO_SELF_FB_VERIFIED = 106 [deprecated=true]; // 1 param, business name 158 | BLUE_MSG_UNVERIFIED_TO_VERIFIED = 107 [deprecated=true]; // 1 param, business name 159 | BLUE_MSG_VERIFIED_TO_BSP_FB_UNVERIFIED = 108 [deprecated=true]; 160 | BLUE_MSG_VERIFIED_TO_BSP_PREMISE_UNVERIFIED = 109 [deprecated=true]; 161 | BLUE_MSG_VERIFIED_TO_SELF_FB_UNVERIFIED = 110 [deprecated=true]; 162 | BLUE_MSG_VERIFIED_TO_UNVERIFIED = 111 [deprecated=true]; 163 | BLUE_MSG_BSP_FB_UNVERIFIED_TO_BSP_PREMISE_VERIFIED = 112 [deprecated=true]; // 1 param, business name 164 | BLUE_MSG_BSP_FB_UNVERIFIED_TO_SELF_FB_VERIFIED = 113 [deprecated=true]; // 1 param, business name 165 | BLUE_MSG_BSP_FB_VERIFIED_TO_BSP_PREMISE_UNVERIFIED = 114 [deprecated=true]; 166 | BLUE_MSG_BSP_FB_VERIFIED_TO_SELF_FB_UNVERIFIED = 115 [deprecated=true]; 167 | BLUE_MSG_SELF_FB_UNVERIFIED_TO_BSP_PREMISE_VERIFIED = 116 [deprecated=true]; // 1 param, business name 168 | BLUE_MSG_SELF_FB_VERIFIED_TO_BSP_PREMISE_UNVERIFIED = 117 [deprecated=true]; 169 | 170 | E2E_IDENTITY_UNAVAILABLE = 118; // 0 param, system message where security codes were turned on for a chat but now they will no longer be received because the business is a non-e2e API user 171 | 172 | GROUP_CREATING = 119; // params - group subject and list of participants in group 173 | GROUP_CREATE_FAILED = 120; // params - group subject and list of participants in group 174 | GROUP_BOUNCED = 121; // no params 175 | BLOCK_CONTACT = 122; // boolean string param - is blocked or not 176 | EPHEMERAL_SETTING_NOT_APPLIED = 123; // int param - setting duration 177 | SYNC_FAILED = 124; // no params 178 | SYNCING = 125; // no params 179 | 180 | // spec: doc/biz/privacy_transparency.md 181 | // These are system messages to show the business privacy mode 182 | // BIZ_PRIVACY_MODE_INIT_FB and BIZ_PRIVACY_MODE_INIT_BSP show at the top of all content messages 183 | // BIZ_PRIVACY_MODE_TO_FB and BIZ_PRIVACY_MODE_TO_BSP show in between content messages 184 | BIZ_PRIVACY_MODE_INIT_FB = 126; // no params 185 | BIZ_PRIVACY_MODE_INIT_BSP = 127; // no params 186 | BIZ_PRIVACY_MODE_TO_FB = 128; // no params 187 | BIZ_PRIVACY_MODE_TO_BSP = 129; // no params 188 | 189 | DISAPPEARING_MODE = 130; // 2 params, 1st param is duration, 2nd param is initiator, should only be used for 1:1 chats 190 | 191 | E2E_DEVICE_FETCH_FAILED = 131; // 1 jid param, user whose devices couldn't be fetched 192 | 193 | ADMIN_REVOKE = 132; // message was revoked by a group admin (not original message sender) 194 | 195 | GROUP_INVITE_LINK_GROWTH_LOCKED = 133; // [1 param boolean, true = link is not available, false = available again] 196 | 197 | // 134-140 to be implemented later 198 | 199 | GROUP_PARTICIPANT_LINKED_GROUP_JOIN = 141; // any number of user jid params, list of participants accepted an add request from the recipient's group invite message 200 | 201 | EPHEMERAL_KEEP_IN_CHAT = 143; // message showed to user to let him know now keep a message is enabled 202 | } 203 | 204 | // When there is a race condition and the phone client renders the "i" button, the phone client should inform the web client by using the biz_privacy_status WebMessageInfo enum attribute and the verified_biz_name string value persisted on the phone client: 205 | // spec: doc/biz/privacy_transparency.md "Protocol Buffers" section 206 | enum BizPrivacyStatus { 207 | E2EE = 0; 208 | FB = 2; 209 | BSP = 1; 210 | BSP_AND_FB = 3 [deprecated=true]; 211 | } 212 | 213 | required MessageKey key = 1; 214 | optional Message message = 2; 215 | optional uint64 message_timestamp = 3; // in unixtime, client timestamp 216 | optional Status status = 4 [default = PENDING]; 217 | optional string participant = 5 [(jid) = true]; // message author, if MessageKey.remote_jid is a group 218 | /* 219 | in unixtime, server-assigned timestamp 220 | 221 | The primary device should only set this field for its own outgoing messages. 222 | Companion devices should save whatever value the primary device sets. 223 | 224 | The following cases help clarify how the primary device should and shouldn't 225 | set this field under various conditions. 226 | 227 | If `fromMe = True` (i.e., outgoing/incoming message from current account)... 228 | - (A) Status > PENDING (i.e., after server ack) 229 | - (A.1) Primary did save c2s timestamp (i.e., from ack or receipt). 230 | - Set `message_c2s_timestamp` with the saved value if it's different 231 | than the saved value for `message_timestamp`. 232 | - Note: For an incoming message from a companion, (A.1) indicates 233 | unoptimized behavior. 234 | - (A.2) Primary didn't save c2s timestamp. 235 | - Don't set `message_c2s_timestamp`. 236 | - Note: For an outgoing message from the primary, (A.2) indicates 237 | unexpected behavior or that c2s timestamps weren't saved by prior 238 | builds. 239 | - (B) Status <= PENDING 240 | - Don't set `message_c2s_timestamp`. 241 | 242 | If `fromMe = False` (i.e., incoming message from different account)... 243 | - (C) Don't set `message_c2s_timestamp`. 244 | */ 245 | optional uint64 message_c2s_timestamp = 6; 246 | 247 | optional bool ignore = 16; // previously 'invis' in xml 248 | optional bool starred = 17; 249 | optional bool broadcast = 18; // true if is a fanned-out broadcast message 250 | optional string push_name = 19; // push name, or previously 'notify' in xml 251 | optional bytes media_ciphertext_sha256 = 20; // nice to have for message forwarding 252 | optional bool multicast = 21; // if true, phone should include node on outgoing message 253 | optional bool url_text = 22; // true indicates the message used the text arg of whatsapp://send link; include node 254 | optional bool url_number = 23; // true indicates the message used the number arg of whatsapp:// send link; include node 255 | optional StubType message_stub_type = 24; // this field should be set if Message is not present 256 | optional bool clear_media = 25; // used only with revoke; if true, phone should also delete media file 257 | repeated string message_stub_parameters = 26; // ordered list of params for template StubTypes 258 | optional uint32 duration = 27; // live location message duration in seconds 259 | repeated string labels = 28; // list of label ids that this message is tagged with 260 | optional PaymentInfo payment_info = 29; // payment info if Message is a SendPaymentMessage or RequestPaymentMessage or StubType.PAYMENT_CIPHERTEXT/FUTUREPROOF 261 | optional Message.LiveLocationMessage final_live_location = 30; // final location data for a live location message 262 | optional PaymentInfo quoted_payment_info = 31; // payment info for a quoted SendPaymentMessage or RequestPaymentMessage 263 | optional uint64 ephemeral_start_timestamp = 32; // server ack timestamp in unixtime, required only for messages from me 264 | optional uint32 ephemeral_duration = 33 [deprecated=true]; // required only for messages without duration in the Message protobuf (e.g. broadcast list, from old clients) 265 | optional bool ephemeral_off_to_on = 34 [deprecated=true]; // required only for EPHEMERAL_SETTING ProtocolMessage, used for displaying the right type of system message 266 | optional bool ephemeral_out_of_sync = 35; // whether the message should display the ephemeral info button 267 | optional BizPrivacyStatus biz_privacy_status = 36; // privacy status of the message when it is out of sync with the one shown in system messages 268 | optional string verified_biz_name = 37; // business name used when biz_privacy_status is present. business name can change and phone persist it for specific messages 269 | optional MediaData media_data = 38; // Media data for media files - some extra data which is not serialized in E2E messages 270 | optional PhotoChange photo_change = 39; // photo change object for changed group icon 271 | repeated UserReceipt user_receipt = 40; // Message's user receipt (one per user), for cross platform migration only 272 | repeated Reaction reactions = 41; // Reactions to this message. This is for history sync only - the legacy web protocol does not support reactions. 273 | optional MediaData quoted_sticker_data = 42; // Quoted sticker data - some extra data which is not serialized in E2E messages. This is used for x-migration and only for quoted stickers 274 | optional bytes futureproof_data = 43; // For StubType.FUTUREPROOF, for cross platform migration only 275 | optional StatusPSA status_psa = 44; // status_psa object for statusv3 messages 276 | optional string agent_id = 47; // uuid for agents, generally associated with companion devices. See https://docs.google.com/document/d/1TZwbr2U8jgEShaiA418wRlftgz-FoW39YLUk3OTQIXY/edit# 277 | optional KeepInChat keep_in_chat = 50; // info related to any keep in chat. only for ephemeral messages 278 | } 279 | 280 | message PaymentInfo { 281 | enum Currency { 282 | UNKNOWN_CURRENCY = 0 [deprecated=true]; // shouldn't be used 283 | INR = 1 [deprecated=true]; // indian rupee 284 | } 285 | enum Status { 286 | UNKNOWN_STATUS = 0 [deprecated=true]; 287 | PROCESSING = 1 [deprecated=true]; 288 | SENT = 2 [deprecated=true]; 289 | NEED_TO_ACCEPT = 3 [deprecated=true]; 290 | COMPLETE = 4 [deprecated=true]; 291 | COULD_NOT_COMPLETE = 5 [deprecated=true]; 292 | REFUNDED = 6 [deprecated=true]; 293 | EXPIRED = 7 [deprecated=true]; 294 | REJECTED = 8 [deprecated=true]; 295 | CANCELLED = 9 [deprecated=true]; 296 | WAITING_FOR_PAYER = 10 [deprecated=true]; 297 | WAITING = 11 [deprecated=true]; 298 | } 299 | enum TxnStatus { 300 | UNKNOWN = 0; // non-server status 301 | PENDING_SETUP = 1; 302 | PENDING_RECEIVER_SETUP = 2; 303 | INIT = 3; // non-server status 304 | SUCCESS = 4; 305 | COMPLETED = 5; 306 | FAILED = 6; 307 | FAILED_RISK = 7; 308 | FAILED_PROCESSING = 8; 309 | FAILED_RECEIVER_PROCESSING = 9; 310 | FAILED_DA = 10; 311 | FAILED_DA_FINAL = 11; 312 | REFUNDED_TXN = 12; // REFUNDED 313 | REFUND_FAILED = 13; 314 | REFUND_FAILED_PROCESSING = 14; 315 | REFUND_FAILED_DA = 15; 316 | EXPIRED_TXN = 16; // EXPIRED 317 | AUTH_CANCELED = 17; 318 | AUTH_CANCEL_FAILED_PROCESSING = 18; 319 | AUTH_CANCEL_FAILED = 19; 320 | COLLECT_INIT = 20; // non-server status 321 | COLLECT_SUCCESS = 21; 322 | COLLECT_FAILED = 22; 323 | COLLECT_FAILED_RISK = 23; 324 | COLLECT_REJECTED = 24; 325 | COLLECT_EXPIRED = 25; 326 | COLLECT_CANCELED = 26; // non-server status 327 | COLLECT_CANCELLING = 27; // non-server status 328 | IN_REVIEW = 28; 329 | REVERSAL_SUCCESS = 29; 330 | REVERSAL_PENDING = 30; 331 | REFUND_PENDING = 31; 332 | } 333 | optional Currency currency_deprecated = 1 [deprecated=true]; 334 | optional uint64 amount_1000 = 2; // This will be deprecated -- payment amount *1000 to account for decimal place 335 | optional string receiver_jid = 3 [(jid) = true]; 336 | optional Status status = 4 [deprecated=true]; 337 | optional uint64 transaction_timestamp = 5; 338 | optional MessageKey request_message_key = 6; 339 | optional uint64 expiry_timestamp = 7; 340 | optional bool futureproofed = 8; 341 | optional string currency = 9; // This will be deprecated -- 3-character ISO 4217 currency code (USD, INR, MXN, ...) 342 | optional TxnStatus txn_status = 10; 343 | 344 | 345 | // In the case of a cross border transaction with Novi the primaryAmount could differ from the secondaryAmount both in number and currency. 346 | // For x-border transactions: 347 | // 387.67 Mexico peso should be displayed as "$387.67 MXN" regardless user device's locale. 348 | // For domestic transactions: 349 | // 387.67 Mexico peso could be displayed as "$387.67" if user device's locale is Mexico, but displayed as "$MX387.67" if user device's locale is not. 350 | optional bool use_novi_fiat_format = 11; // whether we should render the currency as cross-border 351 | 352 | optional Money primary_amount = 12; 353 | // For normal non-novi transactions we may only need the primary amount and can forgo the exchange_amount. 354 | optional Money exchange_amount = 13; 355 | } 356 | 357 | message WebNotificationsInfo { 358 | optional uint64 timestamp = 2; // in unixtime 359 | optional uint32 unread_chats = 3; 360 | optional uint32 notify_message_count = 4; 361 | repeated WebMessageInfo notify_messages = 5; 362 | } 363 | 364 | message NotificationMessageInfo { 365 | optional MessageKey key = 1; 366 | optional Message message = 2; // to limit the msg content, phone client could trim the jpeg_thumbnail and context_info fields out of msg content, which should be the biggest parts of msg that are unnecessary for notification display 367 | optional uint64 message_timestamp = 3; // in unixtime 368 | optional string participant = 4 [(jid) = true]; // message author, if MessageKey.remote_jid is a group 369 | } 370 | 371 | // fields in WebFeatures *MUST* only be of the Flag enum type 372 | message WebFeatures { 373 | enum Flag { 374 | NOT_STARTED = 0; // feature not yet started, equivalent to not setting the field 375 | FORCE_UPGRADE = 1; // feature is backward incompatible, force web client upgrade (confirm with web team before using this value) 376 | DEVELOPMENT = 2; // feature in development, enables the feature in dev 377 | PRODUCTION = 3; // feature ready for production, enables the feature in prod 378 | } 379 | optional Flag labels_display = 1; 380 | optional Flag voip_individual_outgoing = 2; 381 | optional Flag groups_v3 = 3; 382 | optional Flag groups_v3_create = 4; 383 | optional Flag change_number_v2 = 5; 384 | optional Flag query_status_v3_thumbnail = 6; 385 | optional Flag live_locations = 7; 386 | optional Flag query_vname = 8; 387 | optional Flag voip_individual_incoming = 9; 388 | optional Flag quick_replies_query = 10; // quick_replies_ranking and quick_replies_attachment are not in v1 of the quick replies spec 389 | optional Flag payments = 11; 390 | optional Flag sticker_pack_query = 12; // Query for 1st party sticker packs 391 | optional Flag live_locations_final = 13; 392 | optional Flag labels_edit = 14; 393 | optional Flag media_upload = 15; 394 | //optional Flag deprecated_16 = 16; 395 | //optional Flag deprecated_17 = 17; 396 | optional Flag media_upload_rich_quick_replies = 18; 397 | optional Flag vname_v2 = 19; 398 | optional Flag video_playback_url = 20; 399 | optional Flag status_ranking = 21; 400 | optional Flag voip_individual_video = 22; 401 | optional Flag third_party_stickers = 23; // Sticker pack query supports 3rd party sticker packs 402 | optional Flag frequently_forwarded_setting = 24; 403 | optional Flag groups_v4_join_permission = 25; 404 | optional Flag recent_stickers = 26; 405 | optional Flag catalog = 27; 406 | optional Flag starred_stickers = 28; 407 | optional Flag voip_group_call = 29; 408 | optional Flag template_message = 30; 409 | optional Flag template_message_interactivity = 31; 410 | optional Flag ephemeral_messages = 32; 411 | optional Flag e2e_notification_sync = 33; 412 | optional Flag recent_stickers_v2 = 34; // We need to fix a bug for web clients T64193302 413 | //optional Flag deprecated_35 = 35; 414 | optional Flag recent_stickers_v3 = 36; // This is for Android launch 415 | optional Flag user_notice = 37; // This is for Privacy Policy and Terms of Service update 416 | //optional Flag deprecated_38 = 38; 417 | optional Flag support = 39; // This is for enabling In App Support groups 418 | optional Flag group_uii_cleanup = 40; // This is for enabling group uii cleanup on web. We will use FORCE_UPGRADE when enabling this flag 419 | optional Flag group_dogfooding_internal_only = 41; // This is only used for internal fbid group dogfooding. Phone should set val to DEVELOPMENT when accompany AB prop is enabled. 420 | optional Flag settings_sync = 42; // This is for syncing the settings between Phone and Web clients 421 | optional Flag archive_v2 = 43; // This is for enabling Archive 2.0 422 | optional Flag ephemeral_allow_group_members = 44; // Phone should set this flag to PRODUCTION if the ABProp `ephemeral_allow_group_members` is set to true 423 | optional Flag ephemeral_24h_duration = 45; // Phone should set this flag to PRODUCTION if the ABProp `ephemeral_24h_duration` is set to true 424 | optional Flag md_force_upgrade = 46; // Phone should set this flag to FORCE_UPGRADE if the ABProp 'md_force_web_upgrade' is set to true 425 | optional Flag disappearing_mode = 47; // This is for enabling disappearing mode on legacy web 426 | optional Flag external_md_opt_in_available = 48; // This is for enabling old web protocol initiated MD opt in 427 | optional Flag no_delete_message_time_limit = 49; // Phone should set this flag to PRODUCTION if the ABProp `no_delete_message_time_limit` is set to true 428 | } 429 | 430 | message MediaData { 431 | optional string local_path = 1; 432 | } 433 | 434 | message PhotoChange { 435 | optional bytes old_photo = 1; 436 | optional bytes new_photo = 2; 437 | optional uint32 new_photo_id = 3; 438 | } 439 | 440 | message StatusPSA { 441 | required string campaign_id = 44; // the PSA messages has one associated campaign id. See status_v3.txt. 442 | optional uint64 campaign_expiration_timestamp = 45; // the PSA messages has one expiration timestamp. See status_v3.txt. 443 | } 444 | 445 | message UserReceipt { 446 | required string user_jid = 1 [(jid) = true]; 447 | optional int64 receipt_timestamp = 2; 448 | optional int64 read_timestamp = 3; 449 | optional int64 played_timestamp = 4; 450 | 451 | repeated string pending_device_jid = 5; 452 | repeated string delivered_device_jid = 6; 453 | } 454 | 455 | message Reaction { 456 | // Key for the reaction message. 457 | optional MessageKey key = 1; 458 | 459 | // This string should contain a single emoji with the content of the reaction. 460 | // Leave this field unset to remove a reaction. 461 | optional string text = 2; 462 | 463 | // This string is used to group similar emoji. It is like text but without modifiers. 464 | optional string grouping_key = 3; 465 | 466 | // Client-assigned timestamp (milliseconds since 1970). 467 | // Use this to order reactions from the same user. 468 | // This should be set to MAX(last_sender_timestamp_ms + 1, current_server_adjusted_time) (see reactions.md#editing for details) 469 | optional int64 sender_timestamp_ms = 4; 470 | 471 | // read state 472 | optional bool unread = 5; 473 | } 474 | 475 | message KeepInChat { 476 | //whether this is a keep for all 477 | optional KeepType keep_type = 1; 478 | //timestamp of the keep message 479 | optional int64 server_timestamp = 2; 480 | 481 | optional string kic_user = 3 [(jid) = true]; // JID of the user who last kept/un-kept this message from disappearing 482 | } 483 | 484 | -------------------------------------------------------------------------------- /google/protobuf/descriptor.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: kenton@google.com (Kenton Varda) 32 | // Based on original Protocol Buffers design by 33 | // Sanjay Ghemawat, Jeff Dean, and others. 34 | // 35 | // The messages in this file describe the definitions found in .proto files. 36 | // A valid .proto file can be translated directly to a FileDescriptorProto 37 | // without any other information (e.g. without reading its imports). 38 | 39 | 40 | syntax = "proto2"; 41 | 42 | package google.protobuf; 43 | option go_package = "descriptor"; 44 | option java_package = "com.google.protobuf"; 45 | option java_outer_classname = "DescriptorProtos"; 46 | option csharp_namespace = "Google.Protobuf.Reflection"; 47 | option objc_class_prefix = "GPB"; 48 | option java_generate_equals_and_hash = true; 49 | 50 | // descriptor.proto must be optimized for speed because reflection-based 51 | // algorithms don't work during bootstrapping. 52 | option optimize_for = SPEED; 53 | 54 | // The protocol compiler can output a FileDescriptorSet containing the .proto 55 | // files it parses. 56 | message FileDescriptorSet { 57 | repeated FileDescriptorProto file = 1; 58 | } 59 | 60 | // Describes a complete .proto file. 61 | message FileDescriptorProto { 62 | optional string name = 1; // file name, relative to root of source tree 63 | optional string package = 2; // e.g. "foo", "foo.bar", etc. 64 | 65 | // Names of files imported by this file. 66 | repeated string dependency = 3; 67 | // Indexes of the public imported files in the dependency list above. 68 | repeated int32 public_dependency = 10; 69 | // Indexes of the weak imported files in the dependency list. 70 | // For Google-internal migration only. Do not use. 71 | repeated int32 weak_dependency = 11; 72 | 73 | // All top-level definitions in this file. 74 | repeated DescriptorProto message_type = 4; 75 | repeated EnumDescriptorProto enum_type = 5; 76 | repeated ServiceDescriptorProto service = 6; 77 | repeated FieldDescriptorProto extension = 7; 78 | 79 | optional FileOptions options = 8; 80 | 81 | // This field contains optional information about the original source code. 82 | // You may safely remove this entire field without harming runtime 83 | // functionality of the descriptors -- the information is needed only by 84 | // development tools. 85 | optional SourceCodeInfo source_code_info = 9; 86 | 87 | // The syntax of the proto file. 88 | // The supported values are "proto2" and "proto3". 89 | optional string syntax = 12; 90 | } 91 | 92 | // Describes a message type. 93 | message DescriptorProto { 94 | optional string name = 1; 95 | 96 | repeated FieldDescriptorProto field = 2; 97 | repeated FieldDescriptorProto extension = 6; 98 | 99 | repeated DescriptorProto nested_type = 3; 100 | repeated EnumDescriptorProto enum_type = 4; 101 | 102 | message ExtensionRange { 103 | optional int32 start = 1; 104 | optional int32 end = 2; 105 | } 106 | repeated ExtensionRange extension_range = 5; 107 | 108 | repeated OneofDescriptorProto oneof_decl = 8; 109 | 110 | optional MessageOptions options = 7; 111 | 112 | // Range of reserved tag numbers. Reserved tag numbers may not be used by 113 | // fields or extension ranges in the same message. Reserved ranges may 114 | // not overlap. 115 | message ReservedRange { 116 | optional int32 start = 1; // Inclusive. 117 | optional int32 end = 2; // Exclusive. 118 | } 119 | repeated ReservedRange reserved_range = 9; 120 | // Reserved field names, which may not be used by fields in the same message. 121 | // A given name may only be reserved once. 122 | repeated string reserved_name = 10; 123 | } 124 | 125 | // Describes a field within a message. 126 | message FieldDescriptorProto { 127 | enum Type { 128 | // 0 is reserved for errors. 129 | // Order is weird for historical reasons. 130 | TYPE_DOUBLE = 1; 131 | TYPE_FLOAT = 2; 132 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if 133 | // negative values are likely. 134 | TYPE_INT64 = 3; 135 | TYPE_UINT64 = 4; 136 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if 137 | // negative values are likely. 138 | TYPE_INT32 = 5; 139 | TYPE_FIXED64 = 6; 140 | TYPE_FIXED32 = 7; 141 | TYPE_BOOL = 8; 142 | TYPE_STRING = 9; 143 | TYPE_GROUP = 10; // Tag-delimited aggregate. 144 | TYPE_MESSAGE = 11; // Length-delimited aggregate. 145 | 146 | // New in version 2. 147 | TYPE_BYTES = 12; 148 | TYPE_UINT32 = 13; 149 | TYPE_ENUM = 14; 150 | TYPE_SFIXED32 = 15; 151 | TYPE_SFIXED64 = 16; 152 | TYPE_SINT32 = 17; // Uses ZigZag encoding. 153 | TYPE_SINT64 = 18; // Uses ZigZag encoding. 154 | }; 155 | 156 | enum Label { 157 | // 0 is reserved for errors 158 | LABEL_OPTIONAL = 1; 159 | LABEL_REQUIRED = 2; 160 | LABEL_REPEATED = 3; 161 | // TODO(sanjay): Should we add LABEL_MAP? 162 | }; 163 | 164 | optional string name = 1; 165 | optional int32 number = 3; 166 | optional Label label = 4; 167 | 168 | // If type_name is set, this need not be set. If both this and type_name 169 | // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. 170 | optional Type type = 5; 171 | 172 | // For message and enum types, this is the name of the type. If the name 173 | // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping 174 | // rules are used to find the type (i.e. first the nested types within this 175 | // message are searched, then within the parent, on up to the root 176 | // namespace). 177 | optional string type_name = 6; 178 | 179 | // For extensions, this is the name of the type being extended. It is 180 | // resolved in the same manner as type_name. 181 | optional string extendee = 2; 182 | 183 | // For numeric types, contains the original text representation of the value. 184 | // For booleans, "true" or "false". 185 | // For strings, contains the default text contents (not escaped in any way). 186 | // For bytes, contains the C escaped value. All bytes >= 128 are escaped. 187 | // TODO(kenton): Base-64 encode? 188 | optional string default_value = 7; 189 | 190 | // If set, gives the index of a oneof in the containing type's oneof_decl 191 | // list. This field is a member of that oneof. 192 | optional int32 oneof_index = 9; 193 | 194 | // JSON name of this field. The value is set by protocol compiler. If the 195 | // user has set a "json_name" option on this field, that option's value 196 | // will be used. Otherwise, it's deduced from the field's name by converting 197 | // it to camelCase. 198 | optional string json_name = 10; 199 | 200 | optional FieldOptions options = 8; 201 | } 202 | 203 | // Describes a oneof. 204 | message OneofDescriptorProto { 205 | optional string name = 1; 206 | optional OneofOptions options = 2; 207 | } 208 | 209 | // Describes an enum type. 210 | message EnumDescriptorProto { 211 | optional string name = 1; 212 | 213 | repeated EnumValueDescriptorProto value = 2; 214 | 215 | optional EnumOptions options = 3; 216 | } 217 | 218 | // Describes a value within an enum. 219 | message EnumValueDescriptorProto { 220 | optional string name = 1; 221 | optional int32 number = 2; 222 | 223 | optional EnumValueOptions options = 3; 224 | } 225 | 226 | // Describes a service. 227 | message ServiceDescriptorProto { 228 | optional string name = 1; 229 | repeated MethodDescriptorProto method = 2; 230 | 231 | optional ServiceOptions options = 3; 232 | } 233 | 234 | // Describes a method of a service. 235 | message MethodDescriptorProto { 236 | optional string name = 1; 237 | 238 | // Input and output type names. These are resolved in the same way as 239 | // FieldDescriptorProto.type_name, but must refer to a message type. 240 | optional string input_type = 2; 241 | optional string output_type = 3; 242 | 243 | optional MethodOptions options = 4; 244 | 245 | // Identifies if client streams multiple client messages 246 | optional bool client_streaming = 5 [default=false]; 247 | // Identifies if server streams multiple server messages 248 | optional bool server_streaming = 6 [default=false]; 249 | } 250 | 251 | 252 | // =================================================================== 253 | // Options 254 | 255 | // Each of the definitions above may have "options" attached. These are 256 | // just annotations which may cause code to be generated slightly differently 257 | // or may contain hints for code that manipulates protocol messages. 258 | // 259 | // Clients may define custom options as extensions of the *Options messages. 260 | // These extensions may not yet be known at parsing time, so the parser cannot 261 | // store the values in them. Instead it stores them in a field in the *Options 262 | // message called uninterpreted_option. This field must have the same name 263 | // across all *Options messages. We then use this field to populate the 264 | // extensions when we build a descriptor, at which point all protos have been 265 | // parsed and so all extensions are known. 266 | // 267 | // Extension numbers for custom options may be chosen as follows: 268 | // * For options which will only be used within a single application or 269 | // organization, or for experimental options, use field numbers 50000 270 | // through 99999. It is up to you to ensure that you do not use the 271 | // same number for multiple options. 272 | // * For options which will be published and used publicly by multiple 273 | // independent entities, e-mail protobuf-global-extension-registry@google.com 274 | // to reserve extension numbers. Simply provide your project name (e.g. 275 | // Objective-C plugin) and your project website (if available) -- there's no 276 | // need to explain how you intend to use them. Usually you only need one 277 | // extension number. You can declare multiple options with only one extension 278 | // number by putting them in a sub-message. See the Custom Options section of 279 | // the docs for examples: 280 | // https://developers.google.com/protocol-buffers/docs/proto#options 281 | // If this turns out to be popular, a web service will be set up 282 | // to automatically assign option numbers. 283 | 284 | 285 | message FileOptions { 286 | 287 | // Sets the Java package where classes generated from this .proto will be 288 | // placed. By default, the proto package is used, but this is often 289 | // inappropriate because proto packages do not normally start with backwards 290 | // domain names. 291 | optional string java_package = 1; 292 | 293 | 294 | // If set, all the classes from the .proto file are wrapped in a single 295 | // outer class with the given name. This applies to both Proto1 296 | // (equivalent to the old "--one_java_file" option) and Proto2 (where 297 | // a .proto always translates to a single class, but you may want to 298 | // explicitly choose the class name). 299 | optional string java_outer_classname = 8; 300 | 301 | // If set true, then the Java code generator will generate a separate .java 302 | // file for each top-level message, enum, and service defined in the .proto 303 | // file. Thus, these types will *not* be nested inside the outer class 304 | // named by java_outer_classname. However, the outer class will still be 305 | // generated to contain the file's getDescriptor() method as well as any 306 | // top-level extensions defined in the file. 307 | optional bool java_multiple_files = 10 [default=false]; 308 | 309 | // If set true, then the Java code generator will generate equals() and 310 | // hashCode() methods for all messages defined in the .proto file. 311 | // This increases generated code size, potentially substantially for large 312 | // protos, which may harm a memory-constrained application. 313 | // - In the full runtime this is a speed optimization, as the 314 | // AbstractMessage base class includes reflection-based implementations of 315 | // these methods. 316 | // - In the lite runtime, setting this option changes the semantics of 317 | // equals() and hashCode() to more closely match those of the full runtime; 318 | // the generated methods compute their results based on field values rather 319 | // than object identity. (Implementations should not assume that hashcodes 320 | // will be consistent across runtimes or versions of the protocol compiler.) 321 | optional bool java_generate_equals_and_hash = 20 [default=false]; 322 | 323 | // If set true, then the Java2 code generator will generate code that 324 | // throws an exception whenever an attempt is made to assign a non-UTF-8 325 | // byte sequence to a string field. 326 | // Message reflection will do the same. 327 | // However, an extension field still accepts non-UTF-8 byte sequences. 328 | // This option has no effect on when used with the lite runtime. 329 | optional bool java_string_check_utf8 = 27 [default=false]; 330 | 331 | 332 | // Generated classes can be optimized for speed or code size. 333 | enum OptimizeMode { 334 | SPEED = 1; // Generate complete code for parsing, serialization, 335 | // etc. 336 | CODE_SIZE = 2; // Use ReflectionOps to implement these methods. 337 | LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. 338 | } 339 | optional OptimizeMode optimize_for = 9 [default=SPEED]; 340 | 341 | // Sets the Go package where structs generated from this .proto will be 342 | // placed. If omitted, the Go package will be derived from the following: 343 | // - The basename of the package import path, if provided. 344 | // - Otherwise, the package statement in the .proto file, if present. 345 | // - Otherwise, the basename of the .proto file, without extension. 346 | optional string go_package = 11; 347 | 348 | 349 | 350 | // Should generic services be generated in each language? "Generic" services 351 | // are not specific to any particular RPC system. They are generated by the 352 | // main code generators in each language (without additional plugins). 353 | // Generic services were the only kind of service generation supported by 354 | // early versions of google.protobuf. 355 | // 356 | // Generic services are now considered deprecated in favor of using plugins 357 | // that generate code specific to your particular RPC system. Therefore, 358 | // these default to false. Old code which depends on generic services should 359 | // explicitly set them to true. 360 | optional bool cc_generic_services = 16 [default=false]; 361 | optional bool java_generic_services = 17 [default=false]; 362 | optional bool py_generic_services = 18 [default=false]; 363 | 364 | // Is this file deprecated? 365 | // Depending on the target platform, this can emit Deprecated annotations 366 | // for everything in the file, or it will be completely ignored; in the very 367 | // least, this is a formalization for deprecating files. 368 | optional bool deprecated = 23 [default=false]; 369 | 370 | // Enables the use of arenas for the proto messages in this file. This applies 371 | // only to generated classes for C++. 372 | optional bool cc_enable_arenas = 31 [default=false]; 373 | 374 | 375 | // Sets the objective c class prefix which is prepended to all objective c 376 | // generated classes from this .proto. There is no default. 377 | optional string objc_class_prefix = 36; 378 | 379 | // Namespace for generated classes; defaults to the package. 380 | optional string csharp_namespace = 37; 381 | 382 | // The parser stores options it doesn't recognize here. See above. 383 | repeated UninterpretedOption uninterpreted_option = 999; 384 | 385 | // Clients can define custom options in extensions of this message. See above. 386 | extensions 1000 to max; 387 | 388 | reserved 38; 389 | } 390 | 391 | message MessageOptions { 392 | // Set true to use the old proto1 MessageSet wire format for extensions. 393 | // This is provided for backwards-compatibility with the MessageSet wire 394 | // format. You should not use this for any other reason: It's less 395 | // efficient, has fewer features, and is more complicated. 396 | // 397 | // The message must be defined exactly as follows: 398 | // message Foo { 399 | // option message_set_wire_format = true; 400 | // extensions 4 to max; 401 | // } 402 | // Note that the message cannot have any defined fields; MessageSets only 403 | // have extensions. 404 | // 405 | // All extensions of your type must be singular messages; e.g. they cannot 406 | // be int32s, enums, or repeated messages. 407 | // 408 | // Because this is an option, the above two restrictions are not enforced by 409 | // the protocol compiler. 410 | optional bool message_set_wire_format = 1 [default=false]; 411 | 412 | // Disables the generation of the standard "descriptor()" accessor, which can 413 | // conflict with a field of the same name. This is meant to make migration 414 | // from proto1 easier; new code should avoid fields named "descriptor". 415 | optional bool no_standard_descriptor_accessor = 2 [default=false]; 416 | 417 | // Is this message deprecated? 418 | // Depending on the target platform, this can emit Deprecated annotations 419 | // for the message, or it will be completely ignored; in the very least, 420 | // this is a formalization for deprecating messages. 421 | optional bool deprecated = 3 [default=false]; 422 | 423 | // Whether the message is an automatically generated map entry type for the 424 | // maps field. 425 | // 426 | // For maps fields: 427 | // map map_field = 1; 428 | // The parsed descriptor looks like: 429 | // message MapFieldEntry { 430 | // option map_entry = true; 431 | // optional KeyType key = 1; 432 | // optional ValueType value = 2; 433 | // } 434 | // repeated MapFieldEntry map_field = 1; 435 | // 436 | // Implementations may choose not to generate the map_entry=true message, but 437 | // use a native map in the target language to hold the keys and values. 438 | // The reflection APIs in such implementions still need to work as 439 | // if the field is a repeated message field. 440 | // 441 | // NOTE: Do not set the option in .proto files. Always use the maps syntax 442 | // instead. The option should only be implicitly set by the proto compiler 443 | // parser. 444 | optional bool map_entry = 7; 445 | 446 | // The parser stores options it doesn't recognize here. See above. 447 | repeated UninterpretedOption uninterpreted_option = 999; 448 | 449 | // Clients can define custom options in extensions of this message. See above. 450 | extensions 1000 to max; 451 | } 452 | 453 | message FieldOptions { 454 | // The ctype option instructs the C++ code generator to use a different 455 | // representation of the field than it normally would. See the specific 456 | // options below. This option is not yet implemented in the open source 457 | // release -- sorry, we'll try to include it in a future version! 458 | optional CType ctype = 1 [default = STRING]; 459 | enum CType { 460 | // Default mode. 461 | STRING = 0; 462 | 463 | CORD = 1; 464 | 465 | STRING_PIECE = 2; 466 | } 467 | // The packed option can be enabled for repeated primitive fields to enable 468 | // a more efficient representation on the wire. Rather than repeatedly 469 | // writing the tag and type for each element, the entire array is encoded as 470 | // a single length-delimited blob. In proto3, only explicit setting it to 471 | // false will avoid using packed encoding. 472 | optional bool packed = 2; 473 | 474 | 475 | // The jstype option determines the JavaScript type used for values of the 476 | // field. The option is permitted only for 64 bit integral and fixed types 477 | // (int64, uint64, sint64, fixed64, sfixed64). By default these types are 478 | // represented as JavaScript strings. This avoids loss of precision that can 479 | // happen when a large value is converted to a floating point JavaScript 480 | // numbers. Specifying JS_NUMBER for the jstype causes the generated 481 | // JavaScript code to use the JavaScript "number" type instead of strings. 482 | // This option is an enum to permit additional types to be added, 483 | // e.g. goog.math.Integer. 484 | optional JSType jstype = 6 [default = JS_NORMAL]; 485 | enum JSType { 486 | // Use the default type. 487 | JS_NORMAL = 0; 488 | 489 | // Use JavaScript strings. 490 | JS_STRING = 1; 491 | 492 | // Use JavaScript numbers. 493 | JS_NUMBER = 2; 494 | } 495 | 496 | // Should this field be parsed lazily? Lazy applies only to message-type 497 | // fields. It means that when the outer message is initially parsed, the 498 | // inner message's contents will not be parsed but instead stored in encoded 499 | // form. The inner message will actually be parsed when it is first accessed. 500 | // 501 | // This is only a hint. Implementations are free to choose whether to use 502 | // eager or lazy parsing regardless of the value of this option. However, 503 | // setting this option true suggests that the protocol author believes that 504 | // using lazy parsing on this field is worth the additional bookkeeping 505 | // overhead typically needed to implement it. 506 | // 507 | // This option does not affect the public interface of any generated code; 508 | // all method signatures remain the same. Furthermore, thread-safety of the 509 | // interface is not affected by this option; const methods remain safe to 510 | // call from multiple threads concurrently, while non-const methods continue 511 | // to require exclusive access. 512 | // 513 | // 514 | // Note that implementations may choose not to check required fields within 515 | // a lazy sub-message. That is, calling IsInitialized() on the outher message 516 | // may return true even if the inner message has missing required fields. 517 | // This is necessary because otherwise the inner message would have to be 518 | // parsed in order to perform the check, defeating the purpose of lazy 519 | // parsing. An implementation which chooses not to check required fields 520 | // must be consistent about it. That is, for any particular sub-message, the 521 | // implementation must either *always* check its required fields, or *never* 522 | // check its required fields, regardless of whether or not the message has 523 | // been parsed. 524 | optional bool lazy = 5 [default=false]; 525 | 526 | // Is this field deprecated? 527 | // Depending on the target platform, this can emit Deprecated annotations 528 | // for accessors, or it will be completely ignored; in the very least, this 529 | // is a formalization for deprecating fields. 530 | optional bool deprecated = 3 [default=false]; 531 | 532 | // For Google-internal migration only. Do not use. 533 | optional bool weak = 10 [default=false]; 534 | 535 | 536 | // The parser stores options it doesn't recognize here. See above. 537 | repeated UninterpretedOption uninterpreted_option = 999; 538 | 539 | // Clients can define custom options in extensions of this message. See above. 540 | extensions 1000 to max; 541 | } 542 | 543 | message OneofOptions { 544 | // The parser stores options it doesn't recognize here. See above. 545 | repeated UninterpretedOption uninterpreted_option = 999; 546 | 547 | // Clients can define custom options in extensions of this message. See above. 548 | extensions 1000 to max; 549 | } 550 | 551 | message EnumOptions { 552 | 553 | // Set this option to true to allow mapping different tag names to the same 554 | // value. 555 | optional bool allow_alias = 2; 556 | 557 | // Is this enum deprecated? 558 | // Depending on the target platform, this can emit Deprecated annotations 559 | // for the enum, or it will be completely ignored; in the very least, this 560 | // is a formalization for deprecating enums. 561 | optional bool deprecated = 3 [default=false]; 562 | 563 | // The parser stores options it doesn't recognize here. See above. 564 | repeated UninterpretedOption uninterpreted_option = 999; 565 | 566 | // Clients can define custom options in extensions of this message. See above. 567 | extensions 1000 to max; 568 | } 569 | 570 | message EnumValueOptions { 571 | // Is this enum value deprecated? 572 | // Depending on the target platform, this can emit Deprecated annotations 573 | // for the enum value, or it will be completely ignored; in the very least, 574 | // this is a formalization for deprecating enum values. 575 | optional bool deprecated = 1 [default=false]; 576 | 577 | // The parser stores options it doesn't recognize here. See above. 578 | repeated UninterpretedOption uninterpreted_option = 999; 579 | 580 | // Clients can define custom options in extensions of this message. See above. 581 | extensions 1000 to max; 582 | } 583 | 584 | message ServiceOptions { 585 | 586 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 587 | // framework. We apologize for hoarding these numbers to ourselves, but 588 | // we were already using them long before we decided to release Protocol 589 | // Buffers. 590 | 591 | // Is this service deprecated? 592 | // Depending on the target platform, this can emit Deprecated annotations 593 | // for the service, or it will be completely ignored; in the very least, 594 | // this is a formalization for deprecating services. 595 | optional bool deprecated = 33 [default=false]; 596 | 597 | // The parser stores options it doesn't recognize here. See above. 598 | repeated UninterpretedOption uninterpreted_option = 999; 599 | 600 | // Clients can define custom options in extensions of this message. See above. 601 | extensions 1000 to max; 602 | } 603 | 604 | message MethodOptions { 605 | 606 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 607 | // framework. We apologize for hoarding these numbers to ourselves, but 608 | // we were already using them long before we decided to release Protocol 609 | // Buffers. 610 | 611 | // Is this method deprecated? 612 | // Depending on the target platform, this can emit Deprecated annotations 613 | // for the method, or it will be completely ignored; in the very least, 614 | // this is a formalization for deprecating methods. 615 | optional bool deprecated = 33 [default=false]; 616 | 617 | // The parser stores options it doesn't recognize here. See above. 618 | repeated UninterpretedOption uninterpreted_option = 999; 619 | 620 | // Clients can define custom options in extensions of this message. See above. 621 | extensions 1000 to max; 622 | } 623 | 624 | 625 | // A message representing a option the parser does not recognize. This only 626 | // appears in options protos created by the compiler::Parser class. 627 | // DescriptorPool resolves these when building Descriptor objects. Therefore, 628 | // options protos in descriptor objects (e.g. returned by Descriptor::options(), 629 | // or produced by Descriptor::CopyTo()) will never have UninterpretedOptions 630 | // in them. 631 | message UninterpretedOption { 632 | // The name of the uninterpreted option. Each string represents a segment in 633 | // a dot-separated name. is_extension is true iff a segment represents an 634 | // extension (denoted with parentheses in options specs in .proto files). 635 | // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents 636 | // "foo.(bar.baz).qux". 637 | message NamePart { 638 | required string name_part = 1; 639 | required bool is_extension = 2; 640 | } 641 | repeated NamePart name = 2; 642 | 643 | // The value of the uninterpreted option, in whatever type the tokenizer 644 | // identified it as during parsing. Exactly one of these should be set. 645 | optional string identifier_value = 3; 646 | optional uint64 positive_int_value = 4; 647 | optional int64 negative_int_value = 5; 648 | optional double double_value = 6; 649 | optional bytes string_value = 7; 650 | optional string aggregate_value = 8; 651 | } 652 | 653 | // =================================================================== 654 | // Optional source code info 655 | 656 | // Encapsulates information about the original source file from which a 657 | // FileDescriptorProto was generated. 658 | message SourceCodeInfo { 659 | // A Location identifies a piece of source code in a .proto file which 660 | // corresponds to a particular definition. This information is intended 661 | // to be useful to IDEs, code indexers, documentation generators, and similar 662 | // tools. 663 | // 664 | // For example, say we have a file like: 665 | // message Foo { 666 | // optional string foo = 1; 667 | // } 668 | // Let's look at just the field definition: 669 | // optional string foo = 1; 670 | // ^ ^^ ^^ ^ ^^^ 671 | // a bc de f ghi 672 | // We have the following locations: 673 | // span path represents 674 | // [a,i) [ 4, 0, 2, 0 ] The whole field definition. 675 | // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). 676 | // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). 677 | // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). 678 | // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). 679 | // 680 | // Notes: 681 | // - A location may refer to a repeated field itself (i.e. not to any 682 | // particular index within it). This is used whenever a set of elements are 683 | // logically enclosed in a single code segment. For example, an entire 684 | // extend block (possibly containing multiple extension definitions) will 685 | // have an outer location whose path refers to the "extensions" repeated 686 | // field without an index. 687 | // - Multiple locations may have the same path. This happens when a single 688 | // logical declaration is spread out across multiple places. The most 689 | // obvious example is the "extend" block again -- there may be multiple 690 | // extend blocks in the same scope, each of which will have the same path. 691 | // - A location's span is not always a subset of its parent's span. For 692 | // example, the "extendee" of an extension declaration appears at the 693 | // beginning of the "extend" block and is shared by all extensions within 694 | // the block. 695 | // - Just because a location's span is a subset of some other location's span 696 | // does not mean that it is a descendent. For example, a "group" defines 697 | // both a type and a field in a single declaration. Thus, the locations 698 | // corresponding to the type and field and their components will overlap. 699 | // - Code which tries to interpret locations should probably be designed to 700 | // ignore those that it doesn't understand, as more types of locations could 701 | // be recorded in the future. 702 | repeated Location location = 1; 703 | message Location { 704 | // Identifies which part of the FileDescriptorProto was defined at this 705 | // location. 706 | // 707 | // Each element is a field number or an index. They form a path from 708 | // the root FileDescriptorProto to the place where the definition. For 709 | // example, this path: 710 | // [ 4, 3, 2, 7, 1 ] 711 | // refers to: 712 | // file.message_type(3) // 4, 3 713 | // .field(7) // 2, 7 714 | // .name() // 1 715 | // This is because FileDescriptorProto.message_type has field number 4: 716 | // repeated DescriptorProto message_type = 4; 717 | // and DescriptorProto.field has field number 2: 718 | // repeated FieldDescriptorProto field = 2; 719 | // and FieldDescriptorProto.name has field number 1: 720 | // optional string name = 1; 721 | // 722 | // Thus, the above path gives the location of a field name. If we removed 723 | // the last element: 724 | // [ 4, 3, 2, 7 ] 725 | // this path refers to the whole field declaration (from the beginning 726 | // of the label to the terminating semicolon). 727 | repeated int32 path = 1 [packed=true]; 728 | 729 | // Always has exactly three or four elements: start line, start column, 730 | // end line (optional, otherwise assumed same as start line), end column. 731 | // These are packed into a single field for efficiency. Note that line 732 | // and column numbers are zero-based -- typically you will want to add 733 | // 1 to each before displaying to a user. 734 | repeated int32 span = 2 [packed=true]; 735 | 736 | // If this SourceCodeInfo represents a complete declaration, these are any 737 | // comments appearing before and after the declaration which appear to be 738 | // attached to the declaration. 739 | // 740 | // A series of line comments appearing on consecutive lines, with no other 741 | // tokens appearing on those lines, will be treated as a single comment. 742 | // 743 | // leading_detached_comments will keep paragraphs of comments that appear 744 | // before (but not connected to) the current element. Each paragraph, 745 | // separated by empty lines, will be one comment element in the repeated 746 | // field. 747 | // 748 | // Only the comment content is provided; comment markers (e.g. //) are 749 | // stripped out. For block comments, leading whitespace and an asterisk 750 | // will be stripped from the beginning of each line other than the first. 751 | // Newlines are included in the output. 752 | // 753 | // Examples: 754 | // 755 | // optional int32 foo = 1; // Comment attached to foo. 756 | // // Comment attached to bar. 757 | // optional int32 bar = 2; 758 | // 759 | // optional string baz = 3; 760 | // // Comment attached to baz. 761 | // // Another line attached to baz. 762 | // 763 | // // Comment attached to qux. 764 | // // 765 | // // Another line attached to qux. 766 | // optional double qux = 4; 767 | // 768 | // // Detached comment for corge. This is not leading or trailing comments 769 | // // to qux or corge because there are blank lines separating it from 770 | // // both. 771 | // 772 | // // Detached comment for corge paragraph 2. 773 | // 774 | // optional string corge = 5; 775 | // /* Block comment attached 776 | // * to corge. Leading asterisks 777 | // * will be removed. */ 778 | // /* Block comment attached to 779 | // * grault. */ 780 | // optional int32 grault = 6; 781 | // 782 | // // ignored detached comments. 783 | optional string leading_comments = 3; 784 | optional string trailing_comments = 4; 785 | repeated string leading_detached_comments = 6; 786 | } 787 | } 788 | 789 | // Describes the relationship between generated code and its original source 790 | // file. A GeneratedCodeInfo message is associated with only one generated 791 | // source file, but may contain references to different source .proto files. 792 | message GeneratedCodeInfo { 793 | // An Annotation connects some span of text in generated code to an element 794 | // of its generating .proto file. 795 | repeated Annotation annotation = 1; 796 | message Annotation { 797 | // Identifies the element in the original source .proto file. This field 798 | // is formatted the same as SourceCodeInfo.Location.path. 799 | repeated int32 path = 1 [packed=true]; 800 | 801 | // Identifies the filesystem path to the original source .proto. 802 | optional string source_file = 2; 803 | 804 | // Identifies the starting offset in bytes in the generated code 805 | // that relates to the identified object. 806 | optional int32 begin = 3; 807 | 808 | // Identifies the ending offset in bytes in the generated code that 809 | // relates to the identified offset. The end offset should be one past 810 | // the last relevant byte (so the length of the text = end - begin). 811 | optional int32 end = 4; 812 | } 813 | } 814 | -------------------------------------------------------------------------------- /e2e.proto: -------------------------------------------------------------------------------- 1 | package whatsapp; 2 | 3 | option java_package = "com.whatsapp.proto"; 4 | 5 | import "protocol.proto"; 6 | 7 | message Message { 8 | message SenderKeyDistributionMessage { 9 | optional string group_id = 1 [(jid) = true]; 10 | optional bytes axolotl_sender_key_distribution_message = 2; 11 | } 12 | message ImageMessage { 13 | optional string url = 1; 14 | optional string mimetype = 2; 15 | optional string caption = 3; 16 | optional bytes file_sha256 = 4; 17 | // Plaintext size of the file. Use for UI only, not validation, see media.txt 18 | optional uint64 file_length = 5; 19 | // refers to the display dimensions (rotation is applied if present) 20 | optional uint32 height = 6; 21 | optional uint32 width = 7; 22 | 23 | optional bytes media_key = 8; 24 | optional bytes file_enc_sha256 = 9; 25 | repeated InteractiveAnnotation interactive_annotations = 10; 26 | optional string direct_path = 11; 27 | optional int64 media_key_timestamp = 12; 28 | 29 | optional bytes jpeg_thumbnail = 16; 30 | optional ContextInfo context_info = 17; 31 | optional bytes first_scan_sidecar = 18 [deprecated=true]; 32 | optional uint32 first_scan_length = 19 [deprecated=true]; 33 | optional uint32 experiment_group_id = 20; 34 | optional bytes scans_sidecar = 21; 35 | repeated uint32 scan_lengths = 22; 36 | optional bytes mid_quality_file_sha256 = 23; 37 | optional bytes mid_quality_file_enc_sha256 = 24; 38 | optional bool view_once = 25; // See view_once_media.md 39 | optional string thumbnail_direct_path = 26; 40 | optional bytes thumbnail_sha256 = 27; 41 | optional bytes thumbnail_enc_sha256 = 28; 42 | 43 | optional string static_url = 29; // Use for static.whatsapp.net urls to serve PSA assets. See status_v3.txt. 44 | } 45 | 46 | message ContactMessage { 47 | optional string display_name = 1; 48 | 49 | optional string vcard = 16; // To be deprecated in the future in favor of explicit fields in this message. 50 | optional ContextInfo context_info = 17; 51 | } 52 | message LocationMessage { 53 | optional double degrees_latitude = 1; 54 | optional double degrees_longitude = 2; 55 | optional string name = 3; 56 | optional string address = 4; 57 | optional string url = 5; 58 | 59 | // live location information 60 | optional bool is_live = 6 [deprecated=true]; // indicate this message is for live location 61 | optional uint32 accuracy_in_meters = 7 [deprecated=true]; 62 | optional float speed_in_mps = 8 [deprecated=true]; // 2 digits after the decimal point 63 | optional uint32 degrees_clockwise_from_magnetic_north = 9 [deprecated=true]; 64 | optional string comment = 11 [deprecated=true]; 65 | 66 | optional bytes jpeg_thumbnail = 16; 67 | optional ContextInfo context_info = 17; 68 | } 69 | message ExtendedTextMessage { 70 | enum FontType { 71 | SANS_SERIF = 0; 72 | SERIF = 1; 73 | NORICAN_REGULAR = 2; 74 | BRYNDAN_WRITE = 3; 75 | BEBASNEUE_REGULAR = 4; 76 | OSWALD_HEAVY = 5; 77 | } 78 | optional string text = 1; 79 | optional string matched_text = 2; 80 | // string absolute_url had tag 3; removed 2015-10-28 81 | optional string canonical_url = 4; 82 | optional string description = 5; 83 | optional string title = 6; 84 | 85 | optional fixed32 text_argb = 7; 86 | optional fixed32 background_argb = 8; 87 | optional FontType font = 9; 88 | 89 | enum PreviewType { 90 | NONE = 0; 91 | VIDEO = 1; 92 | } 93 | optional PreviewType preview_type = 10; 94 | 95 | optional bytes jpeg_thumbnail = 16; 96 | optional ContextInfo context_info = 17; 97 | 98 | optional bool doNotPlayInline = 18 [deprecated=true]; 99 | 100 | optional string thumbnail_direct_path = 19; 101 | optional bytes thumbnail_sha256 = 20; 102 | optional bytes thumbnail_enc_sha256 = 21; 103 | optional bytes media_key = 22; 104 | optional int64 media_key_timestamp = 23; 105 | optional uint32 thumbnail_height = 24; 106 | optional uint32 thumbnail_width = 25; 107 | 108 | enum InviteLinkGroupType { 109 | DEFAULT = 0; // regular group with no linked subgroup 110 | PARENT = 1; 111 | } 112 | // Only used if the text message is a group invite link. 113 | // This is deprecated. Old clients can still send this, but should be ignored. 114 | // Use invite_link_group_type_v2 instead. 115 | optional InviteLinkGroupType invite_link_group_type = 26; 116 | 117 | optional string invite_link_parent_group_subject_v2 = 27; // Deprecated 118 | optional bytes invite_link_parent_group_thumbnail_v2 = 28; // Deprecated 119 | 120 | optional InviteLinkGroupType invite_link_group_type_v2 = 29; // Only used if the text message is a group invite link - Use in place of invite_link_group_type. 121 | } 122 | 123 | message DocumentMessage { 124 | optional string url = 1; 125 | optional string mimetype = 2; 126 | optional string title = 3; 127 | optional bytes file_sha256 = 4; 128 | // Plaintext size of the file. Use for UI only, not validation, see media.txt 129 | optional uint64 file_length = 5; 130 | optional uint32 page_count = 6; 131 | optional bytes media_key = 7; 132 | optional string file_name = 8; 133 | optional bytes file_enc_sha256 = 9; 134 | optional string direct_path = 10; 135 | optional int64 media_key_timestamp = 11; 136 | optional bool contact_vcard = 12; // whether message contains vCard sent by contacts flow 137 | optional string thumbnail_direct_path = 13; 138 | optional bytes thumbnail_sha256 = 14; 139 | optional bytes thumbnail_enc_sha256 = 15; 140 | optional bytes jpeg_thumbnail = 16; 141 | optional ContextInfo context_info = 17; 142 | optional uint32 thumbnail_height = 18; 143 | optional uint32 thumbnail_width = 19; 144 | } 145 | message AudioMessage { 146 | optional string url = 1; 147 | optional string mimetype = 2; 148 | optional bytes file_sha256 = 3; 149 | // Plaintext size of the file. Use for UI only, not validation, see media.txt 150 | optional uint64 file_length = 4; 151 | optional uint32 seconds = 5; 152 | optional bool ptt = 6; 153 | 154 | optional bytes media_key = 7; 155 | optional bytes file_enc_sha256 = 8; 156 | optional string direct_path = 9; 157 | optional int64 media_key_timestamp = 10; 158 | 159 | optional ContextInfo context_info = 17; 160 | optional bytes streaming_sidecar = 18; 161 | optional bytes waveform = 19; 162 | } 163 | message VideoMessage { 164 | enum Attribution { 165 | NONE = 0; 166 | GIPHY = 1; 167 | TENOR = 2; 168 | } 169 | optional string url = 1; 170 | optional string mimetype = 2; 171 | optional bytes file_sha256 = 3; 172 | // Plaintext size of the file. Use for UI only, not validation, see media.txt 173 | optional uint64 file_length = 4; 174 | optional uint32 seconds = 5; 175 | 176 | optional bytes media_key = 6; 177 | optional string caption = 7; 178 | // please upgrade to an enum if we get 179 | // more playback states 180 | optional bool gif_playback = 8; 181 | // refers to the display dimensions (rotation is applied if present) 182 | optional uint32 height = 9; 183 | optional uint32 width = 10; 184 | optional bytes file_enc_sha256 = 11; 185 | repeated InteractiveAnnotation interactive_annotations = 12; 186 | optional string direct_path = 13; 187 | optional int64 media_key_timestamp = 14; 188 | 189 | optional bytes jpeg_thumbnail = 16; 190 | optional ContextInfo context_info = 17; 191 | optional bytes streaming_sidecar = 18; 192 | optional Attribution gif_attribution = 19; 193 | optional bool view_once = 20; // See view_once_media.md 194 | optional string thumbnail_direct_path = 21; 195 | optional bytes thumbnail_sha256 = 22; 196 | optional bytes thumbnail_enc_sha256 = 23; 197 | 198 | optional string static_url = 24; // Use for static.whatsapp.net urls to serve PSA assets. See status_v3.txt. 199 | } 200 | message Call { 201 | optional bytes call_key = 1; 202 | 203 | // There conversion fields are used to pass CTWA ads conversion info for voice calls to a business 204 | optional string conversion_source = 2; 205 | optional bytes conversion_data = 3; 206 | optional uint32 conversion_delay_seconds = 4; 207 | } 208 | message Chat { 209 | optional string display_name = 1; // push name of the receiver of NFC message 210 | optional string id = 2; // id field from received NFC message 211 | } 212 | message ProtocolMessage { 213 | enum Type { 214 | REVOKE = 0; 215 | // PAYMENTS_DECLINE_REQUEST = 1; deprecated 2018-08-17 216 | // MD_PLACEHOLDER_UPDATE = 2; removed 2019/4/19; multidevice downgraded message placeholder update 217 | EPHEMERAL_SETTING = 3; 218 | EPHEMERAL_SYNC_RESPONSE = 4; 219 | // HISTORY_SYNC_NOTIFICATION is used for sending multidevice history sync payload 220 | // encryption keys and hash to companion 221 | HISTORY_SYNC_NOTIFICATION = 5; 222 | APP_STATE_SYNC_KEY_SHARE = 6; 223 | APP_STATE_SYNC_KEY_REQUEST = 7; 224 | MSG_FANOUT_BACKFILL_REQUEST = 8; 225 | INITIAL_SECURITY_NOTIFICATION_SETTING_SYNC = 9; 226 | APP_STATE_FATAL_EXCEPTION_NOTIFICATION = 10; 227 | } 228 | // Only present if type == REVOKE 229 | optional MessageKey key = 1; 230 | 231 | // Should be present for all ProtocolMessage 232 | optional Type type = 2; 233 | 234 | // optional Message content_update = 3; removed 2019/4/19; message update for multidevice downgraded message placeholder 235 | 236 | // Only present if type == EPHEMERAL_SETTING or type == EPHEMERAL_SYNC_RESPONSE. 237 | // Duration in seconds after which messages should be removed from the conversation 238 | // 0, or a missing value means that the conversation is not ephemeral anymore 239 | optional uint32 ephemeral_expiration = 4; 240 | 241 | // Only present if type == EPHEMERAL_SYNC_RESPONSE. 242 | // Epoch timestamp in seconds indicating when the ephemeral setting has been last changed 243 | optional int64 ephemeral_setting_timestamp = 5; 244 | 245 | // Only present if type == HISTORY_SYNC_NOTIFICATION. 246 | optional HistorySyncNotification history_sync_notification = 6; 247 | 248 | // Only present if type == APP_STATE_SYNC_KEY_SHARE. 249 | optional AppStateSyncKeyShare app_state_sync_key_share = 7; 250 | 251 | // Only present if type == APP_STATE_SYNC_KEY_REQUEST. 252 | optional AppStateSyncKeyRequest app_state_sync_key_request = 8; 253 | 254 | // Only present if type == INITIAL_SECURITY_NOTIFICATION_SETTING_SYNC. 255 | optional InitialSecurityNotificationSettingSync initial_security_notification_setting_sync = 9; 256 | 257 | // Only present if type == APP_STATE_FATAL_EXCEPTION_NOTIFICATION. 258 | // When app state is in fatal mode on companion and notify primary using it. 259 | optional AppStateFatalExceptionNotification app_state_fatal_exception_notification = 10; 260 | 261 | // Only present if type == EPHEMERAL_SYNC_RESPONSE 262 | optional DisappearingMode disappearing_mode = 11; 263 | } 264 | 265 | message HistorySyncNotification { 266 | enum HistorySyncType { 267 | INITIAL_BOOTSTRAP = 0; 268 | INITIAL_STATUS_V3 = 1; 269 | FULL = 2; 270 | RECENT = 3; 271 | PUSH_NAME = 4; 272 | } 273 | optional bytes file_sha256 = 1; 274 | // Plaintext size of the file. Use for UI only, not validation, see media.txt 275 | optional uint64 file_length = 2; 276 | optional bytes media_key = 3; 277 | optional bytes file_enc_sha256 = 4; 278 | optional string direct_path = 5; 279 | optional HistorySyncType sync_type = 6; 280 | // should not be provided for resend 281 | optional uint32 chunk_order = 7; 282 | // used with RESEND only to identify the original message 283 | optional string original_message_id = 8; 284 | } 285 | 286 | message AppStateSyncKey { 287 | optional AppStateSyncKeyId key_id = 1; 288 | optional AppStateSyncKeyData key_data = 2; 289 | } 290 | 291 | message AppStateSyncKeyId { 292 | optional bytes key_id = 1; 293 | } 294 | 295 | message AppStateSyncKeyFingerprint { 296 | optional uint32 raw_id = 1; 297 | optional uint32 current_index = 2; 298 | // List of `key_index` values currently stored in device table on the client including the author device itself 299 | repeated uint32 device_indexes = 3 [packed=true]; 300 | } 301 | 302 | message AppStateSyncKeyData { 303 | // Key bytes. 304 | optional bytes key_data = 1; 305 | // Additional information associated with the key that is used to resolve races key rotation and device list 306 | // changes. 307 | optional AppStateSyncKeyFingerprint fingerprint = 2; 308 | // Time when the key was created. 309 | optional int64 timestamp = 3; 310 | } 311 | 312 | message AppStateSyncKeyShare { 313 | repeated AppStateSyncKey keys = 1; 314 | } 315 | 316 | message AppStateSyncKeyRequest { 317 | repeated AppStateSyncKeyId key_ids = 1; 318 | } 319 | 320 | message AppStateFatalExceptionNotification { 321 | repeated string collection_names = 1; 322 | // Timestamp when the fatal error happened 323 | optional int64 timestamp = 2; 324 | } 325 | 326 | message InitialSecurityNotificationSettingSync { 327 | optional bool security_notification_enabled = 1; 328 | } 329 | 330 | message ContactsArrayMessage { 331 | optional string display_name = 1; 332 | repeated ContactMessage contacts = 2; 333 | 334 | optional ContextInfo context_info = 17; 335 | } 336 | message HighlyStructuredMessage { 337 | message HSMLocalizableParameter { 338 | message HSMCurrency { 339 | optional string currency_code = 1; 340 | optional int64 amount_1000 = 2; // 1000 times the desired amount to avoid floating point numbers 341 | } 342 | message HSMDateTime { 343 | message HSMDateTimeComponent { 344 | enum DayOfWeekType { 345 | MONDAY = 1; 346 | TUESDAY = 2; 347 | WEDNESDAY = 3; 348 | THURSDAY = 4; 349 | FRIDAY = 5; 350 | SATURDAY = 6; 351 | SUNDAY = 7; 352 | } 353 | enum CalendarType { 354 | GREGORIAN = 1; 355 | SOLAR_HIJRI = 2; 356 | } 357 | optional DayOfWeekType day_of_week = 1; // If different from the derived value from the date (if specified), use the derived value 358 | optional uint32 year = 2; 359 | optional uint32 month = 3; 360 | optional uint32 day_of_month = 4; 361 | optional uint32 hour = 5; 362 | optional uint32 minute = 6; 363 | optional CalendarType calendar = 7; 364 | } 365 | message HSMDateTimeUnixEpoch { 366 | optional int64 timestamp = 1; // epoch timestamp in seconds 367 | } 368 | oneof datetime_oneof { 369 | HSMDateTimeComponent component = 1; 370 | HSMDateTimeUnixEpoch unix_epoch = 2; 371 | } 372 | } 373 | optional string default = 1; 374 | oneof param_oneof { 375 | HSMCurrency currency = 2; 376 | HSMDateTime date_time = 3; 377 | } 378 | } 379 | optional string namespace = 1; 380 | optional string element_name = 2; 381 | repeated string params = 3; 382 | optional string fallback_lg = 4; 383 | optional string fallback_lc = 5; 384 | repeated HSMLocalizableParameter localizable_params = 6; 385 | optional string deterministic_lg = 7; 386 | optional string deterministic_lc = 8; 387 | optional TemplateMessage hydrated_hsm = 9; 388 | } 389 | message SendPaymentMessage { 390 | optional Message note_message = 2; 391 | optional MessageKey request_message_key = 3; 392 | optional PaymentBackground background = 4; 393 | } 394 | message RequestPaymentMessage { 395 | optional Message note_message = 4; 396 | optional string currency_code_iso4217 = 1; // To be deprecated in the future 397 | optional uint64 amount_1000 = 2; // To be deprecated in the future 398 | optional string request_from = 3; 399 | // 4 is used above with note_message based on the initial ordering assigned 400 | optional int64 expiry_timestamp = 5; // epoch timestamp in seconds 401 | optional Money amount = 6; 402 | optional PaymentBackground background = 7; 403 | } 404 | message DeclinePaymentRequestMessage { 405 | optional MessageKey key = 1; 406 | } 407 | message CancelPaymentRequestMessage { 408 | optional MessageKey key = 1; 409 | } 410 | message PaymentInviteMessage { 411 | enum ServiceType { 412 | UNKNOWN = 0; 413 | FBPAY = 1; 414 | NOVI = 2; 415 | UPI = 3; 416 | } 417 | optional ServiceType service_type = 1; // the service to which the invitation is sent 418 | optional int64 expiry_timestamp = 2; // epoch timestamp in seconds 419 | } 420 | message LiveLocationMessage { 421 | optional double degrees_latitude = 1; 422 | optional double degrees_longitude = 2; 423 | optional uint32 accuracy_in_meters = 3; 424 | optional float speed_in_mps = 4; // 2 digits after the decimal point 425 | optional uint32 degrees_clockwise_from_magnetic_north = 5; 426 | optional string caption = 6; 427 | optional int64 sequence_number = 7; 428 | optional uint32 time_offset = 8; // Used for final location updates. Seconds since sharing began. 429 | 430 | optional bytes jpeg_thumbnail = 16; 431 | optional ContextInfo context_info = 17; 432 | } 433 | message StickerMessage { 434 | optional string url = 1; 435 | optional bytes file_sha256 = 2; 436 | optional bytes file_enc_sha256 = 3; 437 | optional bytes media_key = 4; 438 | optional string mimetype = 5; 439 | optional uint32 height = 6; 440 | optional uint32 width = 7; 441 | optional string direct_path = 8; 442 | // Plaintext size of the file. Use for UI only, not validation, see media.txt 443 | optional uint64 file_length = 9; 444 | optional int64 media_key_timestamp = 10; 445 | 446 | optional uint32 first_frame_length = 11; //first frame location of animated sticker 447 | optional bytes first_frame_sidecar = 12; 448 | optional bool is_animated = 13; 449 | 450 | optional bytes png_thumbnail = 16 [deprecated=true]; 451 | optional ContextInfo context_info = 17; 452 | } 453 | message TemplateMessage { 454 | message FourRowTemplate { 455 | oneof title { 456 | DocumentMessage document_message = 1; 457 | HighlyStructuredMessage highly_structured_message = 2; 458 | ImageMessage image_message = 3; 459 | VideoMessage video_message = 4; 460 | LocationMessage location_message = 5; 461 | } 462 | // content can be localized 463 | optional HighlyStructuredMessage content = 6; 464 | // footer can be localized 465 | optional HighlyStructuredMessage footer = 7; 466 | repeated TemplateButton buttons = 8; 467 | } 468 | message HydratedFourRowTemplate { 469 | oneof title { 470 | DocumentMessage document_message = 1; 471 | string hydrated_title_text = 2; 472 | ImageMessage image_message = 3; 473 | VideoMessage video_message = 4; 474 | LocationMessage location_message = 5; 475 | } 476 | optional string hydrated_content_text = 6; 477 | optional string hydrated_footer_text = 7; 478 | repeated HydratedTemplateButton hydrated_buttons = 8; 479 | optional string template_id = 9; 480 | } 481 | 482 | // format indicates how this message will be rendered in the UI 483 | oneof format { 484 | FourRowTemplate four_row_template = 1; 485 | HydratedFourRowTemplate hydrated_four_row_template = 2; 486 | } 487 | 488 | optional ContextInfo context_info = 3; 489 | // Enterprise Client would populate/hydrate the message before sending 490 | // Going forward consumer clients should use this if present 491 | // If this is not present, then use "format" 492 | optional HydratedFourRowTemplate hydrated_template = 4; 493 | } 494 | 495 | message TemplateButtonReplyMessage { 496 | optional string selected_id = 1; 497 | optional string selected_display_text = 2; 498 | optional ContextInfo context_info = 3; 499 | optional uint32 selected_index = 4; 500 | } 501 | 502 | message ProductMessage { 503 | optional ProductSnapshot product = 1; 504 | optional string business_owner_jid = 2 [(jid) = true]; 505 | // optional string text = 3; deprecated, never have real code using it. 506 | optional CatalogSnapshot catalog = 4; 507 | optional string body = 5; 508 | optional string footer = 6; 509 | 510 | optional ContextInfo context_info = 17; 511 | 512 | message CatalogSnapshot { 513 | optional ImageMessage catalog_image = 1; 514 | optional string title = 2; 515 | optional string description = 3; 516 | } 517 | 518 | message ProductSnapshot { 519 | optional ImageMessage product_image = 1; 520 | optional string product_id = 2; 521 | optional string title = 3; 522 | optional string description = 4; 523 | optional string currency_code = 5; 524 | optional int64 price_amount_1000 = 6; // 1000 times the desired amount to avoid floating point numbers 525 | optional string retailer_id = 7; 526 | optional string url = 8; 527 | // product_image_count is the number of product images that the product has, so that we know how many placeholder images to display in product detail view 528 | optional uint32 product_image_count = 9; 529 | // optional bool pseudo_reply = 10; 530 | optional string first_image_id = 11; // adding the first image id for better caching experience on client side 531 | optional int64 sale_price_amount_1000 = 12; // 1000 times the desired amount to avoid floating point numbers 532 | } 533 | } 534 | 535 | //if you change OrderMessage object, please also update receive_order_message and send_order_message xmls in whatsapp-smax-mocks submodule 536 | message OrderMessage { 537 | enum OrderStatus { 538 | INQUIRY = 1; 539 | } 540 | enum OrderSurface { 541 | CATALOG = 1; 542 | } 543 | optional string order_id = 1; 544 | optional bytes thumbnail = 2; 545 | optional int32 item_count = 3; 546 | optional OrderStatus status = 4; 547 | optional OrderSurface surface = 5; 548 | optional string message = 6; 549 | // Currently the order title is simply the biz name. 550 | optional string order_title = 7; 551 | optional string seller_jid = 8 [(jid) = true]; 552 | // Token will be use to authenticate who can view this 553 | // order message. 554 | optional string token = 9; 555 | optional int64 total_amount_1000 = 10; // 1000 times the desired amount to avoid floating point numbers 556 | optional string total_currency_code = 11; 557 | optional ContextInfo context_info = 17; 558 | } 559 | 560 | // See list_message.md 561 | message ListMessage { 562 | enum ListType { 563 | UNKNOWN = 0; 564 | SINGLE_SELECT = 1; // product_list_info will be absent. 565 | PRODUCT_LIST = 2; // sections will be absent. 566 | } 567 | optional string title = 1; 568 | optional string description = 2; 569 | optional string button_text = 3; 570 | optional ListType list_type = 4; 571 | repeated Section sections = 5; 572 | optional ProductListInfo product_list_info = 6; 573 | optional string footer_text = 7; 574 | optional ContextInfo context_info = 8; 575 | 576 | message Row { 577 | optional string title = 1; 578 | optional string description = 2; 579 | optional string row_id = 3; 580 | } 581 | message Section { 582 | optional string title = 1; 583 | repeated Row rows = 2; 584 | } 585 | 586 | message Product { 587 | optional string product_id = 1; 588 | } 589 | message ProductSection { 590 | optional string title = 1; 591 | repeated Product products = 2; 592 | } 593 | 594 | message ProductListHeaderImage { 595 | optional string product_id = 1; 596 | optional bytes jpeg_thumbnail = 2; 597 | } 598 | 599 | message ProductListInfo { 600 | repeated ProductSection product_sections = 1; 601 | optional ProductListHeaderImage header_image = 2; 602 | optional string business_owner_jid = 3 [(jid) = true]; 603 | } 604 | } 605 | 606 | // See list_message.md 607 | message ListResponseMessage { 608 | enum ListType { 609 | UNKNOWN = 0; 610 | SINGLE_SELECT = 1; 611 | } 612 | 613 | message SingleSelectReply { 614 | optional string selected_row_id = 1; 615 | } 616 | 617 | optional string title = 1; 618 | optional ListType list_type = 2; 619 | optional SingleSelectReply single_select_reply = 3; 620 | optional ContextInfo context_info = 4; 621 | optional string description = 5; 622 | } 623 | 624 | message InteractiveMessage { 625 | message Header { 626 | optional string title = 1; 627 | optional string subtitle = 2; 628 | oneof media { 629 | DocumentMessage document_message = 3; 630 | ImageMessage image_message = 4; 631 | bytes jpeg_thumbnail = 6; 632 | VideoMessage video_message = 7; 633 | } 634 | optional bool has_media_attachment = 5; 635 | } 636 | 637 | message Body { 638 | optional string text = 1; 639 | } 640 | 641 | message Footer { 642 | optional string text = 1; 643 | } 644 | 645 | message ShopMessage { 646 | enum Surface { 647 | UNKNOWN_SURFACE = 0; 648 | FB = 1; 649 | IG = 2; 650 | WA = 3; 651 | } 652 | optional string id = 1; 653 | optional Surface surface = 2; 654 | // Version 1 - initial message version 655 | optional int32 message_version = 3 [default = 1]; 656 | } 657 | 658 | message CollectionMessage { 659 | optional string biz_jid = 1; 660 | optional string id = 2; 661 | 662 | // Version 1 - initial message version 663 | optional int32 message_version = 3 [default = 1]; 664 | } 665 | 666 | message NativeFlowMessage { 667 | message NativeFlowButton { 668 | optional string name = 1; 669 | optional string params_json = 2; 670 | } 671 | repeated NativeFlowButton buttons = 1; 672 | optional int32 message_version = 2 [default = 1]; 673 | } 674 | 675 | optional Header header = 1; 676 | optional Body body = 2; 677 | optional Footer footer = 3; 678 | 679 | oneof interactive_message { 680 | ShopMessage shop_storefront_message = 4; 681 | CollectionMessage collection_message = 5; 682 | NativeFlowMessage native_flow_message = 6; 683 | } 684 | optional ContextInfo context_info = 15; 685 | } 686 | 687 | message InteractiveResponseMessage { 688 | message Body { 689 | optional string text = 1; 690 | } 691 | 692 | message NativeFlowResponseMessage { 693 | optional string name = 1; 694 | optional string params_json = 2; 695 | optional int32 version = 3 [default = 1]; 696 | } 697 | 698 | optional Body body = 1; 699 | 700 | oneof interactive_response_message { 701 | NativeFlowResponseMessage native_flow_response_message = 2; 702 | } 703 | 704 | optional ContextInfo context_info = 15; 705 | } 706 | 707 | message GroupInviteMessage { 708 | enum GroupType { 709 | DEFAULT = 0; // regular group with no linked subgroup 710 | PARENT = 1; // parent group or community 711 | } 712 | 713 | optional string group_jid = 1 [(jid) = true]; 714 | optional string invite_code = 2; 715 | optional int64 invite_expiration = 3; 716 | optional string group_name = 4; 717 | optional bytes jpeg_thumbnail = 5; 718 | optional string caption = 6; 719 | 720 | optional ContextInfo context_info = 7; 721 | optional GroupType group_type = 8; 722 | } 723 | 724 | // multidevice; copy of the message sent by one of user's other devices 725 | message DeviceSentMessage { 726 | optional string destination_jid = 1 [(jid) = true]; // message recipient (can be 1:1/group/bclist) 727 | optional Message message = 2; 728 | optional string phash = 3; // used by bclist 729 | // repeated EphemeralSetting broadcast_ephemeral_settings = 4; removed 2021-03-11 not used anymore for broadcast retries 730 | } 731 | 732 | message FutureProofMessage { 733 | optional Message message = 1; 734 | } 735 | 736 | // See buttons_message.md 737 | message ButtonsMessage { 738 | 739 | enum HeaderType { 740 | UNKNOWN = 0; 741 | EMPTY = 1; 742 | TEXT = 2; 743 | DOCUMENT = 3; 744 | IMAGE = 4; 745 | VIDEO = 5; 746 | LOCATION = 6; 747 | // In future, if we decide to add another attachment: AUDIO = 7; 748 | } 749 | 750 | oneof header { 751 | string text = 1; 752 | DocumentMessage document_message = 2; 753 | ImageMessage image_message = 3; 754 | VideoMessage video_message = 4; 755 | LocationMessage location_message = 5; 756 | // In future, if we decide to add another attachment: AudioMessage audio_message = 11; 757 | } 758 | 759 | optional string content_text = 6; 760 | optional string footer_text = 7; 761 | optional ContextInfo context_info = 8; 762 | 763 | message Button { 764 | optional string button_id = 1; 765 | message ButtonText { 766 | optional string display_text = 1; 767 | } 768 | optional ButtonText button_text = 2; 769 | optional Type type = 3; 770 | message NativeFlowInfo { 771 | optional string name = 1; 772 | optional string params_json = 2; 773 | } 774 | optional NativeFlowInfo native_flow_info = 4; 775 | enum Type { 776 | UNKNOWN= 0; 777 | RESPONSE = 1; 778 | NATIVE_FLOW = 2; 779 | } 780 | } 781 | 782 | repeated Button buttons = 9; 783 | optional HeaderType header_type = 10; 784 | } 785 | 786 | // See buttons_message.md 787 | message ButtonsResponseMessage { 788 | enum Type { 789 | UNKNOWN= 0; 790 | DISPLAY_TEXT = 1; 791 | // In future, if we decide to add another attachment: LOCATION = 2; 792 | } 793 | optional string selected_button_id = 1; 794 | oneof response { 795 | string selected_display_text = 2; 796 | // In future, if we decide to add another attachment: LocationMessage location_message = 5; 797 | } 798 | optional ContextInfo context_info = 3; 799 | optional Type type = 4; 800 | } 801 | 802 | // See reactions.md 803 | message ReactionMessage { 804 | // Message ID being reacted to. 805 | optional MessageKey key = 1; 806 | 807 | // This string should contain a single emoji with the content of the reaction. 808 | // Leave this field unset to remove a reaction. 809 | optional string text = 2; 810 | 811 | // This string is used to group similar emoji. It is like text but without modifiers. 812 | optional string grouping_key = 3; 813 | 814 | // Client-assigned timestamp (milliseconds since 1970). 815 | // Use this to order reactions from the same user. 816 | // This should be set to MAX(last_sender_timestamp_ms + 1, current_server_adjusted_time) (see reactions.md#editing for details) 817 | optional int64 sender_timestamp_ms = 4; 818 | } 819 | 820 | // See polls.md 821 | // This is referenced by web.proto. It is kept within the Message protobuf for ease of use on Android" 822 | message PollCreationMessage { 823 | // Container for each Poll option 824 | message Option { 825 | // Name of the option voted on. Must be unique 826 | optional string option_name = 1; 827 | } 828 | // 32-byte encryption key used for encrypting PollUpdateMessage(s) 829 | optional bytes enc_key = 1; 830 | // Name of the poll shown to the user. See polls.md#Creating a Poll for validation 831 | optional string name = 2; 832 | 833 | // Options available in the poll for voting. See polls.md#Creating a Poll for validation 834 | repeated Option options = 3; 835 | 836 | // Number of options that can be selected. 0 for unlimited options. 837 | optional uint32 selectable_options_count = 4; 838 | 839 | optional ContextInfo context_info = 5; 840 | } 841 | 842 | // See polls.md 843 | message PollUpdateMessage { 844 | // Message ID of the poll being updated. 845 | optional MessageKey poll_creation_message_key = 1; 846 | 847 | // Contains an encrypted PollVoteMessage protobuf using AES-GCM with the 848 | // enc_key from the PollCreationMessage. See polls.md:Dual Encryption 849 | optional PollEncValue vote = 2; 850 | } 851 | 852 | message PollEncValue { 853 | // A payload encrypted using AES-GCM with the enc_key from the 854 | // PollCreationMessage. When used for PollUpdateMessage's `vote`, for 855 | // example, this will contain an encrypted PollVoteMessage. See 856 | // polls.md:Dual Encryption 857 | optional bytes enc_payload = 1; 858 | // Initialization vector for AES-GCM used with the enc_key to decrypt 859 | // the enc_payload. See polls.md:Dual Encryption 860 | optional bytes enc_iv = 2; 861 | } 862 | 863 | // See polls.md 864 | message PollVoteMessage { 865 | // SHA-256 hashes of option names that the user has selected. See polls.md:Voting 866 | repeated bytes selected_options = 1; 867 | // Client-assigned timestamp (milliseconds since 1970). 868 | // Use this to order votes from the same user. 869 | // This should be set to MAX(last_sender_timestamp_ms + 1, current_server_adjusted_time) (see polls.md#Editing/Ordering for details) 870 | optional int64 sender_timestamp_ms = 2; 871 | } 872 | 873 | // See keep_in_chat.md 874 | message KeepInChatMessage { 875 | //Key of the message that need to be kept or unkept 876 | optional MessageKey key = 1; 877 | // type of operation 878 | optional KeepType keep_type = 2; 879 | // local timestamp from client. used to resolve conflicts from a client 880 | optional int64 timestamp_ms = 3; 881 | } 882 | 883 | 884 | optional string conversation = 1; 885 | optional SenderKeyDistributionMessage sender_key_distribution_message = 2; 886 | optional ImageMessage image_message = 3; 887 | optional ContactMessage contact_message = 4; 888 | optional LocationMessage location_message = 5; 889 | optional ExtendedTextMessage extended_text_message = 6; 890 | optional DocumentMessage document_message = 7; 891 | optional AudioMessage audio_message = 8; 892 | optional VideoMessage video_message = 9; 893 | optional Call call = 10; 894 | optional Chat chat = 11; 895 | optional ProtocolMessage protocol_message = 12; 896 | optional ContactsArrayMessage contacts_array_message = 13; 897 | optional HighlyStructuredMessage highly_structured_message = 14; 898 | optional SenderKeyDistributionMessage fast_ratchet_key_sender_key_distribution_message = 15; 899 | optional SendPaymentMessage send_payment_message = 16; 900 | // optional RequestPaymentMessage request_payment_message = 17; removed 2018-06-21 901 | optional LiveLocationMessage live_location_message = 18; 902 | // optional StickerMessage sticker_message = 19; removed 2018-01-23 due to a bug in Android 2.18.9 dropping sticker messages 903 | // optional StickerMessage sticker_message = 20; removed 2018-10-02 due to Android not wanting to ship a separate protobuf for prod 904 | // optional RequestPaymentMessage request_payment_message = 21; removed 2018-8-17 905 | optional RequestPaymentMessage request_payment_message = 22; 906 | optional DeclinePaymentRequestMessage decline_payment_request_message = 23; 907 | optional CancelPaymentRequestMessage cancel_payment_request_message = 24; 908 | optional TemplateMessage template_message = 25; 909 | optional StickerMessage sticker_message = 26; 910 | // optional ProductMessage product_message = 27; removed 2019-04-23 incrementing proto for launch 911 | optional GroupInviteMessage group_invite_message = 28; 912 | optional TemplateButtonReplyMessage template_button_reply_message = 29; 913 | optional ProductMessage product_message = 30; 914 | optional DeviceSentMessage device_sent_message = 31; 915 | // optional DeviceSyncMessage device_sync_message = 32; removed 2020-03-24 due not being used 916 | // optional FutureProofMessage view_once_message = 33; removed 2020-8-24 because Android forgot to check for this field in numFieldsOnE2eMessage 917 | // optional OrderMessage order_message = 34; removed 2020-8-24 because Android wrongly used '34' for message_context_info 918 | optional MessageContextInfo message_context_info = 35; // presence of field should never trigger futureproofing, not currently 919 | // supported by all public clients so it cannot be used yet 920 | optional ListMessage list_message = 36; // See list_message.md 921 | optional FutureProofMessage view_once_message = 37; // See view_once_media.md 922 | optional OrderMessage order_message = 38; //if you change OrderMessage object, please also update receive_order_message and send_order_message xmls in whatsapp-smax-mocks submodule 923 | optional ListResponseMessage list_response_message = 39; // See list_message.md 924 | optional FutureProofMessage ephemeral_message = 40; // see ephemeral_messages.md 925 | // optional InvoiceMessage invoice_message = 41; // see doc/invoice/rfc_invoice_indonesia_mvp/rfc_invoice_indonesia_mvp.md - removed 2022-05-25 due not being used 926 | optional ButtonsMessage buttons_message = 42; // See buttons_message.md 927 | optional ButtonsResponseMessage buttons_response_message = 43; // See buttons_message.md 928 | optional PaymentInviteMessage payment_invite_message = 44; // See payment_invite_message.md 929 | optional InteractiveMessage interactive_message = 45; 930 | optional ReactionMessage reaction_message = 46; 931 | optional InteractiveResponseMessage interactive_response_message = 48; // See interactive_message.md 932 | optional PollCreationMessage poll_creation_message = 49; 933 | optional PollUpdateMessage poll_update_message = 50; 934 | optional KeepInChatMessage keep_in_chat_message = 51; 935 | } 936 | 937 | message ContextInfo { 938 | 939 | message AdReplyInfo { 940 | enum MediaType { 941 | NONE = 0; 942 | IMAGE = 1; 943 | VIDEO = 2; 944 | } 945 | optional string advertiser_name = 1; 946 | optional MediaType media_type = 2; 947 | 948 | optional bytes jpeg_thumbnail = 16; 949 | optional string caption = 17; 950 | } 951 | 952 | // `ExternalAdReplyInfo` will be used to encapsulate context related to ads run on external surfaces that link into WA (CTWA). 953 | message ExternalAdReplyInfo { 954 | enum MediaType { 955 | NONE = 0; 956 | IMAGE = 1; 957 | VIDEO = 2; 958 | } 959 | 960 | optional string title = 1; 961 | optional string body = 2; 962 | 963 | optional MediaType media_type = 3; 964 | 965 | optional string thumbnail_url = 4; 966 | optional string media_url = 5; 967 | 968 | optional bytes thumbnail = 6; 969 | 970 | optional string source_type = 7; 971 | optional string source_id = 8; 972 | optional string source_url = 9; 973 | optional bool contains_auto_reply = 10; 974 | 975 | // In case of image media type, we want to show larger thumbnails 976 | // staying consistent with link message types. However we don't want 977 | // to affect older messages in users' history. This flag 978 | // will be used to decide whether or not to render larger thumbnail 979 | // if one is available for rendering. 980 | optional bool render_larger_thumbnail = 11; 981 | 982 | // Used for showing visual attribution of CtWA ad, making it 983 | // explicit to viewer that the message came from an ad. 984 | optional bool show_ad_attribution = 12; 985 | } 986 | 987 | // stanza_id and participant refer to another message in the chat referred by remote_jid. 988 | // for 1:1 chats, the participant is null for quoting yourself, or is the jid 989 | // of the other party, if quoting them. for group chats, the 990 | // participant is never null. Use the self jid when quoting yourself 991 | optional string stanza_id = 1; 992 | optional string participant = 2 [(jid) = true]; 993 | 994 | // a full copy of the message being quoted, to aid in rendering the 995 | // quoted content. Leave null when sending an blank reply to an 996 | // announcement group 997 | optional Message quoted_message = 3; 998 | // remote_jid is null when quoting message from the same chat 999 | // use status@broadcast when quoting status v3 messages 1000 | // use an announcement group jid with sending a blank reply to a group administrator 1001 | optional string remote_jid = 4 [(jid) = true]; 1002 | 1003 | // Used to identify individuals in a message. Should contain the full jid 1004 | // string, such as "14085551212@s.whatsapp.net" 1005 | // Group jids are not valid here. 1006 | repeated string mentioned_jid = 15 [(jid) = true]; 1007 | 1008 | // 16 and 17 were used at one point in the life cycle and shouldn't be used again. 1009 | // We can't explicitly mark them as reserved until android moves to a version of 1010 | // protoc that supports them. 1011 | // optional uint32 edit_version = 16; 1012 | // optional bool revoke_message = 17; 1013 | 1014 | optional string conversion_source = 18; 1015 | optional bytes conversion_data = 19; 1016 | optional uint32 conversion_delay_seconds = 20; 1017 | optional uint32 forwarding_score = 21; 1018 | optional bool is_forwarded = 22; 1019 | 1020 | // Only one of quoted_message, blank reply (via remote_jid), and quoted_ad should exist per instance 1021 | optional AdReplyInfo quoted_ad = 23; 1022 | 1023 | // the multidevice placeholder message key that should be updated with the contents of this message 1024 | optional MessageKey placeholder_key = 24; 1025 | 1026 | // the number of seconds the message can be stored after it has been read. 1027 | optional uint32 expiration = 25; 1028 | 1029 | // Epoch timestamp in seconds indicating when the ephemeral setting has been last changed. 1030 | // Only used in 1:1 ephemeral conversations 1031 | optional int64 ephemeral_setting_timestamp = 26; 1032 | 1033 | // Shared secret used to generate keys for encryption/decryption of the ephemeral setting in a broadcast list 1034 | optional bytes ephemeral_shared_secret = 27; 1035 | 1036 | optional ExternalAdReplyInfo external_ad_reply = 28; 1037 | 1038 | // Adding similar conversion fields as for ctwa (18, 19, 20) for other entry points 1039 | optional string entry_point_conversion_source = 29; 1040 | optional string entry_point_conversion_app = 30; 1041 | optional uint32 entry_point_conversion_delay_seconds = 31; 1042 | 1043 | optional DisappearingMode disappearing_mode = 32; 1044 | 1045 | optional ActionLink action_link = 33; 1046 | 1047 | // Used when user request to join a subgroup. User can view all the 1048 | // subgroups linked to a parent group (some which they are not yet in) and 1049 | // ask one of the subgroup admin to add them to the subgroup. This message 1050 | // can only be a quoted message and is blank reply message type. 1051 | optional string group_subject = 34; 1052 | 1053 | // Only used when user request to join a subgroup. Although we save the parent 1054 | // jid info in the database, iOS data structure does not allow easy access 1055 | // to this info. Thus, saving this info in the context info of the message 1056 | // itself. 1057 | optional string parent_group_jid = 35 [(jid) = true]; 1058 | } 1059 | 1060 | // Similar to ContextInfo but may be present for any message type, fields 1061 | // should only be added here when they independent of message type including non 1062 | // user visible messages. One example is ADV data which may be present on any 1063 | // 1-1 message regardless of type. Use ContextInfo and regular message type 1064 | // fields for everything else. 1065 | message MessageContextInfo { 1066 | optional DeviceListMetadata device_list_metadata = 1; 1067 | optional int32 device_list_metadata_version = 2; 1068 | 1069 | // A general purpose 32 byte secret that could be used to derive feature specific secrets to use to authenticate 1070 | // further operations on this message. See message_secret.md for details. 1071 | optional bytes message_secret = 3; 1072 | // sending configurable additional bytes for latency evaluation 1073 | optional bytes padding_bytes = 4; 1074 | } 1075 | 1076 | // Used by ADV "In Chat Device Consistency". See adv_protocol.md 1077 | message DeviceListMetadata { 1078 | optional bytes sender_key_hash = 1; 1079 | optional uint64 sender_timestamp = 2; 1080 | repeated uint32 sender_key_indexes = 3 [packed=true]; 1081 | 1082 | // 4-7 reserved for future self metadata 1083 | 1084 | optional bytes recipient_key_hash = 8; 1085 | optional uint64 recipient_timestamp = 9; 1086 | repeated uint32 recipient_key_indexes = 10 [packed=true]; 1087 | } 1088 | 1089 | message InteractiveAnnotation { 1090 | // Gives the vertices of a polyon enclosing the tappable area. There is an 1091 | // implicit line between adjacent points and between the first and last 1092 | // points, which ensures it is a closed region. There must be at least three 1093 | // vertices. The coordinates are in the space of the enclosing 1094 | // media. 1095 | repeated Point polygonVertices = 1; 1096 | 1097 | // What to do when the annotation is selected? 1098 | oneof action { 1099 | // Open a map to this location 1100 | Location location = 2; 1101 | } 1102 | } 1103 | 1104 | // Describes a coordinate in two dimensions. 1105 | message Point { 1106 | optional int32 x_deprecated = 1 [deprecated=true]; 1107 | optional int32 y_deprecated = 2 [deprecated=true]; 1108 | optional double x = 3; 1109 | optional double y = 4; 1110 | } 1111 | 1112 | // Describes a geographical location. 1113 | message Location { 1114 | optional double degrees_latitude = 1; 1115 | optional double degrees_longitude = 2; 1116 | 1117 | // The place's name. Suitable to display on a map. 1118 | optional string name = 3; 1119 | } 1120 | 1121 | message TemplateButton { 1122 | message QuickReplyButton { 1123 | optional Message.HighlyStructuredMessage display_text = 1; 1124 | optional string id = 2; 1125 | } 1126 | 1127 | message URLButton { 1128 | optional Message.HighlyStructuredMessage display_text = 1; 1129 | optional Message.HighlyStructuredMessage url = 2; 1130 | } 1131 | 1132 | message CallButton { 1133 | optional Message.HighlyStructuredMessage display_text = 1; 1134 | optional Message.HighlyStructuredMessage phone_number = 2; 1135 | } 1136 | 1137 | oneof button { 1138 | QuickReplyButton quick_reply_button = 1; 1139 | URLButton url_button = 2; 1140 | CallButton call_button = 3; 1141 | } 1142 | optional uint32 index = 4; 1143 | } 1144 | 1145 | message HydratedTemplateButton { 1146 | message HydratedQuickReplyButton { 1147 | optional string display_text = 1; 1148 | optional string id = 2; 1149 | } 1150 | 1151 | message HydratedURLButton { 1152 | optional string display_text = 1; 1153 | optional string url = 2; 1154 | } 1155 | 1156 | message HydratedCallButton { 1157 | optional string display_text = 1; 1158 | optional string phone_number = 2; 1159 | } 1160 | 1161 | oneof hydrated_button { 1162 | HydratedQuickReplyButton quick_reply_button = 1; 1163 | HydratedURLButton url_button = 2; 1164 | HydratedCallButton call_button = 3; 1165 | } 1166 | optional uint32 index = 4; 1167 | } 1168 | 1169 | message Money { 1170 | optional int64 value = 1; // Money value represented as an int 1171 | optional uint32 offset = 2; // Base offset for money value to represent a subdivision. value / offset = decimal value 1172 | optional string currency_code = 3; // Currency code for money value (fiat currencies follow ISO 4217 code) 1173 | } 1174 | 1175 | message PaymentBackground { 1176 | message MediaData { 1177 | optional bytes media_key = 1; 1178 | optional int64 media_key_timestamp = 2; 1179 | optional bytes file_sha256 = 3; 1180 | optional bytes file_enc_sha256 = 4; 1181 | optional string direct_path = 5; 1182 | } 1183 | 1184 | enum Type { 1185 | UNKNOWN = 0; 1186 | DEFAULT = 1; 1187 | } 1188 | 1189 | optional string id = 1; 1190 | optional uint64 file_length = 2; 1191 | optional uint32 width = 3; 1192 | optional uint32 height = 4; 1193 | optional string mimetype = 5; 1194 | optional fixed32 placeholder_argb = 6; 1195 | optional fixed32 text_argb = 7; 1196 | optional fixed32 subtext_argb = 8; 1197 | optional MediaData media_data = 9; 1198 | optional Type type = 10; 1199 | } 1200 | 1201 | message DisappearingMode { 1202 | enum Initiator { 1203 | CHANGED_IN_CHAT = 0; 1204 | INITIATED_BY_ME = 1; 1205 | INITIATED_BY_OTHER = 2; 1206 | } 1207 | optional Initiator initiator = 1; 1208 | } 1209 | 1210 | // URL and button title (e.g., 'Learn More') for Status PSA links. See [status_v3](../status_v3.txt) for details. 1211 | message ActionLink { 1212 | optional string url = 1; 1213 | optional string button_title = 2; 1214 | } 1215 | 1216 | // need this top level to not break web & KaiOS as this enum is needed in web.proto as well 1217 | enum KeepType { 1218 | UNKNOWN = 0; 1219 | // keep for all in the group 1220 | KEEP_FOR_ALL = 1; 1221 | // un-keep for all in the group 1222 | UNDO_KEEP_FOR_ALL = 2; 1223 | // this could be extended in future 1224 | } 1225 | 1226 | --------------------------------------------------------------------------------