mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
updated connect & message sending
This commit is contained in:
@@ -26,10 +26,11 @@ import {
|
|||||||
} from './Constants'
|
} from './Constants'
|
||||||
import { EventEmitter } from 'events'
|
import { EventEmitter } from 'events'
|
||||||
import KeyedDB from '@adiwajshing/keyed-db'
|
import KeyedDB from '@adiwajshing/keyed-db'
|
||||||
|
import { STATUS_CODES } from 'http'
|
||||||
|
|
||||||
export class WAConnection extends EventEmitter {
|
export class WAConnection extends EventEmitter {
|
||||||
/** The version of WhatsApp Web we're telling the servers we are */
|
/** The version of WhatsApp Web we're telling the servers we are */
|
||||||
version: [number, number, number] = [2, 2033, 7]
|
version: [number, number, number] = [2, 2035, 14]
|
||||||
/** The Browser we're telling the WhatsApp Web servers we are */
|
/** The Browser we're telling the WhatsApp Web servers we are */
|
||||||
browserDescription: [string, string, string] = Utils.Browsers.baileys ('Chrome')
|
browserDescription: [string, string, string] = Utils.Browsers.baileys ('Chrome')
|
||||||
/** Metadata like WhatsApp id, name set on WhatsApp etc. */
|
/** Metadata like WhatsApp id, name set on WhatsApp etc. */
|
||||||
@@ -224,12 +225,12 @@ export class WAConnection extends EventEmitter {
|
|||||||
* @param tag the tag to attach to the message
|
* @param tag the tag to attach to the message
|
||||||
* recieved JSON
|
* recieved JSON
|
||||||
*/
|
*/
|
||||||
async query({json, binaryTags, tag, timeoutMs, expect200, waitForOpen}: WAQuery) {
|
async query({json, binaryTags, tag, timeoutMs, expect200, waitForOpen, longTag}: WAQuery) {
|
||||||
waitForOpen = typeof waitForOpen === 'undefined' ? true : waitForOpen
|
waitForOpen = typeof waitForOpen === 'undefined' ? true : waitForOpen
|
||||||
if (waitForOpen) await this.waitForConnection ()
|
if (waitForOpen) await this.waitForConnection ()
|
||||||
|
|
||||||
if (binaryTags) tag = await this.sendBinary(json as WANode, binaryTags, tag)
|
if (binaryTags) tag = await this.sendBinary(json as WANode, binaryTags, tag, longTag)
|
||||||
else tag = await this.sendJSON(json, tag)
|
else tag = await this.sendJSON(json, tag, longTag)
|
||||||
|
|
||||||
const response = await this.waitForMessage(tag, json, timeoutMs)
|
const response = await this.waitForMessage(tag, json, timeoutMs)
|
||||||
if (expect200 && response.status && Math.floor(+response.status / 100) !== 2) {
|
if (expect200 && response.status && Math.floor(+response.status / 100) !== 2) {
|
||||||
@@ -239,7 +240,11 @@ export class WAConnection extends EventEmitter {
|
|||||||
const response = await this.query ({json, binaryTags, tag, timeoutMs, expect200, waitForOpen})
|
const response = await this.query ({json, binaryTags, tag, timeoutMs, expect200, waitForOpen})
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
throw new BaileysError(`Unexpected status code in '${json[0] || 'generic query'}': ${response.status}`, {query: json, status: response.status})
|
const message = STATUS_CODES[response.status] || 'unknown'
|
||||||
|
throw new BaileysError(
|
||||||
|
`Unexpected status in '${json[0] || 'generic query'}': ${STATUS_CODES[response.status]}(${response.status})`,
|
||||||
|
{query: json, message, status: response.status}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
@@ -250,12 +255,12 @@ export class WAConnection extends EventEmitter {
|
|||||||
* @param tag the tag to attach to the message
|
* @param tag the tag to attach to the message
|
||||||
* @return the message tag
|
* @return the message tag
|
||||||
*/
|
*/
|
||||||
protected sendBinary(json: WANode, tags: WATag, tag: string = null) {
|
protected sendBinary(json: WANode, tags: WATag, tag: string = null, longTag: boolean = false) {
|
||||||
const binary = this.encoder.write(json) // encode the JSON to the WhatsApp binary format
|
const binary = this.encoder.write(json) // encode the JSON to the WhatsApp binary format
|
||||||
|
|
||||||
let buff = Utils.aesEncrypt(binary, this.authInfo.encKey) // encrypt it using AES and our encKey
|
let 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 sign = Utils.hmacSign(buff, this.authInfo.macKey) // sign the message using HMAC and our macKey
|
||||||
tag = tag || this.generateMessageTag()
|
tag = tag || this.generateMessageTag(longTag)
|
||||||
buff = Buffer.concat([
|
buff = Buffer.concat([
|
||||||
Buffer.from(tag + ','), // generate & prefix the message tag
|
Buffer.from(tag + ','), // generate & prefix the message tag
|
||||||
Buffer.from(tags), // prefix some bytes that tell whatsapp what the message is about
|
Buffer.from(tags), // prefix some bytes that tell whatsapp what the message is about
|
||||||
@@ -271,8 +276,8 @@ export class WAConnection extends EventEmitter {
|
|||||||
* @param tag the tag to attach to the message
|
* @param tag the tag to attach to the message
|
||||||
* @return the message tag
|
* @return the message tag
|
||||||
*/
|
*/
|
||||||
protected sendJSON(json: any[] | WANode, tag: string = null) {
|
protected sendJSON(json: any[] | WANode, tag: string = null, longTag: boolean = false) {
|
||||||
tag = tag || this.generateMessageTag()
|
tag = tag || this.generateMessageTag(longTag)
|
||||||
this.send(`${tag},${JSON.stringify(json)}`)
|
this.send(`${tag},${JSON.stringify(json)}`)
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
@@ -353,8 +358,9 @@ export class WAConnection extends EventEmitter {
|
|||||||
agent: this.connectOptions.agent
|
agent: this.connectOptions.agent
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
generateMessageTag () {
|
generateMessageTag (longTag: boolean = false) {
|
||||||
return `${Utils.unixTimestampSeconds(this.referenceDate)}.--${this.msgCount}`
|
const seconds = Utils.unixTimestampSeconds(this.referenceDate)
|
||||||
|
return `${longTag ? seconds : (seconds%1000)}.--${this.msgCount}`
|
||||||
}
|
}
|
||||||
protected log(text, level: MessageLogLevel) {
|
protected log(text, level: MessageLogLevel) {
|
||||||
(this.logLevel >= level) && console.log(`[Baileys][${new Date().toLocaleString()}] ${text}`)
|
(this.logLevel >= level) && console.log(`[Baileys][${new Date().toLocaleString()}] ${text}`)
|
||||||
|
|||||||
@@ -12,15 +12,24 @@ export class WAConnection extends Base {
|
|||||||
if (!this.authInfo?.clientID) {
|
if (!this.authInfo?.clientID) {
|
||||||
this.authInfo = { clientID: Utils.generateClientID() } as any
|
this.authInfo = { clientID: Utils.generateClientID() } as any
|
||||||
}
|
}
|
||||||
|
|
||||||
this.referenceDate = new Date () // refresh reference date
|
|
||||||
const json = ['admin', 'init', this.version, this.browserDescription, this.authInfo?.clientID, true]
|
|
||||||
|
|
||||||
return this.query({json, expect200: true, waitForOpen: false})
|
const canLogin = this.authInfo?.encKey && this.authInfo?.macKey
|
||||||
.then(json => {
|
this.referenceDate = new Date () // refresh reference date
|
||||||
// we're trying to establish a new connection or are trying to log in
|
|
||||||
if (this.authInfo?.encKey && this.authInfo?.macKey) {
|
const initQueries = [
|
||||||
// if we have the info to restore a closed session
|
(async () => {
|
||||||
|
const json = ['admin', 'init', this.version, this.browserDescription, this.authInfo?.clientID, true]
|
||||||
|
const ref = await this.query({json, expect200: true, waitForOpen: false, longTag: true})
|
||||||
|
if (!canLogin) {
|
||||||
|
const result = await this.generateKeysForAuth (ref)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
]
|
||||||
|
if (canLogin) {
|
||||||
|
// if we have the info to restore a closed session
|
||||||
|
initQueries.push (
|
||||||
|
(async () => {
|
||||||
const json = [
|
const json = [
|
||||||
'admin',
|
'admin',
|
||||||
'login',
|
'login',
|
||||||
@@ -30,38 +39,30 @@ export class WAConnection extends Base {
|
|||||||
]
|
]
|
||||||
if (reconnect) json.push(...['reconnect', reconnect.replace('@s.whatsapp.net', '@c.us')])
|
if (reconnect) json.push(...['reconnect', reconnect.replace('@s.whatsapp.net', '@c.us')])
|
||||||
else json.push ('takeover')
|
else json.push ('takeover')
|
||||||
return this.query({ json, tag: 's1', waitForOpen: false }) // wait for response with tag "s1"
|
|
||||||
}
|
let response = await this.query({ json, tag: 's1', waitForOpen: false, expect200: true, longTag: true }) // wait for response with tag "s1"
|
||||||
return this.generateKeysForAuth(json.ref) // generate keys which will in turn be the QR
|
// if its a challenge request (we get it when logging in)
|
||||||
})
|
if (response[1]?.challenge) {
|
||||||
.then(async json => {
|
await this.respondToChallenge(response[1].challenge)
|
||||||
if ('status' in json) {
|
response = await this.waitForMessage('s2', [])
|
||||||
switch (json.status) {
|
|
||||||
case 401: // if the phone was unpaired
|
|
||||||
throw new BaileysError ('unpaired from phone', json)
|
|
||||||
case 429: // request to login was denied, don't know why it happens
|
|
||||||
throw new BaileysError ('request denied', json)
|
|
||||||
default:
|
|
||||||
throw new BaileysError ('unexpected status ' + json.status, json)
|
|
||||||
}
|
}
|
||||||
}
|
return response
|
||||||
// if its a challenge request (we get it when logging in)
|
})()
|
||||||
if (json[1]?.challenge) {
|
)
|
||||||
await this.respondToChallenge(json[1].challenge)
|
}
|
||||||
return this.waitForMessage('s2', [])
|
|
||||||
}
|
|
||||||
// otherwise just chain the promise further
|
|
||||||
return json
|
|
||||||
})
|
|
||||||
.then(json => {
|
|
||||||
this.user = this.validateNewConnection(json[1]) // validate the connection
|
|
||||||
this.log('validated connection successfully', MessageLogLevel.info)
|
|
||||||
|
|
||||||
this.sendPostConnectQueries ()
|
const validationJSON = (await Promise.all (initQueries)).slice(-1)[0] // get the last result
|
||||||
})
|
|
||||||
// load profile picture
|
this.user = await this.validateNewConnection(validationJSON[1]) // validate the connection
|
||||||
.then (() => this.query({ json: ['query', 'ProfilePicThumb', this.user.jid], waitForOpen: false, expect200: false }))
|
|
||||||
.then (response => this.user.imgUrl = response?.eurl || '')
|
this.log('validated connection successfully', MessageLogLevel.info)
|
||||||
|
|
||||||
|
const response = await this.query({ json: ['query', 'ProfilePicThumb', this.user.jid], waitForOpen: false, expect200: false })
|
||||||
|
this.user.imgUrl = response?.eurl || ''
|
||||||
|
|
||||||
|
this.sendPostConnectQueries ()
|
||||||
|
|
||||||
|
this.log('sent init queries', MessageLogLevel.info)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Send the same queries WA Web sends after connect
|
* Send the same queries WA Web sends after connect
|
||||||
@@ -80,7 +81,7 @@ export class WAConnection extends Base {
|
|||||||
* @returns the new ref
|
* @returns the new ref
|
||||||
*/
|
*/
|
||||||
async generateNewQRCodeRef() {
|
async generateNewQRCodeRef() {
|
||||||
const response = await this.query({json: ['admin', 'Conn', 'reref'], expect200: true, waitForOpen: false})
|
const response = await this.query({json: ['admin', 'Conn', 'reref'], expect200: true, waitForOpen: false, longTag: true})
|
||||||
return response.ref as string
|
return response.ref as string
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ export class WAConnection extends Base {
|
|||||||
const oldChats = this.chats
|
const oldChats = this.chats
|
||||||
const updatedChats: { [k: string]: Partial<WAChat> } = {}
|
const updatedChats: { [k: string]: Partial<WAChat> } = {}
|
||||||
|
|
||||||
for (let chat of chats.all()) {
|
chats.all().forEach (chat => {
|
||||||
const respectiveContact = contacts[chat.jid]
|
const respectiveContact = contacts[chat.jid]
|
||||||
chat.name = respectiveContact?.name || respectiveContact?.notify || chat.name
|
chat.name = respectiveContact?.name || respectiveContact?.notify || chat.name
|
||||||
|
|
||||||
@@ -246,8 +246,8 @@ export class WAConnection extends Base {
|
|||||||
delete changes.messages
|
delete changes.messages
|
||||||
updatedChats[chat.jid] = changes
|
updatedChats[chat.jid] = changes
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
this.chats = chats
|
this.chats = chats
|
||||||
this.contacts = contacts
|
this.contacts = contacts
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export interface WAQuery {
|
|||||||
tag?: string
|
tag?: string
|
||||||
expect200?: boolean
|
expect200?: boolean
|
||||||
waitForOpen?: boolean
|
waitForOpen?: boolean
|
||||||
|
longTag?: boolean
|
||||||
}
|
}
|
||||||
export enum ReconnectMode {
|
export enum ReconnectMode {
|
||||||
/** does not reconnect */
|
/** does not reconnect */
|
||||||
|
|||||||
Reference in New Issue
Block a user