summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--util/src/entities/Config.ts2
-rw-r--r--util/src/entities/User.ts49
2 files changed, 35 insertions, 16 deletions
diff --git a/util/src/entities/Config.ts b/util/src/entities/Config.ts
index 9e25c737..6993cc09 100644
--- a/util/src/entities/Config.ts
+++ b/util/src/entities/Config.ts
@@ -149,6 +149,7 @@ export interface ConfigValue {
 			minUpperCase: number;
 			minSymbols: number;
 		};
+		incrementingDiscriminators: boolean; // random otherwise
 	};
 	regions: {
 		default: string;
@@ -335,6 +336,7 @@ export const DefaultConfigOptions: ConfigValue = {
 			minUpperCase: 2,
 			minSymbols: 0,
 		},
+		incrementingDiscriminators: false,
 	},
 	regions: {
 		default: "fosscord",
diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts
index bc852616..5f2618e0 100644
--- a/util/src/entities/User.ts
+++ b/util/src/entities/User.ts
@@ -64,7 +64,7 @@ export class User extends BaseClass {
 	setDiscriminator(val: string) {
 		const number = Number(val);
 		if (isNaN(number)) throw new Error("invalid discriminator");
-		if (number <= 0 || number > 10000) throw new Error("discriminator must be between 1 and 9999");
+		if (number <= 0 || number >= 10000) throw new Error("discriminator must be between 1 and 9999");
 		this.discriminator = val.toString().padStart(4, "0");
 	}
 
@@ -178,6 +178,35 @@ export class User extends BaseClass {
 		);
 	}
 
+	private static async generateDiscriminator(username: string): Promise<string | undefined> {
+		if (Config.get().register.incrementingDiscriminators) {
+			// discriminator will be incrementally generated
+			
+			// First we need to figure out the currently highest discrimnator for the given username and then increment it
+			const users = await User.find({ where: { username }, select: ["discriminator"] });
+			const highestDiscriminator = Math.max(0, ...users.map((u) => Number(u.discriminator)));
+
+			const discriminator = highestDiscriminator + 1;
+			if (discriminator >= 10000) {
+				return undefined;
+			}
+
+			return discriminator.toString().padStart(4, "0");
+		} else {
+			// discriminator will be randomly generated
+
+			// randomly generates a discriminator between 1 and 9999 and checks max five times if it already exists
+			// TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the database?
+			for (let tries = 0; tries < 5; tries++) {
+				const discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0");
+				const exists = await User.findOne({ where: { discriminator, username: username }, select: ["id"] });
+				if (!exists) return discriminator;
+			}
+
+			return undefined;
+		}
+	}
+
 	static async register({
 		email,
 		username,
@@ -194,21 +223,9 @@ export class User extends BaseClass {
 		// trim special uf8 control characters -> Backspace, Newline, ...
 		username = trimSpecial(username);
 
-		// discriminator will be randomly generated
-		let discriminator = "";
-
-		let exists;
-		// randomly generates a discriminator between 1 and 9999 and checks max five times if it already exists
-		// if it all five times already exists, abort with USERNAME_TOO_MANY_USERS error
-		// else just continue
-		// TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the database?
-		for (let tries = 0; tries < 5; tries++) {
-			discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0");
-			exists = await User.findOne({ where: { discriminator, username: username }, select: ["id"] });
-			if (!exists) break;
-		}
-
-		if (exists) {
+		const discriminator = await User.generateDiscriminator(username);
+		if (!discriminator) {
+			// We've failed to generate a valid and unused discriminator
 			throw FieldErrors({
 				username: {
 					code: "USERNAME_TOO_MANY_USERS",