SquatchMail.Web.WebhookController (SquatchMail v0.1.0)

Copy Markdown View Source

Receives inbound Amazon SNS/SES event notifications at POST <dashboard_path>/webhooks/sns/:token.

This route intentionally lives outside the dashboard's live_session pipe (see SquatchMail.Web.Router): it is a machine-to-machine API endpoint authenticated by the per-source :token path segment, not a browser session, so it skips CSRF protection and session fetching entirely.

Raw body requirement

SNS signature verification needs the exact bytes SNS sent. The pipeline that mounts this route must configure Plug.Parsers with body_reader: {SquatchMail.SNS.RawBodyReader, :read_body, []} (scoped to this path is enough) so conn.assigns[:raw_body] is populated - see SquatchMail.SNS.RawBodyReader's moduledoc for the exact plug pipeline snippet. If :raw_body isn't set (misconfigured pipeline), this falls back to re-encoding conn.params as JSON, which is not byte-identical to what SNS sent and will fail signature verification - that fallback exists only so the endpoint still responds predictably instead of crashing on a nil body.

This is a plain Plug, not a Phoenix.Controller (same pattern as SquatchMail.Web.AssetController) - Phoenix's router dispatches get/ post to either kind of module identically (post "/path", Module, :create), and a webhook endpoint doing a single JSON-in/status-code-out exchange doesn't need view/format negotiation.

Summary

Functions

Handles the inbound webhook POST. Always responds within the request cycle - SNS treats non-2xx as "retry", so the status code doubles as retry/no-retry signaling

Functions

call(conn, atom)

Handles the inbound webhook POST. Always responds within the request cycle - SNS treats non-2xx as "retry", so the status code doubles as retry/no-retry signaling:

  • 200 - processed or intentionally ignored (no retry wanted).
  • 404 - unknown :token (retrying won't help; the token is wrong).
  • 403 - signature verification failed (retrying won't help either; it'll fail again unless the payload changes, which SNS won't do).
  • 500 - a transient failure (SubscribeURL confirmation GET failed, DB hiccup, etc) - retryable, so SNS retrying is the desired behavior.