mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
Rewrite for extensibility & compactness
-This is a break from previous versions unfortunately -Connecting is now a promise -Chats, contacts & previously unread messages are supplied on connection -Groups! -Message confirmations are more reliable -Timeout queries & connections
This commit is contained in:
@@ -1,35 +1,48 @@
|
||||
const Utils = require("./WhatsAppWeb.Utils")
|
||||
const fetch = require('node-fetch')
|
||||
|
||||
/*
|
||||
Contains the code for sending stuff to WhatsApp
|
||||
*/
|
||||
module.exports = function(WhatsAppWeb) {
|
||||
|
||||
// send a read receipt to the given ID on a certain message
|
||||
WhatsAppWeb.prototype.sendReadReceipt = function (jid, messageID) {
|
||||
module.exports = {
|
||||
/**
|
||||
* Send a read receipt to the given ID for a certain message
|
||||
* @param {string} jid the ID of the person/group whose message you read
|
||||
* @param {string} messageID the message ID
|
||||
* @return {Promise<[object, object]>}
|
||||
*/
|
||||
sendReadReceipt: function (jid, messageID) {
|
||||
const json = [
|
||||
"action",
|
||||
{ epoch: this.msgCount.toString(), type: "set" },
|
||||
[
|
||||
["read", {count: "1", index: messageID, jid: jid, owner: "false"}, null]
|
||||
]
|
||||
[ ["read", {count: "1", index: messageID, jid: jid, owner: "false"}, null] ]
|
||||
]
|
||||
return this.query(json, [10, 128]) // encrypt and send off
|
||||
}
|
||||
// tell someone about your presence -- online, typing, offline etc.
|
||||
WhatsAppWeb.prototype.updatePresence = function (jid, type) {
|
||||
},
|
||||
/**
|
||||
* Tell someone about your presence -- online, typing, offline etc.
|
||||
* @param {string} jid the ID of the person/group who you are updating
|
||||
* @param {string} type your presence
|
||||
* @return {Promise<[object, object]>}
|
||||
*/
|
||||
updatePresence: function (jid, type) {
|
||||
const json = [
|
||||
"action",
|
||||
{ epoch: this.msgCount.toString(), type: "set" },
|
||||
[ ["presence", {type: type, to: jid}, null] ]
|
||||
]
|
||||
return this.query(json, [10, 128])
|
||||
}
|
||||
// send a text message to someone, optionally you can provide a quoted message & the timestamp for the message
|
||||
WhatsAppWeb.prototype.sendTextMessage = function (id, txt, quoted=null, timestamp=null) {
|
||||
return this.query(json, [10, 64])
|
||||
},
|
||||
/**
|
||||
* Send a text message
|
||||
* @param {string} id the JID of the person/group you're sending the message to
|
||||
* @param {string} txt the actual text of the message
|
||||
* @param {object} [quoted] the message you may wanna quote along with this message
|
||||
* @param {Date} [timestamp] optionally set the timestamp of the message in Unix time MS
|
||||
* @return {Promise<[object, object]>}
|
||||
*/
|
||||
sendTextMessage: function (id, txt, quoted, timestamp) {
|
||||
if (typeof txt !== "string") {
|
||||
return Promise.reject("")
|
||||
return Promise.reject("expected text to be a string")
|
||||
}
|
||||
let message
|
||||
if (quoted) {
|
||||
@@ -48,9 +61,21 @@ module.exports = function(WhatsAppWeb) {
|
||||
}
|
||||
|
||||
return this.sendMessage(id, message, timestamp)
|
||||
}
|
||||
// send a media message to someone, optionally you can provide a caption, thumbnail, mimetype & the timestamp for the message
|
||||
WhatsAppWeb.prototype.sendMediaMessage = function (id, buffer, mediaType, info=null, timestamp=null) {
|
||||
},
|
||||
/**
|
||||
* Send a media message
|
||||
* @param {string} id the JID of the person/group you're sending the message to
|
||||
* @param {Buffer} buffer the buffer of the actual media you're sending
|
||||
* @param {string} mediaType the type of media, can be one of [imageMessage, documentMessage, stickerMessage, videoMessage]
|
||||
* @param {Object} [info] object to hold some metadata or caption about the media
|
||||
* @param {string} [info.caption] caption to go along with the media
|
||||
* @param {string} [info.thumbnail] base64 encoded thumbnail for the media
|
||||
* @param {string} [info.mimetype] specify the Mimetype of the media (required for document messages)
|
||||
* @param {boolean} [info.gif] whether the media is a gif or not, only valid for video messages
|
||||
* @param {Date} [timestamp] optionally set the timestamp of the message in Unix time MS
|
||||
* @return {Promise<[object, object]>}
|
||||
*/
|
||||
sendMediaMessage: function (id, buffer, mediaType, info, timestamp) {
|
||||
// path to upload the media
|
||||
const mediaPathMap = {
|
||||
imageMessage: "/mms/image",
|
||||
@@ -70,13 +95,13 @@ module.exports = function(WhatsAppWeb) {
|
||||
if (!info) {
|
||||
info = {}
|
||||
}
|
||||
if (mediaType === WhatsAppWeb.MessageType.text || mediaType === WhatsAppWeb.MessageType.extendedText) {
|
||||
if (mediaType === "conversation" || mediaType === "extendedTextMessage") {
|
||||
return Promise.reject("use sendTextMessage() to send text messages")
|
||||
}
|
||||
if (mediaType === WhatsAppWeb.MessageType.document && !info.mimetype) {
|
||||
if (mediaType === "documentMessage" && !info.mimetype) {
|
||||
return Promise.reject("mimetype required to send a document")
|
||||
}
|
||||
if (mediaType === WhatsAppWeb.MessageType.sticker && info.caption) {
|
||||
if (mediaType === "stickerMessage" && info.caption) {
|
||||
return Promise.reject("cannot send a caption with a sticker")
|
||||
}
|
||||
if (!info.mimetype) {
|
||||
@@ -125,21 +150,27 @@ module.exports = function(WhatsAppWeb) {
|
||||
fileLength: buffer.length,
|
||||
jpegThumbnail: info.thumbnail
|
||||
}
|
||||
if (mediaType === WhatsAppWeb.MessageType.video && info.gif) {
|
||||
if (mediaType === "videoMessage" && info.gif) {
|
||||
message[mediaType].gifPlayback = info.gif
|
||||
}
|
||||
//console.log(message)
|
||||
return this.sendMessage(id, message, timestamp)
|
||||
})
|
||||
}
|
||||
// generic send message construct
|
||||
WhatsAppWeb.prototype.sendMessage = function (id, message, timestamp=null) {
|
||||
},
|
||||
/**
|
||||
* Generic send message function
|
||||
* @private
|
||||
* @param {string} id who to send the message to
|
||||
* @param {object} message like, the message
|
||||
* @param {Date} [timestamp] timestamp for the message
|
||||
* @return {Promise<[object, object]>} array of the recieved JSON & the query JSON
|
||||
*/
|
||||
sendMessage: function (id, message, timestamp) {
|
||||
if (!timestamp) { // if no timestamp was provided,
|
||||
timestamp = new Date() // set timestamp to now
|
||||
}
|
||||
timestamp = timestamp.getTime()/1000
|
||||
|
||||
const messageJSON = {
|
||||
let messageJSON = {
|
||||
key: {
|
||||
remoteJid: id,
|
||||
fromMe: true,
|
||||
@@ -149,34 +180,79 @@ module.exports = function(WhatsAppWeb) {
|
||||
messageTimestamp: timestamp,
|
||||
status: "ERROR"
|
||||
}
|
||||
|
||||
if (id.includes ("@g.us")) {
|
||||
messageJSON.participant = this.userMetaData.id
|
||||
}
|
||||
const json = [
|
||||
"action",
|
||||
{epoch: this.msgCount.toString(), type: "relay"},
|
||||
[ ["message", null, messageJSON] ]
|
||||
[ ["message", null, messageJSON] ]]
|
||||
return this.query(json, [16, 128], null, messageJSON.key.id)
|
||||
},
|
||||
/**
|
||||
* Generic function for group queries
|
||||
* @param {string} type the type of query
|
||||
* @param {string} [jid] the id of the group
|
||||
* @param {string} [subject] title to attach to the group
|
||||
* @param {string[]} [participants] the people the query will affect
|
||||
* @return {Promise<[object, object]>} array of the recieved JSON & the query JSON
|
||||
*/
|
||||
groupQuery: function (type, jid, subject, participants) {
|
||||
let json = [
|
||||
"group",
|
||||
{
|
||||
author: this.userMetaData.id,
|
||||
id: Utils.generateMessageTag(),
|
||||
type: type
|
||||
},
|
||||
null
|
||||
]
|
||||
return this.query(json, [16, 64])
|
||||
}
|
||||
// send query message to WhatsApp servers; returns a promise
|
||||
WhatsAppWeb.prototype.query = function (json, binaryTags=null) {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
let tag
|
||||
if (binaryTags) {
|
||||
tag = this.sendBinary(json, binaryTags)
|
||||
} else {
|
||||
tag = this.sendJSON(json)
|
||||
}
|
||||
this.callbacks[tag] = {queryJSON: json, callback: resolve, errCallback: reject}
|
||||
})
|
||||
return promise
|
||||
}
|
||||
// send a binary message, the tags parameter tell WhatsApp what the message is all about
|
||||
WhatsAppWeb.prototype.sendBinary = function (json, tags) {
|
||||
if (participants) {
|
||||
json[2] = participants.map (str => ["participant", {jid: str}, null])
|
||||
}
|
||||
if (jid) {
|
||||
json[1].jid = jid
|
||||
}
|
||||
if (subject) {
|
||||
json[1].subject = subject
|
||||
}
|
||||
json = [
|
||||
"action",
|
||||
{type: "set", epoch: this.msgCount.toString()},
|
||||
[json]
|
||||
]
|
||||
return this.query (json, [10, 128])
|
||||
},
|
||||
/**
|
||||
* Query something from the WhatsApp servers
|
||||
* @param {any[]} json the query itself
|
||||
* @param {[number, number]} [binaryTags] the tags to attach if the query is supposed to be sent encoded in binary
|
||||
* @param {Number} [timeoutMs] timeout after which the query will be failed (set to null to disable a timeout)
|
||||
* @param {string} [tag] the tag to attach to the message
|
||||
* @return {Promise<[object, object]>} array of the recieved JSON & the query JSON
|
||||
*/
|
||||
query: function (json, binaryTags, timeoutMs, tag) {
|
||||
if (binaryTags) {
|
||||
tag = this.sendBinary(json, binaryTags, tag)
|
||||
} else {
|
||||
tag = this.sendJSON(json, tag)
|
||||
}
|
||||
return this.waitForMessage (tag, json, timeoutMs)
|
||||
},
|
||||
/**
|
||||
* Send a binary encoded message
|
||||
* @private
|
||||
* @param {[string, object, [string, object, object][]]} json the message to encode & send
|
||||
* @param {[number, number]} tags the binary tags to tell WhatsApp what the message is all about
|
||||
* @param {string} [tag] the tag to attach to the message
|
||||
* @return {string} the message tag
|
||||
*/
|
||||
sendBinary: function (json, tags, tag) {
|
||||
const binary = this.encoder.write(json) // encode the JSON to the WhatsApp binary format
|
||||
|
||||
var buff = Utils.aesEncrypt(binary, this.authInfo.encKey) // encrypt it using AES and our encKey
|
||||
const sign = Utils.hmacSign(buff, this.authInfo.macKey) // sign the message using HMAC and our macKey
|
||||
const tag = Utils.generateMessageTag()
|
||||
tag = tag ?? Utils.generateMessageTag()
|
||||
buff = Buffer.concat([
|
||||
Buffer.from(tag + ","), // generate & prefix the message tag
|
||||
Buffer.from(tags), // prefix some bytes that tell whatsapp what the message is about
|
||||
@@ -185,17 +261,27 @@ module.exports = function(WhatsAppWeb) {
|
||||
])
|
||||
this.send(buff) // send it off
|
||||
return tag
|
||||
}
|
||||
// send a JSON message to WhatsApp servers
|
||||
WhatsAppWeb.prototype.sendJSON = function (json) {
|
||||
const str = JSON.stringify(json)
|
||||
const tag = Utils.generateMessageTag()
|
||||
},
|
||||
/**
|
||||
* Send a plain JSON message to the WhatsApp servers
|
||||
* @private
|
||||
* @param {[any]} json the message to send
|
||||
* @param {string} [tag] the tag to attach to the message
|
||||
* @return {string} the message tag
|
||||
*/
|
||||
sendJSON: function (json, tag) {
|
||||
const str = JSON.stringify(json)
|
||||
tag = tag ?? Utils.generateMessageTag()
|
||||
this.send(tag + "," + str)
|
||||
return tag
|
||||
}
|
||||
WhatsAppWeb.prototype.send = function (m) {
|
||||
},
|
||||
/**
|
||||
* Send some message to the WhatsApp servers
|
||||
* @private
|
||||
* @param {any} json the message to send
|
||||
*/
|
||||
send: function (m) {
|
||||
this.msgCount += 1 // increment message count, it makes the 'epoch' field when sending binary messages
|
||||
this.conn.send( m )
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user