mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
feat(api): derive stable placeholder names for hidden profiles (#3224)
This commit is contained in:
@@ -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');
|
||||
|
||||
@@ -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']},
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user