Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/jobs/incoming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import logger from '../services/logger'
import fetch, { Response } from 'node-fetch'
import mime from 'mime-types'
import { generateUnoId } from '../utils/id'
import { convertToWebpSticker, MAX_STICKER_BYTES } from '../utils/sticker_convert'

export class IncomingJob {
private incoming: Incoming
Expand Down Expand Up @@ -65,11 +66,16 @@ export class IncomingJob {
const { mediaStore } = await config.getStore(phone, config)
const mediaKey = `${phone}/${idUno}`
const link = payload[payload.type].link
const mimetype = getMimetype(payload)
let mimetype = getMimetype(payload)
const extension = mime.extension(mimetype)
const fileName = `${mediaKey}.${extension}`
const response: Response = await fetch(link, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), method: 'GET' })
const buffer = toBuffer(await response.arrayBuffer())
let buffer: Buffer = toBuffer(await response.arrayBuffer())
if (payload.type === 'sticker' && buffer.byteLength <= MAX_STICKER_BYTES) {
const animated = extension == 'gif'
buffer = await convertToWebpSticker(buffer, { animated })
mimetype = 'image/webp'
}
await mediaStore.saveMediaBuffer(fileName, buffer)
Comment on lines +69 to 79
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Bug: file saved with original extension after webp conversion.

fileName is computed on line 71 using the original mimetype's extension (e.g. .gif, .png), but after the sticker-to-webp conversion the buffer contains webp data. The file is then saved at line 79 with the mismatched extension, which will cause issues when the media is later served or consumed.

Recompute fileName after conversion so the extension reflects the actual content.

🐛 Proposed fix
         let buffer: Buffer = toBuffer(await response.arrayBuffer())
         if (payload.type === 'sticker' && buffer.byteLength <= MAX_STICKER_BYTES) {
           const animated = extension == 'gif'
           buffer = await convertToWebpSticker(buffer, { animated })
           mimetype = 'image/webp'
         }
-        await mediaStore.saveMediaBuffer(fileName, buffer)
+        const finalExtension = mime.extension(mimetype) || extension
+        const finalFileName = `${mediaKey}.${finalExtension}`
+        await mediaStore.saveMediaBuffer(finalFileName, buffer)

Also update messagePayload to use finalFileName if the filename is referenced downstream.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let mimetype = getMimetype(payload)
const extension = mime.extension(mimetype)
const fileName = `${mediaKey}.${extension}`
const response: Response = await fetch(link, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), method: 'GET' })
const buffer = toBuffer(await response.arrayBuffer())
let buffer: Buffer = toBuffer(await response.arrayBuffer())
if (payload.type === 'sticker' && buffer.byteLength <= MAX_STICKER_BYTES) {
const animated = extension == 'gif'
buffer = await convertToWebpSticker(buffer, { animated })
mimetype = 'image/webp'
}
await mediaStore.saveMediaBuffer(fileName, buffer)
let mimetype = getMimetype(payload)
const extension = mime.extension(mimetype)
const fileName = `${mediaKey}.${extension}`
const response: Response = await fetch(link, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), method: 'GET' })
let buffer: Buffer = toBuffer(await response.arrayBuffer())
if (payload.type === 'sticker' && buffer.byteLength <= MAX_STICKER_BYTES) {
const animated = extension == 'gif'
buffer = await convertToWebpSticker(buffer, { animated })
mimetype = 'image/webp'
}
const finalExtension = mime.extension(mimetype) || extension
const finalFileName = `${mediaKey}.${finalExtension}`
await mediaStore.saveMediaBuffer(finalFileName, buffer)
🤖 Prompt for AI Agents
In `@src/jobs/incoming.ts` around lines 69 - 79, The file is saved using fileName
computed from the original mimetype, so after converting stickers to webp the
saved file keeps the wrong extension; update the logic in the incoming handler
(where getMimetype, mime.extension and fileName are used) to recompute the
extension and fileName after convertToWebpSticker when payload.type ===
'sticker' (set mimetype = 'image/webp' already done — ensure you also set a new
finalFileName using mime.extension(mimetype) before calling
mediaStore.saveMediaBuffer), and make sure any downstream reference such as
messagePayload uses that finalFileName instead of the original fileName.

messagePayload = {
filename: payload[payload.type].filename,
Expand Down
1 change: 1 addition & 0 deletions src/services/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ export const toBaileysMessageContent = (payload: any, customMessageCharactersFun
case 'audio':
case 'document':
case 'video':
case 'sticker':
const link = payload[type].link
if (link) {
let mimetype: string = getMimetype(payload)
Expand Down
15 changes: 15 additions & 0 deletions src/utils/sticker_convert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import sharp from 'sharp'

type StickerConvertOptions = {
animated?: boolean
}

export const MAX_STICKER_BYTES = 8 * 1024 * 1024

export const convertToWebpSticker = async (input: Buffer, opts: StickerConvertOptions = {}) => {
const image = sharp(input, { animated: !!opts.animated })
return image
.resize(512, 512, { fit: 'inside', withoutEnlargement: true })
.webp({ lossless: !opts.animated, quality: 80, effort: 4 })
.toBuffer()
}