UNPKG

lotusbail

Version:

WhatsApp API x Button by PL

37 lines (36 loc) 15.9 kB
Object.defineProperty(exports,"__esModule",{value:!0});exports.processSyncAction=exports.chatModificationToAppPatch=exports.decodePatches=exports.decodeSyncdSnapshot=exports.downloadExternalPatch=exports.downloadExternalBlob=exports.extractSyncdPatches=exports.decodeSyncdPatch=exports.decodeSyncdMutations=exports.encodeSyncdPatch=exports.newLTHashState=void 0; const boom_1=require("@hapi/boom"),WAProto_1=require("../../WAProto"),LabelAssociation_1=require("../Types/LabelAssociation"),WABinary_1=require("../WABinary"),crypto_1=require("./crypto"),generics_1=require("./generics"),lt_hash_1=require("./lt-hash"),messages_media_1=require("./messages-media"),mutationKeys=async a=>{a=await (0,crypto_1.hkdf)(a,160,{info:"WhatsApp Mutation Keys"});return{indexKey:a.slice(0,32),valueEncryptionKey:a.slice(32,64),valueMacKey:a.slice(64,96),snapshotMacKey:a.slice(96, 128),patchMacKey:a.slice(128,160)}},generateMac=(a,b,c,g)=>{let f;switch(a){case WAProto_1.proto.SyncdMutation.SyncdOperation.SET:f=1;break;case WAProto_1.proto.SyncdMutation.SyncdOperation.REMOVE:f=2}a=Buffer.from([f]);c=Buffer.concat([a,Buffer.from(c,"base64")]);a=Buffer.alloc(8);a.set([c.length],a.length-1);b=Buffer.concat([c,b,a]);return(0,crypto_1.hmacSign)(b,g,"sha512").slice(0,32)},to64BitNetworkOrder=a=>{const b=Buffer.alloc(8);b.writeUint32BE(a,4);return b},makeLtHashGenerator=({indexValueMap:a, hash:b})=>{a={...a};const c=[],g=[];return{mix:({indexMac:f,valueMac:h,operation:d})=>{const k=Buffer.from(f).toString("base64"),l=a[k];if(d===WAProto_1.proto.SyncdMutation.SyncdOperation.REMOVE){if(!l)throw new boom_1.Boom("tried remove, but no previous op",{data:{indexMac:f,valueMac:h}});delete a[k]}else c.push((new Uint8Array(h)).buffer),a[k]={valueMac:h};l&&g.push((new Uint8Array(l.valueMac)).buffer)},finish:async()=>{var f=(new Uint8Array(b)).buffer;f=await lt_hash_1.LT_HASH_ANTI_TAMPERING.subtractThenAdd(f, c,g);return{hash:Buffer.from(f),indexValueMap:a}}}},generateSnapshotMac=(a,b,c,g)=>{a=Buffer.concat([a,to64BitNetworkOrder(b),Buffer.from(c,"utf-8")]);return(0,crypto_1.hmacSign)(a,g,"sha256")},generatePatchMac=(a,b,c,g,f)=>{a=Buffer.concat([a,...b,to64BitNetworkOrder(c),Buffer.from(g,"utf-8")]);return(0,crypto_1.hmacSign)(a,f)},newLTHashState=()=>({version:0,hash:Buffer.alloc(128),indexValueMap:{}});exports.newLTHashState=newLTHashState; const encodeSyncdPatch=async({type:a,index:b,syncAction:c,apiVersion:g,operation:f},h,d,k)=>{k=h?await k(h):void 0;if(!k)throw new boom_1.Boom(`myAppStateKey ("${h}") not present`,{statusCode:404});h=Buffer.from(h,"base64");d={...d,indexValueMap:{...d.indexValueMap}};b=Buffer.from(JSON.stringify(b));c=WAProto_1.proto.SyncActionData.fromObject({index:b,value:c,padding:new Uint8Array(0),version:g});g=WAProto_1.proto.SyncActionData.encode(c).finish();c=await mutationKeys(k.keyData);g=(0,crypto_1.aesEncrypt)(g, c.valueEncryptionKey);k=generateMac(f,g,h,c.valueMacKey);b=(0,crypto_1.hmacSign)(b,c.indexKey);var l=makeLtHashGenerator(d);l.mix({indexMac:b,valueMac:k,operation:f});Object.assign(d,await l.finish());d.version+=1;l=generateSnapshotMac(d.hash,d.version,a,c.snapshotMacKey);a={patchMac:generatePatchMac(l,[k],d.version,a,c.patchMacKey),snapshotMac:l,keyId:{id:h},mutations:[{operation:f,record:{index:{blob:b},value:{blob:Buffer.concat([g,k])},keyId:{id:h}}}]};f=b.toString("base64");d.indexValueMap[f]= {valueMac:k};return{patch:a,state:d}};exports.encodeSyncdPatch=encodeSyncdPatch; const decodeSyncdMutations=async(a,b,c,g,f)=>{async function h(n){n=Buffer.from(n).toString("base64");const p=await c(n);if(!p)throw new boom_1.Boom(`failed to find key "${n}" to decode mutation`,{statusCode:404,data:{msgMutations:a}});return mutationKeys(p.keyData)}b=makeLtHashGenerator(b);for(const n of a){const p="operation"in n?n.operation:WAProto_1.proto.SyncdMutation.SyncdOperation.SET,m="record"in n&&n.record?n.record:n;var d=await h(m.keyId.id),k=Buffer.from(m.value.blob),l=k.slice(0,-32); k=k.slice(-32);if(f){const e=generateMac(p,l,m.keyId.id,d.valueMacKey);if(0!==Buffer.compare(e,k))throw new boom_1.Boom("HMAC content verification failed");}l=(0,crypto_1.aesDecrypt)(l,d.valueEncryptionKey);l=WAProto_1.proto.SyncActionData.decode(l);if(f&&(d=(0,crypto_1.hmacSign)(l.index,d.indexKey),0!==Buffer.compare(d,m.index.blob)))throw new boom_1.Boom("HMAC index verification failed");d=Buffer.from(l.index).toString();g({syncAction:l,index:JSON.parse(d)});b.mix({indexMac:m.index.blob,valueMac:k, operation:p})}return await b.finish()};exports.decodeSyncdMutations=decodeSyncdMutations; const decodeSyncdPatch=async(a,b,c,g,f,h)=>{if(h){var d=Buffer.from(a.keyId.id).toString("base64"),k=await g(d);if(!k)throw new boom_1.Boom(`failed to find key "${d}" to decode patch`,{statusCode:404,data:{msg:a}});d=await mutationKeys(k.keyData);k=a.mutations.map(l=>l.record.value.blob.slice(-32));b=generatePatchMac(a.snapshotMac,k,(0,generics_1.toNumber)(a.version.version),b,d.patchMacKey);if(0!==Buffer.compare(b,a.patchMac))throw new boom_1.Boom("Invalid patch mac");}return await (0,exports.decodeSyncdMutations)(a.mutations, c,g,f,h)};exports.decodeSyncdPatch=decodeSyncdPatch; const extractSyncdPatches=async(a,b)=>{a=(0,WABinary_1.getBinaryNodeChild)(a,"sync");a=(0,WABinary_1.getBinaryNodeChildren)(a,"collection");const c={};await Promise.all(a.map(async g=>{var f=(0,WABinary_1.getBinaryNodeChild)(g,"patches"),h=(0,WABinary_1.getBinaryNodeChildren)(f||g,"patch");const d=(0,WABinary_1.getBinaryNodeChild)(g,"snapshot");f=[];const k=g.attrs.name,l="true"===g.attrs.has_more_patches;var n=void 0;d&&d.content&&(Buffer.isBuffer(d)||(d.content=Buffer.from(Object.values(d.content))), n=WAProto_1.proto.ExternalBlobReference.decode(d.content),n=await (0,exports.downloadExternalBlob)(n,b),n=WAProto_1.proto.SyncdSnapshot.decode(n));for(let {content:p}of h)p&&(Buffer.isBuffer(p)||(p=Buffer.from(Object.values(p))),h=WAProto_1.proto.SyncdPatch.decode(p),h.version||(h.version={version:+g.attrs.version+1}),f.push(h));c[k]={patches:f,hasMorePatches:l,snapshot:n}}));return c};exports.extractSyncdPatches=extractSyncdPatches; const downloadExternalBlob=async(a,b)=>{a=await (0,messages_media_1.downloadContentFromMessage)(a,"md-app-state",{options:b});b=[];for await(const c of a)b.push(c);return Buffer.concat(b)};exports.downloadExternalBlob=downloadExternalBlob;const downloadExternalPatch=async(a,b)=>{a=await (0,exports.downloadExternalBlob)(a,b);return WAProto_1.proto.SyncdMutations.decode(a)};exports.downloadExternalPatch=downloadExternalPatch; const decodeSyncdSnapshot=async(a,b,c,g,f=!0)=>{const h=(0,exports.newLTHashState)();h.version=(0,generics_1.toNumber)(b.version.version);const d={},{hash:k,indexValueMap:l}=await (0,exports.decodeSyncdMutations)(b.records,h,c,"undefined"===typeof g||h.version>g?n=>{var p;const m=null===(p=n.syncAction.index)||void 0===p?void 0:p.toString();d[m]=n}:()=>{},f);h.hash=k;h.indexValueMap=l;if(f){g=Buffer.from(b.keyId.id).toString("base64");c=await c(g);if(!c)throw new boom_1.Boom(`failed to find key "${g}" to decode mutation`); c=await mutationKeys(c.keyData);c=generateSnapshotMac(h.hash,h.version,a,c.snapshotMacKey);if(0!==Buffer.compare(b.mac,c))throw new boom_1.Boom(`failed to verify LTHash at ${h.version} of ${a} from snapshot`);}return{state:h,mutationMap:d}};exports.decodeSyncdSnapshot=decodeSyncdSnapshot; const decodePatches=async(a,b,c,g,f,h,d,k=!0)=>{var l;c={...c,indexValueMap:{...c.indexValueMap}};const n={};for(const p of b){const {version:m,keyId:e,snapshotMac:r}=p;p.externalMutations&&(null===d||void 0===d||d.trace({name:a,version:m},"downloading external patch"),b=await (0,exports.downloadExternalPatch)(p.externalMutations,f),null===d||void 0===d||d.debug({name:a,version:m,mutations:b.mutations.length},"downloaded external patch"),null===(l=p.mutations)||void 0===l||l.push(...b.mutations)); b=(0,generics_1.toNumber)(m.version);c.version=b;b=await (0,exports.decodeSyncdPatch)(p,a,c,g,"undefined"===typeof h||b>h?q=>{var v;const w=null===(v=q.syncAction.index)||void 0===v?void 0:v.toString();n[w]=q}:()=>{},!0);c.hash=b.hash;c.indexValueMap=b.indexValueMap;if(k){b=Buffer.from(e.id).toString("base64");const q=await g(b);if(!q)throw new boom_1.Boom(`failed to find key "${b}" to decode mutation`);b=await mutationKeys(q.keyData);b=generateSnapshotMac(c.hash,c.version,a,b.snapshotMacKey);if(0!== Buffer.compare(r,b))throw new boom_1.Boom(`failed to verify LTHash at ${c.version} of ${a}`);}p.mutations=[]}return{state:c,mutationMap:n}};exports.decodePatches=decodePatches; const chatModificationToAppPatch=(a,b)=>{const c=WAProto_1.proto.SyncdMutation.SyncdOperation;var g=f=>{if(Array.isArray(f)){const h=f[f.length-1];f={lastMessageTimestamp:null===h||void 0===h?void 0:h.messageTimestamp,messages:(null===f||void 0===f?0:f.length)?f.map(d=>{var k,l;if(!((null===(k=d.key)||void 0===k?0:k.id)&&(null===(l=d.key)||void 0===l?0:l.remoteJid)))throw new boom_1.Boom("Incomplete key",{statusCode:400,data:d});if((0,WABinary_1.isJidGroup)(d.key.remoteJid)&&!d.key.fromMe&&!d.key.participant)throw new boom_1.Boom("Expected not from me message to have participant", {statusCode:400,data:d});if(!d.messageTimestamp||!(0,generics_1.toNumber)(d.messageTimestamp))throw new boom_1.Boom("Missing timestamp in last message list",{statusCode:400,data:d});d.key.participant&&(d.key.participant=(0,WABinary_1.jidNormalizedUser)(d.key.participant));return d}):void 0}}return f};if("mute"in a)a={syncAction:{muteAction:{muted:!!a.mute,muteEndTimestamp:a.mute||void 0}},index:["mute",b],type:"regular_high",apiVersion:2,operation:c.SET};else if("archive"in a)a={syncAction:{archiveChatAction:{archived:!!a.archive, messageRange:g(a.lastMessages)}},index:["archive",b],type:"regular_low",apiVersion:3,operation:c.SET};else if("markRead"in a)a={syncAction:{markChatAsReadAction:{read:a.markRead,messageRange:g(a.lastMessages)}},index:["markChatAsRead",b],type:"regular_low",apiVersion:3,operation:c.SET};else if("deleteForMe"in a){const {timestamp:f,key:h,deleteMedia:d}=a.deleteForMe;a={syncAction:{deleteMessageForMeAction:{deleteMedia:d,messageTimestamp:f}},index:["deleteMessageForMe",b,h.id,h.fromMe?"1":"0","0"], type:"regular_high",apiVersion:3,operation:c.SET}}else if("clear"in a)a={syncAction:{clearChatAction:{messageRange:g(a.lastMessages)}},index:["clearChat",b,"1","0"],type:"regular_high",apiVersion:6,operation:c.SET};else if("pin"in a)a={syncAction:{pinAction:{pinned:!!a.pin}},index:["pin_v1",b],type:"regular_low",apiVersion:5,operation:c.SET};else if("contact"in a)a={syncAction:{contactAction:a.contact||{}},index:["contact",b],type:"critical_unblock_low",apiVersion:2,operation:a.contact?c.SET:c.REMOVE}; else if("star"in a)g=a.star.messages[0],a={syncAction:{starAction:{starred:!!a.star.star}},index:["star",b,g.id,g.fromMe?"1":"0","0"],type:"regular_low",apiVersion:2,operation:c.SET};else if("delete"in a)a={syncAction:{deleteChatAction:{messageRange:g(a.lastMessages)}},index:["deleteChat",b,"1"],type:"regular_high",apiVersion:6,operation:c.SET};else if("pushNameSetting"in a)a={syncAction:{pushNameSetting:{name:a.pushNameSetting}},index:["setting_pushName"],type:"critical_block",apiVersion:1,operation:c.SET}; else if("addLabel"in a)a={syncAction:{labelEditAction:{name:a.addLabel.name,color:a.addLabel.color,predefinedId:a.addLabel.predefinedId,deleted:a.addLabel.deleted}},index:["label_edit",a.addLabel.id],type:"regular",apiVersion:3,operation:c.SET};else if("addChatLabel"in a)a={syncAction:{labelAssociationAction:{labeled:!0}},index:[LabelAssociation_1.LabelAssociationType.Chat,a.addChatLabel.labelId,b],type:"regular",apiVersion:3,operation:c.SET};else if("removeChatLabel"in a)a={syncAction:{labelAssociationAction:{labeled:!1}}, index:[LabelAssociation_1.LabelAssociationType.Chat,a.removeChatLabel.labelId,b],type:"regular",apiVersion:3,operation:c.SET};else if("addMessageLabel"in a)a={syncAction:{labelAssociationAction:{labeled:!0}},index:[LabelAssociation_1.LabelAssociationType.Message,a.addMessageLabel.labelId,b,a.addMessageLabel.messageId,"0","0"],type:"regular",apiVersion:3,operation:c.SET};else if("removeMessageLabel"in a)a={syncAction:{labelAssociationAction:{labeled:!1}},index:[LabelAssociation_1.LabelAssociationType.Message, a.removeMessageLabel.labelId,b,a.removeMessageLabel.messageId,"0","0"],type:"regular",apiVersion:3,operation:c.SET};else throw new boom_1.Boom("not supported");a.syncAction.timestamp=Date.now();return a};exports.chatModificationToAppPatch=chatModificationToAppPatch; const processSyncAction=(a,b,c,g,f)=>{function h(x,t){return p?u=>{if(u=u.historySets.chats[x]||u.chatUpserts[x])return t?Number((null===t||void 0===t?void 0:t.lastMessageTimestamp)||(null===t||void 0===t?void 0:t.lastSystemMessageTimestamp)||0)>=Number((null===u||void 0===u?void 0:u.lastMessageRecvTimestamp)||0):!0}:void 0}var d,k,l,n;const p=!!g;var m=null===g||void 0===g?void 0:g.accountSettings;null===f||void 0===f||f.trace({syncAction:a,initialSync:!!g},"processing sync action");const {syncAction:{value:e}, index:[r,q,v,w]}=a;if(null===e||void 0===e?0:e.muteAction)b.emit("chats.update",[{id:q,muteEndTime:(null===(d=e.muteAction)||void 0===d?0:d.muted)?(0,generics_1.toNumber)(e.muteAction.muteEndTimestamp):null,conditional:h(q,void 0)}]);else if((null===e||void 0===e?0:e.archiveChatAction)||"archive"===r||"unarchive"===r)a=null===e||void 0===e?void 0:e.archiveChatAction,b.emit("chats.update",[{id:q,archived:a?a.archived:"archive"===r,conditional:h(q,(null===m||void 0===m?0:m.unarchiveChats)?null===a|| void 0===a?void 0:a.messageRange:void 0)}]);else if(null===e||void 0===e?0:e.markChatAsReadAction)m=e.markChatAsReadAction,b.emit("chats.update",[{id:q,unreadCount:p&&m.read?null:(null===m||void 0===m?0:m.read)?0:-1,conditional:h(q,null===m||void 0===m?void 0:m.messageRange)}]);else if((null===e||void 0===e?0:e.deleteMessageForMeAction)||"deleteMessageForMe"===r)b.emit("messages.delete",{keys:[{remoteJid:q,id:v,fromMe:"1"===w}]});else if(null===e||void 0===e?0:e.contactAction)b.emit("contacts.upsert", [{id:q,name:e.contactAction.fullName,lid:e.contactAction.lidJid||void 0,jid:(0,WABinary_1.isJidUser)(q)?q:void 0}]);else if(null===e||void 0===e?0:e.pushNameSetting)(m=null===(k=null===e||void 0===e?void 0:e.pushNameSetting)||void 0===k?void 0:k.name)&&(null===c||void 0===c?void 0:c.name)!==m&&b.emit("creds.update",{me:{...c,name:m}});else if(null===e||void 0===e?0:e.pinAction)b.emit("chats.update",[{id:q,pinned:(null===(l=e.pinAction)||void 0===l?0:l.pinned)?(0,generics_1.toNumber)(e.timestamp): null,conditional:h(q,void 0)}]);else if(null===e||void 0===e?0:e.unarchiveChatsSetting)a=!!e.unarchiveChatsSetting.unarchiveChats,b.emit("creds.update",{accountSettings:{unarchiveChats:a}}),null===f||void 0===f||f.info(`archive setting updated => '${e.unarchiveChatsSetting.unarchiveChats}'`),m&&(m.unarchiveChats=a);else if((null===e||void 0===e?0:e.starAction)||"star"===r)m=null===(n=null===e||void 0===e?void 0:e.starAction)||void 0===n?void 0:n.starred,"boolean"!==typeof m&&(m="1"===a.index[a.index.length- 1]),b.emit("messages.update",[{key:{remoteJid:q,id:v,fromMe:"1"===w},update:{starred:m}}]);else if((null===e||void 0===e?0:e.deleteChatAction)||"deleteChat"===r)p||b.emit("chats.delete",[q]);else if(null===e||void 0===e?0:e.labelEditAction){const {name:x,color:t,deleted:u,predefinedId:y}=e.labelEditAction;b.emit("labels.edit",{id:q,name:x,color:t,deleted:u,predefinedId:y?String(y):void 0})}else(null===e||void 0===e?0:e.labelAssociationAction)?b.emit("labels.association",{type:e.labelAssociationAction.labeled? "add":"remove",association:r===LabelAssociation_1.LabelAssociationType.Chat?{type:LabelAssociation_1.LabelAssociationType.Chat,chatId:a.index[2],labelId:a.index[1]}:{type:LabelAssociation_1.LabelAssociationType.Message,chatId:a.index[2],messageId:a.index[3],labelId:a.index[1]}}):null===f||void 0===f||f.debug({syncAction:a,id:q},"unprocessable update")};exports.processSyncAction=processSyncAction;