mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
Update init method to try login multiple times + use WA ttl for QR gen
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import * as Curve from 'curve25519-js'
|
||||
import * as Utils from './Utils'
|
||||
import {WAConnection as Base} from './0.Base'
|
||||
import { WAMetric, WAFlag, BaileysError, Presence, WAUser } from './Constants'
|
||||
import { WAMetric, WAFlag, BaileysError, Presence, WAUser, WAInitResponse } from './Constants'
|
||||
|
||||
export class WAConnection extends Base {
|
||||
|
||||
@@ -12,72 +12,73 @@ export class WAConnection extends Base {
|
||||
if (!this.authInfo?.clientID) {
|
||||
this.authInfo = { clientID: Utils.generateClientID() } as any
|
||||
}
|
||||
const canLogin = this.authInfo?.encKey && this.authInfo?.macKey
|
||||
const canLogin = this.canLogin()
|
||||
this.referenceDate = new Date () // refresh reference date
|
||||
let isNewUser = false
|
||||
|
||||
this.startDebouncedTimeout ()
|
||||
|
||||
const initQueries = [
|
||||
(async () => {
|
||||
const {ref} = await this.query({
|
||||
json: ['admin', 'init', this.version, this.browserDescription, this.authInfo?.clientID, true],
|
||||
expect200: true,
|
||||
waitForOpen: false,
|
||||
longTag: true,
|
||||
requiresPhoneConnection: false,
|
||||
startDebouncedTimeout: true
|
||||
})
|
||||
if (!canLogin) {
|
||||
this.stopDebouncedTimeout () // stop the debounced timeout for QR gen
|
||||
const result = await this.generateKeysForAuth (ref)
|
||||
this.startDebouncedTimeout () // restart debounced timeout
|
||||
return result
|
||||
}
|
||||
})()
|
||||
]
|
||||
const initQuery = (async () => {
|
||||
const {ref, ttl} = await this.query({
|
||||
json: ['admin', 'init', this.version, this.browserDescription, this.authInfo?.clientID, true],
|
||||
expect200: true,
|
||||
waitForOpen: false,
|
||||
longTag: true,
|
||||
requiresPhoneConnection: false,
|
||||
startDebouncedTimeout: true
|
||||
}) as WAInitResponse
|
||||
|
||||
if (!canLogin) {
|
||||
this.stopDebouncedTimeout () // stop the debounced timeout for QR gen
|
||||
this.generateKeysForAuth (ref, ttl)
|
||||
}
|
||||
})();
|
||||
if (canLogin) {
|
||||
// if we have the info to restore a closed session
|
||||
initQueries.push (
|
||||
(async () => {
|
||||
const json = [
|
||||
'admin',
|
||||
'login',
|
||||
this.authInfo?.clientToken,
|
||||
this.authInfo?.serverToken,
|
||||
this.authInfo?.clientID,
|
||||
]
|
||||
if (reconnect) json.push(...['reconnect', reconnect.replace('@s.whatsapp.net', '@c.us')])
|
||||
else json.push ('takeover')
|
||||
|
||||
let response = await this.query({
|
||||
json,
|
||||
tag: 's1',
|
||||
waitForOpen: false,
|
||||
expect200: true,
|
||||
longTag: true,
|
||||
requiresPhoneConnection: false,
|
||||
startDebouncedTimeout: true
|
||||
}) // wait for response with tag "s1"
|
||||
// if its a challenge request (we get it when logging in)
|
||||
if (response[1]?.challenge) {
|
||||
await this.respondToChallenge(response[1].challenge)
|
||||
response = await this.waitForMessage('s2', [], true)
|
||||
}
|
||||
return response
|
||||
})()
|
||||
)
|
||||
const json = [
|
||||
'admin',
|
||||
'login',
|
||||
this.authInfo?.clientToken,
|
||||
this.authInfo?.serverToken,
|
||||
this.authInfo?.clientID,
|
||||
]
|
||||
const tag = this.generateMessageTag(true)
|
||||
|
||||
if (reconnect) json.push(...['reconnect', reconnect.replace('@s.whatsapp.net', '@c.us')])
|
||||
else json.push ('takeover')
|
||||
// send login every 10s
|
||||
const sendLoginReq = () => {
|
||||
this.logger.debug('sending login request')
|
||||
this.sendJSON(json, tag)
|
||||
this.initTimeout = setTimeout(sendLoginReq, 10_000)
|
||||
}
|
||||
sendLoginReq()
|
||||
}
|
||||
|
||||
await initQuery
|
||||
|
||||
const validationJSON = (await Promise.all (initQueries)).slice(-1)[0] // get the last result
|
||||
const newUser = await this.validateNewConnection(validationJSON[1]) // validate the connection
|
||||
// wait for response with tag "s1"
|
||||
let response = await this.waitForMessage('s1', false, undefined)
|
||||
this.startDebouncedTimeout()
|
||||
this.initTimeout && clearTimeout (this.initTimeout)
|
||||
this.initTimeout = null
|
||||
|
||||
if (response.status && response.status !== 200) {
|
||||
throw new BaileysError(`Unexpected error in login`, { response, status: response.status })
|
||||
}
|
||||
// if its a challenge request (we get it when logging in)
|
||||
if (response[1]?.challenge) {
|
||||
await this.respondToChallenge(response[1].challenge)
|
||||
response = await this.waitForMessage('s2', true)
|
||||
}
|
||||
|
||||
const newUser = await this.validateNewConnection(response[1]) // validate the connection
|
||||
if (newUser.jid !== this.user?.jid) {
|
||||
isNewUser = true
|
||||
// clear out old data
|
||||
this.chats.clear()
|
||||
this.contacts = {}
|
||||
}
|
||||
|
||||
this.user = newUser
|
||||
|
||||
this.logger.info('validated connection successfully')
|
||||
@@ -95,7 +96,6 @@ export class WAConnection extends Base {
|
||||
}
|
||||
|
||||
this.sendPostConnectQueries ()
|
||||
|
||||
this.logger.debug('sent init queries')
|
||||
|
||||
return { isNewUser }
|
||||
@@ -110,22 +110,21 @@ export class WAConnection extends Base {
|
||||
this.sendBinary (['query', {type: 'quick_reply', epoch: '1'}, null], [ WAMetric.queryQuickReply, WAFlag.ignore ])
|
||||
this.sendBinary (['query', {type: 'label', epoch: '1'}, null], [ WAMetric.queryLabel, WAFlag.ignore ])
|
||||
this.sendBinary (['query', {type: 'emoji', epoch: '1'}, null], [ WAMetric.queryEmoji, WAFlag.ignore ])
|
||||
this.sendBinary (['action', {type: 'set', epoch: '1'}, [['presence', {type: Presence.available}, null]] ], [ WAMetric.presence, 160 ])
|
||||
this.sendBinary (['action', {type: 'set', epoch: '1'}, [['presence', {type: Presence.available}, null]] ], [ WAMetric.presence, WAFlag.available ])
|
||||
}
|
||||
/**
|
||||
* Refresh QR Code
|
||||
* @returns the new ref
|
||||
*/
|
||||
async generateNewQRCodeRef() {
|
||||
async requestNewQRCodeRef() {
|
||||
const response = await this.query({
|
||||
json: ['admin', 'Conn', 'reref'],
|
||||
expect200: true,
|
||||
waitForOpen: false,
|
||||
longTag: true,
|
||||
timeoutMs: this.connectOptions.maxIdleTimeMs,
|
||||
requiresPhoneConnection: false
|
||||
})
|
||||
return response.ref as string
|
||||
return response as WAInitResponse
|
||||
}
|
||||
/**
|
||||
* Once the QR code is scanned and we can validate our connection, or we resolved the challenge when logging back in
|
||||
@@ -211,41 +210,31 @@ export class WAConnection extends Base {
|
||||
return this.query({json, expect200: true, waitForOpen: false, startDebouncedTimeout: true})
|
||||
}
|
||||
/** When starting a new session, generate a QR code by generating a private/public key pair & the keys the server sends */
|
||||
protected async generateKeysForAuth(ref: string) {
|
||||
protected generateKeysForAuth(ref: string, ttl?: number) {
|
||||
this.curveKeys = Curve.generateKeyPair(Utils.randomBytes(32))
|
||||
const publicKey = Buffer.from(this.curveKeys.public).toString('base64')
|
||||
|
||||
const emitQR = () => {
|
||||
const qrLoop = ttl => {
|
||||
const qr = [ref, publicKey, this.authInfo.clientID].join(',')
|
||||
this.emit ('qr', qr)
|
||||
}
|
||||
|
||||
const regenQR = () => {
|
||||
this.qrTimeout = setTimeout (async () => {
|
||||
this.initTimeout = setTimeout (async () => {
|
||||
if (this.state === 'open') return
|
||||
|
||||
this.logger.debug ('regenerating QR')
|
||||
try {
|
||||
const newRef = await this.generateNewQRCodeRef ()
|
||||
const {ref: newRef, ttl} = await this.requestNewQRCodeRef()
|
||||
ref = newRef
|
||||
emitQR ()
|
||||
regenQR ()
|
||||
|
||||
qrLoop (ttl)
|
||||
} catch (error) {
|
||||
this.logger.warn ({ error }, `error in QR gen`)
|
||||
if (error.status === 429) { // too many QR requests
|
||||
this.emit ('ws-close', { reason: error.message })
|
||||
}
|
||||
}
|
||||
}, this.connectOptions.regenerateQRIntervalMs)
|
||||
}, ttl || 20_000) // default is 20s, on the off-chance ttl is not present
|
||||
}
|
||||
|
||||
emitQR ()
|
||||
if (this.connectOptions.regenerateQRIntervalMs) regenQR ()
|
||||
|
||||
const json = await this.waitForMessage('s1', [], false)
|
||||
this.qrTimeout && clearTimeout (this.qrTimeout)
|
||||
this.qrTimeout = null
|
||||
|
||||
return json
|
||||
qrLoop (ttl)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user