UNPKG

2.87 kBJavaScriptView Raw
1// @flow
2import type {FileSystem} from '@parcel/fs';
3import forge from 'node-forge';
4import path from 'path';
5import logger from '@parcel/logger';
6
7export default async function generateCertificate(
8 fs: FileSystem,
9 cacheDir: string,
10 host: ?string,
11) {
12 let certDirectory = cacheDir;
13
14 const privateKeyPath = path.join(certDirectory, 'private.pem');
15 const certPath = path.join(certDirectory, 'primary.crt');
16 const cachedKey =
17 (await fs.exists(privateKeyPath)) && (await fs.readFile(privateKeyPath));
18 const cachedCert =
19 (await fs.exists(certPath)) && (await fs.readFile(certPath));
20
21 if (cachedKey && cachedCert) {
22 return {
23 key: cachedKey,
24 cert: cachedCert,
25 };
26 }
27
28 logger.progress('Generating SSL Certificate...');
29
30 const pki = forge.pki;
31 const keys = pki.rsa.generateKeyPair(2048);
32 const cert = pki.createCertificate();
33
34 cert.publicKey = keys.publicKey;
35 cert.serialNumber = Date.now().toString();
36 cert.validity.notBefore = new Date();
37 cert.validity.notAfter = new Date();
38 cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
39
40 const attrs = [
41 {
42 name: 'commonName',
43 value: 'parceljs.org',
44 },
45 {
46 name: 'countryName',
47 value: 'US',
48 },
49 {
50 shortName: 'ST',
51 value: 'Virginia',
52 },
53 {
54 name: 'localityName',
55 value: 'Blacksburg',
56 },
57 {
58 name: 'organizationName',
59 value: 'parcelBundler',
60 },
61 {
62 shortName: 'OU',
63 value: 'Test',
64 },
65 ];
66
67 let altNames = [
68 {
69 type: 2, // DNS
70 value: 'localhost',
71 },
72 {
73 type: 7, // IP
74 ip: '127.0.0.1',
75 },
76 ];
77
78 if (host) {
79 altNames.push({
80 type: 2, // DNS
81 value: host,
82 });
83 }
84
85 cert.setSubject(attrs);
86 cert.setIssuer(attrs);
87 cert.setExtensions([
88 {
89 name: 'basicConstraints',
90 cA: false,
91 },
92 {
93 name: 'keyUsage',
94 keyCertSign: true,
95 digitalSignature: true,
96 nonRepudiation: true,
97 keyEncipherment: true,
98 dataEncipherment: true,
99 },
100 {
101 name: 'extKeyUsage',
102 serverAuth: true,
103 clientAuth: true,
104 codeSigning: true,
105 emailProtection: true,
106 timeStamping: true,
107 },
108 {
109 name: 'nsCertType',
110 client: true,
111 server: true,
112 email: true,
113 objsign: true,
114 sslCA: true,
115 emailCA: true,
116 objCA: true,
117 },
118 {
119 name: 'subjectAltName',
120 altNames,
121 },
122 {
123 name: 'subjectKeyIdentifier',
124 },
125 ]);
126
127 cert.sign(keys.privateKey, forge.md.sha256.create());
128
129 const privPem = pki.privateKeyToPem(keys.privateKey);
130 const certPem = pki.certificateToPem(cert);
131
132 await fs.mkdirp(certDirectory);
133 await fs.writeFile(privateKeyPath, privPem);
134 await fs.writeFile(certPath, certPem);
135
136 return {
137 key: privPem,
138 cert: certPem,
139 };
140}