From 1e2c85621bce63b6eaa8106d793673faa1686bde Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 23 Aug 2017 18:08:18 +0800 Subject: [PATCH 1/5] Remove primaryEmail parameter from public-key service. --- src/service/public-key.js | 14 ++------- test/integration/public-key-test.js | 49 +++++++++++++---------------- 2 files changed, 24 insertions(+), 39 deletions(-) diff --git a/src/service/public-key.js b/src/service/public-key.js index 87abfc5..6e3326f 100644 --- a/src/service/public-key.js +++ b/src/service/public-key.js @@ -62,11 +62,10 @@ class PublicKey { /** * Persist a new public key * @param {String} publicKeyArmored The ascii armored pgp key block - * @param {String} primaryEmail (optional) The key's primary email address * @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' } * @yield {undefined} */ - async put({publicKeyArmored, primaryEmail, origin}) { + async put({publicKeyArmored, origin}) { // lazily purge old/unverified keys on every key upload await this._purgeOldUnverified(); // parse key block @@ -79,7 +78,7 @@ class PublicKey { // store key in database await this._persisKey(key); // send mails to verify user ids (send only one if primary email is provided) - await this._sendVerifyEmail(key, primaryEmail, origin); + await this._sendVerifyEmail(key, origin); } /** @@ -121,17 +120,10 @@ class PublicKey { * Send verification emails to the public keys user ids for verification. * If a primary email address is provided only one email will be sent. * @param {Array} userIds user id documents containg the verification nonces - * @param {string} primaryEmail the public key's primary email address * @param {Object} origin the server's origin (required for email links) * @yield {undefined} */ - 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) { - userIds = [primaryUserId]; - } - // send emails + async _sendVerifyEmail({userIds, keyId, publicKeyArmored}, origin) { for (const userId of userIds) { userId.publicKeyArmored = publicKeyArmored; // set key for encryption await this._email.send({template: tpl.verifyKey, userId, keyId, origin}); diff --git a/test/integration/public-key-test.js b/test/integration/public-key-test.js index 3fd42d3..0d76031 100644 --- a/test/integration/public-key-test.js +++ b/test/integration/public-key-test.js @@ -73,30 +73,23 @@ describe('Public Key Integration Tests', function() { }); describe('put', () => { - 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', async () => { await publicKey.put({publicKeyArmored, origin}); expect(mailsSent.length).to.equal(4); }); 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); + await publicKey.put({publicKeyArmored, origin}); + expect(mailsSent.length).to.equal(4); + await publicKey.put({publicKeyArmored, origin}); + expect(mailsSent.length).to.equal(8); }); it('should throw 304 if key already exists', async () => { - await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, origin}); await publicKey.verify(mailsSent[0].params); try { - await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, origin}); expect(false).to.be.true; } catch (e) { expect(e.status).to.equal(304); @@ -147,7 +140,7 @@ describe('Public Key Integration Tests', function() { describe('verify', () => { it('should update the document', async () => { - await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, origin}); const emailParams = mailsSent[0].params; await publicKey.verify(emailParams); const gotten = await mongo.get({keyId: emailParams.keyId}, DB_TYPE); @@ -158,7 +151,7 @@ describe('Public Key Integration Tests', function() { }); it('should not find the document', async () => { - await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, origin}); const emailParams = mailsSent[0].params; try { await publicKey.verify({keyId: emailParams.keyId, nonce: 'fake_nonce'}); @@ -174,10 +167,10 @@ describe('Public Key Integration Tests', function() { }); 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}); - expect(mailsSent.length).to.equal(2); + await publicKey.put({publicKeyArmored, origin}); + expect(mailsSent.length).to.equal(4); + await publicKey.put({publicKeyArmored: publicKeyArmored2, origin}); + expect(mailsSent.length).to.equal(5); await publicKey.verify(mailsSent[1].params); try { @@ -213,7 +206,7 @@ describe('Public Key Integration Tests', function() { describe('should find a verified key', () => { beforeEach(async () => { key = pgp.parseKey(publicKeyArmored); - await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, origin}); await publicKey.verify(mailsSent[0].params); }); @@ -281,7 +274,7 @@ describe('Public Key Integration Tests', function() { let emailParams; beforeEach(async () => { - await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, origin}); emailParams = mailsSent[0].params; }); @@ -337,24 +330,24 @@ describe('Public Key Integration Tests', function() { let keyId; beforeEach(async () => { - await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, origin}); keyId = mailsSent[0].params.keyId; }); it('should work for verified key', async () => { await publicKey.verify(mailsSent[0].params); await publicKey.requestRemove({keyId, origin}); - expect(mailsSent.length).to.equal(5); + expect(mailsSent.length).to.equal(8); }); it('should work for unverified key', async () => { await publicKey.requestRemove({keyId, origin}); - expect(mailsSent.length).to.equal(5); + expect(mailsSent.length).to.equal(8); }); it('should work by email address', async () => { await publicKey.requestRemove({email: primaryEmail, origin}); - expect(mailsSent.length).to.equal(2); + expect(mailsSent.length).to.equal(5); }); it('should throw 404 for no key', async () => { @@ -372,13 +365,13 @@ describe('Public Key Integration Tests', function() { let keyId; beforeEach(async () => { - await publicKey.put({publicKeyArmored, primaryEmail, origin}); + await publicKey.put({publicKeyArmored, origin}); keyId = mailsSent[0].params.keyId; await publicKey.requestRemove({keyId, origin}); }); it('should remove key', async () => { - await publicKey.verifyRemove(mailsSent[1].params); + await publicKey.verifyRemove(mailsSent[4].params); const key = await mongo.get({keyId}, DB_TYPE); expect(key).to.not.exist; }); From 4c28da4eabc2b585a45b5287ad3fcdba97b6d435 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 23 Aug 2017 18:09:54 +0800 Subject: [PATCH 2/5] Add uploaded attribute to documentation. --- src/service/public-key.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/service/public-key.js b/src/service/public-key.js index 6e3326f..9bb0e91 100644 --- a/src/service/public-key.js +++ b/src/service/public-key.js @@ -36,6 +36,7 @@ const tpl = require('../email/templates.json'); * } * ], * created: Sat Oct 17 2015 12:17:03 GMT+0200 (CEST), // key creation time as JavaScript Date + * uploaded: Sat Oct 17 2015 12:17:03 GMT+0200 (CEST), // time of key upload as JavaScript Date * algorithm: 'rsa_encrypt_sign', // primary key alogrithm * keySize: 4096, // key length in bits * publicKeyArmored: '-----BEGIN PGP PUBLIC KEY BLOCK----- ... -----END PGP PUBLIC KEY BLOCK-----' From 5fa36e6d522d6c7b0e9d3e7b8a44c1d41d9a2d69 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 23 Aug 2017 18:19:59 +0800 Subject: [PATCH 3/5] Remove primaryEmail parameter from REST api. --- src/route/rest.js | 6 +++--- test/integration/app-test.js | 29 +++++------------------------ 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/route/rest.js b/src/route/rest.js index af386cf..d9447b7 100644 --- a/src/route/rest.js +++ b/src/route/rest.js @@ -37,12 +37,12 @@ class REST { * @param {Object} ctx The koa request/response context */ async create(ctx) { - const {publicKeyArmored, primaryEmail} = ctx.request.body; - if (!publicKeyArmored || (primaryEmail && !util.isEmail(primaryEmail))) { + const {publicKeyArmored} = ctx.request.body; + if (!publicKeyArmored) { ctx.throw(400, 'Invalid request!'); } const origin = util.origin(ctx); - await this._publicKey.put({publicKeyArmored, primaryEmail, origin}); + await this._publicKey.put({publicKeyArmored, origin}); ctx.body = 'Upload successful. Check your inbox to verify your email address.'; ctx.status = 201; } diff --git a/test/integration/app-test.js b/test/integration/app-test.js index 2edf598..63bd9ad 100644 --- a/test/integration/app-test.js +++ b/test/integration/app-test.js @@ -68,26 +68,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { .end(done); }); - it('should return 400 for an invalid primaryEmail', done => { - request(app.listen()) - .post('/api/v1/key') - .send({publicKeyArmored, primaryEmail: 'foo'}) - .expect(400) - .end(done); - }); - - it('should return 201 with primaryEmail', done => { - request(app.listen()) - .post('/api/v1/key') - .send({publicKeyArmored, primaryEmail}) - .expect(201) - .end(() => { - expect(emailParams).to.exist; - done(); - }); - }); - - it('should return 201 without primaryEmail', done => { + it('should return 201', done => { request(app.listen()) .post('/api/v1/key') .send({publicKeyArmored}) @@ -103,7 +84,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { beforeEach(done => { request(app.listen()) .post('/api/v1/key') - .send({publicKeyArmored, primaryEmail}) + .send({publicKeyArmored}) .expect(201) .end(done); }); @@ -134,7 +115,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { beforeEach(done => { request(app.listen()) .post('/api/v1/key') - .send({publicKeyArmored, primaryEmail}) + .send({publicKeyArmored}) .expect(201) .end(done); }); @@ -196,7 +177,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { beforeEach(done => { request(app.listen()) .post('/api/v1/key') - .send({publicKeyArmored, primaryEmail}) + .send({publicKeyArmored}) .expect(201) .end(done); }); @@ -234,7 +215,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { beforeEach(done => { request(app.listen()) .post('/api/v1/key') - .send({publicKeyArmored, primaryEmail}) + .send({publicKeyArmored}) .expect(201) .end(() => { request(app.listen()) From b74563b3ece429824bf9cb5bec133f92ba8ffbe2 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Wed, 23 Aug 2017 18:20:22 +0800 Subject: [PATCH 4/5] Remove primaryEmail parameter from README --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index b39b7e9..1b7aaee 100644 --- a/README.md +++ b/README.md @@ -124,13 +124,11 @@ POST /api/v1/key ```json { - "publicKeyArmored": "-----BEGIN PGP PUBLIC KEY BLOCK----- ... -----END PGP PUBLIC KEY BLOCK-----", - "primaryEmail": "user@example.com" + "publicKeyArmored": "-----BEGIN PGP PUBLIC KEY BLOCK----- ... -----END PGP PUBLIC KEY BLOCK-----" } ``` * **publicKeyArmored**: The ascii armored public PGP key to be uploaded -* **primaryEmail (optional)**: The ascii armored block is parsed to check for user ids, so this parameter is purely optional. Normally a verification email is sent to every user id found in the pgp key. To prevent this behaviour, user agents can specify the user's primary email address to send out only one email. ### Verify uploaded key (via link in email) From 0400b9c9d97bb7690fdf58aa82c11edc67ebe6c0 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Thu, 24 Aug 2017 13:26:39 +0800 Subject: [PATCH 5/5] Fix test --- test/integration/public-key-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/public-key-test.js b/test/integration/public-key-test.js index 0d76031..a1e0d60 100644 --- a/test/integration/public-key-test.js +++ b/test/integration/public-key-test.js @@ -171,7 +171,7 @@ describe('Public Key Integration Tests', function() { expect(mailsSent.length).to.equal(4); await publicKey.put({publicKeyArmored: publicKeyArmored2, origin}); expect(mailsSent.length).to.equal(5); - await publicKey.verify(mailsSent[1].params); + await publicKey.verify(mailsSent[4].params); try { await publicKey.verify(mailsSent[0].params); @@ -182,7 +182,7 @@ describe('Public Key Integration Tests', function() { 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); + expect(gotten.userIds[1].nonce).to.equal(mailsSent[1].params.nonce); }); it('should be able to verify multiple user ids', async () => {