Skip to content

Commit 7ef97e0

Browse files
committed
fix(events): detect premium/lottie stickers wrapped in lottieStickerMessage
1 parent 053c1f6 commit 7ef97e0

2 files changed

Lines changed: 40 additions & 6 deletions

File tree

src/events/decoders/messages.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ const WRAPPER_FIELDS = [
8080
'viewOnceMessageV2Extension',
8181
'documentWithCaptionMessage',
8282
'editedMessage',
83+
'lottieStickerMessage',
8384
] as const
8485

8586
const unwrap = (content: Record<string, unknown>): Record<string, unknown> => {
@@ -99,6 +100,13 @@ const unwrap = (content: Record<string, unknown>): Record<string, unknown> => {
99100
return node
100101
}
101102

103+
const unwrappedMessage = (msg: WAMessage): WAMessage => {
104+
const content = asRecord(msg.message)
105+
if (content == null) return msg
106+
const inner = unwrap(content)
107+
return inner === content ? msg : ({ ...msg, message: inner } as WAMessage)
108+
}
109+
102110
const richResponseText = (content: Record<string, unknown>): string | null => {
103111
const forwarded = asRecord(asRecord(asRecord(content['botForwardedMessage'])?.['message'])?.['richResponseMessage'])
104112
const rich = forwarded ?? asRecord(content['richResponseMessage'])
@@ -480,12 +488,12 @@ const anyText = (msg: WAMessage): string | null => {
480488
}
481489

482490
const contextInfoOf = (msg: WAMessage): WAContextInfo | null => {
483-
const content = msg.message
491+
const content = asRecord(unwrappedMessage(msg).message)
484492
if (content == null) return null
485-
const ext = content.extendedTextMessage?.contextInfo
493+
const ext = asRecord(content['extendedTextMessage'])?.['contextInfo'] as WAContextInfo | undefined
486494
if (ext != null) return ext
487495
for (const field of Object.values(MEDIA_FIELD)) {
488-
const node = (content as Record<string, unknown>)[field]
496+
const node = content[field]
489497
if (node != null && typeof node === 'object') {
490498
const ci = (node as { contextInfo?: WAContextInfo | null }).contextInfo
491499
if (ci != null) return ci
@@ -729,10 +737,11 @@ const buildMediaAttachment = (
729737
kind: MediaKind,
730738
ctx: DecodeContext,
731739
): MediaAttachment | null => {
732-
const node = mediaNodeOf(msg, kind)
740+
const norm = unwrappedMessage(msg)
741+
const node = mediaNodeOf(norm, kind)
733742
if (node === null) return null
734-
const bufferFn = createDownloadFn(msg, kind, ctx.logger)
735-
const streamFn = createStreamFn(msg, kind, ctx.logger)
743+
const bufferFn = createDownloadFn(norm, kind, ctx.logger)
744+
const streamFn = createStreamFn(norm, kind, ctx.logger)
736745
return {
737746
type: kind,
738747
mimetype: typeof node.mimetype === 'string' ? node.mimetype : null,

tests/events/decoders/messages.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const {
2222
decodeAudio,
2323
decodeDocument,
2424
decodeSticker,
25+
decodeMessage,
2526
decodeMention,
2627
decodeMentionAll,
2728
} = await import('../../../src/events/decoders/messages.js')
@@ -328,6 +329,30 @@ describe('decodeSticker', () => {
328329
expect(out?.chatType).toBe('sticker')
329330
expect(out?.media).toBeDefined()
330331
})
332+
it('decodes a premium/lottie sticker wrapped in lottieStickerMessage', () => {
333+
const lottie = base({
334+
message: {
335+
messageContextInfo: { messageSecret: 'secret' },
336+
lottieStickerMessage: {
337+
message: {
338+
stickerMessage: {
339+
mimetype: 'application/was',
340+
fileLength: '31525',
341+
isAnimated: true,
342+
isLottie: true,
343+
mediaKey: 'k',
344+
url: 'https://mmg.whatsapp.net/x.enc',
345+
directPath: '/v/x.enc',
346+
},
347+
},
348+
},
349+
},
350+
} as unknown as Partial<WAMessage>)
351+
const sticker = decodeSticker(lottie, ctx)
352+
expect(sticker?.chatType).toBe('sticker')
353+
expect(sticker?.media?.type).toBe('sticker')
354+
expect(decodeMessage(lottie, ctx)?.chatType).toBe('sticker')
355+
})
331356
it('returns null without stickerMessage', () => {
332357
expect(decodeSticker(base({ message: {} }), ctx)).toBeNull()
333358
})

0 commit comments

Comments
 (0)