diff --git a/packages/conf/DittoConf.test.ts b/packages/conf/DittoConf.test.ts index b6c2b707..0d7682f0 100644 --- a/packages/conf/DittoConf.test.ts +++ b/packages/conf/DittoConf.test.ts @@ -29,3 +29,26 @@ Deno.test('DittoConfig defaults', async (t) => { assertEquals(config.port, 4036); }); }); + +Deno.test('DittoConfig with insecure media host', () => { + const env = new Map([ + ['LOCAL_DOMAIN', 'https://ditto.test'], + ['MEDIA_DOMAIN', 'https://ditto.test'], + ]); + + assertThrows( + () => new DittoConf(env), + Error, + 'For security reasons, MEDIA_DOMAIN cannot be on the same host as LOCAL_DOMAIN', + ); +}); + +Deno.test('DittoConfig with insecure media host and precheck disabled', () => { + const env = new Map([ + ['LOCAL_DOMAIN', 'https://ditto.test'], + ['MEDIA_DOMAIN', 'https://ditto.test'], + ['DITTO_PRECHECK', 'false'], + ]); + + new DittoConf(env); +}); diff --git a/packages/conf/DittoConf.ts b/packages/conf/DittoConf.ts index b7f5be79..f775a861 100644 --- a/packages/conf/DittoConf.ts +++ b/packages/conf/DittoConf.ts @@ -13,7 +13,17 @@ import { mergeURLPath } from './utils/url.ts'; /** Ditto application-wide configuration. */ export class DittoConf { - constructor(private env: { get(key: string): string | undefined }) {} + constructor(private env: { get(key: string): string | undefined }) { + if (this.precheck) { + const mediaUrl = new URL(this.mediaDomain); + + if (this.url.host === mediaUrl.host) { + throw new Error( + 'For security reasons, MEDIA_DOMAIN cannot be on the same host as LOCAL_DOMAIN.\n\nTo disable this check, set DITTO_PRECHECK="false"', + ); + } + } + } /** Cached parsed admin signer. */ private _signer: NSecSigner | undefined; @@ -465,4 +475,9 @@ export class DittoConf { get streakWindow(): number { return Number(this.env.get('STREAK_WINDOW') || 129600); } + + /** Whether to perform security/configuration checks on startup. */ + get precheck(): boolean { + return optionalBooleanSchema.parse(this.env.get('DITTO_PRECHECK')) ?? true; + } } diff --git a/packages/ditto/precheck.ts b/packages/ditto/precheck.ts deleted file mode 100644 index 40ab2fdb..00000000 --- a/packages/ditto/precheck.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Conf } from '@/config.ts'; - -/** Ensure the media URL is not on the same host as the local domain. */ -function checkMediaHost() { - const { url, mediaDomain } = Conf; - const mediaUrl = new URL(mediaDomain); - - if (url.host === mediaUrl.host) { - throw new PrecheckError('For security reasons, MEDIA_DOMAIN cannot be on the same host as LOCAL_DOMAIN.'); - } -} - -/** Error class for precheck errors. */ -class PrecheckError extends Error { - constructor(message: string) { - super(`${message}\nTo disable this check, set DITTO_PRECHECK="false"`); - } -} - -if (Deno.env.get('DITTO_PRECHECK') !== 'false') { - checkMediaHost(); -} diff --git a/packages/ditto/server.ts b/packages/ditto/server.ts index c5815537..69dc1e02 100644 --- a/packages/ditto/server.ts +++ b/packages/ditto/server.ts @@ -1,6 +1,5 @@ import { logi } from '@soapbox/logi'; -import '@/precheck.ts'; import '@/sentry.ts'; import '@/nostr-wasm.ts'; import app from '@/app.ts';