diff --git a/lib/utils/reserved-users.js b/lib/utils/reserved-users.js new file mode 100644 index 000000000..3039846b3 --- /dev/null +++ b/lib/utils/reserved-users.js @@ -0,0 +1,2236 @@ +// @flow + +const reservedUsernamesSet: $ReadOnlySet = new Set([ + // Additional Reserved Keywords + 'Comm', + 'dapp-tools', + 'dapp_tools', + 'ethers-js', + 'ethers_js', + 'ganache-cli', + 'ganache_cli', + 'hardhat', + 'Mod', + 'Moderator', + 'solidity', + 'truffle', + 'web3', + 'web3modal', + + // Reserved Usernames List + // https://github.com/shouldbee/reserved-usernames + '0', + '12', + '49', + '478', + '1hive', + 'aave', + 'agoraspace', + 'aladdindao', + 'alchemistdao', + 'allships', + 'ampled', + 'angeldao', + 'aragon', + 'badgerdao', + 'bankless', + 'bardao', + 'bayc', + 'beetsdao', + 'braintrust', + 'bright', + 'brightid', + 'brightmomentsgallery', + 'brrdao', + 'cabindao', + 'canudao', + 'cedge', + 'clip', + 'closerdao', + 'coinvise', + 'collab-land', + 'collab_land', + 'colony', + 'comp', + 'compound', + 'coordinape', + 'cre8club', + 'crisisdao', + 'cspdao', + 'daohaus', + 'daosquare', + 'daostack', + 'darkstardao', + 'decred', + 'developerdao', + 'devs', + 'dfdao', + 'dinnerdao', + 'dinogangz', + 'discodao', + 'distributed-town', + 'distributed_town', + 'divineroles', + 'dopewarsdao', + 'dorg', + 'duckdao', + 'dxdao', + 'edendao', + 'elektradao', + 'ethernautdao', + 'etherscan', + 'evewealth', + 'ff', + 'fiatluxdao', + 'fingerprints', + 'fireeyes', + 'flamingodao', + 'forefront', + 'freecompany', + 'friendswithbenefits', + 'fwb', + 'gardens', + 'gcr', + 'genezisbiohacking', + 'genre', + 'geometrydao', + 'gitcoin', + 'gnosis', + 'gnosissafe', + 'gorn', + 'gornhegemonydao', + 'gremlins', + 'guildhall', + 'habitat', + 'heatdao', + 'herstorydao', + 'honeydao', + 'idlefinance', + 'indexcoop', + 'insuredao', + 'jennydao', + 'joystream', + 'jumperdao', + 'keeperdao', + 'kleoverse', + 'komorebicollective', + 'krause', + 'krausehouse', + 'learndao', + 'leavingrecords', + 'lex', + 'lexdao', + 'llama', + 'lovesocietydao', + 'lurkerdao', + 'magnetdao', + 'makerdao', + 'maodao', + 'maskdao', + 'meebitsdao', + 'meritcircle', + 'metacartel', + 'metafam', + 'metagammadelta', + 'metamask', + 'metaversedao', + 'minty', + 'mirror-xyz', + 'mirror_xyz', + 'mirrorclubdao', + 'molochdao', + 'moonshotcollective', + 'moshdao', + 'muse0', + 'nebo', + 'neptunedao', + 'nfdao', + 'nounsdao', + 'olympusdao', + 'opendao', + 'opensea', + 'opolis', + 'orcaprotocol', + 'pacdao', + 'paperclip', + 'parcel', + 'party', + 'partydao', + 'peerion', + 'phlotedao', + 'physicalanddigitalartaficionados', + 'pizzadao', + 'pleasrdao', + 'pokemontrainersclub', + 'prints', + 'proofofhumanity', + 'prosperdao', + 'proteindao', + 'psydao', + 'rabbithole', + 'raidguild', + 'rainbowwallet', + 'raribledao', + 'readyplayerdao', + 'reddao', + 'ref', + 'retokendao', + 'ribondao', + 'rumblekong', + 'sarcophagus', + 'scribedao', + 'seedclub', + 'sharkdao', + 'shinydao', + 'snapshot', + 'snx', + 'sourcecred', + 'spork', + 'sporkdao', + 'sputnik-fund', + 'sputnik_fund', + 'squaddao', + 'squig', + 'squiggle', + 'stack', + 'stackerventuresdao', + 'syndicate', + 'synthetix', + 'tally', + 'taodao', + 'tarascadao', + 'terrachess', + 'thelao', + 'thewipmeetup', + 'thugdao', + 'tinseldao', + 'tokenwalkdao', + 'tomomasterdao', + 'triforcedao', + 'trippy', + 'trojandao', + 'ultradao', + 'universitydao', + 'unlockdao', + 'vectordao', + 'viariodao', + 'vita', + 'vitadao', + 'walletconnect', + 'whalerdao', + 'whiskeypioneers', + 'yamdao', + 'yearn', + 'yfi', + 'ygg', + 'zouzoukwa', + + // Top Level Domains + // https://data.iana.org/TLD/tlds-alpha-by-domain.txt + 'aaa', + 'aarp', + 'abarth', + 'abb', + 'abbott', + 'abbvie', + 'abc', + 'able', + 'abogado', + 'abudhabi', + 'ac', + 'academy', + 'accenture', + 'accountant', + 'accountants', + 'aco', + 'actor', + 'ad', + 'adac', + 'ads', + 'adult', + 'ae', + 'aeg', + 'aero', + 'aetna', + 'af', + 'afamilycompany', + 'afl', + 'africa', + 'ag', + 'agakhan', + 'agency', + 'ai', + 'aig', + 'airbus', + 'airforce', + 'airtel', + 'akdn', + 'al', + 'alfaromeo', + 'alibaba', + 'alipay', + 'allfinanz', + 'allstate', + 'ally', + 'alsace', + 'alstom', + 'am', + 'amazon', + 'americanexpress', + 'americanfamily', + 'amex', + 'amfam', + 'amica', + 'amsterdam', + 'analytics', + 'android', + 'anquan', + 'anz', + 'ao', + 'aol', + 'apartments', + 'app', + 'apple', + 'aq', + 'aquarelle', + 'ar', + 'arab', + 'aramco', + 'archi', + 'army', + 'arpa', + 'art', + 'arte', + 'as', + 'asda', + 'asia', + 'associates', + 'at', + 'athleta', + 'attorney', + 'au', + 'auction', + 'audi', + 'audible', + 'audio', + 'auspost', + 'author', + 'auto', + 'autos', + 'avianca', + 'aw', + 'aws', + 'ax', + 'axa', + 'az', + 'azure', + 'ba', + 'baby', + 'baidu', + 'banamex', + 'bananarepublic', + 'band', + 'bank', + 'bar', + 'barcelona', + 'barclaycard', + 'barclays', + 'barefoot', + 'bargains', + 'baseball', + 'basketball', + 'bauhaus', + 'bayern', + 'bb', + 'bbc', + 'bbt', + 'bbva', + 'bcg', + 'bcn', + 'bd', + 'be', + 'beats', + 'beauty', + 'beer', + 'bentley', + 'berlin', + 'best', + 'bestbuy', + 'bet', + 'bf', + 'bg', + 'bh', + 'bharti', + 'bi', + 'bible', + 'bid', + 'bike', + 'bing', + 'bingo', + 'bio', + 'biz', + 'bj', + 'black', + 'blackfriday', + 'blockbuster', + 'blog', + 'bloomberg', + 'blue', + 'bm', + 'bms', + 'bmw', + 'bn', + 'bnpparibas', + 'bo', + 'boats', + 'boehringer', + 'bofa', + 'bom', + 'bond', + 'boo', + 'book', + 'booking', + 'bosch', + 'bostik', + 'boston', + 'bot', + 'boutique', + 'box', + 'br', + 'bradesco', + 'bridgestone', + 'broadway', + 'broker', + 'brother', + 'brussels', + 'bs', + 'bt', + 'budapest', + 'bugatti', + 'build', + 'builders', + 'business', + 'buy', + 'buzz', + 'bv', + 'bw', + 'by', + 'bz', + 'bzh', + 'ca', + 'cab', + 'cafe', + 'cal', + 'call', + 'calvinklein', + 'cam', + 'camera', + 'camp', + 'cancerresearch', + 'canon', + 'capetown', + 'capital', + 'capitalone', + 'car', + 'caravan', + 'cards', + 'care', + 'career', + 'careers', + 'cars', + 'casa', + 'case', + 'cash', + 'casino', + 'cat', + 'catering', + 'catholic', + 'cba', + 'cbn', + 'cbre', + 'cbs', + 'cc', + 'cd', + 'center', + 'ceo', + 'cern', + 'cf', + 'cfa', + 'cfd', + 'cg', + 'ch', + 'chanel', + 'channel', + 'charity', + 'chase', + 'chat', + 'cheap', + 'chintai', + 'christmas', + 'chrome', + 'church', + 'ci', + 'cipriani', + 'circle', + 'cisco', + 'citadel', + 'citi', + 'citic', + 'city', + 'cityeats', + 'ck', + 'cl', + 'claims', + 'cleaning', + 'click', + 'clinic', + 'clinique', + 'clothing', + 'cloud', + 'club', + 'clubmed', + 'cm', + 'cn', + 'co', + 'coach', + 'codes', + 'coffee', + 'college', + 'cologne', + 'com', + 'comcast', + 'commbank', + 'community', + 'company', + 'compare', + 'computer', + 'comsec', + 'condos', + 'construction', + 'consulting', + 'contact', + 'contractors', + 'cooking', + 'cookingchannel', + 'cool', + 'coop', + 'corsica', + 'country', + 'coupon', + 'coupons', + 'courses', + 'cpa', + 'cr', + 'credit', + 'creditcard', + 'creditunion', + 'cricket', + 'crown', + 'crs', + 'cruise', + 'cruises', + 'csc', + 'cu', + 'cuisinella', + 'cv', + 'cw', + 'cx', + 'cy', + 'cymru', + 'cyou', + 'cz', + 'dabur', + 'dad', + 'dance', + 'data', + 'date', + 'dating', + 'datsun', + 'day', + 'dclk', + 'dds', + 'de', + 'deal', + 'dealer', + 'deals', + 'degree', + 'delivery', + 'dell', + 'deloitte', + 'delta', + 'democrat', + 'dental', + 'dentist', + 'desi', + 'design', + 'dev', + 'dhl', + 'diamonds', + 'diet', + 'digital', + 'direct', + 'directory', + 'discount', + 'discover', + 'dish', + 'diy', + 'dj', + 'dk', + 'dm', + 'dnp', + 'do', + 'docs', + 'doctor', + 'dog', + 'domains', + 'dot', + 'download', + 'drive', + 'dtv', + 'dubai', + 'duck', + 'dunlop', + 'dupont', + 'durban', + 'dvag', + 'dvr', + 'dz', + 'earth', + 'eat', + 'ec', + 'eco', + 'edeka', + 'edu', + 'education', + 'ee', + 'eg', + 'email', + 'emerck', + 'energy', + 'engineer', + 'engineering', + 'enterprises', + 'epson', + 'equipment', + 'er', + 'ericsson', + 'erni', + 'es', + 'esq', + 'estate', + 'et', + 'etisalat', + 'eu', + 'eurovision', + 'eus', + 'events', + 'exchange', + 'expert', + 'exposed', + 'express', + 'extraspace', + 'fage', + 'fail', + 'fairwinds', + 'faith', + 'family', + 'fan', + 'fans', + 'farm', + 'farmers', + 'fashion', + 'fast', + 'fedex', + 'feedback', + 'ferrari', + 'ferrero', + 'fi', + 'fiat', + 'fidelity', + 'fido', + 'film', + 'final', + 'finance', + 'financial', + 'fire', + 'firestone', + 'firmdale', + 'fish', + 'fishing', + 'fit', + 'fitness', + 'fj', + 'fk', + 'flickr', + 'flights', + 'flir', + 'florist', + 'flowers', + 'fly', + 'fm', + 'fo', + 'foo', + 'food', + 'foodnetwork', + 'football', + 'ford', + 'forex', + 'forsale', + 'forum', + 'foundation', + 'fox', + 'fr', + 'free', + 'fresenius', + 'frl', + 'frogans', + 'frontdoor', + 'frontier', + 'ftr', + 'fujitsu', + 'fun', + 'fund', + 'furniture', + 'futbol', + 'fyi', + 'ga', + 'gal', + 'gallery', + 'gallo', + 'gallup', + 'game', + 'games', + 'gap', + 'garden', + 'gay', + 'gb', + 'gbiz', + 'gd', + 'gdn', + 'ge', + 'gea', + 'gent', + 'genting', + 'george', + 'gf', + 'gg', + 'ggee', + 'gh', + 'gi', + 'gift', + 'gifts', + 'gives', + 'giving', + 'gl', + 'glade', + 'glass', + 'gle', + 'global', + 'globo', + 'gm', + 'gmail', + 'gmbh', + 'gmo', + 'gmx', + 'gn', + 'godaddy', + 'gold', + 'goldpoint', + 'golf', + 'goo', + 'goodyear', + 'goog', + 'google', + 'gop', + 'got', + 'gov', + 'gp', + 'gq', + 'gr', + 'grainger', + 'graphics', + 'gratis', + 'green', + 'gripe', + 'grocery', + 'group', + 'gs', + 'gt', + 'gu', + 'guardian', + 'gucci', + 'guge', + 'guide', + 'guitars', + 'guru', + 'gw', + 'gy', + 'hair', + 'hamburg', + 'hangout', + 'haus', + 'hbo', + 'hdfc', + 'hdfcbank', + 'health', + 'healthcare', + 'help', + 'helsinki', + 'here', + 'hermes', + 'hgtv', + 'hiphop', + 'hisamitsu', + 'hitachi', + 'hiv', + 'hk', + 'hkt', + 'hm', + 'hn', + 'hockey', + 'holdings', + 'holiday', + 'homedepot', + 'homegoods', + 'homes', + 'homesense', + 'honda', + 'horse', + 'hospital', + 'host', + 'hosting', + 'hot', + 'hoteles', + 'hotels', + 'hotmail', + 'house', + 'how', + 'hr', + 'hsbc', + 'ht', + 'hu', + 'hughes', + 'hyatt', + 'hyundai', + 'ibm', + 'icbc', + 'ice', + 'icu', + 'id', + 'ie', + 'ieee', + 'ifm', + 'ikano', + 'il', + 'im', + 'imamat', + 'imdb', + 'immo', + 'immobilien', + 'in', + 'inc', + 'industries', + 'infiniti', + 'info', + 'ing', + 'ink', + 'institute', + 'insurance', + 'insure', + 'int', + 'international', + 'intuit', + 'investments', + 'io', + 'ipiranga', + 'iq', + 'ir', + 'irish', + 'is', + 'ismaili', + 'ist', + 'istanbul', + 'it', + 'itau', + 'itv', + 'jaguar', + 'java', + 'jcb', + 'je', + 'jeep', + 'jetzt', + 'jewelry', + 'jio', + 'jll', + 'jm', + 'jmp', + 'jnj', + 'jo', + 'jobs', + 'joburg', + 'jot', + 'joy', + 'jp', + 'jpmorgan', + 'jprs', + 'juegos', + 'juniper', + 'kaufen', + 'kddi', + 'ke', + 'kerryhotels', + 'kerrylogistics', + 'kerryproperties', + 'kfh', + 'kg', + 'kh', + 'ki', + 'kia', + 'kim', + 'kinder', + 'kindle', + 'kitchen', + 'kiwi', + 'km', + 'kn', + 'koeln', + 'komatsu', + 'kosher', + 'kp', + 'kpmg', + 'kpn', + 'kr', + 'krd', + 'kred', + 'kuokgroup', + 'kw', + 'ky', + 'kyoto', + 'kz', + 'la', + 'lacaixa', + 'lamborghini', + 'lamer', + 'lancaster', + 'lancia', + 'land', + 'landrover', + 'lanxess', + 'lasalle', + 'lat', + 'latino', + 'latrobe', + 'law', + 'lawyer', + 'lb', + 'lc', + 'lds', + 'lease', + 'leclerc', + 'lefrak', + 'legal', + 'lego', + 'lexus', + 'lgbt', + 'li', + 'lidl', + 'life', + 'lifeinsurance', + 'lifestyle', + 'lighting', + 'like', + 'lilly', + 'limited', + 'limo', + 'lincoln', + 'linde', + 'link', + 'lipsy', + 'live', + 'living', + 'lixil', + 'lk', + 'llc', + 'llp', + 'loan', + 'loans', + 'locker', + 'locus', + 'loft', + 'lol', + 'london', + 'lotte', + 'lotto', + 'love', + 'lpl', + 'lplfinancial', + 'lr', + 'ls', + 'lt', + 'ltd', + 'ltda', + 'lu', + 'lundbeck', + 'luxe', + 'luxury', + 'lv', + 'ly', + 'ma', + 'macys', + 'madrid', + 'maif', + 'maison', + 'makeup', + 'man', + 'management', + 'mango', + 'map', + 'market', + 'marketing', + 'markets', + 'marriott', + 'marshalls', + 'maserati', + 'mattel', + 'mba', + 'mc', + 'mckinsey', + 'md', + 'me', + 'med', + 'media', + 'meet', + 'melbourne', + 'meme', + 'memorial', + 'men', + 'menu', + 'merckmsd', + 'mg', + 'mh', + 'miami', + 'microsoft', + 'mil', + 'mini', + 'mint', + 'mit', + 'mitsubishi', + 'mk', + 'ml', + 'mlb', + 'mls', + 'mm', + 'mma', + 'mn', + 'mo', + 'mobi', + 'mobile', + 'moda', + 'moe', + 'moi', + 'mom', + 'monash', + 'money', + 'monster', + 'mormon', + 'mortgage', + 'moscow', + 'moto', + 'motorcycles', + 'mov', + 'movie', + 'mp', + 'mq', + 'mr', + 'ms', + 'msd', + 'mt', + 'mtn', + 'mtr', + 'mu', + 'museum', + 'music', + 'mutual', + 'mv', + 'mw', + 'mx', + 'my', + 'mz', + 'na', + 'nab', + 'nagoya', + 'name', + 'natura', + 'navy', + 'nba', + 'nc', + 'ne', + 'nec', + 'net', + 'netbank', + 'netflix', + 'network', + 'neustar', + 'new', + 'news', + 'next', + 'nextdirect', + 'nexus', + 'nf', + 'nfl', + 'ng', + 'ngo', + 'nhk', + 'ni', + 'nico', + 'nike', + 'nikon', + 'ninja', + 'nissan', + 'nissay', + 'nl', + 'no', + 'nokia', + 'northwesternmutual', + 'norton', + 'now', + 'nowruz', + 'nowtv', + 'np', + 'nr', + 'nra', + 'nrw', + 'ntt', + 'nu', + 'nyc', + 'nz', + 'obi', + 'observer', + 'off', + 'office', + 'okinawa', + 'olayan', + 'olayangroup', + 'oldnavy', + 'ollo', + 'om', + 'omega', + 'one', + 'ong', + 'onl', + 'online', + 'ooo', + 'open', + 'oracle', + 'orange', + 'org', + 'organic', + 'origins', + 'osaka', + 'otsuka', + 'ott', + 'ovh', + 'pa', + 'page', + 'panasonic', + 'paris', + 'pars', + 'partners', + 'parts', + 'passagens', + 'pay', + 'pccw', + 'pe', + 'pet', + 'pf', + 'pfizer', + 'pg', + 'ph', + 'pharmacy', + 'phd', + 'philips', + 'phone', + 'photo', + 'photography', + 'photos', + 'physio', + 'pics', + 'pictet', + 'pictures', + 'pid', + 'pin', + 'ping', + 'pink', + 'pioneer', + 'pizza', + 'pk', + 'pl', + 'place', + 'play', + 'playstation', + 'plumbing', + 'plus', + 'pm', + 'pn', + 'pnc', + 'pohl', + 'poker', + 'politie', + 'porn', + 'post', + 'pr', + 'pramerica', + 'praxi', + 'press', + 'prime', + 'pro', + 'prod', + 'productions', + 'prof', + 'progressive', + 'promo', + 'properties', + 'property', + 'protection', + 'pru', + 'prudential', + 'ps', + 'pt', + 'pub', + 'pw', + 'pwc', + 'py', + 'qa', + 'qpon', + 'quebec', + 'quest', + 'racing', + 'radio', + 'raid', + 're', + 'read', + 'realestate', + 'realtor', + 'realty', + 'recipes', + 'red', + 'redstone', + 'redumbrella', + 'rehab', + 'reise', + 'reisen', + 'reit', + 'reliance', + 'ren', + 'rent', + 'rentals', + 'repair', + 'report', + 'republican', + 'rest', + 'restaurant', + 'review', + 'reviews', + 'rexroth', + 'rich', + 'richardli', + 'ricoh', + 'ril', + 'rio', + 'rip', + 'ro', + 'rocher', + 'rocks', + 'rodeo', + 'rogers', + 'room', + 'rs', + 'rsvp', + 'ru', + 'rugby', + 'ruhr', + 'run', + 'rw', + 'rwe', + 'ryukyu', + 'sa', + 'saarland', + 'safe', + 'safety', + 'sakura', + 'sale', + 'salon', + 'samsclub', + 'samsung', + 'sandvik', + 'sandvikcoromant', + 'sanofi', + 'sap', + 'sarl', + 'sas', + 'save', + 'saxo', + 'sb', + 'sbi', + 'sbs', + 'sc', + 'sca', + 'scb', + 'schaeffler', + 'schmidt', + 'scholarships', + 'school', + 'schule', + 'schwarz', + 'science', + 'scjohnson', + 'scot', + 'sd', + 'se', + 'search', + 'seat', + 'secure', + 'security', + 'seek', + 'select', + 'sener', + 'services', + 'ses', + 'seven', + 'sew', + 'sex', + 'sexy', + 'sfr', + 'sg', + 'sh', + 'shangrila', + 'sharp', + 'shaw', + 'shell', + 'shia', + 'shiksha', + 'shoes', + 'shop', + 'shopping', + 'shouji', + 'show', + 'showtime', + 'si', + 'silk', + 'sina', + 'singles', + 'site', + 'sj', + 'sk', + 'ski', + 'skin', + 'sky', + 'skype', + 'sl', + 'sling', + 'sm', + 'smart', + 'smile', + 'sn', + 'sncf', + 'so', + 'soccer', + 'social', + 'softbank', + 'software', + 'sohu', + 'solar', + 'solutions', + 'song', + 'sony', + 'soy', + 'spa', + 'space', + 'sport', + 'spot', + 'sr', + 'srl', + 'ss', + 'st', + 'stada', + 'staples', + 'star', + 'statebank', + 'statefarm', + 'stc', + 'stcgroup', + 'stockholm', + 'storage', + 'store', + 'stream', + 'studio', + 'study', + 'style', + 'su', + 'sucks', + 'supplies', + 'supply', + 'support', + 'surf', + 'surgery', + 'suzuki', + 'sv', + 'swatch', + 'swiss', + 'sx', + 'sy', + 'sydney', + 'systems', + 'sz', + 'tab', + 'taipei', + 'talk', + 'taobao', + 'target', + 'tatamotors', + 'tatar', + 'tattoo', + 'tax', + 'taxi', + 'tc', + 'tci', + 'td', + 'tdk', + 'team', + 'tech', + 'technology', + 'tel', + 'temasek', + 'tennis', + 'teva', + 'tf', + 'tg', + 'th', + 'thd', + 'theater', + 'theatre', + 'tiaa', + 'tickets', + 'tienda', + 'tiffany', + 'tips', + 'tires', + 'tirol', + 'tj', + 'tjmaxx', + 'tjx', + 'tk', + 'tkmaxx', + 'tl', + 'tm', + 'tmall', + 'tn', + 'to', + 'today', + 'tokyo', + 'tools', + 'top', + 'toray', + 'toshiba', + 'total', + 'tours', + 'town', + 'toyota', + 'toys', + 'tr', + 'trade', + 'trading', + 'training', + 'travel', + 'travelchannel', + 'travelers', + 'travelersinsurance', + 'trust', + 'trv', + 'tt', + 'tube', + 'tui', + 'tunes', + 'tushu', + 'tv', + 'tvs', + 'tw', + 'tz', + 'ua', + 'ubank', + 'ubs', + 'ug', + 'uk', + 'unicom', + 'university', + 'uno', + 'uol', + 'ups', + 'us', + 'uy', + 'uz', + 'va', + 'vacations', + 'vana', + 'vanguard', + 'vc', + 've', + 'vegas', + 'ventures', + 'verisign', + 'versicherung', + 'vet', + 'vg', + 'vi', + 'viajes', + 'video', + 'vig', + 'viking', + 'villas', + 'vin', + 'vip', + 'virgin', + 'visa', + 'vision', + 'viva', + 'vivo', + 'vlaanderen', + 'vn', + 'vodka', + 'volkswagen', + 'volvo', + 'vote', + 'voting', + 'voto', + 'voyage', + 'vu', + 'vuelos', + 'wales', + 'walmart', + 'walter', + 'wang', + 'wanggou', + 'watch', + 'watches', + 'weather', + 'weatherchannel', + 'webcam', + 'weber', + 'website', + 'wed', + 'wedding', + 'weibo', + 'weir', + 'wf', + 'whoswho', + 'wien', + 'wiki', + 'williamhill', + 'win', + 'windows', + 'wine', + 'winners', + 'wme', + 'wolterskluwer', + 'woodside', + 'work', + 'works', + 'world', + 'wow', + 'ws', + 'wtc', + 'wtf', + 'xbox', + 'xerox', + 'xfinity', + 'xihuan', + 'xin', + 'xn--11b4c3d', + 'xn--1ck2e1b', + 'xn--1qqw23a', + 'xn--2scrj9c', + 'xn--30rr7y', + 'xn--3bst00m', + 'xn--3ds443g', + 'xn--3e0b707e', + 'xn--3hcrj9c', + 'xn--3pxu8k', + 'xn--42c2d9a', + 'xn--45br5cyl', + 'xn--45brj9c', + 'xn--45q11c', + 'xn--4dbrk0ce', + 'xn--4gbrim', + 'xn--54b7fta0cc', + 'xn--55qw42g', + 'xn--55qx5d', + 'xn--5su34j936bgsg', + 'xn--5tzm5g', + 'xn--6frz82g', + 'xn--6qq986b3xl', + 'xn--80adxhks', + 'xn--80ao21a', + 'xn--80aqecdr1a', + 'xn--80asehdb', + 'xn--80aswg', + 'xn--8y0a063a', + 'xn--90a3ac', + 'xn--90ae', + 'xn--90ais', + 'xn--9dbq2a', + 'xn--9et52u', + 'xn--9krt00a', + 'xn--b4w605ferd', + 'xn--bck1b9a5dre4c', + 'xn--c1avg', + 'xn--c2br7g', + 'xn--cck2b3b', + 'xn--cckwcxetd', + 'xn--cg4bki', + 'xn--clchc0ea0b2g2a9gcd', + 'xn--czr694b', + 'xn--czrs0t', + 'xn--czru2d', + 'xn--d1acj3b', + 'xn--d1alf', + 'xn--e1a4c', + 'xn--eckvdtc9d', + 'xn--efvy88h', + 'xn--fct429k', + 'xn--fhbei', + 'xn--fiq228c5hs', + 'xn--fiq64b', + 'xn--fiqs8s', + 'xn--fiqz9s', + 'xn--fjq720a', + 'xn--flw351e', + 'xn--fpcrj9c3d', + 'xn--fzc2c9e2c', + 'xn--fzys8d69uvgm', + 'xn--g2xx48c', + 'xn--gckr3f0f', + 'xn--gecrj9c', + 'xn--gk3at1e', + 'xn--h2breg3eve', + 'xn--h2brj9c', + 'xn--h2brj9c8c', + 'xn--hxt814e', + 'xn--i1b6b1a6a2e', + 'xn--imr513n', + 'xn--io0a7i', + 'xn--j1aef', + 'xn--j1amh', + 'xn--j6w193g', + 'xn--jlq480n2rg', + 'xn--jlq61u9w7b', + 'xn--jvr189m', + 'xn--kcrx77d1x4a', + 'xn--kprw13d', + 'xn--kpry57d', + 'xn--kput3i', + 'xn--l1acc', + 'xn--lgbbat1ad8j', + 'xn--mgb9awbf', + 'xn--mgba3a3ejt', + 'xn--mgba3a4f16a', + 'xn--mgba7c0bbn0a', + 'xn--mgbaakc7dvf', + 'xn--mgbaam7a8h', + 'xn--mgbab2bd', + 'xn--mgbah1a3hjkrd', + 'xn--mgbai9azgqp6j', + 'xn--mgbayh7gpa', + 'xn--mgbbh1a', + 'xn--mgbbh1a71e', + 'xn--mgbc0a9azcg', + 'xn--mgbca7dzdo', + 'xn--mgbcpq6gpa1a', + 'xn--mgberp4a5d4ar', + 'xn--mgbgu82a', + 'xn--mgbi4ecexp', + 'xn--mgbpl2fh', + 'xn--mgbt3dhd', + 'xn--mgbtx2b', + 'xn--mgbx4cd0ab', + 'xn--mix891f', + 'xn--mk1bu44c', + 'xn--mxtq1m', + 'xn--ngbc5azd', + 'xn--ngbe9e0a', + 'xn--ngbrx', + 'xn--node', + 'xn--nqv7f', + 'xn--nqv7fs00ema', + 'xn--nyqy26a', + 'xn--o3cw4h', + 'xn--ogbpf8fl', + 'xn--otu796d', + 'xn--p1acf', + 'xn--p1ai', + 'xn--pgbs0dh', + 'xn--pssy2u', + 'xn--q7ce6a', + 'xn--q9jyb4c', + 'xn--qcka1pmc', + 'xn--qxa6a', + 'xn--qxam', + 'xn--rhqv96g', + 'xn--rovu88b', + 'xn--rvc1e0am3e', + 'xn--s9brj9c', + 'xn--ses554g', + 'xn--t60b56a', + 'xn--tckwe', + 'xn--tiq49xqyj', + 'xn--unup4y', + 'xn--vermgensberater-ctb', + 'xn--vermgensberatung-pwb', + 'xn--vhquv', + 'xn--vuq861b', + 'xn--w4r85el8fhu5dnra', + 'xn--w4rs40l', + 'xn--wgbh1c', + 'xn--wgbl6a', + 'xn--xhq521b', + 'xn--xkc2al3hye2a', + 'xn--xkc2dl3a5ee0h', + 'xn--y9a3aq', + 'xn--yfro4i67o', + 'xn--ygbi2ammx', + 'xn--zfr164b', + + // DAO aggregate + // https://www.notion.so/commapp/DAO-aggregate-1539d5c849da4eec8f479e8f06d46c73 + 'xxx', + 'xyz', + 'yachts', + 'yahoo', + 'yamaxun', + 'yandex', + 'ye', + 'yodobashi', + 'yoga', + 'yokohama', + 'you', + 'youtube', + 'yt', + 'yun', + 'za', + 'zappos', + 'zara', + 'zero', + 'zip', + 'zm', + 'zone', + 'zuerich', + 'zw', + 'skiptocontent', + 'pullrequests', + 'issues', + 'marketplace', + 'explore', + '@andnasnd', + 'shouldbee/', + 'reserved-usernames', + 'public', + 'code', + 'issues4', + 'actions', + 'projects', + 'insights', + 'about', + 'access', + 'account', + 'accounts', + 'activate', + 'activities', + 'activity', + 'add', + 'address', + 'adm', + 'admin', + 'administration', + 'administrator', + 'advertising', + 'affiliate', + 'affiliates', + 'ajax', + 'all', + 'alpha', + 'analysis', + 'anon', + 'anonymous', + 'api', + 'apps', + 'archive', + 'archives', + 'article', + 'asct', + 'asset', + 'atom', + 'auth', + 'authentication', + 'avatar', + 'backup', + 'balancer-manager', + 'banner', + 'banners', + 'beta', + 'billing', + 'bin', + 'blogs', + 'board', + 'bookmark', + 'bots', + 'bug', + 'cache', + 'cadastro', + 'calendar', + 'campaign', + 'cancel', + 'captcha', + 'cart', + 'categories', + 'category', + 'cgi', + 'cgi-bin', + 'changelog', + 'check', + 'checking', + 'checkout', + 'client', + 'cliente', + 'clients', + 'codereview', + 'comercial', + 'comment', + 'comments', + 'communities', + 'compras', + 'config', + 'configuration', + 'connect', + 'contact-us', + 'contact_us', + 'contactus', + 'contest', + 'contribute', + 'corp', + 'create', + 'css', + 'dashboard', + 'db', + 'default', + 'delete', + 'demo', + 'designer', + 'destroy', + 'devel', + 'developer', + 'developers', + 'diagram', + 'diary', + 'dict', + 'dictionary', + 'die', + 'dir', + 'direct_messages', + 'dist', + 'doc', + 'documentation', + 'domain', + 'downloads', + 'ecommerce', + 'edit', + 'editor', + 'employment', + 'empty', + 'end', + 'enterprise', + 'entries', + 'entry', + 'error', + 'errors', + 'eval', + 'event', + 'everyone', + 'exit', + 'facebook', + 'faq', + 'favorite', + 'favorites', + 'feature', + 'features', + 'feed', + 'feeds', + 'file', + 'files', + 'first', + 'flash', + 'fleet', + 'fleets', + 'flog', + 'follow', + 'followers', + 'following', + 'forgot', + 'form', + 'forums', + 'founder', + 'friend', + 'friends', + 'ftp', + 'gadget', + 'gadgets', + 'get', + 'ghost', + 'gist', + 'github', + 'graph', + 'groups', + 'guest', + 'guests', + 'home', + 'homepage', + 'hostmaster', + 'hostname', + 'howto', + 'hpg', + 'html', + 'http', + 'httpd', + 'https', + 'i', + 'iamges', + 'icon', + 'icons', + 'idea', + 'ideas', + 'image', + 'images', + 'imap', + 'img', + 'index', + 'indice', + 'information', + 'inquiry', + 'instagram', + 'intranet', + 'invitations', + 'invite', + 'ipad', + 'iphone', + 'irc', + 'issue', + 'item', + 'items', + 'javascript', + 'job', + 'join', + 'js', + 'json', + 'jump', + 'knowledgebase', + 'language', + 'languages', + 'last', + 'ldap-status', + 'license', + 'links', + 'linux', + 'list', + 'lists', + 'log', + 'log-in', + 'log-out', + 'log_in', + 'log_out', + 'login', + 'logout', + 'logs', + 'm', + 'mac', + 'mail', + 'mail1', + 'mail2', + 'mail3', + 'mail4', + 'mail5', + 'mailer', + 'mailing', + 'maintenance', + 'manager', + 'manual', + 'maps', + 'master', + 'member', + 'members', + 'message', + 'messages', + 'messenger', + 'microblog', + 'microblogs', + 'mine', + 'mis', + 'mob', + 'movies', + 'mp3', + 'msg', + 'msn', + 'musicas', + 'mysql', + 'named', + 'nan', + 'navi', + 'navigation', + 'newsletter', + 'nick', + 'nickname', + 'notes', + 'noticias', + 'notification', + 'notifications', + 'notify', + 'ns', + 'ns1', + 'ns10', + 'ns2', + 'ns3', + 'ns4', + 'ns5', + 'ns6', + 'ns7', + 'ns8', + 'ns9', + 'null', + 'oauth', + 'oauth_clients', + 'offer', + 'offers', + 'official', + 'old', + 'openid', + 'operator', + 'order', + 'orders', + 'organization', + 'organizations', + 'overview', + 'owner', + 'owners', + 'pager', + 'pages', + 'panel', + 'password', + 'payment', + 'perl', + 'photoalbum', + 'php', + 'phpmyadmin', + 'phppgadmin', + 'phpredisadmin', + 'pic', + 'plan', + 'plans', + 'plugin', + 'plugins', + 'policy', + 'pop', + 'pop3', + 'popular', + 'portal', + 'postfix', + 'postmaster', + 'posts', + 'premium', + 'price', + 'pricing', + 'privacy', + 'privacy-policy', + 'privacy_policy', + 'privacypolicy', + 'private', + 'product', + 'products', + 'profile', + 'project', + 'purpose', + 'put', + 'python', + 'query', + 'random', + 'ranking', + 'readme', + 'recent', + 'recruit', + 'recruitment', + 'register', + 'registration', + 'release', + 'remove', + 'replies', + 'reports', + 'repositories', + 'repository', + 'req', + 'request', + 'requests', + 'reset', + 'roc', + 'root', + 'rss', + 'ruby', + 'rule', + 'sag', + 'sales', + 'sample', + 'samples', + 'script', + 'scripts', + 'self', + 'send', + 'server', + 'server-info', + 'server-status', + 'service', + 'session', + 'sessions', + 'setting', + 'settings', + 'setup', + 'share', + 'sign-in', + 'sign-up', + 'sign_in', + 'sign_up', + 'signin', + 'signout', + 'signup', + 'sitemap', + 'sites', + 'smartphone', + 'smtp', + 'soporte', + 'source', + 'spec', + 'special', + 'sql', + 'src', + 'ssh', + 'ssl', + 'ssladmin', + 'ssladministrator', + 'sslwebmaster', + 'staff', + 'stage', + 'staging', + 'start', + 'stat', + 'state', + 'static', + 'stats', + 'status', + 'stores', + 'stories', + 'styleguide', + 'stylesheet', + 'stylesheets', + 'subdomain', + 'subscribe', + 'subscriptions', + 'suporte', + 'svn', + 'swf', + 'sys', + 'sysadmin', + 'sysadministrator', + 'system', + 'tablet', + 'tablets', + 'tag', + 'task', + 'tasks', + 'teams', + 'telnet', + 'term', + 'terms', + 'terms-of-service', + 'terms_of_service', + 'termsofservice', + 'test', + 'test1', + 'test2', + 'test3', + 'teste', + 'testing', + 'tests', + 'theme', + 'themes', + 'thread', + 'threads', + 'tmp', + 'todo', + 'tool', + 'topic', + 'topics', + 'tos', + 'tour', + 'translations', + 'trends', + 'tutorial', + 'tux', + 'twitter', + 'undef', + 'unfollow', + 'unsubscribe', + 'update', + 'upload', + 'uploads', + 'url', + 'usage', + 'user', + 'username', + 'users', + 'usuario', + 'vendas', + 'ver', + 'version', + 'videos', + 'visitor', + 'web', + 'webhook', + 'webhooks', + 'webmail', + 'webmaster', + 'websites', + 'welcome', + 'widget', + 'widgets', + 'word', + 'workshop', + 'ww', + 'wws', + 'www', + 'www1', + 'www2', + 'www3', + 'www4', + 'www5', + 'www6', + 'www7', + 'wwws', + 'wwww', + 'xfn', + 'xml', + 'xmpp', + 'xpg', + 'yaml', + 'year', + 'yml', + 'yourdomain', + 'yourname', + 'yoursite', + 'yourusername', +]); + +export { reservedUsernamesSet }; diff --git a/native/account/register-panel.react.js b/native/account/register-panel.react.js index 47156c244..a99fa7a81 100644 --- a/native/account/register-panel.react.js +++ b/native/account/register-panel.react.js @@ -1,468 +1,476 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { Text, View, StyleSheet, Platform, Keyboard, Alert, Linking, } from 'react-native'; import Animated from 'react-native-reanimated'; import { registerActionTypes, register } from 'lib/actions/user-actions'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors'; import { validUsernameRegex } from 'lib/shared/account-utils'; import type { RegisterInfo, LogInExtraInfo, RegisterResult, LogInStartingPayload, } from 'lib/types/account-types'; import type { LoadingStatus } from 'lib/types/loading-types'; import { useServerCall, useDispatchActionPromise, type DispatchActionPromise, } from 'lib/utils/action-utils'; import SWMansionIcon from '../components/swmansion-icon.react'; import { NavContext } from '../navigation/navigation-context'; import { useSelector } from '../redux/redux-utils'; import { nativeLogInExtraInfoSelector } from '../selectors/account-selectors'; import type { KeyPressEvent } from '../types/react-native'; import { type StateContainer } from '../utils/state-container'; import { TextInput } from './modal-components.react'; import { setNativeCredentials } from './native-credentials'; import { PanelButton, Panel } from './panel-components.react'; export type RegisterState = { +usernameInputText: string, +passwordInputText: string, +confirmPasswordInputText: string, }; type BaseProps = { +setActiveAlert: (activeAlert: boolean) => void, +opacityValue: Animated.Node, +registerState: StateContainer, }; type Props = { ...BaseProps, // Redux state +loadingStatus: LoadingStatus, +logInExtraInfo: () => LogInExtraInfo, // Redux dispatch functions +dispatchActionPromise: DispatchActionPromise, // async functions that hit server APIs +register: (registerInfo: RegisterInfo) => Promise, }; type State = { +confirmPasswordFocused: boolean, }; class RegisterPanel extends React.PureComponent { state: State = { confirmPasswordFocused: false, }; usernameInput: ?TextInput; passwordInput: ?TextInput; confirmPasswordInput: ?TextInput; passwordBeingAutoFilled = false; render() { let confirmPasswordTextInputExtraProps; if ( Platform.OS !== 'ios' || this.state.confirmPasswordFocused || this.props.registerState.state.confirmPasswordInputText.length > 0 ) { confirmPasswordTextInputExtraProps = { secureTextEntry: true, textContentType: 'password', }; } let onPasswordKeyPress; if (Platform.OS === 'ios') { onPasswordKeyPress = this.onPasswordKeyPress; } /* eslint-disable react-native/no-raw-text */ const privatePolicyNotice = ( By signing up, you agree to our{' '} Terms {' & '} Privacy Policy . ); /* eslint-enable react-native/no-raw-text */ return ( {privatePolicyNotice} ); } usernameInputRef = (usernameInput: ?TextInput) => { this.usernameInput = usernameInput; }; passwordInputRef = (passwordInput: ?TextInput) => { this.passwordInput = passwordInput; }; confirmPasswordInputRef = (confirmPasswordInput: ?TextInput) => { this.confirmPasswordInput = confirmPasswordInput; }; focusUsernameInput = () => { invariant(this.usernameInput, 'ref should be set'); this.usernameInput.focus(); }; focusPasswordInput = () => { invariant(this.passwordInput, 'ref should be set'); this.passwordInput.focus(); }; focusConfirmPasswordInput = () => { invariant(this.confirmPasswordInput, 'ref should be set'); this.confirmPasswordInput.focus(); }; onTermsOfUsePressed = () => { Linking.openURL('https://comm.app/terms'); }; onPrivacyPolicyPressed = () => { Linking.openURL('https://comm.app/privacy'); }; onChangeUsernameInputText = (text: string) => { this.props.registerState.setState({ usernameInputText: text }); }; onChangePasswordInputText = (text: string) => { const stateUpdate = {}; stateUpdate.passwordInputText = text; if (this.passwordBeingAutoFilled) { this.passwordBeingAutoFilled = false; stateUpdate.confirmPasswordInputText = text; } this.props.registerState.setState(stateUpdate); }; onPasswordKeyPress = (event: KeyPressEvent) => { const { key } = event.nativeEvent; if ( key.length > 1 && key !== 'Backspace' && key !== 'Enter' && this.props.registerState.state.confirmPasswordInputText.length === 0 ) { this.passwordBeingAutoFilled = true; } }; onChangeConfirmPasswordInputText = (text: string) => { this.props.registerState.setState({ confirmPasswordInputText: text }); }; onConfirmPasswordFocus = () => { this.setState({ confirmPasswordFocused: true }); }; onSubmit = () => { this.props.setActiveAlert(true); if (this.props.registerState.state.passwordInputText === '') { Alert.alert( 'Empty password', 'Password cannot be empty', [{ text: 'OK', onPress: this.onPasswordAlertAcknowledged }], { cancelable: false }, ); } else if ( this.props.registerState.state.passwordInputText !== this.props.registerState.state.confirmPasswordInputText ) { Alert.alert( "Passwords don't match", 'Password fields must contain the same password', [{ text: 'OK', onPress: this.onPasswordAlertAcknowledged }], { cancelable: false }, ); } else if ( this.props.registerState.state.usernameInputText.search( validUsernameRegex, ) === -1 ) { Alert.alert( 'Invalid username', 'Usernames must be at least six characters long, start with either a ' + 'letter or a number, and may contain only letters, numbers, or the ' + 'characters “-” and “_”', [{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }], { cancelable: false }, ); } else { Keyboard.dismiss(); const extraInfo = this.props.logInExtraInfo(); this.props.dispatchActionPromise( registerActionTypes, this.registerAction(extraInfo), undefined, ({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload), ); } }; onPasswordAlertAcknowledged = () => { this.props.setActiveAlert(false); this.props.registerState.setState( { passwordInputText: '', confirmPasswordInputText: '', }, () => { invariant(this.passwordInput, 'ref should exist'); this.passwordInput.focus(); }, ); }; onUsernameAlertAcknowledged = () => { this.props.setActiveAlert(false); this.props.registerState.setState( { usernameInputText: '', }, () => { invariant(this.usernameInput, 'ref should exist'); this.usernameInput.focus(); }, ); }; async registerAction(extraInfo: LogInExtraInfo) { try { const result = await this.props.register({ username: this.props.registerState.state.usernameInputText, password: this.props.registerState.state.passwordInputText, ...extraInfo, }); this.props.setActiveAlert(false); await setNativeCredentials({ username: result.currentUserInfo.username, password: this.props.registerState.state.passwordInputText, }); return result; } catch (e) { - if (e.message === 'username_taken') { + if (e.message === 'username_reserved') { + Alert.alert( + 'Username reserved', + 'This username is currently reserved. Please contact support@' + + 'comm.app if you would like to claim this account.', + [{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }], + { cancelable: false }, + ); + } else if (e.message === 'username_taken') { Alert.alert( 'Username taken', 'An account with that username already exists', [{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }], { cancelable: false }, ); } else if (e.message === 'client_version_unsupported') { const app = Platform.select({ ios: 'App Store', android: 'Play Store', }); Alert.alert( 'App out of date', "Your app version is pretty old, and the server doesn't know how " + `to speak to it anymore. Please use the ${app} app to update!`, [{ text: 'OK', onPress: this.onAppOutOfDateAlertAcknowledged }], { cancelable: false }, ); } else { Alert.alert( 'Unknown error', 'Uhh... try again?', [{ text: 'OK', onPress: this.onUnknownErrorAlertAcknowledged }], { cancelable: false }, ); } throw e; } } onUnknownErrorAlertAcknowledged = () => { this.props.setActiveAlert(false); this.props.registerState.setState( { usernameInputText: '', passwordInputText: '', confirmPasswordInputText: '', }, () => { invariant(this.usernameInput, 'ref should exist'); this.usernameInput.focus(); }, ); }; onAppOutOfDateAlertAcknowledged = () => { this.props.setActiveAlert(false); }; } const styles = StyleSheet.create({ container: { zIndex: 2, }, footer: { alignItems: 'stretch', flexDirection: 'row', flexShrink: 1, justifyContent: 'space-between', paddingLeft: 24, }, hyperlinkText: { color: '#036AFF', fontWeight: 'bold', }, icon: { bottom: 10, left: 4, position: 'absolute', }, input: { paddingLeft: 35, }, notice: { alignSelf: 'center', display: 'flex', flexShrink: 1, maxWidth: 190, paddingBottom: 18, paddingRight: 8, paddingTop: 12, }, noticeText: { color: '#444', fontSize: 13, lineHeight: 20, textAlign: 'center', }, row: { marginHorizontal: 24, }, }); const loadingStatusSelector = createLoadingStatusSelector(registerActionTypes); const ConnectedRegisterPanel: React.ComponentType = React.memo( function ConnectedRegisterPanel(props: BaseProps) { const loadingStatus = useSelector(loadingStatusSelector); const navContext = React.useContext(NavContext); const logInExtraInfo = useSelector(state => nativeLogInExtraInfoSelector({ redux: state, navContext, }), ); const dispatchActionPromise = useDispatchActionPromise(); const callRegister = useServerCall(register); return ( ); }, ); export default ConnectedRegisterPanel; diff --git a/server/src/creators/account-creator.js b/server/src/creators/account-creator.js index 6c0918e21..cdc2b63eb 100644 --- a/server/src/creators/account-creator.js +++ b/server/src/creators/account-creator.js @@ -1,181 +1,190 @@ // @flow import invariant from 'invariant'; import bcrypt from 'twin-bcrypt'; import ashoat from 'lib/facts/ashoat'; import bots from 'lib/facts/bots'; import genesis from 'lib/facts/genesis'; import { validUsernameRegex, oldValidUsernameRegex, } from 'lib/shared/account-utils'; import { hasMinCodeVersion } from 'lib/shared/version-utils'; import type { RegisterResponse, RegisterRequest, } from 'lib/types/account-types'; import { messageTypes } from 'lib/types/message-types'; import { threadTypes } from 'lib/types/thread-types'; import { ServerError } from 'lib/utils/errors'; import { values } from 'lib/utils/objects'; +import { reservedUsernamesSet } from 'lib/utils/reserved-users'; import { dbQuery, SQL } from '../database/database'; import { deleteCookie } from '../deleters/cookie-deleters'; import { fetchThreadInfos } from '../fetchers/thread-fetchers'; import { fetchLoggedInUserInfo, fetchKnownUserInfos, } from '../fetchers/user-fetchers'; import { verifyCalendarQueryThreadIDs } from '../responders/entry-responders'; import { createNewUserCookie, setNewSession } from '../session/cookies'; import { createScriptViewer } from '../session/scripts'; import type { Viewer } from '../session/viewer'; import { updateThread } from '../updaters/thread-updaters'; import createIDs from './id-creator'; import createMessages from './message-creator'; import { createThread, createPrivateThread, privateThreadDescription, } from './thread-creator'; const { commbot } = bots; const ashoatMessages = [ 'welcome to Comm!', 'as you inevitably discover bugs, have feature requests, or design ' + 'suggestions, feel free to message them to me in the app.', ]; const privateMessages = [privateThreadDescription]; async function createAccount( viewer: Viewer, request: RegisterRequest, ): Promise { if (request.password.trim() === '') { throw new ServerError('empty_password'); } const usernameRegex = hasMinCodeVersion(viewer.platformDetails, 69) ? validUsernameRegex : oldValidUsernameRegex; if (request.username.search(usernameRegex) === -1) { throw new ServerError('invalid_username'); } const usernameQuery = SQL` SELECT COUNT(id) AS count FROM users WHERE LCASE(username) = LCASE(${request.username}) `; const promises = [dbQuery(usernameQuery)]; const { calendarQuery } = request; if (calendarQuery) { promises.push(verifyCalendarQueryThreadIDs(calendarQuery)); } + const [[usernameResult]] = await Promise.all(promises); + if (reservedUsernamesSet.has(request.username.toLowerCase())) { + if (hasMinCodeVersion(viewer.platformDetails, 120)) { + throw new ServerError('username_reserved'); + } else { + throw new ServerError('username_taken'); + } + } if (usernameResult[0].count !== 0) { throw new ServerError('username_taken'); } const hash = bcrypt.hashSync(request.password); const time = Date.now(); const deviceToken = request.deviceTokenUpdateRequest ? request.deviceTokenUpdateRequest.deviceToken : viewer.deviceToken; const [id] = await createIDs('users', 1); const newUserRow = [id, request.username, hash, time]; const newUserQuery = SQL` INSERT INTO users(id, username, hash, creation_time) VALUES ${[newUserRow]} `; const [userViewerData] = await Promise.all([ createNewUserCookie(id, { platformDetails: request.platformDetails, deviceToken, }), deleteCookie(viewer.cookieID), dbQuery(newUserQuery), ]); viewer.setNewCookie(userViewerData); if (calendarQuery) { await setNewSession(viewer, calendarQuery, 0); } await updateThread( createScriptViewer(ashoat.id), { threadID: genesis.id, changes: { newMemberIDs: [id] }, }, { forceAddMembers: true, silenceMessages: true, ignorePermissions: true }, ); const [privateThreadResult, ashoatThreadResult] = await Promise.all([ createPrivateThread(viewer, request.username), createThread( viewer, { type: threadTypes.PERSONAL, initialMemberIDs: [ashoat.id], }, { forceAddMembers: true }, ), ]); const ashoatThreadID = ashoatThreadResult.newThreadInfo ? ashoatThreadResult.newThreadInfo.id : ashoatThreadResult.newThreadID; const privateThreadID = privateThreadResult.newThreadInfo ? privateThreadResult.newThreadInfo.id : privateThreadResult.newThreadID; invariant( ashoatThreadID && privateThreadID, 'createThread should return either newThreadInfo or newThreadID', ); let messageTime = Date.now(); const ashoatMessageDatas = ashoatMessages.map(message => ({ type: messageTypes.TEXT, threadID: ashoatThreadID, creatorID: ashoat.id, time: messageTime++, text: message, })); const privateMessageDatas = privateMessages.map(message => ({ type: messageTypes.TEXT, threadID: privateThreadID, creatorID: commbot.userID, time: messageTime++, text: message, })); const messageDatas = [...ashoatMessageDatas, ...privateMessageDatas]; const [ messageInfos, threadsResult, userInfos, currentUserInfo, ] = await Promise.all([ createMessages(viewer, messageDatas), fetchThreadInfos(viewer), fetchKnownUserInfos(viewer), fetchLoggedInUserInfo(viewer), ]); const rawMessageInfos = [ ...ashoatThreadResult.newMessageInfos, ...privateThreadResult.newMessageInfos, ...messageInfos, ]; return { id, rawMessageInfos, currentUserInfo, cookieChange: { threadInfos: threadsResult.threadInfos, userInfos: values(userInfos), }, }; } export default createAccount;