Skip to content

Commit

Permalink
Merge pull request #7 from RandomByte/update-dependencies
Browse files Browse the repository at this point in the history
Update dependencies, apply fixes from "upstream"
  • Loading branch information
guybedford committed Jul 30, 2024
2 parents 89e2c55 + 46e5f4e commit 02964cd
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 49 deletions.
1 change: 0 additions & 1 deletion index.js

This file was deleted.

29 changes: 20 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
{
"name": "devcert-sanscache",
"version": "0.4.7",
"version": "0.4.8",
"description": "Generate trusted local SSL/TLS certificates for local SSL development",
"main": "index.js",
"type": "module",
"exports": {
"./package.json": "./package.json",
".": {
"import": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
}
}
},
"scripts": {
"prepublish": "tsc"
},
"repository": {
"type": "git",
"url": "git+https://github.com/guybedford/devcert.git"
},
"engines": {
"node": "^14.13.1 || >=16.0.0"
},
"author": "Dave Wasmer",
"license": "MIT",
"devDependencies": {
"@types/node": "^8.0.50",
"typescript": "^2.6.1"
"@types/node": "20.11.0",
"typescript": "^5.5.4"
},
"dependencies": {
"command-exists": "^1.2.2",
"get-port": "^3.0.0",
"glob": "^7.1.1",
"mkdirp": "^0.5.1",
"rimraf": "^2.6.2"
"command-exists": "^1.2.9",
"get-port": "^6.1.2",
"glob": "^10.4.5",
"rimraf": "^5.0.9"
}
}
8 changes: 4 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import commandExists = require('command-exists');
import installAuthority from './install-authority';
import { generateOpensslConf, generateRootCertificate, generateSignedCertificate, tmpClear } from './openssl';
import fs = require('fs');
import commandExists from 'command-exists';
import installAuthority from './install-authority.js';
import { generateOpensslConf, generateRootCertificate, generateSignedCertificate, tmpClear } from './openssl.js';
import fs from 'node:fs';

export default async function generateDevCert (commonName: string) {
if (!commandExists.sync('openssl'))
Expand Down
52 changes: 31 additions & 21 deletions src/install-authority.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { readFileSync, existsSync } from 'fs';
import { exec, execSync } from 'child_process';
import http = require('http');
import path = require('path');
import getPort = require('get-port');
import commandExists = require('command-exists');
import glob = require('glob');
import { execFile, execFileSync } from 'child_process';
import http from 'node:http';
import path from 'node:path';
import getPort from 'get-port';
import commandExists from 'command-exists';
import {glob} from 'glob';

export function waitForUser () {
return new Promise((resolve) => {
return new Promise<void>((resolve) => {
function waitHandler () {
resolve();
process.stdin.removeListener('data', waitHandler);
Expand Down Expand Up @@ -38,7 +38,7 @@ export default function installCertificateAuthority (commonName: string, rootCer
// `nss` Homebrew package, otherwise we go manual with user-facing prompts.
async function addToMacTrustStores (commonName: string, rootCertPath: string): Promise<void> {
// Chrome, Safari, system utils
execSync(`sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain -p ssl -p basic "${rootCertPath}"`);
execFileSync('sudo', ['security', 'add-trusted-cert', '-d', '-r', 'trustRoot', '-k', '/Library/Keychains/System.keychain', '-p', 'ssl', '-p', 'basic', rootCertPath]);
// Firefox
try {
// Try to use certutil to install the cert automatically
Expand All @@ -57,9 +57,9 @@ async function addToMacTrustStores (commonName: string, rootCertPath: string): P
// opening certs, if we can't use certutil, we're out of luck.
async function addToLinuxTrustStores (commonName: string, rootCertPath: string): Promise<void> {
// system utils
execSync(`sudo cp ${rootCertPath} /etc/ssl/certs/${commonName}.pem}`);
execSync(`sudo cp ${rootCertPath} /usr/local/share/ca-certificates/${commonName}.crt`);
execSync(`sudo update-ca-certificates`);
execFileSync('sudo', ['cp', rootCertPath, `/etc/ssl/certs/${commonName}.pem}`]);
execFileSync('sudo', ['cp', rootCertPath, `/usr/local/share/ca-certificates/${commonName}.crt`]);
execFileSync('sudo', ['update-ca-certificates']);
// Firefox
try {
// Try to use certutil to install the cert automatically
Expand All @@ -81,7 +81,7 @@ async function addToLinuxTrustStores (commonName: string, rootCertPath: string):
async function addToWindowsTrustStores (rootCertPath: string): Promise<void> {
// IE, Chrome, system utils
try {
execSync(`certutil -addstore -user root ${rootCertPath}`);
execFileSync('certutil', ['-addstore', '-user', 'root', rootCertPath]);
}
catch (e) {}
// Firefox (don't even try NSS certutil, no easy install for Windows)
Expand All @@ -98,7 +98,7 @@ async function addCertificateToNSSCertDB (commonName: string, rootCertPath: stri
// 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.
if (checkForOpenFirefox) {
let runningProcesses = execSync('ps aux');
let runningProcesses = execFileSync('ps', ['aux']);
if (runningProcesses.indexOf('firefox') > -1) {
console.log('Please close Firefox\nPress <Enter> when ready');
await waitForUser();
Expand All @@ -107,9 +107,9 @@ async function addCertificateToNSSCertDB (commonName: string, rootCertPath: stri

glob.sync(nssDirGlob).forEach(potentialNSSDBDir => {
if (existsSync(path.join(potentialNSSDBDir, 'cert8.db')))
execSync(`${certutilPath} -A -d "${potentialNSSDBDir}" -t 'C,,' -i ${rootCertPath} -n ${commonName}`);
execFileSync(certutilPath, ['-A', '-d', potentialNSSDBDir, '-t', `C,,`, '-i', rootCertPath, '-n', commonName]);
else if (existsSync(path.join(potentialNSSDBDir, 'cert9.db')))
execSync(`${certutilPath} -A -d "sql:${potentialNSSDBDir}" -t 'C,,' -i ${rootCertPath} -n ${commonName}`);
execFileSync(certutilPath, ['-A', '-d', `sql:${potentialNSSDBDir}`, '-t', `C,,`, '-i', rootCertPath, '-n', commonName]);
});
}

Expand All @@ -127,7 +127,7 @@ async function openCertificateInFirefox(rootCertPath: string, firefoxPath: strin
}).listen(port);
console.log(`If using Firefox, a Firefox window will be opened for authorization.\nTick the "Trust this CA to identify websites" option and then confirm.\nPress <Enter> to continue.`);
await waitForUser();
exec(`${firefoxPath} http:https://localhost:${port}`);
execFile(firefoxPath, [`http:https://localhost:${port}`]);
console.log(`Press <Enter> once confirmed (or to skip)`);
await waitForUser();
}
Expand All @@ -137,18 +137,28 @@ function lookupOrInstallCertutil (): string | void {
if (process.platform === 'darwin') {
if (commandExists.sync('brew')) {
let certutilPath: string;
if (!isNSSInstalled()) {
execFileSync('brew', ['install', 'nss']);
}
try {
certutilPath = path.join(execSync('brew --prefix nss').toString().trim(), 'bin', 'certutil');
certutilPath = path.join(execFileSync('brew', ['--prefix', 'nss']).toString().trim(), 'bin', 'certutil');
} catch (e) {
execSync('brew install nss');
certutilPath = path.join(execSync('brew --prefix nss').toString().trim(), 'bin', 'certutil');
certutilPath = path.join(execFileSync('brew', ['--prefix', 'nss']).toString().trim(), 'bin', 'certutil');
}
return certutilPath;
}
}
else if (process.platform === 'linux') {
if (!commandExists.sync('certutil'))
execSync('sudo apt install libnss3-tools');
return execSync('which certutil').toString().trim();
execFileSync('sudo', ['apt', 'install', 'libnss3-tools']);
return execFileSync('which', ['certutil']).toString().trim();
}
}

function isNSSInstalled(): boolean {
try {
return execFileSync('brew', ['list', '-1']).toString().includes('\nnss\n');
} catch (e) {
return false;
}
}
26 changes: 13 additions & 13 deletions src/openssl.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import childProcess = require('child_process');
import path = require('path');
import os = require('os');
import rimraf = require('rimraf');
import fs = require('fs');
import mkdirp = require('mkdirp');
import childProcess from 'node:child_process';
import path from 'node:path';
import os from 'node:os';
import {rimraf} from 'rimraf';
import fs from 'node:fs';

// simple temp file pathing, requires manual removal
let tmpPrefix, tmpFiles;
Expand Down Expand Up @@ -33,10 +32,10 @@ export function tmpClear () {
}

let rndFile;
function openssl (cmd: string) {
function openssl (args: string[]) {
if (!rndFile)
rndFile = tmpFile('rnd');
childProcess.execSync(`openssl ${ cmd }`, {
childProcess.execFileSync('openssl', args, {
stdio: 'ignore',
env: Object.assign({
RANDFILE: rndFile
Expand Down Expand Up @@ -131,30 +130,31 @@ export function generateOpensslConf (commonName: string) {

export function generateKey (): string {
const keyFile = tmpFile('key');
openssl(`genrsa -out ${keyFile} 2048`);
openssl(['genrsa', '-out', keyFile, '2048']);
fs.chmodSync(keyFile, 400);
return keyFile;
}

export function generateRootCertificate (commonName: string, opensslConfPath: string) {
const rootCertPath = tmpFile(`${commonName}.crt`);
const rootKeyPath = generateKey();
openssl(`req -config ${opensslConfPath} -key ${rootKeyPath} -out ${rootCertPath} -new -subj "/CN=${commonName}" -x509 -days 825 -extensions v3_ca`);
openssl(['req', '-config', opensslConfPath, '-key', rootKeyPath, '-out', rootCertPath, '-new', '-subj', `/CN=${commonName}`, '-x509', '-days', '825', '-extensions', 'v3_ca']);
return { rootKeyPath, rootCertPath };
}

export function generateSignedCertificate (commonName: string, opensslConfPath: string, rootKeyPath: string, caPath: string) {
const keyPath = generateKey();
process.env.SAN = commonName;
const csrFile = tmpFile(`${commonName}.csr`);
openssl(`req -config ${ opensslConfPath } -subj "/CN=${commonName}" -key ${keyPath} -out ${csrFile} -new`);
openssl(['req', '-config', opensslConfPath, '-subj', `/CN=${commonName}`, '-key', keyPath, '-out', csrFile, '-new']);
const certPath = tmpFile(`${commonName}.crt`);

// needed but not used (see https://www.mail-archive.com/[email protected]/msg81098.html)
const caCertsDir = path.join(os.tmpdir(), Math.round(Math.random() * 36 ** 10).toString(36));
mkdirp.sync(caCertsDir);

fs.mkdirSync(caCertsDir, {recursive: true});

openssl(`ca -config ${opensslConfPath} -in ${csrFile} -out ${certPath} -outdir ${caCertsDir} -keyfile ${rootKeyPath} -cert ${caPath} -notext -md sha256 -days 825 -batch -extensions server_cert`)
openssl(['ca', '-config', opensslConfPath, '-in', csrFile, '-out', certPath, '-outdir', caCertsDir, '-keyfile', rootKeyPath, '-cert', caPath, '-notext', '-md', 'sha256', '-days', '825', '-batch', '-extensions', 'server_cert'])

rimraf.sync(caCertsDir);

Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"noUnusedParameters": true,
"noUnusedLocals": true,
"typeRoots": ["node_modules/@types"],
"module": "commonjs",
"module": "node16",
"target": "esnext",
"noImplicitAny": false,
"sourceMap": true,
Expand Down

0 comments on commit 02964cd

Please sign in to comment.