MishkaCmsCore.Runtime.Plugs.RawBody (Mishka CMS Core v0.0.1)

Copy Markdown View Source

The bytes a webhook was sent, kept for its signature check.

A webhook is signed over its body exactly as it was sent — Svix (Resend), Stripe and GitHub all sign that way — and Plug.Parsers reads the body to decode it, so a route behind the endpoint sees only the decoded params. One decoded and encoded again is a different text and never matches.

Give the endpoint's parsers this body reader:

plug Plug.Parsers,
  parsers: [:urlencoded, :multipart, :json],
  pass: ["*/*"],
  json_decoder: Phoenix.json_library(),
  body_reader: {MishkaCmsCore.Runtime.Plugs.RawBody, :read_body, []}

A request whose path starts with /webhooks/ then keeps its body in conn.private[:raw_body] (raw_body/1) beside the params, and every other request is read as Plug reads it and keeps nothing. An extension mounts its webhooks under that prefix — /webhooks/<extension>/<sender> — through MishkaCmsCore.ExtensionRouter's :api routes.

The parsers' own :length limit applies, so a body is never kept past what they would read. A request whose content type no parser reads is not read at all, and keeps nothing: its route reads it with Plug.Conn.read_body/2.

Summary

Functions

The path prefix whose requests keep their body.

The body a webhook request was sent, or nil when it was not kept.

Plug.Conn.read_body/2, keeping what it reads when the request is a webhook's. For Plug.Parsers' :body_reader.

Functions

prefix()

@spec prefix() :: String.t()

The path prefix whose requests keep their body.

raw_body(conn)

@spec raw_body(Plug.Conn.t()) :: binary() | nil

The body a webhook request was sent, or nil when it was not kept.

read_body(conn, opts)

@spec read_body(Plug.Conn.t(), keyword()) ::
  {:ok, binary(), Plug.Conn.t()}
  | {:more, binary(), Plug.Conn.t()}
  | {:error, term()}

Plug.Conn.read_body/2, keeping what it reads when the request is a webhook's. For Plug.Parsers' :body_reader.