Compare commits

...

8 Commits

Author SHA1 Message Date
Pedro Lopez
3c55fbf2ca 0.3.2 2020-01-17 22:06:19 -04:00
Pedro Lopez
6b1b51eacd Increase successful connection timeout 2020-01-17 22:06:04 -04:00
Pedro Lopez
2dc53e0820 [FIX] Connection success detection selector changed
close #31
2020-01-17 22:05:05 -04:00
Pedro Lopez
9043e61c40 0.3.1 2019-12-04 03:00:04 -04:00
Pedro Lopez
bea1ebf480 [FIX] Get QR code directly from canvas element (fix #26) 2019-12-04 02:58:55 -04:00
Pedro Lopez
021a213de3 0.3.0 2019-11-24 04:25:35 -04:00
Pedro S. Lopez
d0bef55b8a Merge pull request #24 from pedroslopez/development
Download message attachments (images, documents, etc)
2019-11-24 04:25:14 -04:00
Pedro Lopez
64912dccfd Download message attachments (images, documents, etc) 2019-11-24 04:23:08 -04:00
6 changed files with 90 additions and 17 deletions

View File

@@ -81,6 +81,14 @@ client.on('message', async msg => {
} else if(msg.body == '!chats') { } else if(msg.body == '!chats') {
const chats = await client.getChats(); const chats = await client.getChats();
client.sendMessage(msg.from, `The bot has ${chats.length} chats open.`); client.sendMessage(msg.from, `The bot has ${chats.length} chats open.`);
} else if(msg.body == '!mediainfo' && msg.hasMedia) {
const attachmentData = await msg.downloadMedia();
msg.reply(`
*Media info*
MimeType: ${attachmentData.mimetype}
Filename: ${attachmentData.filename}
Data (length): ${attachmentData.data.length}
`);
} }
}); });

7
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "whatsapp-web.js", "name": "whatsapp-web.js",
"version": "0.2.0", "version": "0.3.2",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -168,6 +168,11 @@
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
}, },
"jsqr": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.2.0.tgz",
"integrity": "sha512-wKcQS9QC2VHGk7aphWCp1RrFyC0CM6fMgC5prZZ2KV/Lk6OKNoCod9IR6bao+yx3KPY0gZFC5dc+h+KFzCI0Wg=="
},
"mime": { "mime": {
"version": "2.4.4", "version": "2.4.4",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",

View File

@@ -1,6 +1,6 @@
{ {
"name": "whatsapp-web.js", "name": "whatsapp-web.js",
"version": "0.2.0", "version": "0.3.2",
"description": "Library for interacting with the WhatsApp Web API ", "description": "Library for interacting with the WhatsApp Web API ",
"main": "./index.js", "main": "./index.js",
"scripts": { "scripts": {
@@ -25,6 +25,7 @@
}, },
"homepage": "https://github.com/pedroslopez/whatsapp-web.js#readme", "homepage": "https://github.com/pedroslopez/whatsapp-web.js#readme",
"dependencies": { "dependencies": {
"jsqr": "^1.2.0",
"moduleraid": "git+https://github.com/pixeldesu/moduleRaid.git", "moduleraid": "git+https://github.com/pixeldesu/moduleRaid.git",
"puppeteer": "^1.20.0" "puppeteer": "^1.20.0"
} }

View File

@@ -3,12 +3,12 @@
const EventEmitter = require('events'); const EventEmitter = require('events');
const puppeteer = require('puppeteer'); const puppeteer = require('puppeteer');
const moduleRaid = require('moduleraid/moduleraid'); const moduleRaid = require('moduleraid/moduleraid');
const jsQR = require('jsqr');
const Util = require('./util/Util'); const Util = require('./util/Util');
const { WhatsWebURL, UserAgent, DefaultOptions, Events, WAState } = require('./util/Constants'); const { WhatsWebURL, UserAgent, DefaultOptions, Events, WAState } = require('./util/Constants');
const { ExposeStore, LoadCustomSerializers } = require('./util/Injected'); const { ExposeStore, LoadUtils } = require('./util/Injected');
const ChatFactory = require('./factories/ChatFactory'); const ChatFactory = require('./factories/ChatFactory');
const Chat = require('./structures/Chat');
const Message = require('./structures/Message'); const Message = require('./structures/Message');
/** /**
@@ -46,12 +46,12 @@ class Client extends EventEmitter {
await page.goto(WhatsWebURL); await page.goto(WhatsWebURL);
const KEEP_PHONE_CONNECTED_IMG_SELECTOR = '._1wSzK'; const KEEP_PHONE_CONNECTED_IMG_SELECTOR = '.HGVhc';
if (this.options.session) { if (this.options.session) {
// Check if session restore was successfull // Check if session restore was successfull
try { try {
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 5000 }); await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 15000 });
} catch (err) { } catch (err) {
if (err.name === 'TimeoutError') { if (err.name === 'TimeoutError') {
this.emit(Events.AUTHENTICATION_FAILURE, 'Unable to log in. Are the session details valid?'); this.emit(Events.AUTHENTICATION_FAILURE, 'Unable to log in. Are the session details valid?');
@@ -65,12 +65,11 @@ class Client extends EventEmitter {
} else { } else {
// Wait for QR Code // Wait for QR Code
const QR_CONTAINER_SELECTOR = '._2d3Jz'; const QR_CANVAS_SELECTOR = 'canvas';
const QR_VALUE_SELECTOR = '._1pw2F'; await page.waitForSelector(QR_CANVAS_SELECTOR);
const qrImgData = await page.$eval(QR_CANVAS_SELECTOR, canvas => [].slice.call(canvas.getContext('2d').getImageData(0,0,264,264).data));
await page.waitForSelector(QR_CONTAINER_SELECTOR); const qr = jsQR(qrImgData, 264, 264).data;
const qr = await page.$eval(QR_VALUE_SELECTOR, node => node.getAttribute('data-ref'));
this.emit(Events.QR_RECEIVED, qr); this.emit(Events.QR_RECEIVED, qr);
// Wait for code scan // Wait for code scan
@@ -96,8 +95,8 @@ class Client extends EventEmitter {
// Check Store Injection // Check Store Injection
await page.waitForFunction('window.Store != undefined'); await page.waitForFunction('window.Store != undefined');
//Load custom serializers //Load util functions (serializers, helper functions)
await page.evaluate(LoadCustomSerializers); await page.evaluate(LoadUtils);
// Register events // Register events
await page.exposeFunction('onAddMessageEvent', msg => { await page.exposeFunction('onAddMessageEvent', msg => {

View File

@@ -15,7 +15,8 @@ class Message extends Base {
_patch(data) { _patch(data) {
this.id = data.id; this.id = data.id;
this.body = data.body; this.hasMedia = data.clientUrl ? true : false;
this.body = this.hasMedia ? data.caption || '' : data.body || '';
this.type = data.type; this.type = data.type;
this.timestamp = data.t; this.timestamp = data.t;
this.from = data.from; this.from = data.from;
@@ -60,6 +61,26 @@ class Message extends Base {
}, chatId, this.id._serialized, message); }, chatId, this.id._serialized, message);
} }
async downloadMedia() {
if (!this.hasMedia) {
return undefined;
}
return await this.client.pupPage.evaluate(async (msgId) => {
const msg = Store.Msg.get(msgId);
const buffer = await WWebJS.downloadBuffer(msg.clientUrl);
const decrypted = await Store.CryptoLib.decryptE2EMedia(msg.type, buffer, msg.mediaKey, msg.mimetype);
const data = await WWebJS.readBlobAsync(decrypted._blob);
return {
data,
mimetype: msg.mimetype,
filename: msg.filename
}
}, this.id._serialized);
}
} }
module.exports = Message; module.exports = Message;

View File

@@ -8,12 +8,12 @@ exports.ExposeStore = (moduleRaidStr) => {
window.mR = moduleRaid(); window.mR = moduleRaid();
window.Store = window.mR.findModule("Chat")[1].default; window.Store = window.mR.findModule("Chat")[1].default;
window.Store.AppState = window.mR.findModule("STREAM")[0].default; window.Store.AppState = window.mR.findModule("STREAM")[0].default;
window.Store.CryptoLib = window.mR.findModule("decryptE2EMedia")[0];
window.Store.genId = window.mR.findModule((module) => module.default && typeof module.default === 'function' && module.default.toString().match(/crypto/))[0].default; window.Store.genId = window.mR.findModule((module) => module.default && typeof module.default === 'function' && module.default.toString().match(/crypto/))[0].default;
window.Store.SendMessage = window.mR.findModule("sendTextMsgToChat")[0].sendTextMsgToChat; window.Store.SendMessage = window.mR.findModule("sendTextMsgToChat")[0].sendTextMsgToChat;
} }
exports.LoadCustomSerializers = () => { exports.LoadUtils = () => {
window.WWebJS = {}; window.WWebJS = {};
window.WWebJS.getChatModel = chat => { window.WWebJS.getChatModel = chat => {
@@ -37,6 +37,45 @@ exports.LoadCustomSerializers = () => {
const chats = Store.Chat.models; const chats = Store.Chat.models;
return chats.map(chat => WWebJS.getChatModel(chat)); return chats.map(chat => WWebJS.getChatModel(chat));
} }
window.WWebJS.downloadBuffer = (url) => {
return new Promise(function(resolve, reject) {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
if (xhr.status == 200) {
resolve(xhr.response);
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send(null);
});
}
window.WWebJS.readBlobAsync = (blob) => {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsDataURL(blob);
})
}
} }
exports.MarkAllRead = () => { exports.MarkAllRead = () => {