diff --git a/bin/now-domains.js b/bin/now-domains.js index 2cddcc5..7c18533 100755 --- a/bin/now-domains.js +++ b/bin/now-domains.js @@ -16,11 +16,12 @@ import NowDomains from '../lib/domains' const argv = minimist(process.argv.slice(2), { string: ['config', 'token'], - boolean: ['help', 'debug', 'force'], + boolean: ['help', 'debug', 'external', 'force'], alias: { help: 'h', config: 'c', debug: 'd', + external: 'e', force: 'f', token: 't' } @@ -37,6 +38,7 @@ const help = () => { -h, --help Output usage information -c ${chalk.bold.underline('FILE')}, --config=${chalk.bold.underline('FILE')} Config file -d, --debug Debug mode [off] + -e, --external Use external DNS server -f, --force Skip DNS verification -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline('TOKEN')} Login token @@ -77,6 +79,18 @@ const help = () => { ${chalk.cyan('$ now domain rm domainId')} To get the list of domain ids, use ${chalk.dim('`now domains ls`')}. + + ${chalk.gray('–')} Adding and verifying a domain name using zeit.world nameservers: + + ${chalk.cyan('$ now domain add my-app.com')} + + The command will tell you if the domain was verified succesfully. In case the domain was not verified succesfully you should retry adding the domain after some time. + + ${chalk.gray('–')} Adding and verifying a domain name using an external nameserver: + + ${chalk.cyan('$ now domain add -e my-app.com')} + + and follow the verification instructions if requested. Finally, rerun the same command after completing the verification step. `) } @@ -137,7 +151,7 @@ async function run(token) { const domains = await domain.ls() domains.sort((a, b) => new Date(b.created) - new Date(a.created)) const current = new Date() - const header = [['', 'id', 'dns', 'url', 'created'].map(s => chalk.dim(s))] + const header = [['', 'id', 'dns', 'url', 'verified', 'created'].map(s => chalk.dim(s))] const out = domains.length === 0 ? null : table(header.concat(domains.map(domain => { const ns = domain.isExternal ? 'external' : 'zeit.world' const url = chalk.underline(`https://${domain.name}`) @@ -147,9 +161,10 @@ async function run(token) { domain.uid, ns, url, + domain.verified, time ] - })), {align: ['l', 'r', 'l', 'l', 'l'], hsep: ' '.repeat(2), stringLength: strlen}) + })), {align: ['l', 'r', 'l', 'l', 'l', 'l'], hsep: ' '.repeat(2), stringLength: strlen}) const elapsed_ = ms(new Date() - start_) console.log(`> ${domains.length} domain${domains.length === 1 ? '' : 's'} found ${chalk.gray(`[${elapsed_}]`)}`) @@ -209,12 +224,18 @@ async function run(token) { const start = new Date() const name = String(args[0]) - const {uid, created} = await domain.add(name, argv.force) + const {uid, code, verified, verifyToken, created} = await domain.add(name, argv.force, argv.external) const elapsed = ms(new Date() - start) - if (created) { + if (created && verified) { console.log(`${chalk.cyan('> Success!')} Domain ${chalk.bold(chalk.underline(name))} ${chalk.dim(`(${uid})`)} added [${elapsed}]`) - } else { + } else if (verified) { + console.log(`${chalk.cyan('> Success!')} Domain ${chalk.bold(chalk.underline(name))} ${chalk.dim(`(${uid})`)} verified [${elapsed}]`) + } else if (verifyToken) { + console.log(`> Verification required: Please add the following TXT record on the external DNS server: _now.${name}: ${verifyToken}`) + } else if (code === 'not_modified') { console.log(`${chalk.cyan('> Success!')} Domain ${chalk.bold(chalk.underline(name))} ${chalk.dim(`(${uid})`)} already exists [${elapsed}]`) + } else { + console.log('> Verification required: Please rerun this command after some time') } break diff --git a/lib/alias.js b/lib/alias.js index b6669d3..1ec462e 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -119,13 +119,27 @@ export default class Alias extends Now { console.log(`> Verifying the DNS settings for ${chalk.bold(chalk.underline(alias))} (see ${chalk.underline('https://zeit.world')} for help)`) const {domain, nameservers} = await this.getNameservers(alias) + let skipDNSVerification = false if (this._debug) { console.log(`> [debug] Found domain ${domain} and nameservers ${nameservers}`) } + if (!isZeitWorld(nameservers)) { + const domainInfo = await this.getDomain(domain) + if (domainInfo.verified) { + skipDNSVerification = true + } else if (domainInfo.uid) { + const e = new Error(`> The domain ${domain} is already registered with now but additional verification is needed, please refer to 'now domain --help'.`) + e.userError = true + throw e + } + } + try { - await this.verifyOwnership(alias) + if (!skipDNSVerification) { + await this.verifyOwnership(alias) + } } catch (err) { if (err.userError) { // a user error would imply that verification failed @@ -178,7 +192,7 @@ export default class Alias extends Now { } } - if (!isZeitWorld(nameservers)) { + if (!isZeitWorld(nameservers) && !skipDNSVerification) { if (this._debug) { console.log(`> [debug] Trying to register a non-ZeitWorld domain ${domain} for the current user`) } diff --git a/lib/domains.js b/lib/domains.js index 74d18df..39a997c 100644 --- a/lib/domains.js +++ b/lib/domains.js @@ -37,15 +37,15 @@ export default class Domains extends Now { }) } - async add(domain, skipVerification) { + async add(domain, skipVerification, isExternal) { if (!domainRegex.test(domain)) { const err = new Error(`The supplied value ${chalk.bold(`"${domain}"`)} is not a valid domain.`) err.userError = true throw err } - if (skipVerification) { - return this.setupDomain(domain) + if (skipVerification || isExternal) { + return this.setupDomain(domain, {isExternal}) } let ns diff --git a/lib/index.js b/lib/index.js index e29eced..663e03e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -387,6 +387,22 @@ export default class Now extends EventEmitter { }) } + async getDomain(domain) { + return this.retry(async (bail, attempt) => { + if (this._debug) { + console.time(`> [debug] #${attempt} GET /domains/${domain}`) + } + + const res = await this._fetch(`/domains/${domain}`) + + if (this._debug) { + console.timeEnd(`> [debug] #${attempt} GET /domains/${domain}`) + } + + return await res.json() + }) + } + getNameservers(domain) { return new Promise(resolve => { let fallback = false @@ -449,8 +465,9 @@ export default class Now extends EventEmitter { console.timeEnd(`> [debug] #${attempt} POST /domains`) } + const body = await res.json() + if (res.status === 403) { - const body = await res.json() const code = body.error.code let err @@ -464,15 +481,13 @@ export default class Now extends EventEmitter { return bail(err) } - const body = await res.json() - // domain already exists if (res.status === 409) { if (this._debug) { console.log('> [debug] Domain already exists (noop)') } - return {uid: body.error.uid} + return {uid: body.error.uid, code: body.error.code} } if (res.status !== 200) {