Compare commits
31 Commits
Author | SHA1 | Date |
---|---|---|
AJ ONeal | 2d7a117197 | |
AJ ONeal | 3c2778a67e | |
AJ ONeal | f4c1aa6906 | |
AJ ONeal | 974b3707c1 | |
AJ ONeal | 06c78a6a10 | |
CaptEmulation | c58785f6e3 | |
AJ ONeal | 766eaa3eed | |
AJ ONeal | 2ac41d914a | |
AJ ONeal | 359755901d | |
AJ ONeal | 7f082d728b | |
AJ ONeal | f4ccef647b | |
AJ ONeal | 10764c4f56 | |
Jonathan Otto | 73f6cd5ab2 | |
AJ ONeal | a52e2aeb8e | |
AJ ONeal | abc665fa81 | |
AJ ONeal | 861872499e | |
AJ ONeal | 434bde67dc | |
AJ ONeal | b3102ded8d | |
AJ ONeal | 8f13081270 | |
AJ ONeal | b5f44afec6 | |
AJ ONeal | c7d2806fe7 | |
AJ ONeal | d657afbac9 | |
AJ ONeal | 43c830482c | |
AJ ONeal | 3083130ccc | |
AJ ONeal | e120d2dcc2 | |
AJ ONeal | f8f7a75c99 | |
AJ ONeal | dfa5f79e0d | |
AJ ONeal | 5af14f1147 | |
AJ ONeal | bbf5168fb7 | |
AJ ONeal | 5a5848614b | |
AJ ONeal | ee294fce8c |
|
@ -0,0 +1,37 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2016 Daplie, Inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,8 @@
|
|||
# See [`greenlock-store-test`](https://git.rootprojects.org/root/greenlock-store-test.js)
|
||||
|
||||
That's the test.
|
||||
|
||||
## Reference implementations
|
||||
|
||||
* [`greenlock-store-fs`](https://git.rootprojects.org/root/greenlock-store-fs.js)
|
||||
* [`greenlock-store-sequelize`](https://git.rootprojects.org/root/greenlock-store-sequelize.js)
|
|
@ -0,0 +1,366 @@
|
|||
'use strict';
|
||||
|
||||
module.exports.create = function (options) {
|
||||
|
||||
|
||||
|
||||
var crypto = require('crypto');
|
||||
var defaults = {};
|
||||
var memDb = {
|
||||
accountKeypairs: {}
|
||||
, certificateKeypairs: {}
|
||||
, accountIndices: {}
|
||||
, certIndices: {}
|
||||
, certificates: {}
|
||||
, accounts: {}
|
||||
, accountCerts: {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
var accounts = {
|
||||
// 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
|
||||
};
|
||||
*/
|
||||
|
||||
cb(null, memDb.accountKeypairs[accountId]);
|
||||
}
|
||||
// Accounts
|
||||
, checkKeypair: function (opts, cb) {
|
||||
// opts.email // optional
|
||||
// opts.accountId // optional
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Accounts
|
||||
, set: function (opts, reg, cb) {
|
||||
// opts.email
|
||||
// reg.keypair
|
||||
// reg.receipt // response from acme server
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
var certificates = {
|
||||
// Certificates
|
||||
setKeypair: function (opts, keypair, cb) {
|
||||
// opts.domains
|
||||
|
||||
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]);
|
||||
}
|
||||
// Certificates
|
||||
, checkKeypair: function (opts, cb) {
|
||||
// opts.domains
|
||||
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]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Certificates
|
||||
, set: function (opts, cb) {
|
||||
// opts.domains
|
||||
// opts.email // optional
|
||||
// opts.accountId // optional
|
||||
|
||||
// opts.certs.privkey
|
||||
// opts.certs.cert
|
||||
// opts.certs.chain
|
||||
|
||||
var index;
|
||||
var accountId;
|
||||
var account;
|
||||
var certs = opts.certs;
|
||||
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);
|
||||
}
|
||||
// Certificates
|
||||
, check: function (opts, cb) {
|
||||
// You will be provided one of these (which should be tried in this order)
|
||||
// opts.domains
|
||||
// opts.email // optional
|
||||
// opts.accountId // optional
|
||||
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 ;
|
||||
}));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
return {
|
||||
getOptions: function () {
|
||||
Object.keys(defaults).forEach(function (key) {
|
||||
if ('undefined' === typeof options[key]) {
|
||||
options[key] = defaults[key];
|
||||
}
|
||||
});
|
||||
|
||||
// merge options with default settings and then return them
|
||||
return options;
|
||||
}
|
||||
, accounts: accounts
|
||||
, certificates: certificates
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
Loading…
Reference in New Issue