Serves attachment bytes, behind a signature.
plug Coelho.Plug.Attachments,
at: "/attachments",
storage: Coelho.Storage.Disk.new("priv/uploads"),
secret: {MyApp.Uploads, :secret, []},
metadata: {MyApp.Uploads, :metadata, []}Requests that do not match :at fall through untouched.
Options
:at— the path prefix to serve from, required:storage— aCoelho.Storage, or an{m, f, a}returning one, required. The{m, f, a}form matters in an endpoint, whereinit/1may run at compile time and a storage built then would freeze the configuration it was built from:secret— the signing secret, as a binary or an{m, f, a}read at request time, required. It has to match what built the URL; seeCoelho.Attachments.signed_url/4:metadata— an{m, f, a}called with the key, returning%{content_type: …, filename: …}ornil. Coelho does not hold a repo, so this is how the row reaches the response
Serving other people's files
Uploads served from the application's own origin are a standing hazard:
a file the browser decides to render as HTML runs as the application.
So a response carrying bytes always has x-content-type-options: nosniff,
and only a short list of image types is served inline. Everything else —
including SVG, which is a document that can carry script — is sent as a
download, whatever it claims to be.
A redirect carries none of those headers, which is why one is only offered
for the types that would have been served inline anyway, and why a storage
implementing Coelho.Storage.redirect_url/3 is expected to honour the
:content_type it is given.