145 lines
20 KiB
JavaScript
145 lines
20 KiB
JavaScript
![]() |
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.assertNotTouchingFiles = exports.openCertificateInFirefox = exports.closeFirefox = exports.removeCertificateFromNSSCertDB = exports.addCertificateToNSSCertDB = void 0;
|
||
|
const tslib_1 = require("tslib");
|
||
|
const path_1 = tslib_1.__importDefault(require("path"));
|
||
|
const url_1 = tslib_1.__importDefault(require("url"));
|
||
|
const debug_1 = tslib_1.__importDefault(require("debug"));
|
||
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
||
|
const get_port_1 = tslib_1.__importDefault(require("get-port"));
|
||
|
const http_1 = tslib_1.__importDefault(require("http"));
|
||
|
const glob_1 = require("glob");
|
||
|
const fs_1 = require("fs");
|
||
|
const utils_1 = require("../utils");
|
||
|
const constants_1 = require("../constants");
|
||
|
const user_interface_1 = tslib_1.__importDefault(require("../user-interface"));
|
||
|
const child_process_1 = require("child_process");
|
||
|
const debug = debug_1.default('devcert:platforms:shared');
|
||
|
/**
|
||
|
* Given a directory or glob pattern of directories, run a callback for each db
|
||
|
* directory, with a version argument.
|
||
|
*/
|
||
|
function doForNSSCertDB(nssDirGlob, callback) {
|
||
|
glob_1.sync(nssDirGlob).forEach((potentialNSSDBDir) => {
|
||
|
debug(`checking to see if ${potentialNSSDBDir} is a valid NSS database directory`);
|
||
|
if (fs_1.existsSync(path_1.default.join(potentialNSSDBDir, 'cert8.db'))) {
|
||
|
debug(`Found legacy NSS database in ${potentialNSSDBDir}, running callback...`);
|
||
|
callback(potentialNSSDBDir, 'legacy');
|
||
|
}
|
||
|
if (fs_1.existsSync(path_1.default.join(potentialNSSDBDir, 'cert9.db'))) {
|
||
|
debug(`Found modern NSS database in ${potentialNSSDBDir}, running callback...`);
|
||
|
callback(potentialNSSDBDir, 'modern');
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Given a directory or glob pattern of directories, attempt to install the
|
||
|
* CA certificate to each directory containing an NSS database.
|
||
|
*/
|
||
|
function addCertificateToNSSCertDB(nssDirGlob, certPath, certutilPath) {
|
||
|
debug(`trying to install certificate into NSS databases in ${nssDirGlob}`);
|
||
|
doForNSSCertDB(nssDirGlob, (dir, version) => {
|
||
|
const dirArg = version === 'modern' ? `sql:${dir}` : dir;
|
||
|
utils_1.run(certutilPath, ['-A', '-d', dirArg, '-t', 'C,,', '-i', certPath, '-n', 'devcert']);
|
||
|
});
|
||
|
debug(`finished scanning & installing certificate in NSS databases in ${nssDirGlob}`);
|
||
|
}
|
||
|
exports.addCertificateToNSSCertDB = addCertificateToNSSCertDB;
|
||
|
function removeCertificateFromNSSCertDB(nssDirGlob, certPath, certutilPath) {
|
||
|
debug(`trying to remove certificates from NSS databases in ${nssDirGlob}`);
|
||
|
doForNSSCertDB(nssDirGlob, (dir, version) => {
|
||
|
const dirArg = version === 'modern' ? `sql:${dir}` : dir;
|
||
|
try {
|
||
|
utils_1.run(certutilPath, ['-A', '-d', dirArg, '-t', 'C,,', '-i', certPath, '-n', 'devcert']);
|
||
|
}
|
||
|
catch (e) {
|
||
|
debug(`failed to remove ${certPath} from ${dir}, continuing. ${e.toString()}`);
|
||
|
}
|
||
|
});
|
||
|
debug(`finished scanning & installing certificate in NSS databases in ${nssDirGlob}`);
|
||
|
}
|
||
|
exports.removeCertificateFromNSSCertDB = removeCertificateFromNSSCertDB;
|
||
|
/**
|
||
|
* Check to see if Firefox is still running, and if so, ask the user to close
|
||
|
* it. Poll until it's closed, then return.
|
||
|
*
|
||
|
* This is needed because Firefox appears to load the NSS database in-memory on
|
||
|
* startup, and overwrite on exit. So we have to ask the user to quite Firefox
|
||
|
* first so our changes don't get overwritten.
|
||
|
*/
|
||
|
function closeFirefox() {
|
||
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
||
|
if (isFirefoxOpen()) {
|
||
|
yield user_interface_1.default.closeFirefoxBeforeContinuing();
|
||
|
while (isFirefoxOpen()) {
|
||
|
yield sleep(50);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
exports.closeFirefox = closeFirefox;
|
||
|
/**
|
||
|
* Check if Firefox is currently open
|
||
|
*/
|
||
|
function isFirefoxOpen() {
|
||
|
// NOTE: We use some Windows-unfriendly methods here (ps) because Windows
|
||
|
// never needs to check this, because it doesn't update the NSS DB
|
||
|
// automaticaly.
|
||
|
assert_1.default(constants_1.isMac || constants_1.isLinux, 'checkForOpenFirefox was invoked on a platform other than Mac or Linux');
|
||
|
return child_process_1.execSync('ps aux').indexOf('firefox') > -1;
|
||
|
}
|
||
|
function sleep(ms) {
|
||
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
||
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Firefox manages it's own trust store for SSL certificates, which can be
|
||
|
* managed via the certutil command (supplied by NSS tooling packages). In the
|
||
|
* event that certutil is not already installed, and either can't be installed
|
||
|
* (Windows) or the user doesn't want to install it (skipCertutilInstall:
|
||
|
* true), it means that we can't programmatically tell Firefox to trust our
|
||
|
* root CA certificate.
|
||
|
*
|
||
|
* There is a recourse though. When a Firefox tab is directed to a URL that
|
||
|
* responds with a certificate, it will automatically prompt the user if they
|
||
|
* want to add it to their trusted certificates. So if we can't automatically
|
||
|
* install the certificate via certutil, we instead start a quick web server
|
||
|
* and host our certificate file. Then we open the hosted cert URL in Firefox
|
||
|
* to kick off the GUI flow.
|
||
|
*
|
||
|
* This method does all this, along with providing user prompts in the terminal
|
||
|
* to walk them through this process.
|
||
|
*/
|
||
|
function openCertificateInFirefox(firefoxPath, certPath) {
|
||
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
||
|
debug('Adding devert to Firefox trust stores manually. Launching a webserver to host our certificate temporarily ...');
|
||
|
let port = yield get_port_1.default();
|
||
|
let server = http_1.default.createServer((req, res) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
||
|
let { pathname } = url_1.default.parse(req.url);
|
||
|
if (pathname === '/certificate') {
|
||
|
res.writeHead(200, { 'Content-type': 'application/x-x509-ca-cert' });
|
||
|
res.write(fs_1.readFileSync(certPath));
|
||
|
res.end();
|
||
|
}
|
||
|
else {
|
||
|
res.writeHead(200);
|
||
|
res.write(yield user_interface_1.default.firefoxWizardPromptPage(`http://localhost:${port}/certificate`));
|
||
|
res.end();
|
||
|
}
|
||
|
})).listen(port);
|
||
|
debug('Certificate server is up. Printing instructions for user and launching Firefox with hosted certificate URL');
|
||
|
yield user_interface_1.default.startFirefoxWizard(`http://localhost:${port}`);
|
||
|
utils_1.run(firefoxPath, [`http://localhost:${port}`]);
|
||
|
yield user_interface_1.default.waitForFirefoxWizard();
|
||
|
server.close();
|
||
|
});
|
||
|
}
|
||
|
exports.openCertificateInFirefox = openCertificateInFirefox;
|
||
|
function assertNotTouchingFiles(filepath, operation) {
|
||
|
if (!filepath.startsWith(constants_1.configDir) && !filepath.startsWith(constants_1.getLegacyConfigDir())) {
|
||
|
throw new Error(`Devcert cannot ${operation} ${filepath}; it is outside known devcert config directories!`);
|
||
|
}
|
||
|
}
|
||
|
exports.assertNotTouchingFiles = assertNotTouchingFiles;
|
||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkLmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJwbGF0Zm9ybXMvc2hhcmVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSx3REFBd0I7QUFDeEIsc0RBQXNCO0FBQ3RCLDBEQUFnQztBQUNoQyw0REFBNEI7QUFDNUIsZ0VBQStCO0FBQy9CLHdEQUF3QjtBQUN4QiwrQkFBb0M7QUFDcEMsMkJBQW9FO0FBQ3BFLG9DQUErQjtBQUMvQiw0Q0FBOEU7QUFDOUUsK0VBQW1DO0FBQ25DLGlEQUFpRDtBQUVqRCxNQUFNLEtBQUssR0FBRyxlQUFXLENBQUMsMEJBQTBCLENBQUMsQ0FBQztBQUV0RDs7O0dBR0c7QUFDSCxTQUFTLGNBQWMsQ0FBQyxVQUFrQixFQUFFLFFBQTZEO0lBQ3ZHLFdBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxpQkFBaUIsRUFBRSxFQUFFO1FBQzdDLEtBQUssQ0FBQyxzQkFBdUIsaUJBQWtCLG9DQUFvQyxDQUFDLENBQUM7UUFDckYsSUFBSSxlQUFNLENBQUMsY0FBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxVQUFVLENBQUMsQ0FBQyxFQUFFO1lBQ3BELEtBQUssQ0FBQyxnQ0FBaUMsaUJBQWtCLHVCQUF1QixDQUFDLENBQUE7WUFDakYsUUFBUSxDQUFDLGlCQUFpQixFQUFFLFFBQVEsQ0FBQyxDQUFDO1NBQ3ZDO1FBQ0QsSUFBSSxlQUFNLENBQUMsY0FBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxVQUFVLENBQUMsQ0FBQyxFQUFFO1lBQ3BELEtBQUssQ0FBQyxnQ0FBaUMsaUJBQWtCLHVCQUF1QixDQUFDLENBQUE7WUFDakYsUUFBUSxDQUFDLGlCQUFpQixFQUFFLFFBQVEsQ0FBQyxDQUFDO1NBQ3ZDO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBZ0IseUJBQXlCLENBQUMsVUFBa0IsRUFBRSxRQUFnQixFQUFFLFlB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
|