deep-package-manager
Version:
DEEP Package Manager
326 lines (259 loc) • 7.04 kB
JavaScript
/**
* Created by AlexanderC on 5/27/15.
*/
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ACMService = undefined;
var _AbstractService = require('./AbstractService');
var _deepCore = require('deep-core');
var _deepCore2 = _interopRequireDefault(_deepCore);
var _FailedToRequestCloudFrontDistributionCertificateException = require('./Exception/FailedToRequestCloudFrontDistributionCertificateException');
var _Hash = require('../../Helpers/Hash');
var _ACMDriver = require('../ListingDriver/ACMDriver');
var _CloudFrontService = require('./CloudFrontService');
var _APIGatewayService = require('./APIGatewayService');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* ACMService service
*/
class ACMService extends _AbstractService.AbstractService {
/**
* @param {Array} args
*/
constructor(...args) {
super(...args);
this._allowRunCf = false;
this._allowRunApg = false;
}
/**
* @returns {Boolean}
*/
get allowRunCf() {
return this._allowRunCf;
}
/**
* @returns {Boolean}
*/
get allowRunApg() {
return this._allowRunApg;
}
/**
* @returns {String}
*/
name() {
return _deepCore2.default.AWS.Service.CERTIFICATE_MANAGER;
}
/**
* @returns {String[]}
*/
static get AVAILABLE_REGIONS() {
return _deepCore2.default.AWS.Region.all();
}
/**
* @param {Core.Generic.ObjectStorage} services
* @returns {ACMService}
*/
_setup(services) {
// @todo: implement!
if (this._isUpdate) {
this._ready = true;
return this;
}
this._ready = true;
return this;
}
/**
* @param {Core.Generic.ObjectStorage} services
* @returns {ACMService}
*/
_postProvision(services) {
let domain = this._certificateDomain;
if (domain) {
this.ensureCertificate(domain, (error, certificateArn) => {
if (error) {
console.error(error);
}
if (certificateArn) {
this._config.certificateArn = certificateArn;
this._addToCf(services, domain, certificateArn);
this._addToApg(services, domain, certificateArn);
this._readyTeardown = true;
return this;
}
this._readyTeardown = true;
this._allowRunCf = true;
this._allowRunApg = true;
});
return this;
}
this._allowRunCf = true;
this._allowRunApg = true;
this._readyTeardown = true;
return this;
}
/**
* @param {*} services
* @param {String} domain
* @param {String} certificateArn
*
* @private
*/
_addToApg(services, domain, certificateArn) {
services.find(_APIGatewayService.APIGatewayService).certificateArn = certificateArn;
this._allowRunApg = true;
}
/**
* @param {*} services
* @param {String} domain
* @param {String} certificateArn
*
* @private
*/
_addToCf(services, domain, certificateArn) {
let domainAliases = this._certificateDomainAliases;
let distMetadata = services.find(_CloudFrontService.CloudFrontService).distMetadata;
distMetadata.ViewerCertificate = {
ACMCertificateArn: certificateArn,
CertificateSource: 'acm',
CloudFrontDefaultCertificate: false,
SSLSupportMethod: 'sni-only' // 'vip' one charges 600$/month prorated
};
// enfore https on CF distribution
distMetadata.ViewerProtocolPolicy = 'redirect-to-https';
let aliases = domainAliases && domainAliases.length > 0 ? domainAliases.map(alias => `${alias}.${domain}`) : [domain];
distMetadata.Aliases = {
Quantity: aliases.length,
Items: aliases
};
this._allowRunCf = true;
}
/**
* @returns {String|null}
* @private
*/
get _certificateDomain() {
return this.provisioning.property.config.domain;
}
/**
* @returns {String[]|null}
* @private
*/
get _certificateDomainAliases() {
return this.provisioning.property.config.domainAliases;
}
/**
* @param {String} str
* @returns {String}
* @private
*/
static _escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
}
/**
* @param {String} domain
* @param {Function} cb
* @returns {*}
*/
ensureCertificate(domain, cb) {
let domainRoot = this.extractDomainRoot(domain);
if (!domainRoot) {
return cb(null, domainRoot);
}
this.getDomainCertificateArn(domainRoot, certArn => {
if (certArn) {
cb(null, certArn);
return;
}
console.warn(`Certificate for domain ${domainRoot} must be created manually. Skipping...`);
return cb(null, null);
// this.createCertificate(domainRoot, (error, certArn) => {
// cb(error, certArn);
// });
});
}
/**
* @param {String} domain
* @returns {String}
*/
extractDomainRoot(domain) {
let domainParts = domain.split('.');
if (domainParts.length < 2) {
return null;
}
let domainExt = domainParts.pop();
let domainName = domainParts.pop();
return `${domainName}.${domainExt}`;
}
/**
* @param {String} domain
* @param {Function} cb
*/
createCertificate(domain, cb) {
let acm = this.provisioning.acm;
let payload = {
DomainName: domain,
IdempotencyToken: _Hash.Hash.md5(`${this.provisioning.property.identifier}|${domain}`)
};
acm.requestCertificate(payload, (error, data) => {
if (error) {
cb(new _FailedToRequestCloudFrontDistributionCertificateException.FailedToRequestCloudFrontDistributionCertificateException(error), null);
return;
}
cb(null, data.CertificateArn);
});
}
/**
* @param {String} domain
* @param {Function} cb
*/
getDomainCertificateArn(domain, cb) {
let listing = new _ACMDriver.ACMDriver(this.provisioning.acm, new RegExp(`^${ACMService._escapeRegExp(domain)}$`, 'i'));
listing.list(() => {
let certificates = listing.extractResetStack;
for (let certArn in certificates) {
if (!certificates.hasOwnProperty(certArn)) {
continue;
}
let certData = certificates[certArn];
if (domain === certData.DomainName) {
cb(certArn);
return;
}
}
cb(null);
});
}
/**
* @param {String} certArn
* @param {Function} cb
*/
isCertificateIssued(certArn, cb) {
let acm = this.provisioning.acm;
let payload = {
CertificateArn: certArn
};
acm.describeCertificate(payload, (error, data) => {
if (error) {
cb(error, null);
return;
}
cb(null, data.Certificate.Status === 'ISSUED');
});
}
/**
* @param {Core.Generic.ObjectStorage} services
* @returns {ACMService}
*/
_postDeployProvision(services) {
// @todo: implement!
if (this._isUpdate) {
this._ready = true;
return this;
}
this._ready = true;
return this;
}
}
exports.ACMService = ACMService;