feat(api): derive stable placeholder names for hidden profiles (#3224)

This commit is contained in:
Hampus
2026-10-05 16:57:25 +02:00
committed by GitHub
parent 02c82f0038
commit 3093e7334b
30 changed files with 629 additions and 65 deletions
+14
View File
@@ -143,6 +143,7 @@ function defaultConfig(): MasterConfig {
auth: {
sudo_mode_secret: '',
connection_initiation_secret: '',
profile_pseudonym_secret: '',
sso_allow_private_addresses: false,
passkeys: {
rp_name: 'Fluxer',
@@ -302,6 +303,18 @@ function requireString(value: string | undefined, envName: string): void {
}
}
const DEVELOPMENT_PROFILE_PSEUDONYM_SECRET = 'fluxer-dev-profile-pseudonym-secret';
function applyProfilePseudonymSecret(config: MasterConfig): void {
if (config.auth.profile_pseudonym_secret.trim().length > 0) {
return;
}
if (config.env === 'production') {
throw new Error('FLUXER_PROFILE_PSEUDONYM_SECRET is required');
}
config.auth.profile_pseudonym_secret = DEVELOPMENT_PROFILE_PSEUDONYM_SECRET;
}
function validateReplyToEmail(value: string): void {
if (value !== '' && !/^[^\s@<>,;"]+@[^\s@<>,;"]+$/.test(value)) {
throw new Error('FLUXER_EMAIL_REPLY_TO_EMAIL must be a single email address such as [email protected]');
@@ -600,6 +613,7 @@ function normalizeConfig(config: MasterConfig): MasterConfig {
}
requireString(config.auth.sudo_mode_secret, 'FLUXER_SUDO_MODE_SECRET');
requireString(config.auth.connection_initiation_secret, 'FLUXER_CONNECTION_INITIATION_SECRET');
applyProfilePseudonymSecret(config);
validateVapidConfig(config);
requireString(config.s3?.access_key_id, 'FLUXER_S3_ACCESS_KEY_ID');
requireString(config.s3?.secret_access_key, 'FLUXER_S3_SECRET_ACCESS_KEY');
+1
View File
@@ -147,6 +147,7 @@ export interface MasterConfig {
auth: {
sudo_mode_secret: string;
connection_initiation_secret: string;
profile_pseudonym_secret: string;
sso_allow_private_addresses: boolean;
passkeys: {
rp_name: string;
@@ -25,6 +25,7 @@ const MINIMAL_ENV: Record<string, string> = {
FLUXER_GATEWAY_RPC_AUTH_TOKEN: 'test-gateway-token',
FLUXER_SUDO_MODE_SECRET: 'test-sudo-secret',
FLUXER_CONNECTION_INITIATION_SECRET: 'test-connection-secret',
FLUXER_PROFILE_PSEUDONYM_SECRET: 'test-profile-pseudonym-secret',
FLUXER_VAPID_PUBLIC_KEY: 'BB76bTFIuoqmxJtTfZX0yGTn1f_qu9H03B_nkj8OyExJFkN7Y-HBZZzShnHZoEhXKc5ZRy3jFu7OkBbnaQG-4aw',
FLUXER_VAPID_PRIVATE_KEY: 'Xgi-3P8J-I3Q6U1HlCcXMuc_tKLGAM9nIfznX3Hz68o',
};
@@ -475,6 +476,25 @@ describe('ConfigLoader', () => {
await expect(loadConfig()).rejects.toThrow('Invalid FLUXER_KV_MODE: sentinel');
});
test('reads the profile pseudonym secret and requires it in production', async () => {
stubMinimalEnv();
expect((await loadConfig()).auth.profile_pseudonym_secret).toBe('test-profile-pseudonym-secret');
resetConfig();
stubMinimalEnv({FLUXER_PROFILE_PSEUDONYM_SECRET: ''});
expect((await loadConfig()).auth.profile_pseudonym_secret).toBe('fluxer-dev-profile-pseudonym-secret');
resetConfig();
stubMinimalEnv({
FLUXER_ENV: 'production',
FLUXER_POSTGRES_HOST: 'postgres.internal',
FLUXER_POSTGRES_DATABASE: 'fluxer_prod',
FLUXER_POSTGRES_USERNAME: 'fluxer_app',
FLUXER_POSTGRES_PASSWORD: 'prod-postgres-secret',
FLUXER_POSTGRES_SSL: 'true',
FLUXER_PROFILE_PSEUDONYM_SECRET: '',
});
await expect(loadConfig()).rejects.toThrow('FLUXER_PROFILE_PSEUDONYM_SECRET is required');
});
test('rejects unsafe production Postgres defaults', async () => {
stubMinimalEnv({FLUXER_ENV: 'production'});
await expect(loadConfig()).rejects.toThrow('FLUXER_POSTGRES_HOST');
@@ -21,6 +21,7 @@ const SECRETS: Record<string, string> = {
FLUXER_ERLANG_COOKIE: 'erlang-cookie',
FLUXER_SUDO_MODE_SECRET: 'sudo-mode-secret',
FLUXER_CONNECTION_INITIATION_SECRET: 'connection-initiation-secret',
FLUXER_PROFILE_PSEUDONYM_SECRET: 'profile-pseudonym-secret',
FLUXER_GATEWAY_RPC_AUTH_TOKEN: 'gateway-rpc-auth-token',
FLUXER_MEDIA_PROXY_SECRET_KEY: 'media-proxy-secret-key',
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64: 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=',
@@ -128,6 +128,7 @@ const NAMED_FLUXER_ENV_OVERRIDES: Record<string, NamedEnvOverride> = {
FLUXER_GATEWAY_RPC_AUTH_TOKEN: {path: ['services', 'gateway', 'rpc_auth_token']},
FLUXER_SUDO_MODE_SECRET: {path: ['auth', 'sudo_mode_secret']},
FLUXER_CONNECTION_INITIATION_SECRET: {path: ['auth', 'connection_initiation_secret']},
FLUXER_PROFILE_PSEUDONYM_SECRET: {path: ['auth', 'profile_pseudonym_secret']},
FLUXER_SSO_ALLOW_PRIVATE_ADDRESSES: {path: ['auth', 'sso_allow_private_addresses'], parse: parseBoolean},
FLUXER_VAPID_PUBLIC_KEY: {path: ['auth', 'vapid', 'public_key']},
FLUXER_VAPID_PRIVATE_KEY: {path: ['auth', 'vapid', 'private_key']},
-4
View File
@@ -155,8 +155,6 @@ export const DELETED_USER_USERNAME = 'DeletedUser';
export const DELETED_USER_GLOBAL_NAME = 'Deleted User';
export const DELETED_USER_DISCRIMINATOR = 0;
export const DELETED_USER_ID = 1n;
export const HIDDEN_USER_USERNAME = 'HiddenUser';
export const HIDDEN_USER_DISCRIMINATOR = 0;
export const PublicUserFlags = {
STAFF: Number(UserFlags.STAFF),
PARTNER: Number(UserFlags.PARTNER),
@@ -164,7 +162,6 @@ export const PublicUserFlags = {
FRIENDLY_BOT: Number(UserFlags.FRIENDLY_BOT),
FRIENDLY_BOT_MANUAL_APPROVAL: Number(UserFlags.FRIENDLY_BOT_MANUAL_APPROVAL),
SPAMMER: Number(UserFlags.SPAMMER),
PROFILE_HIDDEN: Number(UserFlags.PROFILE_HIDDEN),
} as const;
export const PublicUserFlagsDescriptions: Record<keyof typeof PublicUserFlags, string> = {
STAFF: 'User is a staff member',
@@ -173,7 +170,6 @@ export const PublicUserFlagsDescriptions: Record<keyof typeof PublicUserFlags, s
FRIENDLY_BOT: 'Bot accepts friend requests from users',
FRIENDLY_BOT_MANUAL_APPROVAL: 'Bot requires manual approval for friend requests',
SPAMMER: 'User is flagged as a spammer',
PROFILE_HIDDEN: 'User profile details are hidden',
};
export const ThemeTypes = {
DARK: 'dark',