Skip to content

Commit

Permalink
feat(cert-v5): New certification configuration workflow for multi cer…
Browse files Browse the repository at this point in the history
…t UI (#1430)
  • Loading branch information
Brett Goulder committed Feb 5, 2020
1 parent 630331e commit 50414f1
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 1 deletion.
38 changes: 37 additions & 1 deletion packages/certs-v5/commands/certs/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ let certificateDetails = require('../../lib/certificate_details.js')
let isWildcard = require('../../lib/is_wildcard.js')
let isWildcardMatch = require('../../lib/is_wildcard_match.js')
let getCertAndKey = require('../../lib/get_cert_and_key.js')
let matchDomains = require('../../lib/match_domains.js')

let { waitForDomains, printDomains } = require('../../lib/domains')

Expand Down Expand Up @@ -199,10 +200,41 @@ function * addDomains (context, heroku, meta, cert) {
}
}

function * configureDomains (context, heroku, meta, cert) {
let certDomains = cert.ssl_cert.cert_domains
let apiDomains = yield waitForDomains(context, heroku)
let appDomains = apiDomains.map(domain => domain.hostname)
let matchedDomains = matchDomains(certDomains, appDomains)

if (matchedDomains.length > 0) {
cli.styledHeader('Almost done! Which of these domains on this application would you like this certificate associated with?')

let selectedDomains = (yield inquirer.prompt([{
type: 'checkbox',
name: 'domains',
message: 'Select domains',
choices: matchedDomains
}])).domains

if (selectedDomains.length > 0) {
yield Promise.all(selectedDomains.map(domain => {
return heroku.request({
method: 'PATCH',
path: `/apps/${context.app}/domains/${domain}`,
headers: { Accept: 'application/vnd.heroku+json; version=3.allow_multiple_sni_endpoints' },
body: { sni_endpoint: cert.name }
})
}))
}
}
}

function * run (context, heroku) {
let meta = yield getMeta(context, heroku)

let files = yield getCertAndKey(context)
let features = yield heroku.get(`/apps/${context.app}/features`)
let canMultiSni = features.find(feature => feature.name === 'allow-multiple-sni-endpoints' && feature.enabled === true)

let cert = yield cli.action(`Adding SSL certificate to ${cli.color.app(context.app)}`, {}, heroku.request({
path: meta.path,
Expand All @@ -224,7 +256,11 @@ function * run (context, heroku) {

certificateDetails(cert)

yield addDomains(context, heroku, meta, cert)
if (canMultiSni) {
yield configureDomains(context, heroku, meta, cert)
} else {
yield addDomains(context, heroku, meta, cert)
}

displayWarnings(cert)
}
Expand Down
49 changes: 49 additions & 0 deletions packages/certs-v5/lib/match_domains.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

function splitDomains(domains) {
return domains.map((domain) => {
return [domain.substring(0, 1), domain.substring(1)];
});
}

function createMatcherFromSplitDomain([firstChar, rest]) {
const matcherContents = [];
if (firstChar === '*') {
matcherContents.push('^[\\w\\-]+');
} else {
matcherContents.push(firstChar);
}

const escapedRest = rest.replace(/\./g, '\\.');

matcherContents.push(escapedRest);

return new RegExp(matcherContents.join(''));
}

function includesWildcard(domains) {
if (domains.some((domain) => (domain[0] === "*"))) {
return true;
}

return false;
}

module.exports = function (certDomains, appDomains) {
const splitCertDomains = splitDomains(certDomains);
const matchers = splitCertDomains.map((splitDomain) => createMatcherFromSplitDomain(splitDomain));

if (includesWildcard(splitCertDomains)) {
const matchedDomains = appDomains.reduce((acc, appDomain) => {
if (matchers.some((matcher) => matcher.test(appDomain))) {
acc.push(appDomain);
}

return acc;
}, []);

return matchedDomains;
} else {
return certDomains.filter((domain) => appDomains.includes(domain));
}
}
Loading

0 comments on commit 50414f1

Please sign in to comment.