mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
chore: remove legacy code
This commit is contained in:
@@ -2,7 +2,7 @@ import EventEmitter from 'events'
|
||||
import { createReadStream } from 'fs'
|
||||
import { writeFile } from 'fs/promises'
|
||||
import { createInterface } from 'readline'
|
||||
import type { CommonBaileysEventEmitter } from '../Types'
|
||||
import type { BaileysEventEmitter } from '../Types'
|
||||
import { delay } from './generics'
|
||||
import { makeMutex } from './make-mutex'
|
||||
|
||||
@@ -11,7 +11,7 @@ import { makeMutex } from './make-mutex'
|
||||
* @param ev The event emitter to read events from
|
||||
* @param filename File to save to
|
||||
*/
|
||||
export const captureEventStream = (ev: CommonBaileysEventEmitter<any>, filename: string) => {
|
||||
export const captureEventStream = (ev: BaileysEventEmitter, filename: string) => {
|
||||
const oldEmit = ev.emit
|
||||
// write mutex so data is appended in order
|
||||
const writeMutex = makeMutex()
|
||||
@@ -36,7 +36,7 @@ export const captureEventStream = (ev: CommonBaileysEventEmitter<any>, filename:
|
||||
* @param delayIntervalMs delay between each event emit
|
||||
*/
|
||||
export const readAndEmitEventStream = (filename: string, delayIntervalMs: number = 0) => {
|
||||
const ev = new EventEmitter() as CommonBaileysEventEmitter<any>
|
||||
const ev = new EventEmitter() as BaileysEventEmitter
|
||||
|
||||
const fireEvents = async() => {
|
||||
// from: https://stackoverflow.com/questions/6156501/read-a-file-one-line-at-a-time-in-node-js
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import EventEmitter from 'events'
|
||||
import { Logger } from 'pino'
|
||||
import { proto } from '../../WAProto'
|
||||
import { AuthenticationCreds, BaileysEvent, BaileysEventEmitter, BaileysEventMap, BufferedEventData, Chat, Contact, WAMessage, WAMessageStatus } from '../Types'
|
||||
import { BaileysEvent, BaileysEventEmitter, BaileysEventMap, BufferedEventData, Chat, Contact, WAMessage, WAMessageStatus } from '../Types'
|
||||
import { updateMessageWithReaction, updateMessageWithReceipt } from './messages'
|
||||
import { isRealMessage, shouldIncrementChatUnread } from './process-message'
|
||||
|
||||
@@ -28,7 +28,7 @@ type BufferableEvent = typeof BUFFERABLE_EVENT[number]
|
||||
* this can make processing events extremely efficient -- since everything
|
||||
* can be done in a single transaction
|
||||
*/
|
||||
type BaileysEventData = Partial<BaileysEventMap<AuthenticationCreds>>
|
||||
type BaileysEventData = Partial<BaileysEventMap>
|
||||
|
||||
const BUFFERABLE_EVENT_SET = new Set<BaileysEvent>(BUFFERABLE_EVENT)
|
||||
|
||||
@@ -109,7 +109,7 @@ export const makeEventBuffer = (logger: Logger): BaileysBufferableEventEmitter =
|
||||
ev.off('event', listener)
|
||||
}
|
||||
},
|
||||
emit<T extends BaileysEvent>(event: BaileysEvent, evData: BaileysEventMap<AuthenticationCreds>[T]) {
|
||||
emit<T extends BaileysEvent>(event: BaileysEvent, evData: BaileysEventMap[T]) {
|
||||
if(isBuffering && BUFFERABLE_EVENT_SET.has(event)) {
|
||||
append(data, event as any, evData, logger)
|
||||
return true
|
||||
@@ -233,7 +233,7 @@ function append<E extends BufferableEvent>(
|
||||
|
||||
break
|
||||
case 'contacts.update':
|
||||
const contactUpdates = eventData as BaileysEventMap<any>['contacts.update']
|
||||
const contactUpdates = eventData as BaileysEventMap['contacts.update']
|
||||
for(const update of contactUpdates) {
|
||||
const id = update.id!
|
||||
// merge into prior upsert
|
||||
@@ -249,7 +249,7 @@ function append<E extends BufferableEvent>(
|
||||
|
||||
break
|
||||
case 'messages.upsert':
|
||||
const { messages, type } = eventData as BaileysEventMap<any>['messages.upsert']
|
||||
const { messages, type } = eventData as BaileysEventMap['messages.upsert']
|
||||
for(const message of messages) {
|
||||
const key = stringifyMessageKey(message.key)
|
||||
const existing = data.messageUpserts[key]
|
||||
@@ -273,7 +273,7 @@ function append<E extends BufferableEvent>(
|
||||
|
||||
break
|
||||
case 'messages.update':
|
||||
const msgUpdates = eventData as BaileysEventMap<any>['messages.update']
|
||||
const msgUpdates = eventData as BaileysEventMap['messages.update']
|
||||
for(const { key, update } of msgUpdates) {
|
||||
const keyStr = stringifyMessageKey(key)
|
||||
const existing = data.messageUpserts[keyStr]
|
||||
@@ -294,7 +294,7 @@ function append<E extends BufferableEvent>(
|
||||
|
||||
break
|
||||
case 'messages.delete':
|
||||
const deleteData = eventData as BaileysEventMap<any>['messages.delete']
|
||||
const deleteData = eventData as BaileysEventMap['messages.delete']
|
||||
if('keys' in deleteData) {
|
||||
const { keys } = deleteData
|
||||
for(const key of keys) {
|
||||
@@ -315,7 +315,7 @@ function append<E extends BufferableEvent>(
|
||||
|
||||
break
|
||||
case 'messages.reaction':
|
||||
const reactions = eventData as BaileysEventMap<any>['messages.reaction']
|
||||
const reactions = eventData as BaileysEventMap['messages.reaction']
|
||||
for(const { key, reaction } of reactions) {
|
||||
const keyStr = stringifyMessageKey(key)
|
||||
const existing = data.messageUpserts[keyStr]
|
||||
@@ -330,7 +330,7 @@ function append<E extends BufferableEvent>(
|
||||
|
||||
break
|
||||
case 'message-receipt.update':
|
||||
const receipts = eventData as BaileysEventMap<any>['message-receipt.update']
|
||||
const receipts = eventData as BaileysEventMap['message-receipt.update']
|
||||
for(const { key, receipt } of receipts) {
|
||||
const keyStr = stringifyMessageKey(key)
|
||||
const existing = data.messageUpserts[keyStr]
|
||||
@@ -345,7 +345,7 @@ function append<E extends BufferableEvent>(
|
||||
|
||||
break
|
||||
case 'groups.update':
|
||||
const groupUpdates = eventData as BaileysEventMap<any>['groups.update']
|
||||
const groupUpdates = eventData as BaileysEventMap['groups.update']
|
||||
for(const update of groupUpdates) {
|
||||
const id = update.id!
|
||||
const groupUpdate = data.groupUpdates[id] || { }
|
||||
|
||||
@@ -5,7 +5,7 @@ import { platform, release } from 'os'
|
||||
import { Logger } from 'pino'
|
||||
import { proto } from '../../WAProto'
|
||||
import { version as baileysVersion } from '../Defaults/baileys-version.json'
|
||||
import { BaileysEventMap, CommonBaileysEventEmitter, DisconnectReason, WACallUpdateType, WAVersion } from '../Types'
|
||||
import { BaileysEventEmitter, BaileysEventMap, DisconnectReason, WACallUpdateType, WAVersion } from '../Types'
|
||||
import { BinaryNode, getAllBinaryNodeChildren } from '../WABinary'
|
||||
|
||||
const PLATFORM_MAP = {
|
||||
@@ -165,9 +165,9 @@ export async function promiseTimeout<T>(ms: number | undefined, promise: (resolv
|
||||
// generate a random ID to attach to a message
|
||||
export const generateMessageID = () => 'BAE5' + randomBytes(6).toString('hex').toUpperCase()
|
||||
|
||||
export function bindWaitForEvent<T extends keyof BaileysEventMap<any>>(ev: CommonBaileysEventEmitter<any>, event: T) {
|
||||
return async(check: (u: BaileysEventMap<any>[T]) => boolean | undefined, timeoutMs?: number) => {
|
||||
let listener: (item: BaileysEventMap<any>[T]) => void
|
||||
export function bindWaitForEvent<T extends keyof BaileysEventMap>(ev: BaileysEventEmitter, event: T) {
|
||||
return async(check: (u: BaileysEventMap[T]) => boolean | undefined, timeoutMs?: number) => {
|
||||
let listener: (item: BaileysEventMap[T]) => void
|
||||
let closeListener: any
|
||||
await (
|
||||
promiseTimeout(
|
||||
@@ -200,9 +200,9 @@ export function bindWaitForEvent<T extends keyof BaileysEventMap<any>>(ev: Commo
|
||||
}
|
||||
}
|
||||
|
||||
export const bindWaitForConnectionUpdate = (ev: CommonBaileysEventEmitter<any>) => bindWaitForEvent(ev, 'connection.update')
|
||||
export const bindWaitForConnectionUpdate = (ev: BaileysEventEmitter) => bindWaitForEvent(ev, 'connection.update')
|
||||
|
||||
export const printQRIfNecessaryListener = (ev: CommonBaileysEventEmitter<any>, logger: Logger) => {
|
||||
export const printQRIfNecessaryListener = (ev: BaileysEventEmitter, logger: Logger) => {
|
||||
ev.on('connection.update', async({ qr }) => {
|
||||
if(qr) {
|
||||
const QR = await import('qrcode-terminal')
|
||||
|
||||
@@ -10,7 +10,6 @@ export * from './history'
|
||||
export * from './chat-utils'
|
||||
export * from './lt-hash'
|
||||
export * from './auth-utils'
|
||||
export * from './legacy-msgs'
|
||||
export * from './baileys-event-stream'
|
||||
export * from './use-single-file-auth-state'
|
||||
export * from './use-multi-file-auth-state'
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
import { Boom } from '@hapi/boom'
|
||||
import { randomBytes } from 'crypto'
|
||||
import { AuthenticationCreds, Contact, CurveKeyPair, DisconnectReason, LegacyAuthenticationCreds, WATag } from '../Types'
|
||||
import { decodeBinaryNodeLegacy, jidNormalizedUser } from '../WABinary'
|
||||
import { aesDecrypt, Curve, hkdf, hmacSign } from './crypto'
|
||||
import { BufferJSON } from './generics'
|
||||
|
||||
export const newLegacyAuthCreds = () => ({
|
||||
clientID: randomBytes(16).toString('base64')
|
||||
}) as LegacyAuthenticationCreds
|
||||
|
||||
export const decodeWAMessage = (
|
||||
message: Buffer | string,
|
||||
auth: { macKey: Buffer, encKey: Buffer },
|
||||
fromMe: boolean = false
|
||||
) => {
|
||||
let commaIndex = message.indexOf(',') // all whatsapp messages have a tag and a comma, followed by the actual message
|
||||
if(commaIndex < 0) {
|
||||
throw new Boom('invalid message', { data: message })
|
||||
} // if there was no comma, then this message must be not be valid
|
||||
|
||||
if(message[commaIndex + 1] === ',') {
|
||||
commaIndex += 1
|
||||
}
|
||||
|
||||
let data = message.slice(commaIndex + 1, message.length)
|
||||
|
||||
// get the message tag.
|
||||
// If a query was done, the server will respond with the same message tag we sent the query with
|
||||
const messageTag: string = message.slice(0, commaIndex).toString()
|
||||
let json: any
|
||||
let tags: WATag | undefined
|
||||
if(data.length) {
|
||||
const possiblyEnc = (data.length > 32 && data.length % 16 === 0)
|
||||
if(typeof data === 'string' || !possiblyEnc) {
|
||||
json = JSON.parse(data.toString()) // parse the JSON
|
||||
} else {
|
||||
try {
|
||||
json = JSON.parse(data.toString())
|
||||
} catch{
|
||||
const { macKey, encKey } = auth || {}
|
||||
if(!macKey || !encKey) {
|
||||
throw new Boom('recieved encrypted buffer when auth creds unavailable', { data: message, statusCode: DisconnectReason.badSession })
|
||||
}
|
||||
|
||||
/*
|
||||
If the data recieved was not a JSON, then it must be an encrypted message.
|
||||
Such a message can only be decrypted if we're connected successfully to the servers & have encryption keys
|
||||
*/
|
||||
if(fromMe) {
|
||||
tags = [data[0], data[1]]
|
||||
data = data.slice(2, data.length)
|
||||
}
|
||||
|
||||
const checksum = data.slice(0, 32) // the first 32 bytes of the buffer are the HMAC sign of the message
|
||||
data = data.slice(32, data.length) // the actual message
|
||||
const computedChecksum = hmacSign(data, macKey) // compute the sign of the message we recieved using our macKey
|
||||
|
||||
if(checksum.equals(computedChecksum)) {
|
||||
// the checksum the server sent, must match the one we computed for the message to be valid
|
||||
const decrypted = aesDecrypt(data, encKey) // decrypt using AES
|
||||
json = decodeBinaryNodeLegacy(decrypted, { index: 0 }) // decode the binary message into a JSON array
|
||||
} else {
|
||||
throw new Boom('Bad checksum', {
|
||||
data: {
|
||||
received: checksum.toString('hex'),
|
||||
computed: computedChecksum.toString('hex'),
|
||||
data: data.slice(0, 80).toString(),
|
||||
tag: messageTag,
|
||||
message: message.slice(0, 80).toString()
|
||||
},
|
||||
statusCode: DisconnectReason.badSession
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [messageTag, json, tags] as const
|
||||
}
|
||||
|
||||
/**
|
||||
* Once the QR code is scanned and we can validate our connection, or we resolved the challenge when logging back in
|
||||
* @private
|
||||
* @param json
|
||||
*/
|
||||
export const validateNewConnection = (
|
||||
json: { [_: string]: any },
|
||||
auth: LegacyAuthenticationCreds,
|
||||
curveKeys: CurveKeyPair
|
||||
) => {
|
||||
// set metadata: one's WhatsApp ID [cc][number]@s.whatsapp.net, name on WhatsApp, info about the phone
|
||||
const onValidationSuccess = () => {
|
||||
const user: Contact = {
|
||||
id: jidNormalizedUser(json.wid),
|
||||
name: json.pushname
|
||||
}
|
||||
return { user, auth, phone: json.phone }
|
||||
}
|
||||
|
||||
if(!json.secret) {
|
||||
// if we didn't get a secret, we don't need it, we're validated
|
||||
if(json.clientToken && json.clientToken !== auth.clientToken) {
|
||||
auth = { ...auth, clientToken: json.clientToken }
|
||||
}
|
||||
|
||||
if(json.serverToken && json.serverToken !== auth.serverToken) {
|
||||
auth = { ...auth, serverToken: json.serverToken }
|
||||
}
|
||||
|
||||
return onValidationSuccess()
|
||||
}
|
||||
|
||||
const secret = Buffer.from(json.secret, 'base64')
|
||||
if(secret.length !== 144) {
|
||||
throw new Error ('incorrect secret length received: ' + secret.length)
|
||||
}
|
||||
|
||||
// generate shared key from our private key & the secret shared by the server
|
||||
const sharedKey = Curve.sharedKey(curveKeys.private, secret.slice(0, 32))
|
||||
// expand the key to 80 bytes using HKDF
|
||||
const expandedKey = hkdf(sharedKey as Buffer, 80, { })
|
||||
|
||||
// perform HMAC validation.
|
||||
const hmacValidationKey = expandedKey.slice(32, 64)
|
||||
const hmacValidationMessage = Buffer.concat([secret.slice(0, 32), secret.slice(64, secret.length)])
|
||||
|
||||
const hmac = hmacSign(hmacValidationMessage, hmacValidationKey)
|
||||
|
||||
if(!hmac.equals(secret.slice(32, 64))) {
|
||||
// if the checksums didn't match
|
||||
throw new Boom('HMAC validation failed', { statusCode: 400 })
|
||||
}
|
||||
|
||||
// computed HMAC should equal secret[32:64]
|
||||
// expandedKey[64:] + secret[64:] are the keys, encrypted using AES, that are used to encrypt/decrypt the messages recieved from WhatsApp
|
||||
// they are encrypted using key: expandedKey[0:32]
|
||||
const encryptedAESKeys = Buffer.concat([
|
||||
expandedKey.slice(64, expandedKey.length),
|
||||
secret.slice(64, secret.length),
|
||||
])
|
||||
const decryptedKeys = aesDecrypt(encryptedAESKeys, expandedKey.slice(0, 32))
|
||||
// set the credentials
|
||||
auth = {
|
||||
encKey: decryptedKeys.slice(0, 32), // first 32 bytes form the key to encrypt/decrypt messages
|
||||
macKey: decryptedKeys.slice(32, 64), // last 32 bytes from the key to sign messages
|
||||
clientToken: json.clientToken,
|
||||
serverToken: json.serverToken,
|
||||
clientID: auth.clientID,
|
||||
}
|
||||
return onValidationSuccess()
|
||||
}
|
||||
|
||||
export const computeChallengeResponse = (challenge: string, auth: LegacyAuthenticationCreds) => {
|
||||
const bytes = Buffer.from(challenge, 'base64') // decode the base64 encoded challenge string
|
||||
const signed = hmacSign(bytes, auth.macKey).toString('base64') // sign the challenge string with our macKey
|
||||
return ['admin', 'challenge', signed, auth.serverToken, auth.clientID] // prepare to send this signed string with the serverToken & clientID
|
||||
}
|
||||
|
||||
export const useSingleFileLegacyAuthState = (file: string) => {
|
||||
// require fs here so that in case "fs" is not available -- the app does not crash
|
||||
const { readFileSync, writeFileSync, existsSync } = require('fs')
|
||||
let state: LegacyAuthenticationCreds
|
||||
|
||||
if(existsSync(file)) {
|
||||
state = JSON.parse(
|
||||
readFileSync(file, { encoding: 'utf-8' }),
|
||||
BufferJSON.reviver
|
||||
)
|
||||
if(typeof state.encKey === 'string') {
|
||||
state.encKey = Buffer.from(state.encKey, 'base64')
|
||||
}
|
||||
|
||||
if(typeof state.macKey === 'string') {
|
||||
state.macKey = Buffer.from(state.macKey, 'base64')
|
||||
}
|
||||
} else {
|
||||
state = newLegacyAuthCreds()
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
saveState: () => {
|
||||
const str = JSON.stringify(state, BufferJSON.replacer, 2)
|
||||
writeFileSync(file, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getAuthenticationCredsType = (creds: LegacyAuthenticationCreds | AuthenticationCreds) => {
|
||||
if('clientID' in creds && !!creds.clientID) {
|
||||
return 'legacy'
|
||||
}
|
||||
|
||||
if('noiseKey' in creds && !!creds.noiseKey) {
|
||||
return 'md'
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import { Readable, Transform } from 'stream'
|
||||
import { URL } from 'url'
|
||||
import { proto } from '../../WAProto'
|
||||
import { DEFAULT_ORIGIN, MEDIA_HKDF_KEY_MAPPING, MEDIA_PATH_MAP } from '../Defaults'
|
||||
import { BaileysEventMap, CommonSocketConfig, DownloadableMessage, MediaConnInfo, MediaDecryptionKeyInfo, MediaType, MessageType, WAGenericMediaMessage, WAMediaUpload, WAMediaUploadFunction, WAMessageContent } from '../Types'
|
||||
import { BaileysEventMap, DownloadableMessage, MediaConnInfo, MediaDecryptionKeyInfo, MediaType, MessageType, SocketConfig, WAGenericMediaMessage, WAMediaUpload, WAMediaUploadFunction, WAMessageContent } from '../Types'
|
||||
import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildBuffer, jidNormalizedUser } from '../WABinary'
|
||||
import { aesDecryptGCM, aesEncryptGCM, hkdf } from './crypto'
|
||||
import { generateMessageID } from './generics'
|
||||
@@ -514,7 +514,7 @@ export function extensionForMediaMessage(message: WAMessageContent) {
|
||||
return extension
|
||||
}
|
||||
|
||||
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: CommonSocketConfig, refreshMediaConn: (force: boolean) => Promise<MediaConnInfo>): WAMediaUploadFunction => {
|
||||
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: SocketConfig, refreshMediaConn: (force: boolean) => Promise<MediaConnInfo>): WAMediaUploadFunction => {
|
||||
return async(stream, { mediaType, fileEncSha256B64, timeoutMs }) => {
|
||||
const { default: axios } = await import('axios')
|
||||
// send a query JSON to obtain the url & auth token to upload our media
|
||||
@@ -646,7 +646,7 @@ export const encryptMediaRetryRequest = (
|
||||
export const decodeMediaRetryNode = (node: BinaryNode) => {
|
||||
const rmrNode = getBinaryNodeChild(node, 'rmr')!
|
||||
|
||||
const event: BaileysEventMap<any>['messages.media-update'][number] = {
|
||||
const event: BaileysEventMap['messages.media-update'][number] = {
|
||||
key: {
|
||||
id: node.attrs.id,
|
||||
remoteJid: rmrNode.attrs.jid,
|
||||
|
||||
Reference in New Issue
Block a user