From 8dbb22cc930ffeeb87df78daa1c45311466f84f8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 10 Jan 2026 19:13:23 +0100 Subject: [PATCH] fix: signal handle dataMessage.reaction safely (#637) (thanks @neist) --- CHANGELOG.md | 1 + src/signal/monitor.ts | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 100fa3575..bb3086bcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - iOS/Android: enable stricter concurrency/lint checks; fix Swift 6 strict concurrency issues + Android lint errors (ExifInterface, obsolete SDK check). (#662) — thanks @KristijanJovanovski. - iOS/macOS: share `AsyncTimeout`, require explicit `bridgeStableID` on connect, and harden tool display defaults (avoids missing-resource label fallbacks). - Telegram: serialize media-group processing to avoid missed albums under load. +- Signal: handle `dataMessage.reaction` events (signal-cli SSE) to avoid broken attachment errors. (#637) — thanks @neist. - Docs: showcase entries for ParentPay, R2 Upload, iOS TestFlight, and Oura Health. (#650) — thanks @henrino3. ## 2026.1.9 diff --git a/src/signal/monitor.ts b/src/signal/monitor.ts index fe27016cb..34f0c7f44 100644 --- a/src/signal/monitor.ts +++ b/src/signal/monitor.ts @@ -144,6 +144,20 @@ function resolveSignalReactionTargets( return targets; } +function isSignalReactionMessage( + reaction: SignalReactionMessage | null | undefined, +): reaction is SignalReactionMessage { + if (!reaction) return false; + const emoji = reaction.emoji?.trim(); + const timestamp = reaction.targetSentTimestamp; + const hasTarget = Boolean( + reaction.targetAuthor?.trim() || reaction.targetAuthorUuid?.trim(), + ); + return Boolean( + emoji && typeof timestamp === "number" && timestamp > 0 && hasTarget, + ); +} + function shouldEmitSignalReactionNotification(params: { mode?: SignalReactionNotificationMode; account?: string | null; @@ -404,8 +418,11 @@ export async function monitorSignalProvider( } const dataMessage = envelope.dataMessage ?? envelope.editMessage?.dataMessage; - const reaction = - envelope.reactionMessage ?? dataMessage?.reaction ?? null; + const reaction = isSignalReactionMessage(envelope.reactionMessage) + ? envelope.reactionMessage + : isSignalReactionMessage(dataMessage?.reaction) + ? dataMessage?.reaction + : null; const messageText = (dataMessage?.message ?? "").trim(); const quoteText = dataMessage?.quote?.text?.trim() ?? ""; const hasBodyContent =