From 00157ab870b7bcc4a1051c0a2528994448858b24 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Sat, 13 Aug 2016 15:11:09 -0600 Subject: [PATCH] update template, add tests --- index.js | 64 +++++--- tests/basic.js | 352 +++++++++++++++++++++++++++++++++++++++++ tests/relationships.js | 3 + 3 files changed, 396 insertions(+), 23 deletions(-) create mode 100644 tests/basic.js create mode 100644 tests/relationships.js diff --git a/index.js b/index.js index 54efdc1..cf9b84d 100644 --- a/index.js +++ b/index.js @@ -9,76 +9,94 @@ module.exports.create = function (options) { var accounts = { - checkKeypair: function (opts, cb) { + + // Accounts + setKeypair: function (opts, keypair, cb) { // opts.email // optional // opts.accountId // optional - - // check db and return null or keypair object with one of privateKeyPem or privateKeyJwk - cb(null, { privateKeyPem: '...', privateKeyJwk: {} }); - } - , setKeypair: function (opts, keypair, cb) { - // opts.email // optional - // opts.accountId // optional - + // SAVE to db (as PEM and/or JWK) and index each domain in domains to this keypair cb(null, keypair); } + // Accounts + , checkKeypair: function (opts, cb) { + // opts.email // optional + // opts.accountId // optional + + // check db and return null or keypair object with one of privateKeyPem or privateKeyJwk + cb(null, { privateKeyPem: '...', privateKeyJwk: {} }); + } + + + + // Accounts , check: function (opts, cb) { // opts.email // optional // opts.accountId // optional // opts.domains // optional - + // return account from db if it exists, otherwise null cb(null, { id: '...', keypair: { privateKeyJwk: {} }, domains: [] }); } + // Accounts , set: function (opts, reg, cb) { // opts.email // reg.keypair // reg.receipt // response from acme server - - + + cb(null, { id: '...', email: opts.email, keypair: reg.keypair, receipt: reg.receipt }); } + }; var certificates = { - checkKeypair: function (opts, cb) { + + // Certificates + setKeypair: function (opts, keypair, cb) { // opts.domains - - // check db and return null or keypair object with one of privateKeyPem or privateKeyJwk - cb(null, { privateKeyPem: '...', privateKeyJwk: {} }); - } - , setKeypair: function (opts, keypair, cb) { - // opts.domains - + // SAVE to db (as PEM and/or JWK) and index each domain in domains to this keypair cb(null, keypair); } + // Certificates + , checkKeypair: function (opts, cb) { + // opts.domains + + // check db and return null or keypair object with one of privateKeyPem or privateKeyJwk + cb(null, { privateKeyPem: '...', privateKeyJwk: {} }); + } + + + + // 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 - + // return certificate PEMs from db if they exist, otherwise null // optionally include expiresAt and issuedAt, if they are known exactly // (otherwise they will be read from the cert itself later) cb(null, { privkey: 'PEM', cert: 'PEM', chain: 'PEM', domains: [], accountId: '...' }); } + // Certificates , set: function (opts, pems, cb) { // opts.domains // opts.email // optional // opts.accountId // optional - + // pems.privkey // pems.cert // pems.chain - + // SAVE to the database, index the email address, the accountId, and alias the domains cb(null, pems); } + }; diff --git a/tests/basic.js b/tests/basic.js new file mode 100644 index 0000000..cd93d70 --- /dev/null +++ b/tests/basic.js @@ -0,0 +1,352 @@ +'use strict'; + +var PromiseA = require('bluebird'); +var leStore = PromiseA.promisifyAll(require('../').create({ + debug: true +})); +leStore.accounts = PromiseA.promisifyAll(leStore.accounts); +leStore.certificates = PromiseA.promisifyAll(leStore.certificates); + +// fixtures +var doesntExist = { + email: 'e@gmail.co' +, accountId: 'eee' +}; +var goodGuy = { + email: 'goodguy@gmail.com' +, keypair: { + privateKeyPem: 'PRIVKEY.PEM', privateKeyJwk: { e: 'EXPO', n: 'MODULO' } + , publicKeyPem: 'PUBKEY.PEM'/*, publicKeyJwk: would be reduntdant */ + } +}; + +var tests = [ + + + + // + // SANITY CHECKS + // + + // SANITY test that an unregistered email returns no results + function () { + return leStore.accounts.checkKeypairAsync({ + email: doesntExist.email + }).then(function (keypair) { + if (null !== keypair) { + throw new Error("Should return `null` when keypair does not exist by `email`."); + } + }); + } + + // SANITY test that an unregistered account id returns no results +, function () { + return leStore.accounts.checkAsync({ + accountId: doesntExist.accountId + }).then(function (account) { + if (null !== account) { + throw new Error("Should return `null` when account does not exist by `accountId`."); + } + }); + } + + // SANITY test that an unregistered email returns no results +, function () { + return leStore.accounts.checkAsync({ + email: doesntExist.email + }).then(function (account) { + if (null !== account) { + throw new Error("Should return `null` when account does not exist by `accountId`."); + } + }); + } + + + + + + + // + // Creating Account Keypairs + // + + // Register a private key to an email + // and make sure agreeTos remains falsey +, function () { + return leStore.accounts.setKeypairAsync(goodGuy, goodGuy.keypair); + } +, function () { + return leStore.accounts.checkKeypairAsync({ + email: goodGuy.email + }).then(function (keypair) { + + if (!keypair) { + throw new Error("should return saved keypair"); + } + + if (goodGuy.keypair.privateKeyPem !== keypair.privateKeyPem) { + if (keypair.privateKeyJwk) { + throw new Error("Error in test itself (not your fault). TODO: implement checking privateKeyJwk."); + } + throw new Error("agreeTos should return false or null because it was not set."); + } + }); + } + + + + + + + // + // Creating Accounts + // + + // create a new account +, function () { + var account = { + receipt: {} + , agreeTos: true + }; + + return leStore.accounts.setAsync(goodGuy, account).then(function (account) { + if (!account || !account.id || !account.email) { + throw new Error('accounts.set should return the object with its new `id` attached'); + } + + goodGuy.accountId = account.id; + }); + } + + // get by account id +, function () { + return leStore.accounts.checkAsync({ + accountId: goodGuy.accountId + }).then(function (account) { + + if (!account) { + throw new Error("Did not find account."); + } + else if (!account.keypair) { + throw new Error("Account did not have a keypair."); + } + else if (goodGuy.keypair.privateKeyPem !== account.keypair.privateKeyPem) { + if (account.keypair.privateKeyJwk) { + throw new Error("Error in test itself (not your fault). TODO: implement checking privateKeyJwk."); + } + throw new Error("agreeTos should return false or null because it was not set."); + } + + if (!account.email) { + throw new Error("should have returned email"); + } + + if (!account.agreeTos) { + throw new Error("should have returned agreeTos"); + } + + if (!account.receipt) { + throw new Error("should have returned receipt"); + } + }); + } + // get by email +, function () { + return leStore.accounts.checkAsync({ + email: goodGuy.email + }).then(function (account) { + + if (goodGuy.keypair.privateKeyPem !== account.keypair.privateKeyPem) { + if (account.keypair.privateKeyJwk) { + throw new Error("Error in test itself (not your fault). TODO: implement checking privateKeyJwk."); + } + throw new Error("agreeTos should return false or null because it was not set."); + } + + if (!account.email) { + throw new Error("should have returned email"); + } + + if (!account.agreeTos) { + throw new Error("should have returned agreeTos"); + } + + if (!account.receipt) { + throw new Error("should have returned receipt"); + } + }); + } + + // Test that id and accountId are ignored + // and that arbitrary keys are stored +, function () { + var rnd = require('crypto').randomBytes(8).toString('hex'); + var opts = { + accountId: '_account_id' + , id: '__account_id' + , email: 'john.doe@gmail.com' + , agreeTos: 'TOS_URL' + }; + var account = { + keypair: { privateKeyJwk: {}, privateKeyPem: 'PEM2', publicKeyPem: 'PUBPEM2' } + , receipt: {} + }; + account[rnd] = rnd; + return leStore.accounts.setKeypairAsync(opts, account.keypair).then(function () { + return leStore.accounts.setAsync(opts, account).then(function (account) { + + if ('_account_id' === account.id || '__account_id' === account.id) { + throw new Error("Should create `id` deterministically from email or public key, not the given `accountId` or `id`."); + } + + if ('john.doe@gmail.com' !== account.email) { + throw new Error("Should return the same email that was stored."); + } + + if ('TOS_URL' !== account.agreeTos) { + throw new Error("Should return the same string for the tosUrl in agreeTos as was stored."); + } + + if ('PEM2' !== account.keypair.privateKeyPem) { + throw new Error("Should return the same privateKey that was stored."); + } + + if (rnd !== account[rnd]) { + throw new Error("Should save and restore arbitrary keys."); + } + }); + }); + } + + // test lots of stuff +, function () { + return leStore.accounts.checkAsync({ + accountId: goodGuy.accountId + }).then(function (account) { + if (!account + || !account.agreeTos + || account.email !== goodGuy.email + || goodGuy.keypair.privateKeyPem !== account.keypair.privateKeyPem + ) { + throw new Error("Should return the same account that was saved when retrieved using `accountId`."); + } + }); + } +, function () { + return leStore.accounts.checkAsync({ + email: goodGuy.email + }).then(function (account) { + if (!account + || !account.agreeTos + || account.email !== goodGuy.email + || goodGuy.keypair.privateKeyPem !== account.keypair.privateKeyPem + ) { + throw new Error("Should return the same account that was saved when retrieved using `accountId`."); + } + }); + } + + + + + + + // + // Save a cert + // +, function () { + var certOpts = { + domains: [ 'example.com', 'www.example.com', 'foo.net', 'bar.foo.net' ] + , email: goodGuy.email + , certs: { + cert: 'CERT_A.PEM' + , privkey: 'PRIVKEY_A.PEM' + , chain: 'CHAIN_A.PEM' + // TODO issuedAt, expiresAt? + } + }; + + return leStore.certificates.setAsync(certOpts, certOpts.certs); + } + // and another +, function () { + var certOpts = { + domains: [ 'foo.com', 'www.foo.com', 'baz.net', 'bar.baz.net' ] + , accountId: goodGuy.accountId + , certs: { + cert: 'CERT_B.PEM' + , privkey: 'PRIVKEY_B.PEM' + , chain: 'CHAIN_B.PEM' + } + }; + + return leStore.certificates.setAsync(certOpts, certOpts.certs); + } + + // basic test (set by email) +, function () { + var certOpts = { + domains: [ 'example.com' ] + }; + return leStore.certificates.checkAsync(certOpts).then(function (certs) { + if (!certs || certs.privkey !== 'PRIVKEY_A.PEM') { + throw new Error("should have correct certs for example.com (set by email)"); + } + }); + } + // basic test (set by accountId) +, function () { + var certOpts = { + domains: [ 'example.com' ] + }; + return leStore.certificates.checkAsync(certOpts).then(function (certs) { + if (!certs || certs.privkey !== 'PRIVKEY_A.PEM') { + throw new Error("should have correct certs for example.com (set by email)"); + } + }); + } + // altnames test +, function () { + var certOpts = { + domains: [ 'bar.foo.net' ] + }; + return leStore.certificates.checkAsync(certOpts).then(function (certs) { + if (!certs || certs.privkey !== 'PRIVKEY_A.PEM') { + throw new Error("should have correct certs for bar.foo.net (one of the example.com altnames)"); + } + }); + } + // altnames test +, function () { + var certOpts = { + domains: [ 'baz.net' ] + }; + return leStore.certificates.checkAsync(certOpts).then(function (certs) { + if (!certs || certs.privkey !== 'PRIVKEY_B.PEM') { + throw new Error("should have correct certs for baz.net (one of the foo.com altnames)"); + } + }); + } +]; + +var arr = tests.slice(0); + +function run() { + var test = tests.shift(); + if (!test) { + console.info('All tests passed'); + return; + } + + test().then(run, function (err) { + var index = arr.length - tests.length - 1; + console.error(''); + console.error(arr[index].toString()); + console.error(''); + console.error(err.stack); + console.error(''); + console.error('Failed Test #' + index); + }); +} + +run(); diff --git a/tests/relationships.js b/tests/relationships.js new file mode 100644 index 0000000..c110674 --- /dev/null +++ b/tests/relationships.js @@ -0,0 +1,3 @@ +'use strict'; + +throw new Error("Tests not implemented");