2020-07-21 13:20:51 +00:00
|
|
|
const BLACKLISTED_SUBDOMAINS = new Set([
|
|
|
|
// from wiki page as of 2018-12-14
|
|
|
|
'aws',
|
|
|
|
'gristlogin',
|
|
|
|
'issues',
|
|
|
|
'metrics',
|
|
|
|
'phab',
|
|
|
|
'releases',
|
|
|
|
'test',
|
|
|
|
'vpn',
|
|
|
|
'www',
|
|
|
|
|
|
|
|
// A few more reserved just in case. The minimum length requirement would eliminate
|
|
|
|
// some in any case, but specified here also in case that minimum changes.
|
|
|
|
'w', 'ww', 'wwww', 'wwwww',
|
|
|
|
'docs', 'api', 'static',
|
|
|
|
'ftp', 'imap', 'pop', 'smtp', 'mail', 'git', 'blog', 'wiki', 'support', 'kb', 'help',
|
2021-08-31 19:56:44 +00:00
|
|
|
'admin', 'store', 'dev', 'beta',
|
2023-06-06 17:08:50 +00:00
|
|
|
'community', 'try', 'wpx', 'telemetry',
|
2020-07-21 13:20:51 +00:00
|
|
|
|
|
|
|
// a few random tech brands
|
|
|
|
'google', 'apple', 'microsoft', 'ms', 'facebook', 'fb', 'twitter', 'youtube', 'yt',
|
|
|
|
|
|
|
|
// updates for new special domains
|
|
|
|
'current', 'staging', 'prod', 'login', 'login-dev',
|
2021-08-31 19:56:44 +00:00
|
|
|
|
|
|
|
// some domains that look suspicious
|
|
|
|
'1ogin', '1ogin-dev'
|
2020-07-21 13:20:51 +00:00
|
|
|
]);
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Checks whether the subdomain is on the list of forbidden subdomains.
|
|
|
|
* See https://phab.getgrist.com/w/hosting/v1/urls/#organization-subdomains
|
|
|
|
*
|
|
|
|
* Also enforces various sanity checks.
|
|
|
|
*
|
|
|
|
* Throws if the subdomain is invalid.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
export function checkSubdomainValidity(subdomain: string): void {
|
|
|
|
// stick with limited alphanumeric subdomains.
|
2021-08-31 19:56:44 +00:00
|
|
|
if (!(/^[a-z0-9][-a-z0-9]*$/.test(subdomain))) {
|
2022-09-29 12:14:10 +00:00
|
|
|
throw new Error('Domain must include lower-case letters, numbers, and dashes only.');
|
2020-07-21 13:20:51 +00:00
|
|
|
}
|
|
|
|
// 'docs-*' is reserved for personal orgs.
|
|
|
|
if (subdomain.startsWith('docs-')) { throw new Error('Domain cannot use reserved prefix "docs-".'); }
|
2021-06-24 23:32:37 +00:00
|
|
|
// 'o-*' is reserved for automatic org domains.
|
|
|
|
if (subdomain.startsWith('o-')) { throw new Error('Domain cannot use reserved prefix "o-".'); }
|
2020-07-21 13:20:51 +00:00
|
|
|
// 'doc-worker-*' is reserved for doc workers.
|
|
|
|
if (subdomain.startsWith('doc-worker-')) { throw new Error('Domain cannot use reserved prefix "doc-worker-".'); }
|
|
|
|
// special subdomains like _domainkey.
|
|
|
|
if (subdomain.startsWith('_')) { throw new Error('Domain cannot use reserved prefix "_".'); }
|
|
|
|
// some domains are currently in use for testing v1.
|
|
|
|
if (subdomain.startsWith('v1-')) { throw new Error('Domain cannot use reserved prefix "v1-".'); }
|
|
|
|
// check limit of 63 characters on dns label.
|
|
|
|
if (subdomain.length > 63) { throw new Error('Domain must contain less than 64 characters.'); }
|
|
|
|
// check the subdomain isn't too short.
|
|
|
|
if (subdomain.length <= 2) { throw new Error('Domain must contain more than 2 characters.'); }
|
|
|
|
// a small blacklist prepared by hand.
|
|
|
|
if (BLACKLISTED_SUBDOMAINS.has(subdomain)) { throw new Error('Invalid domain value.'); }
|
|
|
|
}
|