vault: Vaultwarden reverse-proxy as the officer-vault sidecar

Transparent pass-through fronting a self-hosted Vaultwarden so the OffVault
(Bitwarden-SDK) app reaches it through the platform's per-app origin gate. True
out-of-process sidecar (officer-vault): it owns all Vaultwarden knowledge (URL,
paths, notifications WebSocket) on a random loopback port and registers via the
sidecar connector; the platform is a thin origin-gated forwarder that knows only
the sidecar's port. Never decrypts/parses/rewrites/logs bodies.

- sidecar/vault: HTTP + notifications-WS proxy to VAULTWARDEN_URL, /_health
- api/vault: sidecar-port discovery + thin forwarder + WS pipe + origin gate
- origin: OFFICER_VAULT_ORIGIN allow-listed, scoped to /api/vault
- mounted top-level (not protected) so the Bitwarden bearer token isn't 401'd
- protocol: vault:server event; ecosystem: officer-vault app

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 01:23:23 +00:00
co-authored by Claude Opus 4.8
parent b2fb6f148c
commit fcf6715844
11 changed files with 549 additions and 1 deletions
@@ -4,7 +4,7 @@ import { IS_DEV_BUILD } from '../build-env';
import { verify } from '../jwt';
import { isSuperAdmin } from '../super-admin';
const { PUBLIC_URL, OFFICER_APP_ORIGIN, MUSIC_APP_ORIGIN } = process.env;
const { PUBLIC_URL, OFFICER_APP_ORIGIN, MUSIC_APP_ORIGIN, OFFICER_VAULT_ORIGIN } = process.env;
// The allowed production web origin comes from PUBLIC_URL in .env (e.g. https://officer.pastilhas.dev),
// not a hardcoded domain.
@@ -33,6 +33,10 @@ const APP_ORIGINS: string[] = [
// Standalone officer-music app — its own custom-scheme origin. Allowlisted so it can authenticate
// and stream; SCOPED_ORIGINS below restricts it to /api/auth + /api/music only.
MUSIC_APP_ORIGIN,
// OffVault app (Bitwarden-SDK client) — its own custom-scheme origin. Allowlisted so it can reach the
// Vaultwarden reverse-proxy; ORIGIN_RULES below restricts it to /api/vault only. It authenticates to
// Vaultwarden with its own bearer token (not a platform account), so no super-admin rule applies.
OFFICER_VAULT_ORIGIN,
].filter((o): o is string => Boolean(o));
// The only path prefixes a non-owner account (and the music app) may reach.
@@ -54,6 +58,9 @@ const ORIGIN_RULES: Record<string, OriginRule> = {};
if (PUBLIC_ORIGIN) ORIGIN_RULES[PUBLIC_ORIGIN] = { superAdminOnly: true };
if (OFFICER_APP_ORIGIN) ORIGIN_RULES[OFFICER_APP_ORIGIN] = { superAdminOnly: true };
if (MUSIC_APP_ORIGIN) ORIGIN_RULES[MUSIC_APP_ORIGIN] = { paths: NON_OWNER_PATHS };
// OffVault may reach ONLY the Vaultwarden proxy. No superAdminOnly: its callers hold Bitwarden tokens,
// not platform accounts, so the account backstop above never applies to them (verify() → null → passes).
if (OFFICER_VAULT_ORIGIN) ORIGIN_RULES[OFFICER_VAULT_ORIGIN] = { paths: ['/api/vault'] };
// True when an Origin is reserved for the platform owner (used at signin to reject a non-owner login).
export function isSuperAdminOnlyOrigin(origin: string | undefined): boolean {