├── extension-chrome
├── images
│ ├── icon128.png
│ ├── icon48.png
│ ├── icon16-off.png
│ ├── icon16-on.png
│ ├── icon32-off.png
│ └── icon32-on.png
├── manifest.json
├── background.js
├── popup
│ ├── popup.html
│ ├── popup.css
│ └── popup.js
└── script
│ ├── content_script.js
│ └── wappbot.js
├── LICENSE
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── README.md
├── wappbot.js
└── newFullMethodWapi.js
/extension-chrome/images/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boehlergerman/WappBot/HEAD/extension-chrome/images/icon128.png
--------------------------------------------------------------------------------
/extension-chrome/images/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boehlergerman/WappBot/HEAD/extension-chrome/images/icon48.png
--------------------------------------------------------------------------------
/extension-chrome/images/icon16-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boehlergerman/WappBot/HEAD/extension-chrome/images/icon16-off.png
--------------------------------------------------------------------------------
/extension-chrome/images/icon16-on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boehlergerman/WappBot/HEAD/extension-chrome/images/icon16-on.png
--------------------------------------------------------------------------------
/extension-chrome/images/icon32-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boehlergerman/WappBot/HEAD/extension-chrome/images/icon32-off.png
--------------------------------------------------------------------------------
/extension-chrome/images/icon32-on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boehlergerman/WappBot/HEAD/extension-chrome/images/icon32-on.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 boehlergerman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/extension-chrome/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "WappBot",
3 | "description": "Automatic answering of incoming messages by means of javascript and using Whatsapp Web",
4 | "version": "2.0.1",
5 | "author": "Boehler German",
6 | "homepage_url": "https://github.com/boehlergerman/WappBot",
7 | "manifest_version": 2,
8 | "permissions": [
9 | "tabs",
10 | "activeTab",
11 | "storage",
12 | "nativeMessaging",
13 | "webRequest",
14 | "webRequestBlocking",
15 | "browsingData",
16 | "https://*.whatsapp.com/"
17 | ],
18 | "background": {
19 | "scripts": [
20 | "background.js"
21 | ]
22 | },
23 | "content_scripts": [
24 | {
25 | "matches": [
26 | "https://*.whatsapp.com/"
27 | ],
28 | "js": [
29 | "script/content_script.js"
30 | ]
31 | }
32 | ],
33 | "externally_connectable": {
34 | "matches": [
35 | "https://*.whatsapp.com/"
36 | ]
37 | },
38 | "web_accessible_resources": [
39 | "script/wappbot.js"
40 | ],
41 | "content_security_policy": "script-src 'self' https://*.whatsapp.com/; object-src 'self'",
42 | "browser_action": {
43 | "default_title": "WappBot",
44 | "default_icon": {
45 | "16": "images/icon32-off.png"
46 | },
47 | "default_popup": "popup/popup.html"
48 | },
49 | "icons": {
50 | "48": "images/icon48.png",
51 | "128": "images/icon128.png"
52 | }
53 | }
--------------------------------------------------------------------------------
/extension-chrome/background.js:
--------------------------------------------------------------------------------
1 | var isCSPDisabled = false;
2 | var tabid;
3 | var filter = {
4 | urls: ["*://*/*"],
5 | types: ["main_frame", "sub_frame"]
6 | };
7 |
8 | var onHeadersReceived = function (details) {
9 | for (var i = 0; i < details.responseHeaders.length; i++) {
10 | if ('content-security-policy' === details.responseHeaders[i].name.toLowerCase()) {
11 | details.responseHeaders[i].value = '';
12 | }
13 | }
14 |
15 | return {
16 | responseHeaders: details.responseHeaders
17 | };
18 | };
19 |
20 | function updateUI() {
21 | var iconName = isCSPDisabled ? 'on' : 'off';
22 | var title = isCSPDisabled ? 'disabled' : 'enabled';
23 |
24 | chrome.browserAction.setIcon({ path: "images/icon32-" + iconName + ".png" });
25 | chrome.browserAction.setTitle({ title: 'Content-Security-Policy headers are ' + title });
26 | }
27 |
28 | chrome.runtime.onMessage.addListener(
29 | function (request, sender, sendResponse) {
30 |
31 | isCSPDisabled = request;
32 | tabid = sender.tab.id;
33 | chrome.browsingData.remove({}, { "serviceWorkers": true }, function () { });
34 |
35 | updateUI();
36 |
37 | }
38 | );
39 |
40 | chrome.webRequest.onHeadersReceived.addListener(onHeadersReceived, filter, ["blocking", "responseHeaders"]);
41 |
42 | chrome.tabs.onRemoved.addListener(function (tabCloseid, removed) {
43 | if (tabid === tabCloseid) {
44 | isCSPDisabled = false;
45 | updateUI();
46 | }
47 | })
48 |
49 | chrome.windows.onRemoved.addListener(function (windowid) {
50 | isCSPDisabled = false;
51 | updateUI();
52 | })
53 |
54 | // chrome.tabs.onUpdated.addListener(function (tabCloseid, changeInfo, tab) {
55 | // if (tabid === tabCloseid) {
56 | // console.log("Refresh Tab!");
57 | // isCSPDisabled = false;
58 | // updateUI();
59 | // }
60 | // });
--------------------------------------------------------------------------------
/extension-chrome/popup/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | WappBot
4 |
5 |
6 |
7 |
8 |
9 | WappBot
10 |
11 | Use WappBot API?
12 |
13 |
14 |
23 |
24 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/extension-chrome/script/content_script.js:
--------------------------------------------------------------------------------
1 | var pollInterval = 5000;
2 | var timerId;
3 | var isCSPDisabled = false;
4 |
5 | function injectVariables(variables, tag) {
6 | var node = document.getElementsByTagName(tag)[0];
7 | var script = document.createElement("script");
8 | script.setAttribute("type", "text/javascript");
9 | console.log("[Info]: Injecting variables");
10 | for (var i = 0; i < variables.length; i++) {
11 | script.textContent =
12 | "var " +
13 | variables[i].name +
14 | " = " +
15 | JSON.stringify(variables[i].value) +
16 | ";";
17 | }
18 | node.appendChild(script);
19 | }
20 | function injectScript(file_path, tag) {
21 | var node = document.getElementsByTagName(tag)[0];
22 | var script = document.createElement("script");
23 | script.setAttribute("type", "text/javascript");
24 | script.setAttribute("src", file_path);
25 | node.appendChild(script);
26 | }
27 |
28 | function injectCode(code, tag) {
29 | var node = document.getElementsByTagName(tag)[0];
30 | var script = document.createElement("script");
31 | script.setAttribute("type", "text/javascript");
32 | script.textContent = code;
33 | node.appendChild(script);
34 | }
35 |
36 |
37 | function start() {
38 | try {
39 | console.log('[Info]: waiting for whatsapp start');
40 | var elementOfInterest = document.getElementsByClassName('_1BjNO');
41 | if (elementOfInterest.length > 0) {
42 | isCSPDisabled = !isCSPDisabled;
43 |
44 | chrome.storage.local.get(['WappBot'], function (result) {
45 | injectCode(`window["WappBot"] = ${JSON.stringify(result.WappBot)}`, 'body');
46 | });
47 |
48 | chrome.runtime.sendMessage(isCSPDisabled);
49 |
50 | injectVariables([{ name: "extensionID", value: chrome.runtime.id }], "body");
51 | injectScript(chrome.extension.getURL("script/wappbot.js"), "body");
52 | }
53 | else timerId = window.setTimeout(start, pollInterval);
54 | } catch (error) {
55 | console.error(error);
56 | }
57 | }
58 |
59 | chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
60 | if (message.type === "media_url") {
61 | var x = new XMLHttpRequest();
62 | x.open("GET", message.url, true);
63 | x.responseType = "blob";
64 | x.onload = function () {
65 | if (this.status == 200) {
66 | var myurl = window.URL.createObjectURL(this.response);
67 | sendResponse({
68 | type: "media_success",
69 | url: myurl
70 | });
71 | } else {
72 | sendResponse({
73 | type: "media_fail"
74 | });
75 | }
76 | };
77 | x.send();
78 | }
79 | return true;
80 | });
81 |
82 | start();
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at germanboehler@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | When contributing to this repository, please first discuss the change you wish to make via issue,
4 | email, or any other method with the owners of this repository before making a change.
5 |
6 | Please note we have a code of conduct, please follow it in all your interactions with the project.
7 |
8 | ## Pull Request Process
9 |
10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a
11 | build.
12 | 2. Update the README.md with details of changes to the interface, this includes new environment
13 | variables, exposed ports, useful file locations and container parameters.
14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this
15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
17 | do not have permission to do that, you may request the second reviewer to merge it for you.
18 |
19 | ## Code of Conduct
20 |
21 | ### Our Pledge
22 |
23 | In the interest of fostering an open and welcoming environment, we as
24 | contributors and maintainers pledge to making participation in our project and
25 | our community a harassment-free experience for everyone, regardless of age, body
26 | size, disability, ethnicity, gender identity and expression, level of experience,
27 | nationality, personal appearance, race, religion, or sexual identity and
28 | orientation.
29 |
30 | ### Our Standards
31 |
32 | Examples of behavior that contributes to creating a positive environment
33 | include:
34 |
35 | * Using welcoming and inclusive language
36 | * Being respectful of differing viewpoints and experiences
37 | * Gracefully accepting constructive criticism
38 | * Focusing on what is best for the community
39 | * Showing empathy towards other community members
40 |
41 | Examples of unacceptable behavior by participants include:
42 |
43 | * The use of sexualized language or imagery and unwelcome sexual attention or
44 | advances
45 | * Trolling, insulting/derogatory comments, and personal or political attacks
46 | * Public or private harassment
47 | * Publishing others' private information, such as a physical or electronic
48 | address, without explicit permission
49 | * Other conduct which could reasonably be considered inappropriate in a
50 | professional setting
51 |
52 | ### Our Responsibilities
53 |
54 | Project maintainers are responsible for clarifying the standards of acceptable
55 | behavior and are expected to take appropriate and fair corrective action in
56 | response to any instances of unacceptable behavior.
57 |
58 | Project maintainers have the right and responsibility to remove, edit, or
59 | reject comments, commits, code, wiki edits, issues, and other contributions
60 | that are not aligned to this Code of Conduct, or to ban temporarily or
61 | permanently any contributor for other behaviors that they deem inappropriate,
62 | threatening, offensive, or harmful.
63 |
64 | ### Scope
65 |
66 | This Code of Conduct applies both within project spaces and in public spaces
67 | when an individual is representing the project or its community. Examples of
68 | representing a project or community include using an official project e-mail
69 | address, posting via an official social media account, or acting as an appointed
70 | representative at an online or offline event. Representation of a project may be
71 | further defined and clarified by project maintainers.
72 |
73 | ### Enforcement
74 |
75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
76 | reported by contacting the project team at [germanboehler@gmail.com]. All
77 | complaints will be reviewed and investigated and will result in a response that
78 | is deemed necessary and appropriate to the circumstances. The project team is
79 | obligated to maintain confidentiality with regard to the reporter of an incident.
80 | Further details of specific enforcement policies may be posted separately.
81 |
82 | Project maintainers who do not follow or enforce the Code of Conduct in good
83 | faith may face temporary or permanent repercussions as determined by other
84 | members of the project's leadership.
85 |
86 | ### Attribution
87 |
88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
89 | available at [http://contributor-covenant.org/version/1/4][version]
90 |
91 | [homepage]: http://contributor-covenant.org
92 | [version]: http://contributor-covenant.org/version/1/4/
93 |
--------------------------------------------------------------------------------
/extension-chrome/popup/popup.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=ABeeZee);
2 | body {
3 | background: #2c3e50;
4 | margin-top: 10px;
5 | padding: 10px 0px;
6 | font-family: "ABeeZee", sans-serif;
7 | font-size: 15px;
8 | }
9 |
10 | h1 {
11 | text-align: center;
12 | color: #fff;
13 | font-size: 20px;
14 | margin-bottom: 10px;
15 | }
16 |
17 | .container {
18 | width: 260px;
19 | margin: 0 auto;
20 | border-bottom: 4px solid #3498db;
21 | padding: 8px 0px;
22 | -webkit-box-sizing: border-box;
23 | -moz-box-sizing: border-box;
24 | -ms-box-sizing: border-box;
25 | -o-box-sizing: border-box;
26 | box-sizing: border-box;
27 | }
28 |
29 | .subcontainer {
30 | border-width: 2px;
31 | border-color: #34495e;
32 | }
33 |
34 | input {
35 | display: none;
36 | font-size: 15px;
37 | }
38 |
39 | span {
40 | float: left;
41 | padding-bottom: 10px;
42 | color: #ecf0f1;
43 | }
44 |
45 | .style label {
46 | width: 18px;
47 | height: 18px;
48 | margin-bottom: -3px;
49 | margin-left: 10px;
50 | background: #e74c3c;
51 | border-radius: 3px;
52 | cursor: pointer;
53 | position: relative;
54 | display: inline-block;
55 | -webkit-transition: 300ms all;
56 | -moz-transition: 300ms all;
57 | -ms-transition: 300ms all;
58 | -o-transition: 300ms all;
59 | transition: 300ms all;
60 | }
61 |
62 | .style label::after {
63 | content: "";
64 | position: absolute;
65 | width: 12px;
66 | height: 12px;
67 | left: 3px;
68 | top: 3px;
69 | background: #c0392b;
70 | border-radius: 3px;
71 | opacity: 1;
72 | z-index: 1;
73 | -webkit-transition: 300ms all;
74 | -moz-transition: 300ms all;
75 | -ms-transition: 300ms all;
76 | -o-transition: 300ms all;
77 | transition: 300ms all;
78 | }
79 |
80 | .style input:checked+label {
81 | background: #27ae60;
82 | }
83 |
84 | .style input:checked+label::after {
85 | opacity: 1;
86 | background: #2ecc71;
87 | }
88 |
89 | input[type=text],
90 | input[type=email] {
91 | display: inline-block;
92 | border: none;
93 | background: #34495e;
94 | -webkit-box-sizing: border-box;
95 | -moz-box-sizing: border-box;
96 | -ms-box-sizing: border-box;
97 | -o-box-sizing: border-box;
98 | box-sizing: border-box;
99 | padding: 8px;
100 | color: #ecf0f1;
101 | width: 100%;
102 | }
103 |
104 | input[type=text]:focus,
105 | input[type=email]:focus {
106 | outline: none;
107 | }
108 |
109 | input[type=text]::-webkit-input-placeholder,
110 | input[type=email]::-webkit-input-placeholder {
111 | color: #999;
112 | }
113 |
114 | input[type=text]:-moz-input-placeholder,
115 | input[type=email]:-moz-input-placeholder {
116 | color: #999;
117 | }
118 |
119 | input[type=text]::-moz-placeholder,
120 | input[type=email]::-moz-placeholder {
121 | color: #999;
122 | }
123 |
124 | input[type=text]:-ms-input-placeholder,
125 | input[type=email]:-ms-input-placeholder {
126 | color: #999;
127 | }
128 |
129 | textarea {
130 | width: 100%;
131 | max-width: 100%;
132 | min-width: 100%;
133 | min-height: 80px;
134 | -webkit-box-sizing: border-box;
135 | -moz-box-sizing: border-box;
136 | -ms-box-sizing: border-box;
137 | -o-box-sizing: border-box;
138 | box-sizing: border-box;
139 | padding: 8px;
140 | background: #34495e;
141 | border: none;
142 | color: #ecf0f1;
143 | font-size: 15px;
144 | font-family: "ABeeZee", sans-serif;
145 | }
146 |
147 | textarea:focus {
148 | outline: none;
149 | }
150 |
151 | textarea::-webkit-input-placeholder {
152 | color: #999;
153 | }
154 |
155 | textarea:-moz-input-placeholder {
156 | color: #999;
157 | font-family: "ABeeZee", sans-serif;
158 | }
159 |
160 | textarea::-moz-placeholder {
161 | color: #999;
162 | font-family: "ABeeZee", sans-serif;
163 | }
164 |
165 | textarea:-ms-input-placeholder {
166 | color: #999;
167 | }
168 |
169 | /* ===================== FILE INPUT ===================== */
170 |
171 | .file-area {
172 | width: 100%;
173 | position: relative;
174 | }
175 |
176 | .file-area input[type=file] {
177 | position: absolute;
178 | width: 100%;
179 | height: 100%;
180 | top: 0;
181 | left: 0;
182 | right: 0;
183 | bottom: 0;
184 | opacity: 0;
185 | cursor: pointer;
186 | }
187 |
188 | .file-area .file-dummy {
189 | width: 100%;
190 | padding: 30px;
191 | background: rgba(255, 255, 255, 0.2);
192 | border: 2px dashed rgba(255, 255, 255, 0.2);
193 | text-align: center;
194 | transition: background 0.3s ease-in-out;
195 | }
196 |
197 | .file-area .file-dummy .success {
198 | display: none;
199 | }
200 |
201 | .file-area:hover .file-dummy {
202 | background: rgba(255, 255, 255, 0.1);
203 | }
204 |
205 | .file-area input[type=file]:focus+.file-dummy {
206 | outline: 2px solid rgba(255, 255, 255, 0.5);
207 | outline: -webkit-focus-ring-color auto 5px;
208 | }
209 |
210 | .file-area input[type=file]:valid+.file-dummy {
211 | border-color: rgba(0, 255, 0, 0.4);
212 | background-color: rgba(0, 255, 0, 0.3);
213 | }
214 |
215 | .file-area input[type=file]:valid+.file-dummy .success {
216 | display: inline-block;
217 | }
218 |
219 | .file-area input[type=file]:valid+.file-dummy .default {
220 | display: none;
221 | }
222 |
223 | button[type=submit] {
224 | font-size: 15px;
225 | display: block;
226 | -webkit-box-sizing: border-box;
227 | -moz-box-sizing: border-box;
228 | -ms-box-sizing: border-box;
229 | -o-box-sizing: border-box;
230 | box-sizing: border-box;
231 | border: none;
232 | -webkit-appearance: none;
233 | color: #ecf0f1;
234 | padding: 8px;
235 | background: #34495e;
236 | width: 100%;
237 | cursor: pointer;
238 | }
239 |
240 | button[type=submit]:active,
241 | button[type=submit]:focus {
242 | outline: none;
243 | }
244 |
245 | #choice {
246 | background: #00B200
247 | }
248 |
249 | /* Tag */
250 |
251 | .tags-input-wrapper {
252 | display: inline-block;
253 | position: relative;
254 | width: 100%;
255 | background-size: contain;
256 | }
257 |
258 | .tags-input-wrapper input {
259 | border: none;
260 | background: transparent;
261 | outline: none;
262 | width: 100px;
263 | margin-left: 8px;
264 | }
265 |
266 | .tags-input-wrapper .tag {
267 | display: inline-block;
268 | background-color: #00B200;
269 | color: white;
270 | padding: 0px 3px 0px 7px;
271 | margin-right: 5px;
272 | margin-bottom: 5px;
273 | box-shadow: 0 5px 15px -2px #005900
274 | }
275 |
276 | .tags-input-wrapper .tag a {
277 | margin: 0 3px 3px;
278 | display: inline-block;
279 | cursor: pointer;
280 | }
281 |
282 | #tag-input1,
283 | #divChoiceName {
284 | display: none;
285 | }
286 |
287 | #divConfirm {
288 | padding-bottom: 50px;
289 | }
290 |
291 | *[tooltip]:focus:after {
292 | padding-top: 20px;
293 | content: attr(tooltip);
294 | display:block;
295 | position: absolute;
296 | color: #FFA500;
297 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WappBot
2 |
3 | Experimental project, which allows to detect the instant in which a new message is received and to carry out an automatic answer, with the possibility of giving personalized options.
4 | This project is based on an excellent application of an unofficial API for whatsapp, which is thanked below.
5 | https://github.com/mukulhase/WebWhatsapp-Wrapper
6 |
7 | The main objective is to present a simple implementation without the need for large installations.
8 |
9 | ## Getting Started
10 |
11 | To start it is necessary to have a registered instance of whatsapp web, and then copy the code contained in the file WappBot.js (See the configuration section for more details, otherwise the code contains default settings).
12 | Once copied and configured correctly, open your browser console F12 and paste the code.
13 |
14 | for more information go to the wiki - [WIKI](https://github.com/boehlergerman/WappBot/wiki)
15 |
16 | ### Prerequisites
17 |
18 | you must have a valid whatsapp account and access to whatsapp web
19 |
20 |
21 | ### Settings
22 |
23 | ```sh
24 | Default configuration:
25 | {
26 | useApi: false,
27 | uriApi: "https://wapp-bot.herokuapp.com/message",
28 | ignoreChat: [],
29 | ignoreGroupChat: false,
30 | messageInitial: {
31 | text: "Hello I'm WappBot send a reply \n",
32 | image: null
33 | },
34 | messageIncorrect: "Incorrect option entered, we remind you that the options are: \n",
35 | messageOption: {
36 | "@Date": {
37 | text: new Date().toLocaleDateString(),
38 | image: null
39 | },
40 | "@Christmas": {
41 | text: (() => {
42 | let myDate = new Date();
43 | let cmas = Date.parse("Dec 25, " + myDate.getFullYear())
44 | let today = Date.parse(myDate)
45 |
46 | let daysToChristmas = Math.round((cmas - today) / (1000 * 60 * 60 * 24))
47 | if (daysToChristmas == 0)
48 | return "Today is Christmas ... Merry Christmas!"
49 | if (daysToChristmas < 0)
50 | return "Christmas was " + -1 * (daysToChristmas) + " days ago.";
51 | if (daysToChristmas > 0)
52 | return "There are " + daysToChristmas + " days to Christmas!"
53 | })(),
54 | image: null
55 | }
56 | }
57 | ```
58 | ```sh
59 | Options:
60 | useApi [Bool] [Default False], allows you to use an API for message processing,
61 | see the DialogFlow-Nodejs-WappBot repository.
62 |
63 | uriApi [String] URL of the api you wish to consult,
64 | you can use the proposed API, it's free :)
65 | [WappBot-API](https://github.com/boehlergerman/DialogFlow-Nodejs-WappBotAPI)
66 |
67 | ignoreChat [Array] prevents repeated messages, preventing a "hello" from being sent again
68 | when an incorrect option is entered
69 |
70 | ignoreGroupChat [Bool] [Default false] prevents automatic message sending if the chat is a group
71 |
72 | messageInitial [Object] configuration of the first message to be sent to the chat
73 | | that generated an incoming message
74 | |
75 | |-> text [String | Self-Invoking Anonymous Function] Welcome text
76 | |
77 | |-> image [String] [Default Null] [Support Base64 Full Format | URL IMAGE]
78 | image to be sent together with the welcome text
79 |
80 | messageIncorrect [String] reply message in case an incorrect option is entered
81 |
82 | messageOption [Object] configuration of the response options that are enabled for the user
83 | |
84 | |
85 | |-> KeyOption [String] identifier to be shown to the user, it is convenient to use a special
86 | | character at the beginning such as @ # $,
87 | | to avoid misinterpreting the user's message.
88 | |
89 | |-> text [String | Self-Invoking Anonymous Function]
90 | | Text to display when the user enters the option properly
91 | |
92 | |-> image [String] [Default Null] [Support Base64 Full Format | URL IMAGE]
93 | image to be sent together with the text of the desired option
94 |
95 | ```
96 |
97 | ## Important
98 | URL use is limited by Content-Security-Policy
99 |
100 | Whatsapp Web contains meta tag that avoids that from the context of the site are executed requests to the outside that are not contemplated in the header, for a security issue this header can only add more restriction and not remove it.
101 |
102 | Therefore, the use of URLAPI or IMAGE configuration in URL format and not Base64 will lead to an error in the console when you receive an incoming message.
103 | This problem can be solved by installing an extension in your browser that removes the security of CSP and thus be able to use the full potential of HTTPS and HTTP requests within the context of Whatsapp Web.
104 |
105 | [Disable CSP Extension recommend](https://bit.ly/2FFEnkT)
106 |
107 | Otherwise you should use applications such as NWJS or Electron that simulate a context above whatsapp web.
108 |
109 | ## Wappbot extension for google chrome
110 |
111 | Wappbot also exists in extension format for google chrome that allows you to use without knowing javascript, *also add the functionality to disable CSP automatically*
112 |
113 | > link to the chrome play store: [Play store](https://chrome.google.com/webstore/detail/wappbot/kfoipoajagcbedgamieppifonpbhnbkd)
114 |
115 | > link to the wiki to know how to use it: [Wiki extension chrome](https://github.com/boehlergerman/WappBot/wiki/how-to-use-it-with-extension)
116 |
117 | 
118 |
119 |
120 | ## Examples and results
121 | ##### starting using script in console
122 |
123 | 
124 |
125 | ##### starting using extension chrome, Choice Settings
126 |
127 | [](https://imgur.com/xtaK7hV)
128 |
129 | ##### starting using extension chrome, WappBot API with DialogFlow (Spanish)
130 |
131 | 
132 |
133 | ```sh
134 | useApi: true,
135 | uriApi: "https://wapp-bot.herokuapp.com/message"
136 | ```
137 |
138 | 
139 |
140 |
141 | ##### results with image configuration, remember to disable CSP
142 |
143 | ```sh
144 | messageInitial: {
145 | text: "Hello I'm WappBot send a reply \n",
146 | image: "https://i.imgur.com/4ufAcMb.png"
147 | },
148 | messageIncorrect: "Incorrect option entered, we remind you that the options are: \n",
149 | messageOption: {
150 | "@Date": {
151 | text: new Date().toLocaleDateString(),
152 | image: null
153 | },
154 | "@Christmas": {
155 | text: "My text",
156 | image: "https://i.imgur.com/GJXbceA.jpg"
157 | }
158 | }
159 | ```
160 | 
161 |
162 |
163 | ## Authors
164 |
165 | * **BoehlerGerman** - *Initial work* - [BoehlerGerman](https://github.com/boehlergerman)
166 |
167 |
168 | ## License
169 |
170 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
171 |
172 | ## Legal
173 |
174 | This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by WhatsApp or any of its affiliates or subsidiaries. This is an independent and unofficial software. Use at your own risk.
175 |
--------------------------------------------------------------------------------
/extension-chrome/popup/popup.js:
--------------------------------------------------------------------------------
1 | // Pure JS:
2 | "use strict";
3 |
4 | var choice = {};
5 | var globalTag;
6 |
7 | document.addEventListener('DOMContentLoaded', function () {
8 | loadTags();
9 | restoreData();
10 | document.getElementById("txtUrlAPI").style.display = "none";
11 | document.getElementById("chkApi").addEventListener("click", () => {
12 | disable();
13 | saveData();
14 | showUrlAPi();
15 | });
16 | document.getElementById("confirm").addEventListener("click", confirm);
17 | document.getElementById("formChoice").addEventListener("submit", (e) => {
18 | e.preventDefault();
19 | document.getElementById("choice").removeAttribute("tooltip");
20 |
21 | const message = document.getElementById("txtMessage");
22 | const imageUrl = document.getElementById("txtImage");
23 | const choiceKey = document.getElementById("txtChoiceName");
24 |
25 |
26 |
27 | for (const iterator of ["Initial", "Incorrect", "Choice1", "Choice2", "Choice3", "Choice4", "Choice5", "Choice6", "Choice7", "Choice8"]) {
28 | if (!choice[iterator]) {
29 | let element = {
30 | text: message.value,
31 | image: imageUrl.value === "" ? null : imageUrl.value,
32 | keyName: choiceKey.value === "" ? iterator : choiceKey.value
33 | }
34 |
35 | if (!globalTag) {
36 | var tagInput1 = new TagsInput({
37 | selector: 'tag-input1',
38 | duplicate: false,
39 | max: 10
40 | });
41 | globalTag = tagInput1.addData([iterator])
42 | } else globalTag.addTag(iterator);
43 |
44 | if (iterator.includes("Choice"))
45 | element.text = ' \t' + element.text;
46 | else element.text += ' \n';
47 |
48 | choice[iterator] = element;
49 | break;
50 | }
51 | else {
52 | if (choice[iterator].keyName.toUpperCase() === choiceKey.value.toUpperCase()) {
53 | document.getElementById("choice").setAttribute("tooltip", 'The choice name already exists');
54 | break;
55 | }
56 | }
57 | }
58 |
59 | choiceSetting();
60 |
61 | saveData();
62 |
63 | message.value = "";
64 | imageUrl.value = "";
65 | choiceKey.value = "";
66 | });
67 | });
68 |
69 |
70 | function choiceSetting() {
71 | if (Object.keys(choice).includes("Initial") && Object.keys(choice).includes("Incorrect")) {
72 | document.getElementById("divChoiceName").style.display = 'block';
73 | document.getElementById("txtChoiceName").required = true;
74 | } else {
75 | document.getElementById("txtChoiceName").value = "";
76 | document.getElementById("divChoiceName").style.display = 'none';
77 | document.getElementById("txtChoiceName").required = false;
78 | }
79 | }
80 |
81 | function disable() {
82 | const check = document.getElementById('chkApi').checked
83 | document.getElementById("txtMessage").disabled = check;
84 | document.getElementById("txtImage").disabled = check;
85 | document.getElementById("choice").disabled = check;
86 | document.getElementById("txtChoiceName").disabled = check;
87 | }
88 |
89 | function showUrlAPi() {
90 | const chboxs = document.getElementById("chkApi");
91 | document.getElementById("txtUrlAPI").style.display = chboxs.checked ? "block" : "none";
92 | }
93 |
94 | function confirm() {
95 | const useApi = document.getElementById('chkApi').checked
96 |
97 | window.WappBot = {
98 | configWappBot: {
99 | useApi: useApi,
100 | uriApi: document.getElementById("txtUrlAPI").value,
101 | ignoreChat: []
102 | }
103 | }
104 |
105 | if (useApi) {
106 | chrome.storage.local.set({ WappBot: window.WappBot }, function () {
107 | console.log('Value is set to ' + window.WappBot);
108 | });
109 | document.getElementById("confirm").setAttribute("tooltip", 'API configuration accepted, refresh Whatsapp Web Please');
110 | return;
111 | }
112 |
113 | if (Object.keys(choice).length <= 2 || !Object.keys(choice).includes("Initial") || !Object.keys(choice).includes("Incorrect")) {
114 | document.getElementById("confirm").setAttribute("tooltip", 'Must contain at least 3 options (initial, incorrect and one choice)');
115 | return;
116 | }
117 |
118 | for (const key in choice) {
119 | if (choice.hasOwnProperty(key)) {
120 | const element = Object.assign({}, choice[key]);
121 | switch (key) {
122 | case "Initial":
123 | delete element["keyName"];
124 | window.WappBot.configWappBot["messageInitial"] = element;
125 | break;
126 | case "Incorrect":
127 | window.WappBot.configWappBot["messageIncorrect"] = element.text;
128 | break;
129 | default:
130 | if (!window.WappBot.configWappBot["messageOption"]) window.WappBot.configWappBot["messageOption"] = {};
131 | const keyName = element.keyName; delete element["keyName"];
132 | window.WappBot.configWappBot["messageOption"][keyName] = element;
133 | break;
134 | }
135 | }
136 | }
137 | chrome.storage.local.set({ WappBot: window.WappBot }, function () {
138 | console.log('Value is set to ' + window.WappBot);
139 | });
140 |
141 | document.getElementById("confirm").setAttribute("tooltip", 'Successfully loaded configuration, refresh Whatsapp Web Please');
142 | }
143 |
144 | // Util data store
145 |
146 | function saveData() {
147 | chrome.storage.local.set({ StorePopup: { "choice": choice, "useApi": document.getElementById('chkApi').checked } }, function () {
148 | console.log('Value is set to ' + JSON.stringify(choice));
149 | });
150 | }
151 |
152 | function restoreData() {
153 | chrome.storage.local.get(['StorePopup'], function (result) {
154 | if (!!result.StorePopup) {
155 | console.log(result);
156 | choice = result.StorePopup.choice;
157 | document.getElementById('chkApi').checked = result.StorePopup.useApi;
158 | disable();
159 | const keys = Object.keys(choice);
160 | if (keys.length > 0) {
161 | var tagInput1 = new TagsInput({
162 | selector: 'tag-input1',
163 | duplicate: false,
164 | max: 10
165 | });
166 | globalTag = tagInput1.addData(keys);
167 | choiceSetting();
168 | }
169 | }
170 | });
171 |
172 | }
173 |
174 |
175 | // Tags
176 |
177 |
178 | function loadTags() {
179 | var TagsInput = function TagsInput(opts) {
180 | this.options = Object.assign(TagsInput.defaults, opts);
181 | this.orignal_input = document.getElementById(opts.selector);
182 | this.arr = [];
183 | this.wrapper = document.createElement('div');
184 | // this.wrapper = document.getElementsByClassName("tags-input-wrapper")[0];
185 | this.input = document.createElement('input');
186 | buildUI(this);
187 | addEvents(this);
188 | };
189 |
190 | TagsInput.prototype.addTag = function (string) {
191 | if (this.anyErrors(string)) return;
192 | this.arr.push(string);
193 | var tagInput = this;
194 | var tag = document.createElement('span');
195 | tag.className = this.options.tagClass;
196 | tag.innerText = string;
197 | var closeIcon = document.createElement('a');
198 | closeIcon.innerHTML = '×';
199 | closeIcon.addEventListener('click', function (e) {
200 | e.preventDefault();
201 | var tag = this.parentNode;
202 |
203 | for (var i = 0; i < tagInput.wrapper.childNodes.length; i++) {
204 | if (tagInput.wrapper.childNodes[i] == tag) tagInput.deleteTag(tag, i);
205 | }
206 | });
207 | tag.appendChild(closeIcon);
208 | this.wrapper.insertBefore(tag, this.input);
209 | this.orignal_input.value = this.arr.join(',');
210 | return this;
211 | };
212 |
213 | TagsInput.prototype.deleteTag = function (tag, i) {
214 | tag.remove();
215 | const key = this.arr[i];
216 | delete choice[key];
217 | this.arr.splice(i, 1);
218 | choiceSetting();
219 | saveData();
220 | this.orignal_input.value = this.arr.join(',');
221 | return this;
222 | };
223 |
224 | TagsInput.prototype.anyErrors = function (string) {
225 | if (this.options.max != null && this.arr.length >= this.options.max) {
226 | console.log('max tags limit reached');
227 | return true;
228 | }
229 |
230 | if (!this.options.duplicate && this.arr.indexOf(string) != -1) {
231 | console.log('duplicate found " ' + string + ' " ');
232 | return true;
233 | }
234 |
235 | return false;
236 | };
237 |
238 | TagsInput.prototype.addData = function (array) {
239 | var plugin = this;
240 | array.forEach(function (string) {
241 | plugin.addTag(string);
242 | });
243 | return this;
244 | };
245 |
246 | TagsInput.prototype.getInputString = function () {
247 | return this.arr.join(',');
248 | }; // Private function to initialize the UI Elements
249 |
250 |
251 | function buildUI(tags) {
252 | tags.wrapper.append(tags.input);
253 | tags.wrapper.classList.add(tags.options.wrapperClass);
254 | // document.getElementById(tags.orignal_input).style.display = 'none';
255 | tags.orignal_input.style.display = 'none';
256 | tags.orignal_input.parentNode.insertBefore(tags.wrapper, tags.orignal_input);
257 | }
258 |
259 | function addEvents(tags) {
260 | tags.wrapper.addEventListener('click', function () {
261 | tags.input.focus();
262 | });
263 | tags.input.addEventListener('keydown', function (e) {
264 | var str = tags.input.value.trim();
265 |
266 | if (!!~[9, 13, 188].indexOf(e.keyCode)) {
267 | tags.input.value = "";
268 | if (str != "") tags.addTag(str);
269 | }
270 | });
271 | }
272 |
273 | TagsInput.defaults = {
274 | selector: '',
275 | wrapperClass: 'tags-input-wrapper',
276 | tagClass: 'tag',
277 | max: null,
278 | duplicate: false
279 | };
280 | window.TagsInput = TagsInput;
281 | }
--------------------------------------------------------------------------------
/wappbot.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | window.WappBot = {
4 | configWappBot: {
5 | useApi: false,
6 | uriApi: "https://wapp-bot.herokuapp.com/message",
7 | ignoreChat: [],
8 | ignoreGroupChat: false,
9 | messageInitial: {
10 | text: "Hello I'm WappBot send a reply \n",
11 | image: null,
12 | },
13 | messageIncorrect: "Incorrect option entered, we remind you that the options are: \n",
14 | messageOption: {
15 | "@Date": {
16 | text: new Date().toLocaleDateString(),
17 | image: null,
18 | },
19 | "@Christmas": {
20 | text: (() => {
21 | let myDate = new Date();
22 | let cmas = Date.parse("Dec 25, " + myDate.getFullYear());
23 | let today = Date.parse(myDate);
24 |
25 | let daysToChristmas = Math.round((cmas - today) / (1000 * 60 * 60 * 24));
26 | if (daysToChristmas == 0) return "Today is Christmas ... Merry Christmas!";
27 | if (daysToChristmas < 0) return "Christmas was " + -1 * daysToChristmas + " days ago.";
28 | if (daysToChristmas > 0) return "There are " + daysToChristmas + " days to Christmas!";
29 | })(),
30 | image: null,
31 | },
32 | },
33 | },
34 | };
35 |
36 | /* eslint-disable */
37 | /**
38 | * This script contains WAPI functions that need to be run in the context of the webpage
39 | */
40 |
41 | /**
42 | * Auto discovery the webpack object references of instances that contains all functions used by the WAPI
43 | * functions and creates the Store object.
44 | */
45 | if (!window["webpackJsonp"]) {
46 | window.webpackJsonp = webpackJsonp;
47 | }
48 |
49 | if (!window.Store) {
50 | (function () {
51 | function getStore(modules) {
52 | let foundCount = 0;
53 | let neededObjects = [
54 | {
55 | id: "Store",
56 | conditions: (module) => (module.default && module.default.Chat && module.default.Msg ? module.default : null),
57 | },
58 | {
59 | id: "MediaCollection",
60 | conditions: (module) =>
61 | module.default && module.default.prototype && module.default.prototype.processAttachments
62 | ? module.default
63 | : null,
64 | },
65 | { id: "MediaProcess", conditions: (module) => (module.BLOB ? module : null) },
66 | { id: "Wap", conditions: (module) => (module.createGroup ? module : null) },
67 | {
68 | id: "ServiceWorker",
69 | conditions: (module) => (module.default && module.default.killServiceWorker ? module : null),
70 | },
71 | { id: "State", conditions: (module) => (module.STATE && module.STREAM ? module : null) },
72 | {
73 | id: "WapDelete",
74 | conditions: (module) =>
75 | module.sendConversationDelete && module.sendConversationDelete.length == 2 ? module : null,
76 | },
77 | {
78 | id: "Conn",
79 | conditions: (module) =>
80 | module.default && module.default.ref && module.default.refTTL ? module.default : null,
81 | },
82 | {
83 | id: "WapQuery",
84 | conditions: (module) =>
85 | module.queryExist ? module : module.default && module.default.queryExist ? module.default : null,
86 | },
87 | { id: "CryptoLib", conditions: (module) => (module.decryptE2EMedia ? module : null) },
88 | {
89 | id: "OpenChat",
90 | conditions: (module) =>
91 | module.default && module.default.prototype && module.default.prototype.openChat ? module.default : null,
92 | },
93 | {
94 | id: "UserConstructor",
95 | conditions: (module) =>
96 | module.default &&
97 | module.default.prototype &&
98 | module.default.prototype.isServer &&
99 | module.default.prototype.isUser
100 | ? module.default
101 | : null,
102 | },
103 | {
104 | id: "SendTextMsgToChat",
105 | conditions: (module) => (module.sendTextMsgToChat ? module.sendTextMsgToChat : null),
106 | },
107 | { id: "SendSeen", conditions: (module) => (module.sendSeen ? module.sendSeen : null) },
108 | { id: "sendDelete", conditions: (module) => (module.sendDelete ? module.sendDelete : null) },
109 | ];
110 | for (let idx in modules) {
111 | if (typeof modules[idx] === "object" && modules[idx] !== null) {
112 | let first = Object.values(modules[idx])[0];
113 | if (typeof first === "object" && first.exports) {
114 | for (let idx2 in modules[idx]) {
115 | let module = modules(idx2);
116 | if (!module) {
117 | continue;
118 | }
119 | neededObjects.forEach((needObj) => {
120 | if (!needObj.conditions || needObj.foundedModule) return;
121 | let neededModule = needObj.conditions(module);
122 | if (neededModule !== null) {
123 | foundCount++;
124 | needObj.foundedModule = neededModule;
125 | }
126 | });
127 | if (foundCount == neededObjects.length) {
128 | break;
129 | }
130 | }
131 |
132 | let neededStore = neededObjects.find((needObj) => needObj.id === "Store");
133 | window.Store = neededStore.foundedModule ? neededStore.foundedModule : {};
134 | neededObjects.splice(neededObjects.indexOf(neededStore), 1);
135 | neededObjects.forEach((needObj) => {
136 | if (needObj.foundedModule) {
137 | window.Store[needObj.id] = needObj.foundedModule;
138 | }
139 | });
140 | window.Store.sendMessage = function (e) {
141 | return window.Store.SendTextMsgToChat(this, ...arguments);
142 | };
143 | return window.Store;
144 | }
145 | }
146 | }
147 | }
148 |
149 | //webpackJsonp([], { 'parasite': (x, y, z) => getStore(z) }, ['parasite']);
150 | /*
151 | Code update
152 | */
153 | if (typeof webpackJsonp === "function") {
154 | webpackJsonp([], { parasite: (x, y, z) => getStore(z) }, ["parasite"]);
155 | } else {
156 | webpackJsonp.push([
157 | ["parasite"],
158 | {
159 | parasite: function (o, e, t) {
160 | getStore(t);
161 | },
162 | },
163 | [["parasite"]],
164 | ]);
165 | }
166 | })();
167 | }
168 |
169 | window.WAPI = {
170 | lastRead: {},
171 | };
172 |
173 | window.WAPI._serializeRawObj = (obj) => {
174 | if (obj) {
175 | return obj.toJSON();
176 | }
177 | return {};
178 | };
179 |
180 | /**
181 | * Serializes a chat object
182 | *
183 | * @param rawChat Chat object
184 | * @returns {{}}
185 | */
186 |
187 | window.WAPI._serializeChatObj = (obj) => {
188 | if (obj == undefined) {
189 | return null;
190 | }
191 |
192 | return Object.assign(window.WAPI._serializeRawObj(obj), {
193 | kind: obj.kind,
194 | isGroup: obj.isGroup,
195 | contact: obj["contact"] ? window.WAPI._serializeContactObj(obj["contact"]) : null,
196 | groupMetadata: obj["groupMetadata"] ? window.WAPI._serializeRawObj(obj["groupMetadata"]) : null,
197 | presence: obj["presence"] ? window.WAPI._serializeRawObj(obj["presence"]) : null,
198 | msgs: null,
199 | });
200 | };
201 |
202 | window.WAPI._serializeContactObj = (obj) => {
203 | if (obj == undefined) {
204 | return null;
205 | }
206 |
207 | return Object.assign(window.WAPI._serializeRawObj(obj), {
208 | formattedName: obj.formattedName,
209 | isHighLevelVerified: obj.isHighLevelVerified,
210 | isMe: obj.isMe,
211 | isMyContact: obj.isMyContact,
212 | isPSA: obj.isPSA,
213 | isUser: obj.isUser,
214 | isVerified: obj.isVerified,
215 | isWAContact: obj.isWAContact,
216 | profilePicThumbObj: obj.profilePicThumb ? WAPI._serializeProfilePicThumb(obj.profilePicThumb) : {},
217 | statusMute: obj.statusMute,
218 | msgs: null,
219 | });
220 | };
221 |
222 | window.WAPI._serializeMessageObj = (obj) => {
223 | if (obj == undefined) {
224 | return null;
225 | }
226 |
227 | return Object.assign(window.WAPI._serializeRawObj(obj), {
228 | id: obj.id._serialized,
229 | sender: obj["senderObj"] ? WAPI._serializeContactObj(obj["senderObj"]) : null,
230 | timestamp: obj["t"],
231 | content: obj["body"],
232 | isGroupMsg: obj.isGroupMsg,
233 | isLink: obj.isLink,
234 | isMMS: obj.isMMS,
235 | isMedia: obj.isMedia,
236 | isNotification: obj.isNotification,
237 | isPSA: obj.isPSA,
238 | type: obj.type,
239 | chat: WAPI._serializeChatObj(obj["chat"]),
240 | chatId: obj.id.remote,
241 | quotedMsgObj: WAPI._serializeMessageObj(obj["_quotedMsgObj"]),
242 | mediaData: window.WAPI._serializeRawObj(obj["mediaData"]),
243 | });
244 | };
245 |
246 | window.WAPI._serializeNumberStatusObj = (obj) => {
247 | if (obj == undefined) {
248 | return null;
249 | }
250 |
251 | return Object.assign(
252 | {},
253 | {
254 | id: obj.jid,
255 | status: obj.status,
256 | isBusiness: obj.biz === true,
257 | canReceiveMessage: obj.status === 200,
258 | }
259 | );
260 | };
261 |
262 | window.WAPI._serializeProfilePicThumb = (obj) => {
263 | if (obj == undefined) {
264 | return null;
265 | }
266 |
267 | return Object.assign(
268 | {},
269 | {
270 | eurl: obj.eurl,
271 | id: obj.id,
272 | img: obj.img,
273 | imgFull: obj.imgFull,
274 | raw: obj.raw,
275 | tag: obj.tag,
276 | }
277 | );
278 | };
279 |
280 | /**
281 | * Fetches chat object from store by ID
282 | *
283 | * @param id ID of chat
284 | * @returns {T|*} Chat object
285 | */
286 | window.WAPI.getChat = function (id) {
287 | id = typeof id == "string" ? id : id._serialized;
288 | const found = window.Store.Chat.get(id);
289 | found.sendMessage = found.sendMessage
290 | ? found.sendMessage
291 | : function () {
292 | return window.Store.sendMessage.apply(this, arguments);
293 | };
294 | return found;
295 | };
296 |
297 | /**
298 | * Fetches all chat IDs from store
299 | *
300 | * @returns {Array|*} List of chat id's
301 | */
302 | window.WAPI.getAllChatIds = function () {
303 | const chatIds = window.Store.Chat.map((chat) => chat.id._serialized || chat.id);
304 | return chatIds;
305 | };
306 |
307 | window.WAPI.processMessageObj = function (messageObj, includeMe, includeNotifications) {
308 | if (messageObj.isNotification) {
309 | if (includeNotifications) return WAPI._serializeMessageObj(messageObj);
310 | else return;
311 | // System message
312 | // (i.e. "Messages you send to this chat and calls are now secured with end-to-end encryption...")
313 | } else if (messageObj.id.fromMe === false || includeMe) {
314 | return WAPI._serializeMessageObj(messageObj);
315 | }
316 | return;
317 | };
318 |
319 | window.WAPI.sendImage = async function (imgBase64, chatid, filename, caption) {
320 | let id = chatid;
321 | if (!window.WAPI.getAllChatIds().find((chat) => chat == chatid))
322 | id = new window.Store.UserConstructor(chatid, { intentionallyUsePrivateConstructor: true });
323 | var chat = WAPI.getChat(id);
324 | // Ignore Group Chat
325 | if (WAPI._serializeChatObj(chat).isGroup && window.WappBot.configWappBot.ignoreGroupChat) return;
326 | // create new chat
327 | try {
328 | var mediaBlob = await window.WAPI.base64ImageToFile(imgBase64, filename);
329 | var mc = new Store.MediaCollection(chat);
330 | mc.processFiles([mediaBlob], chat, 1).then(() => {
331 | var media = mc.models[0];
332 | media.sendToChat(chat, { caption: caption });
333 | });
334 | } catch (error) {
335 | if (window.Store.Chat.length === 0) return false;
336 |
337 | let firstChat = Store.Chat.models[0];
338 | let originalID = firstChat.id;
339 | firstChat.id =
340 | typeof originalID === "string"
341 | ? id
342 | : new window.Store.UserConstructor(id, { intentionallyUsePrivateConstructor: true });
343 | let mediaBlob = await window.WAPI.base64ImageToFile(imgBase64, filename);
344 | var mc = new Store.MediaCollection(chat);
345 | chat = WAPI.getChat(id);
346 | mc.processAttachments([{ file: mediaBlob }, 1], chat, 1).then(() => {
347 | let media = mc.models[0];
348 | media.sendToChat(chat, { caption: caption });
349 | });
350 | return true;
351 | }
352 | };
353 |
354 | window.WAPI.base64ImageToFile = function (image, filename) {
355 | return new Promise(async (resolve) => {
356 | if (!image.includes("base64")) {
357 | image = await window.WappBot.toDataURL("https://cors-anywhere.herokuapp.com/" + image); // convert url in base64
358 | }
359 | var arr = image.split(","),
360 | mime = arr[0].match(/:(.*?);/)[1],
361 | bstr = atob(arr[1]),
362 | n = bstr.length,
363 | u8arr = new Uint8Array(n);
364 | while (n--) {
365 | u8arr[n] = bstr.charCodeAt(n);
366 | }
367 | resolve(new File([u8arr], filename, { type: mime }));
368 | });
369 | };
370 |
371 | window.WAPI.sendMessage = function (idChat, message) {
372 | let id = idChat;
373 | if (!window.WAPI.getAllChatIds().find((chat) => chat == idChat))
374 | id = new window.Store.UserConstructor(idChat, { intentionallyUsePrivateConstructor: true });
375 | var chat = WAPI.getChat(id);
376 | if (WAPI._serializeChatObj(chat).isGroup && window.WappBot.configWappBot.ignoreGroupChat) return;
377 | try {
378 | // create new chat
379 | return chat.sendMessage(message);
380 | } catch (e) {
381 | if (window.Store.Chat.length === 0) return false;
382 |
383 | firstChat = Store.Chat.models[0];
384 | var originalID = firstChat.id;
385 | firstChat.id =
386 | typeof originalID === "string"
387 | ? id
388 | : new window.Store.UserConstructor(id, { intentionallyUsePrivateConstructor: true });
389 | var chat = WAPI.getChat(firstChat.id);
390 | chat.sendMessage(message);
391 | return true;
392 | }
393 | };
394 |
395 | window.WappBot.toDataURL = (url) => {
396 | return new Promise((resolve) => {
397 | var xhr = new XMLHttpRequest();
398 | xhr.onload = function () {
399 | var reader = new FileReader();
400 | reader.onloadend = function () {
401 | resolve(reader.result);
402 | };
403 | reader.readAsDataURL(xhr.response);
404 | };
405 | xhr.open("GET", url);
406 | xhr.responseType = "blob";
407 | xhr.send();
408 | });
409 | };
410 |
411 | window.WappBot.sendByAPIWappBot = (newMessage, chatId) => {
412 | fetch(window.WappBot.configWappBot.uriApi, {
413 | method: "POST",
414 | headers: {
415 | Accept: "application/json",
416 | "Content-Type": "application/json",
417 | },
418 | body: JSON.stringify({ messageText: newMessage }),
419 | }).then(function (response) {
420 | response.json().then((post) => {
421 | if (!post && !post.messageResponse) return;
422 | window.WAPI.sendMessage(chatId, post.messageResponse);
423 | });
424 | });
425 | };
426 |
427 | window.WappBot.messageIncludeKey = (message, options) => {
428 | for (let i = 0; i < options.length; i++) {
429 | if (message.toUpperCase().includes(options[i].toUpperCase()))
430 | return window.WappBot.configWappBot.messageOption[options[i]];
431 | }
432 | return false;
433 | };
434 |
435 | window.WappBot.prepareMessageToSend = (chatId, options) => {
436 | let message = "";
437 | if (window.WappBot.configWappBot.ignoreChat.indexOf(chatId) > -1) {
438 | message = `${window.WappBot.configWappBot.messageIncorrect}`;
439 | } else {
440 | message = `${window.WappBot.configWappBot.messageInitial.text}`;
441 | window.WappBot.configWappBot.ignoreChat.push(chatId);
442 | }
443 | for (let i = 0; i < options.length; i++) message += `\t ${options[i]} \n`;
444 |
445 | return message;
446 | };
447 |
448 | window.WappBot.sendByLocalSetting = (newMessage, chatId) => {
449 | const options = Object.keys(window.WappBot.configWappBot.messageOption);
450 | const messageIncludeKey = window.WappBot.messageIncludeKey(newMessage, options);
451 | if (!messageIncludeKey) {
452 | const message = window.WappBot.prepareMessageToSend(chatId, options);
453 | if (!window.WappBot.configWappBot.messageInitial.image) window.WAPI.sendMessage(chatId, message);
454 | else window.WAPI.sendImage(window.WappBot.configWappBot.messageInitial.image, chatId, "image", message);
455 | } else {
456 | if (!messageIncludeKey.image) window.WAPI.sendMessage(chatId, messageIncludeKey.text);
457 | else window.WAPI.sendImage(messageIncludeKey.image, chatId, "image", messageIncludeKey.text);
458 | }
459 | };
460 |
461 | /**
462 | * New messages observable functions.
463 | */
464 | window.WAPI._newMessagesQueue = [];
465 | window.WAPI._newMessagesBuffer =
466 | sessionStorage.getItem("saved_msgs") != null ? JSON.parse(sessionStorage.getItem("saved_msgs")) : [];
467 | window.WAPI._newMessagesDebouncer = null;
468 | window.WAPI._newMessagesCallbacks = [];
469 |
470 | window.Store.Msg.off("add");
471 | sessionStorage.removeItem("saved_msgs");
472 |
473 | window.WAPI._newMessagesListener = window.Store.Msg.on("add", (newMessage) => {
474 | if (newMessage && newMessage.isNewMsg && !newMessage.isSentByMe) {
475 | let message = window.WAPI.processMessageObj(newMessage, false, false);
476 | if (message) {
477 | if (window.WappBot.configWappBot.useApi)
478 | window.WappBot.sendByAPIWappBot(message.body, message.chatId._serialized);
479 | else window.WappBot.sendByLocalSetting(message.body, message.chatId._serialized);
480 | }
481 | }
482 | });
483 |
484 | window.WAPI._unloadInform = (event) => {
485 | // Save in the buffer the ungot unreaded messages
486 | window.WAPI._newMessagesBuffer.forEach((message) => {
487 | Object.keys(message).forEach((key) => (message[key] === undefined ? delete message[key] : ""));
488 | });
489 | sessionStorage.setItem("saved_msgs", JSON.stringify(window.WAPI._newMessagesBuffer));
490 |
491 | // Inform callbacks that the page will be reloaded.
492 | window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) {
493 | if (callbackObj.callback !== undefined) {
494 | callbackObj.callback({ status: -1, message: "page will be reloaded, wait and register callback again." });
495 | }
496 | });
497 | };
498 |
499 | window.addEventListener("unload", window.WAPI._unloadInform, false);
500 | window.addEventListener("beforeunload", window.WAPI._unloadInform, false);
501 | window.addEventListener("pageunload", window.WAPI._unloadInform, false);
502 |
--------------------------------------------------------------------------------
/extension-chrome/script/wappbot.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | window.WappBot = {
4 | configWappBot: {
5 | useApi: false,
6 | uriApi: "https://wapp-bot.herokuapp.com/message",
7 | ignoreChat: [],
8 | ignoreGroupChat: false,
9 | messageInitial: {
10 | text: "Hello I'm WappBot send a reply \n",
11 | image: null,
12 | },
13 | messageIncorrect: "Incorrect option entered, we remind you that the options are: \n",
14 | messageOption: {
15 | "@Date": {
16 | text: new Date().toLocaleDateString(),
17 | image: null,
18 | },
19 | "@Christmas": {
20 | text: (() => {
21 | let myDate = new Date();
22 | let cmas = Date.parse("Dec 25, " + myDate.getFullYear());
23 | let today = Date.parse(myDate);
24 |
25 | let daysToChristmas = Math.round((cmas - today) / (1000 * 60 * 60 * 24));
26 | if (daysToChristmas == 0) return "Today is Christmas ... Merry Christmas!";
27 | if (daysToChristmas < 0) return "Christmas was " + -1 * daysToChristmas + " days ago.";
28 | if (daysToChristmas > 0) return "There are " + daysToChristmas + " days to Christmas!";
29 | })(),
30 | image: null,
31 | },
32 | },
33 | },
34 | };
35 |
36 | /* eslint-disable */
37 | /**
38 | * This script contains WAPI functions that need to be run in the context of the webpage
39 | */
40 |
41 | /**
42 | * Auto discovery the webpack object references of instances that contains all functions used by the WAPI
43 | * functions and creates the Store object.
44 | */
45 | if (!window["webpackJsonp"]) {
46 | window.webpackJsonp = webpackJsonp;
47 | }
48 |
49 | if (!window.Store) {
50 | (function () {
51 | function getStore(modules) {
52 | let foundCount = 0;
53 | let neededObjects = [
54 | {
55 | id: "Store",
56 | conditions: (module) => (module.default && module.default.Chat && module.default.Msg ? module.default : null),
57 | },
58 | {
59 | id: "MediaCollection",
60 | conditions: (module) =>
61 | module.default && module.default.prototype && module.default.prototype.processAttachments
62 | ? module.default
63 | : null,
64 | },
65 | { id: "MediaProcess", conditions: (module) => (module.BLOB ? module : null) },
66 | { id: "Wap", conditions: (module) => (module.createGroup ? module : null) },
67 | {
68 | id: "ServiceWorker",
69 | conditions: (module) => (module.default && module.default.killServiceWorker ? module : null),
70 | },
71 | { id: "State", conditions: (module) => (module.STATE && module.STREAM ? module : null) },
72 | {
73 | id: "WapDelete",
74 | conditions: (module) =>
75 | module.sendConversationDelete && module.sendConversationDelete.length == 2 ? module : null,
76 | },
77 | {
78 | id: "Conn",
79 | conditions: (module) =>
80 | module.default && module.default.ref && module.default.refTTL ? module.default : null,
81 | },
82 | {
83 | id: "WapQuery",
84 | conditions: (module) =>
85 | module.queryExist ? module : module.default && module.default.queryExist ? module.default : null,
86 | },
87 | { id: "CryptoLib", conditions: (module) => (module.decryptE2EMedia ? module : null) },
88 | {
89 | id: "OpenChat",
90 | conditions: (module) =>
91 | module.default && module.default.prototype && module.default.prototype.openChat ? module.default : null,
92 | },
93 | {
94 | id: "UserConstructor",
95 | conditions: (module) =>
96 | module.default &&
97 | module.default.prototype &&
98 | module.default.prototype.isServer &&
99 | module.default.prototype.isUser
100 | ? module.default
101 | : null,
102 | },
103 | {
104 | id: "SendTextMsgToChat",
105 | conditions: (module) => (module.sendTextMsgToChat ? module.sendTextMsgToChat : null),
106 | },
107 | { id: "SendSeen", conditions: (module) => (module.sendSeen ? module.sendSeen : null) },
108 | { id: "sendDelete", conditions: (module) => (module.sendDelete ? module.sendDelete : null) },
109 | ];
110 | for (let idx in modules) {
111 | if (typeof modules[idx] === "object" && modules[idx] !== null) {
112 | let first = Object.values(modules[idx])[0];
113 | if (typeof first === "object" && first.exports) {
114 | for (let idx2 in modules[idx]) {
115 | let module = modules(idx2);
116 | if (!module) {
117 | continue;
118 | }
119 | neededObjects.forEach((needObj) => {
120 | if (!needObj.conditions || needObj.foundedModule) return;
121 | let neededModule = needObj.conditions(module);
122 | if (neededModule !== null) {
123 | foundCount++;
124 | needObj.foundedModule = neededModule;
125 | }
126 | });
127 | if (foundCount == neededObjects.length) {
128 | break;
129 | }
130 | }
131 |
132 | let neededStore = neededObjects.find((needObj) => needObj.id === "Store");
133 | window.Store = neededStore.foundedModule ? neededStore.foundedModule : {};
134 | neededObjects.splice(neededObjects.indexOf(neededStore), 1);
135 | neededObjects.forEach((needObj) => {
136 | if (needObj.foundedModule) {
137 | window.Store[needObj.id] = needObj.foundedModule;
138 | }
139 | });
140 | window.Store.sendMessage = function (e) {
141 | return window.Store.SendTextMsgToChat(this, ...arguments);
142 | };
143 | return window.Store;
144 | }
145 | }
146 | }
147 | }
148 |
149 | //webpackJsonp([], { 'parasite': (x, y, z) => getStore(z) }, ['parasite']);
150 | /*
151 | Code update
152 | */
153 | if (typeof webpackJsonp === "function") {
154 | webpackJsonp([], { parasite: (x, y, z) => getStore(z) }, ["parasite"]);
155 | } else {
156 | webpackJsonp.push([
157 | ["parasite"],
158 | {
159 | parasite: function (o, e, t) {
160 | getStore(t);
161 | },
162 | },
163 | [["parasite"]],
164 | ]);
165 | }
166 | })();
167 | }
168 |
169 | window.WAPI = {
170 | lastRead: {},
171 | };
172 |
173 | window.WAPI._serializeRawObj = (obj) => {
174 | if (obj) {
175 | return obj.toJSON();
176 | }
177 | return {};
178 | };
179 |
180 | /**
181 | * Serializes a chat object
182 | *
183 | * @param rawChat Chat object
184 | * @returns {{}}
185 | */
186 |
187 | window.WAPI._serializeChatObj = (obj) => {
188 | if (obj == undefined) {
189 | return null;
190 | }
191 |
192 | return Object.assign(window.WAPI._serializeRawObj(obj), {
193 | kind: obj.kind,
194 | isGroup: obj.isGroup,
195 | contact: obj["contact"] ? window.WAPI._serializeContactObj(obj["contact"]) : null,
196 | groupMetadata: obj["groupMetadata"] ? window.WAPI._serializeRawObj(obj["groupMetadata"]) : null,
197 | presence: obj["presence"] ? window.WAPI._serializeRawObj(obj["presence"]) : null,
198 | msgs: null,
199 | });
200 | };
201 |
202 | window.WAPI._serializeContactObj = (obj) => {
203 | if (obj == undefined) {
204 | return null;
205 | }
206 |
207 | return Object.assign(window.WAPI._serializeRawObj(obj), {
208 | formattedName: obj.formattedName,
209 | isHighLevelVerified: obj.isHighLevelVerified,
210 | isMe: obj.isMe,
211 | isMyContact: obj.isMyContact,
212 | isPSA: obj.isPSA,
213 | isUser: obj.isUser,
214 | isVerified: obj.isVerified,
215 | isWAContact: obj.isWAContact,
216 | profilePicThumbObj: obj.profilePicThumb ? WAPI._serializeProfilePicThumb(obj.profilePicThumb) : {},
217 | statusMute: obj.statusMute,
218 | msgs: null,
219 | });
220 | };
221 |
222 | window.WAPI._serializeMessageObj = (obj) => {
223 | if (obj == undefined) {
224 | return null;
225 | }
226 |
227 | return Object.assign(window.WAPI._serializeRawObj(obj), {
228 | id: obj.id._serialized,
229 | sender: obj["senderObj"] ? WAPI._serializeContactObj(obj["senderObj"]) : null,
230 | timestamp: obj["t"],
231 | content: obj["body"],
232 | isGroupMsg: obj.isGroupMsg,
233 | isLink: obj.isLink,
234 | isMMS: obj.isMMS,
235 | isMedia: obj.isMedia,
236 | isNotification: obj.isNotification,
237 | isPSA: obj.isPSA,
238 | type: obj.type,
239 | chat: WAPI._serializeChatObj(obj["chat"]),
240 | chatId: obj.id.remote,
241 | quotedMsgObj: WAPI._serializeMessageObj(obj["_quotedMsgObj"]),
242 | mediaData: window.WAPI._serializeRawObj(obj["mediaData"]),
243 | });
244 | };
245 |
246 | window.WAPI._serializeNumberStatusObj = (obj) => {
247 | if (obj == undefined) {
248 | return null;
249 | }
250 |
251 | return Object.assign(
252 | {},
253 | {
254 | id: obj.jid,
255 | status: obj.status,
256 | isBusiness: obj.biz === true,
257 | canReceiveMessage: obj.status === 200,
258 | }
259 | );
260 | };
261 |
262 | window.WAPI._serializeProfilePicThumb = (obj) => {
263 | if (obj == undefined) {
264 | return null;
265 | }
266 |
267 | return Object.assign(
268 | {},
269 | {
270 | eurl: obj.eurl,
271 | id: obj.id,
272 | img: obj.img,
273 | imgFull: obj.imgFull,
274 | raw: obj.raw,
275 | tag: obj.tag,
276 | }
277 | );
278 | };
279 |
280 | /**
281 | * Fetches chat object from store by ID
282 | *
283 | * @param id ID of chat
284 | * @returns {T|*} Chat object
285 | */
286 | window.WAPI.getChat = function (id) {
287 | id = typeof id == "string" ? id : id._serialized;
288 | const found = window.Store.Chat.get(id);
289 | found.sendMessage = found.sendMessage
290 | ? found.sendMessage
291 | : function () {
292 | return window.Store.sendMessage.apply(this, arguments);
293 | };
294 | return found;
295 | };
296 |
297 | /**
298 | * Fetches all chat IDs from store
299 | *
300 | * @returns {Array|*} List of chat id's
301 | */
302 | window.WAPI.getAllChatIds = function () {
303 | const chatIds = window.Store.Chat.map((chat) => chat.id._serialized || chat.id);
304 | return chatIds;
305 | };
306 |
307 | window.WAPI.processMessageObj = function (messageObj, includeMe, includeNotifications) {
308 | if (messageObj.isNotification) {
309 | if (includeNotifications) return WAPI._serializeMessageObj(messageObj);
310 | else return;
311 | // System message
312 | // (i.e. "Messages you send to this chat and calls are now secured with end-to-end encryption...")
313 | } else if (messageObj.id.fromMe === false || includeMe) {
314 | return WAPI._serializeMessageObj(messageObj);
315 | }
316 | return;
317 | };
318 |
319 | window.WAPI.sendImage = async function (imgBase64, chatid, filename, caption) {
320 | let id = chatid;
321 | if (!window.WAPI.getAllChatIds().find((chat) => chat == chatid))
322 | id = new window.Store.UserConstructor(chatid, { intentionallyUsePrivateConstructor: true });
323 | var chat = WAPI.getChat(id);
324 | // Ignore Group Chat
325 | if (WAPI._serializeChatObj(chat).isGroup && window.WappBot.configWappBot.ignoreGroupChat) return;
326 | // create new chat
327 | try {
328 | var mediaBlob = await window.WAPI.base64ImageToFile(imgBase64, filename);
329 | var mc = new Store.MediaCollection(chat);
330 | mc.processFiles([mediaBlob], chat, 1).then(() => {
331 | var media = mc.models[0];
332 | media.sendToChat(chat, { caption: caption });
333 | });
334 | } catch (error) {
335 | if (window.Store.Chat.length === 0) return false;
336 |
337 | let firstChat = Store.Chat.models[0];
338 | let originalID = firstChat.id;
339 | firstChat.id =
340 | typeof originalID === "string"
341 | ? id
342 | : new window.Store.UserConstructor(id, { intentionallyUsePrivateConstructor: true });
343 | let mediaBlob = await window.WAPI.base64ImageToFile(imgBase64, filename);
344 | var mc = new Store.MediaCollection(chat);
345 | chat = WAPI.getChat(id);
346 | mc.processAttachments([{ file: mediaBlob }, 1], chat, 1).then(() => {
347 | let media = mc.models[0];
348 | media.sendToChat(chat, { caption: caption });
349 | });
350 | return true;
351 | }
352 | };
353 |
354 | window.WAPI.base64ImageToFile = function (image, filename) {
355 | return new Promise(async (resolve) => {
356 | if (!image.includes("base64")) {
357 | image = await window.WappBot.toDataURL("https://cors-anywhere.herokuapp.com/" + image); // convert url in base64
358 | }
359 | var arr = image.split(","),
360 | mime = arr[0].match(/:(.*?);/)[1],
361 | bstr = atob(arr[1]),
362 | n = bstr.length,
363 | u8arr = new Uint8Array(n);
364 | while (n--) {
365 | u8arr[n] = bstr.charCodeAt(n);
366 | }
367 | resolve(new File([u8arr], filename, { type: mime }));
368 | });
369 | };
370 |
371 | window.WAPI.sendMessage = function (idChat, message) {
372 | let id = idChat;
373 | if (!window.WAPI.getAllChatIds().find((chat) => chat == idChat))
374 | id = new window.Store.UserConstructor(idChat, { intentionallyUsePrivateConstructor: true });
375 | var chat = WAPI.getChat(id);
376 | if (WAPI._serializeChatObj(chat).isGroup && window.WappBot.configWappBot.ignoreGroupChat) return;
377 | try {
378 | // create new chat
379 | return chat.sendMessage(message);
380 | } catch (e) {
381 | if (window.Store.Chat.length === 0) return false;
382 |
383 | firstChat = Store.Chat.models[0];
384 | var originalID = firstChat.id;
385 | firstChat.id =
386 | typeof originalID === "string"
387 | ? id
388 | : new window.Store.UserConstructor(id, { intentionallyUsePrivateConstructor: true });
389 | var chat = WAPI.getChat(firstChat.id);
390 | chat.sendMessage(message);
391 | return true;
392 | }
393 | };
394 |
395 | window.WappBot.toDataURL = (url) => {
396 | return new Promise((resolve) => {
397 | var xhr = new XMLHttpRequest();
398 | xhr.onload = function () {
399 | var reader = new FileReader();
400 | reader.onloadend = function () {
401 | resolve(reader.result);
402 | };
403 | reader.readAsDataURL(xhr.response);
404 | };
405 | xhr.open("GET", url);
406 | xhr.responseType = "blob";
407 | xhr.send();
408 | });
409 | };
410 |
411 | window.WappBot.sendByAPIWappBot = (newMessage, chatId) => {
412 | fetch(window.WappBot.configWappBot.uriApi, {
413 | method: "POST",
414 | headers: {
415 | Accept: "application/json",
416 | "Content-Type": "application/json",
417 | },
418 | body: JSON.stringify({ messageText: newMessage }),
419 | }).then(function (response) {
420 | response.json().then((post) => {
421 | if (!post && !post.messageResponse) return;
422 | window.WAPI.sendMessage(chatId, post.messageResponse);
423 | });
424 | });
425 | };
426 |
427 | window.WappBot.messageIncludeKey = (message, options) => {
428 | for (let i = 0; i < options.length; i++) {
429 | if (message.toUpperCase().includes(options[i].toUpperCase()))
430 | return window.WappBot.configWappBot.messageOption[options[i]];
431 | }
432 | return false;
433 | };
434 |
435 | window.WappBot.prepareMessageToSend = (chatId, options) => {
436 | let message = "";
437 | if (window.WappBot.configWappBot.ignoreChat.indexOf(chatId) > -1) {
438 | message = `${window.WappBot.configWappBot.messageIncorrect}`;
439 | } else {
440 | message = `${window.WappBot.configWappBot.messageInitial.text}`;
441 | window.WappBot.configWappBot.ignoreChat.push(chatId);
442 | }
443 | for (let i = 0; i < options.length; i++) message += `\t ${options[i]} \n`;
444 |
445 | return message;
446 | };
447 |
448 | window.WappBot.sendByLocalSetting = (newMessage, chatId) => {
449 | const options = Object.keys(window.WappBot.configWappBot.messageOption);
450 | const messageIncludeKey = window.WappBot.messageIncludeKey(newMessage, options);
451 | if (!messageIncludeKey) {
452 | const message = window.WappBot.prepareMessageToSend(chatId, options);
453 | if (!window.WappBot.configWappBot.messageInitial.image) window.WAPI.sendMessage(chatId, message);
454 | else window.WAPI.sendImage(window.WappBot.configWappBot.messageInitial.image, chatId, "image", message);
455 | } else {
456 | if (!messageIncludeKey.image) window.WAPI.sendMessage(chatId, messageIncludeKey.text);
457 | else window.WAPI.sendImage(messageIncludeKey.image, chatId, "image", messageIncludeKey.text);
458 | }
459 | };
460 |
461 | /**
462 | * New messages observable functions.
463 | */
464 | window.WAPI._newMessagesQueue = [];
465 | window.WAPI._newMessagesBuffer =
466 | sessionStorage.getItem("saved_msgs") != null ? JSON.parse(sessionStorage.getItem("saved_msgs")) : [];
467 | window.WAPI._newMessagesDebouncer = null;
468 | window.WAPI._newMessagesCallbacks = [];
469 |
470 | window.Store.Msg.off("add");
471 | sessionStorage.removeItem("saved_msgs");
472 |
473 | window.WAPI._newMessagesListener = window.Store.Msg.on("add", (newMessage) => {
474 | if (newMessage && newMessage.isNewMsg && !newMessage.isSentByMe) {
475 | let message = window.WAPI.processMessageObj(newMessage, false, false);
476 | if (message) {
477 | if (window.WappBot.configWappBot.useApi)
478 | window.WappBot.sendByAPIWappBot(message.body, message.chatId._serialized);
479 | else window.WappBot.sendByLocalSetting(message.body, message.chatId._serialized);
480 | }
481 | }
482 | });
483 |
484 | window.WAPI._unloadInform = (event) => {
485 | // Save in the buffer the ungot unreaded messages
486 | window.WAPI._newMessagesBuffer.forEach((message) => {
487 | Object.keys(message).forEach((key) => (message[key] === undefined ? delete message[key] : ""));
488 | });
489 | sessionStorage.setItem("saved_msgs", JSON.stringify(window.WAPI._newMessagesBuffer));
490 |
491 | // Inform callbacks that the page will be reloaded.
492 | window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) {
493 | if (callbackObj.callback !== undefined) {
494 | callbackObj.callback({ status: -1, message: "page will be reloaded, wait and register callback again." });
495 | }
496 | });
497 | };
498 |
499 | window.addEventListener("unload", window.WAPI._unloadInform, false);
500 | window.addEventListener("beforeunload", window.WAPI._unloadInform, false);
501 | window.addEventListener("pageunload", window.WAPI._unloadInform, false);
502 |
--------------------------------------------------------------------------------
/newFullMethodWapi.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This script contains WAPI functions that need to be run in the context of the webpage
3 | */
4 |
5 | /**
6 | * Auto discovery the webpack object references of instances that contains all functions used by the WAPI
7 | * functions and creates the Store object.
8 | */
9 | if (!window.Store) {
10 | (function () {
11 | function getStore(modules) {
12 | let foundCount = 0;
13 | let neededObjects = [
14 | { id: "Store", conditions: (module) => (module.default && module.default.Chat && module.default.Msg) ? module.default : null },
15 | { id: "MediaCollection", conditions: (module) => (module.default && module.default.prototype && module.default.prototype.processAttachments) ? module.default : null },
16 | { id: "MediaProcess", conditions: (module) => (module.BLOB) ? module : null },
17 | { id: "Wap", conditions: (module) => (module.createGroup) ? module : null },
18 | { id: "ServiceWorker", conditions: (module) => (module.default && module.default.killServiceWorker) ? module : null },
19 | { id: "State", conditions: (module) => (module.STATE && module.STREAM) ? module : null },
20 | { id: "WapDelete", conditions: (module) => (module.sendConversationDelete && module.sendConversationDelete.length == 2) ? module : null },
21 | { id: "Conn", conditions: (module) => (module.default && module.default.ref && module.default.refTTL) ? module.default : null },
22 | { id: "WapQuery", conditions: (module) => (module.queryExist) ? module : ((module.default && module.default.queryExist) ? module.default : null) },
23 | { id: "CryptoLib", conditions: (module) => (module.decryptE2EMedia) ? module : null },
24 | { id: "OpenChat", conditions: (module) => (module.default && module.default.prototype && module.default.prototype.openChat) ? module.default : null },
25 | { id: "UserConstructor", conditions: (module) => (module.default && module.default.prototype && module.default.prototype.isServer && module.default.prototype.isUser) ? module.default : null },
26 | { id: "SendTextMsgToChat", conditions: (module) => (module.sendTextMsgToChat) ? module.sendTextMsgToChat : null },
27 | { id: "SendSeen", conditions: (module) => (module.sendSeen) ? module.sendSeen : null },
28 | { id: "sendDelete", conditions: (module) => (module.sendDelete) ? module.sendDelete : null }
29 | ];
30 | for (let idx in modules) {
31 | if ((typeof modules[idx] === "object") && (modules[idx] !== null)) {
32 | let first = Object.values(modules[idx])[0];
33 | if ((typeof first === "object") && (first.exports)) {
34 | for (let idx2 in modules[idx]) {
35 | let module = modules(idx2);
36 | if (!module) {
37 | continue;
38 | }
39 | neededObjects.forEach((needObj) => {
40 | if (!needObj.conditions || needObj.foundedModule)
41 | return;
42 | let neededModule = needObj.conditions(module);
43 | if (neededModule !== null) {
44 | foundCount++;
45 | needObj.foundedModule = neededModule;
46 | }
47 | });
48 | if (foundCount == neededObjects.length) {
49 | break;
50 | }
51 | }
52 |
53 | let neededStore = neededObjects.find((needObj) => needObj.id === "Store");
54 | window.Store = neededStore.foundedModule ? neededStore.foundedModule : {};
55 | neededObjects.splice(neededObjects.indexOf(neededStore), 1);
56 | neededObjects.forEach((needObj) => {
57 | if (needObj.foundedModule) {
58 | window.Store[needObj.id] = needObj.foundedModule;
59 | }
60 | });
61 | window.Store.sendMessage = function (e) {
62 | return window.Store.SendTextMsgToChat(this, ...arguments);
63 | };
64 | return window.Store;
65 | }
66 | }
67 | }
68 | }
69 |
70 | if (typeof webpackJsonp === 'function') {
71 | webpackJsonp([], {'parasite': (x, y, z) => getStore(z)}, ['parasite']);
72 | } else {
73 | webpackJsonp.push([
74 | ['parasite'],
75 | {
76 | parasite: function (o, e, t) {
77 | getStore(t);
78 | }
79 | },
80 | [['parasite']]
81 | ]);
82 | }
83 |
84 | })();
85 | }
86 |
87 | window.WAPI = {
88 | lastRead: {}
89 | };
90 |
91 | window.WAPI._serializeRawObj = (obj) => {
92 | if (obj) {
93 | return obj.toJSON();
94 | }
95 | return {}
96 | };
97 |
98 | /**
99 | * Serializes a chat object
100 | *
101 | * @param rawChat Chat object
102 | * @returns {{}}
103 | */
104 |
105 | window.WAPI._serializeChatObj = (obj) => {
106 | if (obj == undefined) {
107 | return null;
108 | }
109 |
110 | return Object.assign(window.WAPI._serializeRawObj(obj), {
111 | kind : obj.kind,
112 | isGroup : obj.isGroup,
113 | contact : obj['contact'] ? window.WAPI._serializeContactObj(obj['contact']) : null,
114 | groupMetadata: obj["groupMetadata"] ? window.WAPI._serializeRawObj(obj["groupMetadata"]): null,
115 | presence : obj["presence"] ? window.WAPI._serializeRawObj(obj["presence"]) : null,
116 | msgs : null
117 | });
118 | };
119 |
120 | window.WAPI._serializeContactObj = (obj) => {
121 | if (obj == undefined) {
122 | return null;
123 | }
124 |
125 | return Object.assign(window.WAPI._serializeRawObj(obj), {
126 | formattedName : obj.formattedName,
127 | isHighLevelVerified: obj.isHighLevelVerified,
128 | isMe : obj.isMe,
129 | isMyContact : obj.isMyContact,
130 | isPSA : obj.isPSA,
131 | isUser : obj.isUser,
132 | isVerified : obj.isVerified,
133 | isWAContact : obj.isWAContact,
134 | profilePicThumbObj : obj.profilePicThumb ? WAPI._serializeProfilePicThumb(obj.profilePicThumb): {},
135 | statusMute : obj.statusMute,
136 | msgs : null
137 | });
138 | };
139 |
140 | window.WAPI._serializeMessageObj = (obj) => {
141 | if (obj == undefined) {
142 | return null;
143 | }
144 |
145 | return Object.assign(window.WAPI._serializeRawObj(obj), {
146 | id : obj.id._serialized,
147 | sender : obj["senderObj"] ? WAPI._serializeContactObj(obj["senderObj"]): null,
148 | timestamp : obj["t"],
149 | content : obj["body"],
150 | isGroupMsg : obj.isGroupMsg,
151 | isLink : obj.isLink,
152 | isMMS : obj.isMMS,
153 | isMedia : obj.isMedia,
154 | isNotification: obj.isNotification,
155 | isPSA : obj.isPSA,
156 | type : obj.type,
157 | chat : WAPI._serializeChatObj(obj['chat']),
158 | chatId : obj.id.remote,
159 | quotedMsgObj : WAPI._serializeMessageObj(obj['_quotedMsgObj']),
160 | mediaData : window.WAPI._serializeRawObj(obj['mediaData'])
161 | });
162 | };
163 |
164 | window.WAPI._serializeNumberStatusObj = (obj) => {
165 | if (obj == undefined) {
166 | return null;
167 | }
168 |
169 | return Object.assign({}, {
170 | id : obj.jid,
171 | status : obj.status,
172 | isBusiness : (obj.biz === true),
173 | canReceiveMessage: (obj.status === 200)
174 | });
175 | };
176 |
177 | window.WAPI._serializeProfilePicThumb = (obj) => {
178 | if (obj == undefined) {
179 | return null;
180 | }
181 |
182 | return Object.assign({}, {
183 | eurl : obj.eurl,
184 | id : obj.id,
185 | img : obj.img,
186 | imgFull: obj.imgFull,
187 | raw : obj.raw,
188 | tag : obj.tag
189 | });
190 | }
191 |
192 | window.WAPI.createGroup = function (name, contactsId) {
193 | if (!Array.isArray(contactsId)) {
194 | contactsId = [contactsId];
195 | }
196 |
197 | return window.Store.Wap.createGroup(name, contactsId);
198 | };
199 |
200 | window.WAPI.leaveGroup = function (groupId) {
201 | groupId = typeof groupId == "string" ? groupId : groupId._serialized;
202 | var group = WAPI.getChat(groupId);
203 | return group.sendExit()
204 | };
205 |
206 |
207 | window.WAPI.getAllContacts = function (done) {
208 | const contacts = window.Store.Contact.map((contact) => WAPI._serializeContactObj(contact));
209 |
210 | if (done !== undefined) done(contacts);
211 | return contacts;
212 | };
213 |
214 | /**
215 | * Fetches all contact objects from store, filters them
216 | *
217 | * @param done Optional callback function for async execution
218 | * @returns {Array|*} List of contacts
219 | */
220 | window.WAPI.getMyContacts = function (done) {
221 | const contacts = window.Store.Contact.filter((contact) => contact.isMyContact === true).map((contact) => WAPI._serializeContactObj(contact));
222 | if (done !== undefined) done(contacts);
223 | return contacts;
224 | };
225 |
226 | /**
227 | * Fetches contact object from store by ID
228 | *
229 | * @param id ID of contact
230 | * @param done Optional callback function for async execution
231 | * @returns {T|*} Contact object
232 | */
233 | window.WAPI.getContact = function (id, done) {
234 | const found = window.Store.Contact.get(id);
235 |
236 | if (done !== undefined) done(window.WAPI._serializeContactObj(found))
237 | return window.WAPI._serializeContactObj(found);
238 | };
239 |
240 | /**
241 | * Fetches all chat objects from store
242 | *
243 | * @param done Optional callback function for async execution
244 | * @returns {Array|*} List of chats
245 | */
246 | window.WAPI.getAllChats = function (done) {
247 | const chats = window.Store.Chat.map((chat) => WAPI._serializeChatObj(chat));
248 |
249 | if (done !== undefined) done(chats);
250 | return chats;
251 | };
252 |
253 | window.WAPI.haveNewMsg = function (chat) {
254 | return chat.unreadCount > 0;
255 | };
256 |
257 | window.WAPI.getAllChatsWithNewMsg = function (done) {
258 | const chats = window.Store.Chat.filter(window.WAPI.haveNewMsg).map((chat) => WAPI._serializeChatObj(chat));
259 |
260 | if (done !== undefined) done(chats);
261 | return chats;
262 | };
263 |
264 | /**
265 | * Fetches all chat IDs from store
266 | *
267 | * @param done Optional callback function for async execution
268 | * @returns {Array|*} List of chat id's
269 | */
270 | window.WAPI.getAllChatIds = function (done) {
271 | const chatIds = window.Store.Chat.map((chat) => chat.id._serialized || chat.id);
272 |
273 | if (done !== undefined) done(chatIds);
274 | return chatIds;
275 | };
276 |
277 | /**
278 | * Fetches all groups objects from store
279 | *
280 | * @param done Optional callback function for async execution
281 | * @returns {Array|*} List of chats
282 | */
283 | window.WAPI.getAllGroups = function (done) {
284 | const groups = window.Store.Chat.filter((chat) => chat.isGroup);
285 |
286 | if (done !== undefined) done(groups);
287 | return groups;
288 | };
289 |
290 | /**
291 | * Fetches chat object from store by ID
292 | *
293 | * @param id ID of chat
294 | * @param done Optional callback function for async execution
295 | * @returns {T|*} Chat object
296 | */
297 | window.WAPI.getChat = function (id, done) {
298 | id = typeof id == "string" ? id : id._serialized;
299 | const found = window.Store.Chat.get(id);
300 | found.sendMessage = (found.sendMessage) ? found.sendMessage : function () { return window.Store.sendMessage.apply(this, arguments); };
301 | if (done !== undefined) done(found);
302 | return found;
303 | }
304 |
305 | window.WAPI.getChatByName = function (name, done) {
306 | const found = window.WAPI.getAllChats().find(val => val.name.includes(name))
307 | if (done !== undefined) done(found);
308 | return found;
309 | };
310 |
311 | window.WAPI.sendImageFromDatabasePicBot = function (picId, chatId, caption) {
312 | var chatDatabase = window.WAPI.getChatByName('DATABASEPICBOT');
313 | var msgWithImg = chatDatabase.msgs.find((msg) => msg.caption == picId);
314 |
315 | if (msgWithImg === undefined) {
316 | return false;
317 | }
318 | var chatSend = WAPI.getChat(chatId);
319 | if (chatSend === undefined) {
320 | return false;
321 | }
322 | const oldCaption = msgWithImg.caption;
323 |
324 | msgWithImg.id.id = window.WAPI.getNewId();
325 | msgWithImg.id.remote = chatId;
326 | msgWithImg.t = Math.ceil(new Date().getTime() / 1000);
327 | msgWithImg.to = chatId;
328 |
329 | if (caption !== undefined && caption !== '') {
330 | msgWithImg.caption = caption;
331 | } else {
332 | msgWithImg.caption = '';
333 | }
334 |
335 | msgWithImg.collection.send(msgWithImg).then(function (e) {
336 | msgWithImg.caption = oldCaption;
337 | });
338 |
339 | return true;
340 | };
341 |
342 | window.WAPI.sendMessageWithThumb = function (thumb, url, title, description, text, chatId, done) {
343 | var chatSend = WAPI.getChat(chatId);
344 | if (chatSend === undefined) {
345 | if (done !== undefined) done(false);
346 | return false;
347 | }
348 | var linkPreview = {
349 | canonicalUrl: url,
350 | description : description,
351 | matchedText : url,
352 | title : title,
353 | thumbnail : thumb,
354 | compose: true
355 | };
356 | chatSend.sendMessage(text, { linkPreview: linkPreview,
357 | mentionedJidList: [],
358 | quotedMsg: null,
359 | quotedMsgAdminGroupJid: null });
360 | if (done !== undefined) done(true);
361 | return true;
362 | };
363 |
364 | window.WAPI.getNewId = function () {
365 | var text = "";
366 | var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
367 |
368 | for (var i = 0; i < 20; i++)
369 | text += possible.charAt(Math.floor(Math.random() * possible.length));
370 | return text;
371 | };
372 |
373 | window.WAPI.getChatById = function (id, done) {
374 | let found = WAPI.getChat(id);
375 | if (found) {
376 | found = WAPI._serializeChatObj(found);
377 | } else {
378 | found = false;
379 | }
380 |
381 | if (done !== undefined) done(found);
382 | return found;
383 | };
384 |
385 |
386 | /**
387 | * I return all unread messages from an asked chat and mark them as read.
388 | *
389 | * :param id: chat id
390 | * :type id: string
391 | *
392 | * :param includeMe: indicates if user messages have to be included
393 | * :type includeMe: boolean
394 | *
395 | * :param includeNotifications: indicates if notifications have to be included
396 | * :type includeNotifications: boolean
397 | *
398 | * :param done: callback passed by selenium
399 | * :type done: function
400 | *
401 | * :returns: list of unread messages from asked chat
402 | * :rtype: object
403 | */
404 | window.WAPI.getUnreadMessagesInChat = function (id, includeMe, includeNotifications, done) {
405 | // get chat and its messages
406 | let chat = WAPI.getChat(id);
407 | let messages = chat.msgs._models;
408 |
409 | // initialize result list
410 | let output = [];
411 |
412 | // look for unread messages, newest is at the end of array
413 | for (let i = messages.length - 1; i >= 0; i--) {
414 | // system message: skip it
415 | if (i === "remove") {
416 | continue;
417 | }
418 |
419 | // get message
420 | let messageObj = messages[i];
421 |
422 | // found a read message: stop looking for others
423 | if (typeof (messageObj.isNewMsg) !== "boolean" || messageObj.isNewMsg === false) {
424 | continue;
425 | } else {
426 | messageObj.isNewMsg = false;
427 | // process it
428 | let message = WAPI.processMessageObj(messageObj,
429 | includeMe,
430 | includeNotifications);
431 |
432 | // save processed message on result list
433 | if (message)
434 | output.push(message);
435 | }
436 | }
437 | // callback was passed: run it
438 | if (done !== undefined) done(output);
439 | // return result list
440 | return output;
441 | }
442 | ;
443 |
444 |
445 | /**
446 | * Load more messages in chat object from store by ID
447 | *
448 | * @param id ID of chat
449 | * @param done Optional callback function for async execution
450 | * @returns None
451 | */
452 | window.WAPI.loadEarlierMessages = function (id, done) {
453 | const found = WAPI.getChat(id);
454 | if (done !== undefined) {
455 | found.loadEarlierMsgs().then(function () {
456 | done()
457 | });
458 | } else {
459 | found.loadEarlierMsgs();
460 | }
461 | };
462 |
463 | /**
464 | * Load more messages in chat object from store by ID
465 | *
466 | * @param id ID of chat
467 | * @param done Optional callback function for async execution
468 | * @returns None
469 | */
470 | window.WAPI.loadAllEarlierMessages = function (id, done) {
471 | const found = WAPI.getChat(id);
472 | x = function () {
473 | if (!found.msgs.msgLoadState.noEarlierMsgs) {
474 | found.loadEarlierMsgs().then(x);
475 | } else if (done) {
476 | done();
477 | }
478 | };
479 | x();
480 | };
481 |
482 | window.WAPI.asyncLoadAllEarlierMessages = function (id, done) {
483 | done();
484 | window.WAPI.loadAllEarlierMessages(id);
485 | };
486 |
487 | window.WAPI.areAllMessagesLoaded = function (id, done) {
488 | const found = WAPI.getChat(id);
489 | if (!found.msgs.msgLoadState.noEarlierMsgs) {
490 | if (done) done(false);
491 | return false
492 | }
493 | if (done) done(true);
494 | return true
495 | };
496 |
497 | /**
498 | * Load more messages in chat object from store by ID till a particular date
499 | *
500 | * @param id ID of chat
501 | * @param lastMessage UTC timestamp of last message to be loaded
502 | * @param done Optional callback function for async execution
503 | * @returns None
504 | */
505 |
506 | window.WAPI.loadEarlierMessagesTillDate = function (id, lastMessage, done) {
507 | const found = WAPI.getChat(id);
508 | x = function () {
509 | if (found.msgs.models[0].t > lastMessage && !found.msgs.msgLoadState.noEarlierMsgs) {
510 | found.loadEarlierMsgs().then(x);
511 | } else {
512 | done();
513 | }
514 | };
515 | x();
516 | };
517 |
518 |
519 | /**
520 | * Fetches all group metadata objects from store
521 | *
522 | * @param done Optional callback function for async execution
523 | * @returns {Array|*} List of group metadata
524 | */
525 | window.WAPI.getAllGroupMetadata = function (done) {
526 | const groupData = window.Store.GroupMetadata.map((groupData) => groupData.all);
527 |
528 | if (done !== undefined) done(groupData);
529 | return groupData;
530 | };
531 |
532 | /**
533 | * Fetches group metadata object from store by ID
534 | *
535 | * @param id ID of group
536 | * @param done Optional callback function for async execution
537 | * @returns {T|*} Group metadata object
538 | */
539 | window.WAPI.getGroupMetadata = async function (id, done) {
540 | let output = window.Store.GroupMetadata.get(id);
541 |
542 | if (output !== undefined) {
543 | if (output.stale) {
544 | await output.update();
545 | }
546 | }
547 |
548 | if (done !== undefined) done(output);
549 | return output;
550 |
551 | };
552 |
553 |
554 | /**
555 | * Fetches group participants
556 | *
557 | * @param id ID of group
558 | * @returns {Promise.<*>} Yields group metadata
559 | * @private
560 | */
561 | window.WAPI._getGroupParticipants = async function (id) {
562 | const metadata = await WAPI.getGroupMetadata(id);
563 | return metadata.participants;
564 | };
565 |
566 | /**
567 | * Fetches IDs of group participants
568 | *
569 | * @param id ID of group
570 | * @param done Optional callback function for async execution
571 | * @returns {Promise.} Yields list of IDs
572 | */
573 | window.WAPI.getGroupParticipantIDs = async function (id, done) {
574 | const output = (await WAPI._getGroupParticipants(id))
575 | .map((participant) => participant.id);
576 |
577 | if (done !== undefined) done(output);
578 | return output;
579 | };
580 |
581 | window.WAPI.getGroupAdmins = async function (id, done) {
582 | const output = (await WAPI._getGroupParticipants(id))
583 | .filter((participant) => participant.isAdmin)
584 | .map((admin) => admin.id);
585 |
586 | if (done !== undefined) done(output);
587 | return output;
588 | };
589 |
590 | /**
591 | * Gets object representing the logged in user
592 | *
593 | * @returns {Array|*|$q.all}
594 | */
595 | window.WAPI.getMe = function (done) {
596 | const rawMe = window.Store.Contact.get(window.Store.Conn.me);
597 |
598 | if (done !== undefined) done(rawMe.all);
599 | return rawMe.all;
600 | };
601 |
602 | window.WAPI.isLoggedIn = function (done) {
603 | // Contact always exists when logged in
604 | const isLogged = window.Store.Contact && window.Store.Contact.checksum !== undefined;
605 |
606 | if (done !== undefined) done(isLogged);
607 | return isLogged;
608 | };
609 |
610 | window.WAPI.isConnected = function (done) {
611 | // Phone Disconnected icon appears when phone is disconnected from the tnternet
612 | const isConnected = document.querySelector('*[data-icon="alert-phone"]') !== null ? false : true;
613 |
614 | if (done !== undefined) done(isConnected);
615 | return isConnected;
616 | };
617 |
618 | window.WAPI.processMessageObj = function (messageObj, includeMe, includeNotifications) {
619 | if (messageObj.isNotification) {
620 | if (includeNotifications)
621 | return WAPI._serializeMessageObj(messageObj);
622 | else
623 | return;
624 | // System message
625 | // (i.e. "Messages you send to this chat and calls are now secured with end-to-end encryption...")
626 | } else if (messageObj.id.fromMe === false || includeMe) {
627 | return WAPI._serializeMessageObj(messageObj);
628 | }
629 | return;
630 | };
631 |
632 | window.WAPI.getAllMessagesInChat = function (id, includeMe, includeNotifications, done) {
633 | const chat = WAPI.getChat(id);
634 | let output = [];
635 | const messages = chat.msgs._models;
636 |
637 | for (const i in messages) {
638 | if (i === "remove") {
639 | continue;
640 | }
641 | const messageObj = messages[i];
642 |
643 | let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications)
644 | if (message)
645 | output.push(message);
646 | }
647 | if (done !== undefined) done(output);
648 | return output;
649 | };
650 |
651 | window.WAPI.getAllMessageIdsInChat = function (id, includeMe, includeNotifications, done) {
652 | const chat = WAPI.getChat(id);
653 | let output = [];
654 | const messages = chat.msgs._models;
655 |
656 | for (const i in messages) {
657 | if ((i === "remove")
658 | || (!includeMe && messages[i].isMe)
659 | || (!includeNotifications && messages[i].isNotification)) {
660 | continue;
661 | }
662 | output.push(messages[i].id._serialized);
663 | }
664 | if (done !== undefined) done(output);
665 | return output;
666 | };
667 |
668 | window.WAPI.getMessageById = function (id, done) {
669 | let result = false;
670 | try {
671 | let msg = window.Store.Msg.get(id);
672 | if (msg) {
673 | result = WAPI.processMessageObj(msg, true, true);
674 | }
675 | } catch (err) { }
676 |
677 | if (done !== undefined) {
678 | done(result);
679 | } else {
680 | return result;
681 | }
682 | };
683 |
684 | window.WAPI.ReplyMessage = function (idMessage, message, done) {
685 | var messageObject = window.Store.Msg.get(idMessage);
686 | if (messageObject === undefined) {
687 | if (done !== undefined) done(false);
688 | return false;
689 | }
690 | messageObject = messageObject.value();
691 |
692 | const chat = WAPI.getChat(messageObject.chat.id)
693 | if (chat !== undefined) {
694 | if (done !== undefined) {
695 | chat.sendMessage(message, null, messageObject).then(function () {
696 | function sleep(ms) {
697 | return new Promise(resolve => setTimeout(resolve, ms));
698 | }
699 |
700 | var trials = 0;
701 |
702 | function check() {
703 | for (let i = chat.msgs.models.length - 1; i >= 0; i--) {
704 | let msg = chat.msgs.models[i];
705 |
706 | if (!msg.senderObj.isMe || msg.body != message) {
707 | continue;
708 | }
709 | done(WAPI._serializeMessageObj(msg));
710 | return True;
711 | }
712 | trials += 1;
713 | console.log(trials);
714 | if (trials > 30) {
715 | done(true);
716 | return;
717 | }
718 | sleep(500).then(check);
719 | }
720 | check();
721 | });
722 | return true;
723 | } else {
724 | chat.sendMessage(message, null, messageObject);
725 | return true;
726 | }
727 | } else {
728 | if (done !== undefined) done(false);
729 | return false;
730 | }
731 | };
732 |
733 | window.WAPI.sendMessageToID = function (id, message, done) {
734 | try {
735 | window.getContact = (id) => {
736 | return Store.WapQuery.queryExist(id);
737 | }
738 | window.getContact(id).then(contact => {
739 | if (contact.status === 404) {
740 | done(true);
741 | } else {
742 | Store.Chat.find(contact.jid).then(chat => {
743 | chat.sendMessage(message);
744 | return true;
745 | }).catch(reject => {
746 | if (WAPI.sendMessage(id, message)) {
747 | done(true);
748 | return true;
749 | }else{
750 | done(false);
751 | return false;
752 | }
753 | });
754 | }
755 | });
756 | } catch (e) {
757 | if (window.Store.Chat.length === 0)
758 | return false;
759 |
760 | firstChat = Store.Chat.models[0];
761 | var originalID = firstChat.id;
762 | firstChat.id = typeof originalID === "string" ? id : new window.Store.UserConstructor(id, { intentionallyUsePrivateConstructor: true });
763 | if (done !== undefined) {
764 | firstChat.sendMessage(message).then(function () {
765 | firstChat.id = originalID;
766 | done(true);
767 | });
768 | return true;
769 | } else {
770 | firstChat.sendMessage(message);
771 | firstChat.id = originalID;
772 | return true;
773 | }
774 | }
775 | if (done !== undefined) done(false);
776 | return false;
777 | }
778 |
779 | window.WAPI.sendMessage = function (id, message, done) {
780 | var chat = WAPI.getChat(id);
781 | if (chat !== undefined) {
782 | if (done !== undefined) {
783 | chat.sendMessage(message).then(function () {
784 | function sleep(ms) {
785 | return new Promise(resolve => setTimeout(resolve, ms));
786 | }
787 |
788 | var trials = 0;
789 |
790 | function check() {
791 | for (let i = chat.msgs.models.length - 1; i >= 0; i--) {
792 | let msg = chat.msgs.models[i];
793 |
794 | if (!msg.senderObj.isMe || msg.body != message) {
795 | continue;
796 | }
797 | done(WAPI._serializeMessageObj(msg));
798 | return True;
799 | }
800 | trials += 1;
801 | console.log(trials);
802 | if (trials > 30) {
803 | done(true);
804 | return;
805 | }
806 | sleep(500).then(check);
807 | }
808 | check();
809 | });
810 | return true;
811 | } else {
812 | chat.sendMessage(message);
813 | return true;
814 | }
815 | } else {
816 | if (done !== undefined) done(false);
817 | return false;
818 | }
819 | };
820 |
821 | window.WAPI.sendMessage2 = function (id, message, done) {
822 | var chat = WAPI.getChat(id);
823 | if (chat !== undefined) {
824 | try {
825 | if (done !== undefined) {
826 | chat.sendMessage(message).then(function () {
827 | done(true);
828 | });
829 | } else {
830 | chat.sendMessage(message);
831 | }
832 | return true;
833 | } catch (error) {
834 | if (done !== undefined) done(false)
835 | return false;
836 | }
837 | }
838 | if (done !== undefined) done(false)
839 | return false;
840 | };
841 |
842 | window.WAPI.sendSeen = function (id, done) {
843 | var chat = window.WAPI.getChat(id);
844 | if (chat !== undefined) {
845 | if (done !== undefined) {
846 | if (chat.getLastMsgKeyForAction === undefined)
847 | chat.getLastMsgKeyForAction = function () { };
848 | Store.SendSeen(chat, false).then(function () {
849 | done(true);
850 | });
851 | return true;
852 | } else {
853 | Store.SendSeen(chat, false);
854 | return true;
855 | }
856 | }
857 | if (done !== undefined) done();
858 | return false;
859 | };
860 |
861 | function isChatMessage(message) {
862 | if (message.isSentByMe) {
863 | return false;
864 | }
865 | if (message.isNotification) {
866 | return false;
867 | }
868 | if (!message.isUserCreatedType) {
869 | return false;
870 | }
871 | return true;
872 | }
873 |
874 |
875 | window.WAPI.getUnreadMessages = function (includeMe, includeNotifications, use_unread_count, done) {
876 | const chats = window.Store.Chat.models;
877 | let output = [];
878 |
879 | for (let chat in chats) {
880 | if (isNaN(chat)) {
881 | continue;
882 | }
883 |
884 | let messageGroupObj = chats[chat];
885 | let messageGroup = WAPI._serializeChatObj(messageGroupObj);
886 |
887 | messageGroup.messages = [];
888 |
889 | const messages = messageGroupObj.msgs._models;
890 | for (let i = messages.length - 1; i >= 0; i--) {
891 | let messageObj = messages[i];
892 | if (typeof (messageObj.isNewMsg) != "boolean" || messageObj.isNewMsg === false) {
893 | continue;
894 | } else {
895 | messageObj.isNewMsg = false;
896 | let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications);
897 | if (message) {
898 | messageGroup.messages.push(message);
899 | }
900 | }
901 | }
902 |
903 | if (messageGroup.messages.length > 0) {
904 | output.push(messageGroup);
905 | } else { // no messages with isNewMsg true
906 | if (use_unread_count) {
907 | let n = messageGroupObj.unreadCount; // will use unreadCount attribute to fetch last n messages from sender
908 | for (let i = messages.length - 1; i >= 0; i--) {
909 | let messageObj = messages[i];
910 | if (n > 0) {
911 | if (!messageObj.isSentByMe) {
912 | let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications);
913 | messageGroup.messages.unshift(message);
914 | n -= 1;
915 | }
916 | } else if (n === -1) { // chat was marked as unread so will fetch last message as unread
917 | if (!messageObj.isSentByMe) {
918 | let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications);
919 | messageGroup.messages.unshift(message);
920 | break;
921 | }
922 | } else { // unreadCount = 0
923 | break;
924 | }
925 | }
926 | if (messageGroup.messages.length > 0) {
927 | messageGroupObj.unreadCount = 0; // reset unread counter
928 | output.push(messageGroup);
929 | }
930 | }
931 | }
932 | }
933 | if (done !== undefined) {
934 | done(output);
935 | }
936 | return output;
937 | };
938 |
939 | window.WAPI.getGroupOwnerID = async function (id, done) {
940 | const output = (await WAPI.getGroupMetadata(id)).owner.id;
941 | if (done !== undefined) {
942 | done(output);
943 | }
944 | return output;
945 |
946 | };
947 |
948 | window.WAPI.getCommonGroups = async function (id, done) {
949 | let output = [];
950 |
951 | groups = window.WAPI.getAllGroups();
952 |
953 | for (let idx in groups) {
954 | try {
955 | participants = await window.WAPI.getGroupParticipantIDs(groups[idx].id);
956 | if (participants.filter((participant) => participant == id).length) {
957 | output.push(groups[idx]);
958 | }
959 | } catch (err) {
960 | console.log("Error in group:");
961 | console.log(groups[idx]);
962 | console.log(err);
963 | }
964 | }
965 |
966 | if (done !== undefined) {
967 | done(output);
968 | }
969 | return output;
970 | };
971 |
972 |
973 | window.WAPI.getProfilePicSmallFromId = function (id, done) {
974 | window.Store.ProfilePicThumb.find(id).then(function (d) {
975 | if (d.img !== undefined) {
976 | window.WAPI.downloadFileWithCredentials(d.img, done);
977 | } else {
978 | done(false);
979 | }
980 | }, function (e) {
981 | done(false);
982 | })
983 | };
984 |
985 | window.WAPI.getProfilePicFromId = function (id, done) {
986 | window.Store.ProfilePicThumb.find(id).then(function (d) {
987 | if (d.imgFull !== undefined) {
988 | window.WAPI.downloadFileWithCredentials(d.imgFull, done);
989 | } else {
990 | done(false);
991 | }
992 | }, function (e) {
993 | done(false);
994 | })
995 | };
996 |
997 | window.WAPI.downloadFileWithCredentials = function (url, done) {
998 | let xhr = new XMLHttpRequest();
999 |
1000 | xhr.onload = function () {
1001 | if (xhr.readyState == 4) {
1002 | if (xhr.status == 200) {
1003 | let reader = new FileReader();
1004 | reader.readAsDataURL(xhr.response);
1005 | reader.onload = function (e) {
1006 | done(reader.result.substr(reader.result.indexOf(',') + 1))
1007 | };
1008 | } else {
1009 | console.error(xhr.statusText);
1010 | }
1011 | } else {
1012 | console.log(err);
1013 | done(false);
1014 | }
1015 | };
1016 |
1017 | xhr.open("GET", url, true);
1018 | xhr.withCredentials = true;
1019 | xhr.responseType = 'blob';
1020 | xhr.send(null);
1021 | };
1022 |
1023 |
1024 | window.WAPI.downloadFile = function (url, done) {
1025 | let xhr = new XMLHttpRequest();
1026 |
1027 |
1028 | xhr.onload = function () {
1029 | if (xhr.readyState == 4) {
1030 | if (xhr.status == 200) {
1031 | let reader = new FileReader();
1032 | reader.readAsDataURL(xhr.response);
1033 | reader.onload = function (e) {
1034 | done(reader.result.substr(reader.result.indexOf(',') + 1))
1035 | };
1036 | } else {
1037 | console.error(xhr.statusText);
1038 | }
1039 | } else {
1040 | console.log(err);
1041 | done(false);
1042 | }
1043 | };
1044 |
1045 | xhr.open("GET", url, true);
1046 | xhr.responseType = 'blob';
1047 | xhr.send(null);
1048 | };
1049 |
1050 | window.WAPI.getBatteryLevel = function (done) {
1051 | if (window.Store.Conn.plugged) {
1052 | if (done !== undefined) {
1053 | done(100);
1054 | }
1055 | return 100;
1056 | }
1057 | output = window.Store.Conn.battery;
1058 | if (done !== undefined) {
1059 | done(output);
1060 | }
1061 | return output;
1062 | };
1063 |
1064 | window.WAPI.deleteConversation = function (chatId, done) {
1065 | let userId = new window.Store.UserConstructor(chatId, {intentionallyUsePrivateConstructor: true});
1066 | let conversation = WAPI.getChat(userId);
1067 |
1068 | if (!conversation) {
1069 | if (done !== undefined) {
1070 | done(false);
1071 | }
1072 | return false;
1073 | }
1074 |
1075 | window.Store.sendDelete(conversation, false).then(() => {
1076 | if (done !== undefined) {
1077 | done(true);
1078 | }
1079 | }).catch(() => {
1080 | if (done !== undefined) {
1081 | done(false);
1082 | }
1083 | });
1084 |
1085 | return true;
1086 | };
1087 |
1088 | window.WAPI.deleteMessage = function (chatId, messageArray, revoke=false, done) {
1089 | let userId = new window.Store.UserConstructor(chatId, {intentionallyUsePrivateConstructor: true});
1090 | let conversation = WAPI.getChat(userId);
1091 |
1092 | if(!conversation) {
1093 | if(done !== undefined) {
1094 | done(false);
1095 | }
1096 | return false;
1097 | }
1098 |
1099 | if (!Array.isArray(messageArray)) {
1100 | messageArray = [messageArray];
1101 | }
1102 | let messagesToDelete = messageArray.map(msgId => window.Store.Msg.get(msgId));
1103 |
1104 | if (revoke) {
1105 | conversation.sendRevokeMsgs(messagesToDelete, conversation);
1106 | } else {
1107 | conversation.sendDeleteMsgs(messagesToDelete, conversation);
1108 | }
1109 |
1110 |
1111 | if (done !== undefined) {
1112 | done(true);
1113 | }
1114 |
1115 | return true;
1116 | };
1117 |
1118 | window.WAPI.checkNumberStatus = function (id, done) {
1119 | window.Store.WapQuery.queryExist(id).then((result) => {
1120 | if( done !== undefined) {
1121 | if (result.jid === undefined) throw 404;
1122 | done(window.WAPI._serializeNumberStatusObj(result));
1123 | }
1124 | }).catch((e) => {
1125 | if (done !== undefined) {
1126 | done(window.WAPI._serializeNumberStatusObj({
1127 | status: e,
1128 | jid : id
1129 | }));
1130 | }
1131 | });
1132 |
1133 | return true;
1134 | };
1135 |
1136 | /**
1137 | * New messages observable functions.
1138 | */
1139 | window.WAPI._newMessagesQueue = [];
1140 | window.WAPI._newMessagesBuffer = (sessionStorage.getItem('saved_msgs') != null) ? JSON.parse(sessionStorage.getItem('saved_msgs')) : [];
1141 | window.WAPI._newMessagesDebouncer = null;
1142 | window.WAPI._newMessagesCallbacks = [];
1143 |
1144 | window.Store.Msg.off('add');
1145 | sessionStorage.removeItem('saved_msgs');
1146 |
1147 | window.WAPI._newMessagesListener = window.Store.Msg.on('add', (newMessage) => {
1148 | if (newMessage && newMessage.isNewMsg && !newMessage.isSentByMe) {
1149 | let message = window.WAPI.processMessageObj(newMessage, false, false);
1150 | if (message) {
1151 | window.WAPI._newMessagesQueue.push(message);
1152 | window.WAPI._newMessagesBuffer.push(message);
1153 | }
1154 |
1155 | // Starts debouncer time to don't call a callback for each message if more than one message arrives
1156 | // in the same second
1157 | if (!window.WAPI._newMessagesDebouncer && window.WAPI._newMessagesQueue.length > 0) {
1158 | window.WAPI._newMessagesDebouncer = setTimeout(() => {
1159 | let queuedMessages = window.WAPI._newMessagesQueue;
1160 |
1161 | window.WAPI._newMessagesDebouncer = null;
1162 | window.WAPI._newMessagesQueue = [];
1163 |
1164 | let removeCallbacks = [];
1165 |
1166 | window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) {
1167 | if (callbackObj.callback !== undefined) {
1168 | callbackObj.callback(queuedMessages);
1169 | }
1170 | if (callbackObj.rmAfterUse === true) {
1171 | removeCallbacks.push(callbackObj);
1172 | }
1173 | });
1174 |
1175 | // Remove removable callbacks.
1176 | removeCallbacks.forEach(function (rmCallbackObj) {
1177 | let callbackIndex = window.WAPI._newMessagesCallbacks.indexOf(rmCallbackObj);
1178 | window.WAPI._newMessagesCallbacks.splice(callbackIndex, 1);
1179 | });
1180 | }, 1000);
1181 | }
1182 | }
1183 | });
1184 |
1185 | window.WAPI._unloadInform = (event) => {
1186 | // Save in the buffer the ungot unreaded messages
1187 | window.WAPI._newMessagesBuffer.forEach((message) => {
1188 | Object.keys(message).forEach(key => message[key] === undefined ? delete message[key] : '');
1189 | });
1190 | sessionStorage.setItem("saved_msgs", JSON.stringify(window.WAPI._newMessagesBuffer));
1191 |
1192 | // Inform callbacks that the page will be reloaded.
1193 | window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) {
1194 | if (callbackObj.callback !== undefined) {
1195 | callbackObj.callback({ status: -1, message: 'page will be reloaded, wait and register callback again.' });
1196 | }
1197 | });
1198 | };
1199 |
1200 | window.addEventListener("unload", window.WAPI._unloadInform, false);
1201 | window.addEventListener("beforeunload", window.WAPI._unloadInform, false);
1202 | window.addEventListener("pageunload", window.WAPI._unloadInform, false);
1203 |
1204 | /**
1205 | * Registers a callback to be called when a new message arrives the WAPI.
1206 | * @param rmCallbackAfterUse - Boolean - Specify if the callback need to be executed only once
1207 | * @param done - function - Callback function to be called when a new message arrives.
1208 | * @returns {boolean}
1209 | */
1210 | window.WAPI.waitNewMessages = function (rmCallbackAfterUse = true, done) {
1211 | window.WAPI._newMessagesCallbacks.push({ callback: done, rmAfterUse: rmCallbackAfterUse });
1212 | return true;
1213 | };
1214 |
1215 | /**
1216 | * Reads buffered new messages.
1217 | * @param done - function - Callback function to be called contained the buffered messages.
1218 | * @returns {Array}
1219 | */
1220 | window.WAPI.getBufferedNewMessages = function (done) {
1221 | let bufferedMessages = window.WAPI._newMessagesBuffer;
1222 | window.WAPI._newMessagesBuffer = [];
1223 | if (done !== undefined) {
1224 | done(bufferedMessages);
1225 | }
1226 | return bufferedMessages;
1227 | };
1228 | /** End new messages observable functions **/
1229 |
1230 | window.WAPI.sendImage = function (imgBase64, chatid, filename, caption, done) {
1231 | //var idUser = new window.Store.UserConstructor(chatid);
1232 | var idUser = new window.Store.UserConstructor(chatid, { intentionallyUsePrivateConstructor: true });
1233 | // create new chat
1234 | return Store.Chat.find(idUser).then((chat) => {
1235 | var mediaBlob = window.WAPI.base64ImageToFile(imgBase64, filename);
1236 | var mc = new Store.MediaCollection(chat);
1237 | mc.processAttachments([{file: mediaBlob}, 1], chat, 1).then(() => {
1238 | var media = mc.models[0];
1239 | media.sendToChat(chat, { caption: caption });
1240 | if (done !== undefined) done(true);
1241 | });
1242 | });
1243 | }
1244 |
1245 | window.WAPI.base64ImageToFile = function (b64Data, filename) {
1246 | var arr = b64Data.split(',');
1247 | var mime = arr[0].match(/:(.*?);/)[1];
1248 | var bstr = atob(arr[1]);
1249 | var n = bstr.length;
1250 | var u8arr = new Uint8Array(n);
1251 |
1252 | while (n--) {
1253 | u8arr[n] = bstr.charCodeAt(n);
1254 | }
1255 |
1256 | return new File([u8arr], filename, {type: mime});
1257 | };
1258 |
1259 | /**
1260 | * Send contact card to a specific chat using the chat ids
1261 | *
1262 | * @param {string} to '000000000000@c.us'
1263 | * @param {string|array} contact '111111111111@c.us' | ['222222222222@c.us', '333333333333@c.us, ... 'nnnnnnnnnnnn@c.us']
1264 | */
1265 | window.WAPI.sendContact = function (to, contact) {
1266 | if (!Array.isArray(contact)) {
1267 | contact = [contact];
1268 | }
1269 | contact = contact.map((c) => {
1270 | return WAPI.getChat(c).__x_contact;
1271 | });
1272 |
1273 | if (contact.length > 1) {
1274 | window.WAPI.getChat(to).sendContactList(contact);
1275 | } else if (contact.length === 1) {
1276 | window.WAPI.getChat(to).sendContact(contact[0]);
1277 | }
1278 | };
1279 |
1280 | /**
1281 | * Create an chat ID based in a cloned one
1282 | *
1283 | * @param {string} chatId '000000000000@c.us'
1284 | */
1285 | window.WAPI.getNewMessageId = function (chatId) {
1286 | var newMsgId = Store.Msg.models[0].__x_id.clone();
1287 |
1288 | newMsgId.fromMe = true;
1289 | newMsgId.id = WAPI.getNewId().toUpperCase();
1290 | newMsgId.remote = chatId;
1291 | newMsgId._serialized = `${newMsgId.fromMe}_${newMsgId.remote}_${newMsgId.id}`
1292 |
1293 | return newMsgId;
1294 | };
1295 |
1296 | /**
1297 | * Send Customized VCard without the necessity of contact be a Whatsapp Contact
1298 | *
1299 | * @param {string} chatId '000000000000@c.us'
1300 | * @param {object|array} vcard { displayName: 'Contact Name', vcard: 'BEGIN:VCARD\nVERSION:3.0\nN:;Contact Name;;;\nEND:VCARD' } | [{ displayName: 'Contact Name 1', vcard: 'BEGIN:VCARD\nVERSION:3.0\nN:;Contact Name 1;;;\nEND:VCARD' }, { displayName: 'Contact Name 2', vcard: 'BEGIN:VCARD\nVERSION:3.0\nN:;Contact Name 2;;;\nEND:VCARD' }]
1301 | */
1302 | window.WAPI.sendVCard = function (chatId, vcard) {
1303 | var chat = Store.Chat.get(chatId);
1304 | var tempMsg = Object.create(Store.Msg.models.filter(msg => msg.__x_isSentByMe)[0]);
1305 | var newId = window.WAPI.getNewMessageId(chatId);
1306 |
1307 | var extend = {
1308 | ack : 0,
1309 | id : newId,
1310 | local : !0,
1311 | self : "out",
1312 | t : parseInt(new Date().getTime() / 1000),
1313 | to : chatId,
1314 | isNewMsg: !0,
1315 | };
1316 |
1317 | if (Array.isArray(vcard)) {
1318 | Object.assign(extend, {
1319 | type : "multi_vcard",
1320 | vcardList: vcard
1321 | });
1322 |
1323 | delete extend.body;
1324 | } else {
1325 | Object.assign(extend, {
1326 | type : "vcard",
1327 | subtype: vcard.displayName,
1328 | body : vcard.vcard
1329 | });
1330 |
1331 | delete extend.vcardList;
1332 | }
1333 |
1334 | Object.assign(tempMsg, extend);
1335 |
1336 | chat.addAndSendMsg(tempMsg);
1337 | };
1338 | /**
1339 | * Block contact
1340 | * @param {string} id '000000000000@c.us'
1341 | * @param {*} done - function - Callback function to be called when a new message arrives.
1342 | */
1343 | window.WAPI.contactBlock = function (id, done) {
1344 | const contact = window.Store.Contact.get(id);
1345 | if (contact !== undefined) {
1346 | contact.setBlock(!0);
1347 | done(true);
1348 | return true;
1349 | }
1350 | done(false);
1351 | return false;
1352 | }
1353 | /**
1354 | * unBlock contact
1355 | * @param {string} id '000000000000@c.us'
1356 | * @param {*} done - function - Callback function to be called when a new message arrives.
1357 | */
1358 | window.WAPI.contactUnblock = function (id, done) {
1359 | const contact = window.Store.Contact.get(id);
1360 | if (contact !== undefined) {
1361 | contact.setBlock(!1);
1362 | done(true);
1363 | return true;
1364 | }
1365 | done(false);
1366 | return false;
1367 | }
1368 |
1369 | /**
1370 | * Remove participant of Group
1371 | * @param {*} idGroup '0000000000-00000000@g.us'
1372 | * @param {*} idParticipant '000000000000@c.us'
1373 | * @param {*} done - function - Callback function to be called when a new message arrives.
1374 | */
1375 | window.WAPI.removeParticipantGroup = function (idGroup, idParticipant, done) {
1376 | window.Store.WapQuery.removeParticipants(idGroup, [idParticipant]).then(() => {
1377 | const metaDataGroup = window.Store.GroupMetadata.get(id)
1378 | checkParticipant = metaDataGroup.participants._index[idParticipant];
1379 | if (checkParticipant === undefined) {
1380 | done(true); return true;
1381 | }
1382 | })
1383 | }
1384 |
1385 | /**
1386 | * Promote Participant to Admin in Group
1387 | * @param {*} idGroup '0000000000-00000000@g.us'
1388 | * @param {*} idParticipant '000000000000@c.us'
1389 | * @param {*} done - function - Callback function to be called when a new message arrives.
1390 | */
1391 | window.WAPI.promoteParticipantAdminGroup = function (idGroup, idParticipant, done) {
1392 | window.Store.WapQuery.promoteParticipants(idGroup, [idParticipant]).then(() => {
1393 | const metaDataGroup = window.Store.GroupMetadata.get(id)
1394 | checkParticipant = metaDataGroup.participants._index[idParticipant];
1395 | if (checkParticipant !== undefined && checkParticipant.isAdmin) {
1396 | done(true); return true;
1397 | }
1398 | done(false); return false;
1399 | })
1400 | }
1401 |
1402 | /**
1403 | * Demote Admin of Group
1404 | * @param {*} idGroup '0000000000-00000000@g.us'
1405 | * @param {*} idParticipant '000000000000@c.us'
1406 | * @param {*} done - function - Callback function to be called when a new message arrives.
1407 | */
1408 | window.WAPI.demoteParticipantAdminGroup = function (idGroup, idParticipant, done) {
1409 | window.Store.WapQuery.demoteParticipants(idGroup, [idParticipant]).then(() => {
1410 | const metaDataGroup = window.Store.GroupMetadata.get(id)
1411 | if (metaDataGroup === undefined) {
1412 | done(false); return false;
1413 | }
1414 | checkParticipant = metaDataGroup.participants._index[idParticipant];
1415 | if (checkParticipant !== undefined && checkParticipant.isAdmin) {
1416 | done(false); return false;
1417 | }
1418 | done(true); return true;
1419 | })
1420 | }
1421 |
1422 |
1423 | /* code from Mikkel-era
1424 | * NOTE: Updated/fixed after merge with upstream etc.
1425 | */
1426 |
1427 | window.WAPI.getAllMessagesAfter = function(unixTimestamp, includeMe, includeNotifications, done) {
1428 | let messageObjs = window.Store.Msg.models.filter((msg) => msg.__x_t > unixTimestamp);
1429 | var output = [];
1430 | for (const i in messageObjs) {
1431 | if (i === "remove")
1432 | continue;
1433 | const messageObj = messageObjs[i];
1434 | let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications);
1435 | if (message)
1436 | output.push(message);
1437 | }
1438 | if (done !== undefined) {
1439 | done(output);
1440 | }
1441 | return output
1442 | };
--------------------------------------------------------------------------------