UNPKG

navy

Version:

Quick and powerful development environments using Docker and Docker Compose

213 lines (163 loc) 6.08 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.createCert = createCert; exports.generateRootCa = generateRootCa; exports.getCertsPath = getCertsPath; exports.removeCert = removeCert; var _path = _interopRequireDefault(require("path")); var _config = require("../config"); var _errors = require("../errors"); var _chalk = _interopRequireDefault(require("chalk")); var _fs = _interopRequireDefault(require("fs")); var _nodeForge = require("node-forge"); var _navy = require("../navy"); const debug = require('debug')('navy:https'); function getCertsPath(create = false) { const certsPath = _path.default.join((0, _config.getConfigDir)(), 'tls-certs'); if (!_fs.default.existsSync(certsPath)) { if (create) { debug(`Create ${certsPath} dir`); // $FlowIgnore _fs.default.mkdirSync(certsPath, { recursive: true }); } else { return ''; } } return certsPath; } async function removeCert(opts) { const certsPath = getCertsPath(); const navy = await (0, _navy.getNavy)(opts.navy); const serviceUrl = await navy.url(opts.disable); const baseName = serviceUrl.split('//')[1]; const extensions = ['crt', 'key']; for (const ext of extensions) { const file = `${certsPath}/${baseName}.${ext}`; if (_fs.default.existsSync(file)) { try { await _fs.default.unlinkSync(file); debug(`File ${file} removed.`); } catch (err) { throw new _errors.NavyError(err); } } } } async function generateRootCa() { const tlsRootCaDir = (0, _config.getConfig)().tlsRootCaDir || _config.DEFAULT_TLS_ROOT_CA_DIR; if (!_fs.default.existsSync(tlsRootCaDir)) { debug(`Creating ${tlsRootCaDir} Root CA dir`); try { // $FlowIgnore _fs.default.mkdirSync(tlsRootCaDir, { recursive: true }); } catch (err) { throw new _errors.NavyError(err); } } if (_fs.default.existsSync(`${tlsRootCaDir}/ca.crt`) && _fs.default.existsSync(`${tlsRootCaDir}/ca.key`)) { debug(`Root CA already exists, skipping generation`); return; } debug('Generating Root CA'); debug('Generating 2048-bit key-pair...'); const keys = _nodeForge.pki.rsa.generateKeyPair(2048); debug('Creating self-signed certificate...'); const cert = _nodeForge.pki.createCertificate(); cert.publicKey = keys.publicKey; cert.serialNumber = '01'; cert.validity.notBefore = new Date(); cert.validity.notAfter = new Date(); cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 5); const attrs = [{ name: 'commonName', value: 'navy-dev-ca.local' }, { name: 'organizationName', value: 'navy-dev' }]; cert.setSubject(attrs); cert.setIssuer(attrs); cert.setExtensions([{ name: 'basicConstraints', cA: true }, { name: 'subjectKeyIdentifier' }, { name: 'authorityKeyIdentifier' }]); try { // self-sign certificate cert.sign(keys.privateKey, _nodeForge.md.sha256.create()); // PEM-format keys and cert const pem = { privateKey: _nodeForge.pki.privateKeyToPem(keys.privateKey), publicKey: _nodeForge.pki.publicKeyToPem(keys.publicKey), certificate: _nodeForge.pki.certificateToPem(cert) }; _fs.default.writeFileSync(tlsRootCaDir + '/ca.key', pem.privateKey, { mode: 0o400 }); _fs.default.writeFileSync(tlsRootCaDir + '/ca.pub.key', pem.publicKey, { mode: 0o640 }); _fs.default.writeFileSync(tlsRootCaDir + '/ca.crt', pem.certificate, { mode: 0o640 }); console.log(_chalk.default.green(`✅ CA Certificate created at ${tlsRootCaDir}/ca.crt`)); console.log(_chalk.default.yellow(`⚠️ Importing a self-signed CA into a browser/truststore/keychain is not advisable ⚠️`)); } catch (e) { throw new _errors.NavyError(e); } } async function createCert(opts) { const tlsRootCaDir = (0, _config.getConfig)().tlsRootCaDir || _config.DEFAULT_TLS_ROOT_CA_DIR; const certName = opts.hostName || opts.serviceUrl.split('//')[1]; const certsPath = getCertsPath(true); if (_fs.default.existsSync(`${certsPath}/${certName}.crt`)) { debug(`Certificate for ${certName} already exists, skipping generation`); return; } await generateRootCa(); const caCertString = _fs.default.readFileSync(`${tlsRootCaDir}/ca.crt`, 'utf8'); const caKeyString = _fs.default.readFileSync(`${tlsRootCaDir}/ca.key`, 'utf8'); debug(`Generating cert for ${certName} in ${certsPath}`); const privateCAKey = _nodeForge.pki.privateKeyFromPem(caKeyString); const keys = _nodeForge.pki.rsa.generateKeyPair(2048); const cert = _nodeForge.pki.createCertificate(); const caCert = _nodeForge.pki.certificateFromPem(caCertString); cert.publicKey = keys.publicKey; cert.serialNumber = Math.floor(Math.random() * (99 - 2) + 2).toString(); cert.validity.notBefore = new Date(); cert.validity.notBefore.setDate(cert.validity.notBefore.getDate() - 1); cert.validity.notAfter = new Date(); cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 2); const attrs = [{ name: 'commonName', value: certName }, { name: 'organizationName', value: 'navy-dev' }]; try { cert.setSubject(attrs); cert.setIssuer(caCert.subject.attributes); cert.setExtensions([{ name: 'extKeyUsage', serverAuth: true }]); cert.sign(privateCAKey, _nodeForge.md.sha256.create()); // PEM-format keys and cert const pem = { privateKey: _nodeForge.pki.privateKeyToPem(keys.privateKey), certificate: _nodeForge.pki.certificateToPem(cert) // publicKey: pki.publicKeyToPem(keys.publicKey), }; _fs.default.writeFileSync(`${certsPath}/${certName}.key`, pem.privateKey); _fs.default.writeFileSync(`${certsPath}/${certName}.crt`, pem.certificate); // fs.writeFileSync(`${certsPath}/${certName}.pub.key`, pem.publicKey) } catch (e) { throw new _errors.NavyError(e); } }