feat(demo): whole-origin IndeeHub proxy on :2101 with sign-in seeding
- nginx-demo.conf: new :2101 server block reverse-proxying the live indee.tx1138.com site with no path prefix (fixes the old sub_filter path-rewrite breakage), X-Frame-Options/CSP stripped, WS upgrade passthrough, and a demo sign-in script injected into <head> - indee-demo-signin.js: PUBLIC-DEMO-ONLY seeder that writes a labelled throwaway "nsec" account (freshly generated keypair, not a secret) into the :2101 origin's indeedhub-accounts/indeedhub-active-account localStorage keys, idempotently, so IndeeHub boots signed in - Dockerfile.web: copy the seeder into the demo web image, EXPOSE 2101 - docker-compose.demo.yml + demo-deploy/docker-compose.yml: publish 2101 (DEMO_INDEE_PORT override documented in the thin deploy stack) Verified: nginx -t clean in nginx:alpine; live proxy smoke shows 200 with no framing headers, injected tag, seed script served, assets proxied. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
e2278ad518
commit
69bc3d3f27
@ -13,6 +13,8 @@
|
||||
# IMAGE_TAG image tag to pull (default: demo)
|
||||
# ANTHROPIC_API_KEY optional — enables the AI chat panel
|
||||
# DEMO_WEB_PORT host port for the UI (default 2100)
|
||||
# DEMO_INDEE_PORT host port for the IndeeHub demo proxy (default 2101;
|
||||
# must stay 2101 unless the UI's demoAppUrl changes)
|
||||
|
||||
services:
|
||||
neode-backend:
|
||||
@ -42,6 +44,8 @@ services:
|
||||
container_name: archy-demo-web
|
||||
ports:
|
||||
- "${DEMO_WEB_PORT:-2100}:80"
|
||||
# IndeeHub whole-origin demo proxy (nginx :2101 in the web image)
|
||||
- "${DEMO_INDEE_PORT:-2101}:2101"
|
||||
environment:
|
||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
||||
depends_on:
|
||||
|
||||
@ -47,6 +47,8 @@ services:
|
||||
container_name: archy-demo-web
|
||||
ports:
|
||||
- "2100:80"
|
||||
# IndeeHub whole-origin demo proxy (nginx :2101 in nginx-demo.conf)
|
||||
- "2101:2101"
|
||||
depends_on:
|
||||
- neode-backend
|
||||
restart: unless-stopped
|
||||
|
||||
@ -57,9 +57,12 @@ COPY neode-ui/docker/nginx-demo.conf /etc/nginx/nginx.conf.template
|
||||
COPY neode-ui/docker/docker-entrypoint.sh /docker-entrypoint-custom.sh
|
||||
RUN chmod +x /docker-entrypoint-custom.sh
|
||||
|
||||
# IndeeHub demo sign-in seeder, injected by the :2101 whole-origin proxy
|
||||
# (nginx-demo.conf). Demo image only — never in real-node artifacts.
|
||||
COPY neode-ui/docker/indee-demo-signin.js /usr/share/nginx/html/__demo/indee-demo-signin.js
|
||||
|
||||
# Expose port
|
||||
EXPOSE 80
|
||||
# Expose ports (80 = demo UI, 2101 = IndeeHub whole-origin demo proxy)
|
||||
EXPOSE 80 2101
|
||||
|
||||
# Substitute ANTHROPIC_API_KEY at runtime, then start nginx
|
||||
ENTRYPOINT ["/docker-entrypoint-custom.sh"]
|
||||
|
||||
58
neode-ui/docker/indee-demo-signin.js
Normal file
58
neode-ui/docker/indee-demo-signin.js
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* PUBLIC-DEMO-ONLY IndeeHub sign-in seeder.
|
||||
*
|
||||
* Served at /__demo/indee-demo-signin.js on the :2101 IndeeHub whole-origin
|
||||
* demo proxy (see nginx-demo.conf) and injected into the proxied site's HTML
|
||||
* <head> via sub_filter. It only ever runs on the demo's :2101 origin inside
|
||||
* the demo iframe — it never ships in real-node artifacts.
|
||||
*
|
||||
* THROWAWAY DEMO IDENTITY — NOT A SECRET. The embedded secp256k1 keypair was
|
||||
* freshly generated for the public demo (2026-07-29) and has never belonged
|
||||
* to any real user. Its whole purpose is to be a shared, public "demo
|
||||
* visitor" Nostr identity so the embedded IndeeHub boots signed in with no
|
||||
* login wall. Anyone extracting this key can only impersonate the demo
|
||||
* visitor, by design (threat T-gjd-01: accepted).
|
||||
*
|
||||
* How it works: IndeeHub's bundle (applesauce-accounts) restores accounts on
|
||||
* boot from localStorage key "indeedhub-accounts" (JSON array of serialized
|
||||
* accounts; a "nsec" private-key account deserializes as
|
||||
* { id, type: "nsec", pubkey, metadata, signer: { key: <hex sk> } }) and
|
||||
* activates the account whose id is stored under "indeedhub-active-account".
|
||||
* This classic script executes before the SPA's deferred module bundle, so
|
||||
* seeding here is visible to that boot-restore. Seeding is idempotent: an
|
||||
* existing non-empty account list is never overwritten.
|
||||
*/
|
||||
;(function () {
|
||||
'use strict'
|
||||
|
||||
var ACCOUNTS_KEY = 'indeedhub-accounts'
|
||||
var ACTIVE_KEY = 'indeedhub-active-account'
|
||||
|
||||
// Throwaway demo keypair (see header — public by design, not a secret).
|
||||
var DEMO_SK_HEX = 'ce2ffa96f99968beffc789cbba5d8b52f4a3020454dcaf77c2b553961bf5a8c9'
|
||||
var DEMO_PK_HEX = '7261540160244ec65ce0bf86ba03997e9b1b3b35c277e416bf1c7ba4271fee31'
|
||||
var DEMO_ACCOUNT_ID = 'archy-demo-visitor'
|
||||
|
||||
try {
|
||||
var existing = null
|
||||
try {
|
||||
existing = JSON.parse(localStorage.getItem(ACCOUNTS_KEY))
|
||||
} catch (e) {
|
||||
existing = null
|
||||
}
|
||||
if (Array.isArray(existing) && existing.length > 0) return
|
||||
|
||||
var account = {
|
||||
id: DEMO_ACCOUNT_ID,
|
||||
type: 'nsec',
|
||||
pubkey: DEMO_PK_HEX,
|
||||
metadata: { name: 'Archy Demo' },
|
||||
signer: { key: DEMO_SK_HEX },
|
||||
}
|
||||
localStorage.setItem(ACCOUNTS_KEY, JSON.stringify([account]))
|
||||
localStorage.setItem(ACTIVE_KEY, DEMO_ACCOUNT_ID)
|
||||
} catch (e) {
|
||||
// localStorage unavailable (e.g. blocked third-party storage) — the demo
|
||||
// visitor just sees IndeeHub's normal signed-out state.
|
||||
}
|
||||
})()
|
||||
@ -103,10 +103,14 @@ http {
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
# IndeeHub is no longer proxied same-origin — the sub_filter rewrite
|
||||
# approach broke the SPA's runtime-built asset URLs. The demo now opens
|
||||
# the real site (https://indee.tx1138.com/) externally instead, via
|
||||
# DEMO_EXTERNAL_URLS in useDemoIntro.ts.
|
||||
# IndeeHub is NOT proxied under a /app/indeedhub/ path prefix — the
|
||||
# old sub_filter path-rewrite approach broke the SPA's runtime-built
|
||||
# absolute-root asset URLs. Instead, a dedicated WHOLE-ORIGIN reverse
|
||||
# proxy of https://indee.tx1138.com listens on :2101 (see the second
|
||||
# server block below): the SPA sees itself at '/' so every asset and
|
||||
# router path just works, framing headers are stripped, and a demo
|
||||
# sign-in seed script is injected. useDemoIntro.demoAppUrl points the
|
||||
# in-app iframe at http://<demo-host>:2101/.
|
||||
|
||||
# Mempool is NOT proxied upstream anymore — the mock backend serves a
|
||||
# branded placeholder page for it (see DEMO_APP_PAGES in mock-backend.js),
|
||||
@ -177,4 +181,46 @@ http {
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# ── IndeeHub whole-origin demo proxy (:2101) ────────────────────────────
|
||||
# Pure reverse proxy of the LIVE https://indee.tx1138.com site on its own
|
||||
# port — no path prefix, no URL rewriting, so the SPA's absolute-root
|
||||
# asset/router paths work untouched. The upstream's X-Frame-Options
|
||||
# (SAMEORIGIN) and any CSP are stripped so the demo can embed it in the
|
||||
# in-app iframe session, and a PUBLIC-DEMO-ONLY sign-in seed script is
|
||||
# injected into the HTML <head> (it seeds a labelled throwaway demo Nostr
|
||||
# account into the :2101 origin's isolated localStorage, so IndeeHub boots
|
||||
# signed in). Upstream is pinned to a single fixed hostname — this cannot
|
||||
# be used as an open proxy.
|
||||
server {
|
||||
listen 2101;
|
||||
server_name _;
|
||||
|
||||
# Demo sign-in seeder, served same-origin to the proxied SPA.
|
||||
location = /__demo/indee-demo-signin.js {
|
||||
root /usr/share/nginx/html;
|
||||
add_header Cache-Control "no-store";
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass https://indee.tx1138.com;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_ssl_name indee.tx1138.com;
|
||||
proxy_set_header Host indee.tx1138.com;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_read_timeout 86400;
|
||||
|
||||
# Allow embedding in the demo's iframe session.
|
||||
proxy_hide_header X-Frame-Options;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
|
||||
# HTML injection: upstream must not compress or sub_filter no-ops.
|
||||
# (sub_filter applies to text/html by default — exactly what we want.)
|
||||
proxy_set_header Accept-Encoding "";
|
||||
sub_filter_once on;
|
||||
sub_filter '</head>' '<script src="/__demo/indee-demo-signin.js"></script></head>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user