Initial commit

This commit is contained in:
Adhiraj
2020-03-16 16:06:30 +05:30
commit 5bd524ca1f
319 changed files with 76526 additions and 0 deletions

BIN
binary_coding/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,25 @@
const assert = require('assert').strict
const BinaryCoding = require("./binary_encoder.js")
const testingPairs = [
[
"f806092f5a0a10f804f80234fc6c0a350a1b39313735323938373131313740732e77686174736170702e6e657410011a143345423030393637354537454433374141424632122b0a292a7069616e6f20726f6f6d2074696d696e6773206172653a2a0a20363a3030414d2d31323a3030414d18b3faa7f3052003f80234fc4c0a410a1b39313735323938373131313740732e77686174736170702e6e657410001a20304643454335333330463634393239433645394132434646443242433845414418bdfaa7f305c00101f80234fc930a350a1b39313735323938373131313740732e77686174736170702e6e657410011a14334542303033433742353339414644303937353312520a50536f727279206672656e2c204920636f756c646e277420756e6465727374616e6420274c69627261272e2054797065202768656c702720746f206b6e6f77207768617420616c6c20492063616e20646f18c1faa7f3052003f80234fc540a410a1b39313735323938373131313740732e77686174736170702e6e657410001a20413132333042384436423041314437393345433241453245413043313638443812090a076c69627261727918c2faa7f305",
["action",{"last":"true","add":"before"},[["message",null,{"key":{"remoteJid":"917529871117@s.whatsapp.net","fromMe":true,"id":"3EB009675E7ED37AABF2"},"message":{"conversation":"*piano room timings are:*\n 6:00AM-12:00AM"},"messageTimestamp":"1584004403","status":"DELIVERY_ACK"}],["message",null,{"key":{"remoteJid":"917529871117@s.whatsapp.net","fromMe":false,"id":"0FCEC5330F64929C6E9A2CFFD2BC8EAD"},"messageTimestamp":"1584004413","messageStubType":"REVOKE"}],["message",null,{"key":{"remoteJid":"917529871117@s.whatsapp.net","fromMe":true,"id":"3EB003C7B539AFD09753"},"message":{"conversation":"Sorry fren, I couldn't understand 'Libra'. Type 'help' to know what all I can do"},"messageTimestamp":"1584004417","status":"DELIVERY_ACK"}],["message",null,{"key":{"remoteJid":"917529871117@s.whatsapp.net","fromMe":false,"id":"A1230B8D6B0A1D793EC2AE2EA0C168D8"},"message":{"conversation":"library"},"messageTimestamp":"1584004418"}]]]
]
]
function testCoding () {
const encoder = new BinaryCoding.Encoder()
const decoder = new BinaryCoding.Decoder()
testingPairs.forEach(pair => {
const buff = Buffer.from(pair[0], 'hex')
const decoded = decoder.read(buff)
assert.deepEqual( JSON.stringify( decoded ), JSON.stringify( pair[1] ))
const encoded = encoder.write(decoded)
assert.deepEqual(encoded, buff)
})
console.log("all coding tests passed")
}
testCoding()

View File

@@ -0,0 +1,476 @@
const ProtoBuf = require("protobufjs")
const WATags = {
LIST_EMPTY: 0,
STREAM_END: 2,
DICTIONARY_0: 236,
DICTIONARY_1: 237,
DICTIONARY_2: 238,
DICTIONARY_3: 239,
LIST_8 : 248,
LIST_16 : 249,
JID_PAIR : 250,
HEX_8 : 251,
BINARY_8 : 252,
BINARY_20 : 253,
BINARY_32 : 254,
NIBBLE_8 : 255,
SINGLE_BYTE_MAX: 256,
PACKED_MAX: 254
}
const WADoubleByteTokens = []
const WASingleByteTokens = [
null,null,null,"200","400","404","500","501","502","action","add",
"after","archive","author","available","battery","before","body",
"broadcast","chat","clear","code","composing","contacts","count",
"create","debug","delete","demote","duplicate","encoding","error",
"false","filehash","from","g.us","group","groups_v2","height","id",
"image","in","index","invis","item","jid","kind","last","leave",
"live","log","media","message","mimetype","missing","modify","name",
"notification","notify","out","owner","participant","paused",
"picture","played","presence","preview","promote","query","raw",
"read","receipt","received","recipient","recording","relay",
"remove","response","resume","retry","s.whatsapp.net","seconds",
"set","size","status","subject","subscribe","t","text","to","true",
"type","unarchive","unavailable","url","user","value","web","width",
"mute","read_only","admin","creator","short","update","powersave",
"checksum","epoch","block","previous","409","replaced","reason",
"spam","modify_tag","message_info","delivery","emoji","title",
"description","canonical-url","matched-text","star","unstar",
"media_key","filename","identity","unread","page","page_count",
"search","media_message","security","call_log","profile","ciphertext",
"invite","gif","vcard","frequent","privacy","blacklist","whitelist",
"verify","location","document","elapsed","revoke_invite","expiration",
"unsubscribe","disable","vname","old_jid","new_jid","announcement",
"locked","prop","label","color","call","offer","call-id",
"quick_reply", "sticker", "pay_t", "accept", "reject", "sticker_pack",
"invalid", "canceled", "missed", "connected", "result", "audio",
"video", "recent"
]
const WebMessageInfo = ProtoBuf.Root.fromJSON( require("./whatsapp_message_coding.json") ).lookupType("proto.WebMessageInfo")
class WhatsAppBinaryEncoder {
constructor () {
this.data = []
}
pushByte (value) {
this.data.push((value & 0xFF))
}
pushInt (value, n, littleEndian=false) {
for (var i = 0; i < n;i++) {
const curShift = littleEndian ? i : (n-1-i)
this.data.push( (value>>(curShift*8)) & 0xFF )
}
}
pushInt20 (value) {
this.pushBytes ( [(value >> 16) & 0x0F, (value >> 8) & 0xFF, value & 0xFF] )
}
pushInt16 (value) {
this.pushInt(value, 2)
}
pushInt32 (value) {
this.pushInt(value, 4)
}
pushInt64 (value) {
this.pushInt(value, 8)
}
pushBytes (bytes) {
this.data.push.apply(this.data, bytes)
}
pushString (str) {
const bytes = new TextEncoder('utf-8').encode(str)
this.pushBytes(bytes)
}
writeByteLength (length) {
if (length >= 4294967296) {
throw "string too large to encode: " + length
}
if (length >= (1<<20)) {
this.pushByte(WATags.BINARY_32)
this.pushInt32(length)
} else if (length >= 256) {
this.pushByte(WATags.BINARY_20)
this.pushInt20(length)
} else {
this.pushByte(WATags.BINARY_8)
this.pushByte(length)
}
}
writeStringRaw (string) {
this.writeByteLength( string.length )
this.pushString(string)
}
writeJid(left,right) {
this.pushByte(WATags.JID_PAIR)
if (left && left.length > 0) {
this.writeString(left)
} else {
this.writeToken(WATags.LIST_EMPTY)
}
this.writeString(right)
}
writeToken (token) {
if (token < 245) {
this.pushByte(token)
} else if (token <= 500) {
throw "invalid token"
}
}
writeString(token, i=null) {
if (typeof token !== "string") {
throw "invalid string: " + token
}
if (token === "c.us") {
token = "s.whatsapp.net"
}
const tokenIndex = WASingleByteTokens.indexOf(token)
if (!i && token === "s.whatsapp.net") {
this.writeToken( tokenIndex )
} else if ( tokenIndex >= 0 ) {
if (tokenIndex < WATags.SINGLE_BYTE_MAX) {
this.writeToken(tokenIndex)
} else {
const overflow = tokenIndex-WATags.SINGLE_BYTE_MAX
const dictionaryIndex = overflow >> 8
if (dictionaryIndex < 0 || dictionaryIndex > 3) {
throw "double byte dict token out of range: " + token + ", " + tokenIndex
}
this.writeToken(WATags.DICTIONARY_0 + dictionaryIndex)
this.writeToken(overflow % 256)
}
} else {
const jidSepIndex = token.indexOf("@")
if (jidSepIndex <= 0) {
this.writeStringRaw(token)
} else {
this.writeJid(token.slice(0,jidSepIndex), token.slice(jidSepIndex+1, token.length))
}
}
}
writeAttributes (attrs) {
if (!attrs) {
return
}
Object.keys(attrs).forEach (key => {
this.writeString( key )
this.writeString( attrs[key] )
})
}
writeListStart (listSize) {
if (listSize === 0) {
this.pushByte(WATags.LIST_EMPTY)
} else if (listSize < 256) {
this.pushBytes([WATags.LIST_8, listSize])
} else {
this.pushByte([WATags.LIST_16, listSize])
}
}
writeChildren (children) {
if (!children) {
return
}
if (typeof children === "string") {
this.writeString(children, true)
} else if (typeof children === "Buffer" || typeof children === "Uint8Array") {
this.writeByteLength(children.length)
this.pushBytes(children)
} else if (Array.isArray(children)) {
this.writeListStart(children.length)
children.forEach (c => {
this.writeNode(c)
})
} else if (typeof children === "object") {
//console.log(children)
const buff = WebMessageInfo.encode(children).finish()
this.writeByteLength(buff.length)
this.pushBytes(buff)
} else {
throw "invalid children: " + children + " (" + (typeof children) + ")"
}
}
getNumValidKeys (arr) {
return arr ? Object.keys(arr).length : 0
}
writeNode (node) {
if (!node) {
return
} else if (!Array.isArray(node) || node.length !== 3) {
throw "invalid node given: " + node
}
const numAttributes = this.getNumValidKeys(node[1])
this.writeListStart( 2*numAttributes + 1 + ( node[2] ? 1 : 0 ) )
this.writeString(node[0])
this.writeAttributes(node[1])
this.writeChildren(node[2])
}
write (data) {
this.data = new Array()
this.writeNode(data)
return Buffer.from(this.data)
}
}
class WhatsAppBinaryDecoder {
constructor () {
this.buffer = null
this.index = 0
}
checkEOS (length) {
if (this.index+length > this.buffer.length) {
throw "end of stream"
}
}
next () {
const value = this.buffer[this.index]
this.index += 1
return value
}
readByte () {
this.checkEOS(1)
return this.next()
}
readInt (n, littleEndian=false) {
this.checkEOS(n)
let val = 0
for (var i = 0; i < n;i++) {
const shift = (littleEndian) ? i : (n-1-i)
val |= this.next() << (shift*8)
}
return val
}
readInt16 (littleEndian=false) {
return this.readInt(2, littleEndian)
}
readInt20 () {
this.checkEOS(3)
return ( (this.next() & 15) << 16 ) + (this.next()<<8) + this.next()
}
readInt32 (littleEndian=false) {
return this.readInt(4, littleEndian)
}
readInt64 (littleEndian=false) {
return this.readInt(8, littleEndian)
}
unpackHex (value) {
if (value >= 0 && value < 16) {
return value<10 ? ('0'.charCodeAt(0)+value) : ('A'.charCodeAt(0)+value-10)
}
throw "invalid hex: " + value
}
unpackNibble(value) {
if (value >= 0 && value <= 9) {
return '0'.charCodeAt(0)+value
}
switch (value) {
case 10:
return '-'.charCodeAt(0)
case 11:
return '.'.charCodeAt(0)
case 15:
return '\0'.charCodeAt(0)
default:
throw "invalid nibble: " + value
}
}
unpackByte (tag, value) {
if (tag === WATags.NIBBLE_8) {
return this.unpackNibble(value)
} else if (tag === WATags.HEX_8) {
return this.unpackHex(value)
} else {
throw "unknown tag: " + tag
}
}
readPacked8(tag) {
const startByte = this.readByte()
let value = ""
for (var i = 0; i < (startByte&127);i++) {
let curByte = this.readByte()
value += String.fromCharCode( this.unpackByte(tag, (curByte&0xF0) >> 4) )
value += String.fromCharCode( this.unpackByte(tag, curByte&0x0F) )
}
if ((startByte >> 7) !== 0) {
value = value.slice(0,-1)
}
return value
}
readRangedVarInt (min, max, description="unknown") {
// value =
throw "WTF"
}
isListTag (tag) {
return tag === WATags.LIST_EMPTY || tag === WATags.LIST_8 || tag === WATags.LIST_16
}
readListSize (tag) {
switch (tag) {
case WATags.LIST_EMPTY:
return 0
case WATags.LIST_8:
return this.readByte()
case WATags.LIST_16:
return this.readInt16()
default:
throw "invalid tag for list size: " + tag
}
}
readStringFromChars (length) {
this.checkEOS(length)
const value = this.buffer.slice(this.index, this.index+length)
this.index += length
return new TextDecoder('utf-8').decode(value)
}
readString (tag) {
if (tag >= 3 && tag <= 235) {
const token = this.getToken(tag)
return token === "s.whatsapp.net" ? "c.us" : token
}
switch (tag) {
case WATags.DICTIONARY_0:
case WATags.DICTIONARY_1:
case WATags.DICTIONARY_2:
case WATags.DICTIONARY_3:
return this.getTokenDouble( tag - WATags.DICTIONARY_0, this.readByte() )
case WATags.LIST_EMPTY:
return null
case WATags.BINARY_8:
return this.readStringFromChars( this.readByte() )
case WATags.BINARY_20:
return this.readStringFromChars( this.readInt20() )
case WATags.BINARY_32:
return this.readStringFromChars( this.readInt32() )
case WATags.JID_PAIR:
const i = this.readString( this.readByte() )
const j = this.readString( this.readByte() )
if (i && j) {
return i + "@" + j
}
throw "invalid jid pair: " + i + ", " + j
case WATags.HEX_8:
case WATags.NIBBLE_8:
return this.readPacked8(tag)
default:
throw "invalid string with tag: " + tag
}
}
readAttributes (n) {
if (n !== 0) {
let attributes = {}
for (var i = 0;i < n;i++) {
const index = this.readString(this.readByte())
const b = this.readByte()
attributes[index] = this.readString(b)
}
return attributes
} else {
return null
}
}
readList (tag) {
let list = Array( this.readListSize(tag) )
for (var i = 0;i < list.length;i++) {
list[i] = this.readNode()
}
return list
}
readBytes (n) {
this.checkEOS(n)
const value = this.buffer.slice(this.index, this.index+n)
this.index += n
return value
}
getToken (index) {
if (index < 3 || index >= WASingleByteTokens.length) {
throw "invalid token index: " + index
}
return WASingleByteTokens[index]
}
getTokenDouble (index1, index2) {
const n = 256*index1 + index2
if (n < 0 || n > WADoubleByteTokens.length) {
throw "invalid double token index: " + n
}
return WADoubleByteTokens[n]
}
readNode () {
const listSize = this.readListSize( this.readByte() )
const descrTag = this.readByte()
if (descrTag === WATags.STREAM_END) {
throw "unexpected stream end"
}
const descr = this.readString(descrTag)
if (listSize === 0 || !descr) {
throw "invalid node"
}
//console.log(descr + "," + listSize)
let attrs = this.readAttributes( (listSize-1) >> 1 )
let content = null
if (listSize%2 === 0) {
const tag = this.readByte()
if (this.isListTag(tag)) {
content = this.readList(tag)
} else {
switch (tag) {
case WATags.BINARY_8:
content = this.readBytes( this.readByte() )
break
case WATags.BINARY_20:
content = this.readBytes( this.readInt20() )
break
case WATags.BINARY_32:
content = this.readBytes( this.readInt32() )
break
default:
content = this.readString(tag)
break
}
}
}
//console.log( descr + "," + JSON.stringify(attrs) + ", " + content)
return [descr, attrs, content]
}
read (buffer) {
this.buffer = buffer
this.index = 0
let node = this.readNode()
if (node[2]) {
for (var i = 0; i < node[2].length;i++) {
if (node[2][0][0] === "message") {
node[2][i][2] = WebMessageInfo.decode( node[2][i][2] )
}
}
}
return node
}
}
module.exports = { Encoder: WhatsAppBinaryEncoder, Decoder: WhatsAppBinaryDecoder }

671
binary_coding/def.proto Normal file
View File

@@ -0,0 +1,671 @@
syntax = "proto2";
package proto;
message HydratedQuickReplyButton {
optional string displayText = 1;
optional string id = 2;
}
message HydratedURLButton {
optional string displayText = 1;
optional string url = 2;
}
message HydratedCallButton {
optional string displayText = 1;
optional string phoneNumber = 2;
}
message HydratedTemplateButton {
optional uint32 index = 4;
oneof hydratedButton {
HydratedQuickReplyButton quickReplyButton = 1;
HydratedURLButton urlButton = 2;
HydratedCallButton callButton = 3;
}
}
message QuickReplyButton {
optional HighlyStructuredMessage displayText = 1;
optional string id = 2;
}
message URLButton {
optional HighlyStructuredMessage displayText = 1;
optional HighlyStructuredMessage url = 2;
}
message CallButton {
optional HighlyStructuredMessage displayText = 1;
optional HighlyStructuredMessage phoneNumber = 2;
}
message TemplateButton {
optional uint32 index = 4;
oneof button {
QuickReplyButton quickReplyButton = 1;
URLButton urlButton = 2;
CallButton callButton = 3;
}
}
message Location {
optional double degreesLatitude = 1;
optional double degreesLongitude = 2;
optional string name = 3;
}
message Point {
optional double x = 3;
optional double y = 4;
}
message InteractiveAnnotation {
repeated Point polygonVertices = 1;
oneof action {
Location location = 2;
}
}
message AdReplyInfo {
optional string advertiserName = 1;
enum AD_REPLY_INFO_MEDIATYPE {
NONE = 0;
IMAGE = 1;
VIDEO = 2;
}
optional AD_REPLY_INFO_MEDIATYPE mediaType = 2;
optional bytes jpegThumbnail = 16;
optional string caption = 17;
}
message ContextInfo {
optional string stanzaId = 1;
optional string participant = 2;
optional Message quotedMessage = 3;
optional string remoteJid = 4;
repeated string mentionedJid = 15;
optional string conversionSource = 18;
optional bytes conversionData = 19;
optional uint32 conversionDelaySeconds = 20;
optional uint32 forwardingScore = 21;
optional bool isForwarded = 22;
optional AdReplyInfo quotedAd = 23;
optional MessageKey placeholderKey = 24;
optional uint32 expiration = 25;
}
message SenderKeyDistributionMessage {
optional string groupId = 1;
optional bytes axolotlSenderKeyDistributionMessage = 2;
}
message ImageMessage {
optional string url = 1;
optional string mimetype = 2;
optional string caption = 3;
optional bytes fileSha256 = 4;
optional uint64 fileLength = 5;
optional uint32 height = 6;
optional uint32 width = 7;
optional bytes mediaKey = 8;
optional bytes fileEncSha256 = 9;
repeated InteractiveAnnotation interactiveAnnotations = 10;
optional string directPath = 11;
optional int64 mediaKeyTimestamp = 12;
optional bytes jpegThumbnail = 16;
optional ContextInfo contextInfo = 17;
optional bytes firstScanSidecar = 18;
optional uint32 firstScanLength = 19;
optional uint32 experimentGroupId = 20;
optional bytes scansSidecar = 21;
repeated uint32 scanLengths = 22;
optional bytes midQualityFileSha256 = 23;
optional bytes midQualityFileEncSha256 = 24;
}
message ContactMessage {
optional string displayName = 1;
optional string vcard = 16;
optional ContextInfo contextInfo = 17;
}
message LocationMessage {
optional double degreesLatitude = 1;
optional double degreesLongitude = 2;
optional string name = 3;
optional string address = 4;
optional string url = 5;
optional bytes jpegThumbnail = 16;
optional ContextInfo contextInfo = 17;
}
message ExtendedTextMessage {
optional string text = 1;
optional string matchedText = 2;
optional string canonicalUrl = 4;
optional string description = 5;
optional string title = 6;
optional fixed32 textArgb = 7;
optional fixed32 backgroundArgb = 8;
enum EXTENDED_TEXT_MESSAGE_FONTTYPE {
SANS_SERIF = 0;
SERIF = 1;
NORICAN_REGULAR = 2;
BRYNDAN_WRITE = 3;
BEBASNEUE_REGULAR = 4;
OSWALD_HEAVY = 5;
}
optional EXTENDED_TEXT_MESSAGE_FONTTYPE font = 9;
enum EXTENDED_TEXT_MESSAGE_PREVIEWTYPE {
NONE = 0;
VIDEO = 1;
}
optional EXTENDED_TEXT_MESSAGE_PREVIEWTYPE previewType = 10;
optional bytes jpegThumbnail = 16;
optional ContextInfo contextInfo = 17;
optional bool doNotPlayInline = 18;
}
message DocumentMessage {
optional string url = 1;
optional string mimetype = 2;
optional string title = 3;
optional bytes fileSha256 = 4;
optional uint64 fileLength = 5;
optional uint32 pageCount = 6;
optional bytes mediaKey = 7;
optional string fileName = 8;
optional bytes fileEncSha256 = 9;
optional string directPath = 10;
optional int64 mediaKeyTimestamp = 11;
optional bytes jpegThumbnail = 16;
optional ContextInfo contextInfo = 17;
}
message AudioMessage {
optional string url = 1;
optional string mimetype = 2;
optional bytes fileSha256 = 3;
optional uint64 fileLength = 4;
optional uint32 seconds = 5;
optional bool ptt = 6;
optional bytes mediaKey = 7;
optional bytes fileEncSha256 = 8;
optional string directPath = 9;
optional int64 mediaKeyTimestamp = 10;
optional ContextInfo contextInfo = 17;
optional bytes streamingSidecar = 18;
}
message VideoMessage {
optional string url = 1;
optional string mimetype = 2;
optional bytes fileSha256 = 3;
optional uint64 fileLength = 4;
optional uint32 seconds = 5;
optional bytes mediaKey = 6;
optional string caption = 7;
optional bool gifPlayback = 8;
optional uint32 height = 9;
optional uint32 width = 10;
optional bytes fileEncSha256 = 11;
repeated InteractiveAnnotation interactiveAnnotations = 12;
optional string directPath = 13;
optional int64 mediaKeyTimestamp = 14;
optional bytes jpegThumbnail = 16;
optional ContextInfo contextInfo = 17;
optional bytes streamingSidecar = 18;
enum VIDEO_MESSAGE_ATTRIBUTION {
NONE = 0;
GIPHY = 1;
TENOR = 2;
}
optional VIDEO_MESSAGE_ATTRIBUTION gifAttribution = 19;
}
message Call {
optional bytes callKey = 1;
}
message Chat {
optional string displayName = 1;
optional string id = 2;
}
message ProtocolMessage {
optional MessageKey key = 1;
enum PROTOCOL_MESSAGE_TYPE {
REVOKE = 0;
EPHEMERAL_SETTING = 3;
}
optional PROTOCOL_MESSAGE_TYPE type = 2;
optional uint32 ephemeralExpiration = 4;
}
message ContactsArrayMessage {
optional string displayName = 1;
repeated ContactMessage contacts = 2;
optional ContextInfo contextInfo = 17;
}
message HSMCurrency {
optional string currencyCode = 1;
optional int64 amount1000 = 2;
}
message HSMDateTimeComponent {
enum HSM_DATE_TIME_COMPONENT_DAYOFWEEKTYPE {
MONDAY = 1;
TUESDAY = 2;
WEDNESDAY = 3;
THURSDAY = 4;
FRIDAY = 5;
SATURDAY = 6;
SUNDAY = 7;
}
optional HSM_DATE_TIME_COMPONENT_DAYOFWEEKTYPE dayOfWeek = 1;
optional uint32 year = 2;
optional uint32 month = 3;
optional uint32 dayOfMonth = 4;
optional uint32 hour = 5;
optional uint32 minute = 6;
enum HSM_DATE_TIME_COMPONENT_CALENDARTYPE {
GREGORIAN = 1;
SOLAR_HIJRI = 2;
}
optional HSM_DATE_TIME_COMPONENT_CALENDARTYPE calendar = 7;
}
message HSMDateTimeUnixEpoch {
optional int64 timestamp = 1;
}
message HSMDateTime {
oneof datetimeOneof {
HSMDateTimeComponent component = 1;
HSMDateTimeUnixEpoch unixEpoch = 2;
}
}
message HSMLocalizableParameter {
optional string default = 1;
oneof paramOneof {
HSMCurrency currency = 2;
HSMDateTime dateTime = 3;
}
}
message HighlyStructuredMessage {
optional string namespace = 1;
optional string elementName = 2;
repeated string params = 3;
optional string fallbackLg = 4;
optional string fallbackLc = 5;
repeated HSMLocalizableParameter localizableParams = 6;
optional string deterministicLg = 7;
optional string deterministicLc = 8;
optional TemplateMessage hydratedHsm = 9;
}
message SendPaymentMessage {
optional Message noteMessage = 2;
optional MessageKey requestMessageKey = 3;
}
message RequestPaymentMessage {
optional Message noteMessage = 4;
optional string currencyCodeIso4217 = 1;
optional uint64 amount1000 = 2;
optional string requestFrom = 3;
optional int64 expiryTimestamp = 5;
}
message DeclinePaymentRequestMessage {
optional MessageKey key = 1;
}
message CancelPaymentRequestMessage {
optional MessageKey key = 1;
}
message LiveLocationMessage {
optional double degreesLatitude = 1;
optional double degreesLongitude = 2;
optional uint32 accuracyInMeters = 3;
optional float speedInMps = 4;
optional uint32 degreesClockwiseFromMagneticNorth = 5;
optional string caption = 6;
optional int64 sequenceNumber = 7;
optional uint32 timeOffset = 8;
optional bytes jpegThumbnail = 16;
optional ContextInfo contextInfo = 17;
}
message StickerMessage {
optional string url = 1;
optional bytes fileSha256 = 2;
optional bytes fileEncSha256 = 3;
optional bytes mediaKey = 4;
optional string mimetype = 5;
optional uint32 height = 6;
optional uint32 width = 7;
optional string directPath = 8;
optional uint64 fileLength = 9;
optional int64 mediaKeyTimestamp = 10;
optional uint32 firstFrameLength = 11;
optional bytes firstFrameSidecar = 12;
optional ContextInfo contextInfo = 17;
}
message FourRowTemplate {
optional HighlyStructuredMessage content = 6;
optional HighlyStructuredMessage footer = 7;
repeated TemplateButton buttons = 8;
oneof title {
DocumentMessage documentMessage = 1;
HighlyStructuredMessage highlyStructuredMessage = 2;
ImageMessage imageMessage = 3;
VideoMessage videoMessage = 4;
LocationMessage locationMessage = 5;
}
}
message HydratedFourRowTemplate {
optional string hydratedContentText = 6;
optional string hydratedFooterText = 7;
repeated HydratedTemplateButton hydratedButtons = 8;
optional string templateId = 9;
oneof title {
DocumentMessage documentMessage = 1;
string hydratedTitleText = 2;
ImageMessage imageMessage = 3;
VideoMessage videoMessage = 4;
LocationMessage locationMessage = 5;
}
}
message TemplateMessage {
optional ContextInfo contextInfo = 3;
optional HydratedFourRowTemplate hydratedTemplate = 4;
oneof format {
FourRowTemplate fourRowTemplate = 1;
HydratedFourRowTemplate hydratedFourRowTemplate = 2;
}
}
message TemplateButtonReplyMessage {
optional string selectedId = 1;
optional string selectedDisplayText = 2;
optional ContextInfo contextInfo = 3;
optional uint32 selectedIndex = 4;
}
message ProductSnapshot {
optional ImageMessage productImage = 1;
optional string productId = 2;
optional string title = 3;
optional string description = 4;
optional string currencyCode = 5;
optional int64 priceAmount1000 = 6;
optional string retailerId = 7;
optional string url = 8;
optional uint32 productImageCount = 9;
optional string firstImageId = 11;
}
message ProductMessage {
optional ProductSnapshot product = 1;
optional string businessOwnerJid = 2;
optional ContextInfo contextInfo = 17;
}
message GroupInviteMessage {
optional string groupJid = 1;
optional string inviteCode = 2;
optional int64 inviteExpiration = 3;
optional string groupName = 4;
optional bytes jpegThumbnail = 5;
optional string caption = 6;
optional ContextInfo contextInfo = 7;
}
message DeviceSentMessage {
optional string destinationJid = 1;
optional Message message = 2;
}
message DeviceSyncMessage {
optional bytes serializedXmlBytes = 1;
}
message Message {
optional string conversation = 1;
optional SenderKeyDistributionMessage senderKeyDistributionMessage = 2;
optional ImageMessage imageMessage = 3;
optional ContactMessage contactMessage = 4;
optional LocationMessage locationMessage = 5;
optional ExtendedTextMessage extendedTextMessage = 6;
optional DocumentMessage documentMessage = 7;
optional AudioMessage audioMessage = 8;
optional VideoMessage videoMessage = 9;
optional Call call = 10;
optional Chat chat = 11;
optional ProtocolMessage protocolMessage = 12;
optional ContactsArrayMessage contactsArrayMessage = 13;
optional HighlyStructuredMessage highlyStructuredMessage = 14;
optional SenderKeyDistributionMessage fastRatchetKeySenderKeyDistributionMessage = 15;
optional SendPaymentMessage sendPaymentMessage = 16;
optional LiveLocationMessage liveLocationMessage = 18;
optional RequestPaymentMessage requestPaymentMessage = 22;
optional DeclinePaymentRequestMessage declinePaymentRequestMessage = 23;
optional CancelPaymentRequestMessage cancelPaymentRequestMessage = 24;
optional TemplateMessage templateMessage = 25;
optional StickerMessage stickerMessage = 26;
optional GroupInviteMessage groupInviteMessage = 28;
optional TemplateButtonReplyMessage templateButtonReplyMessage = 29;
optional ProductMessage productMessage = 30;
optional DeviceSentMessage deviceSentMessage = 31;
optional DeviceSyncMessage deviceSyncMessage = 32;
}
message MessageKey {
optional string remoteJid = 1;
optional bool fromMe = 2;
optional string id = 3;
optional string participant = 4;
}
message WebFeatures {
enum WEB_FEATURES_FLAG {
NOT_STARTED = 0;
FORCE_UPGRADE = 1;
DEVELOPMENT = 2;
PRODUCTION = 3;
}
optional WEB_FEATURES_FLAG labelsDisplay = 1;
optional WEB_FEATURES_FLAG voipIndividualOutgoing = 2;
optional WEB_FEATURES_FLAG groupsV3 = 3;
optional WEB_FEATURES_FLAG groupsV3Create = 4;
optional WEB_FEATURES_FLAG changeNumberV2 = 5;
optional WEB_FEATURES_FLAG queryStatusV3Thumbnail = 6;
optional WEB_FEATURES_FLAG liveLocations = 7;
optional WEB_FEATURES_FLAG queryVname = 8;
optional WEB_FEATURES_FLAG voipIndividualIncoming = 9;
optional WEB_FEATURES_FLAG quickRepliesQuery = 10;
optional WEB_FEATURES_FLAG payments = 11;
optional WEB_FEATURES_FLAG stickerPackQuery = 12;
optional WEB_FEATURES_FLAG liveLocationsFinal = 13;
optional WEB_FEATURES_FLAG labelsEdit = 14;
optional WEB_FEATURES_FLAG mediaUpload = 15;
optional WEB_FEATURES_FLAG mediaUploadRichQuickReplies = 18;
optional WEB_FEATURES_FLAG vnameV2 = 19;
optional WEB_FEATURES_FLAG videoPlaybackUrl = 20;
optional WEB_FEATURES_FLAG statusRanking = 21;
optional WEB_FEATURES_FLAG voipIndividualVideo = 22;
optional WEB_FEATURES_FLAG thirdPartyStickers = 23;
optional WEB_FEATURES_FLAG frequentlyForwardedSetting = 24;
optional WEB_FEATURES_FLAG groupsV4JoinPermission = 25;
optional WEB_FEATURES_FLAG recentStickers = 26;
optional WEB_FEATURES_FLAG catalog = 27;
optional WEB_FEATURES_FLAG starredStickers = 28;
optional WEB_FEATURES_FLAG voipGroupCall = 29;
optional WEB_FEATURES_FLAG templateMessage = 30;
optional WEB_FEATURES_FLAG templateMessageInteractivity = 31;
optional WEB_FEATURES_FLAG ephemeralMessages = 32;
}
message TabletNotificationsInfo {
optional uint64 timestamp = 2;
optional uint32 unreadChats = 3;
optional uint32 notifyMessageCount = 4;
repeated NotificationMessageInfo notifyMessage = 5;
}
message NotificationMessageInfo {
optional MessageKey key = 1;
optional Message message = 2;
optional uint64 messageTimestamp = 3;
optional string participant = 4;
}
message WebNotificationsInfo {
optional uint64 timestamp = 2;
optional uint32 unreadChats = 3;
optional uint32 notifyMessageCount = 4;
repeated WebMessageInfo notifyMessages = 5;
}
message PaymentInfo {
optional uint64 amount1000 = 2;
optional string receiverJid = 3;
enum PAYMENT_INFO_STATUS {
UNKNOWN_STATUS = 0;
PROCESSING = 1;
SENT = 2;
NEED_TO_ACCEPT = 3;
COMPLETE = 4;
COULD_NOT_COMPLETE = 5;
REFUNDED = 6;
EXPIRED = 7;
REJECTED = 8;
CANCELLED = 9;
WAITING_FOR_PAYER = 10;
WAITING = 11;
}
optional PAYMENT_INFO_STATUS status = 4;
optional uint64 transactionTimestamp = 5;
optional MessageKey requestMessageKey = 6;
optional uint64 expiryTimestamp = 7;
optional bool futureproofed = 8;
optional string currency = 9;
}
message WebMessageInfo {
required MessageKey key = 1;
optional Message message = 2;
optional uint64 messageTimestamp = 3;
enum WEB_MESSAGE_INFO_STATUS {
ERROR = 0;
PENDING = 1;
SERVER_ACK = 2;
DELIVERY_ACK = 3;
READ = 4;
PLAYED = 5;
}
optional WEB_MESSAGE_INFO_STATUS status = 4;
optional string participant = 5;
optional bool ignore = 16;
optional bool starred = 17;
optional bool broadcast = 18;
optional string pushName = 19;
optional bytes mediaCiphertextSha256 = 20;
optional bool multicast = 21;
optional bool urlText = 22;
optional bool urlNumber = 23;
enum WEB_MESSAGE_INFO_STUBTYPE {
UNKNOWN = 0;
REVOKE = 1;
CIPHERTEXT = 2;
FUTUREPROOF = 3;
NON_VERIFIED_TRANSITION = 4;
UNVERIFIED_TRANSITION = 5;
VERIFIED_TRANSITION = 6;
VERIFIED_LOW_UNKNOWN = 7;
VERIFIED_HIGH = 8;
VERIFIED_INITIAL_UNKNOWN = 9;
VERIFIED_INITIAL_LOW = 10;
VERIFIED_INITIAL_HIGH = 11;
VERIFIED_TRANSITION_ANY_TO_NONE = 12;
VERIFIED_TRANSITION_ANY_TO_HIGH = 13;
VERIFIED_TRANSITION_HIGH_TO_LOW = 14;
VERIFIED_TRANSITION_HIGH_TO_UNKNOWN = 15;
VERIFIED_TRANSITION_UNKNOWN_TO_LOW = 16;
VERIFIED_TRANSITION_LOW_TO_UNKNOWN = 17;
VERIFIED_TRANSITION_NONE_TO_LOW = 18;
VERIFIED_TRANSITION_NONE_TO_UNKNOWN = 19;
GROUP_CREATE = 20;
GROUP_CHANGE_SUBJECT = 21;
GROUP_CHANGE_ICON = 22;
GROUP_CHANGE_INVITE_LINK = 23;
GROUP_CHANGE_DESCRIPTION = 24;
GROUP_CHANGE_RESTRICT = 25;
GROUP_CHANGE_ANNOUNCE = 26;
GROUP_PARTICIPANT_ADD = 27;
GROUP_PARTICIPANT_REMOVE = 28;
GROUP_PARTICIPANT_PROMOTE = 29;
GROUP_PARTICIPANT_DEMOTE = 30;
GROUP_PARTICIPANT_INVITE = 31;
GROUP_PARTICIPANT_LEAVE = 32;
GROUP_PARTICIPANT_CHANGE_NUMBER = 33;
BROADCAST_CREATE = 34;
BROADCAST_ADD = 35;
BROADCAST_REMOVE = 36;
GENERIC_NOTIFICATION = 37;
E2E_IDENTITY_CHANGED = 38;
E2E_ENCRYPTED = 39;
CALL_MISSED_VOICE = 40;
CALL_MISSED_VIDEO = 41;
INDIVIDUAL_CHANGE_NUMBER = 42;
GROUP_DELETE = 43;
GROUP_ANNOUNCE_MODE_MESSAGE_BOUNCE = 44;
CALL_MISSED_GROUP_VOICE = 45;
CALL_MISSED_GROUP_VIDEO = 46;
PAYMENT_CIPHERTEXT = 47;
PAYMENT_FUTUREPROOF = 48;
PAYMENT_TRANSACTION_STATUS_UPDATE_FAILED = 49;
PAYMENT_TRANSACTION_STATUS_UPDATE_REFUNDED = 50;
PAYMENT_TRANSACTION_STATUS_UPDATE_REFUND_FAILED = 51;
PAYMENT_TRANSACTION_STATUS_RECEIVER_PENDING_SETUP = 52;
PAYMENT_TRANSACTION_STATUS_RECEIVER_SUCCESS_AFTER_HICCUP = 53;
PAYMENT_ACTION_ACCOUNT_SETUP_REMINDER = 54;
PAYMENT_ACTION_SEND_PAYMENT_REMINDER = 55;
PAYMENT_ACTION_SEND_PAYMENT_INVITATION = 56;
PAYMENT_ACTION_REQUEST_DECLINED = 57;
PAYMENT_ACTION_REQUEST_EXPIRED = 58;
PAYMENT_ACTION_REQUEST_CANCELLED = 59;
BIZ_VERIFIED_TRANSITION_TOP_TO_BOTTOM = 60;
BIZ_VERIFIED_TRANSITION_BOTTOM_TO_TOP = 61;
BIZ_INTRO_TOP = 62;
BIZ_INTRO_BOTTOM = 63;
BIZ_NAME_CHANGE = 64;
BIZ_MOVE_TO_CONSUMER_APP = 65;
BIZ_TWO_TIER_MIGRATION_TOP = 66;
BIZ_TWO_TIER_MIGRATION_BOTTOM = 67;
OVERSIZED = 68;
GROUP_CHANGE_NO_FREQUENTLY_FORWARDED = 69;
GROUP_V4_ADD_INVITE_SENT = 70;
GROUP_PARTICIPANT_ADD_REQUEST_JOIN = 71;
CHANGE_EPHEMERAL_SETTING = 72;
}
optional WEB_MESSAGE_INFO_STUBTYPE messageStubType = 24;
optional bool clearMedia = 25;
repeated string messageStubParameters = 26;
optional uint32 duration = 27;
repeated string labels = 28;
optional PaymentInfo paymentInfo = 29;
optional LiveLocationMessage finalLiveLocation = 30;
optional PaymentInfo quotedPaymentInfo = 31;
optional uint64 ephemeralStartTimestamp = 32;
optional uint32 ephemeralDuration = 33;
}

File diff suppressed because it is too large Load Diff