fix(security-headers): allow iframe embedding when ARCHY_EMBEDDED=1
CI / check (push) Failing after 6m22s

secureHeaders() defaulted to X-Frame-Options: SAMEORIGIN, added as part of
the NIP-98/JWT auth hardening. This unconditionally blocked the Archipelago
node dashboard's iframe (a different origin by port) — 1.1.0 never sent
this header at all, so this was a hard regression for the platform's normal
embedded-app UX.

Fix: X-Frame-Options is now conditional on ARCHY_EMBEDDED=1, an env var the
archy manifest sets for the node-installed instance (first-party, trusted
embedding on the same host). Standalone/public-arena instances keep the
default SAMEORIGIN clickjacking protection unchanged.

Verified: with ARCHY_EMBEDDED=1 no X-Frame-Options header is sent; without
it, X-Frame-Options: SAMEORIGIN is still sent as before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-07-31 05:38:48 -04:00
co-authored by Claude Fable 5
parent d2fc998a28
commit 8eb27ed9b4
+9
View File
@@ -53,7 +53,16 @@ app.use('*', async (c, next) => {
})
// Security headers: X-Frame-Options, X-Content-Type-Options, HSTS, Referrer-Policy, etc.
// ARCHY_EMBEDDED=1 means this instance is running as an app inside the
// Archipelago node dashboard's iframe (a first-party, trusted embedding
// context on the same host, different port — never a third-party site).
// X-Frame-Options: SAMEORIGIN (the secureHeaders default) blocks that framing
// outright, since the dashboard and this app are different origins by port.
// Standalone/public-arena instances (ARCHY_EMBEDDED unset) keep the default
// clickjacking protection.
const isEmbedded = process.env.ARCHY_EMBEDDED === '1'
app.use('*', secureHeaders({
xFrameOptions: isEmbedded ? false : true,
contentSecurityPolicy: process.env.NODE_ENV === 'production' ? {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'blob:', "'wasm-unsafe-eval'"],