mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
Typescript update
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import WS from 'ws'
|
||||
import QR from 'qrcode-terminal'
|
||||
import fs from 'fs'
|
||||
import * as QR from 'qrcode-terminal'
|
||||
import * as fs from 'fs'
|
||||
import * as WS from 'ws'
|
||||
import * as Utils from './Utils'
|
||||
import Encoder from '../Binary/Encoder'
|
||||
import Decoder from '../Binary/Decoder'
|
||||
import { AuthenticationCredentials, UserMetaData, WANode, AuthenticationCredentialsBase64, WATag } from './Constants'
|
||||
import { AuthenticationCredentials, UserMetaData, WANode, AuthenticationCredentialsBase64, WATag, MessageLogLevel } from './Constants'
|
||||
|
||||
|
||||
/** Generate a QR code from the ref & the curve public key. This is scanned by the phone */
|
||||
const generateQRCode = function ([ref, publicKey, clientID]) {
|
||||
@@ -23,7 +24,7 @@ export default class WAConnectionBase {
|
||||
autoReconnect = true
|
||||
lastSeen: Date = null
|
||||
/** Log messages that are not handled, so you can debug & see what custom stuff you can implement */
|
||||
logUnhandledMessages = false
|
||||
logLevel: MessageLogLevel = MessageLogLevel.none
|
||||
/** Data structure of tokens & IDs used to establish one's identiy to WhatsApp Web */
|
||||
protected authInfo: AuthenticationCredentials = {
|
||||
clientID: null,
|
||||
@@ -259,6 +260,6 @@ export default class WAConnectionBase {
|
||||
}
|
||||
}
|
||||
protected log(text) {
|
||||
console.log(`[Baileys] ${text}`)
|
||||
console.log(`[Baileys][${new Date().toLocaleString()}] ${text}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import WS from 'ws'
|
||||
|
||||
import * as WS from 'ws'
|
||||
import * as Utils from './Utils'
|
||||
import { AuthenticationCredentialsBase64, UserMetaData, WAMessage, WAChat, WAContact } from './Constants'
|
||||
import { AuthenticationCredentialsBase64, UserMetaData, WAMessage, WAChat, WAContact, MessageLogLevel } from './Constants'
|
||||
import WAConnectionValidator from './Validation'
|
||||
|
||||
export default class WAConnectionConnector extends WAConnectionValidator {
|
||||
@@ -13,7 +12,7 @@ export default class WAConnectionConnector extends WAConnectionValidator {
|
||||
*/
|
||||
async connect(authInfo: AuthenticationCredentialsBase64 | string = null, timeoutMs: number = null) {
|
||||
const userInfo = await this.connectSlim(authInfo, timeoutMs)
|
||||
const chats = await this.receiveChatsAndContacts()
|
||||
const chats = await this.receiveChatsAndContacts(timeoutMs)
|
||||
return [userInfo, ...chats] as [UserMetaData, WAChat[], WAContact[], WAMessage[]]
|
||||
}
|
||||
/**
|
||||
@@ -31,7 +30,7 @@ export default class WAConnectionConnector extends WAConnectionValidator {
|
||||
try {
|
||||
this.loadAuthInfoFromBase64(authInfo)
|
||||
} catch {}
|
||||
|
||||
|
||||
this.conn = new WS('wss://web.whatsapp.com/ws', null, { origin: 'https://web.whatsapp.com' })
|
||||
|
||||
let promise: Promise<UserMetaData> = new Promise((resolve, reject) => {
|
||||
@@ -52,8 +51,8 @@ export default class WAConnectionConnector extends WAConnectionValidator {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
promise = timeoutMs ? Utils.promiseTimeout(timeoutMs, promise) : promise
|
||||
return promise.catch((err) => {
|
||||
promise = Utils.promiseTimeout(timeoutMs, promise)
|
||||
return promise.catch(err => {
|
||||
this.close()
|
||||
throw err
|
||||
})
|
||||
@@ -61,25 +60,31 @@ export default class WAConnectionConnector extends WAConnectionValidator {
|
||||
/**
|
||||
* Sets up callbacks to receive chats, contacts & unread messages.
|
||||
* Must be called immediately after connect
|
||||
* [chats, contacts, unreadMessages]
|
||||
* @returns [chats, contacts, unreadMessages]
|
||||
*/
|
||||
receiveChatsAndContacts() {
|
||||
const chats: Array<WAChat> = []
|
||||
async receiveChatsAndContacts(timeoutMs: number = null) {
|
||||
let chats: Array<WAChat> = []
|
||||
let contacts: Array<WAContact> = []
|
||||
const unreadMessages: Array<WAMessage> = []
|
||||
const unreadMap = {}
|
||||
let unreadMessages: Array<WAMessage> = []
|
||||
let unreadMap: Record<string, number> = {}
|
||||
|
||||
let encounteredAddBefore = false
|
||||
let receivedContacts = false
|
||||
let receivedMessages = false
|
||||
let convoResolve
|
||||
|
||||
this.log('waiting for chats & contacts') // wait for the message with chats
|
||||
const waitForConvos = () =>
|
||||
new Promise((resolve, _) => {
|
||||
convoResolve = resolve
|
||||
const chatUpdate = (json) => {
|
||||
new Promise(resolve => {
|
||||
convoResolve = () => {
|
||||
// de-register the callbacks, so that they don't get called again
|
||||
this.deregisterCallback(['action', 'add:last'])
|
||||
this.deregisterCallback(['action', 'add:before'])
|
||||
this.deregisterCallback(['action', 'add:unread'])
|
||||
resolve()
|
||||
}
|
||||
const chatUpdate = json => {
|
||||
receivedMessages = true
|
||||
const isLast = json[1].last
|
||||
encounteredAddBefore = json[1].add === 'before' ? true : encounteredAddBefore
|
||||
|
||||
json = json[2]
|
||||
if (json) {
|
||||
for (let k = json.length - 1; k >= 0; k--) {
|
||||
@@ -92,12 +97,8 @@ export default class WAConnectionConnector extends WAConnectionValidator {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isLast) {
|
||||
// de-register the callbacks, so that they don't get called again
|
||||
this.deregisterCallback(['action', 'add:last'])
|
||||
this.deregisterCallback(['action', 'add:before'])
|
||||
this.deregisterCallback(['action', 'add:unread'])
|
||||
resolve()
|
||||
if (isLast && receivedContacts) { // if received contacts before messages
|
||||
convoResolve ()
|
||||
}
|
||||
}
|
||||
// wait for actual messages to load, "last" is the most recent message, "before" contains prior messages
|
||||
@@ -105,22 +106,27 @@ export default class WAConnectionConnector extends WAConnectionValidator {
|
||||
this.registerCallback(['action', 'add:before'], chatUpdate)
|
||||
this.registerCallback(['action', 'add:unread'], chatUpdate)
|
||||
})
|
||||
const waitForChats = this.registerCallbackOneTime(['response', 'type:chat']).then((json) => {
|
||||
json[2].forEach((chat) => {
|
||||
const waitForChats = async () => {
|
||||
const json = await this.registerCallbackOneTime(['response', 'type:chat'])
|
||||
json[2].forEach(chat => {
|
||||
chats.push(chat[1]) // chats data (log json to see what it looks like)
|
||||
// store the number of unread messages for each sender
|
||||
unreadMap[chat[1].jid] = chat[1].count
|
||||
})
|
||||
if (chats && chats.length > 0) return waitForConvos()
|
||||
})
|
||||
const waitForContacts = this.registerCallbackOneTime(['response', 'type:contacts']).then((json) => {
|
||||
contacts = json[2].map((item) => item[1])
|
||||
// if no add:before messages are sent, and you receive contacts
|
||||
if (chats.length > 0) return waitForConvos()
|
||||
}
|
||||
const waitForContacts = async () => {
|
||||
const json = await this.registerCallbackOneTime(['response', 'type:contacts'])
|
||||
contacts = json[2].map(item => item[1])
|
||||
receivedContacts = true
|
||||
// if you receive contacts after messages
|
||||
// should probably resolve the promise
|
||||
if (!encounteredAddBefore && convoResolve) convoResolve()
|
||||
})
|
||||
if (receivedMessages) convoResolve()
|
||||
}
|
||||
// wait for the chats & contacts to load
|
||||
return Promise.all([waitForChats, waitForContacts]).then(() => [chats, contacts, unreadMessages])
|
||||
const promise = Promise.all([waitForChats(), waitForContacts()])
|
||||
await Utils.promiseTimeout (timeoutMs, promise)
|
||||
return [chats, contacts, unreadMessages] as [WAChat[], WAContact[], WAMessage[]]
|
||||
}
|
||||
private onMessageRecieved(message) {
|
||||
if (message[0] === '!') {
|
||||
@@ -170,6 +176,9 @@ export default class WAConnectionConnector extends WAConnectionValidator {
|
||||
// if we recieved a message that was encrypted but we don't have the keys, then there must be an error
|
||||
throw [3, 'recieved encrypted message when auth creds not available', message]
|
||||
}
|
||||
if (this.logLevel === MessageLogLevel.all) {
|
||||
this.log(messageTag + ', ' + JSON.stringify(json))
|
||||
}
|
||||
/*
|
||||
Check if this is a response to a message we sent
|
||||
*/
|
||||
@@ -214,7 +223,7 @@ export default class WAConnectionConnector extends WAConnectionValidator {
|
||||
return
|
||||
}
|
||||
}
|
||||
if (this.logUnhandledMessages) {
|
||||
if (this.logLevel === MessageLogLevel.unhandled) {
|
||||
this.log('[Unhandled] ' + messageTag + ', ' + JSON.stringify(json))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { WA } from '../Binary/Constants'
|
||||
import { proto } from '../Binary/WAMessage'
|
||||
|
||||
export enum MessageLogLevel {
|
||||
none=0,
|
||||
unhandled=1,
|
||||
all=2
|
||||
}
|
||||
export interface AuthenticationCredentials {
|
||||
clientID: string
|
||||
serverToken: string
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import assert from 'assert'
|
||||
import * as assert from 'assert'
|
||||
import WAConnection from './WAConnection'
|
||||
import { AuthenticationCredentialsBase64 } from './Constants'
|
||||
|
||||
@@ -22,17 +22,16 @@ describe('Test Connect', () => {
|
||||
it('should connect', async () => {
|
||||
console.log('please be ready to scan with your phone')
|
||||
const conn = new WAConnection()
|
||||
await assert.doesNotReject(async () => conn.connectSlim(null), 'initial connection failed')
|
||||
assert.ok(conn.userMetaData)
|
||||
assert.ok(conn.userMetaData.id)
|
||||
const user = await conn.connectSlim(null)
|
||||
assert.ok(user)
|
||||
assert.ok(user.id)
|
||||
|
||||
conn.close()
|
||||
auth = conn.base64EncodedAuthInfo()
|
||||
})
|
||||
it('should reconnect', async () => {
|
||||
const conn = new WAConnection()
|
||||
|
||||
const [user, chats, contacts, unread] = await conn.connect('./auth_info.json', 20 * 1000)
|
||||
const [user, chats, contacts, unread] = await conn.connect(auth, 20*1000)
|
||||
|
||||
assert.ok(user)
|
||||
assert.ok(user.id)
|
||||
@@ -55,4 +54,4 @@ describe('Test Connect', () => {
|
||||
|
||||
await assert.rejects(async () => conn.connectSlim(auth), 'reconnect should have failed')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import Crypto from 'crypto'
|
||||
import HKDF from 'futoin-hkdf'
|
||||
import * as Crypto from 'crypto'
|
||||
import * as HKDF from 'futoin-hkdf'
|
||||
|
||||
/** decrypt AES 256 CBC; where the IV is prefixed to the buffer */
|
||||
|
||||
@@ -38,6 +38,7 @@ export function randomBytes(length) {
|
||||
return Crypto.randomBytes(length)
|
||||
}
|
||||
export function promiseTimeout<T>(ms: number, promise: Promise<T>) {
|
||||
if (!ms) { return promise }
|
||||
// Create a promise that rejects in <ms> milliseconds
|
||||
const timeout = new Promise((_, reject) => {
|
||||
const id = setTimeout(() => {
|
||||
|
||||
Reference in New Issue
Block a user