multiple bugfixes and enhancements for accounts
This commit is contained in:
parent
3a1f66f9e2
commit
dad8249d5f
12
index.js
12
index.js
|
@ -5,7 +5,7 @@
|
|||
var PromiseA = require('bluebird');
|
||||
var leCore = require('letiny-core');
|
||||
var merge = require('./lib/common').merge;
|
||||
var tplHostname = require('./lib/common').tplHostname;
|
||||
var tplCopy = require('./lib/common').tplCopy;
|
||||
|
||||
var LE = module.exports;
|
||||
LE.productionServerUrl = leCore.productionServerUrl;
|
||||
|
@ -58,7 +58,7 @@ LE.create = function (defaults, handlers, backend) {
|
|||
var getChallenge = require('./lib/default-handlers').getChallenge;
|
||||
var copy = merge(defaults, { domains: [hostname] });
|
||||
|
||||
tplHostname(hostname, copy);
|
||||
tplCopy(copy);
|
||||
defaultos.domains = [hostname];
|
||||
|
||||
if (3 === getChallenge.length) {
|
||||
|
@ -158,9 +158,13 @@ LE.create = function (defaults, handlers, backend) {
|
|||
return;
|
||||
}
|
||||
|
||||
//console.log("[NLE]: begin registration");
|
||||
if (args.debug) {
|
||||
console.log("[NLE]: begin registration");
|
||||
}
|
||||
return backend.registerAsync(copy).then(function (pems) {
|
||||
//console.log("[NLE]: end registration");
|
||||
if (args.debug) {
|
||||
console.log("[NLE]: end registration");
|
||||
}
|
||||
cb(null, pems);
|
||||
//return le.fetch(args, cb);
|
||||
}, cb);
|
||||
|
|
|
@ -13,7 +13,7 @@ function createAccount(args, handlers) {
|
|||
|
||||
// TODO support ECDSA
|
||||
// arg.rsaBitLength args.rsaExponent
|
||||
return leCrypto.generateRsaKeypairAsync(args.rsaBitLength, args.rsaExponent).then(function (pems) {
|
||||
return leCrypto.generateRsaKeypairAsync(args.rsaKeySize, 65537).then(function (pems) {
|
||||
/* pems = { privateKeyPem, privateKeyJwk, publicKeyPem, publicKeyMd5, publicKeySha256 } */
|
||||
|
||||
return LeCore.registerNewAccountAsync({
|
||||
|
@ -117,15 +117,69 @@ function getAccount(accountId, args, handlers) {
|
|||
});
|
||||
}
|
||||
|
||||
function getAccountByEmail(/*args*/) {
|
||||
function getAccountIdByEmail(args, handlers) {
|
||||
// If we read 10,000 account directories looking for
|
||||
// just one email address, that could get crazy.
|
||||
// We should have a folder per email and list
|
||||
// each account as a file in the folder
|
||||
// TODO
|
||||
return PromiseA.resolve(null);
|
||||
var email = args.email;
|
||||
if ('string' !== typeof email) {
|
||||
if (args.debug) {
|
||||
console.log("[LE] No email given");
|
||||
}
|
||||
return PromiseA.resolve(null);
|
||||
}
|
||||
return fs.readdirAsync(args.accountsDir).then(function (nodes) {
|
||||
if (args.debug) {
|
||||
console.log("[LE] arg.accountsDir success");
|
||||
}
|
||||
|
||||
return PromiseA.all(nodes.map(function (node) {
|
||||
return fs.readFileAsync(path.join(args.accountsDir, node, 'regr.json'), 'utf8').then(function (text) {
|
||||
var regr = JSON.parse(text);
|
||||
regr.__accountId = node;
|
||||
|
||||
return regr;
|
||||
});
|
||||
})).then(function (regrs) {
|
||||
var accountId;
|
||||
|
||||
/*
|
||||
if (args.debug) {
|
||||
console.log('read many regrs');
|
||||
console.log('regrs', regrs);
|
||||
}
|
||||
*/
|
||||
|
||||
regrs.some(function (regr) {
|
||||
return regr.body.contact.some(function (contact) {
|
||||
var match = contact.toLowerCase() === 'mailto:' + email.toLowerCase();
|
||||
if (match) {
|
||||
accountId = regr.__accountId;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!accountId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return accountId;
|
||||
});
|
||||
}).then(function (accountId) {
|
||||
return accountId;
|
||||
}, function (err) {
|
||||
if ('ENOENT' == err.code) {
|
||||
// ignore error
|
||||
return null;
|
||||
}
|
||||
|
||||
return PromiseA.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.getAccountByEmail = getAccountByEmail;
|
||||
module.exports.getAccountIdByEmail = getAccountIdByEmail;
|
||||
module.exports.getAccount = getAccount;
|
||||
module.exports.createAccount = createAccount;
|
||||
|
|
|
@ -45,12 +45,23 @@ module.exports.merge = function merge(defaults, args) {
|
|||
return copy;
|
||||
};
|
||||
|
||||
module.exports.tplHostname = function merge(hostname, copy) {
|
||||
module.exports.tplCopy = function merge(copy) {
|
||||
var homedir = require('homedir')();
|
||||
var tpls = {
|
||||
hostname: (copy.domains || [])[0]
|
||||
, server: (copy.server || '').replace('https://', '').replace(/(\/)$/, '')
|
||||
, conf: copy.configDir
|
||||
, config: copy.configDir
|
||||
};
|
||||
|
||||
Object.keys(copy).forEach(function (key) {
|
||||
if ('string' === typeof copy[key]) {
|
||||
copy[key] = copy[key].replace(':hostname', hostname).replace(':host', hostname);
|
||||
copy[key] = copy[key].replace(homeRe, homedir + path.sep);
|
||||
Object.keys(tpls).sort(function (a, b) {
|
||||
return b.length - a.length;
|
||||
}).forEach(function (tplname) {
|
||||
copy[key] = copy[key].replace(':' + tplname, tpls[tplname]);
|
||||
copy[key] = copy[key].replace(homeRe, homedir + path.sep);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
85
lib/core.js
85
lib/core.js
|
@ -10,7 +10,7 @@ var leCrypto = PromiseA.promisifyAll(LeCore.leCrypto);
|
|||
var Accounts = require('./accounts');
|
||||
|
||||
var merge = require('./common').merge;
|
||||
var tplHostname = require('./common').tplHostname;
|
||||
var tplCopy = require('./common').tplCopy;
|
||||
var fetchFromConfigLiveDir = require('./common').fetchFromDisk;
|
||||
|
||||
var ipc = {}; // in-process cache
|
||||
|
@ -34,7 +34,7 @@ function getAcmeUrls(args) {
|
|||
|
||||
|
||||
function getCertificateAsync(account, args, defaults, handlers) {
|
||||
return leCrypto.generateRsaKeypairAsync(args.rsaKeySize, args.rsaExponent).then(function (domainKey) {
|
||||
return leCrypto.generateRsaKeypairAsync(args.rsaKeySize, 65537).then(function (domainKey) {
|
||||
if (args.debug) {
|
||||
console.log("get certificate");
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ function getCertificateAsync(account, args, defaults, handlers) {
|
|||
//
|
||||
, setChallenge: function (domain, key, value, done) {
|
||||
var copy = merge(defaults, { domains: [domain] });
|
||||
tplHostname(domain, copy);
|
||||
tplCopy(copy);
|
||||
|
||||
args.domains = [domain];
|
||||
args.webrootPath = args.webrootPath;
|
||||
|
@ -74,7 +74,7 @@ function getCertificateAsync(account, args, defaults, handlers) {
|
|||
}
|
||||
, removeChallenge: function (domain, key, done) {
|
||||
var copy = merge(defaults, { domains: [domain] });
|
||||
tplHostname(domain, copy);
|
||||
tplCopy(copy);
|
||||
|
||||
if (3 === handlers.removeChallenge.length) {
|
||||
handlers.removeChallenge(copy, key, done);
|
||||
|
@ -204,7 +204,35 @@ function getCertificateAsync(account, args, defaults, handlers) {
|
|||
});
|
||||
}
|
||||
|
||||
function registerWithAcme(args, defaults, handlers) {
|
||||
function getOrCreateDomainCertificate(account, args, defaults, hanlers) {
|
||||
return fetchFromConfigLiveDir(args).then(function (certs) {
|
||||
// if nothing, register and save
|
||||
// if something, check date (don't register unless 30+ days)
|
||||
// if good, don't bother registering
|
||||
// (but if we get to the point that we're actually calling
|
||||
// this function, that shouldn't be the case, right?)
|
||||
//console.log(certs);
|
||||
if (!certs) {
|
||||
// no certs, seems like a good time to get some
|
||||
return getCertificateAsync(account, args, defaults, handlers);
|
||||
}
|
||||
else if (certs.issuedAt > (27 * 24 * 60 * 60 * 1000)) {
|
||||
// cert is at least 27 days old we can renew that
|
||||
return getCertificateAsync(account, args, defaults, handlers);
|
||||
}
|
||||
else if (args.duplicate) {
|
||||
// YOLO! I be gettin' fresh certs 'erday! Yo!
|
||||
return getCertificateAsync(account, args, defaults, handlers);
|
||||
}
|
||||
else {
|
||||
console.warn('[WARN] Ignoring renewal attempt for certificate less than 27 days old. Use args.duplicate to force.');
|
||||
// We're happy with what we have
|
||||
return certs;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function getOrCreateAcmeAccount(args, defaults, handlers) {
|
||||
var pyconf = PromiseA.promisifyAll(require('pyconf'));
|
||||
var server = args.server;
|
||||
var acmeHostname = require('url').parse(server).hostname;
|
||||
|
@ -220,18 +248,28 @@ function registerWithAcme(args, defaults, handlers) {
|
|||
return accountId;
|
||||
}, function (err) {
|
||||
if ("ENOENT" === err.code) {
|
||||
return Accounts.getAccountByEmail(args, handlers);
|
||||
if (args.debug) {
|
||||
console.log("[LE] try email");
|
||||
}
|
||||
return Accounts.getAccountIdByEmail(args, handlers);
|
||||
}
|
||||
|
||||
return PromiseA.reject(err);
|
||||
}).then(function (accountId) {
|
||||
|
||||
// Note: the ACME urls are always fetched fresh on purpose
|
||||
return getAcmeUrls(args).then(function (urls) {
|
||||
args._acmeUrls = urls;
|
||||
|
||||
if (accountId) {
|
||||
if (args.debug) {
|
||||
console.log('[LE] use account');
|
||||
}
|
||||
return Accounts.getAccount(accountId, args, handlers);
|
||||
} else {
|
||||
if (args.debug) {
|
||||
console.log('[LE] create account');
|
||||
}
|
||||
return Accounts.createAccount(args, handlers);
|
||||
}
|
||||
});
|
||||
|
@ -242,33 +280,6 @@ function registerWithAcme(args, defaults, handlers) {
|
|||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
//console.log(account);
|
||||
return fetchFromConfigLiveDir(args).then(function (certs) {
|
||||
// if nothing, register and save
|
||||
// if something, check date (don't register unless 30+ days)
|
||||
// if good, don't bother registering
|
||||
// (but if we get to the point that we're actually calling
|
||||
// this function, that shouldn't be the case, right?)
|
||||
//console.log(certs);
|
||||
if (!certs) {
|
||||
// no certs, seems like a good time to get some
|
||||
return getCertificateAsync(account, args, defaults, handlers);
|
||||
}
|
||||
else if (certs.issuedAt > (27 * 24 * 60 * 60 * 1000)) {
|
||||
// cert is at least 27 days old we can renew that
|
||||
return getCertificateAsync(account, args, defaults, handlers);
|
||||
}
|
||||
else if (args.duplicate) {
|
||||
// YOLO! I be gettin' fresh certs 'erday! Yo!
|
||||
return getCertificateAsync(account, args, defaults, handlers);
|
||||
}
|
||||
else {
|
||||
console.warn('[WARN] Ignoring renewal attempt for certificate less than 27 days old. Use args.duplicate to force.');
|
||||
// We're happy with what we have
|
||||
return certs;
|
||||
}
|
||||
});
|
||||
});
|
||||
/*
|
||||
return fs.readdirAsync(accountsDir, function (nodes) {
|
||||
|
@ -293,16 +304,18 @@ module.exports.create = function (defaults, handlers) {
|
|||
// So :config/accounts/:server/directory is *incorrect*, but the following *is* correct:
|
||||
args.accountsDir = args.accountsDir || ':config/accounts/:server';
|
||||
copy = merge(args, defaults);
|
||||
tplHostname(args.domains[0], copy);
|
||||
tplCopy(copy);
|
||||
|
||||
if (args.debug) {
|
||||
console.log('[LE DEBUG] reg domains', args.domains);
|
||||
}
|
||||
return registerWithAcme(copy, defaults, handlers);
|
||||
return getOrCreateAcmeAccount(copy, defaults, handlers).then(function (account) {
|
||||
return getOrCreateDomainCertificate(account, copy, defaults, handlers);
|
||||
});
|
||||
}
|
||||
, fetchAsync: function (args) {
|
||||
var copy = merge(args, defaults);
|
||||
tplHostname(args.domains[0], copy);
|
||||
tplCopy(copy);
|
||||
|
||||
if (args.debug) {
|
||||
console.log('[LE DEBUG] fetch domains', copy);
|
||||
|
|
Loading…
Reference in New Issue