lint: 0 warnings left

This commit is contained in:
Rajeh Taher
2024-10-14 05:15:10 +03:00
parent 61a0ff3178
commit 18ac07df8e
32 changed files with 652 additions and 1006 deletions

View File

@@ -6,5 +6,5 @@ coverage
src/WABinary/index.ts
WAProto
WASignalGroup
Example/test.ts
Example/Example.ts
docs

View File

@@ -1,5 +1,5 @@
{
"extends": "@adiwajshing",
"extends": "@whiskeysockets",
"parserOptions": {
"sourceType": "module",
"project": "./tsconfig.json"
@@ -21,13 +21,7 @@
"@typescript-eslint/no-unnecessary-type-assertion": [
"warn"
],
"no-restricted-syntax": [
"warn",
{
"selector": "TSEnumDeclaration",
"message": "Don't declare enums, use literals instead"
}
],
"no-restricted-syntax": "off",
"keyword-spacing": [
"warn"
]

View File

@@ -34,8 +34,8 @@
"changelog:update": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
"example": "node --inspect -r ts-node/register Example/example.ts",
"gen:protobuf": "sh WAProto/GenerateStatics.sh",
"lint": "eslint src --ext .js,.ts,.jsx,.tsx",
"lint:fix": "eslint src --fix --ext .js,.ts,.jsx,.tsx",
"lint": "eslint src --ext .js,.ts",
"lint:fix": "yarn lint --fix",
"prepack": "tsc",
"prepare": "tsc",
"release": "release-it",
@@ -44,6 +44,7 @@
"dependencies": {
"@adiwajshing/keyed-db": "^0.2.4",
"@hapi/boom": "^9.1.3",
"@whiskeysockets/eslint-config": "github:whiskeysockets/eslint-config",
"async-lock": "^1.4.1",
"audio-decode": "^2.1.3",
"axios": "^1.6.0",
@@ -60,7 +61,6 @@
"ws": "^8.13.0"
},
"devDependencies": {
"@adiwajshing/eslint-config": "github:adiwajshing/eslint-config",
"@types/got": "^9.6.11",
"@types/jest": "^27.5.1",
"@types/node": "^16.0.0",

View File

@@ -20,8 +20,6 @@ export const KEY_BUNDLE_TYPE = Buffer.from([5])
export const NOISE_WA_HEADER = Buffer.from(
[ 87, 65, 6, DICT_VERSION ]
) // last is "DICT_VERSION"
export const PROTOCOL_VERSION = [5, 2]
export const MOBILE_NOISE_HEADER = Buffer.concat([Buffer.from('WA'), Buffer.from(PROTOCOL_VERSION)])
/** from: https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url */
export const URL_REGEX = /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/

View File

@@ -999,15 +999,13 @@ export const makeChatsSocket = (config: SocketConfig) => {
)
}
if(receivedPendingNotifications) {
// if we don't have the app state key
if(receivedPendingNotifications && // if we don't have the app state key
// we keep buffering events until we finally have
// the key and can sync the messages
// todo scrutinize
if(!authState.creds?.myAppStateKeyId) {
ev.buffer()
needToFlushWithAppStateSync = true
}
!authState.creds?.myAppStateKeyId) {
ev.buffer()
needToFlushWithAppStateSync = true
}
})

View File

@@ -342,7 +342,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
break
case 'membership_approval_mode':
const approvalMode: any = getBinaryNodeChild(child, 'group_join')
const approvalMode = getBinaryNodeChild(child, 'group_join')
if(approvalMode) {
msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE
msg.messageStubParameters = [ approvalMode.attrs.state ]
@@ -574,8 +574,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
logger.debug({ participant, sendToAll }, 'forced new session for retry recp')
for(let i = 0; i < msgs.length;i++) {
const msg = msgs[i]
for(const [i, msg] of msgs.entries()) {
if(msg) {
updateSendMessageAgainCount(ids[i], participant)
const msgRelayOpts: MessageRelayOptions = { messageId: ids[i] }
@@ -761,10 +760,8 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
msg.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT, response]
}
if(msg.message?.protocolMessage?.type === proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER) {
if(node.attrs.sender_pn) {
ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn })
}
if(msg.message?.protocolMessage?.type === proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER && node.attrs.sender_pn) {
ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn })
}
try {
@@ -851,7 +848,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
return sendPeerDataOperationMessage(pdoMessage)
}
const requestPlaceholderResend = async(messageKey: WAMessageKey): Promise<'RESOLVED'| string | undefined> => {
const requestPlaceholderResend = async(messageKey: WAMessageKey): Promise<string | undefined> => {
if(!authState.creds.me?.id) {
throw new Boom('Not authenticated')
}

View File

@@ -280,7 +280,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
}
}
const meJid = jidNormalizedUser(authState.creds.me.id)!
const meJid = jidNormalizedUser(authState.creds.me.id)
const msgId = await relayMessage(meJid, protocolMessage, {
additionalAttributes: {

View File

@@ -76,7 +76,7 @@ export const makeSocket = (config: SocketConfig) => {
url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'))
}
const ws = config.socket ? config.socket : new WebSocketClient(url, config)
const ws = new WebSocketClient(url, config)
ws.connect()
@@ -327,11 +327,12 @@ export const makeSocket = (config: SocketConfig) => {
const l1 = frame.attrs || {}
const l2 = Array.isArray(frame.content) ? frame.content[0]?.tag : ''
Object.keys(l1).forEach(key => {
for(const key of Object.keys(l1)) {
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered
})
}
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered

View File

@@ -225,16 +225,14 @@ export default (config: BaileysInMemoryStoreConfig) => {
const list = assertMessageList(jid)
list.upsert(msg, 'append')
if(type === 'notify') {
if(!chats.get(jid)) {
ev.emit('chats.upsert', [
{
id: jid,
conversationTimestamp: toNumber(msg.messageTimestamp),
unreadCount: 1
}
])
}
if(type === 'notify' && !chats.get(jid)) {
ev.emit('chats.upsert', [
{
id: jid,
conversationTimestamp: toNumber(msg.messageTimestamp),
unreadCount: 1
}
])
}
}

View File

@@ -61,9 +61,9 @@ function makeOrderedDictionary<T>(idGetter: (item: T) => string) {
},
clear: () => {
array.splice(0, array.length)
Object.keys(dict).forEach(key => {
for(const key of Object.keys(dict)) {
delete dict[key]
})
}
},
filter: (contain: (item: T) => boolean) => {
let i = 0

View File

@@ -15,6 +15,6 @@ export interface Contact {
* null => if the profile picture has not been set (default profile picture)
* any other string => url of the profile picture
*/
imgUrl?: string | null | 'changed'
imgUrl?: string | null
status?: string
}

View File

@@ -23,7 +23,9 @@ export type WAGenericMediaMessage = proto.Message.IVideoMessage | proto.Message.
export import WAMessageStubType = proto.WebMessageInfo.StubType
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
export import WAMessageStatus = proto.WebMessageInfo.Status
export type WAMediaUpload = Buffer | { url: URL | string } | { stream: Readable }
export type WAMediaPayloadURL = { url: URL | string }
export type WAMediaPayloadStream = { stream: Readable }
export type WAMediaUpload = Buffer | WAMediaPayloadStream | WAMediaPayloadURL
/** Set of message types that are supported by the library */
export type MessageType = keyof proto.Message

View File

@@ -125,7 +125,4 @@ export type SocketConfig = {
cachedGroupMetadata: (jid: string) => Promise<GroupMetadata | undefined>
makeSignalRepository: (auth: SignalAuthState) => SignalRepository
/** Socket passthrough */
socket?: any
}

View File

@@ -160,6 +160,7 @@ export const addTransactionCapability = (
let tries = maxCommitRetries
while(tries) {
tries -= 1
//eslint-disable-next-line max-depth
try {
await state.set(mutations)
logger.trace({ dbQueriesInTransaction }, 'committed transaction')
@@ -207,6 +208,7 @@ export const initAuthCreds = (): AuthenticationCreds => {
accountSettings: {
unarchiveChats: false
},
registered: false,
pairingCode: undefined,
lastPropHash: undefined,
routingInfo: undefined,

View File

@@ -35,7 +35,7 @@ export const captureEventStream = (ev: BaileysEventEmitter, filename: string) =>
* @param filename filename containing event data
* @param delayIntervalMs delay between each event emit
*/
export const readAndEmitEventStream = (filename: string, delayIntervalMs: number = 0) => {
export const readAndEmitEventStream = (filename: string, delayIntervalMs = 0) => {
const ev = new EventEmitter() as BaileysEventEmitter
const fireEvents = async() => {

View File

@@ -38,7 +38,7 @@ const generateMac = (operation: proto.SyncdMutation.SyncdOperation, data: Buffer
}
const buff = Buffer.from([r])
return Buffer.concat([buff, Buffer.from(keyId as any, 'base64')])
return Buffer.concat([buff, Buffer.from(keyId as string, 'base64')])
}
const keyData = getKeyData()
@@ -144,7 +144,7 @@ export const encodeSyncdPatch = async(
})
const encoded = proto.SyncActionData.encode(dataProto).finish()
const keyValue = mutationKeys(key!.keyData!)
const keyValue = mutationKeys(key.keyData!)
const encValue = aesEncrypt(encoded, keyValue.valueEncryptionKey)
const valueMac = generateMac(operation, encValue, encKeyId, keyValue.valueMacKey)
@@ -196,7 +196,7 @@ export const decodeSyncdMutations = async(
// indexKey used to HMAC sign record.index.blob
// valueEncryptionKey used to AES-256-CBC encrypt record.value.blob[0:-32]
// the remaining record.value.blob[0:-32] is the mac, it the HMAC sign of key.keyId + decoded proto data + length of bytes in keyId
for(const msgMutation of msgMutations!) {
for(const msgMutation of msgMutations) {
// if it's a syncdmutation, get the operation property
// otherwise, if it's only a record -- it'll be a SET mutation
const operation = 'operation' in msgMutation ? msgMutation.operation : proto.SyncdMutation.SyncdOperation.SET
@@ -236,7 +236,7 @@ export const decodeSyncdMutations = async(
return ltGenerator.finish()
async function getKey(keyId: Uint8Array) {
const base64Key = Buffer.from(keyId!).toString('base64')
const base64Key = Buffer.from(keyId).toString('base64')
const keyEnc = await getAppStateSyncKey(base64Key)
if(!keyEnc) {
throw new Boom(`failed to find key "${base64Key}" to decode mutation`, { statusCode: 404, data: { msgMutations } })
@@ -264,19 +264,19 @@ export const decodeSyncdPatch = async(
const mainKey = mutationKeys(mainKeyObj.keyData!)
const mutationmacs = msg.mutations!.map(mutation => mutation.record!.value!.blob!.slice(-32))
const patchMac = generatePatchMac(msg.snapshotMac!, mutationmacs, toNumber(msg.version!.version!), name, mainKey.patchMacKey)
const patchMac = generatePatchMac(msg.snapshotMac!, mutationmacs, toNumber(msg.version!.version), name, mainKey.patchMacKey)
if(Buffer.compare(patchMac, msg.patchMac!) !== 0) {
throw new Boom('Invalid patch mac')
}
}
const result = await decodeSyncdMutations(msg!.mutations!, initialState, getAppStateSyncKey, onMutation, validateMacs)
const result = await decodeSyncdMutations(msg.mutations!, initialState, getAppStateSyncKey, onMutation, validateMacs)
return result
}
export const extractSyncdPatches = async(
result: BinaryNode,
options: AxiosRequestConfig<any>
options: AxiosRequestConfig<{}>
) => {
const syncNode = getBinaryNodeChild(result, 'sync')
const collectionNodes = getBinaryNodeChildren(syncNode, 'collection')
@@ -302,7 +302,7 @@ export const extractSyncdPatches = async(
}
const blobRef = proto.ExternalBlobReference.decode(
snapshotNode.content! as Buffer
snapshotNode.content as Buffer
)
const data = await downloadExternalBlob(blobRef, options)
snapshot = proto.SyncdSnapshot.decode(data)
@@ -314,7 +314,7 @@ export const extractSyncdPatches = async(
content = Buffer.from(Object.values(content))
}
const syncd = proto.SyncdPatch.decode(content! as Uint8Array)
const syncd = proto.SyncdPatch.decode(content as Uint8Array)
if(!syncd.version) {
syncd.version = { version: +collectionNode.attrs.version + 1 }
}
@@ -334,7 +334,7 @@ export const extractSyncdPatches = async(
export const downloadExternalBlob = async(
blob: proto.IExternalBlobReference,
options: AxiosRequestConfig<any>
options: AxiosRequestConfig<{}>
) => {
const stream = await downloadContentFromMessage(blob, 'md-app-state', { options })
const bufferArray: Buffer[] = []
@@ -347,7 +347,7 @@ export const downloadExternalBlob = async(
export const downloadExternalPatch = async(
blob: proto.IExternalBlobReference,
options: AxiosRequestConfig<any>
options: AxiosRequestConfig<{}>
) => {
const buffer = await downloadExternalBlob(blob, options)
const syncData = proto.SyncdMutations.decode(buffer)
@@ -359,10 +359,10 @@ export const decodeSyncdSnapshot = async(
snapshot: proto.ISyncdSnapshot,
getAppStateSyncKey: FetchAppStateSyncKey,
minimumVersionNumber: number | undefined,
validateMacs: boolean = true
validateMacs = true
) => {
const newState = newLTHashState()
newState.version = toNumber(snapshot.version!.version!)
newState.version = toNumber(snapshot.version!.version)
const mutationMap: ChatMutationMap = {}
const areMutationsRequired = typeof minimumVersionNumber === 'undefined'
@@ -408,10 +408,10 @@ export const decodePatches = async(
syncds: proto.ISyncdPatch[],
initial: LTHashState,
getAppStateSyncKey: FetchAppStateSyncKey,
options: AxiosRequestConfig<any>,
options: AxiosRequestConfig<{}>,
minimumVersionNumber?: number,
logger?: Logger,
validateMacs: boolean = true
validateMacs = true
) => {
const newState: LTHashState = {
...initial,
@@ -420,8 +420,7 @@ export const decodePatches = async(
const mutationMap: ChatMutationMap = {}
for(let i = 0; i < syncds.length; i++) {
const syncd = syncds[i]
for(const syncd of syncds) {
const { version, keyId, snapshotMac } = syncd
if(syncd.externalMutations) {
logger?.trace({ name, version }, 'downloading external patch')
@@ -430,7 +429,7 @@ export const decodePatches = async(
syncd.mutations?.push(...ref.mutations)
}
const patchVersion = toNumber(version!.version!)
const patchVersion = toNumber(version!.version)
newState.version = patchVersion
const shouldMutate = typeof minimumVersionNumber === 'undefined' || patchVersion > minimumVersionNumber
@@ -736,7 +735,7 @@ export const processSyncAction = (
{
id,
muteEndTime: action.muteAction?.muted
? toNumber(action.muteAction!.muteEndTimestamp!)
? toNumber(action.muteAction.muteEndTimestamp)
: null,
conditional: getChatUpdateConditional(id, undefined)
}
@@ -794,7 +793,7 @@ export const processSyncAction = (
]
})
} else if(action?.contactAction) {
ev.emit('contacts.upsert', [{ id, name: action.contactAction!.fullName! }])
ev.emit('contacts.upsert', [{ id, name: action.contactAction.fullName! }])
} else if(action?.pushNameSetting) {
const name = action?.pushNameSetting?.name
if(name && me?.name !== name) {
@@ -803,7 +802,7 @@ export const processSyncAction = (
} else if(action?.pinAction) {
ev.emit('chats.update', [{
id,
pinned: action.pinAction?.pinned ? toNumber(action.timestamp!) : null,
pinned: action.pinAction?.pinned ? toNumber(action.timestamp) : null,
conditional: getChatUpdateConditional(id, undefined)
}])
} else if(action?.unarchiveChatsSetting) {
@@ -831,7 +830,7 @@ export const processSyncAction = (
ev.emit('chats.delete', [id])
}
} else if(action?.labelEditAction) {
const { name, color, deleted, predefinedId } = action.labelEditAction!
const { name, color, deleted, predefinedId } = action.labelEditAction
ev.emit('labels.edit', {
id,

View File

@@ -177,6 +177,7 @@ export const decryptMessageNode = (
let msg: proto.IMessage = proto.Message.decode(e2eType !== 'plaintext' ? unpadRandomMax16(msgBuffer) : msgBuffer)
msg = msg.deviceSentMessage?.message || msg
if(msg.senderKeyDistributionMessage) {
//eslint-disable-next-line max-depth
try {
await repository.processSenderKeyDistributionMessage({
authorJid: author,

View File

@@ -42,6 +42,7 @@ type BaileysBufferableEventEmitter = BaileysEventEmitter & {
* */
buffer(): void
/** buffers all events till the promise completes */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
createBufferedFunction<A extends any[], T>(work: (...args: A) => Promise<T>): ((...args: A) => Promise<T>)
/**
* flushes all buffered events
@@ -132,7 +133,7 @@ export const makeEventBuffer = (logger: Logger): BaileysBufferableEventEmitter =
},
emit<T extends BaileysEvent>(event: BaileysEvent, evData: BaileysEventMap[T]) {
if(buffersInProgress && BUFFERABLE_EVENT_SET.has(event)) {
append(data, historyCache, event as any, evData, logger)
append(data, historyCache, event as BufferableEvent, evData, logger)
return true
}
@@ -187,6 +188,7 @@ function append<E extends BufferableEvent>(
data: BufferedEventData,
historyCache: Set<string>,
event: E,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventData: any,
logger: Logger
) {
@@ -331,7 +333,7 @@ function append<E extends BufferableEvent>(
}
if(data.contactUpdates[contact.id]) {
upsert = Object.assign(data.contactUpdates[contact.id], trimUndefined(contact))
upsert = Object.assign(data.contactUpdates[contact.id], trimUndefined(contact)) as Contact
delete data.contactUpdates[contact.id]
}
}
@@ -598,12 +600,10 @@ function consolidateEvents(data: BufferedEventData) {
}
function concatChats<C extends Partial<Chat>>(a: C, b: Partial<Chat>) {
if(b.unreadCount === null) {
// neutralize unread counter
if(a.unreadCount! < 0) {
a.unreadCount = undefined
b.unreadCount = undefined
}
if(b.unreadCount === null && // neutralize unread counter
a.unreadCount! < 0) {
a.unreadCount = undefined
b.unreadCount = undefined
}
if(typeof a.unreadCount === 'number' && typeof b.unreadCount === 'number') {

View File

@@ -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 { BaileysEventEmitter, BaileysEventMap, BrowsersMap, DisconnectReason, WACallUpdateType, WAVersion } from '../Types'
import { BaileysEventEmitter, BaileysEventMap, BrowsersMap, ConnectionState, DisconnectReason, WACallUpdateType, WAVersion } from '../Types'
import { BinaryNode, getAllBinaryNodeChildren, jidDecode } from '../WABinary'
const PLATFORM_MAP = {
@@ -33,6 +33,7 @@ export const getPlatformId = (browser: string) => {
}
export const BufferJSON = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
replacer: (k, value: any) => {
if(Buffer.isBuffer(value) || value instanceof Uint8Array || value?.type === 'Buffer') {
return { type: 'Buffer', data: Buffer.from(value?.data || value).toString('base64') }
@@ -40,6 +41,8 @@ export const BufferJSON = {
return value
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
reviver: (_, value: any) => {
if(typeof value === 'object' && !!value && (value.buffer === true || value.type === 'Buffer')) {
const val = value.data || value.value
@@ -52,7 +55,7 @@ export const BufferJSON = {
export const getKeyAuthor = (
key: proto.IMessageKey | undefined | null,
meId: string = 'me'
meId = 'me'
) => (
(key?.fromMe ? meId : key?.participant || key?.remoteJid) || ''
)
@@ -102,14 +105,14 @@ export const encodeBigEndian = (e: number, t = 4) => {
return a
}
export const toNumber = (t: Long | number | null | undefined): number => ((typeof t === 'object' && t) ? ('toNumber' in t ? t.toNumber() : (t as any).low) : t)
export const toNumber = (t: Long | number | null | undefined): number => ((typeof t === 'object' && t) ? ('toNumber' in t ? t.toNumber() : (t as Long).low) : t || 0)
/** unix timestamp of a date in seconds */
export const unixTimestampSeconds = (date: Date = new Date()) => Math.floor(date.getTime() / 1000)
export type DebouncedTimeout = ReturnType<typeof debouncedTimeout>
export const debouncedTimeout = (intervalMs: number = 1000, task?: () => void) => {
export const debouncedTimeout = (intervalMs = 1000, task?: () => void) => {
let timeout: NodeJS.Timeout | undefined
return {
start: (newIntervalMs?: number, newTask?: () => void) => {
@@ -184,9 +187,9 @@ export const generateMessageIDV2 = (userId?: string): string => {
const data = Buffer.alloc(8 + 20 + 16)
data.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)))
if (userId) {
if(userId) {
const id = jidDecode(userId)
if (id?.user) {
if(id?.user) {
data.write(id.user, 8)
data.write('@c.us', 8 + id.user.length)
}
@@ -205,7 +208,7 @@ export const generateMessageID = () => '3EB0' + randomBytes(18).toString('hex').
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
let closeListener: (state: Partial<ConnectionState>) => void
await (
promiseTimeout<void>(
timeoutMs,
@@ -256,7 +259,7 @@ export const printQRIfNecessaryListener = (ev: BaileysEventEmitter, logger: Logg
* utility that fetches latest baileys version from the master branch.
* Use to ensure your WA connection is always on the latest version
*/
export const fetchLatestBaileysVersion = async(options: AxiosRequestConfig<any> = { }) => {
export const fetchLatestBaileysVersion = async(options: AxiosRequestConfig<{}> = { }) => {
const URL = 'https://raw.githubusercontent.com/WhiskeySockets/Baileys/master/src/Defaults/baileys-version.json'
try {
const result = await axios.get<{ version: WAVersion }>(
@@ -283,7 +286,7 @@ export const fetchLatestBaileysVersion = async(options: AxiosRequestConfig<any>
* A utility that fetches the latest web version of whatsapp.
* Use to ensure your WA connection is always on the latest version
*/
export const fetchLatestWaWebVersion = async(options: AxiosRequestConfig<any>) => {
export const fetchLatestWaWebVersion = async(options: AxiosRequestConfig<{}>) => {
try {
const result = await axios.get(
'https://web.whatsapp.com/check-update?version=1&platform=web',
@@ -393,6 +396,7 @@ export const getCodeFromWSError = (error: Error) => {
statusCode = code
}
} else if(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(error as any)?.code?.startsWith('E')
|| error?.message?.includes('timed out')
) { // handle ETIMEOUT, ENOTFOUND etc
@@ -410,7 +414,8 @@ export const isWABusinessPlatform = (platform: string) => {
return platform === 'smbi' || platform === 'smba'
}
export function trimUndefined(obj: any) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function trimUndefined(obj: {[_: string]: any}) {
for(const key in obj) {
if(typeof obj[key] === 'undefined') {
delete obj[key]
@@ -427,8 +432,8 @@ export function bytesToCrockford(buffer: Buffer): string {
let bitCount = 0
const crockford: string[] = []
for(let i = 0; i < buffer.length; i++) {
value = (value << 8) | (buffer[i] & 0xff)
for(const element of buffer) {
value = (value << 8) | (element & 0xff)
bitCount += 8
while(bitCount >= 5) {

View File

@@ -12,7 +12,7 @@ const inflatePromise = promisify(inflate)
export const downloadHistory = async(
msg: proto.Message.IHistorySyncNotification,
options: AxiosRequestConfig<any>
options: AxiosRequestConfig<{}>
) => {
const stream = await downloadContentFromMessage(msg, 'md-msg-hist', { options })
const bufferArray: Buffer[] = []
@@ -101,7 +101,7 @@ export const processHistoryMessage = (item: proto.IHistorySync) => {
export const downloadAndProcessHistorySyncNotification = async(
msg: proto.Message.IHistorySyncNotification,
options: AxiosRequestConfig<any>
options: AxiosRequestConfig<{}>
) => {
const historyMsg = await downloadHistory(msg, options)
return processHistoryMessage(historyMsg)

View File

@@ -1,4 +1,5 @@
export const makeMutex = () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let task = Promise.resolve() as Promise<any>
let taskTimeout: NodeJS.Timeout | undefined

View File

@@ -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, DownloadableMessage, MediaConnInfo, MediaDecryptionKeyInfo, MediaType, MessageType, SocketConfig, WAGenericMediaMessage, WAMediaUpload, WAMediaUploadFunction, WAMessageContent } from '../Types'
import { BaileysEventMap, DownloadableMessage, MediaConnInfo, MediaDecryptionKeyInfo, MediaType, MessageType, SocketConfig, WAGenericMediaMessage, WAMediaPayloadURL, WAMediaUpload, WAMediaUploadFunction, WAMessageContent } from '../Types'
import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildBuffer, jidNormalizedUser } from '../WABinary'
import { aesDecryptGCM, aesEncryptGCM, hkdf } from './crypto'
import { generateMessageID } from './generics'
@@ -79,7 +79,7 @@ const extractVideoThumb = async(
destPath: string,
time: string,
size: { width: number, height: number },
) => new Promise((resolve, reject) => {
) => new Promise<void>((resolve, reject) => {
const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`
exec(cmd, (err) => {
if(err) {
@@ -88,7 +88,7 @@ const extractVideoThumb = async(
resolve()
}
})
}) as Promise<void>
})
export const extractImageThumb = async(bufferOrFilePath: Readable | Buffer | string, width = 32) => {
if(bufferOrFilePath instanceof Readable) {
@@ -97,7 +97,7 @@ export const extractImageThumb = async(bufferOrFilePath: Readable | Buffer | str
const lib = await getImageProcessingLibrary()
if('sharp' in lib && typeof lib.sharp?.default === 'function') {
const img = lib.sharp!.default(bufferOrFilePath)
const img = lib.sharp.default(bufferOrFilePath)
const dimensions = await img.metadata()
const buffer = await img
@@ -114,7 +114,7 @@ export const extractImageThumb = async(bufferOrFilePath: Readable | Buffer | str
} else if('jimp' in lib && typeof lib.jimp?.read === 'function') {
const { read, MIME_JPEG, RESIZE_BILINEAR, AUTO } = lib.jimp
const jimp = await read(bufferOrFilePath as any)
const jimp = await read(bufferOrFilePath as string)
const dimensions = {
width: jimp.getWidth(),
height: jimp.getHeight()
@@ -154,7 +154,7 @@ export const generateProfilePicture = async(mediaUpload: WAMediaUpload) => {
const lib = await getImageProcessingLibrary()
let img: Promise<Buffer>
if('sharp' in lib && typeof lib.sharp?.default === 'function') {
img = lib.sharp!.default(bufferOrFilePath)
img = lib.sharp.default(bufferOrFilePath)
.resize(640, 640)
.jpeg({
quality: 50,
@@ -162,7 +162,7 @@ export const generateProfilePicture = async(mediaUpload: WAMediaUpload) => {
.toBuffer()
} else if('jimp' in lib && typeof lib.jimp?.read === 'function') {
const { read, MIME_JPEG, RESIZE_BILINEAR } = lib.jimp
const jimp = await read(bufferOrFilePath as any)
const jimp = await read(bufferOrFilePath as string)
const min = Math.min(jimp.getWidth(), jimp.getHeight())
const cropped = jimp.crop(0, 0, min, min)
@@ -351,7 +351,7 @@ export const encryptedStream = async(
let writeStream: WriteStream | undefined
let didSaveToTmpPath = false
if(type === 'file') {
bodyPath = (media as any).url
bodyPath = (media as WAMediaPayloadURL).url.toString()
} else if(saveOriginalFileIfRequired) {
bodyPath = join(getTmpFilesDirectory(), mediaType + generateMessageID())
writeStream = createWriteStream(bodyPath)
@@ -382,10 +382,8 @@ export const encryptedStream = async(
}
sha256Plain = sha256Plain.update(data)
if(writeStream) {
if(!writeStream.write(data)) {
await once(writeStream, 'drain')
}
if(writeStream && !writeStream.write(data)) {
await once(writeStream, 'drain')
}
onChunk(aes.update(data))
@@ -455,7 +453,7 @@ const toSmallestChunkSize = (num: number) => {
export type MediaDownloadOptions = {
startByte?: number
endByte?: number
options?: AxiosRequestConfig<any>
options?: AxiosRequestConfig<{}>
}
export const getUrlFromDirectPath = (directPath: string) => `https://${DEF_HOST}${directPath}`
@@ -501,9 +499,9 @@ export const downloadEncryptedContent = async(
Origin: DEFAULT_ORIGIN,
}
if(startChunk || endChunk) {
headers!.Range = `bytes=${startChunk}-`
headers.Range = `bytes=${startChunk}-`
if(endChunk) {
headers!.Range += endChunk
headers.Range += endChunk
}
}
@@ -614,6 +612,7 @@ export const getWAUploadToServer = (
const auth = encodeURIComponent(uploadInfo.auth) // the auth token
const url = `https://${hostname}${MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let result: any
try {
@@ -770,9 +769,4 @@ const MEDIA_RETRY_STATUS_MAP = {
[proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
[proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
[proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
} as const
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function __importStar(arg0: any): any {
throw new Error('Function not implemented.')
}
} as const

View File

@@ -488,7 +488,7 @@ export const generateWAMessageContent = async(
options: message.poll.values.map(optionName => ({ optionName })),
}
if (message.poll.toAnnouncementGroup) {
if(message.poll.toAnnouncementGroup) {
// poll v2 is for community announcement groups (single select and multiple)
m.pollCreationMessageV2 = pollCreationMessage
} else {
@@ -859,17 +859,13 @@ export const downloadMediaMessage = async<Type extends 'buffer' | 'stream'>(
) => {
const result = await downloadMsg()
.catch(async(error) => {
if(ctx) {
if(axios.isAxiosError(error)) {
// check if the message requires a reupload
if(REUPLOAD_REQUIRED_STATUS.includes(error.response?.status!)) {
ctx.logger.info({ key: message.key }, 'sending reupload media request...')
// request reupload
message = await ctx.reuploadRequest(message)
const result = await downloadMsg()
return result
}
}
if(ctx && axios.isAxiosError(error) && // check if the message requires a reupload
REUPLOAD_REQUIRED_STATUS.includes(error.response?.status!)) {
ctx.logger.info({ key: message.key }, 'sending reupload media request...')
// request reupload
message = await ctx.reuploadRequest(message)
const result = await downloadMsg()
return result
}
throw error

View File

@@ -283,6 +283,7 @@ const processMessage = async(
const { peerDataOperationResult } = response
for(const result of peerDataOperationResult!) {
const { placeholderMessageResendResponse: retryResponse } = result
//eslint-disable-next-line max-depth
if(retryResponse) {
const webMessageInfo = proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes!)
// wait till another upsert event is available, don't want it to be part of the PDO response message

View File

@@ -73,7 +73,7 @@ export const parseAndInjectE2ESessions = async(
const extractKey = (key: BinaryNode) => (
key ? ({
keyId: getBinaryNodeChildUInt(key, 'id', 3)!,
publicKey: generateSignalPubKey(getBinaryNodeChildBuffer(key, 'value')!)!,
publicKey: generateSignalPubKey(getBinaryNodeChildBuffer(key, 'value')!),
signature: getBinaryNodeChildBuffer(key, 'signature')!,
}) : undefined
)
@@ -125,8 +125,10 @@ export const extractDeviceJids = (result: BinaryNode, myJid: string, excludeZero
const devicesNode = getBinaryNodeChild(item, 'devices')
const deviceListNode = getBinaryNodeChild(devicesNode, 'device-list')
if(Array.isArray(deviceListNode?.content)) {
//eslint-disable-next-line max-depth
for(const { tag, attrs } of deviceListNode!.content) {
const device = +attrs.id
//eslint-disable-next-line max-depth
if(
tag === 'device' && // ensure the "device" tag
(!excludeZeroDevices || device !== 0) && // if zero devices are not-excluded, or device is non zero

View File

@@ -21,7 +21,7 @@ const fileLock = new AsyncLock({ maxPending: Infinity })
* Would recommend writing an auth state for use with a proper SQL or No-SQL DB
* */
export const useMultiFileAuthState = async(folder: string): Promise<{ state: AuthenticationState, saveCreds: () => Promise<void> }> => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const writeData = (data: any, file: string) => {
const filePath = join(folder, fixFileName(file)!)
return fileLock.acquire(

View File

@@ -31,12 +31,12 @@ export const SINGLE_BYTE_TOKENS: (string | null)[] = [
export const TOKEN_MAP: { [token: string]: { dict?: number, index: number } } = { }
for(let i = 0;i < SINGLE_BYTE_TOKENS.length;i++) {
TOKEN_MAP[SINGLE_BYTE_TOKENS[i]!] = { index: i }
for(const [i, SINGLE_BYTE_TOKEN] of SINGLE_BYTE_TOKENS.entries()) {
TOKEN_MAP[SINGLE_BYTE_TOKEN!] = { index: i }
}
for(let i = 0;i < DOUBLE_BYTE_TOKENS.length;i++) {
for(let j = 0;j < DOUBLE_BYTE_TOKENS[i].length;j++) {
TOKEN_MAP[DOUBLE_BYTE_TOKENS[i][j]] = { dict: i, index: j }
for(const [i, DOUBLE_BYTE_TOKEN] of DOUBLE_BYTE_TOKENS.entries()) {
for(const [j, element] of DOUBLE_BYTE_TOKEN.entries()) {
TOKEN_MAP[element] = { dict: i, index: j }
}
}

View File

@@ -28,9 +28,12 @@ const encodeBinaryNodeInner = (
}
}
const pushBytes = (bytes: Uint8Array | Buffer | number[]) => (
bytes.forEach (b => buffer.push(b))
)
const pushBytes = (bytes: Uint8Array | Buffer | number[]) => {
for(const b of bytes) {
buffer.push(b)
}
}
const pushInt16 = (value: number) => {
pushBytes([(value >> 8) & 0xff, value & 0xff])
}
@@ -151,8 +154,7 @@ const encodeBinaryNodeInner = (
return false
}
for(let i = 0;i < str.length;i++) {
const char = str[i]
for(const char of str) {
const isInNibbleRange = char >= '0' && char <= '9'
if(!isInNibbleRange && char !== '-' && char !== '.') {
return false
@@ -167,8 +169,7 @@ const encodeBinaryNodeInner = (
return false
}
for(let i = 0;i < str.length;i++) {
const char = str[i]
for(const char of str) {
const isInNibbleRange = char >= '0' && char <= '9'
if(!isInNibbleRange && !(char >= 'A' && char <= 'F') && !(char >= 'a' && char <= 'f')) {
return false

View File

@@ -4,7 +4,7 @@ export const SERVER_JID = 'server@c.us'
export const PSA_WID = '0@c.us'
export const STORIES_JID = 'status@broadcast'
export type JidServer = 'c.us' | 'g.us' | 'broadcast' | 's.whatsapp.net' | 'call' | 'lid'
export type JidServer = 'c.us' | 'g.us' | 'broadcast' | 's.whatsapp.net' | 'call' | 'lid' | 'newsletter'
export type JidWithDevice = {
user: string
@@ -12,7 +12,7 @@ export type JidWithDevice = {
}
export type FullJid = JidWithDevice & {
server: JidServer | string
server: JidServer
domainType?: number
}
@@ -33,7 +33,7 @@ export const jidDecode = (jid: string | undefined): FullJid | undefined => {
const user = userAgent.split('_')[0]
return {
server,
server: server as JidServer,
user,
domainType: server === 'lid' ? 1 : 0,
device: device ? +device : undefined

View File

@@ -15375,8 +15375,10 @@ export type EventInputType = {
[key in Event['name']]: {
props: {
// @ts-ignore
[k in keyof EventByName<key>['props']]: any
[k in keyof EventByName<key>['props']]: Value
}
globals: { [x: string]: any }
globals: { [x: string]: Value }
}
} & {}
export type Value = number | null | string

View File

@@ -1,9 +1,7 @@
import { BinaryInfo } from './BinaryInfo'
import { FLAG_BYTE, FLAG_EVENT, FLAG_EXTENDED, FLAG_FIELD, FLAG_GLOBAL, WEB_EVENTS, WEB_GLOBALS } from './constants'
import { FLAG_BYTE, FLAG_EVENT, FLAG_EXTENDED, FLAG_FIELD, FLAG_GLOBAL, Value, WEB_EVENTS, WEB_GLOBALS } from './constants'
const getHeaderBitLength = (key: number) => (key < 256 ? 2 : 3)
type Value = number | null | string
export const encodeWAM = (binaryInfo: BinaryInfo) => {
binaryInfo.buffer = []
@@ -17,10 +15,10 @@ export const encodeWAM = (binaryInfo: BinaryInfo) => {
.reduce((a, b) => a + b)
const buffer = Buffer.alloc(totalSize)
let offset = 0
binaryInfo.buffer.forEach((buffer_) => {
for(const buffer_ of binaryInfo.buffer) {
buffer_.copy(buffer, offset)
offset += buffer_.length
})
}
return buffer
}
@@ -77,7 +75,7 @@ function encodeEvents(binaryInfo: BinaryInfo) {
}
const fieldFlag = extended ? FLAG_EVENT : FLAG_FIELD | FLAG_EXTENDED
binaryInfo.buffer.push(serializeData(id, value as Value, fieldFlag))
binaryInfo.buffer.push(serializeData(id, value, fieldFlag))
}
}
}

1367
yarn.lock

File diff suppressed because it is too large Load Diff