Merge branch 'master' into invalid-qr-patch

This commit is contained in:
Adhiraj Singh
2022-04-22 18:20:17 +05:30
4 changed files with 61 additions and 25 deletions

View File

@@ -276,6 +276,11 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
} }
} }
const willSendMessageAgain = (id: string) => {
const retryCount = msgRetryMap[id] || 0
return retryCount < 5
}
const sendMessagesAgain = async(key: proto.IMessageKey, ids: string[]) => { const sendMessagesAgain = async(key: proto.IMessageKey, ids: string[]) => {
const msgs = await Promise.all( const msgs = await Promise.all(
ids.map(id => ( ids.map(id => (
@@ -294,6 +299,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
for(let i = 0; i < msgs.length;i++) { for(let i = 0; i < msgs.length;i++) {
if(msgs[i]) { if(msgs[i]) {
msgRetryMap[ids[i]] = (msgRetryMap[ids[i]] || 0) + 1
await relayMessage(key.remoteJid, msgs[i], { await relayMessage(key.remoteJid, msgs[i], {
messageId: ids[i], messageId: ids[i],
participant participant
@@ -363,18 +369,22 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
} }
if(attrs.type === 'retry') { if(attrs.type === 'retry') {
// correctly set who is asking for the retry if(willSendMessageAgain(ids[0])) {
key.participant = key.participant || attrs.from // correctly set who is asking for the retry
if(key.fromMe) { key.participant = key.participant || attrs.from
try { if(key.fromMe) {
logger.debug({ attrs, key }, 'recv retry request') try {
await sendMessagesAgain(key, ids) logger.debug({ attrs, key }, 'recv retry request')
} catch(error) { await sendMessagesAgain(key, ids)
logger.error({ key, ids, trace: error.stack }, 'error in sending message again') } catch(error) {
shouldAck = false logger.error({ key, ids, trace: error.stack }, 'error in sending message again')
shouldAck = false
}
} else {
logger.info({ attrs, key }, 'recv retry for not fromMe message')
} }
} else { } else {
logger.info({ attrs, key }, 'recv retry for not fromMe message') logger.info({ attrs, key }, 'will not send message again, as sent too many times')
} }
} }

View File

@@ -103,6 +103,7 @@ export type AnyMediaMessageContent = (
export type AnyRegularMessageContent = ( export type AnyRegularMessageContent = (
({ ({
text: string text: string
linkPreview?: WAUrlInfo
} }
& Mentionable & Buttonable & Templatable & Listable) | & Mentionable & Buttonable & Templatable & Listable) |
AnyMediaMessageContent | AnyMediaMessageContent |
@@ -177,3 +178,9 @@ export type WAMessageUpdate = { update: Partial<WAMessage>, key: proto.IMessageK
export type WAMessageCursor = { before: WAMessageKey | undefined } | { after: WAMessageKey | undefined } export type WAMessageCursor = { before: WAMessageKey | undefined } | { after: WAMessageKey | undefined }
export type MessageUserReceiptUpdate = { key: proto.IMessageKey, receipt: MessageUserReceipt } export type MessageUserReceiptUpdate = { key: proto.IMessageKey, receipt: MessageUserReceipt }
export type MediaDecryptionKeyInfo = {
iv: Buffer
cipherKey: Buffer
macKey?: Buffer
}

View File

@@ -11,7 +11,7 @@ import type { Logger } from 'pino'
import { Readable, Transform } from 'stream' import { Readable, Transform } from 'stream'
import { URL } from 'url' import { URL } from 'url'
import { DEFAULT_ORIGIN, MEDIA_PATH_MAP } from '../Defaults' import { DEFAULT_ORIGIN, MEDIA_PATH_MAP } from '../Defaults'
import { CommonSocketConfig, DownloadableMessage, MediaConnInfo, MediaType, MessageType, WAGenericMediaMessage, WAMediaUpload, WAMediaUploadFunction, WAMessageContent, WAProto } from '../Types' import { CommonSocketConfig, DownloadableMessage, MediaConnInfo, MediaDecryptionKeyInfo, MediaType, MessageType, WAGenericMediaMessage, WAMediaUpload, WAMediaUploadFunction, WAMessageContent, WAProto } from '../Types'
import { hkdf } from './crypto' import { hkdf } from './crypto'
import { generateMessageID } from './generics' import { generateMessageID } from './generics'
@@ -60,7 +60,7 @@ export const hkdfInfoKey = (type: MediaType) => {
} }
/** generates all the keys required to encrypt/decrypt & sign a media message */ /** generates all the keys required to encrypt/decrypt & sign a media message */
export function getMediaKeys(buffer, mediaType: MediaType) { export function getMediaKeys(buffer: Uint8Array | string, mediaType: MediaType): MediaDecryptionKeyInfo {
if(typeof buffer === 'string') { if(typeof buffer === 'string') {
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64') buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64')
} }
@@ -186,6 +186,7 @@ export const toBuffer = async(stream: Readable) => {
buff = Buffer.concat([ buff, chunk ]) buff = Buffer.concat([ buff, chunk ])
} }
stream.destroy()
return buff return buff
} }
@@ -343,12 +344,26 @@ export type MediaDownloadOptions = {
endByte?: number endByte?: number
} }
export const downloadContentFromMessage = async( export const downloadContentFromMessage = (
{ mediaKey, directPath, url }: DownloadableMessage, { mediaKey, directPath, url }: DownloadableMessage,
type: MediaType, type: MediaType,
{ startByte, endByte }: MediaDownloadOptions = { } opts: MediaDownloadOptions = { }
) => { ) => {
const downloadUrl = url || `https://${DEF_HOST}${directPath}` const downloadUrl = url || `https://${DEF_HOST}${directPath}`
const keys = getMediaKeys(mediaKey, type)
return downloadEncryptedContent(downloadUrl, keys, opts)
}
/**
* Decrypts and downloads an AES256-CBC encrypted file given the keys.
* Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
* */
export const downloadEncryptedContent = async(
downloadUrl: string,
{ cipherKey, iv }: MediaDecryptionKeyInfo,
{ startByte, endByte }: MediaDownloadOptions = { }
) => {
let bytesFetched = 0 let bytesFetched = 0
let startChunk = 0 let startChunk = 0
let firstBlockIsIV = false let firstBlockIsIV = false
@@ -386,7 +401,6 @@ export const downloadContentFromMessage = async(
) )
let remainingBytes = Buffer.from([]) let remainingBytes = Buffer.from([])
const { cipherKey, iv } = getMediaKeys(mediaKey, type)
let aes: Crypto.Decipher let aes: Crypto.Decipher

View File

@@ -17,7 +17,7 @@ import {
WAMessageContent, WAMessageContent,
WAMessageStatus, WAMessageStatus,
WAProto, WAProto,
WATextMessage WATextMessage,
} from '../Types' } from '../Types'
import { generateMessageID, unixTimestampSeconds } from './generics' import { generateMessageID, unixTimestampSeconds } from './generics'
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, MediaDownloadOptions } from './messages-media' import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, MediaDownloadOptions } from './messages-media'
@@ -245,21 +245,26 @@ export const generateWAMessageContent = async(
) => { ) => {
let m: WAMessageContent = {} let m: WAMessageContent = {}
if('text' in message) { if('text' in message) {
const extContent = { ...message } as WATextMessage const extContent = { text: message.text } as WATextMessage
if(!!options.getUrlInfo && message.text.match(URL_REGEX)) {
let urlInfo = message.linkPreview
if(!urlInfo && !!options.getUrlInfo && message.text.match(URL_REGEX)) {
try { try {
const data = await options.getUrlInfo(message.text) urlInfo = await options.getUrlInfo(message.text)
extContent.canonicalUrl = data['canonical-url']
extContent.matchedText = data['matched-text']
extContent.jpegThumbnail = data.jpegThumbnail
extContent.description = data.description
extContent.title = data.title
extContent.previewType = 0
} catch(error) { // ignore if fails } catch(error) { // ignore if fails
options.logger?.warn({ trace: error.stack }, 'url generation failed') options.logger?.warn({ trace: error.stack }, 'url generation failed')
} }
} }
if(urlInfo) {
extContent.canonicalUrl = urlInfo['canonical-url']
extContent.matchedText = urlInfo['matched-text']
extContent.jpegThumbnail = urlInfo.jpegThumbnail
extContent.description = urlInfo.description
extContent.title = urlInfo.title
extContent.previewType = 0
}
m.extendedTextMessage = extContent m.extendedTextMessage = extContent
} else if('contacts' in message) { } else if('contacts' in message) {
const contactLen = message.contacts.contacts.length const contactLen = message.contacts.contacts.length