From 7178a12ed54c7e708ac5b7371cfa18e7882c320b Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 16 Aug 2017 11:43:44 +0800 Subject: [PATCH 01/12] Activate ES2017 in eslint to allow async/await --- .eslintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc b/.eslintrc index 322a0f0..54caf24 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,7 @@ { "extends": "eslint:recommended", "parserOptions": { - "ecmaVersion": 6 + "ecmaVersion": 2017 }, "env": { "node": true, From 5ecc728564eff13a4b180a1feaa6370e696e9883 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 16 Aug 2017 11:49:43 +0800 Subject: [PATCH 02/12] Update dependencies for koa 2 and async/await --- package.json | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 5ae7d09..82073c4 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,11 @@ }, "dependencies": { "addressparser": "^1.0.1", - "co": "^4.6.0", - "co-body": "^5.1.1", "config": "^1.20.4", - "koa": "^1.2.0", - "koa-router": "^5.4.0", - "koa-static": "^2.0.0", + "koa": "^2.3.0", + "koa-body": "^2.3.0", + "koa-router": "^7.2.1", + "koa-static": "^4.0.1", "mongodb": "^2.2.31", "nodemailer": "^2.4.2", "nodemailer-openpgp": "^1.0.2", @@ -35,16 +34,14 @@ }, "devDependencies": { "chai": "^4.1.1", - "co-mocha": "^1.1.2", "eslint": "^4.4.1", "mocha": "^3.2.0", - "sinon": "^1.17.4", + "sinon": "^3.2.0", "supertest": "^3.0.0" }, "greenkeeper": { "ignore": [ - "nodemailer", - "sinon" + "nodemailer" ] } } From 26807e03b13de6c3f0cc9242199a3d7ccee5de34 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 16 Aug 2017 11:50:03 +0800 Subject: [PATCH 03/12] Remove co-mocha from test setup --- test/setup.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/setup.js b/test/setup.js index 31e9669..4e3ef2c 100644 --- a/test/setup.js +++ b/test/setup.js @@ -1,7 +1,5 @@ 'use strict'; -require('co-mocha')(require('mocha')); // monkey patch mocha for generators - const expect = require('chai').expect; const sinon = require('sinon'); From 874903c64b3c93743f943cb836b4219175082823 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 16 Aug 2017 12:03:32 +0800 Subject: [PATCH 04/12] Migrate mongo DAO --- src/dao/mongo.js | 4 +-- test/integration/mongo-test.js | 62 +++++++++++++++++----------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/dao/mongo.js b/src/dao/mongo.js index f1ccecc..d61d572 100644 --- a/src/dao/mongo.js +++ b/src/dao/mongo.js @@ -30,9 +30,9 @@ class Mongo { * @param {String} pass The database user's password * @yield {undefined} */ - *init({uri, user, pass}) { + async init({uri, user, pass}) { const url = `mongodb://${user}:${pass}@${uri}`; - this._db = yield MongoClient.connect(url); + this._db = await MongoClient.connect(url); } /** diff --git a/test/integration/mongo-test.js b/test/integration/mongo-test.js index fdc2abd..4f74d07 100644 --- a/test/integration/mongo-test.js +++ b/test/integration/mongo-test.js @@ -9,31 +9,31 @@ describe('Mongo Integration Tests', function() { const DB_TYPE = 'apple'; let mongo; - before(function *() { + before(async() => { mongo = new Mongo(); - yield mongo.init(config.mongo); + await mongo.init(config.mongo); }); - beforeEach(function *() { - yield mongo.clear(DB_TYPE); + beforeEach(async() => { + await mongo.clear(DB_TYPE); }); - after(function *() { - yield mongo.clear(DB_TYPE); - yield mongo.disconnect(); + after(async() => { + await mongo.clear(DB_TYPE); + await mongo.disconnect(); }); describe("create", () => { - it('should insert a document', function *() { - const r = yield mongo.create({_id: '0'}, DB_TYPE); + it('should insert a document', async() => { + const r = await mongo.create({_id: '0'}, DB_TYPE); expect(r.insertedCount).to.equal(1); }); - it('should fail if two with the same ID are inserted', function *() { - let r = yield mongo.create({_id: '0'}, DB_TYPE); + it('should fail if two with the same ID are inserted', async() => { + let r = await mongo.create({_id: '0'}, DB_TYPE); expect(r.insertedCount).to.equal(1); try { - r = yield mongo.create({_id: '0'}, DB_TYPE); + r = await mongo.create({_id: '0'}, DB_TYPE); } catch (e) { expect(e.message).to.match(/duplicate/); } @@ -41,16 +41,16 @@ describe('Mongo Integration Tests', function() { }); describe("batch", () => { - it('should insert a document', function *() { - const r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE); + it('should insert a document', async() => { + const r = await mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE); expect(r.insertedCount).to.equal(2); }); - it('should fail if docs with the same ID are inserted', function *() { - let r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE); + it('should fail if docs with the same ID are inserted', async() => { + let r = await mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE); expect(r.insertedCount).to.equal(2); try { - r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE); + r = await mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE); } catch (e) { expect(e.message).to.match(/duplicate/); } @@ -58,36 +58,36 @@ describe('Mongo Integration Tests', function() { }); describe("update", () => { - it('should update a document', function *() { - let r = yield mongo.create({_id: '0'}, DB_TYPE); - r = yield mongo.update({_id: '0'}, {foo: 'bar'}, DB_TYPE); + it('should update a document', async() => { + let r = await mongo.create({_id: '0'}, DB_TYPE); + r = await mongo.update({_id: '0'}, {foo: 'bar'}, DB_TYPE); expect(r.modifiedCount).to.equal(1); - r = yield mongo.get({_id: '0'}, DB_TYPE); + r = await mongo.get({_id: '0'}, DB_TYPE); expect(r.foo).to.equal('bar'); }); }); describe("get", () => { - it('should get a document', function *() { - let r = yield mongo.create({_id: '0'}, DB_TYPE); - r = yield mongo.get({_id: '0'}, DB_TYPE); + it('should get a document', async() => { + let r = await mongo.create({_id: '0'}, DB_TYPE); + r = await mongo.get({_id: '0'}, DB_TYPE); expect(r).to.exist; }); }); describe("list", () => { - it('should list documents', function *() { - let r = yield mongo.batch([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE); - r = yield mongo.list({foo: 'bar'}, DB_TYPE); + it('should list documents', async() => { + let r = await mongo.batch([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE); + r = await mongo.list({foo: 'bar'}, DB_TYPE); expect(r).to.deep.equal([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE); }); }); describe("remove", () => { - it('should remove a document', function *() { - let r = yield mongo.create({_id: '0'}, DB_TYPE); - r = yield mongo.remove({_id: '0'}, DB_TYPE); - r = yield mongo.get({_id: '0'}, DB_TYPE); + it('should remove a document', async() => { + let r = await mongo.create({_id: '0'}, DB_TYPE); + r = await mongo.remove({_id: '0'}, DB_TYPE); + r = await mongo.get({_id: '0'}, DB_TYPE); expect(r).to.not.exist; }); }); From ba671126dbab43067769cec46ee9627bb873510d Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 16 Aug 2017 12:27:03 +0800 Subject: [PATCH 05/12] Migrate email module --- src/email/email.js | 8 +++---- test/integration/email-test.js | 20 ++++++++--------- test/unit/email-test.js | 40 +++++++++++++++------------------- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/src/email/email.js b/src/email/email.js index 060bf22..dcaf996 100644 --- a/src/email/email.js +++ b/src/email/email.js @@ -58,7 +58,7 @@ class Email { * @param {Object} origin origin of the server * @yield {Object} send response from the SMTP server */ - *send({template, userId, keyId, origin}) { + async send({template, userId, keyId, origin}) { const message = { from: this._sender, to: userId, @@ -72,7 +72,7 @@ class Email { nonce: userId.nonce } }; - return yield this._sendHelper(message); + return this._sendHelper(message); } /** @@ -85,7 +85,7 @@ class Email { * @param {Object} params (optional) nodermailer template parameters * @yield {Object} reponse object containing SMTP info */ - *_sendHelper({from, to, subject, text, html, params = {}}) { + async _sendHelper({from, to, subject, text, html, params = {}}) { const template = { subject, text, @@ -107,7 +107,7 @@ class Email { try { const sendFn = this._transport.templateSender(template, sender); - const info = yield sendFn(recipient, params); + const info = await sendFn(recipient, params); if (!this._checkResponse(info)) { log.warn('email', 'Message may not have been received.', info); } diff --git a/test/integration/email-test.js b/test/integration/email-test.js index e414132..cf4eaa3 100644 --- a/test/integration/email-test.js +++ b/test/integration/email-test.js @@ -36,7 +36,7 @@ describe('Email Integration Tests', function() { }); describe("_sendHelper", () => { - it('should work', function *() { + it('should work', async() => { const mailOptions = { from: email._sender, to: recipient, @@ -44,30 +44,30 @@ describe('Email Integration Tests', function() { text: 'Hello world 🐴', // plaintext body html: 'Hello world 🐴' // html body }; - const info = yield email._sendHelper(mailOptions); + const info = await email._sendHelper(mailOptions); expect(info).to.exist; }); }); describe("send verifyKey template", () => { - it('should send plaintext email', function *() { + it('should send plaintext email', async() => { delete userId.publicKeyArmored; - yield email.send({template: tpl.verifyKey, userId, keyId, origin}); + await email.send({template: tpl.verifyKey, userId, keyId, origin}); }); - it('should send pgp encrypted email', function *() { - yield email.send({template: tpl.verifyKey, userId, keyId, origin}); + it('should send pgp encrypted email', async() => { + await email.send({template: tpl.verifyKey, userId, keyId, origin}); }); }); describe("send verifyRemove template", () => { - it('should send plaintext email', function *() { + it('should send plaintext email', async() => { delete userId.publicKeyArmored; - yield email.send({template: tpl.verifyRemove, userId, keyId, origin}); + await email.send({template: tpl.verifyRemove, userId, keyId, origin}); }); - it('should send pgp encrypted email', function *() { - yield email.send({template: tpl.verifyRemove, userId, keyId, origin}); + it('should send pgp encrypted email', async() => { + await email.send({template: tpl.verifyRemove, userId, keyId, origin}); }); }); }); diff --git a/test/unit/email-test.js b/test/unit/email-test.js index 7c14b6b..837a2e3 100644 --- a/test/unit/email-test.js +++ b/test/unit/email-test.js @@ -5,6 +5,7 @@ const Email = require('../../src/email/email'); const nodemailer = require('nodemailer'); describe('Email Unit Tests', () => { + let sandbox; let email; let sendFnStub; @@ -36,13 +37,14 @@ describe('Email Unit Tests', () => { }; beforeEach(() => { + sandbox = sinon.sandbox.create(); + sendFnStub = sinon.stub(); - sinon.stub(nodemailer, 'createTransport').returns({ + sandbox.stub(nodemailer, 'createTransport').returns({ templateSender: () => sendFnStub }); - sinon.stub(log, 'warn'); - sinon.stub(log, 'error'); + sandbox.stub(log); email = new Email(nodemailer); email.init({ @@ -54,50 +56,44 @@ describe('Email Unit Tests', () => { }); afterEach(() => { - nodemailer.createTransport.restore(); - log.warn.restore(); - log.error.restore(); + sandbox.restore(); }); describe("send", () => { beforeEach(() => { - sinon.stub(email, '_sendHelper').returns(Promise.resolve({response: '250'})); + sandbox.stub(email, '_sendHelper').resolves({response: '250'}); }); - afterEach(() => { - email._sendHelper.restore(); - }); - - it('should work', function *() { - const info = yield email.send({template, userId: userId1, keyId, origin}); + it('should work', async() => { + const info = await email.send({template, userId: userId1, keyId, origin}); expect(info.response).to.match(/^250/); }); }); describe("_sendHelper", () => { - it('should work', function *() { - sendFnStub.returns(Promise.resolve({response: '250'})); + it('should work', async() => { + sendFnStub.resolves({response: '250'}); - const info = yield email._sendHelper(mailOptions); + const info = await email._sendHelper(mailOptions); expect(info.response).to.match(/^250/); }); - it('should log warning for reponse error', function *() { - sendFnStub.returns(Promise.resolve({response: '554'})); + it('should log warning for reponse error', async() => { + sendFnStub.resolves({response: '554'}); - const info = yield email._sendHelper(mailOptions); + const info = await email._sendHelper(mailOptions); expect(info.response).to.match(/^554/); expect(log.warn.calledOnce).to.be.true; }); - it('should fail', function *() { - sendFnStub.returns(Promise.reject(new Error('boom'))); + it('should fail', async() => { + sendFnStub.rejects(new Error('boom')); try { - yield email._sendHelper(mailOptions); + await email._sendHelper(mailOptions); } catch (e) { expect(log.error.calledOnce).to.be.true; expect(e.status).to.equal(500); From 5778f8fa13019ab78930307e9b86bde540dd55b2 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 16 Aug 2017 16:55:28 +0800 Subject: [PATCH 06/12] Migrate pgp-test to sinon sandbox --- test/unit/pgp-test.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/unit/pgp-test.js b/test/unit/pgp-test.js index 455e273..338ef74 100644 --- a/test/unit/pgp-test.js +++ b/test/unit/pgp-test.js @@ -6,47 +6,50 @@ const openpgp = require('openpgp'); const PGP = require('../../src/service/pgp'); describe('PGP Unit Tests', () => { + let sandbox; let pgp; let key1Armored; let key2Armored; let key3Armored; beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.stub(log); + key1Armored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8'); key2Armored = fs.readFileSync(`${__dirname}/../key2.asc`, 'utf8'); key3Armored = fs.readFileSync(`${__dirname}/../key3.asc`, 'utf8'); pgp = new PGP(); }); + afterEach(() => { + sandbox.restore(); + }); + describe('parseKey', () => { it('should should throw error on key parsing', () => { - const readStub = sinon.stub(openpgp.key, 'readArmored').returns({err: [new Error()]}); - sinon.stub(log, 'error'); + sandbox.stub(openpgp.key, 'readArmored').returns({err: [new Error()]}); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/Failed to parse/); expect(log.error.calledOnce).to.be.true; - log.error.restore(); - readStub.restore(); }); it('should should throw error when more than one key', () => { - const readStub = sinon.stub(openpgp.key, 'readArmored').returns({keys: [{}, {}]}); + sandbox.stub(openpgp.key, 'readArmored').returns({keys: [{}, {}]}); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only one key/); - readStub.restore(); }); it('should should throw error when more than one key', () => { - const readStub = sinon.stub(openpgp.key, 'readArmored').returns({ + sandbox.stub(openpgp.key, 'readArmored').returns({ keys: [{ primaryKey: {}, verifyPrimaryKey() { return false; } }] }); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/primary key verification/); - readStub.restore(); }); it('should only accept 16 char key id', () => { - const readStub = sinon.stub(openpgp.key, 'readArmored').returns({ + sandbox.stub(openpgp.key, 'readArmored').returns({ keys: [{ primaryKey: { fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e9', @@ -60,11 +63,10 @@ describe('PGP Unit Tests', () => { }] }); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/); - readStub.restore(); }); it('should only accept version 4 fingerprint', () => { - const readStub = sinon.stub(openpgp.key, 'readArmored').returns({ + sandbox.stub(openpgp.key, 'readArmored').returns({ keys: [{ primaryKey: { fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e', @@ -78,11 +80,10 @@ describe('PGP Unit Tests', () => { }] }); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/); - readStub.restore(); }); it('should only accept valid user ids', () => { - sinon.stub(pgp, 'parseUserIds').returns([]); + sandbox.stub(pgp, 'parseUserIds').returns([]); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/invalid user ids/); }); @@ -182,11 +183,10 @@ describe('PGP Unit Tests', () => { }); it('should throw for a invalid email address', () => { - const verifyStub = sinon.stub(key.users[0], 'isValidSelfCertificate').returns(true); + sandbox.stub(key.users[0], 'isValidSelfCertificate').returns(true); key.users[0].userId.userid = 'safewithme testuser '; const parsed = pgp.parseUserIds(key.users, key.primaryKey); expect(parsed.length).to.equal(0); - verifyStub.restore(); }); }); }); From 59a77fd01e850d5886cf68bf5006fd1fe66a59fa Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 16 Aug 2017 17:39:55 +0800 Subject: [PATCH 07/12] Go back to sinon v1.x for now due to failing tests. --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 82073c4..9e27f6a 100644 --- a/package.json +++ b/package.json @@ -36,12 +36,13 @@ "chai": "^4.1.1", "eslint": "^4.4.1", "mocha": "^3.2.0", - "sinon": "^3.2.0", + "sinon": "^1.17.4", "supertest": "^3.0.0" }, "greenkeeper": { "ignore": [ - "nodemailer" + "nodemailer", + "sinon" ] } } From 1557a5f925b3429dd1e0bf3a3f67d865384fa443 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 16 Aug 2017 17:55:32 +0800 Subject: [PATCH 08/12] Migrate public-key service to async/await --- src/service/public-key.js | 54 +++---- test/integration/public-key-test.js | 221 ++++++++++++++-------------- 2 files changed, 139 insertions(+), 136 deletions(-) diff --git a/src/service/public-key.js b/src/service/public-key.js index 3e567ab..74e5937 100644 --- a/src/service/public-key.js +++ b/src/service/public-key.js @@ -65,18 +65,18 @@ class PublicKey { * @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' } * @yield {undefined} */ - *put({publicKeyArmored, primaryEmail, origin}) { + async put({publicKeyArmored, primaryEmail, origin}) { // parse key block const key = this._pgp.parseKey(publicKeyArmored); // check for existing verfied key by id or email addresses - const verified = yield this.getVerified(key); + const verified = await this.getVerified(key); if (verified) { util.throw(304, 'Key for this user already exists'); } // store key in database - yield this._persisKey(key); + await this._persisKey(key); // send mails to verify user ids (send only one if primary email is provided) - yield this._sendVerifyEmail(key, primaryEmail, origin); + await this._sendVerifyEmail(key, primaryEmail, origin); } /** @@ -84,15 +84,15 @@ class PublicKey { * @param {Object} key public key parameters * @yield {undefined} The persisted user id documents */ - *_persisKey(key) { + async _persisKey(key) { // delete old/unverified key - yield this._mongo.remove({keyId: key.keyId}, DB_TYPE); + await this._mongo.remove({keyId: key.keyId}, DB_TYPE); // generate nonces for verification for (const uid of key.userIds) { uid.nonce = util.random(); } // persist new key - const r = yield this._mongo.create(key, DB_TYPE); + const r = await this._mongo.create(key, DB_TYPE); if (r.insertedCount !== 1) { util.throw(500, 'Failed to persist key'); } @@ -106,7 +106,7 @@ class PublicKey { * @param {Object} origin the server's origin (required for email links) * @yield {undefined} */ - *_sendVerifyEmail({userIds, keyId, publicKeyArmored}, primaryEmail, origin) { + async _sendVerifyEmail({userIds, keyId, publicKeyArmored}, primaryEmail, origin) { // check for primary email (send only one email) const primaryUserId = userIds.find(uid => uid.email === primaryEmail); if (primaryUserId) { @@ -115,7 +115,7 @@ class PublicKey { // send emails for (const userId of userIds) { userId.publicKeyArmored = publicKeyArmored; // set key for encryption - yield this._email.send({template: tpl.verifyKey, userId, keyId, origin}); + await this._email.send({template: tpl.verifyKey, userId, keyId, origin}); } } @@ -125,20 +125,20 @@ class PublicKey { * @param {string} nonce The verification nonce proving email address ownership * @yield {undefined} */ - *verify({keyId, nonce}) { + async verify({keyId, nonce}) { // look for verification nonce in database const query = {keyId, 'userIds.nonce': nonce}; - const key = yield this._mongo.get(query, DB_TYPE); + const key = await this._mongo.get(query, DB_TYPE); if (!key) { util.throw(404, 'User id not found'); } // check if user ids of this key have already been verified in another key - const verified = yield this.getVerified(key); + const verified = await this.getVerified(key); if (verified && verified.keyId !== keyId) { util.throw(304, 'Key for this user already exists'); } // flag the user id as verified - yield this._mongo.update(query, { + await this._mongo.update(query, { 'userIds.$.verified': true, 'userIds.$.nonce': null }, DB_TYPE); @@ -153,7 +153,7 @@ class PublicKey { * @param {string} keyId (optional) The public key id * @yield {Object} The verified key document */ - *getVerified({userIds, fingerprint, keyId}) { + async getVerified({userIds, fingerprint, keyId}) { let queries = []; // query by fingerprint if (fingerprint) { @@ -180,7 +180,7 @@ class PublicKey { } }))); } - return yield this._mongo.get({$or: queries}, DB_TYPE); + return this._mongo.get({$or: queries}, DB_TYPE); } /** @@ -191,10 +191,10 @@ class PublicKey { * @param {String} email (optional) The user's email address * @yield {Object} The public key document */ - *get({fingerprint, keyId, email}) { + async get({fingerprint, keyId, email}) { // look for verified key const userIds = email ? [{email}] : undefined; - const key = yield this.getVerified({keyId, fingerprint, userIds}); + const key = await this.getVerified({keyId, fingerprint, userIds}); if (!key) { util.throw(404, 'Key not found'); } @@ -218,16 +218,16 @@ class PublicKey { * @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' } * @yield {undefined} */ - *requestRemove({keyId, email, origin}) { + async requestRemove({keyId, email, origin}) { // flag user ids for removal - const key = yield this._flagForRemove(keyId, email); + const key = await this._flagForRemove(keyId, email); if (!key) { util.throw(404, 'User id not found'); } // send verification mails keyId = key.keyId; // get keyId in case request was by email for (const userId of key.userIds) { - yield this._email.send({template: tpl.verifyRemove, userId, keyId, origin}); + await this._email.send({template: tpl.verifyRemove, userId, keyId, origin}); } } @@ -238,16 +238,16 @@ class PublicKey { * @param {String} email (optional) The user's email address * @yield {Array} A list of user ids with nonces */ - *_flagForRemove(keyId, email) { + async _flagForRemove(keyId, email) { const query = email ? {'userIds.email': email} : {keyId}; - const key = yield this._mongo.get(query, DB_TYPE); + const key = await this._mongo.get(query, DB_TYPE); if (!key) { return; } // flag only the provided user id if (email) { const nonce = util.random(); - yield this._mongo.update(query, {'userIds.$.nonce': nonce}, DB_TYPE); + await this._mongo.update(query, {'userIds.$.nonce': nonce}, DB_TYPE); const uid = key.userIds.find(u => u.email === email); uid.nonce = nonce; return {userIds: [uid], keyId: key.keyId}; @@ -256,7 +256,7 @@ class PublicKey { if (keyId) { for (const uid of key.userIds) { const nonce = util.random(); - yield this._mongo.update({'userIds.email': uid.email}, {'userIds.$.nonce': nonce}, DB_TYPE); + await this._mongo.update({'userIds.email': uid.email}, {'userIds.$.nonce': nonce}, DB_TYPE); uid.nonce = nonce; } return key; @@ -270,14 +270,14 @@ class PublicKey { * @param {string} nonce The verification nonce proving email address ownership * @yield {undefined} */ - *verifyRemove({keyId, nonce}) { + async verifyRemove({keyId, nonce}) { // check if key exists in database - const flagged = yield this._mongo.get({keyId, 'userIds.nonce': nonce}, DB_TYPE); + const flagged = await this._mongo.get({keyId, 'userIds.nonce': nonce}, DB_TYPE); if (!flagged) { util.throw(404, 'User id not found'); } // delete the key - yield this._mongo.remove({keyId}, DB_TYPE); + await this._mongo.remove({keyId}, DB_TYPE); } } diff --git a/test/integration/public-key-test.js b/test/integration/public-key-test.js index 964323a..b889870 100644 --- a/test/integration/public-key-test.js +++ b/test/integration/public-key-test.js @@ -10,6 +10,7 @@ const PublicKey = require('../../src/service/public-key'); describe('Public Key Integration Tests', function() { this.timeout(20000); + let sandbox; let publicKey; let email; let mongo; @@ -24,15 +25,17 @@ describe('Public Key Integration Tests', function() { const primaryEmail2 = 'test2@example.com'; const origin = {host: 'localhost', protocol: 'http'}; - before(function *() { + before(async() => { publicKeyArmored = require('fs').readFileSync(`${__dirname}/../key3.asc`, 'utf8'); publicKeyArmored2 = require('fs').readFileSync(`${__dirname}/../key4.asc`, 'utf8'); mongo = new Mongo(); - yield mongo.init(config.mongo); + await mongo.init(config.mongo); }); - beforeEach(function *() { - yield mongo.clear(DB_TYPE); + beforeEach(async() => { + sandbox = sinon.sandbox.create(); + + await mongo.clear(DB_TYPE); mailsSent = []; sendEmailStub = sinon.stub().returns(Promise.resolve({response: '250'})); sendEmailStub.withArgs(sinon.match(recipient => { @@ -44,7 +47,7 @@ describe('Public Key Integration Tests', function() { expect(params.keyId).to.exist; return true; })); - sinon.stub(nodemailer, 'createTransport').returns({ + sandbox.stub(nodemailer, 'createTransport').returns({ templateSender: () => sendEmailStub }); email = new Email(nodemailer); @@ -58,39 +61,39 @@ describe('Public Key Integration Tests', function() { }); afterEach(() => { - nodemailer.createTransport.restore(); + sandbox.restore(); }); - after(function *() { - yield mongo.clear(DB_TYPE); - yield mongo.disconnect(); + after(async() => { + await mongo.clear(DB_TYPE); + await mongo.disconnect(); }); describe('put', () => { - it('should persist key and send verification email with primaryEmail', function *() { - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + it('should persist key and send verification email with primaryEmail', async() => { + await publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(mailsSent.length).to.equal(1); expect(mailsSent[0].to).to.equal(primaryEmail); expect(mailsSent[0].params.keyId).to.exist; expect(mailsSent[0].params.nonce).to.exist; }); - it('should persist key and send verification email without primaryEmail', function *() { - yield publicKey.put({publicKeyArmored, origin}); + it('should persist key and send verification email without primaryEmail', async() => { + await publicKey.put({publicKeyArmored, origin}); expect(mailsSent.length).to.equal(4); }); - it('should work twice if not yet verified', function *() { - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + it('should work twice if not yet verified', async() => { + await publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(mailsSent.length).to.equal(1); - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(mailsSent.length).to.equal(2); }); - it('should throw 304 if key already exists', function *() { - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); - yield publicKey.verify(mailsSent[0].params); + it('should throw 304 if key already exists', async() => { + await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.verify(mailsSent[0].params); try { - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(false).to.be.true; } catch (e) { expect(e.status).to.equal(304); @@ -99,60 +102,60 @@ describe('Public Key Integration Tests', function() { }); describe('verify', () => { - it('should update the document', function *() { - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + it('should update the document', async() => { + await publicKey.put({publicKeyArmored, primaryEmail, origin}); const emailParams = mailsSent[0].params; - yield publicKey.verify(emailParams); - const gotten = yield mongo.get({keyId: emailParams.keyId}, DB_TYPE); + await publicKey.verify(emailParams); + const gotten = await mongo.get({keyId: emailParams.keyId}, DB_TYPE); expect(gotten.userIds[0].verified).to.be.true; expect(gotten.userIds[0].nonce).to.be.null; expect(gotten.userIds[1].verified).to.be.false; expect(gotten.userIds[1].nonce).to.exist; }); - it('should not find the document', function *() { - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + it('should not find the document', async() => { + await publicKey.put({publicKeyArmored, primaryEmail, origin}); const emailParams = mailsSent[0].params; try { - yield publicKey.verify({keyId: emailParams.keyId, nonce: 'fake_nonce'}); + await publicKey.verify({keyId: emailParams.keyId, nonce: 'fake_nonce'}); expect(true).to.be.false; } catch (e) { expect(e.status).to.equal(404); } - const gotten = yield mongo.get({keyId: emailParams.keyId}, DB_TYPE); + const gotten = await mongo.get({keyId: emailParams.keyId}, DB_TYPE); expect(gotten.userIds[0].verified).to.be.false; expect(gotten.userIds[0].nonce).to.equal(emailParams.nonce); expect(gotten.userIds[1].verified).to.be.false; expect(gotten.userIds[1].nonce).to.exist; }); - it('should not verify a second key for already verified user id of another key', function *() { - yield publicKey.put({publicKeyArmored, primaryEmail: primaryEmail2, origin}); + it('should not verify a second key for already verified user id of another key', async() => { + await publicKey.put({publicKeyArmored, primaryEmail: primaryEmail2, origin}); expect(mailsSent.length).to.equal(1); - yield publicKey.put({publicKeyArmored: publicKeyArmored2, primaryEmail: primaryEmail2, origin}); + await publicKey.put({publicKeyArmored: publicKeyArmored2, primaryEmail: primaryEmail2, origin}); expect(mailsSent.length).to.equal(2); - yield publicKey.verify(mailsSent[1].params); + await publicKey.verify(mailsSent[1].params); try { - yield publicKey.verify(mailsSent[0].params); + await publicKey.verify(mailsSent[0].params); expect(true).to.be.false; } catch (e) { expect(e.status).to.equal(304); } - const gotten = yield mongo.get({keyId: mailsSent[0].params.keyId}, DB_TYPE); + const gotten = await mongo.get({keyId: mailsSent[0].params.keyId}, DB_TYPE); expect(gotten.userIds[1].email).to.equal(primaryEmail2); expect(gotten.userIds[1].verified).to.be.false; expect(gotten.userIds[1].nonce).to.equal(mailsSent[0].params.nonce); }); - it('should be able to verify multiple user ids', function *() { - yield publicKey.put({publicKeyArmored, origin}); + it('should be able to verify multiple user ids', async() => { + await publicKey.put({publicKeyArmored, origin}); expect(mailsSent.length).to.equal(4); - yield publicKey.verify(mailsSent[0].params); - yield publicKey.verify(mailsSent[1].params); - yield publicKey.verify(mailsSent[2].params); - yield publicKey.verify(mailsSent[3].params); - const gotten = yield mongo.get({keyId: mailsSent[0].params.keyId}, DB_TYPE); + await publicKey.verify(mailsSent[0].params); + await publicKey.verify(mailsSent[1].params); + await publicKey.verify(mailsSent[2].params); + await publicKey.verify(mailsSent[3].params); + const gotten = await mongo.get({keyId: mailsSent[0].params.keyId}, DB_TYPE); expect(gotten.userIds[0].verified).to.be.true; expect(gotten.userIds[1].verified).to.be.true; expect(gotten.userIds[2].verified).to.be.true; @@ -164,67 +167,67 @@ describe('Public Key Integration Tests', function() { let key; describe('should find a verified key', () => { - beforeEach(function *() { + beforeEach(async() => { key = pgp.parseKey(publicKeyArmored); - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); - yield publicKey.verify(mailsSent[0].params); + await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.verify(mailsSent[0].params); }); - it('by fingerprint', function *() { - const verified = yield publicKey.getVerified({fingerprint: key.fingerprint}); + it('by fingerprint', async() => { + const verified = await publicKey.getVerified({fingerprint: key.fingerprint}); expect(verified).to.exist; }); - it('by all userIds', function *() { - const verified = yield publicKey.getVerified({userIds: key.userIds}); + it('by all userIds', async() => { + const verified = await publicKey.getVerified({userIds: key.userIds}); expect(verified).to.exist; }); - it('by verified userId', function *() { - const verified = yield publicKey.getVerified({userIds: [key.userIds[0]]}); + it('by verified userId', async() => { + const verified = await publicKey.getVerified({userIds: [key.userIds[0]]}); expect(verified).to.exist; }); - it('by unverified userId', function *() { - const verified = yield publicKey.getVerified({userIds: [key.userIds[1]]}); + it('by unverified userId', async() => { + const verified = await publicKey.getVerified({userIds: [key.userIds[1]]}); expect(verified).to.not.exist; }); - it('by keyId', function *() { - const verified = yield publicKey.getVerified({keyId: key.keyId}); + it('by keyId', async() => { + const verified = await publicKey.getVerified({keyId: key.keyId}); expect(verified).to.exist; }); - it('by all params', function *() { - const verified = yield publicKey.getVerified(key); + it('by all params', async() => { + const verified = await publicKey.getVerified(key); expect(verified).to.exist; }); }); describe('should not find an unverified key', () => { - beforeEach(function *() { + beforeEach(async() => { key = pgp.parseKey(publicKeyArmored); key.userIds[0].verified = false; - yield mongo.create(key, DB_TYPE); + await mongo.create(key, DB_TYPE); }); - it('by fingerprint', function *() { - const verified = yield publicKey.getVerified({fingerprint: key.fingerprint}); + it('by fingerprint', async() => { + const verified = await publicKey.getVerified({fingerprint: key.fingerprint}); expect(verified).to.not.exist; }); - it('by userIds', function *() { - const verified = yield publicKey.getVerified({userIds: key.userIds}); + it('by userIds', async() => { + const verified = await publicKey.getVerified({userIds: key.userIds}); expect(verified).to.not.exist; }); - it('by keyId', function *() { - const verified = yield publicKey.getVerified({keyId: key.keyId}); + it('by keyId', async() => { + const verified = await publicKey.getVerified({keyId: key.keyId}); expect(verified).to.not.exist; }); - it('by all params', function *() { - const verified = yield publicKey.getVerified(key); + it('by all params', async() => { + const verified = await publicKey.getVerified(key); expect(verified).to.not.exist; }); }); @@ -233,52 +236,52 @@ describe('Public Key Integration Tests', function() { describe('get', () => { let emailParams; - beforeEach(function *() { - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + beforeEach(async() => { + await publicKey.put({publicKeyArmored, primaryEmail, origin}); emailParams = mailsSent[0].params; }); - it('should return verified key by key id', function *() { - yield publicKey.verify(emailParams); - const key = yield publicKey.get({keyId: emailParams.keyId}); + it('should return verified key by key id', async() => { + await publicKey.verify(emailParams); + const key = await publicKey.get({keyId: emailParams.keyId}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by key id (uppercase)', function *() { - yield publicKey.verify(emailParams); - const key = yield publicKey.get({keyId: emailParams.keyId.toUpperCase()}); + it('should return verified key by key id (uppercase)', async() => { + await publicKey.verify(emailParams); + const key = await publicKey.get({keyId: emailParams.keyId.toUpperCase()}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by fingerprint', function *() { - yield publicKey.verify(emailParams); + it('should return verified key by fingerprint', async() => { + await publicKey.verify(emailParams); const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint; - const key = yield publicKey.get({fingerprint}); + const key = await publicKey.get({fingerprint}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by fingerprint (uppercase)', function *() { - yield publicKey.verify(emailParams); + it('should return verified key by fingerprint (uppercase)', async() => { + await publicKey.verify(emailParams); const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint.toUpperCase(); - const key = yield publicKey.get({fingerprint}); + const key = await publicKey.get({fingerprint}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by email address', function *() { - yield publicKey.verify(emailParams); - const key = yield publicKey.get({email: primaryEmail}); + it('should return verified key by email address', async() => { + await publicKey.verify(emailParams); + const key = await publicKey.get({email: primaryEmail}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by email address (uppercase)', function *() { - yield publicKey.verify(emailParams); - const key = yield publicKey.get({email: primaryEmail.toUpperCase()}); + it('should return verified key by email address (uppercase)', async() => { + await publicKey.verify(emailParams); + const key = await publicKey.get({email: primaryEmail.toUpperCase()}); expect(key.publicKeyArmored).to.exist; }); - it('should throw 404 for unverified key', function *() { + it('should throw 404 for unverified key', async() => { try { - yield publicKey.get({keyId: emailParams.keyId}); + await publicKey.get({keyId: emailParams.keyId}); expect(false).to.be.true; } catch (e) { expect(e.status).to.equal(404); @@ -289,31 +292,31 @@ describe('Public Key Integration Tests', function() { describe('requestRemove', () => { let keyId; - beforeEach(function *() { - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + beforeEach(async() => { + await publicKey.put({publicKeyArmored, primaryEmail, origin}); keyId = mailsSent[0].params.keyId; }); - it('should work for verified key', function *() { - yield publicKey.verify(mailsSent[0].params); - yield publicKey.requestRemove({keyId, origin}); + it('should work for verified key', async() => { + await publicKey.verify(mailsSent[0].params); + await publicKey.requestRemove({keyId, origin}); expect(mailsSent.length).to.equal(5); }); - it('should work for unverified key', function *() { - yield publicKey.requestRemove({keyId, origin}); + it('should work for unverified key', async() => { + await publicKey.requestRemove({keyId, origin}); expect(mailsSent.length).to.equal(5); }); - it('should work by email address', function *() { - yield publicKey.requestRemove({email: primaryEmail, origin}); + it('should work by email address', async() => { + await publicKey.requestRemove({email: primaryEmail, origin}); expect(mailsSent.length).to.equal(2); }); - it('should throw 404 for no key', function *() { - yield mongo.remove({keyId}, DB_TYPE); + it('should throw 404 for no key', async() => { + await mongo.remove({keyId}, DB_TYPE); try { - yield publicKey.requestRemove({keyId, origin}); + await publicKey.requestRemove({keyId, origin}); expect(false).to.be.true; } catch (e) { expect(e.status).to.equal(404); @@ -324,22 +327,22 @@ describe('Public Key Integration Tests', function() { describe('verifyRemove', () => { let keyId; - beforeEach(function *() { - yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + beforeEach(async() => { + await publicKey.put({publicKeyArmored, primaryEmail, origin}); keyId = mailsSent[0].params.keyId; - yield publicKey.requestRemove({keyId, origin}); + await publicKey.requestRemove({keyId, origin}); }); - it('should remove key', function *() { - yield publicKey.verifyRemove(mailsSent[1].params); - const key = yield mongo.get({keyId}, DB_TYPE); + it('should remove key', async() => { + await publicKey.verifyRemove(mailsSent[1].params); + const key = await mongo.get({keyId}, DB_TYPE); expect(key).to.not.exist; }); - it('should throw 404 for no key', function *() { - yield mongo.remove({keyId}, DB_TYPE); + it('should throw 404 for no key', async() => { + await mongo.remove({keyId}, DB_TYPE); try { - yield publicKey.verifyRemove(mailsSent[1].params); + await publicKey.verifyRemove(mailsSent[1].params); expect(false).to.be.true; } catch (e) { expect(e.status).to.equal(404); From 3dfa447fcf6a2eb2336c7ebed35aeefad3162192 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 16 Aug 2017 17:57:33 +0800 Subject: [PATCH 09/12] Revert resolves/rejects changes in email unit test. --- test/unit/email-test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/email-test.js b/test/unit/email-test.js index 837a2e3..294eca2 100644 --- a/test/unit/email-test.js +++ b/test/unit/email-test.js @@ -61,7 +61,7 @@ describe('Email Unit Tests', () => { describe("send", () => { beforeEach(() => { - sandbox.stub(email, '_sendHelper').resolves({response: '250'}); + sandbox.stub(email, '_sendHelper').returns(Promise.resolve({response: '250'})); }); it('should work', async() => { @@ -73,7 +73,7 @@ describe('Email Unit Tests', () => { describe("_sendHelper", () => { it('should work', async() => { - sendFnStub.resolves({response: '250'}); + sendFnStub.returns(Promise.resolve({response: '250'})); const info = await email._sendHelper(mailOptions); @@ -81,7 +81,7 @@ describe('Email Unit Tests', () => { }); it('should log warning for reponse error', async() => { - sendFnStub.resolves({response: '554'}); + sendFnStub.returns(Promise.resolve({response: '554'})); const info = await email._sendHelper(mailOptions); @@ -90,7 +90,7 @@ describe('Email Unit Tests', () => { }); it('should fail', async() => { - sendFnStub.rejects(new Error('boom')); + sendFnStub.returns(Promise.reject(new Error('boom'))); try { await email._sendHelper(mailOptions); From 49b24a5cb4eb9c716915dcfa300838fce3b74e31 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Thu, 17 Aug 2017 15:34:47 +0800 Subject: [PATCH 10/12] Migrate to koa 2 Refactor rest api to async/await --- src/app.js | 77 ++++++++++++++++++------------------ src/route/rest.js | 25 ++++++------ test/integration/app-test.js | 32 ++++++++------- 3 files changed, 68 insertions(+), 66 deletions(-) diff --git a/src/app.js b/src/app.js index 61bbf94..1121ac6 100644 --- a/src/app.js +++ b/src/app.js @@ -17,8 +17,8 @@ 'use strict'; -const co = require('co'); -const app = require('koa')(); +const Koa = require('koa'); +const koaBody = require('koa-body'); const log = require('npmlog'); const config = require('config'); const serve = require('koa-static'); @@ -31,6 +31,8 @@ const PublicKey = require('./service/public-key'); const HKP = require('./route/hkp'); const REST = require('./route/rest'); +const app = new Koa(); + let mongo; let email; let pgp; @@ -43,55 +45,50 @@ let rest; // // HKP routes -router.post('/pks/add', function *() { - yield hkp.add(this); -}); -router.get('/pks/lookup', function *() { - yield hkp.lookup(this); -}); +router.post('/pks/add', ctx => hkp.add(ctx)); +router.get('/pks/lookup', ctx => hkp.lookup(ctx)); // REST api routes -router.post('/api/v1/key', function *() { - yield rest.create(this); -}); -router.get('/api/v1/key', function *() { - yield rest.query(this); -}); -router.del('/api/v1/key', function *() { - yield rest.remove(this); -}); +router.post('/api/v1/key', ctx => rest.create(ctx)); +router.get('/api/v1/key', ctx => rest.query(ctx)); +router.del('/api/v1/key', ctx => rest.remove(ctx)); // Redirect all http traffic to https -app.use(function *(next) { - if (util.isTrue(config.server.httpsUpgrade) && util.checkHTTP(this)) { - this.redirect(`https://${this.hostname}${this.url}`); +app.use(async(ctx, next) => { + if (util.isTrue(config.server.httpsUpgrade) && util.checkHTTP(ctx)) { + ctx.redirect(`https://${ctx.hostname}${ctx.url}`); } else { - yield next; + await next(); } }); // Set HTTP response headers -app.use(function *(next) { +app.use(async(ctx, next) => { // HSTS if (util.isTrue(config.server.httpsUpgrade)) { - this.set('Strict-Transport-Security', 'max-age=16070400'); + ctx.set('Strict-Transport-Security', 'max-age=16070400'); } // HPKP if (config.server.httpsKeyPin && config.server.httpsKeyPinBackup) { - this.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`); + ctx.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`); } // CSP - this.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; script-src 'self' code.jquery.com; style-src 'self' maxcdn.bootstrapcdn.com; font-src 'self' maxcdn.bootstrapcdn.com"); + ctx.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; script-src 'self' code.jquery.com; style-src 'self' maxcdn.bootstrapcdn.com; font-src 'self' maxcdn.bootstrapcdn.com"); // Prevent rendering website in foreign iframe (Clickjacking) - this.set('X-Frame-Options', 'DENY'); + ctx.set('X-Frame-Options', 'DENY'); // CORS - this.set('Access-Control-Allow-Origin', '*'); - this.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); - this.set('Access-Control-Allow-Headers', 'Content-Type'); - this.set('Connection', 'keep-alive'); - yield next; + ctx.set('Access-Control-Allow-Origin', '*'); + ctx.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); + ctx.set('Access-Control-Allow-Headers', 'Content-Type'); + ctx.set('Connection', 'keep-alive'); + await next(); }); +app.use(koaBody({ + multipart: true, + formLimit: '1mb' +})); + app.use(router.routes()); app.use(router.allowedMethods()); @@ -124,19 +121,23 @@ function injectDependencies() { // if (!global.testing) { // don't automatically start server in tests - co(function *() { - const app = yield init(); - app.listen(config.server.port); - log.info('app', `Ready to rock! Listening on http://localhost:${config.server.port}`); - }).catch(err => log.error('app', 'Initialization failed!', err)); + (async() => { + try { + const app = await init(); + app.listen(config.server.port); + log.info('app', `Ready to rock! Listening on http://localhost:${config.server.port}`); + } catch (err) { + log.error('app', 'Initialization failed!', err); + } + })(); } -function *init() { +async function init() { log.level = config.log.level; // set log level depending on process.env.NODE_ENV injectDependencies(); email.init(config.email); log.info('app', 'Connecting to MongoDB ...'); - yield mongo.init(config.mongo); + await mongo.init(config.mongo); return app; } diff --git a/src/route/rest.js b/src/route/rest.js index ae47f29..af386cf 100644 --- a/src/route/rest.js +++ b/src/route/rest.js @@ -17,7 +17,6 @@ 'use strict'; -const parse = require('co-body'); const util = require('../service/util'); /** @@ -37,13 +36,13 @@ class REST { * Public key upload via http POST * @param {Object} ctx The koa request/response context */ - *create(ctx) { - const {publicKeyArmored, primaryEmail} = yield parse.json(ctx, {limit: '1mb'}); + async create(ctx) { + const {publicKeyArmored, primaryEmail} = ctx.request.body; if (!publicKeyArmored || (primaryEmail && !util.isEmail(primaryEmail))) { ctx.throw(400, 'Invalid request!'); } const origin = util.origin(ctx); - yield this._publicKey.put({publicKeyArmored, primaryEmail, origin}); + await this._publicKey.put({publicKeyArmored, primaryEmail, origin}); ctx.body = 'Upload successful. Check your inbox to verify your email address.'; ctx.status = 201; } @@ -52,29 +51,29 @@ class REST { * Public key query via http GET * @param {Object} ctx The koa request/response context */ - *query(ctx) { + async query(ctx) { const op = ctx.query.op; if (op === 'verify' || op === 'verifyRemove') { - return yield this[op](ctx); // delegate operation + return this[op](ctx); // delegate operation } // do READ if no 'op' provided const q = {keyId: ctx.query.keyId, fingerprint: ctx.query.fingerprint, email: ctx.query.email}; if (!util.isKeyId(q.keyId) && !util.isFingerPrint(q.fingerprint) && !util.isEmail(q.email)) { ctx.throw(400, 'Invalid request!'); } - ctx.body = yield this._publicKey.get(q); + ctx.body = await this._publicKey.get(q); } /** * Verify a public key's user id via http GET * @param {Object} ctx The koa request/response context */ - *verify(ctx) { + async verify(ctx) { const q = {keyId: ctx.query.keyId, nonce: ctx.query.nonce}; if (!util.isKeyId(q.keyId) || !util.isString(q.nonce)) { ctx.throw(400, 'Invalid request!'); } - yield this._publicKey.verify(q); + await this._publicKey.verify(q); // create link for sharing const link = util.url(util.origin(ctx), `/pks/lookup?op=get&search=0x${q.keyId.toUpperCase()}`); ctx.body = `

Email address successfully verified!

Link to share your key: ${link}

`; @@ -85,12 +84,12 @@ class REST { * Request public key removal via http DELETE * @param {Object} ctx The koa request/response context */ - *remove(ctx) { + async remove(ctx) { const q = {keyId: ctx.query.keyId, email: ctx.query.email, origin: util.origin(ctx)}; if (!util.isKeyId(q.keyId) && !util.isEmail(q.email)) { ctx.throw(400, 'Invalid request!'); } - yield this._publicKey.requestRemove(q); + await this._publicKey.requestRemove(q); ctx.body = 'Check your inbox to verify the removal of your key.'; ctx.status = 202; } @@ -99,12 +98,12 @@ class REST { * Verify public key removal via http GET * @param {Object} ctx The koa request/response context */ - *verifyRemove(ctx) { + async verifyRemove(ctx) { const q = {keyId: ctx.query.keyId, nonce: ctx.query.nonce}; if (!util.isKeyId(q.keyId) || !util.isString(q.nonce)) { ctx.throw(400, 'Invalid request!'); } - yield this._publicKey.verifyRemove(q); + await this._publicKey.verifyRemove(q); ctx.body = 'Key successfully removed!'; } } diff --git a/test/integration/app-test.js b/test/integration/app-test.js index 756e85c..3271646 100644 --- a/test/integration/app-test.js +++ b/test/integration/app-test.js @@ -10,6 +10,7 @@ const log = require('npmlog'); describe('Koa App (HTTP Server) Integration Tests', function() { this.timeout(20000); + let sandbox; let app; let mongo; let sendEmailStub; @@ -21,40 +22,41 @@ describe('Koa App (HTTP Server) Integration Tests', function() { const primaryEmail = 'safewithme.testuser@gmail.com'; const fingerprint = '4277257930867231CE393FB8DBC0B3D92B1B86E9'; - before(function *() { + before(async() => { + sandbox = sinon.sandbox.create(); + publicKeyArmored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8'); mongo = new Mongo(); - yield mongo.init(config.mongo); + await mongo.init(config.mongo); - sendEmailStub = sinon.stub().returns(Promise.resolve({response: '250'})); + sendEmailStub = sandbox.stub().returns(Promise.resolve({response: '250'})); sendEmailStub.withArgs(sinon.match(recipient => recipient.to.address === primaryEmail), sinon.match(params => { emailParams = params; return Boolean(params.nonce); })); - sinon.stub(nodemailer, 'createTransport').returns({ + sandbox.stub(nodemailer, 'createTransport').returns({ templateSender: () => sendEmailStub, use() {} }); - sinon.stub(log); + sandbox.stub(log); global.testing = true; const init = require('../../src/app'); - app = yield init(); + app = await init(); }); - beforeEach(function *() { - yield mongo.clear(DB_TYPE_PUB_KEY); - yield mongo.clear(DB_TYPE_USER_ID); + beforeEach(async() => { + await mongo.clear(DB_TYPE_PUB_KEY); + await mongo.clear(DB_TYPE_USER_ID); emailParams = null; }); - after(function *() { - sinon.restore(log); - nodemailer.createTransport.restore(); - yield mongo.clear(DB_TYPE_PUB_KEY); - yield mongo.clear(DB_TYPE_USER_ID); - yield mongo.disconnect(); + after(async() => { + sandbox.restore(); + await mongo.clear(DB_TYPE_PUB_KEY); + await mongo.clear(DB_TYPE_USER_ID); + await mongo.disconnect(); }); describe('REST api', () => { From 4081463dfa5ce90ef3f3433ed91fdeea0410205c Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Thu, 17 Aug 2017 15:37:59 +0800 Subject: [PATCH 11/12] Migrate HKP api --- src/route/hkp.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/route/hkp.js b/src/route/hkp.js index 5bd1f4a..81fc73c 100644 --- a/src/route/hkp.js +++ b/src/route/hkp.js @@ -17,7 +17,6 @@ 'use strict'; -const parse = require('co-body'); const util = require('../service/util'); /** @@ -37,13 +36,13 @@ class HKP { * Public key upload via http POST * @param {Object} ctx The koa request/response context */ - *add(ctx) { - const {keytext: publicKeyArmored} = yield parse.form(ctx, {limit: '1mb'}); + async add(ctx) { + const publicKeyArmored = ctx.request.body.keytext; if (!publicKeyArmored) { ctx.throw(400, 'Invalid request!'); } const origin = util.origin(ctx); - yield this._publicKey.put({publicKeyArmored, origin}); + await this._publicKey.put({publicKeyArmored, origin}); ctx.body = 'Upload successful. Check your inbox to verify your email address.'; ctx.status = 201; } @@ -52,9 +51,9 @@ class HKP { * Public key lookup via http GET * @param {Object} ctx The koa request/response context */ - *lookup(ctx) { + async lookup(ctx) { const params = this.parseQueryString(ctx); - const key = yield this._publicKey.get(params); + const key = await this._publicKey.get(params); this.setGetHeaders(ctx, params); this.setGetBody(ctx, params, key); } From a52cef2771c7070a7ec842b6f1e9953806c8ea96 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Thu, 17 Aug 2017 17:44:26 +0800 Subject: [PATCH 12/12] Add space after async in `async () =>` --- .eslintrc | 6 ++- src/app.js | 6 +-- test/integration/app-test.js | 6 +-- test/integration/email-test.js | 10 ++-- test/integration/mongo-test.js | 22 ++++---- test/integration/public-key-test.js | 78 ++++++++++++++--------------- test/unit/email-test.js | 8 +-- 7 files changed, 70 insertions(+), 66 deletions(-) diff --git a/.eslintrc b/.eslintrc index 54caf24..36a19d3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -41,7 +41,11 @@ "semi": ["warn", "always"], // require or disallow semicolons instead of ASI "semi-spacing": 1, // enforce consistent spacing before and after semicolons "space-before-blocks": 1, // enforce consistent spacing before blocks - "space-before-function-paren": ["warn", "never"], // enforce consistent spacing before function definition opening parenthesis + "space-before-function-paren": ["warn", { + "anonymous": "never", + "named": "never", + "asyncArrow": "always" + }], // enforce consistent spacing before function definition opening parenthesis "space-in-parens": ["warn", "never"], // enforce consistent spacing inside parentheses "space-infix-ops": 1, // require spacing around operators /* ES6 */ diff --git a/src/app.js b/src/app.js index 1121ac6..b4f7eb5 100644 --- a/src/app.js +++ b/src/app.js @@ -54,7 +54,7 @@ router.get('/api/v1/key', ctx => rest.query(ctx)); router.del('/api/v1/key', ctx => rest.remove(ctx)); // Redirect all http traffic to https -app.use(async(ctx, next) => { +app.use(async (ctx, next) => { if (util.isTrue(config.server.httpsUpgrade) && util.checkHTTP(ctx)) { ctx.redirect(`https://${ctx.hostname}${ctx.url}`); } else { @@ -63,7 +63,7 @@ app.use(async(ctx, next) => { }); // Set HTTP response headers -app.use(async(ctx, next) => { +app.use(async (ctx, next) => { // HSTS if (util.isTrue(config.server.httpsUpgrade)) { ctx.set('Strict-Transport-Security', 'max-age=16070400'); @@ -121,7 +121,7 @@ function injectDependencies() { // if (!global.testing) { // don't automatically start server in tests - (async() => { + (async () => { try { const app = await init(); app.listen(config.server.port); diff --git a/test/integration/app-test.js b/test/integration/app-test.js index 3271646..ae5445e 100644 --- a/test/integration/app-test.js +++ b/test/integration/app-test.js @@ -22,7 +22,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { const primaryEmail = 'safewithme.testuser@gmail.com'; const fingerprint = '4277257930867231CE393FB8DBC0B3D92B1B86E9'; - before(async() => { + before(async () => { sandbox = sinon.sandbox.create(); publicKeyArmored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8'); @@ -46,13 +46,13 @@ describe('Koa App (HTTP Server) Integration Tests', function() { app = await init(); }); - beforeEach(async() => { + beforeEach(async () => { await mongo.clear(DB_TYPE_PUB_KEY); await mongo.clear(DB_TYPE_USER_ID); emailParams = null; }); - after(async() => { + after(async () => { sandbox.restore(); await mongo.clear(DB_TYPE_PUB_KEY); await mongo.clear(DB_TYPE_USER_ID); diff --git a/test/integration/email-test.js b/test/integration/email-test.js index cf4eaa3..e3afc2d 100644 --- a/test/integration/email-test.js +++ b/test/integration/email-test.js @@ -36,7 +36,7 @@ describe('Email Integration Tests', function() { }); describe("_sendHelper", () => { - it('should work', async() => { + it('should work', async () => { const mailOptions = { from: email._sender, to: recipient, @@ -50,23 +50,23 @@ describe('Email Integration Tests', function() { }); describe("send verifyKey template", () => { - it('should send plaintext email', async() => { + it('should send plaintext email', async () => { delete userId.publicKeyArmored; await email.send({template: tpl.verifyKey, userId, keyId, origin}); }); - it('should send pgp encrypted email', async() => { + it('should send pgp encrypted email', async () => { await email.send({template: tpl.verifyKey, userId, keyId, origin}); }); }); describe("send verifyRemove template", () => { - it('should send plaintext email', async() => { + it('should send plaintext email', async () => { delete userId.publicKeyArmored; await email.send({template: tpl.verifyRemove, userId, keyId, origin}); }); - it('should send pgp encrypted email', async() => { + it('should send pgp encrypted email', async () => { await email.send({template: tpl.verifyRemove, userId, keyId, origin}); }); }); diff --git a/test/integration/mongo-test.js b/test/integration/mongo-test.js index 4f74d07..9a9f9bb 100644 --- a/test/integration/mongo-test.js +++ b/test/integration/mongo-test.js @@ -9,27 +9,27 @@ describe('Mongo Integration Tests', function() { const DB_TYPE = 'apple'; let mongo; - before(async() => { + before(async () => { mongo = new Mongo(); await mongo.init(config.mongo); }); - beforeEach(async() => { + beforeEach(async () => { await mongo.clear(DB_TYPE); }); - after(async() => { + after(async () => { await mongo.clear(DB_TYPE); await mongo.disconnect(); }); describe("create", () => { - it('should insert a document', async() => { + it('should insert a document', async () => { const r = await mongo.create({_id: '0'}, DB_TYPE); expect(r.insertedCount).to.equal(1); }); - it('should fail if two with the same ID are inserted', async() => { + it('should fail if two with the same ID are inserted', async () => { let r = await mongo.create({_id: '0'}, DB_TYPE); expect(r.insertedCount).to.equal(1); try { @@ -41,12 +41,12 @@ describe('Mongo Integration Tests', function() { }); describe("batch", () => { - it('should insert a document', async() => { + it('should insert a document', async () => { const r = await mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE); expect(r.insertedCount).to.equal(2); }); - it('should fail if docs with the same ID are inserted', async() => { + it('should fail if docs with the same ID are inserted', async () => { let r = await mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE); expect(r.insertedCount).to.equal(2); try { @@ -58,7 +58,7 @@ describe('Mongo Integration Tests', function() { }); describe("update", () => { - it('should update a document', async() => { + it('should update a document', async () => { let r = await mongo.create({_id: '0'}, DB_TYPE); r = await mongo.update({_id: '0'}, {foo: 'bar'}, DB_TYPE); expect(r.modifiedCount).to.equal(1); @@ -68,7 +68,7 @@ describe('Mongo Integration Tests', function() { }); describe("get", () => { - it('should get a document', async() => { + it('should get a document', async () => { let r = await mongo.create({_id: '0'}, DB_TYPE); r = await mongo.get({_id: '0'}, DB_TYPE); expect(r).to.exist; @@ -76,7 +76,7 @@ describe('Mongo Integration Tests', function() { }); describe("list", () => { - it('should list documents', async() => { + it('should list documents', async () => { let r = await mongo.batch([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE); r = await mongo.list({foo: 'bar'}, DB_TYPE); expect(r).to.deep.equal([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE); @@ -84,7 +84,7 @@ describe('Mongo Integration Tests', function() { }); describe("remove", () => { - it('should remove a document', async() => { + it('should remove a document', async () => { let r = await mongo.create({_id: '0'}, DB_TYPE); r = await mongo.remove({_id: '0'}, DB_TYPE); r = await mongo.get({_id: '0'}, DB_TYPE); diff --git a/test/integration/public-key-test.js b/test/integration/public-key-test.js index b889870..24a26a7 100644 --- a/test/integration/public-key-test.js +++ b/test/integration/public-key-test.js @@ -25,14 +25,14 @@ describe('Public Key Integration Tests', function() { const primaryEmail2 = 'test2@example.com'; const origin = {host: 'localhost', protocol: 'http'}; - before(async() => { + before(async () => { publicKeyArmored = require('fs').readFileSync(`${__dirname}/../key3.asc`, 'utf8'); publicKeyArmored2 = require('fs').readFileSync(`${__dirname}/../key4.asc`, 'utf8'); mongo = new Mongo(); await mongo.init(config.mongo); }); - beforeEach(async() => { + beforeEach(async () => { sandbox = sinon.sandbox.create(); await mongo.clear(DB_TYPE); @@ -64,32 +64,32 @@ describe('Public Key Integration Tests', function() { sandbox.restore(); }); - after(async() => { + after(async () => { await mongo.clear(DB_TYPE); await mongo.disconnect(); }); describe('put', () => { - it('should persist key and send verification email with primaryEmail', async() => { + it('should persist key and send verification email with primaryEmail', async () => { await publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(mailsSent.length).to.equal(1); expect(mailsSent[0].to).to.equal(primaryEmail); expect(mailsSent[0].params.keyId).to.exist; expect(mailsSent[0].params.nonce).to.exist; }); - it('should persist key and send verification email without primaryEmail', async() => { + it('should persist key and send verification email without primaryEmail', async () => { await publicKey.put({publicKeyArmored, origin}); expect(mailsSent.length).to.equal(4); }); - it('should work twice if not yet verified', async() => { + it('should work twice if not yet verified', async () => { await publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(mailsSent.length).to.equal(1); await publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(mailsSent.length).to.equal(2); }); - it('should throw 304 if key already exists', async() => { + it('should throw 304 if key already exists', async () => { await publicKey.put({publicKeyArmored, primaryEmail, origin}); await publicKey.verify(mailsSent[0].params); try { @@ -102,7 +102,7 @@ describe('Public Key Integration Tests', function() { }); describe('verify', () => { - it('should update the document', async() => { + it('should update the document', async () => { await publicKey.put({publicKeyArmored, primaryEmail, origin}); const emailParams = mailsSent[0].params; await publicKey.verify(emailParams); @@ -113,7 +113,7 @@ describe('Public Key Integration Tests', function() { expect(gotten.userIds[1].nonce).to.exist; }); - it('should not find the document', async() => { + it('should not find the document', async () => { await publicKey.put({publicKeyArmored, primaryEmail, origin}); const emailParams = mailsSent[0].params; try { @@ -129,7 +129,7 @@ describe('Public Key Integration Tests', function() { expect(gotten.userIds[1].nonce).to.exist; }); - it('should not verify a second key for already verified user id of another key', async() => { + it('should not verify a second key for already verified user id of another key', async () => { await publicKey.put({publicKeyArmored, primaryEmail: primaryEmail2, origin}); expect(mailsSent.length).to.equal(1); await publicKey.put({publicKeyArmored: publicKeyArmored2, primaryEmail: primaryEmail2, origin}); @@ -148,7 +148,7 @@ describe('Public Key Integration Tests', function() { expect(gotten.userIds[1].nonce).to.equal(mailsSent[0].params.nonce); }); - it('should be able to verify multiple user ids', async() => { + it('should be able to verify multiple user ids', async () => { await publicKey.put({publicKeyArmored, origin}); expect(mailsSent.length).to.equal(4); await publicKey.verify(mailsSent[0].params); @@ -167,66 +167,66 @@ describe('Public Key Integration Tests', function() { let key; describe('should find a verified key', () => { - beforeEach(async() => { + beforeEach(async () => { key = pgp.parseKey(publicKeyArmored); await publicKey.put({publicKeyArmored, primaryEmail, origin}); await publicKey.verify(mailsSent[0].params); }); - it('by fingerprint', async() => { + it('by fingerprint', async () => { const verified = await publicKey.getVerified({fingerprint: key.fingerprint}); expect(verified).to.exist; }); - it('by all userIds', async() => { + it('by all userIds', async () => { const verified = await publicKey.getVerified({userIds: key.userIds}); expect(verified).to.exist; }); - it('by verified userId', async() => { + it('by verified userId', async () => { const verified = await publicKey.getVerified({userIds: [key.userIds[0]]}); expect(verified).to.exist; }); - it('by unverified userId', async() => { + it('by unverified userId', async () => { const verified = await publicKey.getVerified({userIds: [key.userIds[1]]}); expect(verified).to.not.exist; }); - it('by keyId', async() => { + it('by keyId', async () => { const verified = await publicKey.getVerified({keyId: key.keyId}); expect(verified).to.exist; }); - it('by all params', async() => { + it('by all params', async () => { const verified = await publicKey.getVerified(key); expect(verified).to.exist; }); }); describe('should not find an unverified key', () => { - beforeEach(async() => { + beforeEach(async () => { key = pgp.parseKey(publicKeyArmored); key.userIds[0].verified = false; await mongo.create(key, DB_TYPE); }); - it('by fingerprint', async() => { + it('by fingerprint', async () => { const verified = await publicKey.getVerified({fingerprint: key.fingerprint}); expect(verified).to.not.exist; }); - it('by userIds', async() => { + it('by userIds', async () => { const verified = await publicKey.getVerified({userIds: key.userIds}); expect(verified).to.not.exist; }); - it('by keyId', async() => { + it('by keyId', async () => { const verified = await publicKey.getVerified({keyId: key.keyId}); expect(verified).to.not.exist; }); - it('by all params', async() => { + it('by all params', async () => { const verified = await publicKey.getVerified(key); expect(verified).to.not.exist; }); @@ -236,50 +236,50 @@ describe('Public Key Integration Tests', function() { describe('get', () => { let emailParams; - beforeEach(async() => { + beforeEach(async () => { await publicKey.put({publicKeyArmored, primaryEmail, origin}); emailParams = mailsSent[0].params; }); - it('should return verified key by key id', async() => { + it('should return verified key by key id', async () => { await publicKey.verify(emailParams); const key = await publicKey.get({keyId: emailParams.keyId}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by key id (uppercase)', async() => { + it('should return verified key by key id (uppercase)', async () => { await publicKey.verify(emailParams); const key = await publicKey.get({keyId: emailParams.keyId.toUpperCase()}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by fingerprint', async() => { + it('should return verified key by fingerprint', async () => { await publicKey.verify(emailParams); const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint; const key = await publicKey.get({fingerprint}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by fingerprint (uppercase)', async() => { + it('should return verified key by fingerprint (uppercase)', async () => { await publicKey.verify(emailParams); const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint.toUpperCase(); const key = await publicKey.get({fingerprint}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by email address', async() => { + it('should return verified key by email address', async () => { await publicKey.verify(emailParams); const key = await publicKey.get({email: primaryEmail}); expect(key.publicKeyArmored).to.exist; }); - it('should return verified key by email address (uppercase)', async() => { + it('should return verified key by email address (uppercase)', async () => { await publicKey.verify(emailParams); const key = await publicKey.get({email: primaryEmail.toUpperCase()}); expect(key.publicKeyArmored).to.exist; }); - it('should throw 404 for unverified key', async() => { + it('should throw 404 for unverified key', async () => { try { await publicKey.get({keyId: emailParams.keyId}); expect(false).to.be.true; @@ -292,28 +292,28 @@ describe('Public Key Integration Tests', function() { describe('requestRemove', () => { let keyId; - beforeEach(async() => { + beforeEach(async () => { await publicKey.put({publicKeyArmored, primaryEmail, origin}); keyId = mailsSent[0].params.keyId; }); - it('should work for verified key', async() => { + it('should work for verified key', async () => { await publicKey.verify(mailsSent[0].params); await publicKey.requestRemove({keyId, origin}); expect(mailsSent.length).to.equal(5); }); - it('should work for unverified key', async() => { + it('should work for unverified key', async () => { await publicKey.requestRemove({keyId, origin}); expect(mailsSent.length).to.equal(5); }); - it('should work by email address', async() => { + it('should work by email address', async () => { await publicKey.requestRemove({email: primaryEmail, origin}); expect(mailsSent.length).to.equal(2); }); - it('should throw 404 for no key', async() => { + it('should throw 404 for no key', async () => { await mongo.remove({keyId}, DB_TYPE); try { await publicKey.requestRemove({keyId, origin}); @@ -327,19 +327,19 @@ describe('Public Key Integration Tests', function() { describe('verifyRemove', () => { let keyId; - beforeEach(async() => { + beforeEach(async () => { await publicKey.put({publicKeyArmored, primaryEmail, origin}); keyId = mailsSent[0].params.keyId; await publicKey.requestRemove({keyId, origin}); }); - it('should remove key', async() => { + it('should remove key', async () => { await publicKey.verifyRemove(mailsSent[1].params); const key = await mongo.get({keyId}, DB_TYPE); expect(key).to.not.exist; }); - it('should throw 404 for no key', async() => { + it('should throw 404 for no key', async () => { await mongo.remove({keyId}, DB_TYPE); try { await publicKey.verifyRemove(mailsSent[1].params); diff --git a/test/unit/email-test.js b/test/unit/email-test.js index 294eca2..68375a9 100644 --- a/test/unit/email-test.js +++ b/test/unit/email-test.js @@ -64,7 +64,7 @@ describe('Email Unit Tests', () => { sandbox.stub(email, '_sendHelper').returns(Promise.resolve({response: '250'})); }); - it('should work', async() => { + it('should work', async () => { const info = await email.send({template, userId: userId1, keyId, origin}); expect(info.response).to.match(/^250/); @@ -72,7 +72,7 @@ describe('Email Unit Tests', () => { }); describe("_sendHelper", () => { - it('should work', async() => { + it('should work', async () => { sendFnStub.returns(Promise.resolve({response: '250'})); const info = await email._sendHelper(mailOptions); @@ -80,7 +80,7 @@ describe('Email Unit Tests', () => { expect(info.response).to.match(/^250/); }); - it('should log warning for reponse error', async() => { + it('should log warning for reponse error', async () => { sendFnStub.returns(Promise.resolve({response: '554'})); const info = await email._sendHelper(mailOptions); @@ -89,7 +89,7 @@ describe('Email Unit Tests', () => { expect(log.warn.calledOnce).to.be.true; }); - it('should fail', async() => { + it('should fail', async () => { sendFnStub.returns(Promise.reject(new Error('boom'))); try {