feat(captcha): make ALTCHA the only captcha (#3035)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-29 17:00:15 +02:00
1 parent d433a039b5
commit 4f968bbc47
209 files changed
+4097 -8692

No files matched your search

-24
View File
@@ -194,10 +194,6 @@ function defaultConfig(): MasterConfig {
from_name: 'Fluxer',
app_base_url: '',
},
captcha: {
enabled: false,
provider: 'none',
},
voice: {
enabled: false,
api_key: '',
@@ -425,24 +421,6 @@ function validatePostgresConfig(config: MasterConfig): void {
}
}
function validateCaptchaConfig(config: MasterConfig): void {
const captcha = config.integrations.captcha;
if (!captcha.enabled) {
return;
}
if (captcha.provider === 'hcaptcha') {
requireString(captcha.hcaptcha?.site_key, 'FLUXER_CAPTCHA_HCAPTCHA_SITE_KEY');
requireString(captcha.hcaptcha?.secret_key, 'FLUXER_CAPTCHA_HCAPTCHA_SECRET_KEY');
return;
}
if (captcha.provider === 'turnstile') {
requireString(captcha.turnstile?.site_key, 'FLUXER_CAPTCHA_TURNSTILE_SITE_KEY');
requireString(captcha.turnstile?.secret_key, 'FLUXER_CAPTCHA_TURNSTILE_SECRET_KEY');
return;
}
throw new Error('FLUXER_CAPTCHA_PROVIDER must be hcaptcha or turnstile when FLUXER_CAPTCHA_ENABLED is true');
}
function validateApiWorkerConfig(config: MasterConfig): void {
const worker = config.services.api?.worker;
if (!worker) {
@@ -564,11 +542,9 @@ function normalizeConfig(config: MasterConfig): MasterConfig {
assertOneOf(config.internal.kv_provider, ['redis'], 'FLUXER_KV_PROVIDER');
assertOneOf(config.internal.kv_mode, ['standalone', 'cluster'], 'FLUXER_KV_MODE');
assertOneOf(config.integrations.email.provider, ['smtp', 'none'], 'FLUXER_EMAIL_PROVIDER');
assertOneOf(config.integrations.captcha.provider, ['hcaptcha', 'turnstile', 'none'], 'FLUXER_CAPTCHA_PROVIDER');
assertOneOf(config.integrations.search.engine, ['elasticsearch', 'meilisearch'], 'FLUXER_SEARCH_ENGINE');
assertOneOf(config.integrations.cache_purge.adapter, CACHE_PURGE_ADAPTER_NAMES, 'FLUXER_CACHE_PURGE_ADAPTER');
validatePostgresConfig(config);
validateCaptchaConfig(config);
validateApiWorkerConfig(config);
validateStorageChangeFeedConfig(config);
validateCachePurgeConfig(config);
-12
View File
@@ -207,18 +207,6 @@ export interface MasterConfig {
secure: boolean;
};
};
captcha: {
enabled: boolean;
provider: 'hcaptcha' | 'turnstile' | 'none';
hcaptcha?: {
site_key: string;
secret_key: string;
};
turnstile?: {
site_key: string;
secret_key: string;
};
};
voice: {
enabled: boolean;
api_key: string;
@@ -507,46 +507,6 @@ describe('ConfigLoader', () => {
expect(config.instance.setup.configured).toBe(true);
});
test('rejects an enabled captcha with no keys for the selected provider', async () => {
stubMinimalEnv({FLUXER_CAPTCHA_ENABLED: 'true', FLUXER_CAPTCHA_PROVIDER: 'hcaptcha'});
await expect(loadConfig()).rejects.toThrow('FLUXER_CAPTCHA_HCAPTCHA_SITE_KEY is required');
});
test('rejects an enabled captcha with a site key but no secret key', async () => {
stubMinimalEnv({
FLUXER_CAPTCHA_ENABLED: 'true',
FLUXER_CAPTCHA_PROVIDER: 'turnstile',
FLUXER_CAPTCHA_TURNSTILE_SITE_KEY: 'turnstile-site-key',
});
await expect(loadConfig()).rejects.toThrow('FLUXER_CAPTCHA_TURNSTILE_SECRET_KEY is required');
});
test('rejects an enabled captcha with no provider', async () => {
stubMinimalEnv({FLUXER_CAPTCHA_ENABLED: 'true'});
await expect(loadConfig()).rejects.toThrow(
'FLUXER_CAPTCHA_PROVIDER must be hcaptcha or turnstile when FLUXER_CAPTCHA_ENABLED is true',
);
});
test('accepts an enabled captcha with both keys for the selected provider', async () => {
stubMinimalEnv({
FLUXER_CAPTCHA_ENABLED: 'true',
FLUXER_CAPTCHA_PROVIDER: 'hcaptcha',
FLUXER_CAPTCHA_HCAPTCHA_SITE_KEY: 'hcaptcha-site-key',
FLUXER_CAPTCHA_HCAPTCHA_SECRET_KEY: 'hcaptcha-secret-key',
});
const config = await loadConfig();
expect(config.integrations.captcha.enabled).toBe(true);
expect(config.integrations.captcha.hcaptcha?.secret_key).toBe('hcaptcha-secret-key');
});
test('leaves a disabled captcha unvalidated', async () => {
stubMinimalEnv({FLUXER_CAPTCHA_PROVIDER: 'hcaptcha'});
expect((await loadConfig()).integrations.captcha.enabled).toBe(false);
});
test('defaults the cache purge adapter to none', async () => {
stubMinimalEnv();
expect((await loadConfig()).integrations.cache_purge).toEqual({
@@ -233,12 +233,6 @@ const NAMED_FLUXER_ENV_OVERRIDES: Record<string, NamedEnvOverride> = {
FLUXER_EMAIL_SMTP_USERNAME: {path: ['integrations', 'email', 'smtp', 'username']},
FLUXER_EMAIL_SMTP_PASSWORD: {path: ['integrations', 'email', 'smtp', 'password']},
FLUXER_EMAIL_SMTP_SECURE: {path: ['integrations', 'email', 'smtp', 'secure'], parse: parseBoolean},
FLUXER_CAPTCHA_ENABLED: {path: ['integrations', 'captcha', 'enabled'], parse: parseBoolean},
FLUXER_CAPTCHA_PROVIDER: {path: ['integrations', 'captcha', 'provider']},
FLUXER_CAPTCHA_HCAPTCHA_SITE_KEY: {path: ['integrations', 'captcha', 'hcaptcha', 'site_key']},
FLUXER_CAPTCHA_HCAPTCHA_SECRET_KEY: {path: ['integrations', 'captcha', 'hcaptcha', 'secret_key']},
FLUXER_CAPTCHA_TURNSTILE_SITE_KEY: {path: ['integrations', 'captcha', 'turnstile', 'site_key']},
FLUXER_CAPTCHA_TURNSTILE_SECRET_KEY: {path: ['integrations', 'captcha', 'turnstile', 'secret_key']},
FLUXER_LIVEKIT_ENABLED: {path: ['integrations', 'voice', 'enabled'], parse: parseBoolean},
FLUXER_LIVEKIT_API_KEY: {path: ['integrations', 'voice', 'api_key']},
FLUXER_LIVEKIT_API_SECRET: {path: ['integrations', 'voice', 'api_secret']},