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
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ output.csv
|
||||
package-lock.json
|
||||
*/.DS_Store
|
||||
.DS_Store
|
||||
.env
|
||||
|
||||
@@ -17,7 +17,7 @@ export default class Encoder {
|
||||
this.pushBytes([(value >> 16) & 0x0f, (value >> 8) & 0xff, value & 0xff])
|
||||
}
|
||||
pushBytes(bytes: Uint8Array | Array<number>) {
|
||||
this.data.push(...bytes)
|
||||
this.data.push.apply(this.data, bytes)
|
||||
}
|
||||
pushString(str: string) {
|
||||
const bytes = new TextEncoder().encode(str)
|
||||
|
||||
@@ -1,53 +1,40 @@
|
||||
import {
|
||||
WAClient,
|
||||
AuthenticationCredentialsBase64,
|
||||
getNotificationType,
|
||||
MessageType,
|
||||
decodeMediaMessage,
|
||||
Presence,
|
||||
MessageOptions,
|
||||
Mimetype,
|
||||
WALocationMessage,
|
||||
MessageLogLevel,
|
||||
} from '../WAClient/WAClient'
|
||||
import fs from 'fs'
|
||||
import * as fs from 'fs'
|
||||
|
||||
async function example() {
|
||||
const client = new WAClient() // instantiate
|
||||
client.autoReconnect = true // auto reconnect on disconnect
|
||||
client.logUnhandledMessages = false // set to true to see what kind of stuff you can implement
|
||||
client.logLevel = MessageLogLevel.none // set to unhandled to see what kind of stuff you can implement
|
||||
|
||||
let authInfo: AuthenticationCredentialsBase64 = null
|
||||
try {
|
||||
const file = fs.readFileSync('auth_info.json') // load a closed session back if it exists
|
||||
authInfo = JSON.parse(file)
|
||||
} catch {}
|
||||
|
||||
// connect or timeout in 20 seconds
|
||||
const [user, chats, contacts, unread] = await client.connect(authInfo, 20 * 1000)
|
||||
// connect or timeout in 20 seconds (loads the auth file credentials if present)
|
||||
const [user, chats, contacts, unread] = await client.connect('./auth_info.json', 20 * 1000)
|
||||
|
||||
console.log('oh hello ' + user.name + ' (' + user.id + ')')
|
||||
console.log('you have ' + unread.length + ' unread messages')
|
||||
console.log('you have ' + chats.length + ' chats & ' + contacts.length + ' contacts')
|
||||
|
||||
authInfo = client.base64EncodedAuthInfo() // get all the auth info we need to restore this session
|
||||
const authInfo = client.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,
|
||||
and get full access to one's WhatsApp. Despite the convenience, be careful with this file */
|
||||
|
||||
client.setOnPresenceUpdate((json) => console.log(json.id + ' presence is ' + json.type))
|
||||
client.setOnMessageStatusChange((json) => {
|
||||
client.setOnPresenceUpdate(json => console.log(json.id + ' presence is ' + json.type))
|
||||
client.setOnMessageStatusChange(json => {
|
||||
const participant = json.participant ? ' (' + json.participant + ')' : '' // participant exists when the message is from a group
|
||||
console.log(
|
||||
json.to +
|
||||
participant +
|
||||
' acknowledged message(s) ' +
|
||||
json.ids +
|
||||
' as ' +
|
||||
json.type +
|
||||
' at ' +
|
||||
json.timestamp,
|
||||
)
|
||||
console.log(`${json.to}${participant} acknlowledged message(s) ${json.ids} as ${json.type}`)
|
||||
})
|
||||
client.setOnUnreadMessage(async (m) => {
|
||||
// set to false to NOT relay your own sent messages
|
||||
client.setOnUnreadMessage(true, async (m) => {
|
||||
const [notificationType, messageType] = getNotificationType(m) // get what type of notification it is -- message, group add notification etc.
|
||||
console.log('got notification of type: ' + notificationType)
|
||||
|
||||
@@ -74,32 +61,20 @@ async function example() {
|
||||
const contact = m.message.contactMessage
|
||||
console.log(sender + ' sent contact (' + contact.displayName + '): ' + contact.vcard)
|
||||
} else if (messageType === MessageType.location || messageType === MessageType.liveLocation) {
|
||||
const locMessage = m.message[messageType]
|
||||
console.log(
|
||||
sender +
|
||||
' sent location (lat: ' +
|
||||
locMessage.degreesLatitude +
|
||||
', long: ' +
|
||||
locMessage.degreesLongitude +
|
||||
'), saving thumbnail...',
|
||||
)
|
||||
decodeMediaMessage(m.message, 'loc_thumb_in_' + m.key.id)
|
||||
const locMessage = m.message[messageType] as WALocationMessage
|
||||
console.log(`${sender} sent location (lat: ${locMessage.degreesLatitude}, long: ${locMessage.degreesLongitude})`)
|
||||
|
||||
decodeMediaMessage(m.message, './Media/loc_thumb_in_' + m.key.id) // save location thumbnail
|
||||
|
||||
if (messageType === MessageType.liveLocation) {
|
||||
console.log(
|
||||
sender +
|
||||
' sent live location for duration: ' +
|
||||
m.duration / 60 +
|
||||
' minutes, seq number: ' +
|
||||
locMessage.sequenceNumber,
|
||||
)
|
||||
console.log(`${sender} sent live location for duration: ${m.duration/60}`)
|
||||
}
|
||||
} else {
|
||||
// if it is a media (audio, image, video) message
|
||||
// decode, decrypt & save the media.
|
||||
// The extension to the is applied automatically based on the media type
|
||||
try {
|
||||
const savedFile = await decodeMediaMessage(m.message, 'media_in_' + m.key.id)
|
||||
const savedFile = await decodeMediaMessage(m.message, './Media/media_in_' + m.key.id)
|
||||
console.log(sender + ' sent media, saved at: ' + savedFile)
|
||||
} catch (err) {
|
||||
console.log('error in decoding message: ' + err)
|
||||
@@ -124,21 +99,22 @@ async function example() {
|
||||
content = { degreesLatitude: 32.123123, degreesLongitude: 12.12123123 }
|
||||
type = MessageType.location
|
||||
} else {
|
||||
content = fs.readFileSync('example/ma_gif.mp4') // load the gif
|
||||
content = fs.readFileSync('./Media/ma_gif.mp4') // load the gif
|
||||
options.mimetype = Mimetype.gif
|
||||
type = MessageType.video
|
||||
}
|
||||
const response = await client.sendMessage(m.key.remoteJid, content, type, options)
|
||||
console.log("sent message with ID '" + response.messageID + "' successfully: " + (response.status === 200))
|
||||
}, 3 * 1000)
|
||||
}, true) // set to false to not relay your own sent messages
|
||||
})
|
||||
|
||||
/* example of custom functionality for tracking battery */
|
||||
client.registerCallback(['action', null, 'battery'], (json) => {
|
||||
client.registerCallback(['action', null, 'battery'], json => {
|
||||
const batteryLevelStr = json[2][0][1].value
|
||||
const batterylevel = parseInt(batteryLevelStr)
|
||||
console.log('battery level: ' + batterylevel)
|
||||
})
|
||||
client.setOnUnexpectedDisconnect((err) => console.log('disconnected unexpectedly: ' + err))
|
||||
client.setOnUnexpectedDisconnect(err => console.log('disconnected unexpectedly: ' + err))
|
||||
}
|
||||
|
||||
example().catch((err) => console.log(`encountered error: ${err}`))
|
||||
|
||||
2
Media/.gitkeep
Normal file
2
Media/.gitkeep
Normal file
@@ -0,0 +1,2 @@
|
||||
ma_gif.mp4
|
||||
meme.jpeg
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
WAGroupCreateResponse,
|
||||
WAGroupMetadata,
|
||||
WAGroupModification,
|
||||
MessageLogLevel,
|
||||
} from '../WAConnection/Constants'
|
||||
import { generateMessageTag } from '../WAConnection/Utils'
|
||||
|
||||
@@ -51,7 +52,7 @@ export default class WhatsAppWebBase extends WAConnection {
|
||||
if (!message.key.fromMe || callbackOnMyMessages) {
|
||||
// if this message was sent to us, notify
|
||||
callback(message as WAMessage)
|
||||
} else if (this.logUnhandledMessages) {
|
||||
} else if (this.logLevel >= MessageLogLevel.unhandled) {
|
||||
this.log(`[Unhandled] message - ${JSON.stringify(message)}`)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
import { WAClient } from './WAClient'
|
||||
import { MessageType, MessageOptions, Mimetype, Presence } from './Constants'
|
||||
import fs from 'fs'
|
||||
import * as fs from 'fs'
|
||||
import * as assert from 'assert'
|
||||
|
||||
import assert from 'assert'
|
||||
import { decodeMediaMessage } from './Utils'
|
||||
import { promiseTimeout } from '../WAConnection/Utils'
|
||||
|
||||
const testJid = '919646328797@s.whatsapp.net'
|
||||
const createTimeout = (timeout) => new Promise((resolve) => setTimeout(resolve, timeout))
|
||||
require ('dotenv').config () // dotenv to load test jid
|
||||
const testJid = process.env.TEST_JID // set TEST_JID=xyz@s.whatsapp.net in a .env file in the root directory
|
||||
|
||||
const createTimeout = (timeout) => new Promise(resolve => setTimeout(resolve, timeout))
|
||||
|
||||
async function sendAndRetreiveMessage(client: WAClient, content, type: MessageType, options: MessageOptions = {}) {
|
||||
const response = await client.sendMessage(testJid, content, type, options)
|
||||
assert.equal(response.status, 200)
|
||||
assert.strictEqual(response.status, 200)
|
||||
const messages = await client.loadConversation(testJid, 1, null, true)
|
||||
assert.equal(messages[0].key.id, response.messageID)
|
||||
assert.strictEqual(messages[0].key.id, response.messageID)
|
||||
return messages[0]
|
||||
}
|
||||
function WAClientTest(name: string, func: (client: WAClient) => void) {
|
||||
describe(name, () => {
|
||||
const client = new WAClient()
|
||||
console.log (`test jid: ${testJid}`)
|
||||
before(async () => {
|
||||
const file = './auth_info.json'
|
||||
await client.connectSlim(file)
|
||||
@@ -31,14 +34,14 @@ function WAClientTest(name: string, func: (client: WAClient) => void) {
|
||||
WAClientTest('Messages', (client) => {
|
||||
it('should send a text message', async () => {
|
||||
const message = await sendAndRetreiveMessage(client, 'hello fren', MessageType.text)
|
||||
assert.equal(message.message.conversation, 'hello fren')
|
||||
assert.strictEqual(message.message.conversation, 'hello fren')
|
||||
})
|
||||
it('should quote a message', async () => {
|
||||
const messages = await client.loadConversation(testJid, 2)
|
||||
const message = await sendAndRetreiveMessage(client, 'hello fren 2', MessageType.extendedText, {
|
||||
quoted: messages[0],
|
||||
})
|
||||
assert.equal(message.message.extendedTextMessage.contextInfo.stanzaId, messages[0].key.id)
|
||||
assert.strictEqual(message.message.extendedTextMessage.contextInfo.stanzaId, messages[0].key.id)
|
||||
})
|
||||
it('should send a gif', async () => {
|
||||
const content = fs.readFileSync('./Media/ma_gif.mp4')
|
||||
@@ -56,7 +59,7 @@ WAClientTest('Messages', (client) => {
|
||||
const content = fs.readFileSync('./Media/meme.jpeg')
|
||||
const message = await sendAndRetreiveMessage(client, content, MessageType.image, { quoted: messages[0] })
|
||||
const file = await decodeMediaMessage(message.message, './Media/received_img')
|
||||
assert.equal(message.message.imageMessage.contextInfo.stanzaId, messages[0].key.id)
|
||||
assert.strictEqual(message.message.imageMessage.contextInfo.stanzaId, messages[0].key.id)
|
||||
})
|
||||
})
|
||||
WAClientTest('Presence', (client) => {
|
||||
@@ -64,7 +67,7 @@ WAClientTest('Presence', (client) => {
|
||||
const presences = Object.values(Presence)
|
||||
for (const i in presences) {
|
||||
const response = await client.updatePresence(testJid, presences[i])
|
||||
assert.equal(response.status, 200)
|
||||
assert.strictEqual(response.status, 200)
|
||||
|
||||
await createTimeout(1500)
|
||||
}
|
||||
@@ -73,15 +76,15 @@ WAClientTest('Presence', (client) => {
|
||||
WAClientTest('Misc', (client) => {
|
||||
it('should tell if someone has an account on WhatsApp', async () => {
|
||||
const response = await client.isOnWhatsApp(testJid)
|
||||
assert.equal(response, true)
|
||||
assert.strictEqual(response, true)
|
||||
|
||||
const responseFail = await client.isOnWhatsApp('abcd@s.whatsapp.net')
|
||||
assert.equal(responseFail, false)
|
||||
assert.strictEqual(responseFail, false)
|
||||
})
|
||||
it('should return the status', async () => {
|
||||
const response = await client.getStatus(testJid)
|
||||
assert.ok(response.status)
|
||||
assert.equal(typeof response.status, 'string')
|
||||
assert.strictEqual(typeof response.status, 'string')
|
||||
})
|
||||
it('should return the profile picture', async () => {
|
||||
const response = await client.getProfilePicture(testJid)
|
||||
@@ -93,38 +96,38 @@ WAClientTest('Groups', (client) => {
|
||||
let gid: string
|
||||
it('should create a group', async () => {
|
||||
const response = await client.groupCreate('Cool Test Group', [testJid])
|
||||
assert.equal(response.status, 200)
|
||||
assert.strictEqual(response.status, 200)
|
||||
gid = response.gid
|
||||
console.log('created group: ' + gid)
|
||||
})
|
||||
it('should retreive group invite code', async () => {
|
||||
const code = await client.groupInviteCode(gid)
|
||||
assert.ok(code)
|
||||
assert.equal(typeof code, 'string')
|
||||
assert.strictEqual(typeof code, 'string')
|
||||
})
|
||||
it('should retreive group metadata', async () => {
|
||||
const metadata = await client.groupMetadata(gid)
|
||||
assert.equal(metadata.id, gid)
|
||||
assert.equal(metadata.participants.filter((obj) => obj.id.split('@')[0] === testJid.split('@')[0]).length, 1)
|
||||
assert.strictEqual(metadata.id, gid)
|
||||
assert.strictEqual(metadata.participants.filter((obj) => obj.id.split('@')[0] === testJid.split('@')[0]).length, 1)
|
||||
})
|
||||
it('should send a message on the group', async () => {
|
||||
const r = await client.sendMessage(gid, 'hello', MessageType.text)
|
||||
assert.equal(r.status, 200)
|
||||
assert.strictEqual(r.status, 200)
|
||||
})
|
||||
it('should update the subject', async () => {
|
||||
const subject = 'V Cool Title'
|
||||
const r = await client.groupUpdateSubject(gid, subject)
|
||||
assert.equal(r.status, 200)
|
||||
assert.strictEqual(r.status, 200)
|
||||
|
||||
const metadata = await client.groupMetadata(gid)
|
||||
assert.equal(metadata.subject, subject)
|
||||
assert.strictEqual(metadata.subject, subject)
|
||||
})
|
||||
it('should remove someone from a group', async () => {
|
||||
await client.groupRemove(gid, [testJid])
|
||||
})
|
||||
it('should leave the group', async () => {
|
||||
const response = await client.groupLeave(gid)
|
||||
assert.equal(response.status, 200)
|
||||
assert.strictEqual(response.status, 200)
|
||||
})
|
||||
})
|
||||
WAClientTest('Events', (client) => {
|
||||
@@ -146,7 +149,12 @@ WAClientTest('Events', (client) => {
|
||||
console.log (presence)
|
||||
})
|
||||
const response = await client.requestPresenceUpdate (client.userMetaData)
|
||||
assert.equal (response.status, 200)
|
||||
assert.strictEqual (response.status, 200)
|
||||
await createTimeout (25000)
|
||||
})*/
|
||||
})
|
||||
/*WAClientTest ('Testz', client => {
|
||||
it ('should work', async () => {
|
||||
|
||||
})
|
||||
})*/
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MessageType, HKDFInfoKeys, MessageOptions, MessageStubTypes } from './Constants'
|
||||
import sharp from 'sharp'
|
||||
import fs from 'fs'
|
||||
import * as sharp from 'sharp'
|
||||
import * as fs from 'fs'
|
||||
import fetch from 'node-fetch'
|
||||
import { WAMessage, WAMessageContent } from '../WAConnection/Constants'
|
||||
import { hmacSign, aesDecryptWithIV, hkdf } from '../WAConnection/Utils'
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
15
package-lock.json
generated
15
package-lock.json
generated
@@ -140,6 +140,15 @@
|
||||
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/ws": {
|
||||
"version": "7.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.6.tgz",
|
||||
"integrity": "sha512-Q07IrQUSNpr+cXU4E4LtkSIBPie5GLZyyMC1QtQYRLWz701+XcoVygGUZgvLqElq1nU4ICldMYPnexlBsg3dqQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.5.0.tgz",
|
||||
@@ -722,6 +731,12 @@
|
||||
"esutils": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
|
||||
"dev": true
|
||||
},
|
||||
"dynamic-dedupe": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"lint": "eslint '*/*.ts' --quiet --fix",
|
||||
"tsc": "tsc",
|
||||
"dev": "ts-node-dev --respawn --transpileOnly ./app/app.ts",
|
||||
"prod": "tsc && node ./build/app.js"
|
||||
"example": "npx ts-node Example/example.ts"
|
||||
},
|
||||
"author": "Adhiraj Singh",
|
||||
"license": "MIT",
|
||||
@@ -40,9 +40,11 @@
|
||||
"@types/mocha": "^7.0.2",
|
||||
"@types/node": "^14.0.14",
|
||||
"@types/sharp": "^0.25.0",
|
||||
"@types/ws": "^7.2.6",
|
||||
"@typescript-eslint/eslint-plugin": "^3.5.0",
|
||||
"@typescript-eslint/parser": "^3.5.0",
|
||||
"assert": "^2.0.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"eslint": "^7.3.1",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
|
||||
Reference in New Issue
Block a user