feat(federation): PUBLIC_ORIGIN env override for getOurOrigin
Adds an explicit override for the federation transport URL returned by getOurOrigin(). When unset, behaviour is unchanged (https://${DOMAIN} -> http://localhost:${PORT} dev fallback). Intended for reverse-proxy / dev-without-TLS deployments where the public origin must be advertised explicitly (typically http://...) and differs from the bare DOMAIN value used for federated identity. Wired via config.publicOrigin (envOptional('PUBLIC_ORIGIN')) so the override flows through the existing config layer rather than scattering process.env reads. Trailing slash is stripped for symmetry with peer.origin storage. docs/systems/federation.md gets a "Public Origin Override" subsection under §14 Background Workers documenting the resolution order.
This commit is contained in:
@@ -1427,6 +1427,10 @@ DM channel hard-delete cascades: reactions, embeds, attachments (DB rows + disk
|
|||||||
|
|
||||||
`startFederationWorkers()` in `utils/federationWorker.ts:1211` starts: outbox-delivery tick, federated-call sentinel, file-replication ticks, health-check ticks, and the storage janitor. The whole bundle is gated by `process.env.DISABLE_FEDERATION_WORKERS` matching `'1'` or `'true'` at `index.ts:171-176` (envBool semantics). Tests set `DISABLE_FEDERATION_WORKERS=1` to silence cross-instance background traffic during setup.
|
`startFederationWorkers()` in `utils/federationWorker.ts:1211` starts: outbox-delivery tick, federated-call sentinel, file-replication ticks, health-check ticks, and the storage janitor. The whole bundle is gated by `process.env.DISABLE_FEDERATION_WORKERS` matching `'1'` or `'true'` at `index.ts:171-176` (envBool semantics). Tests set `DISABLE_FEDERATION_WORKERS=1` to silence cross-instance background traffic during setup.
|
||||||
|
|
||||||
|
### Public Origin Override
|
||||||
|
|
||||||
|
`PUBLIC_ORIGIN` env (read via `config.publicOrigin`, consumed by `getOurOrigin()` in `utils/federationAuth.ts`) overrides the federation transport URL verbatim, taking precedence over the default `https://${DOMAIN}`. When unset, behaviour is unchanged. Intended for reverse-proxy / dev-without-TLS deployments where the public origin must be advertised explicitly (typically `http://...`) and differs from the bare `DOMAIN` value used for federated identity. The integration test harness does NOT use this override — see `seedPeer.ts` for why localhost-port instances cannot collapse to a single peer row.
|
||||||
|
|
||||||
### Test-Only Routes
|
### Test-Only Routes
|
||||||
|
|
||||||
`POST /api/admin/test/seed-peer` directly inserts a `federation_peers` row, skipping the multi-step peer handshake. Strictly gated: `NODE_ENV='test'` AND `ENABLE_TEST_ROUTES='1'` together; returns 404 in any other configuration. Used exclusively by the two-instance integration harness in `packages/server/test/`. Validates `origin` (must be http(s) URL), `hmacSecret` (≥32 chars), and `status` (must be one of `'active'`, `'pending'`, `'awaiting_approval'`, `'rejected'`, `'revoked'`, `'needs_attention'`, `'unreachable'`, `'accepted'`).
|
`POST /api/admin/test/seed-peer` directly inserts a `federation_peers` row, skipping the multi-step peer handshake. Strictly gated: `NODE_ENV='test'` AND `ENABLE_TEST_ROUTES='1'` together; returns 404 in any other configuration. Used exclusively by the two-instance integration harness in `packages/server/test/`. Validates `origin` (must be http(s) URL), `hmacSecret` (≥32 chars), and `status` (must be one of `'active'`, `'pending'`, `'awaiting_approval'`, `'rejected'`, `'revoked'`, `'needs_attention'`, `'unreachable'`, `'accepted'`).
|
||||||
|
|||||||
@@ -34,12 +34,27 @@ function envBool(key: string, defaultValue: boolean): boolean {
|
|||||||
return value === 'true' || value === '1';
|
return value === 'true' || value === '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PUBLIC_ORIGIN overrides the federation transport URL returned by getOurOrigin().
|
||||||
|
// Used by integration test harnesses that bind to 127.0.0.1:<ephemeral> and by
|
||||||
|
// reverse-proxy setups where federation must advertise an http:// origin (the
|
||||||
|
// proxy terminates TLS upstream). When unset, getOurOrigin() falls back to
|
||||||
|
// https://${DOMAIN} for production safety.
|
||||||
|
const publicOrigin = envOptional('PUBLIC_ORIGIN');
|
||||||
|
if (publicOrigin !== undefined) {
|
||||||
|
if (!/^https?:\/\//i.test(publicOrigin)) {
|
||||||
|
throw new Error(
|
||||||
|
`PUBLIC_ORIGIN must start with http:// or https:// — got: ${publicOrigin}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
port: envInt('PORT', 3000),
|
port: envInt('PORT', 3000),
|
||||||
host: env('HOST', '0.0.0.0'),
|
host: env('HOST', '0.0.0.0'),
|
||||||
jwtSecret: env('JWT_SECRET'),
|
jwtSecret: env('JWT_SECRET'),
|
||||||
jwtExpiresIn: env('JWT_EXPIRES_IN', '30d'),
|
jwtExpiresIn: env('JWT_EXPIRES_IN', '30d'),
|
||||||
domain: envOptional('DOMAIN'),
|
domain: envOptional('DOMAIN'),
|
||||||
|
publicOrigin,
|
||||||
|
|
||||||
livekit: {
|
livekit: {
|
||||||
url: envOptional('LIVEKIT_URL'),
|
url: envOptional('LIVEKIT_URL'),
|
||||||
|
|||||||
@@ -174,9 +174,21 @@ export function parseFederationHeaders(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the canonical origin URL for this instance.
|
* Return the canonical origin URL for this instance.
|
||||||
* Uses DOMAIN env var for production, falls back to localhost for dev.
|
*
|
||||||
|
* Resolution order:
|
||||||
|
* 1. `PUBLIC_ORIGIN` env (verbatim, trailing slash stripped) — overrides everything.
|
||||||
|
* Used by integration test harnesses that bind to 127.0.0.1:<ephemeral> and by
|
||||||
|
* reverse-proxy / dev-without-TLS setups where federation must advertise an
|
||||||
|
* explicit origin distinct from the public DOMAIN. The override is the URL
|
||||||
|
* transport layer; identity (homeInstance) still derives from DOMAIN.
|
||||||
|
* 2. `https://${DOMAIN}` — production default.
|
||||||
|
* 3. `http://localhost:${PORT}` — dev fallback when DOMAIN is unset.
|
||||||
*/
|
*/
|
||||||
export function getOurOrigin(): string {
|
export function getOurOrigin(): string {
|
||||||
|
const override = config.publicOrigin;
|
||||||
|
if (override && override.trim()) {
|
||||||
|
return override.trim().replace(/\/$/, '');
|
||||||
|
}
|
||||||
if (config.domain) {
|
if (config.domain) {
|
||||||
return `https://${config.domain}`;
|
return `https://${config.domain}`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user