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…
Reference in New Issue