UNPKG

@denis-kalinin/dev-certs

Version:

Managing certificates on nodejs http server

145 lines 5.87 kB
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. Object.defineProperty(exports, "__esModule", { value: true }); exports.verifyCertificates = exports.validateCertificateAndKey = exports.isCaInDir = exports.isCaCertificateInstalled = exports.outputMarker = void 0; const child_process_1 = require("child_process"); const crypto = require("crypto"); const fs = require("fs"); const path = require("path"); const defaults = require("./defaults"); const defaults_1 = require("./defaults"); const office_addin_usage_data_1 = require("office-addin-usage-data"); // On win32 this is a unique hash used with PowerShell command to reliably delineate command output exports.outputMarker = process.platform === "win32" ? `[${crypto .createHash("md5") .update(`${defaults.certificateName}${defaults.caCertificatePath}`) .digest("hex")}]` : ""; /* global process, Buffer, __dirname */ function getVerifyCommand(returnInvalidCertificate) { switch (process.platform) { case "win32": { const script = path.resolve(__dirname, "..\\scripts\\verify_ca.ps1"); const defaultCommand = `powershell -ExecutionPolicy Bypass -File "${script}" -CaCertificateName "${defaults.certificateName}" -CaCertificatePath "${defaults.caCertificatePath}" -OutputMarker "${exports.outputMarker}"`; if (returnInvalidCertificate) { return defaultCommand + ` -ReturnInvalidCertificate`; } return defaultCommand; } case "darwin": { // macOS const script = path.resolve(__dirname, "../scripts/verify_ca.sh"); return `sh '${script}' '${defaults.certificateName}'`; } case "linux": { const script = path.resolve(__dirname, "../scripts/verify_ca_linux.sh"); return `sh '${script}' '${defaults.certificateName}'`; } default: throw new office_addin_usage_data_1.ExpectedError(`Platform not supported: ${process.platform}`); } } function isCaCertificateInstalled(returnInvalidCertificate = false) { const command = getVerifyCommand(returnInvalidCertificate); try { const output = (0, child_process_1.execSync)(command, { stdio: "pipe" }).toString(); if (process.platform === "win32") { // Remove any PowerShell output that preceeds invoking the actual certificate check command return (output .slice(output.lastIndexOf(exports.outputMarker) + exports.outputMarker.length) .trim().length !== 0); } // script files return empty string if the certificate not found or expired if (output.length !== 0) { return true; } } catch (error) { // Some commands throw errors if the certifcate is not found or expired } return false; } exports.isCaCertificateInstalled = isCaCertificateInstalled; function isCaInDir() { //check CA has a valid key const caCertPath = path.join(defaults.certificateDirectory, defaults.caCertificateFileName); const caCertKey = path.join(defaults.certificateDirectory, defaults.caKeyFileName); try { validateCertificateAndKey(caCertPath, caCertKey); return true; } catch (err) { return false; } } exports.isCaInDir = isCaInDir; function validateCertificateAndKey(certificatePath, keyPath) { let certificate; let key; try { certificate = fs.readFileSync(certificatePath).toString(); } catch (err) { throw new Error(`Unable to read the certificate.\n${err}`); } try { key = fs.readFileSync(keyPath).toString(); } catch (err) { throw new Error(`Unable to read the certificate key.\n${err}`); } let encrypted; try { encrypted = crypto.publicEncrypt(certificate, Buffer.from("test")); } catch (err) { throw new Error(`The certificate is not valid.\n${err}`); } try { crypto.privateDecrypt(key, encrypted); } catch (err) { throw new Error(`The certificate key is not valid.\n${err}`); } return { certificate, key }; } exports.validateCertificateAndKey = validateCertificateAndKey; function validateIssuer(certificate) { const caPath = path.join(defaults.certificateDirectory, defaults.caCertificateFileName); const caCert = new crypto.X509Certificate(fs.readFileSync(caPath)); const now = new Date(); if (now < new Date(caCert.validFrom)) throw new Error("CA certificate is not YET valid."); if (now > new Date(caCert.validTo)) throw new Error("CA certificate is not ALREADY valid"); const localcert = new crypto.X509Certificate(certificate); if (now < new Date(localcert.validFrom)) throw new Error(`Cert for ${localcert.subject} is not YET valid.`); if (now > new Date(localcert.validTo)) throw new Error(`Cert for ${localcert.subject} is not ALREADY valid.`); const isCertChainOk = localcert.checkIssued(caCert); if (!isCertChainOk) throw new Error("Certificate chain is wrong."); } function verifyCertificates(filename) { const localPath = defaults.getLocalPath(filename); try { let isCertificateValid = true; try { const certKey = validateCertificateAndKey(`${localPath}.crt`, `${localPath}.key`); validateIssuer(certKey.certificate); } catch (err) { isCertificateValid = false; } defaults_1.usageDataObject.reportSuccess("verifyCertificates()"); return isCertificateValid; } catch (err) { defaults_1.usageDataObject.reportException("verifyCertificates()", err); throw err; } } exports.verifyCertificates = verifyCertificates; //# sourceMappingURL=verify.js.map