1 | import {
|
2 | readFileSync,
|
3 | readdirSync,
|
4 | writeFileSync,
|
5 | unlinkSync,
|
6 | chmodSync,
|
7 | existsSync
|
8 | } from 'fs';
|
9 | import * as path from 'path';
|
10 | import { exec, execSync, ExecSyncOptions } from 'child_process';
|
11 | import * as tmp from 'tmp';
|
12 | import * as Configstore from 'configstore';
|
13 | import * as mkdirp from 'mkdirp';
|
14 | import * as createDebug from 'debug';
|
15 | import { sync as commandExists } from 'command-exists';
|
16 |
|
17 | import {
|
18 | isMac,
|
19 | isLinux,
|
20 | isWindows,
|
21 | configDir,
|
22 | configPath,
|
23 | opensslConfTemplate,
|
24 | opensslConfPath,
|
25 | rootKeyPath,
|
26 | rootCertPath,
|
27 | caCertsDir
|
28 | } from './constants';
|
29 | import installCertificateAuthority from './root-authority';
|
30 | import { openssl, generateKey } from './utils';
|
31 |
|
32 | const debug = createDebug('devcert');
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | export default async function devcert(appName: string, options: { installCertutil?: boolean } = {}) {
|
46 | debug(`development cert requested for ${ appName }`);
|
47 |
|
48 | if (!isMac && !isLinux && !isWindows) {
|
49 | throw new Error(`devcert: "${ process.platform }" platform not supported`);
|
50 | }
|
51 |
|
52 | if (!commandExists('openssl')) {
|
53 | throw new Error('Unable to find openssl - make sure it is installed and available in your PATH');
|
54 | }
|
55 |
|
56 | let appKeyPath = configPath(`${ appName }.key`);
|
57 | let appCertPath = configPath(`${ appName }.crt`);
|
58 |
|
59 | if (!existsSync(rootCertPath)) {
|
60 | debug('devcert root CA not installed yet, must be first run; installing root CA ...');
|
61 | await installCertificateAuthority(options.installCertutil);
|
62 | }
|
63 |
|
64 | if (!existsSync(configPath(`${ appName }.crt`))) {
|
65 | debug(`first request for ${ appName } cert, generating and caching ...`);
|
66 | generateKey(configPath(`${ appName }.key`));
|
67 | generateSignedCertificate(appName, appKeyPath);
|
68 | }
|
69 |
|
70 | debug(`returning app cert`);
|
71 | return {
|
72 | keyPath: appKeyPath,
|
73 | certPath: appCertPath,
|
74 | key: readFileSync(appKeyPath),
|
75 | cert: readFileSync(appCertPath)
|
76 | };
|
77 |
|
78 | }
|
79 |
|
80 |
|
81 | function generateSignedCertificate(name: string, keyPath: string): void {
|
82 | debug(`generating certificate signing request for ${ name }`);
|
83 | let csrFile = configPath(`${ name }.csr`)
|
84 | openssl(`req -config ${ opensslConfPath } -subj "/CN=${ name }" -key ${ keyPath } -out ${ csrFile } -new`);
|
85 | debug(`generating certificate for ${ name } from signing request; signing with devcert root CA`);
|
86 | let certPath = configPath(`${ name }.crt`);
|
87 | openssl(`ca -config ${ opensslConfPath } -in ${ csrFile } -out ${ certPath } -outdir ${ caCertsDir } -keyfile ${ rootKeyPath } -cert ${ rootCertPath } -notext -md sha256 -days 7000 -batch -extensions server_cert`)
|
88 | }
|