Skip to content

Commit b0cb0d3

Browse files
authored
refactor: Replace remaining trivial dependencies (#5)
1 parent aa7875d commit b0cb0d3

14 files changed

+134
-205
lines changed

openssl-configurations/domain-certificate-signing-requests.conf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ distinguished_name = req_distinguished_name
1313
req_extensions = req_extensions
1414

1515
[ req_distinguished_name ]
16-
CN = <%= domain %>
16+
CN = %DOMAIN%
1717

1818
[ req_extensions ]
1919
basicConstraints = CA:FALSE
2020
subjectAltName = @subject_alt_names
2121
subjectKeyIdentifier = hash
2222

2323
[ subject_alt_names ]
24-
DNS.1 = <%= domain %>
25-
DNS.2 = *.<%= domain %>
24+
DNS.1 = %DOMAIN%
25+
DNS.2 = *.%DOMAIN%

openssl-configurations/domain-certificates.conf

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ default_ca = devcert_ca
33

44
[ devcert_ca ]
55
# Serial file that counts up unique IDs for each cert issued
6-
serial = <%= serialFile.replace(/\\/g, '\\\\') %>
6+
serial = %SERIALFILE%
77
# Database file that tracks all issued certs
8-
database = <%= databaseFile.replace(/\\/g, '\\\\') %>
8+
database = %DATABASEFILE%
99
# Where to put the new cert
10-
new_certs_dir = <%= domainDir.replace(/\\/g, '\\\\') %>
10+
new_certs_dir = %DOMAINDIR%
1111
# Which algorithm to use
1212
default_md = sha256
1313
# Don't prompt the TTY for input, just use the config file values
@@ -35,5 +35,5 @@ extendedKeyUsage = serverAuth
3535
subjectAltName = @subject_alt_names
3636

3737
[ subject_alt_names ]
38-
DNS.1 = <%= domain %>
39-
DNS.2 = *.<%= domain %>
38+
DNS.1 = %DOMAIN%
39+
DNS.2 = *.%DOMAIN%

package.json

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,13 @@
2828
"homepage": "https://github.com/expo/devcert#readme",
2929
"devDependencies": {
3030
"@types/debug": "^0.0.30",
31-
"@types/get-port": "^3.2.0",
32-
"@types/lodash": "^4.14.92",
33-
"@types/mkdirp": "^0.5.2",
3431
"@types/node": "^20.12.7",
35-
"@types/tmp": "^0.0.33",
3632
"standard-version": "^8.0.1",
3733
"typescript": "^5.1.3"
3834
},
3935
"dependencies": {
4036
"@expo/sudo-prompt": "^9.3.1",
41-
"application-config-path": "^0.1.0",
42-
"command-exists": "^1.2.4",
4337
"debug": "^3.1.0",
44-
"eol": "^0.9.1",
45-
"get-port": "^3.2.0",
46-
"glob": "^10.4.2",
47-
"lodash": "^4.17.21",
48-
"mkdirp": "^0.5.1",
49-
"password-prompt": "^1.0.4",
50-
"tmp": "^0.0.33",
51-
"tslib": "^2.4.0"
38+
"glob": "^10.4.2"
5239
}
5340
}

src/certificates.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// import path from 'path';
22
import createDebug from 'debug';
3-
import { sync as mkdirp } from 'mkdirp';
4-
import { chmodSync as chmod } from 'fs';
3+
import fs from 'fs';
54
import { pathForDomain, withDomainSigningRequestConfig, withDomainCertificateConfig } from './constants';
65
import { openssl } from './utils';
76
import { withCertificateAuthorityCredentials } from './certificate-authority';
@@ -16,7 +15,7 @@ const debug = createDebug('devcert:certificates');
1615
* added to the OS/browser trust stores), they are trusted.
1716
*/
1817
export default async function generateDomainCertificate(domain: string): Promise<void> {
19-
mkdirp(pathForDomain(domain));
18+
await fs.promises.mkdir(pathForDomain(domain), { recursive: true });
2019

2120
debug(`Generating private key for ${ domain }`);
2221
let domainKeyPath = pathForDomain(domain, 'private-key.key');
@@ -42,5 +41,5 @@ export default async function generateDomainCertificate(domain: string): Promise
4241
export function generateKey(filename: string): void {
4342
debug(`generateKey: ${ filename }`);
4443
openssl(['genrsa', '-out', filename, '2048']);
45-
chmod(filename, 400);
46-
}
44+
fs.chmodSync(filename, 400);
45+
}

src/constants.ts

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
import path from 'path';
2-
import { unlinkSync as rm, writeFileSync as writeFile, readFileSync as readFile } from 'fs';
3-
import { sync as mkdirp } from 'mkdirp';
4-
import { template as makeTemplate } from 'lodash';
5-
import applicationConfigPath = require('application-config-path');
6-
import eol from 'eol';
2+
import fs from 'fs';
73
import { mktmp } from './utils';
84

5+
function applicationConfigPath(name: string): string {
6+
switch (process.platform) {
7+
case 'darwin':
8+
return path.join(process.env.HOME, 'Library', 'Application Support', name);
9+
case 'win32':
10+
return process.env.LOCALAPPDATA
11+
? path.join(process.env.LOCALAPPDATA, name)
12+
: path.join(process.env.USERPROFILE, 'Local Settings', 'Application Data', name);
13+
case 'linux':
14+
default:
15+
return process.env.XDG_CONFIG_HOME
16+
? path.join(process.env.XDG_CONFIG_HOME, name)
17+
: path.join(process.env.HOME, '.config', name);
18+
}
19+
}
20+
921
export const VALID_IP = /(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}/;
1022
export const VALID_DOMAIN = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.?)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/i;
1123

@@ -26,34 +38,35 @@ export const opensslSerialFilePath = configPath('certificate-authority', 'serial
2638
export const opensslDatabaseFilePath = configPath('certificate-authority', 'index.txt');
2739
export const caSelfSignConfig = path.join(__dirname, '../openssl-configurations/certificate-authority-self-signing.conf');
2840

41+
function eolAuto(str: string): string {
42+
return str.replace(/\r?\n|\r/g, isWindows ? '\r\n' : '\n');
43+
}
44+
2945
export function withDomainSigningRequestConfig(domain: string, cb: (filepath: string) => void) {
3046
let tmpFile = mktmp();
31-
let source = readFile(path.join(__dirname, '../openssl-configurations/domain-certificate-signing-requests.conf'), 'utf-8');
32-
let template = makeTemplate(source);
33-
let result = template({ domain });
34-
writeFile(tmpFile, eol.auto(result));
47+
let source = fs.readFileSync(path.join(__dirname, '../openssl-configurations/domain-certificate-signing-requests.conf'), 'utf-8');
48+
let result = source.replace(/%DOMAIN%/g, domain);
49+
fs.writeFileSync(tmpFile, eolAuto(result));
3550
cb(tmpFile);
36-
rm(tmpFile);
51+
fs.rmSync(tmpFile);
3752
}
3853

3954
export function withDomainCertificateConfig(domain: string, cb: (filepath: string) => void) {
4055
let tmpFile = mktmp();
41-
let source = readFile(path.join(__dirname, '../openssl-configurations/domain-certificates.conf'), 'utf-8');
42-
let template = makeTemplate(source);
43-
let result = template({
44-
domain,
45-
serialFile: opensslSerialFilePath,
46-
databaseFile: opensslDatabaseFilePath,
47-
domainDir: pathForDomain(domain)
48-
});
49-
writeFile(tmpFile, eol.auto(result));
56+
let source = fs.readFileSync(path.join(__dirname, '../openssl-configurations/domain-certificates.conf'), 'utf-8');
57+
let result = source
58+
.replace(/%DOMAIN%/g, domain)
59+
.replace(/%SERIALFILE%/g, opensslSerialFilePath.replace(/\\/g, '\\\\'))
60+
.replace(/%DATABASEFILE%/g, opensslDatabaseFilePath.replace(/\\/g, '\\\\'))
61+
.replace(/%DOMAINDIR%/g, pathForDomain(domain).replace(/\\/g, '\\\\'))
62+
fs.writeFileSync(tmpFile, eolAuto(result));
5063
cb(tmpFile);
51-
rm(tmpFile);
64+
fs.rmSync(tmpFile);
5265
}
5366

5467
// confTemplate = confTemplate.replace(/DATABASE_PATH/, configPath('index.txt').replace(/\\/g, '\\\\'));
5568
// confTemplate = confTemplate.replace(/SERIAL_PATH/, configPath('serial').replace(/\\/g, '\\\\'));
56-
// confTemplate = eol.auto(confTemplate);
69+
// confTemplate = eolAuto(confTemplate);
5770

5871
export const rootCADir = configPath('certificate-authority');
5972
export const rootCAKeyPath = configPath('certificate-authority', 'private-key.key');
@@ -73,9 +86,9 @@ export function getLegacyConfigDir(): string {
7386
}
7487

7588
export function ensureConfigDirs() {
76-
mkdirp(configDir);
77-
mkdirp(domainsDir);
78-
mkdirp(rootCADir);
89+
fs.mkdirSync(configDir, { recursive: true });
90+
fs.mkdirSync(domainsDir, { recursive: true });
91+
fs.mkdirSync(rootCADir, { recursive: true });
7992
}
8093

8194
ensureConfigDirs();

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { rmSync as rm, readFileSync as readFile, readdirSync as readdir, existsSync as exists } from 'fs';
22
import createDebug from 'debug';
3-
import { sync as commandExists } from 'command-exists';
43
import {
54
isMac,
65
isLinux,
@@ -13,6 +12,7 @@ import {
1312
VALID_IP
1413
} from './constants';
1514
import currentPlatform from './platforms';
15+
import { commandExists } from './utils';
1616
import installCertificateAuthority, { ensureCACertReadable, uninstall } from './certificate-authority';
1717
import generateDomainCertificate from './certificates';
1818
import UI, { UserInterface } from './user-interface';

src/platforms/darwin.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import path from 'path';
22
import { writeFileSync as writeFile, existsSync as exists, readFileSync as read } from 'fs';
33
import createDebug from 'debug';
4-
import { sync as commandExists } from 'command-exists';
5-
import { run, sudoAppend } from '../utils';
4+
import { run, sudoAppend, commandExists } from '../utils';
65
import { Options } from '../index';
76
import { addCertificateToNSSCertDB, assertNotTouchingFiles, openCertificateInFirefox, closeFirefox, removeCertificateFromNSSCertDB } from './shared';
87
import { Platform } from '.';

src/platforms/linux.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import path from 'path';
22
import { existsSync as exists, readFileSync as read, writeFileSync as writeFile } from 'fs';
33
import createDebug from 'debug';
4-
import { sync as commandExists } from 'command-exists';
54
import { addCertificateToNSSCertDB, assertNotTouchingFiles, openCertificateInFirefox, closeFirefox, removeCertificateFromNSSCertDB } from './shared';
6-
import { run, sudoAppend } from '../utils';
5+
import { run, sudoAppend, commandExists } from '../utils';
76
import { Options } from '../index';
87
import UI from '../user-interface';
98
import { Platform } from '.';
@@ -121,4 +120,4 @@ export default class LinuxPlatform implements Platform {
121120
return exists(this.CHROME_BIN_PATH);
122121
}
123122

124-
}
123+
}

src/platforms/shared.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import path from 'path';
2-
import url from 'url';
32
import createDebug from 'debug';
43
import assert from 'assert';
5-
import getPort from 'get-port';
4+
import net from 'net';
65
import http from 'http';
76
import { sync as glob } from 'glob';
87
import { readFileSync as readFile, existsSync as exists } from 'fs';
@@ -109,28 +108,37 @@ async function sleep(ms: number) {
109108
*/
110109
export async function openCertificateInFirefox(firefoxPath: string, certPath: string): Promise<void> {
111110
debug('Adding devert to Firefox trust stores manually. Launching a webserver to host our certificate temporarily ...');
112-
let port = await getPort();
113-
let server = http.createServer(async (req, res) => {
114-
let { pathname } = url.parse(req.url);
111+
let port: number;
112+
const server = http.createServer(async (req, res) => {
113+
let { pathname } = new URL(req.url);
115114
if (pathname === '/certificate') {
116115
res.writeHead(200, { 'Content-type': 'application/x-x509-ca-cert' });
117116
res.write(readFile(certPath));
118117
res.end();
119118
} else {
120119
res.writeHead(200);
121-
res.write(await UI.firefoxWizardPromptPage(`http://localhost:${ port }/certificate`));
120+
res.write(await UI.firefoxWizardPromptPage(`http://localhost:${port}/certificate`));
122121
res.end();
123122
}
124-
}).listen(port);
125-
debug('Certificate server is up. Printing instructions for user and launching Firefox with hosted certificate URL');
126-
await UI.startFirefoxWizard(`http://localhost:${ port }`);
127-
run(firefoxPath, [`http://localhost:${ port }`]);
128-
await UI.waitForFirefoxWizard();
129-
server.close();
123+
});
124+
port = await new Promise((resolve, reject) => {
125+
server.on('error', reject);
126+
server.listen(() => {
127+
resolve((server.address() as net.AddressInfo).port);
128+
});
129+
});
130+
try {
131+
debug('Certificate server is up. Printing instructions for user and launching Firefox with hosted certificate URL');
132+
await UI.startFirefoxWizard(`http://localhost:${port}`);
133+
run(firefoxPath, [`http://localhost:${ port }`]);
134+
await UI.waitForFirefoxWizard();
135+
} finally {
136+
server.close();
137+
}
130138
}
131139

132140
export function assertNotTouchingFiles(filepath: string, operation: string): void {
133141
if (!filepath.startsWith(configDir) && !filepath.startsWith(getLegacyConfigDir())) {
134142
throw new Error(`Devcert cannot ${ operation } ${ filepath }; it is outside known devcert config directories!`);
135143
}
136-
}
144+
}

src/types.d.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)