diff --git a/.config/example.yml b/.config/example.yml index 3f0ce4031..8e881c187 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -79,8 +79,8 @@ redis: # host: localhost # port: 9200 # ssl: false -# user: -# pass: +# user: +# pass: # ┌───────────────┐ #───┘ ID generation └─────────────────────────────────────────── @@ -109,6 +109,19 @@ id: 'aid' # Maximum lenght of an image caption or file comment (default 1500, max 8192) #maxCaptionLength: 1500 +# Reserved usernames that only the administrator can register with +reservedUsernames: + - root + - admin + - system + - test + - proxy + - relay + - mod + - moderator + - info + - information + # Whether disable HSTS #disableHsts: true @@ -211,4 +224,4 @@ id: 'aid' # !!!!!!!!!! # Seriously. Do NOT fill out the above settings if you're self-hosting. -# They're much better off being set from the control panel. +# They're much better off being set from the control panel. diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts index a7cdc89cf..4f367debe 100644 --- a/packages/backend/src/config/types.ts +++ b/packages/backend/src/config/types.ts @@ -77,6 +77,8 @@ export type Source = { sha256CertFingerprints?: string[]; }; + reservedUsernames?: string[]; + // Managed hosting stuff maxUserSignups?: number; isManagedHosting?: boolean; diff --git a/packages/backend/src/server/api/endpoints/username/available.ts b/packages/backend/src/server/api/endpoints/username/available.ts index f5aa4ed1e..6fa09ba36 100644 --- a/packages/backend/src/server/api/endpoints/username/available.ts +++ b/packages/backend/src/server/api/endpoints/username/available.ts @@ -1,5 +1,6 @@ import { IsNull } from "typeorm"; import { Users, UsedUsernames } from "@/models/index.js"; +import config from "@/config/index.js"; import define from "../../define.js"; export const meta = { @@ -40,7 +41,11 @@ export default define(meta, paramDef, async (ps) => { username: ps.username.toLowerCase(), }); + const reserved = config.reservedUsernames?.includes( + ps.username.toLowerCase(), + ); + return { - available: exist === 0 && exist2 === 0, + available: exist === 0 && exist2 === 0 && !reserved, }; }); diff --git a/packages/backend/src/server/api/private/signup.ts b/packages/backend/src/server/api/private/signup.ts index 754d86c3b..d24a74c12 100644 --- a/packages/backend/src/server/api/private/signup.ts +++ b/packages/backend/src/server/api/private/signup.ts @@ -44,6 +44,11 @@ export default async (ctx: Koa.Context) => { const invitationCode = body["invitationCode"]; const emailAddress = body["emailAddress"]; + if (config.reservedUsernames?.includes(username.toLowerCase())) { + ctx.status = 400; + return; + } + if (instance.emailRequiredForSignup) { if (emailAddress == null || typeof emailAddress !== "string") { ctx.status = 400;