Handle updating of credentials

This commit is contained in:
Adhiraj
2020-10-02 14:19:04 +05:30
parent 67d82b4169
commit 0d13a15904
6 changed files with 54 additions and 13 deletions

View File

@@ -22,6 +22,13 @@ async function example() {
// attempt to reconnect at most 10 times // attempt to reconnect at most 10 times
conn.connectOptions.maxRetries = 10 conn.connectOptions.maxRetries = 10
conn.on ('credentials-updated', () => {
// save credentials whenever updated
console.log (`credentials updated`)
const authInfo = conn.base64EncodedAuthInfo() // get all the auth info we need to restore this session
fs.writeFileSync('./auth_info.json', JSON.stringify(authInfo, null, '\t')) // save this info to a file
})
// loads the auth file credentials if present // loads the auth file credentials if present
fs.existsSync('./auth_info.json') && conn.loadAuthInfo ('./auth_info.json') fs.existsSync('./auth_info.json') && conn.loadAuthInfo ('./auth_info.json')
// uncomment the following line to proxy the connection; some random proxy I got off of: https://proxyscrape.com/free-proxy-list // uncomment the following line to proxy the connection; some random proxy I got off of: https://proxyscrape.com/free-proxy-list
@@ -34,9 +41,6 @@ async function example() {
console.log('you have ' + conn.chats.length + ' chats & ' + Object.keys(conn.contacts).length + ' contacts') console.log('you have ' + conn.chats.length + ' chats & ' + Object.keys(conn.contacts).length + ' contacts')
console.log ('you have ' + unread.length + ' unread messages') console.log ('you have ' + unread.length + ' unread messages')
const authInfo = conn.base64EncodedAuthInfo() // get all the auth info we need to restore this session
fs.writeFileSync('./auth_info.json', JSON.stringify(authInfo, null, '\t')) // save this info to a file
/* Note: one can take this auth_info.json file and login again from any computer without having to scan the QR code, /* Note: one can take this auth_info.json file and login again from any computer without having to scan the QR code,
and get full access to one's WhatsApp. Despite the convenience, be careful with this file */ and get full access to one's WhatsApp. Despite the convenience, be careful with this file */
conn.on ('user-presence-update', json => console.log(json.id + ' presence is ' + json.type)) conn.on ('user-presence-update', json => console.log(json.id + ' presence is ' + json.type))

View File

@@ -84,14 +84,19 @@ console.log ("oh hello " + conn.user.name + "! You connected via a proxy")
You obviously don't want to keep scanning the QR code every time you want to connect. You obviously don't want to keep scanning the QR code every time you want to connect.
So, do the following every time you open a new connection: So, you can save the credentials to log back in via:
``` ts ``` ts
import * as fs from 'fs' import * as fs from 'fs'
const conn = new WAConnection() const conn = new WAConnection()
await conn.connect() // connect first // this will be called as soon as the credentials are updated
const creds = conn.base64EncodedAuthInfo () // contains all the keys you need to restore a session conn.on ('credentials-updated', () => {
fs.writeFileSync('./auth_info.json', JSON.stringify(creds, null, '\t')) // save JSON to file // save credentials whenever updated
console.log (`credentials updated!`)
const authInfo = conn.base64EncodedAuthInfo() // get all the auth info we need to restore this session
fs.writeFileSync('./auth_info.json', JSON.stringify(authInfo, null, '\t')) // save this info to a file
})
await conn.connect() // connect
``` ```
Then, to restore a session: Then, to restore a session:
@@ -108,11 +113,13 @@ await conn.connect()
If you're considering switching from a Chromium/Puppeteer based library, you can use WhatsApp Web's Browser credentials to restore sessions too: If you're considering switching from a Chromium/Puppeteer based library, you can use WhatsApp Web's Browser credentials to restore sessions too:
``` ts ``` ts
conn.loadAuthInfo ('./auth_info_browser.json') // use loaded credentials & timeout in 20s conn.loadAuthInfo ('./auth_info_browser.json')
await conn.connect() // works the same await conn.connect() // works the same
``` ```
See the browser credentials type in the docs. See the browser credentials type in the docs.
**Note**: Upon every successive connection, WA can update part of the stored credentials. Whenever that happens, the `credentials-updated` event is triggered, and you should probably update your saved credentials upon receiving that event. Not doing so *may* lead WA to log you out after a few weeks with a 419 error code.
## QR Callback ## QR Callback
If you want to do some custom processing with the QR code used to authenticate, you can register for the following event: If you want to do some custom processing with the QR code used to authenticate, you can register for the following event:
@@ -143,6 +150,10 @@ on (event: 'open', listener: (result: WAOpenResult) => void): this
on (event: 'connecting', listener: () => void): this on (event: 'connecting', listener: () => void): this
/** when the connection has closed */ /** when the connection has closed */
on (event: 'close', listener: (err: {reason?: DisconnectReason | string, isReconnecting: boolean}) => void): this on (event: 'close', listener: (err: {reason?: DisconnectReason | string, isReconnecting: boolean}) => void): this
/** when the connection has closed */
on (event: 'intermediate-close', listener: (err: {reason?: DisconnectReason | string}) => void): this
/** when WA updates the credentials */
on (event: 'credentials-updated', listener: (auth: AuthenticationCredentials) => void): this
/** when a new QR is generated, ready for scanning */ /** when a new QR is generated, ready for scanning */
on (event: 'qr', listener: (qr: string) => void): this on (event: 'qr', listener: (qr: string) => void): this
/** when the connection to the phone changes */ /** when the connection to the phone changes */

View File

@@ -33,10 +33,15 @@ describe('Test Connect', () => {
console.log('please be ready to scan with your phone') console.log('please be ready to scan with your phone')
const conn = new WAConnection() const conn = new WAConnection()
let credentialsUpdateCalled = false
conn.on ('credentials-updated', () => credentialsUpdateCalled = true)
await conn.connect () await conn.connect ()
assert.ok(conn.user?.jid) assert.ok(conn.user?.jid)
assert.ok(conn.user?.phone) assert.ok(conn.user?.phone)
assert.ok (conn.user?.imgUrl || conn.user.imgUrl === '') assert.ok (conn.user?.imgUrl || conn.user.imgUrl === '')
assert.ok (credentialsUpdateCalled)
assertChatDBIntegrity (conn) assertChatDBIntegrity (conn)
@@ -45,15 +50,19 @@ describe('Test Connect', () => {
}) })
it('should reconnect', async () => { it('should reconnect', async () => {
const conn = new WAConnection() const conn = new WAConnection()
let credentialsUpdateCalled = false
conn.on ('credentials-updated', () => credentialsUpdateCalled = true)
await conn.loadAuthInfo (auth).connect () await conn.loadAuthInfo (auth).connect ()
assert.ok(conn.user) assert.ok(conn.user)
assert.ok(conn.user.jid) assert.ok(conn.user.jid)
assert.ok (credentialsUpdateCalled)
assertChatDBIntegrity (conn) assertChatDBIntegrity (conn)
await conn.logout() await conn.logout()
conn.loadAuthInfo(auth) conn.loadAuthInfo(auth)
await conn.connect() await conn.connect()
.then (() => assert.fail('should not have reconnected')) .then (() => assert.fail('should not have reconnected'))
.catch (err => { .catch (err => {

View File

@@ -112,10 +112,22 @@ export class WAConnection extends Base {
}) as WAUser }) as WAUser
if (!json.secret) { if (!json.secret) {
let credsChanged = false
// if we didn't get a secret, we don't need it, we're validated // if we didn't get a secret, we don't need it, we're validated
if (json.clientToken && json.clientToken !== this.authInfo.clientToken) {
console.log (`change: ${this.authInfo.clientToken}, ${json.clientToken}`)
this.authInfo = { ...this.authInfo, clientToken: json.clientToken }
credsChanged = true
}
if (json.serverToken && json.serverToken !== this.authInfo.serverToken) {
this.authInfo = { ...this.authInfo, serverToken: json.serverToken }
credsChanged = true
}
if (credsChanged) {
this.emit ('credentials-updated', this.authInfo)
}
return onValidationSuccess() return onValidationSuccess()
} }
const secret = Buffer.from(json.secret, 'base64') const secret = Buffer.from(json.secret, 'base64')
if (secret.length !== 144) { if (secret.length !== 144) {
throw new Error ('incorrect secret length received: ' + secret.length) throw new Error ('incorrect secret length received: ' + secret.length)
@@ -153,6 +165,8 @@ export class WAConnection extends Base {
serverToken: json.serverToken, serverToken: json.serverToken,
clientID: this.authInfo.clientID, clientID: this.authInfo.clientID,
} }
this.emit ('credentials-updated', this.authInfo)
return onValidationSuccess() return onValidationSuccess()
} }
/** /**

View File

@@ -1,6 +1,6 @@
import * as QR from 'qrcode-terminal' import * as QR from 'qrcode-terminal'
import { WAConnection as Base } from './3.Connect' import { WAConnection as Base } from './3.Connect'
import { WAMessageStatusUpdate, WAMessage, WAContact, WAChat, WAMessageProto, WA_MESSAGE_STUB_TYPE, WA_MESSAGE_STATUS_TYPE, MessageLogLevel, PresenceUpdate, BaileysEvent, DisconnectReason, WANode, WAOpenResult, Presence } from './Constants' import { WAMessageStatusUpdate, WAMessage, WAContact, WAChat, WAMessageProto, WA_MESSAGE_STUB_TYPE, WA_MESSAGE_STATUS_TYPE, MessageLogLevel, PresenceUpdate, BaileysEvent, DisconnectReason, WANode, WAOpenResult, Presence, AuthenticationCredentials } from './Constants'
import { whatsappID, unixTimestampSeconds, isGroupID, toNumber, GET_MESSAGE_ID, WA_MESSAGE_ID, WA_MESSAGE_KEY } from './Utils' import { whatsappID, unixTimestampSeconds, isGroupID, toNumber, GET_MESSAGE_ID, WA_MESSAGE_ID, WA_MESSAGE_KEY } from './Utils'
import KeyedDB from '@adiwajshing/keyed-db' import KeyedDB from '@adiwajshing/keyed-db'
import { Mutex } from './Mutex' import { Mutex } from './Mutex'
@@ -322,6 +322,8 @@ export class WAConnection extends Base {
on (event: 'close', listener: (err: {reason?: DisconnectReason | string, isReconnecting: boolean}) => void): this on (event: 'close', listener: (err: {reason?: DisconnectReason | string, isReconnecting: boolean}) => void): this
/** when the connection has closed */ /** when the connection has closed */
on (event: 'intermediate-close', listener: (err: {reason?: DisconnectReason | string}) => void): this on (event: 'intermediate-close', listener: (err: {reason?: DisconnectReason | string}) => void): this
/** when WA updates the credentials */
on (event: 'credentials-updated', listener: (auth: AuthenticationCredentials) => void): this
/** when a new QR is generated, ready for scanning */ /** when a new QR is generated, ready for scanning */
on (event: 'qr', listener: (qr: string) => void): this on (event: 'qr', listener: (qr: string) => void): this
/** when the connection to the phone changes */ /** when the connection to the phone changes */

View File

@@ -431,4 +431,5 @@ export type BaileysEvent =
'group-participants-demote' | 'group-participants-demote' |
'group-settings-update' | 'group-settings-update' |
'group-description-update' | 'group-description-update' |
'received-pong' 'received-pong' |
'credentials-updated'