2016-08-12 05:42:28 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
module.exports.create = function (options) {
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-08-13 20:48:55 +00:00
|
|
|
var crypto = require('crypto');
|
2016-08-12 05:42:28 +00:00
|
|
|
var defaults = {};
|
2016-08-13 20:48:55 +00:00
|
|
|
var memDb = {
|
|
|
|
accountKeypairs: {}
|
|
|
|
, certificateKeypairs: {}
|
|
|
|
, accountIndices: {}
|
|
|
|
, certIndices: {}
|
|
|
|
, certificates: {}
|
|
|
|
, accounts: {}
|
|
|
|
, accountCerts: {}
|
|
|
|
};
|
2016-08-12 05:42:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var accounts = {
|
2016-08-13 20:48:55 +00:00
|
|
|
// Accounts
|
|
|
|
setKeypair: function (opts, keypair, cb) {
|
|
|
|
// opts.email // non-optional
|
|
|
|
// opts.keypair // non-optional
|
|
|
|
|
|
|
|
if (!opts.email) {
|
|
|
|
cb(new Error("MUST use email when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!keypair.privateKeyJwk) {
|
|
|
|
cb(new Error("MUST use privateKeyJwk when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!keypair.privateKeyPem) {
|
|
|
|
cb(new Error("MUST use privateKeyPem when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!keypair.publicKeyPem) {
|
|
|
|
cb(new Error("MUST use publicKeyPem when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var accountId = crypto.createHash('sha256').update(keypair.publicKeyPem).digest('hex');
|
|
|
|
|
|
|
|
memDb.accountIndices[accountId] = accountId;
|
|
|
|
memDb.accountIndices[opts.email] = accountId;
|
|
|
|
memDb.accountKeypairs[accountId] = keypair;
|
|
|
|
/*
|
|
|
|
{
|
|
|
|
id: accountId
|
|
|
|
// TODO nix accountId
|
|
|
|
, accountId: accountId
|
|
|
|
, email: opts.email
|
|
|
|
, keypair: keypair
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
|
2016-11-15 23:14:52 +00:00
|
|
|
cb(null, memDb.accountKeypairs[accountId]);
|
2016-08-12 05:42:28 +00:00
|
|
|
}
|
2016-08-13 20:48:55 +00:00
|
|
|
// Accounts
|
|
|
|
, checkKeypair: function (opts, cb) {
|
2016-08-12 05:42:28 +00:00
|
|
|
// opts.email // optional
|
|
|
|
// opts.accountId // optional
|
2016-08-13 20:48:55 +00:00
|
|
|
|
|
|
|
var keypair = opts.keypair || {};
|
|
|
|
var index;
|
|
|
|
|
|
|
|
if (keypair.publicKeyPem) {
|
|
|
|
index = crypto.createHash('sha256').update(keypair.publicKeyPem).digest('hex');
|
|
|
|
index = memDb.accountIndices[index];
|
|
|
|
}
|
|
|
|
else if (keypair.publicKeyJwk) {
|
|
|
|
// TODO RSA.exportPublicPem(keypair);
|
|
|
|
cb(new Error("id from publicKeyJwk not yet implemented"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (opts.email) {
|
|
|
|
index = memDb.accountIndices[opts.email];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cb(new Error("MUST supply email or keypair.publicKeyPem or keypair.publicKeyJwk"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(null, memDb.accountKeypairs[index] || null);
|
2016-08-12 05:42:28 +00:00
|
|
|
}
|
2016-08-13 20:48:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Accounts
|
2016-08-12 05:42:28 +00:00
|
|
|
, set: function (opts, reg, cb) {
|
|
|
|
// opts.email
|
|
|
|
// reg.keypair
|
|
|
|
// reg.receipt // response from acme server
|
2016-08-13 20:48:55 +00:00
|
|
|
|
|
|
|
var keypair = reg.keypair || opts.keypair || {};
|
|
|
|
var accountId;
|
|
|
|
var index;
|
|
|
|
|
|
|
|
if (keypair.publicKeyPem) {
|
|
|
|
index = crypto.createHash('sha256').update(keypair.publicKeyPem).digest('hex');
|
|
|
|
index = memDb.accountIndices[index];
|
|
|
|
}
|
|
|
|
else if (keypair.publicKeyJwk) {
|
|
|
|
// TODO RSA.exportPublicPem(keypair);
|
|
|
|
cb(new Error("id from publicKeyJwk not yet implemented"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (opts.email) {
|
|
|
|
index = memDb.accountIndices[opts.email];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cb(new Error("MUST supply email or keypair.publicKeyPem or keypair.publicKeyJwk"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
accountId = memDb.accountIndices[index];
|
|
|
|
if (!accountId) {
|
|
|
|
cb(new Error("keypair was not previously set with email and keypair.publicKeyPem"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memDb.accounts[accountId] = {
|
|
|
|
id: accountId
|
|
|
|
// TODO nix accountId
|
|
|
|
, accountId: accountId
|
|
|
|
, email: opts.email
|
|
|
|
, keypair: keypair
|
|
|
|
, agreeTos: opts.agreeTos || reg.agreeTos
|
|
|
|
//, receipt: reg.receipt || opts.receipt
|
|
|
|
};
|
|
|
|
Object.keys(reg).forEach(function (key) {
|
|
|
|
memDb.accounts[accountId][key] = reg[key];
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cb(null, memDb.accounts[accountId]);
|
|
|
|
}
|
|
|
|
// Accounts
|
|
|
|
, check: function (opts, cb) {
|
|
|
|
// opts.email // optional
|
|
|
|
// opts.accountId // optional
|
|
|
|
// opts.domains // optional
|
|
|
|
|
|
|
|
var keypair = opts.keypair || {};
|
|
|
|
var index;
|
|
|
|
var accountId;
|
|
|
|
var account;
|
|
|
|
|
|
|
|
if (opts.accountId) {
|
|
|
|
index = memDb.accountIndices[opts.accountId];
|
|
|
|
}
|
|
|
|
else if (keypair.publicKeyPem) {
|
|
|
|
index = crypto.createHash('sha256').update(keypair.publicKeyPem).digest('hex');
|
|
|
|
index = memDb.accountIndices[index];
|
|
|
|
}
|
|
|
|
else if (keypair.publicKeyJwk) {
|
|
|
|
// TODO RSA.exportPublicPem(keypair);
|
|
|
|
cb(new Error("id from publicKeyJwk not yet implemented"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (opts.email) {
|
|
|
|
index = memDb.accountIndices[opts.email];
|
|
|
|
}
|
|
|
|
else if (opts.domains && opts.domains[0]) {
|
|
|
|
index = memDb.accountIndices[opts.domains[0]];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.error(opts);
|
|
|
|
cb(new Error("MUST supply email or keypair.publicKeyPem or keypair.publicKeyJwk"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
accountId = memDb.accountIndices[index];
|
|
|
|
if (!accountId) {
|
|
|
|
cb(null, null);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
account = JSON.parse(JSON.stringify(memDb.accounts[accountId] || null));
|
|
|
|
account.keypair = memDb.accountKeypairs[accountId] || null;
|
|
|
|
|
|
|
|
cb(null, account);
|
2016-08-12 05:42:28 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var certificates = {
|
2016-08-13 20:48:55 +00:00
|
|
|
// Certificates
|
|
|
|
setKeypair: function (opts, keypair, cb) {
|
2016-08-12 05:42:28 +00:00
|
|
|
// opts.domains
|
2016-08-13 20:48:55 +00:00
|
|
|
|
|
|
|
if (!opts.domains || !opts.domains.length) {
|
|
|
|
cb(new Error("MUST use domains when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!opts.email) {
|
|
|
|
cb(new Error("MUST use email when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!opts.accountId) {
|
|
|
|
cb(new Error("MUST use accountId when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!keypair.privateKeyJwk) {
|
|
|
|
cb(new Error("MUST use privateKeyJwk when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!keypair.privateKeyPem) {
|
|
|
|
cb(new Error("MUST use privateKeyPem when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!keypair.publicKeyPem) {
|
|
|
|
cb(new Error("MUST use publicKeyPem when setting Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var subject = opts.domains[0];
|
|
|
|
|
|
|
|
opts.domains.forEach(function (domain) {
|
|
|
|
memDb.certIndices[domain] = subject;
|
|
|
|
});
|
|
|
|
|
|
|
|
memDb.certKeypairs[subject] = keypair;
|
|
|
|
/*
|
|
|
|
{
|
|
|
|
subject: subject
|
|
|
|
, keypair: keypair
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
|
|
|
|
cb(null, memDb.certKeypairs[subject]);
|
2016-08-12 05:42:28 +00:00
|
|
|
}
|
2016-08-13 20:48:55 +00:00
|
|
|
// Certificates
|
|
|
|
, checkKeypair: function (opts, cb) {
|
2016-08-12 05:42:28 +00:00
|
|
|
// opts.domains
|
2016-08-13 20:48:55 +00:00
|
|
|
if (!opts.domains || !opts.domains.length) {
|
|
|
|
cb(new Error("MUST use domains when checking Keypair"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var domain = opts.domains[0];
|
|
|
|
var subject = memDb.certIndices[domain];
|
|
|
|
|
|
|
|
cb(null, memDb.certKeypairs[subject]);
|
2016-08-12 05:42:28 +00:00
|
|
|
}
|
2016-08-13 20:48:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Certificates
|
|
|
|
, set: function (opts, certs, cb) {
|
2016-08-12 05:42:28 +00:00
|
|
|
// opts.domains
|
|
|
|
// opts.email // optional
|
|
|
|
// opts.accountId // optional
|
2016-08-13 20:48:55 +00:00
|
|
|
|
|
|
|
// certs.privkey
|
|
|
|
// certs.cert
|
|
|
|
// certs.chain
|
|
|
|
|
|
|
|
var index;
|
|
|
|
var accountId;
|
|
|
|
var account;
|
|
|
|
var subject = certs.subject || opts.domains[0];
|
|
|
|
var altnames = certs.altnames || opts.domains;
|
|
|
|
var accountCerts;
|
|
|
|
|
|
|
|
if (opts.accountId) {
|
|
|
|
index = opts.accountId;
|
|
|
|
}
|
|
|
|
else if (opts.email) {
|
|
|
|
index = opts.email;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cb(new Error("MUST supply email or accountId"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
accountId = memDb.accountIndices[index];
|
|
|
|
account = memDb.accounts[accountId];
|
|
|
|
|
|
|
|
if (!account) {
|
|
|
|
cb(new Error("account must exist"));
|
|
|
|
}
|
|
|
|
|
|
|
|
accountId = memDb.accountIndices[index];
|
|
|
|
if (!accountId) {
|
|
|
|
cb(new Error("keypair was not previously set with email and keypair.publicKeyPem"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memDb.certIndices[subject] = subject;
|
|
|
|
altnames.forEach(function (altname) {
|
|
|
|
memDb.certIndices[altname] = subject;
|
|
|
|
});
|
|
|
|
|
|
|
|
accountCerts = memDb.accountCerts[accountId] || {};
|
|
|
|
accountCerts[subject] = subject;
|
|
|
|
memDb.accountCerts[accountId] = accountCerts;
|
|
|
|
|
|
|
|
memDb.certificates[subject] = certs;
|
|
|
|
|
|
|
|
// SAVE to the database, index the email address, the accountId, and alias the domains
|
|
|
|
cb(null, certs);
|
2016-08-12 05:42:28 +00:00
|
|
|
}
|
2016-08-13 20:48:55 +00:00
|
|
|
// Certificates
|
|
|
|
, check: function (opts, cb) {
|
|
|
|
// You will be provided one of these (which should be tried in this order)
|
2016-08-12 05:42:28 +00:00
|
|
|
// opts.domains
|
|
|
|
// opts.email // optional
|
|
|
|
// opts.accountId // optional
|
2016-08-13 20:48:55 +00:00
|
|
|
var subject;
|
|
|
|
var subjects;
|
|
|
|
var accountId;
|
|
|
|
|
|
|
|
if (opts.domains) {
|
|
|
|
subject = memDb.certIndices[opts.domains[0]];
|
|
|
|
cb(null, memDb.certificates[subject]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts.accountId) {
|
|
|
|
accountId = memDb.accountIndices[opts.accountId];
|
|
|
|
}
|
|
|
|
else if (opts.email) {
|
|
|
|
accountId = memDb.accountIndices[opts.email];
|
|
|
|
}
|
|
|
|
|
|
|
|
subjects = memDb.accountCerts[accountId] || [];
|
|
|
|
cb(null, subjects.map(function (subject) {
|
|
|
|
subject = memDb.certIndices[subject];
|
|
|
|
return memDb.certificates[subject] || null ;
|
|
|
|
}));
|
2016-08-12 05:42:28 +00:00
|
|
|
}
|
2016-08-13 20:48:55 +00:00
|
|
|
|
2016-08-12 05:42:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
getOptions: function () {
|
2016-08-13 20:48:55 +00:00
|
|
|
Object.keys(defaults).forEach(function (key) {
|
|
|
|
if ('undefined' === typeof options[key]) {
|
|
|
|
options[key] = defaults[key];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-08-12 05:42:28 +00:00
|
|
|
// merge options with default settings and then return them
|
|
|
|
return options;
|
|
|
|
}
|
|
|
|
, accounts: accounts
|
|
|
|
, certificates: certificates
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|