Skip to content

Commit d75238b

Browse files
committed
convert CA creation to async
1 parent 9ac7963 commit d75238b

File tree

4 files changed

+86
-53
lines changed

4 files changed

+86
-53
lines changed

lib/ca.js

Lines changed: 79 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
'use strict';
2+
13
var FS = require('fs');
4+
var path = require('path');
25
var Forge = require('node-forge');
36
var pki = Forge.pki;
7+
var mkdirp = require('mkdirp');
8+
var async = require('async');
49

510
var CAattrs = [{
611
name: 'commonName',
@@ -99,25 +104,33 @@ var ServerExtensions = [{
99104
name: 'subjectKeyIdentifier'
100105
}];
101106

102-
var CA = function (caFolder) {
103-
this.baseCAFolder = caFolder;
104-
this.certsFolder = this.baseCAFolder + '/certs';
105-
this.keysFolder = this.baseCAFolder + '/keys';
106-
try {
107-
FS.mkdirSync(this.baseCAFolder);
108-
} catch (e) { /* no op */ }
109-
try {
110-
FS.mkdirSync(this.certsFolder);
111-
} catch (e) { /* no op */ }
112-
try {
113-
FS.mkdirSync(this.keysFolder);
114-
} catch (e) { /* no op */ }
115-
try {
116-
var stats = FS.statSync(this.certsFolder + '/ca.pem');
117-
this.loadCA();
118-
} catch (e) {
119-
this.generateCA();
120-
}
107+
var CA = function () {
108+
};
109+
110+
CA.create = function (caFolder, callback) {
111+
var ca = new CA();
112+
ca.baseCAFolder = caFolder;
113+
ca.certsFolder = path.join(ca.baseCAFolder, 'certs');
114+
ca.keysFolder = path.join(ca.baseCAFolder, 'keys');
115+
async.series([
116+
mkdirp.bind(null, ca.baseCAFolder),
117+
mkdirp.bind(null, ca.certsFolder),
118+
mkdirp.bind(null, ca.keysFolder),
119+
function (callback) {
120+
FS.exists(path.join(ca.certsFolder, 'ca.pem'), function (exists) {
121+
if (exists) {
122+
ca.loadCA(callback);
123+
} else {
124+
ca.generateCA(callback);
125+
}
126+
});
127+
}
128+
], function (err) {
129+
if (err) {
130+
return callback(err);
131+
}
132+
return callback(null, ca);
133+
});
121134
};
122135

123136
CA.prototype.randomSerialNumber = function () {
@@ -129,34 +142,55 @@ CA.prototype.randomSerialNumber = function () {
129142
return sn;
130143
}
131144

132-
CA.prototype.generateCA = function () {
133-
var keys = pki.rsa.generateKeyPair(2048);
134-
var cert = pki.createCertificate();
135-
cert.publicKey = keys.publicKey;
136-
cert.serialNumber = this.randomSerialNumber();
137-
cert.validity.notBefore = new Date();
138-
cert.validity.notAfter = new Date();
139-
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10);
140-
cert.setSubject(CAattrs);
141-
cert.setIssuer(CAattrs);
142-
cert.setExtensions(CAextensions);
143-
cert.sign(keys.privateKey, Forge.md.sha256.create());
144-
this.CAcert = cert;
145-
this.CAkeys = keys;
146-
FS.writeFileSync(this.certsFolder + '/ca.pem', pki.certificateToPem(cert));
147-
FS.writeFileSync(this.keysFolder + '/ca.private.key', pki.privateKeyToPem(keys.privateKey));
148-
FS.writeFileSync(this.keysFolder + '/ca.public.key', pki.publicKeyToPem(keys.publicKey));
145+
CA.prototype.generateCA = function (callback) {
146+
var self = this;
147+
pki.rsa.generateKeyPair({bits: 2048}, function(err, keys) {
148+
if (err) {
149+
return callback(err);
150+
}
151+
var cert = pki.createCertificate();
152+
cert.publicKey = keys.publicKey;
153+
cert.serialNumber = self.randomSerialNumber();
154+
cert.validity.notBefore = new Date();
155+
cert.validity.notAfter = new Date();
156+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10);
157+
cert.setSubject(CAattrs);
158+
cert.setIssuer(CAattrs);
159+
cert.setExtensions(CAextensions);
160+
cert.sign(keys.privateKey, Forge.md.sha256.create());
161+
self.CAcert = cert;
162+
self.CAkeys = keys;
163+
async.parallel([
164+
FS.writeFile.bind(null, path.join(self.certsFolder, 'ca.pem'), pki.certificateToPem(cert)),
165+
FS.writeFile.bind(null, path.join(self.keysFolder, 'ca.private.key'), pki.privateKeyToPem(keys.privateKey)),
166+
FS.writeFile.bind(null, path.join(self.keysFolder, 'ca.public.key'), pki.publicKeyToPem(keys.publicKey))
167+
], callback);
168+
});
149169
};
150170

151-
CA.prototype.loadCA = function () {
152-
var certPEM = FS.readFileSync(this.certsFolder + '/ca.pem');
153-
var keyPrivatePEM = FS.readFileSync(this.keysFolder + '/ca.private.key');
154-
var keyPublicPEM = FS.readFileSync(this.keysFolder + '/ca.public.key');
155-
this.CAcert = pki.certificateFromPem(certPEM);
156-
this.CAkeys = {
157-
privateKey: pki.privateKeyFromPem(keyPrivatePEM),
158-
publicKey: pki.publicKeyFromPem(keyPublicPEM)
159-
};
171+
CA.prototype.loadCA = function (callback) {
172+
var self = this;
173+
async.auto({
174+
certPEM: function (callback) {
175+
FS.readFile(path.join(self.certsFolder, 'ca.pem'), 'utf-8', callback);
176+
},
177+
keyPrivatePEM: function (callback) {
178+
FS.readFile(path.join(self.keysFolder, 'ca.private.key'), 'utf-8', callback);
179+
},
180+
keyPublicPEM: function (callback) {
181+
FS.readFile(path.join(self.keysFolder, 'ca.public.key'), 'utf-8', callback);
182+
}
183+
}, function (err, results) {
184+
if (err) {
185+
return callback(err);
186+
}
187+
self.CAcert = pki.certificateFromPem(results.certPEM);
188+
self.CAkeys = {
189+
privateKey: pki.privateKeyFromPem(results.keyPrivatePEM),
190+
publicKey: pki.publicKeyFromPem(results.keyPublicPEM)
191+
};
192+
return callback();
193+
});
160194
};
161195

162196
CA.prototype.generateServerCertificateKeys = function (hosts, cb) {

lib/proxy.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ var util = require('util');
88
var fs = require('fs');
99
var path = require('path');
1010
var events = require('events');
11-
var mkdirps = require('mkdirps');
1211
var WebSocket = require('ws');
1312
var url = require('url');
1413
var os = require('os');
@@ -57,13 +56,13 @@ Proxy.prototype.listen = function(options, callback) {
5756
this.useNamedSocket = !!options.useNamedSocket;
5857
this.httpsPort = this.forceSNI ? options.httpsPort : undefined;
5958
this.sslCaDir = options.sslCaDir || path.resolve(process.cwd(), '.http-mitm-proxy');
60-
this.ca = new ca(this.sslCaDir);
61-
this.sslServers = {};
62-
this.sslSemaphores = {};
63-
mkdirps(this.sslCaDir, function(err) {
59+
ca.create(this.sslCaDir, function(err, ca) {
6460
if (err) {
65-
self._onError('CERT_DIRECTORY_CREATION', null, err);
61+
return callback(err);
6662
}
63+
self.ca = ca;
64+
self.sslServers = {};
65+
self.sslSemaphores = {};
6766
self.httpServer = http.createServer();
6867
self.httpServer.timeout = self.timeout;
6968
self.httpServer.on('error', self._onError.bind(self, 'HTTP_SERVER_ERROR', null));

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
},
3434
"dependencies": {
3535
"async": "^1.5.2",
36-
"mkdirps": "0.0.0",
36+
"mkdirp": "^0.5.1",
3737
"node-forge": "^0.6.38",
3838
"optimist": "^0.6.1",
3939
"semaphore": "^1.0.5",

test/01_proxy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var countString = function (str, substr, cb) {
4545
};
4646

4747
describe('proxy', function () {
48-
this.timeout(5000);
48+
this.timeout(30000);
4949
var srvA = null;
5050
var srvB = null;
5151
var proxy = null;

0 commit comments

Comments
 (0)