mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
fix(api): skip the mature gate when no birth date is collected (#2582)
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {Config} from '../Config';
|
||||
|
||||
let cachedCollectDateOfBirth: boolean | null = null;
|
||||
|
||||
export function getDefaultDateOfBirthCollection(): boolean {
|
||||
return !Config.instance.selfHosted;
|
||||
}
|
||||
|
||||
export function instanceCollectsDateOfBirth(): boolean {
|
||||
return cachedCollectDateOfBirth ?? getDefaultDateOfBirthCollection();
|
||||
}
|
||||
|
||||
export function setCachedDateOfBirthCollection(collect: boolean): void {
|
||||
cachedCollectDateOfBirth = collect;
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import {resolveDeferredPhoneGateEnabled, setCachedDeferredPhoneGateEnabled} from
|
||||
import {InstanceConfiguration} from '../Tables';
|
||||
import {DEFAULT_DECAY_CONSTANTS, DEFAULT_RENEWAL_CONSTANTS} from '../utils/AttachmentDecay';
|
||||
import {isJsonRecord, parseJsonArray, parseJsonRecord} from '../utils/JsonBoundaryUtils';
|
||||
import {getDefaultDateOfBirthCollection, setCachedDateOfBirthCollection} from './DateOfBirthCollectionCache';
|
||||
import {normalizeSsoAllowedEmailDomains} from './SsoConfigValidation';
|
||||
|
||||
const GATEWAY_ROLLOUT_CONFIG_KEY = 'gateway_rollout_config';
|
||||
@@ -357,11 +358,21 @@ function getDefaultAppPublicConfig(): InstanceAppPublicConfig {
|
||||
privacy_url: null,
|
||||
},
|
||||
registration: {
|
||||
collect_date_of_birth: !Config.instance.selfHosted,
|
||||
collect_date_of_birth: getDefaultDateOfBirthCollection(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function parseAppPublicConfig(raw: string): InstanceAppPublicConfig {
|
||||
try {
|
||||
const parsed: unknown = JSON.parse(raw);
|
||||
return normalizeAppPublicConfig(parsed);
|
||||
} catch (error) {
|
||||
Logger.warn({error}, 'Invalid app public config JSON, returning defaults');
|
||||
return getDefaultAppPublicConfig();
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeAppPublicConfig(value: unknown): InstanceAppPublicConfig {
|
||||
const defaults = getDefaultAppPublicConfig();
|
||||
if (!isJsonRecord(value)) {
|
||||
@@ -939,6 +950,7 @@ export class InstanceConfigRepository {
|
||||
this.configCache = await this.fetchAllConfigsFromDatabase();
|
||||
} while (this.refreshRequested);
|
||||
this.syncDeferredPhoneGateCache(this.configCache.get(INSTANCE_POLICY_CONFIG_KEY) ?? null);
|
||||
this.syncDateOfBirthCollectionCache(this.configCache.get(APP_PUBLIC_CONFIG_KEY) ?? null);
|
||||
})().finally(() => {
|
||||
this.refreshPromise = null;
|
||||
});
|
||||
@@ -950,6 +962,11 @@ export class InstanceConfigRepository {
|
||||
setCachedDeferredPhoneGateEnabled(resolveDeferredPhoneGateEnabled(policy));
|
||||
}
|
||||
|
||||
private syncDateOfBirthCollectionCache(raw: string | null): void {
|
||||
const appPublic = raw ? normalizeAppPublicConfig(parseJsonRecord(raw)) : getDefaultAppPublicConfig();
|
||||
setCachedDateOfBirthCollection(appPublic.registration.collect_date_of_birth);
|
||||
}
|
||||
|
||||
private updateCachedConfigs(entries: Array<[string, string]>): void {
|
||||
if (!this.configCache) {
|
||||
return;
|
||||
@@ -1067,16 +1084,9 @@ export class InstanceConfigRepository {
|
||||
|
||||
async getAppPublicConfig(): Promise<InstanceAppPublicConfig> {
|
||||
const raw = await this.getConfig(APP_PUBLIC_CONFIG_KEY);
|
||||
if (!raw) {
|
||||
return getDefaultAppPublicConfig();
|
||||
}
|
||||
try {
|
||||
const parsed: unknown = JSON.parse(raw);
|
||||
return normalizeAppPublicConfig(parsed);
|
||||
} catch (error) {
|
||||
Logger.warn({error}, 'Invalid app public config JSON, returning defaults');
|
||||
return getDefaultAppPublicConfig();
|
||||
}
|
||||
const config = raw ? parseAppPublicConfig(raw) : getDefaultAppPublicConfig();
|
||||
setCachedDateOfBirthCollection(config.registration.collect_date_of_birth);
|
||||
return config;
|
||||
}
|
||||
|
||||
async setAppPublicConfig(config: {
|
||||
@@ -1105,6 +1115,7 @@ export class InstanceConfigRepository {
|
||||
},
|
||||
});
|
||||
await this.setConfig(APP_PUBLIC_CONFIG_KEY, JSON.stringify(next));
|
||||
setCachedDateOfBirthCollection(next.registration.collect_date_of_birth);
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {afterEach, describe, expect, it} from 'vitest';
|
||||
import {setCachedDateOfBirthCollection} from '../instance/DateOfBirthCollectionCache';
|
||||
import {canUserAccessNsfwContent} from './AgeUtils';
|
||||
|
||||
const ADULT_DATE_OF_BIRTH = '1990-01-01';
|
||||
const MINOR_DATE_OF_BIRTH = '2020-01-01';
|
||||
|
||||
describe('canUserAccessNsfwContent', () => {
|
||||
afterEach(() => {
|
||||
setCachedDateOfBirthCollection(true);
|
||||
});
|
||||
|
||||
it('allows a bot whatever the instance collects', () => {
|
||||
setCachedDateOfBirthCollection(true);
|
||||
expect(canUserAccessNsfwContent({isBot: true, dateOfBirth: null})).toBe(true);
|
||||
});
|
||||
|
||||
it('allows an adult when the instance collects a date of birth', () => {
|
||||
setCachedDateOfBirthCollection(true);
|
||||
expect(canUserAccessNsfwContent({isBot: false, dateOfBirth: ADULT_DATE_OF_BIRTH})).toBe(true);
|
||||
});
|
||||
|
||||
it('blocks a minor when the instance collects a date of birth', () => {
|
||||
setCachedDateOfBirthCollection(true);
|
||||
expect(canUserAccessNsfwContent({isBot: false, dateOfBirth: MINOR_DATE_OF_BIRTH})).toBe(false);
|
||||
});
|
||||
|
||||
it('blocks a missing date of birth when the instance collects one', () => {
|
||||
setCachedDateOfBirthCollection(true);
|
||||
expect(canUserAccessNsfwContent({isBot: false, dateOfBirth: null})).toBe(false);
|
||||
});
|
||||
|
||||
it('allows a missing date of birth when the instance collects none', () => {
|
||||
setCachedDateOfBirthCollection(false);
|
||||
expect(canUserAccessNsfwContent({isBot: false, dateOfBirth: null})).toBe(true);
|
||||
});
|
||||
|
||||
it('allows an account with a minor date of birth when the instance collects none', () => {
|
||||
setCachedDateOfBirthCollection(false);
|
||||
expect(canUserAccessNsfwContent({isBot: false, dateOfBirth: MINOR_DATE_OF_BIRTH})).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {instanceCollectsDateOfBirth} from '../instance/DateOfBirthCollectionCache';
|
||||
|
||||
export function calculateAge(
|
||||
dateOfBirth:
|
||||
| {
|
||||
@@ -53,5 +55,8 @@ export function canUserAccessNsfwContent(user: NsfwEligibilityUser): boolean {
|
||||
if (user.isBot) {
|
||||
return true;
|
||||
}
|
||||
if (!instanceCollectsDateOfBirth()) {
|
||||
return true;
|
||||
}
|
||||
return isUserAdult(user.dateOfBirth);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user