Documentation
¶
Overview ¶
Package secheaders sets the response headers filex sends for the browser's sake on every answer, whatever serves it and wherever filex is deployed — so every self-hosted install has them, not only one whose reverse proxy adds them:
- X-Content-Type-Options: nosniff — a body is what its Content-Type says, never what the browser guesses from its bytes;
- Referrer-Policy: strict-origin-when-cross-origin — another site is told which filex a link came from, never the path (a folder or file name);
- Content-Security-Policy: frame-ancestors 'self' [allowed…] — on the pages filex draws (HTML), who may show them inside a frame;
- and, on the same pages, frame-src — what THEY may show inside a frame: filex itself BY PATH (the app interfaces, the download frame; WithOwnFrames, else 'self'), the external editors the operator set up (draw.io, ONLYOFFICE) and the origin app interfaces are served from (WithFrameSources).
⚠⚠ frame-src is the one wall around an app interface's own navigation. An app's interface runs in a sandboxed frame with connect-src 'none', and a frame may still navigate ITSELF: to the author's server (with data in the address), or to a data:/blob: document of its own making — a fresh realm the WebRTC bootstrap never ran in. Measured 2026-09-27 (docs/research, harness variants B-sep-nohostcsp and B-bootstrap-nohostcsp): without the host page's frame-src all three browsers followed those navigations; with it none did. So data: and blob: are never frame sources here, whatever a caller passes.
⚠ frame-ancestors goes on HTML only. A file's own bytes are framed by design: the explorer embedded in another site (the web component, which is not a frame) shows a PDF from filex in an <embed> on the HOST's page, and a download is started through a hidden frame. Neither is a page with buttons to trick somebody into pressing, and refusing them would break every embed.
A handler's own values win: nosniff and the referrer policy are set before the handler runs, so a handler may replace them, and a handler's own CSP is kept — frame-ancestors is added to it only when it names none, unless the handler said its page names none ON PURPOSE (OpenFraming).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FrameAncestors ¶
FrameAncestors is the policy the HTML pages carry.
func FrameSrc ¶
FrameSrc is the frame-src directive of a filex page: filex's own paths (own; 'self' when none is usable) and the origin of every usable entry of extra, once each, in the order given.
func Middleware ¶
Middleware sets the headers. `allowed` is Normalize's answer.
func Normalize ¶
Normalize checks the pages allowed to frame filex besides filex itself (`frame_ancestors`, FILEX_FRAME_ANCESTORS) and returns them in the form the header carries. Accepted, each on its own:
https://home.example.com an origin (scheme, host, optional port) https://*.example.com every subdomain of a host * any page at all — the protection is off
Anything else stops the server with a message that says what to write: a value that is silently dropped would leave filex unframeable for the one dashboard the operator was trying to allow, with nothing to say why.
func OpenFraming ¶ added in v0.55.0
OpenFraming tells the middleware that the page this request answers carries NO frame-ancestors on purpose, so none is added: any page may frame it, a page with an opaque origin included. That is an app interface's page (internal/wasmplugin uiserve.go): the explorer that frames it is embedded in sites filex cannot list, and with `ui:frame-package` the page that frames one of its pages is the interface itself - a sandboxed, opaque origin that no source expression matches, not even `*` (Chromium refused the framed page under `frame-ancestors *`, 2026-10-08). Such a page holds nothing for whoever frames it: its sandbox and its bridge are what protect it. Nothing happens outside this middleware.
Types ¶
type Option ¶
type Option func(*options)
Option adjusts the middleware.
func WithFrameSources ¶
WithFrameSources names, per request, the origins a filex page may show in a frame besides filex itself: the external editors and the app-interface origin. Each entry is reduced to its origin (a path is dropped: the browser's own frame src carries it); anything that is not an http(s) URL — data:, blob:, a keyword, a relative path (that is filex itself, 'self') — is left out. It is asked once per HTML answer, so it must be cheap.
func WithOwnFrames ¶
WithOwnFrames names, per request, the paths of filex ITSELF its pages may show in a frame, as host sources with a path — `files.example.com/_appui/`, `files.example.com/z/` — in place of 'self'. ⚠ Security review UI-11: with 'self' an app's sandboxed frame could navigate itself to any page of filex; named by path, it reaches only another interface or a download. No scheme: a source without one takes the page's own (and its upgrade). An entry not of that plain `host[:port]/path/` form is left out; with none left, the pages frame 'self' as before.