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) 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/src/service/public-key.js b/src/service/public-key.js index 87abfc5..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-----' @@ -62,11 +63,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 +79,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 +121,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/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()) diff --git a/test/integration/public-key-test.js b/test/integration/public-key-test.js index 3fd42d3..a1e0d60 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,11 +167,11 @@ 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.verify(mailsSent[1].params); + 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[4].params); try { await publicKey.verify(mailsSent[0].params); @@ -189,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 () => { @@ -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; });