Improve validation of username searches

Co-authored-by: Joris Z. van den Oever <jzvandenoever@users.noreply.github.com>
This commit is contained in:
Scott Nonnenberg
2025-04-19 08:21:10 +10:00
committed by GitHub
parent 6b496f41a2
commit 78b4bda568
2 changed files with 39 additions and 6 deletions
+37 -5
View File
@@ -10,10 +10,10 @@ describe('Username', () => {
const { getUsernameFromSearch } = Username;
it('matches partial username searches without discriminator', () => {
assert.strictEqual(getUsernameFromSearch('u'), 'u.01');
assert.strictEqual(getUsernameFromSearch('us'), 'us.01');
assert.strictEqual(getUsernameFromSearch('use'), 'use.01');
assert.strictEqual(getUsernameFromSearch('use.'), 'use.01');
assert.strictEqual(getUsernameFromSearch('user'), 'user.01');
assert.strictEqual(getUsernameFromSearch('usern'), 'usern.01');
assert.strictEqual(getUsernameFromSearch('usern.'), 'usern.01');
});
it('matches and strips leading @', () => {
@@ -30,6 +30,28 @@ describe('Username', () => {
it('matches valid username searches', () => {
assert.strictEqual(getUsernameFromSearch('username.12'), 'username.12');
assert.strictEqual(getUsernameFromSearch('xyz.568'), 'xyz.568');
assert.strictEqual(getUsernameFromSearch('numbered9.34'), 'numbered9.34');
assert.strictEqual(getUsernameFromSearch('u12.34'), 'u12.34');
assert.strictEqual(
getUsernameFromSearch('with_underscore.56'),
'with_underscore.56'
);
assert.strictEqual(
getUsernameFromSearch('username_with_32_characters_1234.45'),
'username_with_32_characters_1234.45'
);
});
it('does not match when then username starts with a number', () => {
assert.isUndefined(getUsernameFromSearch('1user.12'));
assert.isUndefined(getUsernameFromSearch('9user_name.12'));
});
it('does not match usernames shorter than 3 characters or longer than 32', () => {
assert.isUndefined(getUsernameFromSearch('us.12'));
assert.isUndefined(
getUsernameFromSearch('username_with_33_characters_12345.67')
);
});
it('does not match something that looks like a phone number', () => {
@@ -51,8 +73,8 @@ describe('Username', () => {
it('returns true if it ends with a discriminator', () => {
assert.isTrue(probablyAUsername('someone.00'));
assert.isTrue(probablyAUsername('32423423.04'));
assert.isTrue(probablyAUsername('d.04'));
assert.isTrue(probablyAUsername('d2423423.04'));
assert.isTrue(probablyAUsername('e_f.04'));
});
it('returns false if just a discriminator', () => {
@@ -67,6 +89,16 @@ describe('Username', () => {
assert.isFalse(probablyAUsername('john'));
});
it('returns false for usernames starting with a number', () => {
assert.isFalse(probablyAUsername('1user.01'));
assert.isFalse(probablyAUsername('9name.99'));
});
it('returns false for usernames shorter than 3 characters or longer than 32', () => {
assert.isFalse(probablyAUsername('us.12'));
assert.isFalse(probablyAUsername('username_with_33_characters_12345.67'));
});
it('returns false for something that looks like a phone number', () => {
assert.isFalse(probablyAUsername('+'));
assert.isFalse(probablyAUsername('2223'));
+2 -1
View File
@@ -14,7 +14,8 @@ export function getMinNickname(): number {
return parseIntWithFallback(RemoteConfig.getValue('global.nicknames.min'), 3);
}
const USERNAME_CHARS = /^@?[a-zA-Z0-9]+(.\d+)?$/;
// Usernames have a minimum length of 3 and maximum of 32
const USERNAME_CHARS = /^@?[a-zA-Z_][a-zA-Z0-9_]{2,31}(.\d+)?$/;
const ALL_DIGITS = /^\d+$/;
export function getUsernameFromSearch(searchTerm: string): string | undefined {