forked from root/acme.js
		
	cleanup and bugfixes
This commit is contained in:
		
							parent
							
								
									24c3633d75
								
							
						
					
					
						commit
						499ac7f8ea
					
				
							
								
								
									
										35
									
								
								lib/acme.js
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								lib/acme.js
									
									
									
									
									
								
							@ -354,7 +354,6 @@ ACME._testChallengeOptions = function() {
 | 
				
			|||||||
	];
 | 
						];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
ACME._testChallenges = function(me, options) {
 | 
					ACME._testChallenges = function(me, options) {
 | 
				
			||||||
	console.log('[debug] testChallenges');
 | 
					 | 
				
			||||||
	var CHECK_DELAY = 0;
 | 
						var CHECK_DELAY = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// memoized so that it doesn't run until it's first called
 | 
						// memoized so that it doesn't run until it's first called
 | 
				
			||||||
@ -461,13 +460,16 @@ ACME._testChallenges = function(me, options) {
 | 
				
			|||||||
		return ACME._wait(CHECK_DELAY).then(function() {
 | 
							return ACME._wait(CHECK_DELAY).then(function() {
 | 
				
			||||||
			return Promise.all(
 | 
								return Promise.all(
 | 
				
			||||||
				auths.map(function(auth) {
 | 
									auths.map(function(auth) {
 | 
				
			||||||
					return ACME.challengeTests[auth.type](me, auth).then(
 | 
										return ACME.challengeTests[auth.type](me, auth)
 | 
				
			||||||
						function(result) {
 | 
											.then(function(result) {
 | 
				
			||||||
							// not a blocker
 | 
												// not a blocker
 | 
				
			||||||
							ACME._removeChallenge(me, options, auth);
 | 
												ACME._removeChallenge(me, options, auth);
 | 
				
			||||||
							return result;
 | 
												return result;
 | 
				
			||||||
						}
 | 
											})
 | 
				
			||||||
					);
 | 
											.catch(function(err) {
 | 
				
			||||||
 | 
												ACME._removeChallenge(me, options, auth);
 | 
				
			||||||
 | 
												throw err;
 | 
				
			||||||
 | 
											});
 | 
				
			||||||
				})
 | 
									})
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
@ -671,14 +673,16 @@ ACME._postChallenge = function(me, options, auth) {
 | 
				
			|||||||
					return ACME._wait(RETRY_INTERVAL).then(respondToChallenge);
 | 
										return ACME._wait(RETRY_INTERVAL).then(respondToChallenge);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if ('valid' === resp.body.status) {
 | 
									// REMOVE DNS records as soon as the state is non-processing
 | 
				
			||||||
					if (me.debug) {
 | 
					 | 
				
			||||||
						console.debug('VALID !!!!!!!!!!!!!!!! poll: valid');
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				try {
 | 
									try {
 | 
				
			||||||
					ACME._removeChallenge(me, options, auth);
 | 
										ACME._removeChallenge(me, options, auth);
 | 
				
			||||||
				} catch (e) {}
 | 
									} catch (e) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if ('valid' === resp.body.status) {
 | 
				
			||||||
 | 
										if (me.debug) {
 | 
				
			||||||
 | 
											console.debug('poll: valid');
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					return resp.body;
 | 
										return resp.body;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1126,7 +1130,6 @@ ACME._getCertificate = function(me, options) {
 | 
				
			|||||||
								challenge,
 | 
													challenge,
 | 
				
			||||||
								false
 | 
													false
 | 
				
			||||||
							).then(function(auth) {
 | 
												).then(function(auth) {
 | 
				
			||||||
								console.log('ADD DUBIOUS AUTH');
 | 
					 | 
				
			||||||
								auths.push(auth);
 | 
													auths.push(auth);
 | 
				
			||||||
								return ACME._setChallenge(
 | 
													return ACME._setChallenge(
 | 
				
			||||||
									me,
 | 
														me,
 | 
				
			||||||
@ -1151,7 +1154,6 @@ ACME._getCertificate = function(me, options) {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				function checkNext() {
 | 
									function checkNext() {
 | 
				
			||||||
					console.log('CONSUME DUBIOUS AUTH', auths.length);
 | 
					 | 
				
			||||||
					var auth = auths.shift();
 | 
										var auth = auths.shift();
 | 
				
			||||||
					if (!auth) {
 | 
										if (!auth) {
 | 
				
			||||||
						return;
 | 
											return;
 | 
				
			||||||
@ -1161,20 +1163,17 @@ ACME._getCertificate = function(me, options) {
 | 
				
			|||||||
						// not so much "valid" as "not invalid"
 | 
											// not so much "valid" as "not invalid"
 | 
				
			||||||
						// but in this case we can't confirm either way
 | 
											// but in this case we can't confirm either way
 | 
				
			||||||
						validAuths.push(auth);
 | 
											validAuths.push(auth);
 | 
				
			||||||
						console.log('ADD VALID AUTH (skip)', validAuths.length);
 | 
					 | 
				
			||||||
						return checkNext();
 | 
											return checkNext();
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					return ACME.challengeTests[auth.type](me, auth)
 | 
										return ACME.challengeTests[auth.type](me, auth)
 | 
				
			||||||
						.then(function() {
 | 
											.then(function() {
 | 
				
			||||||
							console.log('ADD VALID AUTH');
 | 
					 | 
				
			||||||
							validAuths.push(auth);
 | 
												validAuths.push(auth);
 | 
				
			||||||
						})
 | 
											})
 | 
				
			||||||
						.then(checkNext);
 | 
											.then(checkNext);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				function presentNext() {
 | 
									function presentNext() {
 | 
				
			||||||
					console.log('CONSUME VALID AUTH', validAuths.length);
 | 
					 | 
				
			||||||
					var auth = validAuths.shift();
 | 
										var auth = validAuths.shift();
 | 
				
			||||||
					if (!auth) {
 | 
										if (!auth) {
 | 
				
			||||||
						return;
 | 
											return;
 | 
				
			||||||
@ -1535,15 +1534,21 @@ ACME._removeChallenge = function(me, options, auth) {
 | 
				
			|||||||
	var challengers = options.challenges || {};
 | 
						var challengers = options.challenges || {};
 | 
				
			||||||
	var removeChallenge =
 | 
						var removeChallenge =
 | 
				
			||||||
		challengers[auth.type] && challengers[auth.type].remove;
 | 
							challengers[auth.type] && challengers[auth.type].remove;
 | 
				
			||||||
 | 
						if (!removeChallenge) {
 | 
				
			||||||
 | 
							throw new Error('challenge plugin is missing remove()');
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (1 === removeChallenge.length) {
 | 
						if (1 === removeChallenge.length) {
 | 
				
			||||||
		return Promise.resolve(removeChallenge(auth)).then(
 | 
							return Promise.resolve(removeChallenge(auth)).then(
 | 
				
			||||||
			function() {},
 | 
								function() {},
 | 
				
			||||||
			function() {}
 | 
								function() {}
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
	} else if (2 === removeChallenge.length) {
 | 
						} else if (2 === removeChallenge.length) {
 | 
				
			||||||
 | 
							return new Promise(function(resolve) {
 | 
				
			||||||
			removeChallenge(auth, function(err) {
 | 
								removeChallenge(auth, function(err) {
 | 
				
			||||||
 | 
									resolve();
 | 
				
			||||||
				return err;
 | 
									return err;
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		throw new Error(
 | 
							throw new Error(
 | 
				
			||||||
			"Bad function signature for '" + auth.type + "' challenge.remove()"
 | 
								"Bad function signature for '" + auth.type + "' challenge.remove()"
 | 
				
			||||||
 | 
				
			|||||||
@ -216,9 +216,7 @@ EC.__thumbprint = function(jwk) {
 | 
				
			|||||||
		'","y":"' +
 | 
							'","y":"' +
 | 
				
			||||||
		jwk.y +
 | 
							jwk.y +
 | 
				
			||||||
		'"}';
 | 
							'"}';
 | 
				
			||||||
	console.log('[debug] EC', alg, payload);
 | 
					 | 
				
			||||||
	return sha2.sum(alg, payload).then(function(hash) {
 | 
						return sha2.sum(alg, payload).then(function(hash) {
 | 
				
			||||||
		console.log('[debug] EC hash', hash);
 | 
					 | 
				
			||||||
		return Enc.bufToUrlBase64(Uint8Array.from(hash));
 | 
							return Enc.bufToUrlBase64(Uint8Array.from(hash));
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -76,13 +76,10 @@ Keypairs.neuter = function(opts) {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Keypairs.thumbprint = function(opts) {
 | 
					Keypairs.thumbprint = function(opts) {
 | 
				
			||||||
	//console.log('[debug]', new Error('NOT_ERROR').stack);
 | 
					 | 
				
			||||||
	return Promise.resolve().then(function() {
 | 
						return Promise.resolve().then(function() {
 | 
				
			||||||
		if (/EC/i.test(opts.jwk.kty)) {
 | 
							if (/EC/i.test(opts.jwk.kty)) {
 | 
				
			||||||
			console.log('[debug] EC thumbprint');
 | 
					 | 
				
			||||||
			return Eckles.thumbprint(opts);
 | 
								return Eckles.thumbprint(opts);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			console.log('[debug] RSA thumbprint');
 | 
					 | 
				
			||||||
			return Rasha.thumbprint(opts);
 | 
								return Rasha.thumbprint(opts);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
@ -122,7 +119,6 @@ Keypairs.publish = function(opts) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// JWT a.k.a. JWS with Claims using Compact Serialization
 | 
					// JWT a.k.a. JWS with Claims using Compact Serialization
 | 
				
			||||||
Keypairs.signJwt = function(opts) {
 | 
					Keypairs.signJwt = function(opts) {
 | 
				
			||||||
	console.log('[debug] signJwt');
 | 
					 | 
				
			||||||
	return Keypairs.thumbprint({ jwk: opts.jwk }).then(function(thumb) {
 | 
						return Keypairs.thumbprint({ jwk: opts.jwk }).then(function(thumb) {
 | 
				
			||||||
		var header = opts.header || {};
 | 
							var header = opts.header || {};
 | 
				
			||||||
		var claims = JSON.parse(JSON.stringify(opts.claims || {}));
 | 
							var claims = JSON.parse(JSON.stringify(opts.claims || {}));
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,9 @@ require('dotenv').config();
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var ACME = require('../');
 | 
					var ACME = require('../');
 | 
				
			||||||
var Keypairs = require('../lib/keypairs.js');
 | 
					var Keypairs = require('../lib/keypairs.js');
 | 
				
			||||||
var acme = ACME.create({ debug: true });
 | 
					var acme = ACME.create({
 | 
				
			||||||
 | 
						// debug: true
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO exec npm install --save-dev CHALLENGE_MODULE
 | 
					// TODO exec npm install --save-dev CHALLENGE_MODULE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13,14 +15,42 @@ var config = {
 | 
				
			|||||||
	email: process.env.SUBSCRIBER_EMAIL,
 | 
						email: process.env.SUBSCRIBER_EMAIL,
 | 
				
			||||||
	domain: process.env.BASE_DOMAIN,
 | 
						domain: process.env.BASE_DOMAIN,
 | 
				
			||||||
	challengeType: process.env.CHALLENGE_TYPE,
 | 
						challengeType: process.env.CHALLENGE_TYPE,
 | 
				
			||||||
	challengeModule: process.env.CHALLENGE_MODULE,
 | 
						challengeModule: process.env.CHALLENGE_PLUGIN,
 | 
				
			||||||
	challengeOptions: JSON.parse(process.env.CHALLENGE_OPTIONS)
 | 
						challengeOptions: JSON.parse(process.env.CHALLENGE_OPTIONS)
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
config.debug = !/^PROD/i.test(config.env);
 | 
					config.debug = !/^PROD/i.test(config.env);
 | 
				
			||||||
config.challenger = require('acme-' +
 | 
					var pluginPrefix = 'acme-' + config.challengeType + '-';
 | 
				
			||||||
	config.challengeType +
 | 
					var pluginName = config.challengeModule;
 | 
				
			||||||
	'-' +
 | 
					var plugin;
 | 
				
			||||||
	config.challengeModule).create(config.challengeOptions);
 | 
					
 | 
				
			||||||
 | 
					function badPlugin(err) {
 | 
				
			||||||
 | 
						if ('MODULE_NOT_FOUND' !== err.code) {
 | 
				
			||||||
 | 
							console.error(err);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						console.error("Couldn't find '" + pluginName + "'. Is it installed?");
 | 
				
			||||||
 | 
						console.error("\tnpm install --save-dev '" + pluginName + "'");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					try {
 | 
				
			||||||
 | 
						plugin = require(pluginName);
 | 
				
			||||||
 | 
					} catch (err) {
 | 
				
			||||||
 | 
						if (
 | 
				
			||||||
 | 
							'MODULE_NOT_FOUND' !== err.code ||
 | 
				
			||||||
 | 
							0 === pluginName.indexOf(pluginPrefix)
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							badPlugin(err);
 | 
				
			||||||
 | 
							process.exit(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						try {
 | 
				
			||||||
 | 
							pluginName = pluginPrefix + pluginName;
 | 
				
			||||||
 | 
							plugin = require(pluginName);
 | 
				
			||||||
 | 
						} catch (e) {
 | 
				
			||||||
 | 
							badPlugin(e);
 | 
				
			||||||
 | 
							process.exit(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config.challenger = plugin.create(config.challengeOptions);
 | 
				
			||||||
if (!config.challengeType || !config.domain) {
 | 
					if (!config.challengeType || !config.domain) {
 | 
				
			||||||
	console.error(
 | 
						console.error(
 | 
				
			||||||
		new Error('Missing config variables. Check you .env and the docs')
 | 
							new Error('Missing config variables. Check you .env and the docs')
 | 
				
			||||||
@ -33,7 +63,7 @@ if (!config.challengeType || !config.domain) {
 | 
				
			|||||||
var challenges = {};
 | 
					var challenges = {};
 | 
				
			||||||
challenges[config.challengeType] = config.challenger;
 | 
					challenges[config.challengeType] = config.challenger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function happyPath() {
 | 
					async function happyPath(accKty, srvKty, rnd) {
 | 
				
			||||||
	var agreed = false;
 | 
						var agreed = false;
 | 
				
			||||||
	var metadata = await acme.init(
 | 
						var metadata = await acme.init(
 | 
				
			||||||
		'https://acme-staging-v02.api.letsencrypt.org/directory'
 | 
							'https://acme-staging-v02.api.letsencrypt.org/directory'
 | 
				
			||||||
@ -47,8 +77,7 @@ async function happyPath() {
 | 
				
			|||||||
		console.info();
 | 
							console.info();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// EC for account (but RSA for cert, for testing both)
 | 
						var accountKeypair = await Keypairs.generate({ kty: accKty });
 | 
				
			||||||
	var accountKeypair = await Keypairs.generate({ kty: 'EC' });
 | 
					 | 
				
			||||||
	if (config.debug) {
 | 
						if (config.debug) {
 | 
				
			||||||
		console.info('Account Key Created');
 | 
							console.info('Account Key Created');
 | 
				
			||||||
		console.info(JSON.stringify(accountKeypair, null, 2));
 | 
							console.info(JSON.stringify(accountKeypair, null, 2));
 | 
				
			||||||
@ -83,7 +112,7 @@ async function happyPath() {
 | 
				
			|||||||
		throw new Error('Failed to ask the user to agree to terms');
 | 
							throw new Error('Failed to ask the user to agree to terms');
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var serverKeypair = await Keypairs.generate({ kty: 'RSA' });
 | 
						var serverKeypair = await Keypairs.generate({ kty: srvKty });
 | 
				
			||||||
	if (config.debug) {
 | 
						if (config.debug) {
 | 
				
			||||||
		console.info('Server Key Created');
 | 
							console.info('Server Key Created');
 | 
				
			||||||
		console.info(JSON.stringify(serverKeypair, null, 2));
 | 
							console.info(JSON.stringify(serverKeypair, null, 2));
 | 
				
			||||||
@ -91,7 +120,7 @@ async function happyPath() {
 | 
				
			|||||||
		console.info();
 | 
							console.info();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var domains = randomDomains();
 | 
						var domains = randomDomains(rnd);
 | 
				
			||||||
	if (config.debug) {
 | 
						if (config.debug) {
 | 
				
			||||||
		console.info('Get certificates for random domains:');
 | 
							console.info('Get certificates for random domains:');
 | 
				
			||||||
		console.info(domains);
 | 
							console.info(domains);
 | 
				
			||||||
@ -107,6 +136,7 @@ async function happyPath() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (config.debug) {
 | 
						if (config.debug) {
 | 
				
			||||||
		console.info('Got SSL Certificate:');
 | 
							console.info('Got SSL Certificate:');
 | 
				
			||||||
 | 
							console.info(Object.keys(results));
 | 
				
			||||||
		console.info(results.expires);
 | 
							console.info(results.expires);
 | 
				
			||||||
		console.info(results.cert);
 | 
							console.info(results.cert);
 | 
				
			||||||
		console.info(results.chain);
 | 
							console.info(results.chain);
 | 
				
			||||||
@ -115,17 +145,22 @@ async function happyPath() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
happyPath()
 | 
					// Try EC + RSA
 | 
				
			||||||
 | 
					var rnd = random();
 | 
				
			||||||
 | 
					happyPath('EC', 'RSA', rnd)
 | 
				
			||||||
	.then(function() {
 | 
						.then(function() {
 | 
				
			||||||
 | 
							// Now try RSA + EC
 | 
				
			||||||
 | 
							rnd = random();
 | 
				
			||||||
 | 
							return happyPath('RSA', 'EC', rnd).then(function() {
 | 
				
			||||||
			console.info('success');
 | 
								console.info('success');
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	.catch(function(err) {
 | 
						.catch(function(err) {
 | 
				
			||||||
		console.error('Error:');
 | 
							console.error('Error:');
 | 
				
			||||||
		console.error(err.stack);
 | 
							console.error(err.stack);
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function randomDomains() {
 | 
					function randomDomains(rnd) {
 | 
				
			||||||
	var rnd = random();
 | 
					 | 
				
			||||||
	return ['foo-acmejs', 'bar-acmejs', '*.baz-acmejs', 'baz-acmejs'].map(
 | 
						return ['foo-acmejs', 'bar-acmejs', '*.baz-acmejs', 'baz-acmejs'].map(
 | 
				
			||||||
		function(pre) {
 | 
							function(pre) {
 | 
				
			||||||
			return pre + '-' + rnd + '.' + config.domain;
 | 
								return pre + '-' + rnd + '.' + config.domain;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user