UNPKG

@heroku-cli/plugin-certs-v5

Version:
110 lines (86 loc) 3.38 kB
'use strict' let _ = require('lodash') let cli = require('heroku-cli-util') let psl = require('psl') const wait = ms => new Promise(resolve => setTimeout(resolve, ms)) function type(domain) { return psl.parse(domain.hostname).subdomain === null ? 'ALIAS/ANAME' : 'CNAME' } async function waitForDomains(context, heroku) { function someNull(domains) { return _.some(domains, domain => domain.kind === 'custom' && !domain.cname) } function apiRequest(context, heroku) { return heroku.get(`/apps/${context.app}/domains`) } let apiDomains = await apiRequest(context, heroku) if (someNull(apiDomains)) { await cli.action('Waiting for stable domains to be created', (async function () { let index = 0 do { // trying 30 times was easier for me to test that setTimeout if (index >= 30) { throw new Error('Timed out while waiting for stable domains to be created') } await wait(1000) apiDomains = await apiRequest(context, heroku) index++ } while (someNull(apiDomains)) })()) } return apiDomains } function printDomains(domainsTable, message) { domainsTable = domainsTable.filter(domain => domain.kind === 'custom') domainsTable = domainsTable.map(domain => Object.assign({}, domain, {type: type(domain)})) if (domainsTable.length === 0) { cli.styledHeader(`${message} Add a custom domain to your app by running ${cli.color.app('heroku domains:add <yourdomain.com>')}`) /* eslint-enable no-irregular-whitespace */ } else { cli.styledHeader(`${message} Update your application's DNS settings as follows`) let columns = [ {label: 'Domain', key: 'hostname'}, {label: 'Record Type', key: 'type'}, {label: 'DNS Target', key: 'cname'}, ] if (_.some(domainsTable, domain => domain.warning)) { columns.push({label: 'Warnings', key: 'warning'}) } cli.table(domainsTable, {columns: columns}) } } async function waitForCertIssuedOnDomains(context, heroku) { function certIssuedOrFailedForAllCustomDomains(domains) { domains = domains.filter(domain => domain.kind === 'custom') return _.every(domains, domain => domain.acm_status === 'cert issued' || domain.acm_status === 'failed') } function someFailed(domains) { domains = domains.filter(domain => domain.kind === 'custom') return _.some(domains, domain => domain.acm_status === 'failed') } function apiRequest(context, heroku) { return heroku.get(`/apps/${context.app}/domains`) } function backoff(attempts) { let wait = 15 * 1000 // Don't wait more than 60 seconds let multiplier = attempts < 60 ? Math.floor(attempts / 20) : 3 let extraWait = wait * multiplier return wait + extraWait } let domains = await apiRequest(context, heroku) if (!certIssuedOrFailedForAllCustomDomains(domains)) { await cli.action('Waiting until the certificate is issued to all domains', (async function () { let retries = 0 while (!certIssuedOrFailedForAllCustomDomains(domains)) { await wait(backoff(retries)) domains = await apiRequest(context, heroku) retries++ } if (someFailed(domains)) { throw new Error('ACM not enabled for some domains') } })()) } } module.exports = {waitForDomains, printDomains, waitForCertIssuedOnDomains}