mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
feat: add "strictNullChecks"
This commit is contained in:
@@ -36,8 +36,7 @@ export const addTransactionCapability = (state: SignalKeyStore, logger: Logger,
|
||||
dbQueriesInTransaction += 1
|
||||
const result = await state.get(type, idsRequiringFetch)
|
||||
|
||||
transactionCache[type] = transactionCache[type] || { }
|
||||
Object.assign(transactionCache[type], result)
|
||||
transactionCache[type] = Object.assign(transactionCache[type] || { }, result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ export const parseCollectionsNode = (node: BinaryNode) => {
|
||||
const collectionsNode = getBinaryNodeChild(node, 'collections')
|
||||
const collections = getBinaryNodeChildren(collectionsNode, 'collection').map<CatalogCollection>(
|
||||
collectionNode => {
|
||||
const id = getBinaryNodeChildString(collectionNode, 'id')
|
||||
const name = getBinaryNodeChildString(collectionNode, 'name')
|
||||
const id = getBinaryNodeChildString(collectionNode, 'id')!
|
||||
const name = getBinaryNodeChildString(collectionNode, 'name')!
|
||||
|
||||
const products = getBinaryNodeChildren(collectionNode, 'product').map(parseProductNode)
|
||||
return {
|
||||
@@ -36,14 +36,14 @@ export const parseOrderDetailsNode = (node: BinaryNode) => {
|
||||
const orderNode = getBinaryNodeChild(node, 'order')
|
||||
const products = getBinaryNodeChildren(orderNode, 'product').map<OrderProduct>(
|
||||
productNode => {
|
||||
const imageNode = getBinaryNodeChild(productNode, 'image')
|
||||
const imageNode = getBinaryNodeChild(productNode, 'image')!
|
||||
return {
|
||||
id: getBinaryNodeChildString(productNode, 'id'),
|
||||
name: getBinaryNodeChildString(productNode, 'name'),
|
||||
imageUrl: getBinaryNodeChildString(imageNode, 'url'),
|
||||
price: +getBinaryNodeChildString(productNode, 'price'),
|
||||
currency: getBinaryNodeChildString(productNode, 'currency'),
|
||||
quantity: +getBinaryNodeChildString(productNode, 'quantity')
|
||||
id: getBinaryNodeChildString(productNode, 'id')!,
|
||||
name: getBinaryNodeChildString(productNode, 'name')!,
|
||||
imageUrl: getBinaryNodeChildString(imageNode, 'url')!,
|
||||
price: +getBinaryNodeChildString(productNode, 'price')!,
|
||||
currency: getBinaryNodeChildString(productNode, 'currency')!,
|
||||
quantity: +getBinaryNodeChildString(productNode, 'quantity')!
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -52,8 +52,8 @@ export const parseOrderDetailsNode = (node: BinaryNode) => {
|
||||
|
||||
const orderDetails: OrderDetails = {
|
||||
price: {
|
||||
total: +getBinaryNodeChildString(priceNode, 'total'),
|
||||
currency: getBinaryNodeChildString(priceNode, 'currency'),
|
||||
total: +getBinaryNodeChildString(priceNode, 'total')!,
|
||||
currency: getBinaryNodeChildString(priceNode, 'currency')!,
|
||||
},
|
||||
products
|
||||
}
|
||||
@@ -172,24 +172,24 @@ export const toProductNode = (productId: string | undefined, product: ProductCre
|
||||
|
||||
export const parseProductNode = (productNode: BinaryNode) => {
|
||||
const isHidden = productNode.attrs.is_hidden === 'true'
|
||||
const id = getBinaryNodeChildString(productNode, 'id')
|
||||
const id = getBinaryNodeChildString(productNode, 'id')!
|
||||
|
||||
const mediaNode = getBinaryNodeChild(productNode, 'media')
|
||||
const statusInfoNode = getBinaryNodeChild(productNode, 'status_info')
|
||||
const mediaNode = getBinaryNodeChild(productNode, 'media')!
|
||||
const statusInfoNode = getBinaryNodeChild(productNode, 'status_info')!
|
||||
|
||||
const product: Product = {
|
||||
id,
|
||||
imageUrls: parseImageUrls(mediaNode),
|
||||
reviewStatus: {
|
||||
whatsapp: getBinaryNodeChildString(statusInfoNode, 'status'),
|
||||
whatsapp: getBinaryNodeChildString(statusInfoNode, 'status')!,
|
||||
},
|
||||
availability: 'in stock',
|
||||
name: getBinaryNodeChildString(productNode, 'name'),
|
||||
name: getBinaryNodeChildString(productNode, 'name')!,
|
||||
retailerId: getBinaryNodeChildString(productNode, 'retailer_id'),
|
||||
url: getBinaryNodeChildString(productNode, 'url'),
|
||||
description: getBinaryNodeChildString(productNode, 'description'),
|
||||
price: +getBinaryNodeChildString(productNode, 'price'),
|
||||
currency: getBinaryNodeChildString(productNode, 'currency'),
|
||||
description: getBinaryNodeChildString(productNode, 'description')!,
|
||||
price: +getBinaryNodeChildString(productNode, 'price')!,
|
||||
currency: getBinaryNodeChildString(productNode, 'currency')!,
|
||||
isHidden,
|
||||
}
|
||||
|
||||
@@ -246,15 +246,15 @@ export const uploadingNecessaryImages = async(images: WAMediaUpload[], waUploadT
|
||||
const parseImageUrls = (mediaNode: BinaryNode) => {
|
||||
const imgNode = getBinaryNodeChild(mediaNode, 'image')
|
||||
return {
|
||||
requested: getBinaryNodeChildString(imgNode, 'request_image_url'),
|
||||
original: getBinaryNodeChildString(imgNode, 'original_image_url')
|
||||
requested: getBinaryNodeChildString(imgNode, 'request_image_url')!,
|
||||
original: getBinaryNodeChildString(imgNode, 'original_image_url')!
|
||||
}
|
||||
}
|
||||
|
||||
const parseStatusInfo = (mediaNode: BinaryNode): CatalogStatus => {
|
||||
const node = getBinaryNodeChild(mediaNode, 'status_info')
|
||||
return {
|
||||
status: getBinaryNodeChildString(node, 'status'),
|
||||
status: getBinaryNodeChildString(node, 'status')!,
|
||||
canAppeal: getBinaryNodeChildString(node, 'can_appeal') === 'true',
|
||||
}
|
||||
}
|
||||
@@ -220,7 +220,7 @@ export const decodeSyncdMutations = async(
|
||||
const encContent = content.slice(0, -32)
|
||||
const ogValueMac = content.slice(-32)
|
||||
if(validateMacs) {
|
||||
const contentHmac = generateMac(operation, encContent, record.keyId!.id!, key.valueMacKey)
|
||||
const contentHmac = generateMac(operation!, encContent, record.keyId!.id!, key.valueMacKey)
|
||||
if(Buffer.compare(contentHmac, ogValueMac) !== 0) {
|
||||
throw new Boom('HMAC content verification failed')
|
||||
}
|
||||
@@ -231,7 +231,7 @@ export const decodeSyncdMutations = async(
|
||||
|
||||
if(validateMacs) {
|
||||
const hmac = hmacSign(syncAction.index, key.indexKey)
|
||||
if(Buffer.compare(hmac, record.index!.blob) !== 0) {
|
||||
if(Buffer.compare(hmac, record.index!.blob!) !== 0) {
|
||||
throw new Boom('HMAC index verification failed')
|
||||
}
|
||||
}
|
||||
@@ -242,7 +242,7 @@ export const decodeSyncdMutations = async(
|
||||
ltGenerator.mix({
|
||||
indexMac: record.index!.blob!,
|
||||
valueMac: ogValueMac,
|
||||
operation: operation
|
||||
operation: operation!
|
||||
})
|
||||
}
|
||||
|
||||
@@ -258,13 +258,13 @@ export const decodeSyncdPatch = async(
|
||||
validateMacs: boolean
|
||||
) => {
|
||||
if(validateMacs) {
|
||||
const base64Key = Buffer.from(msg.keyId!.id).toString('base64')
|
||||
const base64Key = Buffer.from(msg.keyId!.id!).toString('base64')
|
||||
const mainKeyObj = await getAppStateSyncKey(base64Key)
|
||||
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)
|
||||
if(Buffer.compare(patchMac, msg.patchMac) !== 0) {
|
||||
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')
|
||||
}
|
||||
}
|
||||
@@ -418,10 +418,10 @@ export const decodePatches = async(
|
||||
logger?.trace({ name, version }, 'downloading external patch')
|
||||
const ref = await downloadExternalPatch(syncd.externalMutations)
|
||||
logger?.debug({ name, version, mutations: ref.mutations.length }, 'downloaded external patch')
|
||||
syncd.mutations.push(...ref.mutations)
|
||||
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
|
||||
@@ -439,7 +439,7 @@ export const decodePatches = async(
|
||||
|
||||
const result = mutationKeys(keyEnc.keyData!)
|
||||
const computedSnapshotMac = generateSnapshotMac(newState.hash, newState.version, name, result.snapshotMacKey)
|
||||
if(Buffer.compare(snapshotMac, computedSnapshotMac) !== 0) {
|
||||
if(Buffer.compare(snapshotMac!, computedSnapshotMac) !== 0) {
|
||||
throw new Boom(`failed to verify LTHash at ${newState.version} of ${name}`)
|
||||
}
|
||||
}
|
||||
@@ -482,7 +482,6 @@ export const chatModificationToAppPatch = (
|
||||
}
|
||||
|
||||
if(m.key.participant) {
|
||||
m.key = { ...m.key }
|
||||
m.key.participant = jidNormalizedUser(m.key.participant)
|
||||
}
|
||||
|
||||
@@ -627,7 +626,7 @@ export const processSyncAction = (
|
||||
if(
|
||||
isValidPatchBasedOnMessageRange(id, archiveAction.messageRange)
|
||||
|| !isInitialSync
|
||||
|| !accountSettings.unarchiveChats
|
||||
|| !accountSettings?.unarchiveChats
|
||||
) {
|
||||
// basically we don't need to fire an "archive" update if the chat is being marked unarchvied
|
||||
// this only applies for the initial sync
|
||||
@@ -661,19 +660,21 @@ 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) {
|
||||
if(me?.name !== action?.pushNameSetting) {
|
||||
ev.emit('creds.update', { me: { ...me, name: action?.pushNameSetting?.name! } })
|
||||
}
|
||||
} else if(action?.pinAction) {
|
||||
ev.emit('chats.update', [{ id, pin: action.pinAction?.pinned ? toNumber(action.timestamp) : null }])
|
||||
ev.emit('chats.update', [{ id, pin: action.pinAction?.pinned ? toNumber(action.timestamp!) : null }])
|
||||
} else if(action?.unarchiveChatsSetting) {
|
||||
const unarchiveChats = !!action.unarchiveChatsSetting.unarchiveChats
|
||||
ev.emit('creds.update', { accountSettings: { unarchiveChats } })
|
||||
|
||||
logger.info(`archive setting updated => '${action.unarchiveChatsSetting.unarchiveChats}'`)
|
||||
accountSettings.unarchiveChats = unarchiveChats
|
||||
logger?.info(`archive setting updated => '${action.unarchiveChatsSetting.unarchiveChats}'`)
|
||||
if(accountSettings) {
|
||||
accountSettings.unarchiveChats = unarchiveChats
|
||||
}
|
||||
} else if(action?.starAction) {
|
||||
ev.emit('messages.update', [
|
||||
{
|
||||
@@ -689,12 +690,12 @@ export const processSyncAction = (
|
||||
ev.emit('chats.delete', [id])
|
||||
}
|
||||
} else {
|
||||
logger.warn({ syncAction, id }, 'unprocessable update')
|
||||
logger?.warn({ syncAction, id }, 'unprocessable update')
|
||||
}
|
||||
|
||||
function isValidPatchBasedOnMessageRange(id: string, msgRange: proto.ISyncActionMessageRange) {
|
||||
function isValidPatchBasedOnMessageRange(id: string, msgRange: proto.ISyncActionMessageRange | null | undefined) {
|
||||
const chat = recvChats?.[id]
|
||||
const lastMsgTimestamp = msgRange.lastMessageTimestamp || msgRange.lastSystemMessageTimestamp || 0
|
||||
const lastMsgTimestamp = msgRange?.lastMessageTimestamp || msgRange?.lastSystemMessageTimestamp || 0
|
||||
const chatLastMsgTimestamp = chat?.lastMsgRecvTimestamp || 0
|
||||
return lastMsgTimestamp >= chatLastMsgTimestamp
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ export const decodeMessageStanza = (stanza: BinaryNode, auth: AuthenticationStat
|
||||
|
||||
chatId = from
|
||||
author = participant
|
||||
} else {
|
||||
throw new Boom('Unknown message type', { data: stanza })
|
||||
}
|
||||
|
||||
const sender = msgType === 'chat' ? author : chatId
|
||||
@@ -117,6 +119,8 @@ export const decodeMessageStanza = (stanza: BinaryNode, auth: AuthenticationStat
|
||||
const user = isJidUser(sender) ? sender : author
|
||||
msgBuffer = await decryptSignalProto(user, e2eType, content as Buffer, auth)
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unknown e2e type: ${e2eType}`)
|
||||
}
|
||||
|
||||
let msg: proto.IMessage = proto.Message.decode(unpadRandomMax16(msgBuffer))
|
||||
|
||||
@@ -96,6 +96,8 @@ export const makeEventBuffer = (logger: Logger): BaileysBufferableEventEmitter =
|
||||
isBuffering = true
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
async flush() {
|
||||
if(!isBuffering) {
|
||||
@@ -209,12 +211,13 @@ function append<E extends BufferableEvent>(
|
||||
case 'contacts.update':
|
||||
const contactUpdates = eventData as BaileysEventMap<any>['contacts.update']
|
||||
for(const update of contactUpdates) {
|
||||
const id = update.id!
|
||||
const upsert = data.contactUpserts[update.id!]
|
||||
if(upsert) {
|
||||
Object.assign(upsert, update)
|
||||
} else {
|
||||
const contactUpdate = data.contactUpdates[update.id] || { }
|
||||
data.contactUpdates[update.id] = Object.assign(contactUpdate, update)
|
||||
const contactUpdate = data.contactUpdates[id] || { }
|
||||
data.contactUpdates[id] = Object.assign(contactUpdate, update)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,8 +315,9 @@ function append<E extends BufferableEvent>(
|
||||
case 'groups.update':
|
||||
const groupUpdates = eventData as BaileysEventMap<any>['groups.update']
|
||||
for(const update of groupUpdates) {
|
||||
const groupUpdate = data.groupUpdates[update.id] || { }
|
||||
data.groupUpdates[update.id] = Object.assign(groupUpdate, update)
|
||||
const id = update.id!
|
||||
const groupUpdate = data.groupUpdates[id] || { }
|
||||
data.groupUpdates[id] = Object.assign(groupUpdate, update)
|
||||
}
|
||||
|
||||
break
|
||||
@@ -324,12 +328,12 @@ function append<E extends BufferableEvent>(
|
||||
function decrementChatReadCounterIfMsgDidUnread(message: WAMessage) {
|
||||
// decrement chat unread counter
|
||||
// if the message has already been marked read by us
|
||||
const chatId = message.key.remoteJid
|
||||
const chatId = message.key.remoteJid!
|
||||
const chat = data.chatUpdates[chatId] || data.chatUpserts[chatId]
|
||||
if(
|
||||
isRealMessage(message)
|
||||
&& shouldIncrementChatUnread(message)
|
||||
&& typeof chat?.unreadCount !== 'undefined'
|
||||
&& typeof chat?.unreadCount === 'number'
|
||||
&& chat.unreadCount > 0
|
||||
) {
|
||||
logger.debug({ chatId: chat.id }, 'decrementing chat counter')
|
||||
@@ -413,16 +417,16 @@ function consolidateEvents(data: BufferedEventData) {
|
||||
function concatChats<C extends Partial<Chat>>(a: C, b: C) {
|
||||
if(b.unreadCount === null) {
|
||||
// neutralize unread counter
|
||||
if(a.unreadCount < 0) {
|
||||
if(a.unreadCount! < 0) {
|
||||
a.unreadCount = undefined
|
||||
b.unreadCount = undefined
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof a.unreadCount !== 'undefined' && typeof b.unreadCount !== 'undefined') {
|
||||
if(typeof a.unreadCount === 'number' && typeof b.unreadCount === 'number') {
|
||||
b = { ...b }
|
||||
if(b.unreadCount >= 0) {
|
||||
b.unreadCount = Math.max(b.unreadCount, 0) + Math.max(a.unreadCount, 0)
|
||||
if(b.unreadCount! >= 0) {
|
||||
b.unreadCount = Math.max(b.unreadCount!, 0) + Math.max(a.unreadCount, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,40 +86,21 @@ export const encodeBigEndian = (e: number, t = 4) => {
|
||||
return a
|
||||
}
|
||||
|
||||
export const toNumber = (t: Long | number): number => ((typeof t === 'object' && t) ? ('toNumber' in t ? t.toNumber() : (t as any).low) : t)
|
||||
|
||||
export function shallowChanges <T>(old: T, current: T, { lookForDeletedKeys }: {lookForDeletedKeys: boolean}): Partial<T> {
|
||||
const changes: Partial<T> = {}
|
||||
for(const key in current) {
|
||||
if(old[key] !== current[key]) {
|
||||
changes[key] = current[key] || null
|
||||
}
|
||||
}
|
||||
|
||||
if(lookForDeletedKeys) {
|
||||
for(const key in old) {
|
||||
if(!changes[key] && old[key] !== current[key]) {
|
||||
changes[key] = current[key] || null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
export const toNumber = (t: Long | number | null | undefined): number => ((typeof t === 'object' && t) ? ('toNumber' in t ? t.toNumber() : (t as any).low) : t)
|
||||
|
||||
/** 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 = undefined) => {
|
||||
let timeout: NodeJS.Timeout
|
||||
export const debouncedTimeout = (intervalMs: number = 1000, task?: () => void) => {
|
||||
let timeout: NodeJS.Timeout | undefined
|
||||
return {
|
||||
start: (newIntervalMs?: number, newTask?: () => void) => {
|
||||
task = newTask || task
|
||||
intervalMs = newIntervalMs || intervalMs
|
||||
timeout && clearTimeout(timeout)
|
||||
timeout = setTimeout(task, intervalMs)
|
||||
timeout = setTimeout(() => task?.(), intervalMs)
|
||||
},
|
||||
cancel: () => {
|
||||
timeout && clearTimeout(timeout)
|
||||
@@ -155,7 +136,7 @@ export const delayCancellable = (ms: number) => {
|
||||
return { delay, cancel }
|
||||
}
|
||||
|
||||
export async function promiseTimeout<T>(ms: number, promise: (resolve: (v?: T)=>void, reject: (error) => void) => void) {
|
||||
export async function promiseTimeout<T>(ms: number | undefined, promise: (resolve: (v?: T)=>void, reject: (error) => void) => void) {
|
||||
if(!ms) {
|
||||
return new Promise (promise)
|
||||
}
|
||||
@@ -185,7 +166,7 @@ export async function promiseTimeout<T>(ms: number, promise: (resolve: (v?: T)=>
|
||||
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, timeoutMs?: number) => {
|
||||
return async(check: (u: BaileysEventMap<any>[T]) => boolean | undefined, timeoutMs?: number) => {
|
||||
let listener: (item: BaileysEventMap<any>[T]) => void
|
||||
let closeListener: any
|
||||
await (
|
||||
@@ -291,7 +272,7 @@ const STATUS_MAP: { [_: string]: proto.WebMessageInfo.WebMessageInfoStatus } = {
|
||||
* @param type type from receipt
|
||||
*/
|
||||
export const getStatusFromReceiptType = (type: string | undefined) => {
|
||||
const status = STATUS_MAP[type]
|
||||
const status = STATUS_MAP[type!]
|
||||
if(typeof type === 'undefined') {
|
||||
return proto.WebMessageInfo.WebMessageInfoStatus.DELIVERY_ACK
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export const processHistoryMessage = (
|
||||
switch (item.syncType) {
|
||||
case proto.HistorySync.HistorySyncHistorySyncType.INITIAL_BOOTSTRAP:
|
||||
case proto.HistorySync.HistorySyncHistorySyncType.RECENT:
|
||||
for(const chat of item.conversations) {
|
||||
for(const chat of item.conversations!) {
|
||||
const contactId = `c:${chat.id}`
|
||||
if(chat.name && !historyCache.has(contactId)) {
|
||||
contacts.push({ id: chat.id, name: chat.name })
|
||||
@@ -43,15 +43,16 @@ export const processHistoryMessage = (
|
||||
}
|
||||
|
||||
const msgs = chat.messages || []
|
||||
for(const { message } of msgs) {
|
||||
for(const item of msgs) {
|
||||
const message = item.message!
|
||||
const uqId = `${message.key.remoteJid}:${message.key.id}`
|
||||
if(!historyCache.has(uqId)) {
|
||||
messages.push(message)
|
||||
|
||||
const curItem = recvChats[message.key.remoteJid]
|
||||
const curItem = recvChats[message.key.remoteJid!]
|
||||
const timestamp = toNumber(message.messageTimestamp)
|
||||
if(!message.key.fromMe && (!curItem || timestamp > curItem.lastMsgRecvTimestamp)) {
|
||||
recvChats[message.key.remoteJid] = { lastMsgRecvTimestamp: timestamp }
|
||||
recvChats[message.key.remoteJid!] = { lastMsgRecvTimestamp: timestamp }
|
||||
// keep only the most recent message in the chat array
|
||||
chat.messages = [{ message }]
|
||||
}
|
||||
@@ -72,10 +73,10 @@ export const processHistoryMessage = (
|
||||
|
||||
break
|
||||
case proto.HistorySync.HistorySyncHistorySyncType.PUSH_NAME:
|
||||
for(const c of item.pushnames) {
|
||||
for(const c of item.pushnames!) {
|
||||
const contactId = `c:${c.id}`
|
||||
if(!historyCache.has(contactId)) {
|
||||
contacts.push({ notify: c.pushname, id: c.id })
|
||||
contacts.push({ notify: c.pushname!, id: c.id! })
|
||||
historyCache.add(contactId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export const decodeWAMessage = (
|
||||
// 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
|
||||
let tags: WATag | undefined
|
||||
if(data.length) {
|
||||
const possiblyEnc = (data.length > 32 && data.length % 16 === 0)
|
||||
if(typeof data === 'string' || !possiblyEnc) {
|
||||
|
||||
@@ -62,7 +62,11 @@ export const hkdfInfoKey = (type: MediaType) => {
|
||||
}
|
||||
|
||||
/** generates all the keys required to encrypt/decrypt & sign a media message */
|
||||
export function getMediaKeys(buffer: Uint8Array | string, mediaType: MediaType): MediaDecryptionKeyInfo {
|
||||
export function getMediaKeys(buffer: Uint8Array | string | null | undefined, mediaType: MediaType): MediaDecryptionKeyInfo {
|
||||
if(!buffer) {
|
||||
throw new Boom('Cannot derive from empty media key')
|
||||
}
|
||||
|
||||
if(typeof buffer === 'string') {
|
||||
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64')
|
||||
}
|
||||
@@ -163,13 +167,13 @@ export async function getAudioDuration(buffer: Buffer | string | Readable) {
|
||||
const musicMetadata = await import('music-metadata')
|
||||
let metadata: IAudioMetadata
|
||||
if(Buffer.isBuffer(buffer)) {
|
||||
metadata = await musicMetadata.parseBuffer(buffer, null, { duration: true })
|
||||
metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true })
|
||||
} else if(typeof buffer === 'string') {
|
||||
const rStream = createReadStream(buffer)
|
||||
metadata = await musicMetadata.parseStream(rStream, null, { duration: true })
|
||||
metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true })
|
||||
rStream.close()
|
||||
} else {
|
||||
metadata = await musicMetadata.parseStream(buffer, null, { duration: true })
|
||||
metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true })
|
||||
}
|
||||
|
||||
return metadata.format.duration
|
||||
@@ -216,7 +220,7 @@ export async function generateThumbnail(
|
||||
logger?: Logger
|
||||
}
|
||||
) {
|
||||
let thumbnail: string
|
||||
let thumbnail: string | undefined
|
||||
if(mediaType === 'image') {
|
||||
const buff = await extractImageThumb(file)
|
||||
thumbnail = buff.toString('base64')
|
||||
@@ -259,8 +263,8 @@ export const encryptedStream = async(
|
||||
// const encWriteStream = createWriteStream(encBodyPath)
|
||||
const encWriteStream = new Readable({ read: () => {} })
|
||||
|
||||
let bodyPath: string
|
||||
let writeStream: WriteStream
|
||||
let bodyPath: string | undefined
|
||||
let writeStream: WriteStream | undefined
|
||||
let didSaveToTmpPath = false
|
||||
if(type === 'file') {
|
||||
bodyPath = (media as any).url
|
||||
@@ -272,7 +276,7 @@ export const encryptedStream = async(
|
||||
|
||||
let fileLength = 0
|
||||
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv)
|
||||
let hmac = Crypto.createHmac('sha256', macKey).update(iv)
|
||||
let hmac = Crypto.createHmac('sha256', macKey!).update(iv)
|
||||
let sha256Plain = Crypto.createHash('sha256')
|
||||
let sha256Enc = Crypto.createHash('sha256')
|
||||
|
||||
@@ -323,7 +327,7 @@ export const encryptedStream = async(
|
||||
}
|
||||
} catch(error) {
|
||||
encWriteStream.destroy(error)
|
||||
writeStream.destroy(error)
|
||||
writeStream?.destroy(error)
|
||||
aes.destroy(error)
|
||||
hmac.destroy(error)
|
||||
sha256Plain.destroy(error)
|
||||
@@ -353,7 +357,7 @@ export const downloadContentFromMessage = (
|
||||
type: MediaType,
|
||||
opts: MediaDownloadOptions = { }
|
||||
) => {
|
||||
const downloadUrl = url || getUrlFromDirectPath(directPath)
|
||||
const downloadUrl = url || getUrlFromDirectPath(directPath!)
|
||||
const keys = getMediaKeys(mediaKey, type)
|
||||
|
||||
return downloadEncryptedContent(downloadUrl, keys, opts)
|
||||
@@ -410,8 +414,8 @@ export const downloadEncryptedContent = async(
|
||||
|
||||
const pushBytes = (bytes: Buffer, push: (bytes: Buffer) => void) => {
|
||||
if(startByte || endByte) {
|
||||
const start = bytesFetched >= startByte ? undefined : Math.max(startByte - bytesFetched, 0)
|
||||
const end = bytesFetched + bytes.length < endByte ? undefined : Math.max(endByte - bytesFetched, 0)
|
||||
const start = bytesFetched >= startByte! ? undefined : Math.max(startByte! - bytesFetched, 0)
|
||||
const end = bytesFetched + bytes.length < endByte! ? undefined : Math.max(endByte! - bytesFetched, 0)
|
||||
|
||||
push(bytes.slice(start, end))
|
||||
|
||||
@@ -486,13 +490,13 @@ export function extensionForMediaMessage(message: WAMessageContent) {
|
||||
return extension
|
||||
}
|
||||
|
||||
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: CommonSocketConfig<any>, refreshMediaConn: (force: boolean) => Promise<MediaConnInfo>): WAMediaUploadFunction => {
|
||||
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: CommonSocketConfig, 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
|
||||
let uploadInfo = await refreshMediaConn(false)
|
||||
|
||||
let urls: { mediaUrl: string, directPath: string }
|
||||
let urls: { mediaUrl: string, directPath: string } | undefined
|
||||
const hosts = [ ...customUploadHosts, ...uploadInfo.hosts ]
|
||||
|
||||
const chunks: Buffer[] = []
|
||||
@@ -500,7 +504,7 @@ export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: C
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
let reqBody = Buffer.concat(chunks)
|
||||
const reqBody = Buffer.concat(chunks)
|
||||
|
||||
for(const { hostname, maxContentLengthBytes } of hosts) {
|
||||
logger.debug(`uploading to "${hostname}"`)
|
||||
@@ -550,9 +554,6 @@ export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: C
|
||||
}
|
||||
}
|
||||
|
||||
// clear buffer just to be sure we're releasing the memory
|
||||
reqBody = undefined
|
||||
|
||||
if(!urls) {
|
||||
throw new Boom(
|
||||
'Media upload failed on all hosts',
|
||||
@@ -583,12 +584,12 @@ export const encryptMediaRetryRequest = (
|
||||
|
||||
const iv = Crypto.randomBytes(12)
|
||||
const retryKey = getMediaRetryKey(mediaKey)
|
||||
const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id))
|
||||
const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id!))
|
||||
|
||||
const req: BinaryNode = {
|
||||
tag: 'receipt',
|
||||
attrs: {
|
||||
id: key.id,
|
||||
id: key.id!,
|
||||
to: jidNormalizedUser(meId),
|
||||
type: 'server-error'
|
||||
},
|
||||
@@ -607,8 +608,9 @@ export const encryptMediaRetryRequest = (
|
||||
{
|
||||
tag: 'rmr',
|
||||
attrs: {
|
||||
jid: key.remoteJid,
|
||||
jid: key.remoteJid!,
|
||||
from_me: (!!key.fromMe).toString(),
|
||||
// @ts-ignore
|
||||
participant: key.participant || undefined
|
||||
}
|
||||
}
|
||||
@@ -619,7 +621,7 @@ export const encryptMediaRetryRequest = (
|
||||
}
|
||||
|
||||
export const decodeMediaRetryNode = (node: BinaryNode) => {
|
||||
const rmrNode = getBinaryNodeChild(node, 'rmr')
|
||||
const rmrNode = getBinaryNodeChild(node, 'rmr')!
|
||||
|
||||
const event: BaileysEventMap<any>['messages.media-update'][number] = {
|
||||
key: {
|
||||
|
||||
@@ -75,13 +75,17 @@ export const prepareWAMessageMedia = async(
|
||||
) => {
|
||||
const logger = options.logger
|
||||
|
||||
let mediaType: typeof MEDIA_KEYS[number]
|
||||
let mediaType: typeof MEDIA_KEYS[number] | undefined
|
||||
for(const key of MEDIA_KEYS) {
|
||||
if(key in message) {
|
||||
mediaType = key
|
||||
}
|
||||
}
|
||||
|
||||
if(!mediaType) {
|
||||
throw new Boom('Invalid media type', { statusCode: 400 })
|
||||
}
|
||||
|
||||
const uploadData: MediaUploadData = {
|
||||
...message,
|
||||
media: message[mediaType]
|
||||
@@ -106,15 +110,14 @@ export const prepareWAMessageMedia = async(
|
||||
|
||||
// check for cache hit
|
||||
if(cacheableKey) {
|
||||
const mediaBuff: Buffer = options.mediaCache!.get(cacheableKey)
|
||||
const mediaBuff = options.mediaCache!.get<Buffer>(cacheableKey)
|
||||
if(mediaBuff) {
|
||||
logger?.debug({ cacheableKey }, 'got media cache hit')
|
||||
|
||||
const obj = WAProto.Message.decode(mediaBuff)
|
||||
const key = `${mediaType}Message`
|
||||
|
||||
delete uploadData.media
|
||||
Object.assign(obj[key], { ...uploadData })
|
||||
Object.assign(obj[key], { ...uploadData, media: undefined })
|
||||
|
||||
return obj
|
||||
}
|
||||
@@ -153,12 +156,12 @@ export const prepareWAMessageMedia = async(
|
||||
(async() => {
|
||||
try {
|
||||
if(requiresThumbnailComputation) {
|
||||
uploadData.jpegThumbnail = await generateThumbnail(bodyPath, mediaType as any, options)
|
||||
uploadData.jpegThumbnail = await generateThumbnail(bodyPath!, mediaType as any, options)
|
||||
logger?.debug('generated thumbnail')
|
||||
}
|
||||
|
||||
if(requiresDurationComputation) {
|
||||
uploadData.seconds = await getAudioDuration(bodyPath)
|
||||
uploadData.seconds = await getAudioDuration(bodyPath!)
|
||||
logger?.debug('computed audio duration')
|
||||
}
|
||||
} catch(error) {
|
||||
@@ -177,8 +180,6 @@ export const prepareWAMessageMedia = async(
|
||||
}
|
||||
)
|
||||
|
||||
delete uploadData.media
|
||||
|
||||
const obj = WAProto.Message.fromObject({
|
||||
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject(
|
||||
{
|
||||
@@ -189,13 +190,14 @@ export const prepareWAMessageMedia = async(
|
||||
fileSha256,
|
||||
fileLength,
|
||||
mediaKeyTimestamp: unixTimestampSeconds(),
|
||||
...uploadData
|
||||
...uploadData,
|
||||
media: undefined
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
if(cacheableKey) {
|
||||
logger.debug({ cacheableKey }, 'set cache')
|
||||
logger?.debug({ cacheableKey }, 'set cache')
|
||||
options.mediaCache!.set(cacheableKey, WAProto.Message.encode(obj).finish())
|
||||
}
|
||||
|
||||
@@ -232,8 +234,8 @@ export const generateForwardMessageContent = (
|
||||
}
|
||||
|
||||
// hacky copy
|
||||
content = normalizeMessageContent(message.message)
|
||||
content = proto.Message.decode(proto.Message.encode(content).finish())
|
||||
content = normalizeMessageContent(content)
|
||||
content = proto.Message.decode(proto.Message.encode(content!).finish())
|
||||
|
||||
let key = Object.keys(content)[0] as MessageType
|
||||
|
||||
@@ -428,8 +430,8 @@ export const generateWAMessageFromContent = (
|
||||
if(quoted) {
|
||||
const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid)
|
||||
|
||||
let quotedMsg = normalizeMessageContent(quoted.message)
|
||||
const msgType = getContentType(quotedMsg)
|
||||
let quotedMsg = normalizeMessageContent(quoted.message)!
|
||||
const msgType = getContentType(quotedMsg)!
|
||||
// strip any redundant properties
|
||||
quotedMsg = proto.Message.fromObject({ [msgType]: quotedMsg[msgType] })
|
||||
|
||||
@@ -439,7 +441,7 @@ export const generateWAMessageFromContent = (
|
||||
}
|
||||
|
||||
const contextInfo: proto.IContextInfo = message[key].contextInfo || { }
|
||||
contextInfo.participant = jidNormalizedUser(participant)
|
||||
contextInfo.participant = jidNormalizedUser(participant!)
|
||||
contextInfo.stanzaId = quoted.key.id
|
||||
contextInfo.quotedMessage = quotedMsg
|
||||
|
||||
@@ -521,7 +523,7 @@ export const getContentType = (content: WAProto.IMessage | undefined) => {
|
||||
* @param content
|
||||
* @returns
|
||||
*/
|
||||
export const normalizeMessageContent = (content: WAMessageContent | undefined): WAMessageContent => {
|
||||
export const normalizeMessageContent = (content: WAMessageContent | null | undefined): WAMessageContent | undefined => {
|
||||
content = content?.ephemeralMessage?.message?.viewOnceMessage?.message ||
|
||||
content?.ephemeralMessage?.message ||
|
||||
content?.viewOnceMessage?.message ||
|
||||
@@ -614,13 +616,13 @@ export const aggregateMessageKeysNotFromMe = (keys: proto.IMessageKey[]) => {
|
||||
const uqKey = `${remoteJid}:${participant || ''}`
|
||||
if(!keyMap[uqKey]) {
|
||||
keyMap[uqKey] = {
|
||||
jid: remoteJid,
|
||||
participant,
|
||||
jid: remoteJid!,
|
||||
participant: participant!,
|
||||
messageIds: []
|
||||
}
|
||||
}
|
||||
|
||||
keyMap[uqKey].messageIds.push(id)
|
||||
keyMap[uqKey].messageIds.push(id!)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,7 +652,7 @@ export const downloadMediaMessage = async(
|
||||
if(ctx) {
|
||||
if(axios.isAxiosError(error)) {
|
||||
// check if the message requires a reupload
|
||||
if(REUPLOAD_REQUIRED_STATUS.includes(error.response?.status)) {
|
||||
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)
|
||||
@@ -670,9 +672,9 @@ export const downloadMediaMessage = async(
|
||||
}
|
||||
|
||||
const contentType = getContentType(mContent)
|
||||
const mediaType = contentType.replace('Message', '') as MediaType
|
||||
const media = mContent[contentType]
|
||||
if(typeof media !== 'object' || !('url' in media)) {
|
||||
const mediaType = contentType?.replace('Message', '') as MediaType
|
||||
const media = mContent[contentType!]
|
||||
if(!media || typeof media !== 'object' || !('url' in media)) {
|
||||
throw new Boom(`"${contentType}" message is not a media message`)
|
||||
}
|
||||
|
||||
@@ -691,7 +693,7 @@ export const downloadMediaMessage = async(
|
||||
}
|
||||
|
||||
/** Checks whether the given message is a media message; if it is returns the inner content */
|
||||
export const assertMediaContent = (content: proto.IMessage) => {
|
||||
export const assertMediaContent = (content: proto.IMessage | null | undefined) => {
|
||||
content = extractMessageContent(content)
|
||||
const mediaContent = content?.documentMessage
|
||||
|| content?.imageMessage
|
||||
|
||||
@@ -97,7 +97,7 @@ export const makeNoiseHandler = (
|
||||
finishInit,
|
||||
processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => {
|
||||
authenticate(serverHello!.ephemeral!)
|
||||
mixIntoKey(Curve.sharedKey(privateKey, serverHello.ephemeral!))
|
||||
mixIntoKey(Curve.sharedKey(privateKey, serverHello!.ephemeral!))
|
||||
|
||||
const decStaticContent = decrypt(serverHello!.static!)
|
||||
mixIntoKey(Curve.sharedKey(privateKey, decStaticContent))
|
||||
|
||||
@@ -42,7 +42,7 @@ export const isRealMessage = (message: proto.IWebMessageInfo) => {
|
||||
const normalizedContent = normalizeMessageContent(message.message)
|
||||
return (
|
||||
!!normalizedContent
|
||||
|| MSG_MISSED_CALL_TYPES.has(message.messageStubType)
|
||||
|| MSG_MISSED_CALL_TYPES.has(message.messageStubType!)
|
||||
)
|
||||
&& !normalizedContent?.protocolMessage
|
||||
&& !normalizedContent?.reactionMessage
|
||||
@@ -59,7 +59,7 @@ const processMessage = async(
|
||||
const meId = creds.me!.id
|
||||
const { accountSettings } = creds
|
||||
|
||||
const chat: Partial<Chat> = { id: jidNormalizedUser(message.key.remoteJid) }
|
||||
const chat: Partial<Chat> = { id: jidNormalizedUser(message.key.remoteJid!) }
|
||||
|
||||
if(isRealMessage(message)) {
|
||||
chat.conversationTimestamp = toNumber(message.messageTimestamp)
|
||||
@@ -79,7 +79,7 @@ const processMessage = async(
|
||||
if(protocolMsg) {
|
||||
switch (protocolMsg.type) {
|
||||
case proto.ProtocolMessage.ProtocolMessageType.HISTORY_SYNC_NOTIFICATION:
|
||||
const histNotification = protocolMsg!.historySyncNotification
|
||||
const histNotification = protocolMsg!.historySyncNotification!
|
||||
|
||||
logger?.info({ histNotification, id: message.key.id }, 'got history notification')
|
||||
|
||||
@@ -117,10 +117,10 @@ const processMessage = async(
|
||||
await keyStore.transaction(
|
||||
async() => {
|
||||
for(const { keyData, keyId } of keys) {
|
||||
const strKeyId = Buffer.from(keyId.keyId!).toString('base64')
|
||||
const strKeyId = Buffer.from(keyId!.keyId!).toString('base64')
|
||||
|
||||
logger?.info({ strKeyId }, 'injecting new app state sync key')
|
||||
await keyStore.set({ 'app-state-sync-key': { [strKeyId]: keyData } })
|
||||
await keyStore.set({ 'app-state-sync-key': { [strKeyId]: keyData! } })
|
||||
|
||||
newAppStateSyncKeyId = strKeyId
|
||||
}
|
||||
@@ -176,7 +176,7 @@ const processMessage = async(
|
||||
switch (message.messageStubType) {
|
||||
case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
|
||||
case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
|
||||
participants = message.messageStubParameters
|
||||
participants = message.messageStubParameters || []
|
||||
emitParticipantsUpdate('remove')
|
||||
// mark the chat read only if you left the group
|
||||
if(participantsIncludesMe()) {
|
||||
@@ -187,7 +187,7 @@ const processMessage = async(
|
||||
case WAMessageStubType.GROUP_PARTICIPANT_ADD:
|
||||
case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
|
||||
case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
|
||||
participants = message.messageStubParameters
|
||||
participants = message.messageStubParameters || []
|
||||
if(participantsIncludesMe()) {
|
||||
chat.readOnly = false
|
||||
}
|
||||
@@ -195,23 +195,23 @@ const processMessage = async(
|
||||
emitParticipantsUpdate('add')
|
||||
break
|
||||
case WAMessageStubType.GROUP_PARTICIPANT_DEMOTE:
|
||||
participants = message.messageStubParameters
|
||||
participants = message.messageStubParameters || []
|
||||
emitParticipantsUpdate('demote')
|
||||
break
|
||||
case WAMessageStubType.GROUP_PARTICIPANT_PROMOTE:
|
||||
participants = message.messageStubParameters
|
||||
participants = message.messageStubParameters || []
|
||||
emitParticipantsUpdate('promote')
|
||||
break
|
||||
case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
|
||||
const announceValue = message.messageStubParameters[0]
|
||||
const announceValue = message.messageStubParameters?.[0]
|
||||
emitGroupUpdate({ announce: announceValue === 'true' || announceValue === 'on' })
|
||||
break
|
||||
case WAMessageStubType.GROUP_CHANGE_RESTRICT:
|
||||
const restrictValue = message.messageStubParameters[0]
|
||||
const restrictValue = message.messageStubParameters?.[0]
|
||||
emitGroupUpdate({ restrict: restrictValue === 'true' || restrictValue === 'on' })
|
||||
break
|
||||
case WAMessageStubType.GROUP_CHANGE_SUBJECT:
|
||||
const name = message.messageStubParameters[0]
|
||||
const name = message.messageStubParameters?.[0]
|
||||
chat.name = name
|
||||
emitGroupUpdate({ subject: name })
|
||||
break
|
||||
|
||||
@@ -142,7 +142,7 @@ export const processSenderKeyMessage = async(
|
||||
auth: SignalAuthState
|
||||
) => {
|
||||
const builder = new GroupSessionBuilder(signalStorage(auth))
|
||||
const senderName = jidToSignalSenderKeyName(item.groupId, authorJid)
|
||||
const senderName = jidToSignalSenderKeyName(item.groupId!, authorJid)
|
||||
|
||||
const senderMsg = new SenderKeyDistributionMessage(null, null, null, null, item.axolotlSenderKeyDistributionMessage)
|
||||
const { [senderName]: senderKey } = await auth.keys.get('sender-key', [senderName])
|
||||
@@ -203,9 +203,7 @@ export const parseAndInjectE2ESessions = async(node: BinaryNode, auth: SignalAut
|
||||
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
|
||||
)
|
||||
@@ -217,9 +215,9 @@ export const parseAndInjectE2ESessions = async(node: BinaryNode, auth: SignalAut
|
||||
await Promise.all(
|
||||
nodes.map(
|
||||
async node => {
|
||||
const signedKey = getBinaryNodeChild(node, 'skey')
|
||||
const key = getBinaryNodeChild(node, 'key')
|
||||
const identity = getBinaryNodeChildBuffer(node, 'identity')
|
||||
const signedKey = getBinaryNodeChild(node, 'skey')!
|
||||
const key = getBinaryNodeChild(node, 'key')!
|
||||
const identity = getBinaryNodeChildBuffer(node, 'identity')!
|
||||
const jid = node.attrs.jid
|
||||
const registrationId = getBinaryNodeChildUInt(node, 'registration', 4)
|
||||
|
||||
@@ -237,13 +235,13 @@ export const parseAndInjectE2ESessions = async(node: BinaryNode, auth: SignalAut
|
||||
}
|
||||
|
||||
export const extractDeviceJids = (result: BinaryNode, myJid: string, excludeZeroDevices: boolean) => {
|
||||
const { user: myUser, device: myDevice } = jidDecode(myJid)
|
||||
const { user: myUser, device: myDevice } = jidDecode(myJid)!
|
||||
const extracted: JidWithDevice[] = []
|
||||
for(const node of result.content as BinaryNode[]) {
|
||||
const list = getBinaryNodeChild(node, 'list')?.content
|
||||
if(list && Array.isArray(list)) {
|
||||
for(const item of list) {
|
||||
const { user } = jidDecode(item.attrs.jid)
|
||||
const { user } = jidDecode(item.attrs.jid)!
|
||||
const devicesNode = getBinaryNodeChild(item, 'devices')
|
||||
const deviceListNode = getBinaryNodeChild(devicesNode, 'device-list')
|
||||
if(Array.isArray(deviceListNode?.content)) {
|
||||
|
||||
@@ -15,12 +15,12 @@ import { BufferJSON } from './generics'
|
||||
export const useMultiFileAuthState = async(folder: string): Promise<{ state: AuthenticationState, saveCreds: () => Promise<void> }> => {
|
||||
|
||||
const writeData = (data: any, file: string) => {
|
||||
return writeFile(join(folder, fixFileName(file)), JSON.stringify(data, BufferJSON.replacer))
|
||||
return writeFile(join(folder, fixFileName(file)!), JSON.stringify(data, BufferJSON.replacer))
|
||||
}
|
||||
|
||||
const readData = async(file: string) => {
|
||||
try {
|
||||
const data = await readFile(join(folder, fixFileName(file)), { encoding: 'utf-8' })
|
||||
const data = await readFile(join(folder, fixFileName(file)!), { encoding: 'utf-8' })
|
||||
return JSON.parse(data, BufferJSON.reviver)
|
||||
} catch(error) {
|
||||
return null
|
||||
@@ -29,7 +29,7 @@ export const useMultiFileAuthState = async(folder: string): Promise<{ state: Aut
|
||||
|
||||
const removeData = async(file: string) => {
|
||||
try {
|
||||
await unlink(fixFileName(file))
|
||||
await unlink(fixFileName(file)!)
|
||||
} catch{
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ const getClientPayload = (config: ClientPayloadConfig): proto.IClientPayload =>
|
||||
}
|
||||
|
||||
export const generateLoginNode = (userJid: string, config: ClientPayloadConfig): proto.IClientPayload => {
|
||||
const { user, device } = jidDecode(userJid)
|
||||
const { user, device } = jidDecode(userJid)!
|
||||
const payload: proto.IClientPayload = {
|
||||
...getClientPayload(config),
|
||||
passive: true,
|
||||
@@ -137,7 +137,7 @@ export const configureSuccessfulPairing = (
|
||||
const deviceMsg = Buffer.concat([ Buffer.from([6, 1]), deviceDetails, signedIdentityKey.public, accountSignatureKey ])
|
||||
account.deviceSignature = Curve.sign(signedIdentityKey.private, deviceMsg)
|
||||
// do not provide the "accountSignatureKey" back
|
||||
account.accountSignatureKey = null
|
||||
account.accountSignatureKey = Buffer.alloc(0)
|
||||
|
||||
const identity = createSignalIdentity(jid, accountSignatureKey)
|
||||
const accountEnc = proto.ADVSignedDeviceIdentity.encode(account).finish()
|
||||
|
||||
Reference in New Issue
Block a user