From 0c2b80049402d9285bd65270151c00c051ad25d9 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 31 Mar 2026 00:31:22 -0400 Subject: [PATCH] increase username randomness to stop pages (#1261) We were getting several username collisions a day under the old algorithm --- .../src/username/generate_random_username.rs | 105 +++++---- .../handle_new_sso_account_for_new_user.rs | 2 +- .../usernames/atoms/username_adjectives.txt | 170 ++++++++++++++ .../usernames/atoms/username_nouns.txt | 218 ++++++++++++++++++ .../atoms/username_nouns_animals.txt | 167 ++++++++++++++ 5 files changed, 621 insertions(+), 41 deletions(-) diff --git a/crates/lib/users/src/username/generate_random_username.rs b/crates/lib/users/src/username/generate_random_username.rs index e8cb5755f5..fa8006cb90 100644 --- a/crates/lib/users/src/username/generate_random_username.rs +++ b/crates/lib/users/src/username/generate_random_username.rs @@ -76,63 +76,88 @@ fn generate_candidate_username() -> Option { UsernameFormat::ScreamingSnakeCase => format!("{}_{}", adjective.to_uppercase(), noun.to_uppercase()), }; - if let Some(digit) = maybe_random_safe_digit() { - candidate_username = match format { - UsernameFormat::CamelCase => format!("{}{}", candidate_username, digit), - UsernameFormat::KebabCase - | UsernameFormat::CamelKebabCase => format!("{}-{}", candidate_username, digit), - UsernameFormat::SnakeCase - | UsernameFormat::CamelSnakeCase - | UsernameFormat::ScreamingSnakeCase => format!("{}_{}", candidate_username, digit), - }; - } + let digit = random_digit_probably_safe(); + + candidate_username = match format { + UsernameFormat::CamelCase => format!("{}{}", candidate_username, digit), + UsernameFormat::KebabCase + | UsernameFormat::CamelKebabCase => format!("{}-{}", candidate_username, digit), + UsernameFormat::SnakeCase + | UsernameFormat::CamelSnakeCase + | UsernameFormat::ScreamingSnakeCase => format!("{}_{}", candidate_username, digit), + }; Some(candidate_username) } -fn maybe_random_safe_digit() -> Option { - fn maybe_random_digit() -> Option { - // Give uniform probability for the number of digits - let num_digits = rand::thread_rng().gen_range(0..5u8); - match num_digits { - 0 => None, - 1 => Some(rand::thread_rng().gen_range(0..10)), - 2 => Some(rand::thread_rng().gen_range(10..100)), - 3 => Some(rand::thread_rng().gen_range(100..1000)), - 4 => Some(rand::thread_rng().gen_range(1000..10000)), - _ => Some(rand::thread_rng().gen_range(10000..100000)), +fn random_digit_probably_safe() -> u32 { + for _ in 0..100 { + if let Some(digit) = maybe_safe_random_digit() { + return digit; } } + random_digit() +} - // Don't return potentially offensive numbers - match maybe_random_digit() { - None => None, - Some(69) => None, - Some(420) => None, - Some(666) => None, - Some(8008) => None, - Some(80085) => None, - Some(8008135) => None, - Some(digit) => Some(digit), +/// Don't return potentially offensive numbers +fn maybe_safe_random_digit() -> Option { + match random_digit() { + 69 => None, + 420 => None, + 666 => None, + 8008 => None, + 80085 => None, + 8008135 => None, + digit => Some(digit), + } +} + +fn random_digit() -> u32 { + // Non-uniform probability for the number of digits + let num_digits = rand::thread_rng().gen_range(0..100); + match num_digits { + 0..5 => rand::thread_rng().gen_range(0..10), // 5% + 5..25 => rand::thread_rng().gen_range(10..100), // 20% + 25..60 => rand::thread_rng().gen_range(100..1000), // 35% + 60..90 => rand::thread_rng().gen_range(1000..10000), // 30% + _ => rand::thread_rng().gen_range(10000..100000), // 10% } } #[cfg(test)] mod tests { use std::collections::HashSet; + use crate::username::generate_random_username::maybe_safe_random_digit; use crate::username::generate_random_username::generate_random_username; - #[test] - fn test_base_case_success() { - assert!(generate_random_username().len() > 0); + mod usernames { + use super::*; + + #[test] + fn test_base_case_success() { + assert!(generate_random_username().len() > 0); + } + + #[test] + fn generate_lots() { + let mut collection = HashSet::new(); + for _ in 0..100 { + collection.insert(generate_random_username()); + } + assert!(collection.len() > 95); // NB: Should be an easy bar to hit + } } - #[test] - fn generate_lots() { - let mut collection = HashSet::new(); - for _ in 0..100 { - collection.insert(generate_random_username()); + mod random_numbers { + use super::*; + + #[test] + fn generate_lots_of_numbers() { + let mut collection = HashSet::new(); + for _ in 0..10000 { + collection.insert(maybe_safe_random_digit()); + } + assert!(collection.len() > 1000); } - assert!(collection.len() > 50); // NB: Should be an easy bar to hit } } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/users/google_sso/handle_new_sso_account_for_new_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/users/google_sso/handle_new_sso_account_for_new_user.rs index 68edcb7d97..716e1c46bd 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/users/google_sso/handle_new_sso_account_for_new_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/users/google_sso/handle_new_sso_account_for_new_user.rs @@ -47,7 +47,7 @@ pub async fn handle_new_sso_account_for_new_user( let mut maybe_user_token = None; let mut maybe_user_display_name = None; - for _ in 0..3 { + for _ in 0..5 { // NB: We try a few times to make sure we don't hit a username collision. let display_name = generate_random_username(); let username = display_name.trim().to_lowercase(); diff --git a/includes/binary_includes/usernames/atoms/username_adjectives.txt b/includes/binary_includes/usernames/atoms/username_adjectives.txt index 91de949504..691731c7a4 100644 --- a/includes/binary_includes/usernames/atoms/username_adjectives.txt +++ b/includes/binary_includes/usernames/atoms/username_adjectives.txt @@ -14,64 +14,100 @@ adept admirable advanced adventurous +aerial agile +alpine altruistic amazing ambitious amused amusing +ancient animated apt +aquatic arctic artistic +astral authentic awesome +balanced best better +blazing bold +booming +boundless brave +breezy bright brilliant brisk bronze +calm capital carefree +celestial +champion charming cheerful classic clever +coastal +colossal complex +composed +confident constant conventional cool coordinated +copper +cosmic courageous crafty crazy creative +crisp critical +crystal dapper +daring dazzling decisive +deep definite definitive +delightful determined +devoted digital diligent distinct dizzy +double downright dramatic +driven dual +dynamic +eager +earnest +effortless elaborate elated electric elegant +elevated +emerald enchanted +endless energetic enlightened +epic essential esteemed +eternal evergreen exalted excellent @@ -81,19 +117,40 @@ exciting exemplary experienced expert +exquisite famous fancy fantastic favorable favorite +fearless +fiery +fine +flagship +flawless +fleet +fluent +flying +focal focused +forged formal +formidable +fortunate friendly +frosted +frosty funny fuzzy +gallant gargantuan general +generous +gentle +genuine gigantic +glacial +glad glamorous glass gleaming @@ -101,15 +158,28 @@ glistening glittering glorious glossy +glowing golden +graceful +grand +granite +grateful +great +grounded +growing growling grumpy +hallowed +happy harmonious haunting heavenly +heroic +highland hilarious honest hopeful +humble idealistic illustrious imaginary @@ -117,6 +187,7 @@ imaginative immaculate immaterial immediate +immense impartial impeccable important @@ -126,55 +197,108 @@ improbable incredible infamous infinite +inspired +instant intelligent +intrepid +inventive +invincible +iron +jolly +jovial +joyful +keen +kind +knowing lavish +leading +legendary +light linear +lively loud +loyal lucky luminous +lunar +lush +magnetic magnificent majestic major +marble +marvelous +masterful mellow melodic memorable +meridian metallic +mighty +mindful modern +modest monumental +moonlit +mosaic +mountain +moving mysterious +mystic +natural nautical necessary neighborly nifty nimble +noble nocturnal +northern notable noteworthy novel obvious +oceanic +onyx optimal optimistic +opulent +orbital original ornate outgoing outrageous outstanding +overland +pacific parallel +passionate pastel +patient +peak perfect +persistent +pioneer +placid plastic +polished popular posh positive possible powerful practical +premier +premium prestigious previous primary prime pristine probable +profound +prolific +prominent proud prudent punctual @@ -190,13 +314,22 @@ rare real realistic recent +refined regal +relentless remarkable +resolute +rising +robust royal +rugged +rustic sarcastic sardonic +scenic scholarly scientific +seasoned second secret serious @@ -208,15 +341,22 @@ shiny shocking silent silly +silver similar +sincere +skilled sleepy slight slim smart snappy sneaky +soaring +solar solid +sonic sophisticated +southern sparkling specific spectacular @@ -224,37 +364,65 @@ speedy spiffy spirited splendid +spring +stalwart +starlit starry +steadfast +steady steel +stellar +stoic +stout +strategic strong studious stupendous stylish subtle suburban +summit +sunlit sunny super superb +supreme surprised swift talkative tall +tenacious terrific +thermal third thorough thoughtful thunderous +tidal timely +titanium +topaz tough +towering tricky +triple +tropical +trusted +twilight ultimate uncommon +undaunted unique united +universal +unwavering upbeat urban valid +valiant +vast venerated +verdant vibrant victorious vigilant @@ -262,6 +430,8 @@ virtual virtuous visible vivid +vocal +wandering watchful whimsical wild diff --git a/includes/binary_includes/usernames/atoms/username_nouns.txt b/includes/binary_includes/usernames/atoms/username_nouns.txt index 7e7b44cb06..667121e441 100644 --- a/includes/binary_includes/usernames/atoms/username_nouns.txt +++ b/includes/binary_includes/usernames/atoms/username_nouns.txt @@ -24,25 +24,48 @@ ambition amount analysis analyst +anchor angle answer +anthem anybody anything anywhere application +arc +arena +armor art aspect +atlas +aurora +autumn +banner +bastion battle +beacon beach beat being bell bet beyond +blade +blaze +bolt book +boulder bridge brush +cadence +caliber +campaign +campus candidate +canyon +captain +castle +catalyst champion chance channel @@ -51,71 +74,129 @@ character charge chemical chemistry +chronicle +circuit +citadel city +cliff cloud coast code coffee +comet command +compass computer concept concert condition connection consideration +conquest constant construction context cookie corner +cosmos country courage craft +crest creative crew +crown +crystal +current cycle dance data +dawn +delta department +design device diamond dimension direction director +discovery disk district doctor +domain drawing dream +drift drive +dusk +echo +eclipse +edge effect +ember +empire energy engine engineer engineering entertainment +envoy +epoch factor fall +fathom final finding fix +flare +flash flight focus force +forecast forever +forge +formation +formula +fortress fortune foundation +fountain frame +frontier +frost future +galaxy game +garden +gateway +gem +genesis +glacier glass +gleam +glimpse goal gold +granite +grove +guardian guitar +gust +harbor +harvest +haven +haze +helm +herald highlight highway history holiday +hollow +horizon +hub ice idea ideal @@ -123,47 +204,104 @@ image imagination impact impression +infinity instance +instrument intention introduction +invention island +jewel joke +journal +journey +junction +keystone knowledge +lagoon lake land landscape +lantern +lattice +league +legacy +legend +lens level light +lighthouse limit line link lock +lodge +loft machine +marble +market +meadow +mechanism +melody mention +meridian +mesa message metal +meteor +method midnight +milestone mind mine minute +mirage mirror mission model +moment +momentum +monument +mosaic motor mountain move movie +mural music +mystery +nerve +network +nexus news night +nimbus +nomad +north +notion +oasis +ocean +odyssey opinion +opus +orbit original +outpost +overture page painting +palace +panorama +parade +paragon party +passage passenger +passport path pattern +peak +pebble perspective phase philosophy @@ -174,20 +312,30 @@ physical physics piano picture +pillar +pinnacle +pioneer +pixel pizza place plan plane +planet player +plaza +plume point policy +polaris position possibility potato potential power +praxis present president +prism procedure process professor @@ -196,45 +344,73 @@ program progress project prompt +prospect +pulse purpose +puzzle +pyramid quantity +quantum +quest question +quill quote +radiance rain +rampart range ratio reach reaction reality +realm reason recipe record reference reflection +relay +relic resolution resort resource result return +ridge +rift river road rock +rocket rule +rune +sage +sail +sanctuary +sapphire scene science +scope score screen script +scroll season sector +sentinel +shadow shift +shimmer shine ship show sign signal +sign singer +sketch sky +slate smoke snow society @@ -243,54 +419,94 @@ song sound source space +spark +spectrum speech +sphere +spire +spring stable stage star start state +station status +stone storm strategy street strength +stride strike string +stronghold structure studio style success +summit summer +sunrise +sunset surprise +survey +sword +symbol system tale target team technology +tempest +tempo +terrain theme theory thing thought +threshold +thunder +tide +timber time title +token +torch +tower track trade +trail train travel +treasure trick trip +tribute +triumph truck tune +tundra +tunnel +twilight unit +valor +vault +venture version +vessel video view +vista voice volume +voyage wave way weather +whirl wind +wing winter wish world @@ -298,4 +514,6 @@ writer writing year yesterday +zenith +zephyr zone diff --git a/includes/binary_includes/usernames/atoms/username_nouns_animals.txt b/includes/binary_includes/usernames/atoms/username_nouns_animals.txt index c2786b1054..56134374b4 100644 --- a/includes/binary_includes/usernames/atoms/username_nouns_animals.txt +++ b/includes/binary_includes/usernames/atoms/username_nouns_animals.txt @@ -2,35 +2,202 @@ # https://github.com/jneidel/animal-names/blob/master/animals-common.txt # This has been trimmed to remove potentially negative, offensive, uncool, or otherwise bad choices +albatross alligator alpaca +antelope +armadillo +axolotl badger +barracuda +bobcat +cardinal +caribou cat +chameleon cheetah cobra +condor +corgi coyote +crane crocodile +dingo +dolphin dragon +dragonfly eagle +elk falcon +finch fox +gazelle gecko giraffe hawk hedgehog +heron +hyena +iguana +impala jaguar kangaroo +kiwi +kleekai koala +komodo +lemur leopard lion llama +lynx +mako +marlin +marmot +meerkat +narwhal +nighthawk +orca +osprey +owl +panda +parrot penguin +phoenix puma +python rabbit raccoon +raptor +raven +reindeer +roadrunner shark +shiba +sparrow +sphinx +squirrel +taipan tiger +toucan +unicorn +viper wallaby +wildcat wolf +wolverine wombat zebra + +# Probably not good animals to use, for one reason or another: +# baboon +# bat +# bear +# beaver +# bison +# buffalo +# bunny +# butterfly +# camel +# chinchilla +# chipmunk +# cockatoo +# cougar +# crow +# cuttlefish +# deer +# dove +# duck +# eel +# elephant +# emu +# ermine +# ferret +# firefly +# flamingo +# frog +# goose +# gorilla +# grasshopper +# grizzly +# grouse +# hamster +# hare +# hippo +# hornet +# hound +# hummingbird +# husky +# ibex +# ibis +# jackal +# jackrabbit +# jay +# jellyfish +# kestrel +# kingfisher +# kookaburra +# lizard +# lobster +# macaw +# mammoth +# manatee +# mandrill +# mantis +# mockingbird +# mongoose +# moose +# mustang +# newt +# ocelot +# octopus +# okapi +# oriole +# otter +# ox +# panther +# peacock +# pelican +# peregrine +# pheasant +# piranha +# platypus +# porcupine +# porpoise +# quail +# quetzal +# ram +# rhino +# robin +# rooster +# sailfish +# salamander +# salmon +# seahorse +# seal +# squid +# stallion +# starfish +# starling +# stingray +# stork +# sturgeon +# swan +# swordfish +# tamarin +# tapir +# tarpon +# terrapin +# thrush +# trout +# tuna +# turtle +# vulture +# walrus +# warthog +# wasp +# weasel +# whale +# woodpecker +# wren +# yak