Skip to content

feat: decrypt secret-encrypted message edits - #161

Open
FlavioPulli wants to merge 1 commit into
evolution-foundation:developfrom
FlavioPulli:fix/secret-message-edit-decrypt-develop
Open

feat: decrypt secret-encrypted message edits#161
FlavioPulli wants to merge 1 commit into
evolution-foundation:developfrom
FlavioPulli:fix/secret-message-edit-decrypt-develop

Conversation

@FlavioPulli

@FlavioPulli FlavioPulli commented Aug 4, 2026

Copy link
Copy Markdown

When a phone edits a message in a @lid-addressed chat, WhatsApp delivers the edit as secretEncryptedMessage (MESSAGE_EDIT): the new content is encrypted with the message secret of the original message — a secret the whatsmeow session already holds (it arrived inside the original message). Today the encrypted event is forwarded to the webhook as-is, so consumers learn that an edit happened but not what changed.

This decrypts it with whatsmeow's official primitive (Client.DecryptSecretEncryptedMessage, native EncSecretMessageEdit support) and rewrites the event into the canonical cleartext shape (protocolMessage MESSAGE_EDIT + editedMessage) — the same shape BuildEdit produces — so webhook consumers handle phone edits and app edits identically.

Fail-open by design: if the secret is missing (message predates the pairing) the event passes through unchanged. Self-contained file plus a one-line call-site to keep review/rebase easy. Battle-tested in our production since 2026-07-21.


Retargeted to develop (replaces #128), as requested by @iagocotta in #128 (comment).

Note that main and develop have no common ancestor — the GitHub API refuses to compare them (No common ancestor between main and develop) — so the base branch of the original PR could not simply be edited. This branch was created from develop and the commit cherry-picked onto it.

Verified on this branch: go build ./... and go vet ./... both pass.

Summary by Sourcery

Handle secret-encrypted message edits by decrypting them and normalizing them to the standard cleartext edit event shape before forwarding to webhooks.

New Features:

  • Support decryption of secretEncryptedMessage-based MESSAGE_EDIT events when the original message secret is available.
  • Normalize decrypted phone-originated edits into the canonical protocolMessage MESSAGE_EDIT + editedMessage format used for app-originated edits.
  • Preserve existing behavior by passing through encrypted edit events unchanged when decryption fails or the required secret is unavailable.

When a phone edits a message in a @lid-addressed chat, WhatsApp delivers
the edit as secretEncryptedMessage (MESSAGE_EDIT), encrypted with the
original message's "message secret" — which this whatsmeow session
already holds. Today the encrypted event is forwarded to the webhook
as-is, so consumers learn that an edit happened but not what changed.

Decrypt it with whatsmeow's official primitive
(Client.DecryptSecretEncryptedMessage, native EncSecretMessageEdit
support) and rewrite the event into the canonical cleartext shape
(protocolMessage MESSAGE_EDIT + editedMessage) — the same shape
BuildEdit produces — so webhook consumers handle phone edits and app
edits identically. Fail-open: if the secret is missing (message predates
the pairing) the event passes through unchanged.

Battle-tested in production since 2026-07-21 against real phone edits.
@sourcery-ai

sourcery-ai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Reviewer's Guide

Decrypts WhatsApp secretEncryptedMessage MESSAGE_EDIT events using whatsmeow’s official primitive and rewrites them into the canonical cleartext protocolMessage/editedMessage shape so webhook consumers see the actual edit content when possible, while failing open when decryption is not possible.

Sequence diagram for decrypting secretEncryptedMessage MESSAGE_EDIT before webhook forwarding

sequenceDiagram
    participant WhatsApp
    participant MyClient
    participant WAClient
    participant Webhook

    WhatsApp->>MyClient: events.Message (secretEncryptedMessage MESSAGE_EDIT)
    MyClient->>MyClient: myEventHandler
    MyClient->>MyClient: resolveSecretEncryptedEdit(evt)
    alt enc is MESSAGE_EDIT
        MyClient->>WAClient: DecryptSecretEncryptedMessage(context, evt)
        alt decryption succeeds
            WAClient-->>MyClient: decrypted waE2E.Message
            alt decrypted has ProtocolMessage MESSAGE_EDIT with editedMessage
                MyClient->>MyClient: evt.Message = decrypted
            else fallback shape
                MyClient->>MyClient: evt.Message = new waE2E.Message{ProtocolMessage MESSAGE_EDIT, EditedMessage: decrypted}
            end
        else decryption fails
            WAClient-->>MyClient: error
            MyClient->>MyClient: keep original evt.Message (encrypted)
        end
    else not a secretEncryptedMessage edit
        MyClient->>MyClient: return without changes
    end
    MyClient->>Webhook: postMap[event="Message"], evt.Message (possibly rewritten)
Loading

File-Level Changes

Change Details Files
Introduce helper to detect and decrypt secret-encrypted message edits and normalize them into the canonical protocolMessage MESSAGE_EDIT shape, failing open when decryption is not possible.
  • Added resolveSecretEncryptedEdit method on MyClient that inspects incoming events for secretEncryptedMessage edits and returns early when not applicable.
  • Integrated whatsmeow’s Client.DecryptSecretEncryptedMessage to decrypt MESSAGE_EDIT payloads using the stored original message secret.
  • Implemented logging for both decryption failures (e.g., missing secret) and successful decryptions to aid observability of edit handling.
  • Normalized decrypted edits: when the decrypted payload is already a protocolMessage MESSAGE_EDIT with editedMessage, reuse it directly; otherwise, wrap the decrypted content into a new protocolMessage MESSAGE_EDIT with appropriate key and timestamp metadata, preserving event compatibility with BuildEdit output.
  • Kept the secret edit handling self-contained in a new secret_edit.go file under the whatsmeow service package to simplify future rebases and whatsmeow upgrades.
pkg/whatsmeow/service/secret_edit.go
Wire secret edit resolution into the main WhatsApp event handler so that incoming message events are transparently normalized before webhook forwarding.
  • Inserted a call to resolveSecretEncryptedEdit in myEventHandler before existing message logging and webhook-related processing so edits are decrypted and reshaped early.
  • Documented in-line that secret-encrypted edits are converted to cleartext protocolMessage events when the original message’s secret is known, pointing reviewers to secret_edit.go for details.
pkg/whatsmeow/service/whatsmeow.go

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant