whatsapp-web.js 1.20.0-alpha.0 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.wwebjs_cache/2.2320.10.html +2 -0
- package/.wwebjs_cache/2.2322.15.html +2 -0
- package/README.md +1 -1
- package/example.js +59 -7
- package/index.d.ts +93 -1
- package/package.json +1 -1
- package/src/Client.js +137 -3
- package/src/structures/Chat.js +6 -0
- package/src/structures/GroupChat.js +25 -0
- package/src/structures/Message.js +61 -14
- package/src/util/Constants.js +11 -1
- package/src/util/Injected.js +93 -8
- package/src/util/InterfaceController.js +4 -2
- package/src/webCache/LocalWebCache.js +43 -0
- package/src/webCache/RemoteWebCache.js +40 -0
- package/src/webCache/WebCache.js +14 -0
- package/src/webCache/WebCacheFactory.js +20 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
<!DOCTYPE html><html class="no-js" dir="ltr" loc="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><title>WhatsApp Web</title><meta name="viewport" content="width=device-width"><meta name="google" content="notranslate"><meta name="format-detection" content="telephone=no"><meta name="description" content="Quickly send and receive WhatsApp messages right from your computer."><meta name="og:description" content="Quickly send and receive WhatsApp messages right from your computer."><meta name="og:url" content="https://web.whatsapp.com/"><meta name="og:title" content="WhatsApp Web"><meta name="og:image" content="https://static.facebook.com/images/whatsapp/www/whatsapp-promo.png"><link id="favicon" rel="shortcut icon" href="/img/favicon/1x/favicon.png" type="image/png"><link rel="apple-touch-icon" sizes="194x194" href="/apple-touch-icon.png" type="image/png"><meta name="theme-color" content="#111b21" media="(prefers-color-scheme: dark)"><meta name="theme-color" content="#f0f2f5"><link id="whatsapp-pwa-manifest-link" rel="manifest" href="/manifest.json" crossorigin="use-credentials"><style>#initial_startup{--startup-background:#f0f2f5;--startup-background-rgb:240,242,245;--startup-icon:#bbc5cb;--secondary-lighter:#8696a0;--primary-title:#41525d;--progress-primary:#00c298;--progress-background:#e9edef}.dark #initial_startup{--startup-background:#111b21;--startup-background-rgb:17,27,33;--startup-icon:#676f73;--primary-title:rgba(233, 237, 239, 0.88);--secondary-lighter:#667781;--progress-primary:#0b846d;--progress-background:#233138}#app,body,html{width:100%;height:100%;padding:0;margin:0;overflow:hidden}#app{position:absolute;top:0;left:0}#initial_startup{position:fixed;top:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;user-select:none;background-color:var(--startup-background)}#initial_startup .graphic{margin-top:-40px;color:var(--startup-icon)}#initial_startup .graphic .resume-logo{transform:translateX(calc(50% - 52px / 2))}#initial_startup .graphic::after{position:relative;top:-100%;left:calc(50% - 72px * 2 - 72px / 2);display:block;width:calc(72px * 3);height:100%;content:'';background:linear-gradient(to right,rgba(var(--startup-background-rgb),.5) 0,rgba(var(--startup-background-rgb),.5) 33.33%,rgba(var(--startup-background-rgb),0) 44.1%,rgba(var(--startup-background-rgb),0) 55.8%,rgba(var(--startup-background-rgb),.5) 66.66%,rgba(var(--startup-background-rgb),.5) 100%);opacity:1;animation:shimmer 1.5s linear .6s infinite}html[dir=rtl] #initial_startup .graphic::after{animation-direction:reverse}@keyframes shimmer{from{left:calc(50% - 72px * 2 - 72px / 2)}to{left:calc(50% - 72px / 2)}}#initial_startup .progress{position:relative;width:420px;height:3px;margin-top:40px}#initial_startup .progress progress{vertical-align:top}#initial_startup .main{margin-top:40px;font-size:17px;color:var(--primary-title)}#initial_startup .secondary{margin-top:12px;font-size:14px;color:var(--secondary-lighter)}#initial_startup .secondary span{display:inline-block;margin-bottom:2px;vertical-align:middle}progress{-webkit-appearance:none;appearance:none;width:100%;height:3px;margin:0;color:var(--progress-primary);background-color:var(--progress-background);border:none}progress[value]::-webkit-progress-bar{background-color:var(--progress-background)}progress[value]::-moz-progress-bar,progress[value]::-webkit-progress-value{background-color:var(--progress-primary);transition:width .45s ease}</style><link href="/stylex-4a088306e44f3215558b4ef8b78657c5.css" rel="stylesheet"><link href="/app-a2c2cd1b2aea3ab61005.css" rel="stylesheet"></head><body class="web"><script data-binary-transparency-hash-key="inline-js-4b79b6dc91a7ee33373b115991c3eb287ed710cfb6708421b4cab682eddbfcbd">try{var systemThemeDark,theme=window.localStorage.getItem(""),systemThemeMode=window.localStorage.getItem("system-theme-mode");if(("true"===systemThemeMode||!theme)&&window.matchMedia){var systemTheme=window.matchMedia("(prefers-color-scheme: dark)");systemThemeDark=systemTheme&&systemTheme.matches}var darkTheme='"dark"'===theme||Boolean(systemThemeDark);darkTheme&&document.body.classList.add("dark")}catch(e){}</script><div id="app"></div><div id="hard_expire_time" data-time="1699300794.986"></div><div id="initial_startup"><div class="graphic"><span><svg width="250" height="52" xmlns="http://www.w3.org/2000/svg"><path class="resume-logo" d="M37.7 31.2c-.6-.4-3.8-2-4.4-2.1-.6-.2-1-.4-1.4.3l-2 2.5c-.4.4-.8.5-1.5.2-.6-.3-2.7-1-5.1-3.2-2-1.7-3.2-3.8-3.6-4.5-.4-.6 0-1 .3-1.3l1-1.1.6-1.1c.2-.4 0-.8 0-1.1l-2-4.8c-.6-1.3-1.1-1-1.5-1.1h-1.2c-.5 0-1.2.1-1.8.8-.5.6-2.2 2.2-2.2 5.3 0 3.2 2.3 6.3 2.6 6.7.3.4 4.6 7 11 9.7l3.7 1.4c1.5.5 3 .4 4 .2 1.3-.1 3.9-1.5 4.4-3 .5-1.5.5-2.8.4-3-.2-.4-.6-.5-1.3-.8M26 47.2c-3.9 0-7.6-1-11-3l-.7-.4-8.1 2L8.4 38l-.6-.8A21.4 21.4 0 0126 4.4a21.3 21.3 0 0121.4 21.4c0 11.8-9.6 21.4-21.4 21.4M44.2 7.6a25.8 25.8 0 00-40.6 31L0 52l13.7-3.6A25.8 25.8 0 0044.3 7.5" fill="currentColor"></path></svg></span></div><div class="progress"><progress value="0" max="100" dir="ltr"></progress></div><div class="main">WhatsApp</div><div class="secondary"><span><svg width="10" height="12" xmlns="http://www.w3.org/2000/svg"><path d="M5 1.6c1.4 0 2.5 1 2.6 2.4v1.5h.2c.5 0 1 .4 1 1V10c0 .6-.5 1-1 1H2.3a1 1 0 01-1.1-1V6.5c0-.6.5-1 1-1h.2V4.2c0-1.4 1-2.5 2.4-2.6H5zm0 1.2c-.7 0-1.3.6-1.3 1.3v1.4h2.6V4.2c0-.7-.4-1.2-1-1.3H5z" fill="currentColor"></path></svg> </span> End-to-end encrypted</div></div><link rel="preload" crossorigin="anonymous" as="fetch" href="/binary-transparency-manifest-2.2320.10.json" id="binary-transparency-manifest-preload"><script src="/libsignal-protocol-ee5b8ba.min.js"></script><script defer="defer" src="/runtime.48c50558556d819fec57.js"></script><script data-binary-transparency-hash-key="inline-js-026e63eb49dc1ea304d8d5b3073c120b618f17c45d3e4186fc3a06527b75bc4a">/*! Copyright (c) 2023 WhatsApp Inc. All Rights Reserved. */
|
|
2
|
+
(self.webpackChunkwhatsapp_web_client=self.webpackChunkwhatsapp_web_client||[]).push([[5617],{307914:e=>{e.exports=function(e){return e&&e.__esModule?e:{default:e}}},595318:e=>{e.exports=function(e){return e&&e.__esModule?e:{default:e}},e.exports.default=e.exports,e.exports.__esModule=!0},415227:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){const t=new Error(e);if(void 0===t.stack)try{throw t}catch(e){}return t}},670983:(e,t,r)=>{"use strict";var n=r(307914);Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"?";if(null==e)throw(0,o.default)("Unexpected null or undefined: "+t);return e};var o=n(r(415227))},801506:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TICKET_URL=t.CLB_URL=t.CLB_TOKEN=t.CLB_CHECK_URL=void 0,t.CLB_CHECK_URL="https://crashlogs.whatsapp.net/wa_fls_upload_check",t.CLB_TOKEN="1063127757113399|745146ffa34413f9dbb5469f5370b7af",t.CLB_URL="https://crashlogs.whatsapp.net/wa_clb_data",t.TICKET_URL="https://web.whatsapp.com/web-contact-us"},207024:(e,t,r)=>{"use strict";var n=r(595318);Object.defineProperty(t,"__esModule",{value:!0}),t.getDistribution=function(){let e="unknown";return e="prod","web_prod"},t.getLogUserAgent=function(e){let t,{appVersion:r,browser:n,device:o}=e;return t="Web/"+n,`WhatsApp/${r} ${t} Device/${o}`},n(r(556869))},794858:(e,t,r)=>{"use strict";var n=r(595318),o=n(r(670983)),a=r(801506),s=r(207024),c=n(r(174285)),u=r(425017);function i(e){!function(e,t){const r=window.navigator.userAgent;if(r===p&&e.includes("getElementsByTagName"))return;const n=new FormData,i=new Blob([e],{type:"text/plain"});n.append("from_jid",function(){if(f)return f;try{f=JSON.parse((0,o.default)(c.default,"localStorage").getItem(d)),f&&(f=f.replace("-",""))}catch(e){}if(!f){f="unknown"+Math.floor(1e10*Math.random());const e=f;try{(0,o.default)(c.default,"localStorage").setItem(d,JSON.stringify(e))}catch(e){}}return(0,o.default)(f,"id")}()),n.append("agent",(0,s.getLogUserAgent)((0,u.parseUASimple)(r,"2.2320.10"))),n.append("file",i,"logs.txt"),n.append("tags","load");const l=new XMLHttpRequest,_=a.CLB_URL+"?access_token="+encodeURIComponent(a.CLB_TOKEN);l.open("POST",_,!0),l.send(n)}(e)}function l(e){let{error:t,reason:r,stack:n}=e;const o=(new Date).toISOString();return`${o}: error: ${t}\n${o}: reason for logs: ${r}\n${o}: userAgent: ${window.navigator.userAgent}\n${n}`}null==window.onerror&&(window.onerror=function(e,t,r){const n=t.split("?")[0];return"Uncaught SyntaxError: Unexpected token '<'"===e?(function(e){i(l({error:"failed to load a js or css bundle",reason:`failed to load [${e.split("/")[3].replace(/^\//,"")}]`,stack:""}))}(n),!0):(i(l({error:e,reason:`Error at [${n}:${r}]`,stack:""})),!1)});const d="WAUnknownID",p="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";let f},425017:(e,t)=>{"use strict";function r(e){return e.includes("windows")?"Windows":e.includes("mac")?"Mac OS":e.includes("linux")?"Linux":"Unparsed"}Object.defineProperty(t,"__esModule",{value:!0}),t.parseUASimple=function(e,t){const n=e.toLowerCase();return{browser:s(n),device:r(n),appVersion:t}};const n=/(chrome|firefox)\/([\w\.]+)/i,o=/(edge|opr)\/([\w\.]+)/i,a={chrome:"Chrome",edge:"Edge",opr:"Opera",firefox:"Firefox"};function s(e){const t=e.match(o)||e.match(n);return null==t?"Unparsed":`${a[t[1]]} ${t[2]}`}},174285:(e,t)=>{"use strict";let r;Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;try{r=window.localStorage}catch(e){}var n=r;t.default=n},556869:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function e(t){const r=new Error(t);if(void 0===r.stack)try{throw e}catch(e){}return r}}},e=>{"use strict";e(e.s=794858)}])</script><script defer="defer" src="/vendor1~app.a91035d81a749b3d5627.js"></script><script defer="defer" src="/app.e77d49e02fab96b93f06.js"></script><script data-binary-transparency-hash-key="inline-js-9c8cd3d0f4d5af8c7f5cd1c45208edd308bfe472e353a50e4cbacbf6cb58627c">(i => {const l = document.getElementById(i); l &&fetch(l.href).then(b => b.text()).then(code => {const script = document.createElement('script');script.id = 'binary-transparency-manifest';script.type = 'application/json';script.innerHTML = code;document.body.append(script);});})('binary-transparency-manifest-preload');</script></body></html>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
<!DOCTYPE html><html class="no-js" dir="ltr" loc="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><title>WhatsAppX Web</title><meta name="viewport" content="width=device-width"><meta name="google" content="notranslate"><meta name="format-detection" content="telephone=no"><meta name="description" content="Quickly send and receive WhatsApp messages right from your computer."><meta name="og:description" content="Quickly send and receive WhatsApp messages right from your computer."><meta name="og:url" content="https://web.whatsapp.com/"><meta name="og:title" content="WhatsApp Web"><meta name="og:image" content="https://static.facebook.com/images/whatsapp/www/whatsapp-promo.png"><link id="favicon" rel="shortcut icon" href="/img/favicon/1x/favicon.png" type="image/png"><link rel="apple-touch-icon" sizes="194x194" href="/apple-touch-icon.png" type="image/png"><meta name="theme-color" content="#111b21" media="(prefers-color-scheme: dark)"><meta name="theme-color" content="#f0f2f5"><link id="whatsapp-pwa-manifest-link" rel="manifest" href="/manifest.json" crossorigin="use-credentials"><style>#initial_startup{--startup-background:#f0f2f5;--startup-background-rgb:240,242,245;--startup-icon:#bbc5cb;--secondary-lighter:#8696a0;--primary-title:#41525d;--progress-primary:#00c298;--progress-background:#e9edef}.dark #initial_startup{--startup-background:#111b21;--startup-background-rgb:17,27,33;--startup-icon:#676f73;--primary-title:rgba(233, 237, 239, 0.88);--secondary-lighter:#667781;--progress-primary:#0b846d;--progress-background:#233138}#app,body,html{width:100%;height:100%;padding:0;margin:0;overflow:hidden}#app{position:absolute;top:0;left:0}#initial_startup{position:fixed;top:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;user-select:none;background-color:var(--startup-background)}#initial_startup .graphic{margin-top:-40px;color:var(--startup-icon)}#initial_startup .graphic .resume-logo{transform:translateX(calc(50% - 52px / 2))}#initial_startup .graphic::after{position:relative;top:-100%;left:calc(50% - 72px * 2 - 72px / 2);display:block;width:calc(72px * 3);height:100%;content:'';background:linear-gradient(to right,rgba(var(--startup-background-rgb),.5) 0,rgba(var(--startup-background-rgb),.5) 33.33%,rgba(var(--startup-background-rgb),0) 44.1%,rgba(var(--startup-background-rgb),0) 55.8%,rgba(var(--startup-background-rgb),.5) 66.66%,rgba(var(--startup-background-rgb),.5) 100%);opacity:1;animation:shimmer 1.5s linear .6s infinite}html[dir=rtl] #initial_startup .graphic::after{animation-direction:reverse}@keyframes shimmer{from{left:calc(50% - 72px * 2 - 72px / 2)}to{left:calc(50% - 72px / 2)}}#initial_startup .progress{position:relative;width:420px;height:3px;margin-top:40px}#initial_startup .progress progress{vertical-align:top}#initial_startup .main{margin-top:40px;font-size:17px;color:var(--primary-title)}#initial_startup .secondary{margin-top:12px;font-size:14px;color:var(--secondary-lighter)}#initial_startup .secondary span{display:inline-block;margin-bottom:2px;vertical-align:middle}progress{-webkit-appearance:none;appearance:none;width:100%;height:3px;margin:0;color:var(--progress-primary);background-color:var(--progress-background);border:none}progress[value]::-webkit-progress-bar{background-color:var(--progress-background)}progress[value]::-moz-progress-bar,progress[value]::-webkit-progress-value{background-color:var(--progress-primary);transition:width .45s ease}</style><link href="/stylex-534e186735a7216f8166323ac4f40ec0.css" rel="stylesheet"><link href="/app-397dc77d692df7ff99b6.css" rel="stylesheet"></head><body class="web"><script data-binary-transparency-hash-key="inline-js-4b79b6dc91a7ee33373b115991c3eb287ed710cfb6708421b4cab682eddbfcbd">try{var systemThemeDark,theme=window.localStorage.getItem(""),systemThemeMode=window.localStorage.getItem("system-theme-mode");if(("true"===systemThemeMode||!theme)&&window.matchMedia){var systemTheme=window.matchMedia("(prefers-color-scheme: dark)");systemThemeDark=systemTheme&&systemTheme.matches}var darkTheme='"dark"'===theme||Boolean(systemThemeDark);darkTheme&&document.body.classList.add("dark")}catch(e){}</script><div id="app"></div><div id="hard_expire_time" data-time="1700350311.621"></div><div id="initial_startup"><div class="graphic"><span><svg width="250" height="52" xmlns="http://www.w3.org/2000/svg"><path class="resume-logo" d="M37.7 31.2c-.6-.4-3.8-2-4.4-2.1-.6-.2-1-.4-1.4.3l-2 2.5c-.4.4-.8.5-1.5.2-.6-.3-2.7-1-5.1-3.2-2-1.7-3.2-3.8-3.6-4.5-.4-.6 0-1 .3-1.3l1-1.1.6-1.1c.2-.4 0-.8 0-1.1l-2-4.8c-.6-1.3-1.1-1-1.5-1.1h-1.2c-.5 0-1.2.1-1.8.8-.5.6-2.2 2.2-2.2 5.3 0 3.2 2.3 6.3 2.6 6.7.3.4 4.6 7 11 9.7l3.7 1.4c1.5.5 3 .4 4 .2 1.3-.1 3.9-1.5 4.4-3 .5-1.5.5-2.8.4-3-.2-.4-.6-.5-1.3-.8M26 47.2c-3.9 0-7.6-1-11-3l-.7-.4-8.1 2L8.4 38l-.6-.8A21.4 21.4 0 0126 4.4a21.3 21.3 0 0121.4 21.4c0 11.8-9.6 21.4-21.4 21.4M44.2 7.6a25.8 25.8 0 00-40.6 31L0 52l13.7-3.6A25.8 25.8 0 0044.3 7.5" fill="currentColor"></path></svg></span></div><div class="progress"><progress value="0" max="100" dir="ltr"></progress></div><div class="main">WhatsApp</div><div class="secondary"><span><svg width="10" height="12" xmlns="http://www.w3.org/2000/svg"><path d="M5 1.6c1.4 0 2.5 1 2.6 2.4v1.5h.2c.5 0 1 .4 1 1V10c0 .6-.5 1-1 1H2.3a1 1 0 01-1.1-1V6.5c0-.6.5-1 1-1h.2V4.2c0-1.4 1-2.5 2.4-2.6H5zm0 1.2c-.7 0-1.3.6-1.3 1.3v1.4h2.6V4.2c0-.7-.4-1.2-1-1.3H5z" fill="currentColor"></path></svg> </span> End-to-end encrypted</div></div><link rel="preload" crossorigin="anonymous" as="fetch" href="/binary-transparency-manifest-2.2322.15.json" id="binary-transparency-manifest-preload"><script src="/libsignal-protocol-ee5b8ba.min.js"></script><script defer="defer" src="/runtime.d9a06bd6a7a484d6e04e.js"></script><script data-binary-transparency-hash-key="inline-js-fa16de51ee7511dd7a3e11537a929d8433d81c4653032c11129c2f55dd563575">/*! Copyright (c) 2023 WhatsApp Inc. All Rights Reserved. */
|
|
2
|
+
(self.webpackChunkwhatsapp_web_client=self.webpackChunkwhatsapp_web_client||[]).push([[5617],{307914:e=>{e.exports=function(e){return e&&e.__esModule?e:{default:e}}},595318:e=>{e.exports=function(e){return e&&e.__esModule?e:{default:e}},e.exports.default=e.exports,e.exports.__esModule=!0},415227:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){const t=new Error(e);if(void 0===t.stack)try{throw t}catch(e){}return t}},670983:(e,t,r)=>{"use strict";var n=r(307914);Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"?";if(null==e)throw(0,o.default)("Unexpected null or undefined: "+t);return e};var o=n(r(415227))},801506:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TICKET_URL=t.CLB_URL=t.CLB_TOKEN=t.CLB_CHECK_URL=void 0,t.CLB_CHECK_URL="https://crashlogs.whatsapp.net/wa_fls_upload_check",t.CLB_TOKEN="1063127757113399|745146ffa34413f9dbb5469f5370b7af",t.CLB_URL="https://crashlogs.whatsapp.net/wa_clb_data",t.TICKET_URL="https://web.whatsapp.com/web-contact-us"},207024:(e,t,r)=>{"use strict";var n=r(595318);Object.defineProperty(t,"__esModule",{value:!0}),t.getDistribution=function(){let e="unknown";return e="prod","web_prod"},t.getLogUserAgent=function(e){let t,{appVersion:r,browser:n,device:o}=e;return t="Web/"+n,`WhatsApp/${r} ${t} Device/${o}`},n(r(97359)),n(r(556869))},794858:(e,t,r)=>{"use strict";var n=r(595318),o=n(r(670983)),a=r(801506),s=r(207024),u=n(r(174285)),c=r(425017);function i(e){!function(e,t){const r=window.navigator.userAgent;if(r===f&&e.includes("getElementsByTagName"))return;const n=new FormData,i=new Blob([e],{type:"text/plain"});n.append("from_jid",function(){if(p)return p;try{p=JSON.parse((0,o.default)(u.default,"localStorage").getItem(d)),p&&(p=p.replace("-",""))}catch(e){}if(!p){p="unknown"+Math.floor(1e10*Math.random());const e=p;try{(0,o.default)(u.default,"localStorage").setItem(d,JSON.stringify(e))}catch(e){}}return(0,o.default)(p,"id")}()),n.append("agent",(0,s.getLogUserAgent)((0,c.parseUASimple)(r,"2.2322.15"))),n.append("file",i,"logs.txt"),n.append("tags","load");const l=new XMLHttpRequest,_=a.CLB_URL+"?access_token="+encodeURIComponent(a.CLB_TOKEN);l.open("POST",_,!0),l.send(n)}(e)}function l(e){let{error:t,reason:r,stack:n}=e;const o=(new Date).toISOString();return`${o}: error: ${t}\n${o}: reason for logs: ${r}\n${o}: userAgent: ${window.navigator.userAgent}\n${n}`}null==window.onerror&&(window.onerror=function(e,t,r){const n=t.split("?")[0];return"Uncaught SyntaxError: Unexpected token '<'"===e?(function(e){i(l({error:"failed to load a js or css bundle",reason:`failed to load [${e.split("/")[3].replace(/^\//,"")}]`,stack:""}))}(n),!0):(i(l({error:e,reason:`Error at [${n}:${r}]`,stack:""})),!1)});const d="WAUnknownID",f="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";let p},425017:(e,t)=>{"use strict";function r(e){return e.includes("windows")?"Windows":e.includes("mac")?"Mac OS":e.includes("linux")?"Linux":"Unparsed"}Object.defineProperty(t,"__esModule",{value:!0}),t.parseUASimple=function(e,t){const n=e.toLowerCase();return{browser:s(n),device:r(n),appVersion:t}};const n=/(chrome|firefox)\/([\w\.]+)/i,o=/(edge|opr)\/([\w\.]+)/i,a={chrome:"Chrome",edge:"Edge",opr:"Opera",firefox:"Firefox"};function s(e){const t=e.match(o)||e.match(n);return null==t?"Unparsed":`${a[t[1]]} ${t[2]}`}},174285:(e,t)=>{"use strict";let r;Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;try{r=window.localStorage}catch(e){}var n=r;t.default=n},97359:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){return e.default}},556869:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function e(t){const r=new Error(t);if(void 0===r.stack)try{throw e}catch(e){}return r}}},e=>{"use strict";e(e.s=794858)}])</script><script defer="defer" src="/vendor1~app.a91035d81a749b3d5627.js"></script><script defer="defer" src="/app.df22dc4b1b984dc87f36.js"></script><script data-binary-transparency-hash-key="inline-js-9c8cd3d0f4d5af8c7f5cd1c45208edd308bfe472e353a50e4cbacbf6cb58627c">(i => {const l = document.getElementById(i); l &&fetch(l.href).then(b => b.text()).then(code => {const script = document.createElement('script');script.id = 'binary-transparency-manifest';script.type = 'application/json';script.innerHTML = code;document.body.append(script);});})('binary-transparency-manifest-preload');</script></body></html>
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://www.npmjs.com/package/whatsapp-web.js) [](https://depfu.com/github/pedroslopez/whatsapp-web.js?project_id=9765) ](https://www.npmjs.com/package/whatsapp-web.js) [](https://depfu.com/github/pedroslopez/whatsapp-web.js?project_id=9765)  [](https://discord.gg/H7DqQs4)
|
|
2
2
|
|
|
3
3
|
# whatsapp-web.js
|
|
4
4
|
A WhatsApp API client that connects through the WhatsApp Web browser app
|
package/example.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
const { Client, Location, List, Buttons, LocalAuth} = require('./index');
|
|
1
|
+
const { Client, Location, List, Buttons, LocalAuth } = require('./index');
|
|
2
2
|
|
|
3
3
|
const client = new Client({
|
|
4
4
|
authStrategy: new LocalAuth(),
|
|
5
|
-
|
|
5
|
+
// proxyAuthentication: { username: 'username', password: 'password' },
|
|
6
|
+
puppeteer: {
|
|
7
|
+
// args: ['--proxy-server=proxy-server-that-requires-authentication.example.com'],
|
|
8
|
+
headless: false
|
|
9
|
+
}
|
|
6
10
|
});
|
|
7
11
|
|
|
8
12
|
client.initialize();
|
|
@@ -189,11 +193,11 @@ client.on('message', async msg => {
|
|
|
189
193
|
client.interface.openChatWindowAt(quotedMsg.id._serialized);
|
|
190
194
|
}
|
|
191
195
|
} else if (msg.body === '!buttons') {
|
|
192
|
-
let button = new Buttons('Button body',[{body:'bt1'},{body:'bt2'},{body:'bt3'}],'title','footer');
|
|
196
|
+
let button = new Buttons('Button body', [{ body: 'bt1' }, { body: 'bt2' }, { body: 'bt3' }], 'title', 'footer');
|
|
193
197
|
client.sendMessage(msg.from, button);
|
|
194
198
|
} else if (msg.body === '!list') {
|
|
195
|
-
let sections = [{title:'sectionTitle',rows:[{title:'ListItem1', description: 'desc'},{title:'ListItem2'}]}];
|
|
196
|
-
let list = new List('List body','btnText',sections,'Title','footer');
|
|
199
|
+
let sections = [{ title: 'sectionTitle', rows: [{ title: 'ListItem1', description: 'desc' }, { title: 'ListItem2' }] }];
|
|
200
|
+
let list = new List('List body', 'btnText', sections, 'Title', 'footer');
|
|
197
201
|
client.sendMessage(msg.from, list);
|
|
198
202
|
} else if (msg.body === '!reaction') {
|
|
199
203
|
msg.react('👍');
|
|
@@ -231,7 +235,7 @@ client.on('message_ack', (msg, ack) => {
|
|
|
231
235
|
ACK_PLAYED: 4
|
|
232
236
|
*/
|
|
233
237
|
|
|
234
|
-
if(ack == 3) {
|
|
238
|
+
if (ack == 3) {
|
|
235
239
|
// The message was read
|
|
236
240
|
}
|
|
237
241
|
});
|
|
@@ -254,7 +258,7 @@ client.on('group_update', (notification) => {
|
|
|
254
258
|
});
|
|
255
259
|
|
|
256
260
|
client.on('change_state', state => {
|
|
257
|
-
console.log('CHANGE STATE', state
|
|
261
|
+
console.log('CHANGE STATE', state);
|
|
258
262
|
});
|
|
259
263
|
|
|
260
264
|
// Change to false if you don't want to reject incoming calls
|
|
@@ -270,3 +274,51 @@ client.on('disconnected', (reason) => {
|
|
|
270
274
|
console.log('Client was logged out', reason);
|
|
271
275
|
});
|
|
272
276
|
|
|
277
|
+
client.on('contact_changed', async (message, oldId, newId, isContact) => {
|
|
278
|
+
/** The time the event occurred. */
|
|
279
|
+
const eventTime = (new Date(message.timestamp * 1000)).toLocaleString();
|
|
280
|
+
|
|
281
|
+
console.log(
|
|
282
|
+
`The contact ${oldId.slice(0, -5)}` +
|
|
283
|
+
`${!isContact ? ' that participates in group ' +
|
|
284
|
+
`${(await client.getChatById(message.to ?? message.from)).name} ` : ' '}` +
|
|
285
|
+
`changed their phone number\nat ${eventTime}.\n` +
|
|
286
|
+
`Their new phone number is ${newId.slice(0, -5)}.\n`);
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Information about the {@name message}:
|
|
290
|
+
*
|
|
291
|
+
* 1. If a notification was emitted due to a group participant changing their phone number:
|
|
292
|
+
* {@name message.author} is a participant's id before the change.
|
|
293
|
+
* {@name message.recipients[0]} is a participant's id after the change (a new one).
|
|
294
|
+
*
|
|
295
|
+
* 1.1 If the contact who changed their number WAS in the current user's contact list at the time of the change:
|
|
296
|
+
* {@name message.to} is a group chat id the event was emitted in.
|
|
297
|
+
* {@name message.from} is a current user's id that got an notification message in the group.
|
|
298
|
+
* Also the {@name message.fromMe} is TRUE.
|
|
299
|
+
*
|
|
300
|
+
* 1.2 Otherwise:
|
|
301
|
+
* {@name message.from} is a group chat id the event was emitted in.
|
|
302
|
+
* {@name message.to} is @type {undefined}.
|
|
303
|
+
* Also {@name message.fromMe} is FALSE.
|
|
304
|
+
*
|
|
305
|
+
* 2. If a notification was emitted due to a contact changing their phone number:
|
|
306
|
+
* {@name message.templateParams} is an array of two user's ids:
|
|
307
|
+
* the old (before the change) and a new one, stored in alphabetical order.
|
|
308
|
+
* {@name message.from} is a current user's id that has a chat with a user,
|
|
309
|
+
* whos phone number was changed.
|
|
310
|
+
* {@name message.to} is a user's id (after the change), the current user has a chat with.
|
|
311
|
+
*/
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
client.on('group_admin_changed', (notification) => {
|
|
315
|
+
if (notification.type === 'promote') {
|
|
316
|
+
/**
|
|
317
|
+
* Emitted when a current user is promoted to an admin.
|
|
318
|
+
* {@link notification.author} is a user who performs the action of promoting/demoting the current user.
|
|
319
|
+
*/
|
|
320
|
+
console.log(`You were promoted by ${notification.author}`);
|
|
321
|
+
} else if (notification.type === 'demote')
|
|
322
|
+
/** Emitted when a current user is demoted to a regular user. */
|
|
323
|
+
console.log(`You were demoted by ${notification.author}`);
|
|
324
|
+
});
|
package/index.d.ts
CHANGED
|
@@ -148,6 +148,12 @@ declare namespace WAWebJS {
|
|
|
148
148
|
/** Unmutes the Chat */
|
|
149
149
|
unmuteChat(chatId: string): Promise<void>
|
|
150
150
|
|
|
151
|
+
/** Sets the current user's profile picture */
|
|
152
|
+
setProfilePicture(media: MessageMedia): Promise<boolean>
|
|
153
|
+
|
|
154
|
+
/** Deletes the current user's profile picture */
|
|
155
|
+
deleteProfilePicture(): Promise<boolean>
|
|
156
|
+
|
|
151
157
|
/** Generic event */
|
|
152
158
|
on(event: string, listener: (...args: any) => void): this
|
|
153
159
|
|
|
@@ -192,12 +198,30 @@ declare namespace WAWebJS {
|
|
|
192
198
|
notification: GroupNotification
|
|
193
199
|
) => void): this
|
|
194
200
|
|
|
201
|
+
/** Emitted when a current user is promoted to an admin or demoted to a regular user */
|
|
202
|
+
on(event: 'group_admin_changed', listener: (
|
|
203
|
+
/** GroupNotification with more information about the action */
|
|
204
|
+
notification: GroupNotification
|
|
205
|
+
) => void): this
|
|
206
|
+
|
|
195
207
|
/** Emitted when group settings are updated, such as subject, description or picture */
|
|
196
208
|
on(event: 'group_update', listener: (
|
|
197
209
|
/** GroupNotification with more information about the action */
|
|
198
210
|
notification: GroupNotification
|
|
199
211
|
) => void): this
|
|
200
212
|
|
|
213
|
+
/** Emitted when a contact or a group participant changed their phone number. */
|
|
214
|
+
on(event: 'contact_changed', listener: (
|
|
215
|
+
/** Message with more information about the event. */
|
|
216
|
+
message: Message,
|
|
217
|
+
/** Old user's id. */
|
|
218
|
+
oldId : String,
|
|
219
|
+
/** New user's id. */
|
|
220
|
+
newId : String,
|
|
221
|
+
/** Indicates if a contact or a group participant changed their phone number. */
|
|
222
|
+
isContact : Boolean
|
|
223
|
+
) => void): this
|
|
224
|
+
|
|
201
225
|
/** Emitted when media has been uploaded for a message sent by the client */
|
|
202
226
|
on(event: 'media_uploaded', listener: (
|
|
203
227
|
/** The message with media that was uploaded */
|
|
@@ -217,6 +241,12 @@ declare namespace WAWebJS {
|
|
|
217
241
|
/** The new ACK value */
|
|
218
242
|
ack: MessageAck
|
|
219
243
|
) => void): this
|
|
244
|
+
|
|
245
|
+
/** Emitted when a chat unread count changes */
|
|
246
|
+
on(event: 'unread_count', listener: (
|
|
247
|
+
/** The chat that was affected */
|
|
248
|
+
chat: Chat
|
|
249
|
+
) => void): this
|
|
220
250
|
|
|
221
251
|
/** Emitted when a new message is created, which may include the current user's own messages */
|
|
222
252
|
on(event: 'message_create', listener: (
|
|
@@ -247,6 +277,22 @@ declare namespace WAWebJS {
|
|
|
247
277
|
reaction: Reaction
|
|
248
278
|
) => void): this
|
|
249
279
|
|
|
280
|
+
/** Emitted when a chat is removed */
|
|
281
|
+
on(event: 'chat_removed', listener: (
|
|
282
|
+
/** The chat that was removed */
|
|
283
|
+
chat: Chat
|
|
284
|
+
) => void): this
|
|
285
|
+
|
|
286
|
+
/** Emitted when a chat is archived/unarchived */
|
|
287
|
+
on(event: 'chat_archived', listener: (
|
|
288
|
+
/** The chat that was archived/unarchived */
|
|
289
|
+
chat: Chat,
|
|
290
|
+
/** State the chat is currently in */
|
|
291
|
+
currState: boolean,
|
|
292
|
+
/** State the chat was previously in */
|
|
293
|
+
prevState: boolean
|
|
294
|
+
) => void): this
|
|
295
|
+
|
|
250
296
|
/** Emitted when loading screen is appearing */
|
|
251
297
|
on(event: 'loading_screen', listener: (percent: string, message: string) => void): this
|
|
252
298
|
|
|
@@ -319,6 +365,10 @@ declare namespace WAWebJS {
|
|
|
319
365
|
puppeteer?: puppeteer.PuppeteerNodeLaunchOptions & puppeteer.ConnectOptions
|
|
320
366
|
/** Determines how to save and restore sessions. Will use LegacySessionAuth if options.session is set. Otherwise, NoAuth will be used. */
|
|
321
367
|
authStrategy?: AuthStrategy,
|
|
368
|
+
/** The version of WhatsApp Web to use. Use options.webVersionCache to configure how the version is retrieved. */
|
|
369
|
+
webVersion?: string,
|
|
370
|
+
/** Determines how to retrieve the WhatsApp Web version specified in options.webVersion. */
|
|
371
|
+
webVersionCache?: WebCacheOptions,
|
|
322
372
|
/** How many times should the qrcode be refreshed before giving up
|
|
323
373
|
* @default 0 (disabled) */
|
|
324
374
|
qrMaxRetries?: number,
|
|
@@ -341,9 +391,29 @@ declare namespace WAWebJS {
|
|
|
341
391
|
userAgent?: string
|
|
342
392
|
/** Ffmpeg path to use when formating videos to webp while sending stickers
|
|
343
393
|
* @default 'ffmpeg' */
|
|
344
|
-
ffmpegPath?: string
|
|
394
|
+
ffmpegPath?: string,
|
|
395
|
+
/** Object with proxy autentication requirements @default: undefined */
|
|
396
|
+
proxyAuthentication?: {username: string, password: string} | undefined
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export interface LocalWebCacheOptions {
|
|
400
|
+
type: 'local',
|
|
401
|
+
path?: string,
|
|
402
|
+
strict?: boolean
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export interface RemoteWebCacheOptions {
|
|
406
|
+
type: 'remote',
|
|
407
|
+
remotePath: string,
|
|
408
|
+
strict?: boolean
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export interface NoWebCacheOptions {
|
|
412
|
+
type: 'none'
|
|
345
413
|
}
|
|
346
414
|
|
|
415
|
+
export type WebCacheOptions = NoWebCacheOptions | LocalWebCacheOptions | RemoteWebCacheOptions;
|
|
416
|
+
|
|
347
417
|
/**
|
|
348
418
|
* Base class which all authentication strategies extend
|
|
349
419
|
*/
|
|
@@ -498,8 +568,10 @@ declare namespace WAWebJS {
|
|
|
498
568
|
MESSAGE_REVOKED_ME = 'message_revoke_me',
|
|
499
569
|
MESSAGE_ACK = 'message_ack',
|
|
500
570
|
MEDIA_UPLOADED = 'media_uploaded',
|
|
571
|
+
CONTACT_CHANGED = 'contact_changed',
|
|
501
572
|
GROUP_JOIN = 'group_join',
|
|
502
573
|
GROUP_LEAVE = 'group_leave',
|
|
574
|
+
GROUP_ADMIN_CHANGED = 'group_admin_changed',
|
|
503
575
|
GROUP_UPDATE = 'group_update',
|
|
504
576
|
QR_RECEIVED = 'qr',
|
|
505
577
|
LOADING_SCREEN = 'loading_screen',
|
|
@@ -637,6 +709,7 @@ declare namespace WAWebJS {
|
|
|
637
709
|
* broadcast: false,
|
|
638
710
|
* fromMe: false,
|
|
639
711
|
* hasQuotedMsg: false,
|
|
712
|
+
* hasReaction: false,
|
|
640
713
|
* location: undefined,
|
|
641
714
|
* mentionedIds: []
|
|
642
715
|
* }
|
|
@@ -666,6 +739,8 @@ declare namespace WAWebJS {
|
|
|
666
739
|
hasMedia: boolean,
|
|
667
740
|
/** Indicates if the message was sent as a reply to another message */
|
|
668
741
|
hasQuotedMsg: boolean,
|
|
742
|
+
/** Indicates whether there are reactions to the message */
|
|
743
|
+
hasReaction: boolean,
|
|
669
744
|
/** Indicates the duration of the message in seconds */
|
|
670
745
|
duration: string,
|
|
671
746
|
/** ID that represents the message */
|
|
@@ -767,6 +842,10 @@ declare namespace WAWebJS {
|
|
|
767
842
|
* Gets the payment details associated with a given message
|
|
768
843
|
*/
|
|
769
844
|
getPayment: () => Promise<Payment>,
|
|
845
|
+
/**
|
|
846
|
+
* Gets the reactions associated with the given message
|
|
847
|
+
*/
|
|
848
|
+
getReactions: () => Promise<ReactionList[]>,
|
|
770
849
|
}
|
|
771
850
|
|
|
772
851
|
/** ID that represents a message */
|
|
@@ -1019,6 +1098,8 @@ declare namespace WAWebJS {
|
|
|
1019
1098
|
timestamp: number,
|
|
1020
1099
|
/** Amount of messages unread */
|
|
1021
1100
|
unreadCount: number,
|
|
1101
|
+
/** Last message fo chat */
|
|
1102
|
+
lastMessage: Message,
|
|
1022
1103
|
|
|
1023
1104
|
/** Archives this chat */
|
|
1024
1105
|
archive: () => Promise<void>,
|
|
@@ -1162,6 +1243,10 @@ declare namespace WAWebJS {
|
|
|
1162
1243
|
revokeInvite: () => Promise<void>;
|
|
1163
1244
|
/** Makes the bot leave the group */
|
|
1164
1245
|
leave: () => Promise<void>;
|
|
1246
|
+
/** Sets the group's picture.*/
|
|
1247
|
+
setPicture: (media: MessageMedia) => Promise<boolean>;
|
|
1248
|
+
/** Deletes the group's picture */
|
|
1249
|
+
deletePicture: () => Promise<boolean>;
|
|
1165
1250
|
}
|
|
1166
1251
|
|
|
1167
1252
|
/**
|
|
@@ -1365,6 +1450,13 @@ declare namespace WAWebJS {
|
|
|
1365
1450
|
senderId: string
|
|
1366
1451
|
ack?: number
|
|
1367
1452
|
}
|
|
1453
|
+
|
|
1454
|
+
export type ReactionList = {
|
|
1455
|
+
id: string,
|
|
1456
|
+
aggregateEmoji: string,
|
|
1457
|
+
hasReactionByMe: boolean,
|
|
1458
|
+
senders: Array<Reaction>
|
|
1459
|
+
}
|
|
1368
1460
|
}
|
|
1369
1461
|
|
|
1370
1462
|
export = WAWebJS
|
package/package.json
CHANGED
package/src/Client.js
CHANGED
|
@@ -10,7 +10,8 @@ const { WhatsWebURL, DefaultOptions, Events, WAState } = require('./util/Constan
|
|
|
10
10
|
const { ExposeStore, LoadUtils } = require('./util/Injected');
|
|
11
11
|
const ChatFactory = require('./factories/ChatFactory');
|
|
12
12
|
const ContactFactory = require('./factories/ContactFactory');
|
|
13
|
-
const
|
|
13
|
+
const WebCacheFactory = require('./webCache/WebCacheFactory');
|
|
14
|
+
const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification, Label, Call, Buttons, List, Reaction, Chat } = require('./structures');
|
|
14
15
|
const LegacySessionAuth = require('./authStrategies/LegacySessionAuth');
|
|
15
16
|
const NoAuth = require('./authStrategies/NoAuth');
|
|
16
17
|
|
|
@@ -19,6 +20,8 @@ const NoAuth = require('./authStrategies/NoAuth');
|
|
|
19
20
|
* @extends {EventEmitter}
|
|
20
21
|
* @param {object} options - Client options
|
|
21
22
|
* @param {AuthStrategy} options.authStrategy - Determines how to save and restore sessions. Will use LegacySessionAuth if options.session is set. Otherwise, NoAuth will be used.
|
|
23
|
+
* @param {string} options.webVersion - The version of WhatsApp Web to use. Use options.webVersionCache to configure how the version is retrieved.
|
|
24
|
+
* @param {object} options.webVersionCache - Determines how to retrieve the WhatsApp Web version. Defaults to a local cache (LocalWebCache) that falls back to latest if the requested version is not found.
|
|
22
25
|
* @param {number} options.authTimeoutMs - Timeout for authentication selector in puppeteer
|
|
23
26
|
* @param {object} options.puppeteer - Puppeteer launch options. View docs here: https://github.com/puppeteer/puppeteer/
|
|
24
27
|
* @param {number} options.qrMaxRetries - How many times should the qrcode be refreshed before giving up
|
|
@@ -29,6 +32,7 @@ const NoAuth = require('./authStrategies/NoAuth');
|
|
|
29
32
|
* @param {string} options.userAgent - User agent to use in puppeteer
|
|
30
33
|
* @param {string} options.ffmpegPath - Ffmpeg path to use when formating videos to webp while sending stickers
|
|
31
34
|
* @param {boolean} options.bypassCSP - Sets bypassing of page's Content-Security-Policy.
|
|
35
|
+
* @param {object} options.proxyAuthentication - Proxy Authentication object.
|
|
32
36
|
*
|
|
33
37
|
* @fires Client#qr
|
|
34
38
|
* @fires Client#authenticated
|
|
@@ -45,6 +49,8 @@ const NoAuth = require('./authStrategies/NoAuth');
|
|
|
45
49
|
* @fires Client#group_update
|
|
46
50
|
* @fires Client#disconnected
|
|
47
51
|
* @fires Client#change_state
|
|
52
|
+
* @fires Client#contact_changed
|
|
53
|
+
* @fires Client#group_admin_changed
|
|
48
54
|
*/
|
|
49
55
|
class Client extends EventEmitter {
|
|
50
56
|
constructor(options = {}) {
|
|
@@ -100,6 +106,10 @@ class Client extends EventEmitter {
|
|
|
100
106
|
browser = await puppeteer.launch({...puppeteerOpts, args: browserArgs});
|
|
101
107
|
page = (await browser.pages())[0];
|
|
102
108
|
}
|
|
109
|
+
|
|
110
|
+
if (this.options.proxyAuthentication !== undefined) {
|
|
111
|
+
await page.authenticate(this.options.proxyAuthentication);
|
|
112
|
+
}
|
|
103
113
|
|
|
104
114
|
await page.setUserAgent(this.options.userAgent);
|
|
105
115
|
if (this.options.bypassCSP) await page.setBypassCSP(true);
|
|
@@ -108,6 +118,7 @@ class Client extends EventEmitter {
|
|
|
108
118
|
this.pupPage = page;
|
|
109
119
|
|
|
110
120
|
await this.authStrategy.afterBrowserInitialized();
|
|
121
|
+
await this.initWebVersionCache();
|
|
111
122
|
|
|
112
123
|
await page.goto(WhatsWebURL, {
|
|
113
124
|
waitUntil: 'load',
|
|
@@ -317,6 +328,13 @@ class Client extends EventEmitter {
|
|
|
317
328
|
* @param {GroupNotification} notification GroupNotification with more information about the action
|
|
318
329
|
*/
|
|
319
330
|
this.emit(Events.GROUP_LEAVE, notification);
|
|
331
|
+
} else if (msg.subtype === 'promote' || msg.subtype === 'demote') {
|
|
332
|
+
/**
|
|
333
|
+
* Emitted when a current user is promoted to an admin or demoted to a regular user.
|
|
334
|
+
* @event Client#group_admin_changed
|
|
335
|
+
* @param {GroupNotification} notification GroupNotification with more information about the action
|
|
336
|
+
*/
|
|
337
|
+
this.emit(Events.GROUP_ADMIN_CHANGED, notification);
|
|
320
338
|
} else {
|
|
321
339
|
/**
|
|
322
340
|
* Emitted when group settings are updated, such as subject, description or picture.
|
|
@@ -376,6 +394,36 @@ class Client extends EventEmitter {
|
|
|
376
394
|
last_message = msg;
|
|
377
395
|
}
|
|
378
396
|
|
|
397
|
+
/**
|
|
398
|
+
* The event notification that is received when one of
|
|
399
|
+
* the group participants changes thier phone number.
|
|
400
|
+
*/
|
|
401
|
+
const isParticipant = msg.type === 'gp2' && msg.subtype === 'modify';
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* The event notification that is received when one of
|
|
405
|
+
* the contacts changes thier phone number.
|
|
406
|
+
*/
|
|
407
|
+
const isContact = msg.type === 'notification_template' && msg.subtype === 'change_number';
|
|
408
|
+
|
|
409
|
+
if (isParticipant || isContact) {
|
|
410
|
+
/** {@link GroupNotification} object does not provide enough information about this event, so a {@link Message} object is used. */
|
|
411
|
+
const message = new Message(this, msg);
|
|
412
|
+
|
|
413
|
+
const newId = isParticipant ? msg.recipients[0] : msg.to;
|
|
414
|
+
const oldId = isParticipant ? msg.author : msg.templateParams.find(id => id !== newId);
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Emitted when a contact or a group participant changes their phone number.
|
|
418
|
+
* @event Client#contact_changed
|
|
419
|
+
* @param {Message} message Message with more information about the event.
|
|
420
|
+
* @param {String} oldId The user's id (an old one) who changed their phone number
|
|
421
|
+
* and who triggered the notification.
|
|
422
|
+
* @param {String} newId The user's new id after the change.
|
|
423
|
+
* @param {Boolean} isContact Indicates if a contact or a group participant changed their phone number.
|
|
424
|
+
*/
|
|
425
|
+
this.emit(Events.CONTACT_CHANGED, message, oldId, newId, isContact);
|
|
426
|
+
}
|
|
379
427
|
});
|
|
380
428
|
|
|
381
429
|
await page.exposeFunction('onRemoveMessageEvent', (msg) => {
|
|
@@ -407,6 +455,15 @@ class Client extends EventEmitter {
|
|
|
407
455
|
|
|
408
456
|
});
|
|
409
457
|
|
|
458
|
+
await page.exposeFunction('onChatUnreadCountEvent', async (data) =>{
|
|
459
|
+
const chat = await this.getChatById(data.id);
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Emitted when the chat unread count changes
|
|
463
|
+
*/
|
|
464
|
+
this.emit(Events.UNREAD_COUNT, chat);
|
|
465
|
+
});
|
|
466
|
+
|
|
410
467
|
await page.exposeFunction('onMessageMediaUploadedEvent', (msg) => {
|
|
411
468
|
|
|
412
469
|
const message = new Message(this, msg);
|
|
@@ -507,6 +564,26 @@ class Client extends EventEmitter {
|
|
|
507
564
|
}
|
|
508
565
|
});
|
|
509
566
|
|
|
567
|
+
await page.exposeFunction('onRemoveChatEvent', (chat) => {
|
|
568
|
+
/**
|
|
569
|
+
* Emitted when a chat is removed
|
|
570
|
+
* @event Client#chat_removed
|
|
571
|
+
* @param {Chat} chat
|
|
572
|
+
*/
|
|
573
|
+
this.emit(Events.CHAT_REMOVED, new Chat(this, chat));
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
await page.exposeFunction('onArchiveChatEvent', (chat, currState, prevState) => {
|
|
577
|
+
/**
|
|
578
|
+
* Emitted when a chat is archived/unarchived
|
|
579
|
+
* @event Client#chat_archived
|
|
580
|
+
* @param {Chat} chat
|
|
581
|
+
* @param {boolean} currState
|
|
582
|
+
* @param {boolean} prevState
|
|
583
|
+
*/
|
|
584
|
+
this.emit(Events.CHAT_ARCHIVED, new Chat(this, chat), currState, prevState);
|
|
585
|
+
});
|
|
586
|
+
|
|
510
587
|
await page.evaluate(() => {
|
|
511
588
|
window.Store.Msg.on('change', (msg) => { window.onChangeMessageEvent(window.WWebJS.getMessageModel(msg)); });
|
|
512
589
|
window.Store.Msg.on('change:type', (msg) => { window.onChangeMessageTypeEvent(window.WWebJS.getMessageModel(msg)); });
|
|
@@ -516,6 +593,8 @@ class Client extends EventEmitter {
|
|
|
516
593
|
window.Store.AppState.on('change:state', (_AppState, state) => { window.onAppStateChangedEvent(state); });
|
|
517
594
|
window.Store.Conn.on('change:battery', (state) => { window.onBatteryStateChangedEvent(state); });
|
|
518
595
|
window.Store.Call.on('add', (call) => { window.onIncomingCall(call); });
|
|
596
|
+
window.Store.Chat.on('remove', async (chat) => { window.onRemoveChatEvent(await window.WWebJS.getChatModel(chat)); });
|
|
597
|
+
window.Store.Chat.on('change:archive', async (chat, currState, prevState) => { window.onArchiveChatEvent(await window.WWebJS.getChatModel(chat), currState, prevState); });
|
|
519
598
|
window.Store.Msg.on('add', (msg) => {
|
|
520
599
|
if (msg.isNewMsg) {
|
|
521
600
|
if(msg.type === 'ciphertext') {
|
|
@@ -526,7 +605,8 @@ class Client extends EventEmitter {
|
|
|
526
605
|
}
|
|
527
606
|
}
|
|
528
607
|
});
|
|
529
|
-
|
|
608
|
+
window.Store.Chat.on('change:unreadCount', (chat) => {window.onChatUnreadCountEvent(chat);});
|
|
609
|
+
|
|
530
610
|
{
|
|
531
611
|
const module = window.Store.createOrUpdateReactionsModule;
|
|
532
612
|
const ogMethod = module.createOrUpdateReactions;
|
|
@@ -562,6 +642,35 @@ class Client extends EventEmitter {
|
|
|
562
642
|
});
|
|
563
643
|
}
|
|
564
644
|
|
|
645
|
+
async initWebVersionCache() {
|
|
646
|
+
const { type: webCacheType, ...webCacheOptions } = this.options.webVersionCache;
|
|
647
|
+
const webCache = WebCacheFactory.createWebCache(webCacheType, webCacheOptions);
|
|
648
|
+
|
|
649
|
+
const requestedVersion = this.options.webVersion;
|
|
650
|
+
const versionContent = await webCache.resolve(requestedVersion);
|
|
651
|
+
|
|
652
|
+
if(versionContent) {
|
|
653
|
+
await this.pupPage.setRequestInterception(true);
|
|
654
|
+
this.pupPage.on('request', async (req) => {
|
|
655
|
+
if(req.url() === WhatsWebURL) {
|
|
656
|
+
req.respond({
|
|
657
|
+
status: 200,
|
|
658
|
+
contentType: 'text/html',
|
|
659
|
+
body: versionContent
|
|
660
|
+
});
|
|
661
|
+
} else {
|
|
662
|
+
req.continue();
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
} else {
|
|
666
|
+
this.pupPage.on('response', async (res) => {
|
|
667
|
+
if(res.ok() && res.url() === WhatsWebURL) {
|
|
668
|
+
await webCache.persist(await res.text());
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
565
674
|
/**
|
|
566
675
|
* Closes the client
|
|
567
676
|
*/
|
|
@@ -937,7 +1046,7 @@ class Client extends EventEmitter {
|
|
|
937
1046
|
unmuteDate = unmuteDate ? unmuteDate.getTime() / 1000 : -1;
|
|
938
1047
|
await this.pupPage.evaluate(async (chatId, timestamp) => {
|
|
939
1048
|
let chat = await window.Store.Chat.get(chatId);
|
|
940
|
-
await chat.mute.mute(timestamp,
|
|
1049
|
+
await chat.mute.mute({expiration: timestamp, sendDevice:!0});
|
|
941
1050
|
}, chatId, unmuteDate || -1);
|
|
942
1051
|
}
|
|
943
1052
|
|
|
@@ -1178,6 +1287,31 @@ class Client extends EventEmitter {
|
|
|
1178
1287
|
|
|
1179
1288
|
return blockedContacts.map(contact => ContactFactory.create(this.client, contact));
|
|
1180
1289
|
}
|
|
1290
|
+
|
|
1291
|
+
/**
|
|
1292
|
+
* Sets the current user's profile picture.
|
|
1293
|
+
* @param {MessageMedia} media
|
|
1294
|
+
* @returns {Promise<boolean>} Returns true if the picture was properly updated.
|
|
1295
|
+
*/
|
|
1296
|
+
async setProfilePicture(media) {
|
|
1297
|
+
const success = await this.pupPage.evaluate((chatid, media) => {
|
|
1298
|
+
return window.WWebJS.setPicture(chatid, media);
|
|
1299
|
+
}, this.info.wid._serialized, media);
|
|
1300
|
+
|
|
1301
|
+
return success;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
/**
|
|
1305
|
+
* Deletes the current user's profile picture.
|
|
1306
|
+
* @returns {Promise<boolean>} Returns true if the picture was properly deleted.
|
|
1307
|
+
*/
|
|
1308
|
+
async deleteProfilePicture() {
|
|
1309
|
+
const success = await this.pupPage.evaluate((chatid) => {
|
|
1310
|
+
return window.WWebJS.deletePicture(chatid);
|
|
1311
|
+
}, this.info.wid._serialized);
|
|
1312
|
+
|
|
1313
|
+
return success;
|
|
1314
|
+
}
|
|
1181
1315
|
}
|
|
1182
1316
|
|
|
1183
1317
|
module.exports = Client;
|
package/src/structures/Chat.js
CHANGED
|
@@ -75,6 +75,12 @@ class Chat extends Base {
|
|
|
75
75
|
*/
|
|
76
76
|
this.muteExpiration = data.muteExpiration;
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Last message fo chat
|
|
80
|
+
* @type {Message}
|
|
81
|
+
*/
|
|
82
|
+
this.lastMessage = data.lastMessage ? new Message(super.client, data.lastMessage) : undefined;
|
|
83
|
+
|
|
78
84
|
return super._patch(data);
|
|
79
85
|
}
|
|
80
86
|
|
|
@@ -213,6 +213,31 @@ class GroupChat extends Chat {
|
|
|
213
213
|
return true;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Deletes the group's picture.
|
|
218
|
+
* @returns {Promise<boolean>} Returns true if the picture was properly deleted. This can return false if the user does not have the necessary permissions.
|
|
219
|
+
*/
|
|
220
|
+
async deletePicture() {
|
|
221
|
+
const success = await this.client.pupPage.evaluate((chatid) => {
|
|
222
|
+
return window.WWebJS.deletePicture(chatid);
|
|
223
|
+
}, this.id._serialized);
|
|
224
|
+
|
|
225
|
+
return success;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Sets the group's picture.
|
|
230
|
+
* @param {MessageMedia} media
|
|
231
|
+
* @returns {Promise<boolean>} Returns true if the picture was properly updated. This can return false if the user does not have the necessary permissions.
|
|
232
|
+
*/
|
|
233
|
+
async setPicture(media) {
|
|
234
|
+
const success = await this.client.pupPage.evaluate((chatid, media) => {
|
|
235
|
+
return window.WWebJS.setPicture(chatid, media);
|
|
236
|
+
}, this.id._serialized, media);
|
|
237
|
+
|
|
238
|
+
return success;
|
|
239
|
+
}
|
|
240
|
+
|
|
216
241
|
/**
|
|
217
242
|
* Gets the invite code for a specific group
|
|
218
243
|
* @returns {Promise<string>} Group's invite code
|
|
@@ -5,7 +5,8 @@ const MessageMedia = require('./MessageMedia');
|
|
|
5
5
|
const Location = require('./Location');
|
|
6
6
|
const Order = require('./Order');
|
|
7
7
|
const Payment = require('./Payment');
|
|
8
|
-
const
|
|
8
|
+
const Reaction = require('./Reaction');
|
|
9
|
+
const {MessageTypes} = require('../util/Constants');
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Represents a Message on WhatsApp
|
|
@@ -88,8 +89,7 @@ class Message extends Base {
|
|
|
88
89
|
* String that represents from which device type the message was sent
|
|
89
90
|
* @type {string}
|
|
90
91
|
*/
|
|
91
|
-
this.deviceType = data.id.id.length > 21 ? 'android' : data.id.id.substring(0, 2)
|
|
92
|
-
|
|
92
|
+
this.deviceType = typeof data.id.id === 'string' && data.id.id.length > 21 ? 'android' : typeof data.id.id === 'string' && data.id.id.substring(0, 2) === '3A' ? 'ios' : 'web';
|
|
93
93
|
/**
|
|
94
94
|
* Indicates if the message was forwarded
|
|
95
95
|
* @type {boolean}
|
|
@@ -108,7 +108,7 @@ class Message extends Base {
|
|
|
108
108
|
* Indicates if the message is a status update
|
|
109
109
|
* @type {boolean}
|
|
110
110
|
*/
|
|
111
|
-
this.isStatus = data.isStatusV3;
|
|
111
|
+
this.isStatus = data.isStatusV3 || data.id.remote === 'status@broadcast';
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* Indicates if the message was starred
|
|
@@ -134,6 +134,12 @@ class Message extends Base {
|
|
|
134
134
|
*/
|
|
135
135
|
this.hasQuotedMsg = data.quotedMsg ? true : false;
|
|
136
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Indicates whether there are reactions to the message
|
|
139
|
+
* @type {boolean}
|
|
140
|
+
*/
|
|
141
|
+
this.hasReaction = data.hasReaction ? true : false;
|
|
142
|
+
|
|
137
143
|
/**
|
|
138
144
|
* Indicates the duration of the message in seconds
|
|
139
145
|
* @type {string}
|
|
@@ -403,7 +409,7 @@ class Message extends Base {
|
|
|
403
409
|
}
|
|
404
410
|
|
|
405
411
|
try {
|
|
406
|
-
const decryptedMedia = await window.Store.DownloadManager.
|
|
412
|
+
const decryptedMedia = await window.Store.DownloadManager.downloadAndMaybeDecrypt({
|
|
407
413
|
directPath: msg.directPath,
|
|
408
414
|
encFilehash: msg.encFilehash,
|
|
409
415
|
filehash: msg.filehash,
|
|
@@ -436,15 +442,16 @@ class Message extends Base {
|
|
|
436
442
|
* @param {?boolean} everyone If true and the message is sent by the current user or the user is an admin, will delete it for everyone in the chat.
|
|
437
443
|
*/
|
|
438
444
|
async delete(everyone) {
|
|
439
|
-
await this.client.pupPage.evaluate((msgId, everyone) => {
|
|
445
|
+
await this.client.pupPage.evaluate(async (msgId, everyone) => {
|
|
440
446
|
let msg = window.Store.Msg.get(msgId);
|
|
441
|
-
|
|
447
|
+
let chat = await window.Store.Chat.find(msg.id.remote);
|
|
448
|
+
|
|
442
449
|
const canRevoke = window.Store.MsgActionChecks.canSenderRevokeMsg(msg) || window.Store.MsgActionChecks.canAdminRevokeMsg(msg);
|
|
443
450
|
if (everyone && canRevoke) {
|
|
444
|
-
return window.Store.Cmd.sendRevokeMsgs(
|
|
451
|
+
return window.Store.Cmd.sendRevokeMsgs(chat, [msg], { clearMedia: true, type: msg.id.fromMe ? 'Sender' : 'Admin' });
|
|
445
452
|
}
|
|
446
453
|
|
|
447
|
-
return window.Store.Cmd.sendDeleteMsgs(
|
|
454
|
+
return window.Store.Cmd.sendDeleteMsgs(chat, [msg], true);
|
|
448
455
|
}, this.id._serialized, everyone);
|
|
449
456
|
}
|
|
450
457
|
|
|
@@ -452,11 +459,12 @@ class Message extends Base {
|
|
|
452
459
|
* Stars this message
|
|
453
460
|
*/
|
|
454
461
|
async star() {
|
|
455
|
-
await this.client.pupPage.evaluate((msgId) => {
|
|
462
|
+
await this.client.pupPage.evaluate(async (msgId) => {
|
|
456
463
|
let msg = window.Store.Msg.get(msgId);
|
|
457
|
-
|
|
464
|
+
|
|
458
465
|
if (window.Store.MsgActionChecks.canStarMsg(msg)) {
|
|
459
|
-
|
|
466
|
+
let chat = await window.Store.Chat.find(msg.id.remote);
|
|
467
|
+
return window.Store.Cmd.sendStarMsgs(chat, [msg], false);
|
|
460
468
|
}
|
|
461
469
|
}, this.id._serialized);
|
|
462
470
|
}
|
|
@@ -465,11 +473,12 @@ class Message extends Base {
|
|
|
465
473
|
* Unstars this message
|
|
466
474
|
*/
|
|
467
475
|
async unstar() {
|
|
468
|
-
await this.client.pupPage.evaluate((msgId) => {
|
|
476
|
+
await this.client.pupPage.evaluate(async (msgId) => {
|
|
469
477
|
let msg = window.Store.Msg.get(msgId);
|
|
470
478
|
|
|
471
479
|
if (window.Store.MsgActionChecks.canStarMsg(msg)) {
|
|
472
|
-
|
|
480
|
+
let chat = await window.Store.Chat.find(msg.id.remote);
|
|
481
|
+
return window.Store.Cmd.sendUnstarMsgs(chat, [msg], false);
|
|
473
482
|
}
|
|
474
483
|
}, this.id._serialized);
|
|
475
484
|
}
|
|
@@ -529,6 +538,44 @@ class Message extends Base {
|
|
|
529
538
|
}
|
|
530
539
|
return undefined;
|
|
531
540
|
}
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Reaction List
|
|
545
|
+
* @typedef {Object} ReactionList
|
|
546
|
+
* @property {string} id Original emoji
|
|
547
|
+
* @property {string} aggregateEmoji aggregate emoji
|
|
548
|
+
* @property {boolean} hasReactionByMe Flag who sent the reaction
|
|
549
|
+
* @property {Array<Reaction>} senders Reaction senders, to this message
|
|
550
|
+
*/
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Gets the reactions associated with the given message
|
|
554
|
+
* @return {Promise<ReactionList[]>}
|
|
555
|
+
*/
|
|
556
|
+
async getReactions() {
|
|
557
|
+
if (!this.hasReaction) {
|
|
558
|
+
return undefined;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const reactions = await this.client.pupPage.evaluate(async (msgId) => {
|
|
562
|
+
const msgReactions = await window.Store.Reactions.find(msgId);
|
|
563
|
+
if (!msgReactions || !msgReactions.reactions.length) return null;
|
|
564
|
+
return msgReactions.reactions.serialize();
|
|
565
|
+
}, this.id._serialized);
|
|
566
|
+
|
|
567
|
+
if (!reactions) {
|
|
568
|
+
return undefined;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
return reactions.map(reaction => {
|
|
572
|
+
reaction.senders = reaction.senders.map(sender => {
|
|
573
|
+
sender.timestamp = Math.round(sender.timestamp / 1000);
|
|
574
|
+
return new Reaction(this.client, sender);
|
|
575
|
+
});
|
|
576
|
+
return reaction;
|
|
577
|
+
});
|
|
578
|
+
}
|
|
532
579
|
}
|
|
533
580
|
|
|
534
581
|
module.exports = Message;
|
package/src/util/Constants.js
CHANGED
|
@@ -7,13 +7,18 @@ exports.DefaultOptions = {
|
|
|
7
7
|
headless: true,
|
|
8
8
|
defaultViewport: null
|
|
9
9
|
},
|
|
10
|
+
webVersion: '2.2322.15',
|
|
11
|
+
webVersionCache: {
|
|
12
|
+
type: 'local',
|
|
13
|
+
},
|
|
10
14
|
authTimeoutMs: 0,
|
|
11
15
|
qrMaxRetries: 0,
|
|
12
16
|
takeoverOnConflict: false,
|
|
13
17
|
takeoverTimeoutMs: 0,
|
|
14
18
|
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
|
|
15
19
|
ffmpegPath: 'ffmpeg',
|
|
16
|
-
bypassCSP: false
|
|
20
|
+
bypassCSP: false,
|
|
21
|
+
proxyAuthentication: undefined
|
|
17
22
|
};
|
|
18
23
|
|
|
19
24
|
/**
|
|
@@ -36,15 +41,20 @@ exports.Events = {
|
|
|
36
41
|
AUTHENTICATED: 'authenticated',
|
|
37
42
|
AUTHENTICATION_FAILURE: 'auth_failure',
|
|
38
43
|
READY: 'ready',
|
|
44
|
+
CHAT_REMOVED: 'chat_removed',
|
|
45
|
+
CHAT_ARCHIVED: 'chat_archived',
|
|
39
46
|
MESSAGE_RECEIVED: 'message',
|
|
40
47
|
MESSAGE_CREATE: 'message_create',
|
|
41
48
|
MESSAGE_REVOKED_EVERYONE: 'message_revoke_everyone',
|
|
42
49
|
MESSAGE_REVOKED_ME: 'message_revoke_me',
|
|
43
50
|
MESSAGE_ACK: 'message_ack',
|
|
51
|
+
UNREAD_COUNT: 'unread_count',
|
|
44
52
|
MESSAGE_REACTION: 'message_reaction',
|
|
45
53
|
MEDIA_UPLOADED: 'media_uploaded',
|
|
54
|
+
CONTACT_CHANGED: 'contact_changed',
|
|
46
55
|
GROUP_JOIN: 'group_join',
|
|
47
56
|
GROUP_LEAVE: 'group_leave',
|
|
57
|
+
GROUP_ADMIN_CHANGED: 'group_admin_changed',
|
|
48
58
|
GROUP_UPDATE: 'group_update',
|
|
49
59
|
QR_RECEIVED: 'qr',
|
|
50
60
|
LOADING_SCREEN: 'loading_screen',
|
package/src/util/Injected.js
CHANGED
|
@@ -17,7 +17,7 @@ exports.ExposeStore = (moduleRaidStr) => {
|
|
|
17
17
|
window.Store.Invite = window.mR.findModule('resetGroupInviteCode')[0];
|
|
18
18
|
window.Store.InviteInfo = window.mR.findModule('queryGroupInvite')[0];
|
|
19
19
|
window.Store.Label = window.mR.findModule('LabelCollection')[0].LabelCollection;
|
|
20
|
-
window.Store.MediaPrep = window.mR.findModule('
|
|
20
|
+
window.Store.MediaPrep = window.mR.findModule('prepRawMedia')[0];
|
|
21
21
|
window.Store.MediaObject = window.mR.findModule('getOrCreateMediaObject')[0];
|
|
22
22
|
window.Store.NumberInfo = window.mR.findModule('formattedPhoneNumber')[0];
|
|
23
23
|
window.Store.MediaTypes = window.mR.findModule('msgToMediaType')[0];
|
|
@@ -25,7 +25,7 @@ exports.ExposeStore = (moduleRaidStr) => {
|
|
|
25
25
|
window.Store.MsgKey = window.mR.findModule((module) => module.default && module.default.fromString)[0].default;
|
|
26
26
|
window.Store.MessageInfo = window.mR.findModule('sendQueryMsgInfo')[0];
|
|
27
27
|
window.Store.OpaqueData = window.mR.findModule(module => module.default && module.default.createFromData)[0].default;
|
|
28
|
-
window.Store.QueryExist = window.mR.findModule('queryExists')[0].queryExists;
|
|
28
|
+
window.Store.QueryExist = window.mR.findModule('queryExists')[0] ? window.mR.findModule('queryExists')[0].queryExists : window.mR.findModule('queryExist')[0].queryWidExists;
|
|
29
29
|
window.Store.QueryProduct = window.mR.findModule('queryProduct')[0];
|
|
30
30
|
window.Store.QueryOrder = window.mR.findModule('queryOrder')[0];
|
|
31
31
|
window.Store.SendClear = window.mR.findModule('sendClear')[0];
|
|
@@ -41,7 +41,7 @@ exports.ExposeStore = (moduleRaidStr) => {
|
|
|
41
41
|
window.Store.ProfilePic = window.mR.findModule('profilePicResync')[0];
|
|
42
42
|
window.Store.PresenceUtils = window.mR.findModule('sendPresenceAvailable')[0];
|
|
43
43
|
window.Store.ChatState = window.mR.findModule('sendChatStateComposing')[0];
|
|
44
|
-
window.Store.GroupParticipants = window.mR.findModule('promoteParticipants')[
|
|
44
|
+
window.Store.GroupParticipants = window.mR.findModule('promoteParticipants')[0];
|
|
45
45
|
window.Store.JoinInviteV4 = window.mR.findModule('sendJoinGroupViaInviteV4')[0];
|
|
46
46
|
window.Store.findCommonGroups = window.mR.findModule('findCommonGroups')[0].findCommonGroups;
|
|
47
47
|
window.Store.StatusUtils = window.mR.findModule('setMyStatus')[0];
|
|
@@ -54,6 +54,8 @@ exports.ExposeStore = (moduleRaidStr) => {
|
|
|
54
54
|
window.Store.QuotedMsg = window.mR.findModule('getQuotedMsgObj')[0];
|
|
55
55
|
window.Store.Socket = window.mR.findModule('deprecatedSendIq')[0];
|
|
56
56
|
window.Store.SocketWap = window.mR.findModule('wap')[0];
|
|
57
|
+
window.Store.SearchContext = window.mR.findModule('getSearchContext')[0].getSearchContext;
|
|
58
|
+
window.Store.DrawerManager = window.mR.findModule('DrawerManager')[0].DrawerManager;
|
|
57
59
|
window.Store.StickerTools = {
|
|
58
60
|
...window.mR.findModule('toWebpSticker')[0],
|
|
59
61
|
...window.mR.findModule('addWebpMetadata')[0]
|
|
@@ -62,7 +64,8 @@ exports.ExposeStore = (moduleRaidStr) => {
|
|
|
62
64
|
window.Store.GroupUtils = {
|
|
63
65
|
...window.mR.findModule('createGroup')[0],
|
|
64
66
|
...window.mR.findModule('setGroupDescription')[0],
|
|
65
|
-
...window.mR.findModule('sendExitGroup')[0]
|
|
67
|
+
...window.mR.findModule('sendExitGroup')[0],
|
|
68
|
+
...window.mR.findModule('sendSetPicture')[0]
|
|
66
69
|
};
|
|
67
70
|
|
|
68
71
|
if (!window.Store.Chat._find) {
|
|
@@ -116,7 +119,10 @@ exports.LoadUtils = () => {
|
|
|
116
119
|
forceDocument: options.sendMediaAsDocument,
|
|
117
120
|
forceGif: options.sendVideoAsGif
|
|
118
121
|
});
|
|
119
|
-
|
|
122
|
+
|
|
123
|
+
if (options.caption){
|
|
124
|
+
attOptions.caption = options.caption;
|
|
125
|
+
}
|
|
120
126
|
content = options.sendMediaAsSticker ? undefined : attOptions.preview;
|
|
121
127
|
|
|
122
128
|
delete options.attachment;
|
|
@@ -242,11 +248,12 @@ exports.LoadUtils = () => {
|
|
|
242
248
|
|
|
243
249
|
const meUser = window.Store.User.getMaybeMeUser();
|
|
244
250
|
const isMD = window.Store.MDBackend;
|
|
245
|
-
|
|
251
|
+
const newId = await window.Store.MsgKey.newId();
|
|
252
|
+
|
|
246
253
|
const newMsgId = new window.Store.MsgKey({
|
|
247
254
|
from: meUser,
|
|
248
255
|
to: chat.id,
|
|
249
|
-
id:
|
|
256
|
+
id: newId,
|
|
250
257
|
participant: isMD && chat.id.isGroup() ? meUser : undefined,
|
|
251
258
|
selfDir: 'out',
|
|
252
259
|
});
|
|
@@ -271,6 +278,7 @@ exports.LoadUtils = () => {
|
|
|
271
278
|
...ephemeralFields,
|
|
272
279
|
...locationOptions,
|
|
273
280
|
...attOptions,
|
|
281
|
+
...(attOptions.toJSON ? attOptions.toJSON() : {}),
|
|
274
282
|
...quotedMsgOptions,
|
|
275
283
|
...vcardOptions,
|
|
276
284
|
...buttonOptions,
|
|
@@ -426,7 +434,15 @@ exports.LoadUtils = () => {
|
|
|
426
434
|
await window.Store.GroupMetadata.update(chatWid);
|
|
427
435
|
res.groupMetadata = chat.groupMetadata.serialize();
|
|
428
436
|
}
|
|
429
|
-
|
|
437
|
+
|
|
438
|
+
res.lastMessage = null;
|
|
439
|
+
if (res.msgs && res.msgs.length) {
|
|
440
|
+
const lastMessage = window.Store.Msg.get(chat.lastReceivedKey._serialized);
|
|
441
|
+
if (lastMessage) {
|
|
442
|
+
res.lastMessage = window.WWebJS.getMessageModel(lastMessage);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
430
446
|
delete res.msgs;
|
|
431
447
|
delete res.msgUnsyncedButtonReplyMsgs;
|
|
432
448
|
delete res.unsyncedButtonReplies;
|
|
@@ -625,4 +641,73 @@ exports.LoadUtils = () => {
|
|
|
625
641
|
]);
|
|
626
642
|
await window.Store.Socket.deprecatedCastStanza(stanza);
|
|
627
643
|
};
|
|
644
|
+
|
|
645
|
+
window.WWebJS.cropAndResizeImage = async (media, options = {}) => {
|
|
646
|
+
if (!media.mimetype.includes('image'))
|
|
647
|
+
throw new Error('Media is not an image');
|
|
648
|
+
|
|
649
|
+
if (options.mimetype && !options.mimetype.includes('image'))
|
|
650
|
+
delete options.mimetype;
|
|
651
|
+
|
|
652
|
+
options = Object.assign({ size: 640, mimetype: media.mimetype, quality: .75, asDataUrl: false }, options);
|
|
653
|
+
|
|
654
|
+
const img = await new Promise ((resolve, reject) => {
|
|
655
|
+
const img = new Image();
|
|
656
|
+
img.onload = () => resolve(img);
|
|
657
|
+
img.onerror = reject;
|
|
658
|
+
img.src = `data:${media.mimetype};base64,${media.data}`;
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
const sl = Math.min(img.width, img.height);
|
|
662
|
+
const sx = Math.floor((img.width - sl) / 2);
|
|
663
|
+
const sy = Math.floor((img.height - sl) / 2);
|
|
664
|
+
|
|
665
|
+
const canvas = document.createElement('canvas');
|
|
666
|
+
canvas.width = options.size;
|
|
667
|
+
canvas.height = options.size;
|
|
668
|
+
|
|
669
|
+
const ctx = canvas.getContext('2d');
|
|
670
|
+
ctx.drawImage(img, sx, sy, sl, sl, 0, 0, options.size, options.size);
|
|
671
|
+
|
|
672
|
+
const dataUrl = canvas.toDataURL(options.mimetype, options.quality);
|
|
673
|
+
|
|
674
|
+
if (options.asDataUrl)
|
|
675
|
+
return dataUrl;
|
|
676
|
+
|
|
677
|
+
return Object.assign(media, {
|
|
678
|
+
mimetype: options.mimeType,
|
|
679
|
+
data: dataUrl.replace(`data:${options.mimeType};base64,`, '')
|
|
680
|
+
});
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
window.WWebJS.setPicture = async (chatid, media) => {
|
|
684
|
+
const thumbnail = await window.WWebJS.cropAndResizeImage(media, { asDataUrl: true, mimetype: 'image/jpeg', size: 96 });
|
|
685
|
+
const profilePic = await window.WWebJS.cropAndResizeImage(media, { asDataUrl: true, mimetype: 'image/jpeg', size: 640 });
|
|
686
|
+
|
|
687
|
+
const chatWid = window.Store.WidFactory.createWid(chatid);
|
|
688
|
+
try {
|
|
689
|
+
const collection = window.Store.ProfilePicThumb.get(chatid);
|
|
690
|
+
if (!collection.canSet()) return;
|
|
691
|
+
|
|
692
|
+
const res = await window.Store.GroupUtils.sendSetPicture(chatWid, thumbnail, profilePic);
|
|
693
|
+
return res ? res.status === 200 : false;
|
|
694
|
+
} catch (err) {
|
|
695
|
+
if(err.name === 'ServerStatusCodeError') return false;
|
|
696
|
+
throw err;
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
window.WWebJS.deletePicture = async (chatid) => {
|
|
701
|
+
const chatWid = window.Store.WidFactory.createWid(chatid);
|
|
702
|
+
try {
|
|
703
|
+
const collection = window.Store.ProfilePicThumb.get(chatid);
|
|
704
|
+
if (!collection.canDelete()) return;
|
|
705
|
+
|
|
706
|
+
const res = await window.Store.GroupUtils.requestDeletePicture(chatWid);
|
|
707
|
+
return res ? res.status === 200 : false;
|
|
708
|
+
} catch (err) {
|
|
709
|
+
if(err.name === 'ServerStatusCodeError') return false;
|
|
710
|
+
throw err;
|
|
711
|
+
}
|
|
712
|
+
};
|
|
628
713
|
};
|
|
@@ -50,7 +50,9 @@ class InterfaceController {
|
|
|
50
50
|
async openChatWindowAt(msgId) {
|
|
51
51
|
await this.pupPage.evaluate(async msgId => {
|
|
52
52
|
let msg = await window.Store.Msg.get(msgId);
|
|
53
|
-
await window.Store.
|
|
53
|
+
let chat = await window.Store.Chat.find(msg.id.remote);
|
|
54
|
+
let searchContext = await window.Store.SearchContext(chat,msg);
|
|
55
|
+
await window.Store.Cmd.openChatAt(chat, searchContext);
|
|
54
56
|
}, msgId);
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -70,7 +72,7 @@ class InterfaceController {
|
|
|
70
72
|
*/
|
|
71
73
|
async closeRightDrawer() {
|
|
72
74
|
await this.pupPage.evaluate(async () => {
|
|
73
|
-
await window.Store.
|
|
75
|
+
await window.Store.DrawerManager.closeDrawerRight();
|
|
74
76
|
});
|
|
75
77
|
}
|
|
76
78
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
const { WebCache, VersionResolveError } = require('./WebCache');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* LocalWebCache - Fetches a WhatsApp Web version from a local file store
|
|
8
|
+
* @param {object} options - options
|
|
9
|
+
* @param {string} options.path - Path to the directory where cached versions are saved, default is: "./.wwebjs_cache/"
|
|
10
|
+
* @param {boolean} options.strict - If true, will throw an error if the requested version can't be fetched. If false, will resolve to the latest version.
|
|
11
|
+
*/
|
|
12
|
+
class LocalWebCache extends WebCache {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
super();
|
|
15
|
+
|
|
16
|
+
this.path = options.path || './.wwebjs_cache/';
|
|
17
|
+
this.strict = options.strict || false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async resolve(version) {
|
|
21
|
+
const filePath = path.join(this.path, `${version}.html`);
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
return fs.readFileSync(filePath, 'utf-8');
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
if (this.strict) throw new VersionResolveError(`Couldn't load version ${version} from the cache`);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async persist(indexHtml) {
|
|
33
|
+
// extract version from index (e.g. manifest-2.2206.9.json -> 2.2206.9)
|
|
34
|
+
const version = indexHtml.match(/manifest-([\d\\.]+)\.json/)[1];
|
|
35
|
+
if(!version) return;
|
|
36
|
+
|
|
37
|
+
const filePath = path.join(this.path, `${version}.html`);
|
|
38
|
+
fs.mkdirSync(this.path, { recursive: true });
|
|
39
|
+
fs.writeFileSync(filePath, indexHtml);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = LocalWebCache;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const fetch = require('node-fetch');
|
|
2
|
+
const { WebCache, VersionResolveError } = require('./WebCache');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* RemoteWebCache - Fetches a WhatsApp Web version index from a remote server
|
|
6
|
+
* @param {object} options - options
|
|
7
|
+
* @param {string} options.remotePath - Endpoint that should be used to fetch the version index. Use {version} as a placeholder for the version number.
|
|
8
|
+
* @param {boolean} options.strict - If true, will throw an error if the requested version can't be fetched. If false, will resolve to the latest version. Defaults to false.
|
|
9
|
+
*/
|
|
10
|
+
class RemoteWebCache extends WebCache {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
super();
|
|
13
|
+
|
|
14
|
+
if (!options.remotePath) throw new Error('webVersionCache.remotePath is required when using the remote cache');
|
|
15
|
+
this.remotePath = options.remotePath;
|
|
16
|
+
this.strict = options.strict || false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async resolve(version) {
|
|
20
|
+
const remotePath = this.remotePath.replace('{version}', version);
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const cachedRes = await fetch(remotePath);
|
|
24
|
+
if (cachedRes.ok) {
|
|
25
|
+
return cachedRes.text();
|
|
26
|
+
}
|
|
27
|
+
} catch (err) {
|
|
28
|
+
console.error(`Error fetching version ${version} from remote`, err);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (this.strict) throw new VersionResolveError(`Couldn't load version ${version} from the archive`);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async persist() {
|
|
36
|
+
// Nothing to do here
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = RemoteWebCache;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default implementation of a web version cache that does nothing.
|
|
3
|
+
*/
|
|
4
|
+
class WebCache {
|
|
5
|
+
async resolve() { return null; }
|
|
6
|
+
async persist() { }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class VersionResolveError extends Error { }
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
WebCache,
|
|
13
|
+
VersionResolveError
|
|
14
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const RemoteWebCache = require('./RemoteWebCache');
|
|
2
|
+
const LocalWebCache = require('./LocalWebCache');
|
|
3
|
+
const { WebCache } = require('./WebCache');
|
|
4
|
+
|
|
5
|
+
const createWebCache = (type, options) => {
|
|
6
|
+
switch (type) {
|
|
7
|
+
case 'remote':
|
|
8
|
+
return new RemoteWebCache(options);
|
|
9
|
+
case 'local':
|
|
10
|
+
return new LocalWebCache(options);
|
|
11
|
+
case 'none':
|
|
12
|
+
return new WebCache();
|
|
13
|
+
default:
|
|
14
|
+
throw new Error(`Invalid WebCache type ${type}`);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
createWebCache,
|
|
20
|
+
};
|