diff --git a/packages/server/src/utils/federationAuth.ts b/packages/server/src/utils/federationAuth.ts index c5f53f4f..ee97908d 100644 --- a/packages/server/src/utils/federationAuth.ts +++ b/packages/server/src/utils/federationAuth.ts @@ -1,4 +1,5 @@ import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto'; +import { config } from '../config.js'; const DEFAULT_MAX_AGE_MS = 15 * 60 * 1000; // 15 minutes @@ -122,3 +123,14 @@ export function parseFederationHeaders( return { origin, timestamp: timestampMs, signature }; } + +/** + * Return the canonical origin URL for this instance. + * Uses DOMAIN env var for production, falls back to localhost for dev. + */ +export function getOurOrigin(): string { + if (config.domain) { + return `https://${config.domain}`; + } + return `http://localhost:${config.port}`; +} diff --git a/packages/server/src/utils/federationOutbox.ts b/packages/server/src/utils/federationOutbox.ts index 58b1fe15..c139fa8e 100644 --- a/packages/server/src/utils/federationOutbox.ts +++ b/packages/server/src/utils/federationOutbox.ts @@ -4,7 +4,7 @@ import { eq, and } from 'drizzle-orm'; import { generateSnowflake } from './snowflake.js'; import crypto from 'node:crypto'; import type { FederationRelayEvent, FederationRelayParticipant, FederationRelayAttachment, DmMessageWithUser } from '@backspace/shared'; -import { config } from '../config.js'; +import { getOurOrigin } from './federationAuth.js'; // ─── Settings Cache ────────────────────────────────────────────────────────── @@ -229,7 +229,7 @@ export function getDmParticipants(dmChannelId: string): FederationRelayParticipa .where(eq(schema.dmMembers.dmChannelId, dmChannelId)) .all(); - const domainOrigin = config.domain ? `https://${config.domain}` : ''; + const domainOrigin = getOurOrigin(); return members.map(m => ({ homeUserId: m.homeUserId || m.id, @@ -252,7 +252,7 @@ export function queueDmRelay( dmChannelId: string, eventType: 'create' | 'update', ): void { - const domainOrigin = config.domain ? `https://${config.domain}` : `http://localhost:${config.port}`; + const domainOrigin = getOurOrigin(); const attachments: FederationRelayAttachment[] = (message.attachments ?? []).map(a => ({ id: a.id, @@ -300,7 +300,7 @@ export function buildRelayPayload( return { userId: user.id, homeUserId: user.homeUserId || user.id, - homeInstance: user.homeInstance || config.domain || '', + homeInstance: user.homeInstance || getOurOrigin(), content: message.content, replyToId: message.replyToId ?? null, editedAt: message.editedAt ?? null, diff --git a/packages/server/src/utils/federationWorker.ts b/packages/server/src/utils/federationWorker.ts index 73cf8280..fbf05806 100644 --- a/packages/server/src/utils/federationWorker.ts +++ b/packages/server/src/utils/federationWorker.ts @@ -3,7 +3,7 @@ import * as schema from '../db/schema.js'; import { eq, and, lte, asc, inArray } from 'drizzle-orm'; import { config } from '../config.js'; import { isFederationRelayEnabled } from './federationOutbox.js'; -import { buildFederationHeaders } from './federationAuth.js'; +import { buildFederationHeaders, getOurOrigin } from './federationAuth.js'; import { generateSnowflake } from './snowflake.js'; import { getDmMessageWithUser } from '../routes/dm.js'; import { connectionManager } from '../ws/handler.js'; @@ -63,17 +63,6 @@ function getBackoffMs(attempt: number): number { return BACKOFF_SCHEDULE_MS[Math.max(0, index)] ?? 86_400_000; } -/** - * Build the origin URL for this instance. - * Uses DOMAIN env var for production, falls back to localhost for dev. - */ -function getOurOrigin(): string { - if (config.domain) { - return `https://${config.domain}`; - } - return `http://localhost:${config.port}`; -} - /** * Get the effective max upload size from instance settings or config fallback. */ @@ -627,7 +616,7 @@ async function runInitialSyncForNewPeers(): Promise { if (unsyncedPeers.length === 0) return; - const ourOrigin = config.domain ? `https://${config.domain}` : `http://localhost:${config.port}`; + const ourOrigin = getOurOrigin(); for (const peer of unsyncedPeers) { try {