fix(collaboration): configure federation from existing deployment settings
This commit is contained in:
30
backend/src/modules/collaboration/config.ts
Normal file
30
backend/src/modules/collaboration/config.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { instanceUrl } from "./transport"
|
||||
|
||||
type Settings = {
|
||||
API_BASE_URL?: string;
|
||||
ENCRYPTION_KEY?: string;
|
||||
FEDEO_PUBLIC_URL?: string;
|
||||
FEDEO_FEDERATION_URL?: string;
|
||||
FEDEO_FEDERATION_ENABLED?: string;
|
||||
}
|
||||
|
||||
/** Existing deployment settings are sufficient; extra URLs are optional overrides. */
|
||||
export function collaborationConfig(settings: Settings) {
|
||||
const configuredApi = settings.API_BASE_URL?.trim() || ""
|
||||
let apiUrl = (settings.FEDEO_FEDERATION_URL?.trim() || configuredApi).replace(/\/+$/, "")
|
||||
let publicUrl = settings.FEDEO_PUBLIC_URL?.trim().replace(/\/+$/, "") || ""
|
||||
if (!publicUrl) {
|
||||
try { publicUrl = new URL(configuredApi || apiUrl).origin } catch { /* Local development may have no public URL. */ }
|
||||
}
|
||||
const mode = settings.FEDEO_FEDERATION_ENABLED?.trim().toLowerCase() || "auto"
|
||||
if (!["auto", "true", "false"].includes(mode)) throw new Error("FEDEO_FEDERATION_ENABLED muss auto, true oder false sein")
|
||||
if (mode === "false") return { apiUrl, publicUrl, enabled: false, disabledReason: "Die Föderation wurde vom Betreiber deaktiviert." }
|
||||
|
||||
let disabledReason: string | undefined
|
||||
try { apiUrl = instanceUrl(apiUrl) }
|
||||
catch { disabledReason = "Föderation benötigt eine gültige öffentliche HTTPS-API_BASE_URL auf Port 443." }
|
||||
if (!disabledReason && !/^[a-f0-9]{64}$/i.test(settings.ENCRYPTION_KEY || "")) {
|
||||
disabledReason = "Föderation benötigt einen gültigen ENCRYPTION_KEY mit 64 Hex-Zeichen." }
|
||||
if (mode === "true" && disabledReason) throw new Error(disabledReason)
|
||||
return { apiUrl, publicUrl, enabled: !disabledReason, disabledReason }
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { FederationKey, Headers, instanceUrl, safeTransport, signedHeaders, Tran
|
||||
|
||||
type Options = {
|
||||
apiUrl: string; enabled: boolean;
|
||||
disabledReason?: string;
|
||||
seal: (value: string) => any; unseal: (value: any) => string;
|
||||
transport?: Transport;
|
||||
}
|
||||
@@ -22,7 +23,7 @@ export class FederationService {
|
||||
this.transport = options.transport || safeTransport
|
||||
}
|
||||
enabled() {
|
||||
if (!this.options.enabled) fail("Der Betreiber muss die Föderation zuerst aktivieren", 503)
|
||||
if (!this.options.enabled) fail(this.options.disabledReason || "Der Betreiber muss die Föderation zuerst aktivieren", 503)
|
||||
instanceUrl(this.origin)
|
||||
}
|
||||
async keys() {
|
||||
@@ -71,7 +72,7 @@ export class FederationService {
|
||||
VALUES (${ctx.tenantId},${origin},${instanceId},${keyId},${publicKey}) ON CONFLICT(tenant_id,origin) DO UPDATE SET active=true,updated_at=now()`)
|
||||
}
|
||||
}
|
||||
return { enabled: this.options.enabled, origin: this.origin, partners: (await rows(this.service.db,
|
||||
return { enabled: this.options.enabled, disabledReason: this.options.disabledReason, origin: this.origin, partners: (await rows(this.service.db,
|
||||
sql`SELECT origin,active,public_key FROM collaboration_partners WHERE tenant_id=${ctx.tenantId} ORDER BY origin`)).map(p => ({ origin: p.origin, active: p.active, fingerprint: hash(p.public_key) })) }
|
||||
}
|
||||
async call(tenantId: number, origin: string, action: string, payload: any) {
|
||||
|
||||
@@ -4,16 +4,18 @@ import { sendMail } from "../../utils/mailer"
|
||||
import { CollaborationService } from "./service"
|
||||
import { FederationService } from "./federation"
|
||||
import { encrypt, decrypt } from "../../utils/crypt"
|
||||
import { collaborationConfig } from "./config"
|
||||
|
||||
export function collaborationRuntime(server: FastifyInstance) {
|
||||
const apiUrl = String(process.env.FEDEO_FEDERATION_URL || secrets.API_BASE_URL || "").replace(/\/$/, "")
|
||||
const publicUrl = String(process.env.FEDEO_PUBLIC_URL || (apiUrl ? new URL(apiUrl).origin : "")).replace(/\/$/, "")
|
||||
const { apiUrl, publicUrl, enabled, disabledReason } = collaborationConfig({
|
||||
...process.env, API_BASE_URL: secrets.API_BASE_URL, ENCRYPTION_KEY: secrets.ENCRYPTION_KEY,
|
||||
})
|
||||
const service = new CollaborationService(server.db, {
|
||||
publicUrl,
|
||||
guestPepper: () => secrets.ENCRYPTION_KEY || "",
|
||||
sendMail,
|
||||
})
|
||||
const federation = new FederationService(service, { apiUrl, enabled: process.env.FEDEO_FEDERATION_ENABLED === "true", seal: encrypt, unseal: decrypt })
|
||||
const federation = new FederationService(service, { apiUrl, enabled, disabledReason, seal: encrypt, unseal: decrypt })
|
||||
service.options.changed = (roomId, db) => federation.changed(roomId, db)
|
||||
service.options.invited = (ctx, roomId, target, invitationId, db) => federation.invite(ctx, roomId, target, invitationId, db)
|
||||
let timer: ReturnType<typeof setInterval>
|
||||
|
||||
Reference in New Issue
Block a user