diff --git a/docker-compose.yaml b/docker-compose.yaml index 2eefb398..d33772c5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -36,10 +36,10 @@ services: - DATABASE_CONNECTION_URI=mongodb://root:root@mongodb:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true - DATABASE_CONNECTION_DB_PREFIX_NAME=evolution # Choose the data you want to save in the application's database or store - - DATABASE_SAVE_DATA_INSTANCE=false + - DATABASE_SAVE_DATA_INSTANCE=true - DATABASE_SAVE_DATA_OLD_MESSAGE=false - DATABASE_SAVE_DATA_NEW_MESSAGE=true - - DATABASE_SAVE_MESSAGE_UPDATE=false + - DATABASE_SAVE_MESSAGE_UPDATE=true - DATABASE_SAVE_DATA_CONTACTS=true - DATABASE_SAVE_DATA_CHATS=true - REDIS_ENABLED=true diff --git a/package.json b/package.json index 791a9e6f..7c282d68 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "cross-env": "^7.0.3", "dayjs": "^1.11.7", "eventemitter2": "^6.4.9", + "exiftool-vendored": "^22.0.0", "express": "^4.18.2", "express-async-errors": "^3.1.1", "hbs": "^4.2.0", diff --git a/src/utils/poll-update-decrypt-message.ts b/src/utils/poll-update-decrypt-message.ts deleted file mode 100644 index ab035e99..00000000 --- a/src/utils/poll-update-decrypt-message.ts +++ /dev/null @@ -1,164 +0,0 @@ -// Built around ShellTear's POC at #2215#issuecomment-1292885678 on @adiwajshing/baileys -// Copyright ~ purpshell - -import crypto from 'node:crypto'; - -const enc = new TextEncoder(); -/** - * Decrypt PollUpdate messages - */ -export class PollUpdateDecrypt { - /** - * Compare the SHA-256 hashes of the poll options from the update to find the original choices - * @param options Options from the poll creation message - * @param pollOptionHash hash from `this.decrypt()` - * @returns the original option, can be empty when none are currently selected - */ - static async compare(options: string[], pollOptionHashes: string[]): Promise { - const selectedOptions = []; - for (const option of options) { - const hash = Buffer.from( - await crypto.webcrypto.subtle.digest('SHA-256', new TextEncoder().encode(option)), - ) - .toString('hex') - .toUpperCase(); - for (const pollOptionHash of pollOptionHashes) { - if (pollOptionHash === hash) { - selectedOptions.push(option); - } - } - } - return selectedOptions; - } - - /** - * decrypt a poll message update - * @param encPayload from the update - * @param encIv from the update - * @param encKey from the original poll - * @param pollMsgSender sender jid of the pollCreation message - * @param pollMsgId id of the pollCreation message - * @param voteMsgSender sender of the pollUpdate message - * @returns The option or empty array if something went wrong OR everything was unticked - */ - static async decrypt( - encKey: Uint8Array, - encPayload: Uint8Array, - encIv: Uint8Array, - pollMsgSender: string, - pollMsgId: string, - voteMsgSender: string, - ): Promise { - const stanzaId = enc.encode(pollMsgId); - const parentMsgOriginalSender = enc.encode(pollMsgSender); - const modificationSender = enc.encode(voteMsgSender); - const modificationType = enc.encode('Poll Vote'); - const pad = new Uint8Array([1]); - - const signMe = new Uint8Array([ - ...stanzaId, - ...parentMsgOriginalSender, - ...modificationSender, - ...modificationType, - pad, - ] as any); - - const createSignKey = async (n: Uint8Array = new Uint8Array(32)) => { - return await crypto.webcrypto.subtle.importKey( - 'raw', - n, - { name: 'HMAC', hash: 'SHA-256' }, - false, - ['sign'], - ); - }; - - const sign = async ( - n: crypto.webcrypto.BufferSource, - key: crypto.webcrypto.CryptoKey, - ) => { - return await crypto.webcrypto.subtle.sign( - { name: 'HMAC', hash: 'SHA-256' }, - key, - n, - ); - }; - - let key = await createSignKey(); - - const temp = await sign(encKey, key); - - key = await createSignKey(new Uint8Array(temp)); - - const decryptionKey = new Uint8Array(await sign(signMe, key)); - - const additionalData = enc.encode(`${pollMsgId}\u0000${voteMsgSender}`); - - const decryptedMessage = await this._decryptMessage( - encPayload, - encIv, - additionalData, - decryptionKey, - ); - - const pollOptionHash = this._decodeMessage(decryptedMessage); - - // '0A20' in hex represents unicode " " and "\n" thus declaring the end of one option - // we want multiple hashes to make it easier to iterate and understand for your use cases - return pollOptionHash.split('0A20') || []; - } - - /** - * Internal method to decrypt the message after gathering all information - * @deprecated Use `this.decrypt()` instead, only use this if you know what you are doing - * @param encPayload - * @param encIv - * @param additionalData - * @param decryptionKey - * @returns - */ - static async _decryptMessage( - encPayload: Uint8Array, - encIv: Uint8Array, - additionalData: Uint8Array, - decryptionKey: Uint8Array, - ) { - const tagSize_multiplier = 16; - const encoded = encPayload; - const key = await crypto.webcrypto.subtle.importKey( - 'raw', - decryptionKey, - 'AES-GCM', - false, - ['encrypt', 'decrypt'], - ); - const decrypted = await crypto.webcrypto.subtle.decrypt( - { - name: 'AES-GCM', - iv: encIv, - additionalData: additionalData, - tagLength: 8 * tagSize_multiplier, - }, - key, - encoded, - ); - return new Uint8Array(decrypted).slice(2); // remove 2 bytes (OA20)(space+newline) - } - - /** - * Decode the message from `this._decryptMessage()` - * @param decryptedMessage the message from `this._decrpytMessage()` - * @returns - */ - static _decodeMessage(decryptedMessage: Uint8Array) { - const n = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70]; - const outarr: number[] = []; - - for (let i = 0; i < decryptedMessage.length; i++) { - const val = decryptedMessage[i]; - outarr.push(n[val >> 4], n[15 & val]); - } - - return String.fromCharCode(...outarr); - } -} diff --git a/src/whatsapp/services/monitor.service.ts b/src/whatsapp/services/monitor.service.ts index 89462b7a..64770751 100644 --- a/src/whatsapp/services/monitor.service.ts +++ b/src/whatsapp/services/monitor.service.ts @@ -224,6 +224,7 @@ export class WAMonitoringService { await set(dirent.name); } } + initInstance(); } catch (error) { this.logger.error(error); } diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index cb5d67e6..8895c356 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -29,12 +29,7 @@ import makeWASocket, { WAMessage, WAMessageUpdate, WASocket, - WAMessageKey, - WAMessageContent, getAggregateVotesInPollMessage, - jidNormalizedUser, - getKeyAuthor, - decryptPollVote, } from '@evolution/base'; import { Auth, @@ -44,10 +39,8 @@ import { Database, QrCode, Redis, - StoreConf, Webhook, } from '../../config/env.config'; -import { PollUpdateDecrypt } from '../../utils/poll-update-decrypt-message'; import fs from 'fs'; import { Logger } from '../../config/logger.config'; import { INSTANCE_DIR, ROOT_DIR } from '../../config/path.config'; @@ -119,7 +112,6 @@ import { WebhookRaw } from '../models/webhook.model'; import { dbserver } from '../../db/db.connect'; import NodeCache from 'node-cache'; import { useMultiFileAuthStateRedisDb } from '../../utils/use-multi-file-auth-state-redis-db'; -import { promisify } from 'util'; import sharp from 'sharp'; export class WAStartupService { @@ -726,49 +718,6 @@ export class WAStartupService { received.messageTimestamp = received.messageTimestamp?.toNumber(); } - // if (received.message?.pollUpdateMessage) { - // const creationMsgKey = received.message.pollUpdateMessage.pollCreationMessageKey; - // const pollCreation = (await this.getMessage( - // creationMsgKey, - // true, - // )) as proto.IWebMessageInfo; - - // if (pollCreation) { - // const meIdNormalised = jidNormalizedUser(this.instance.wuid); - // const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised); - // const voterJid = getKeyAuthor(received.key!, meIdNormalised); - // const pollEncKey = pollCreation.message?.messageContextInfo?.messageSecret; - // // const voteMsg = decryptPollVote(received.message.pollUpdateMessage.vote, { - // // pollEncKey, - // // pollCreatorJid, - // // pollMsgId: creationMsgKey.id, - // // voterJid, - // // }); - // // console.log('voteMsg: ', voteMsg); - // // console.log( - // // pollEncKey, - // // received.message?.pollUpdateMessage.vote.encPayload, - // // received.message?.pollUpdateMessage.vote.encIv, - // // pollCreatorJid, - // // pollCreation.key.id, - // // voterJid, - // // ); - // const hash = await PollUpdateDecrypt.decrypt( - // pollEncKey, // from PollCreationMessage, HAS to be Uint8Array - // received.message?.pollUpdateMessage.vote.encPayload, // from PollUpdateMessage, HAS to be Uint8Array - // received.message?.pollUpdateMessage.vote.encIv, // from PollUpdateMessage, HAS to be Uint8Array - // pollCreatorJid, // PollCreationMessage sender jid (author) - // pollCreation.key.id, // Message ID of the PollCreationMessage (can be gotten via the store & pollCreationMessageKey property on the update) - // voterJid, // PollUpdateMessage sender jid (author) \\ from above - // ); - // const opt = pollCreation.message?.pollCreationMessage?.options.map( - // (o) => o.optionName, - // ); - // const option = await PollUpdateDecrypt.compare(opt, hash); - // console.log('option: ', option); - // } - // } - const messageRaw: MessageRaw = { key: received.key, pushName: received.pushName, @@ -1218,6 +1167,7 @@ export class WAStartupService { imagePath = `${join(process.cwd(), 'temp', 'temp-sticker.png')}`; await sharp(imageBuffer).toFile(imagePath); } + await sharp(imagePath).webp().toFile(outputPath); return outputPath; diff --git a/temp/sticker.webp b/temp/sticker.webp index b04e82da..4ceb886e 100644 Binary files a/temp/sticker.webp and b/temp/sticker.webp differ diff --git a/temp/sticker.webp_original b/temp/sticker.webp_original new file mode 100644 index 00000000..b04e82da Binary files /dev/null and b/temp/sticker.webp_original differ diff --git a/temp/temp-sticker.png b/temp/temp-sticker.png deleted file mode 100644 index fde5f86f..00000000 Binary files a/temp/temp-sticker.png and /dev/null differ