Allow update of an email address’ key with remove/verify flow in between

This commit is contained in:
Tankred Hase 2017-08-24 16:36:32 +08:00
parent 164585b406
commit b738e1bc5c
2 changed files with 38 additions and 22 deletions

View File

@ -71,10 +71,10 @@ class PublicKey {
await this._purgeOldUnverified();
// parse key block
const key = this._pgp.parseKey(publicKeyArmored);
// check for existing verfied key by id or email addresses
const verified = await this.getVerified(key);
// check for existing verified key with same id
const verified = await this.getVerified({keyId: key.keyId});
if (verified) {
util.throw(304, 'Key for this user already exists');
util.throw(304, 'Key with this key id already exists');
}
// store key in database
await this._persisKey(key);
@ -144,11 +144,7 @@ class PublicKey {
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 = await this.getVerified(key);
if (verified && verified.keyId !== keyId) {
util.throw(304, 'Key for this user already exists');
}
await this._removeKeysWithSameEmail(key, nonce);
// flag the user id as verified
await this._mongo.update(query, {
'userIds.$.verified': true,
@ -156,6 +152,15 @@ class PublicKey {
}, DB_TYPE);
}
async _removeKeysWithSameEmail({keyId, userIds}, nonce) {
const {email} = userIds.find(uid => uid.nonce === nonce);
const keys = await this._mongo.list({
keyId: {$ne: keyId},
'userIds.email': email
}, DB_TYPE);
await Promise.all(keys.map(({_id}) => this._mongo.remove({_id}, DB_TYPE)));
}
/**
* Check if a verified key already exists either by fingerprint, 16 char key id,
* or email address. There can only be one verified user ID for an email address

View File

@ -23,7 +23,6 @@ describe('Public Key Integration Tests', function() {
const DB_TYPE = 'publickey';
const primaryEmail = 'test1@example.com';
const primaryEmail2 = 'test2@example.com';
const origin = {host: 'localhost', protocol: 'http'};
before(async () => {
@ -95,6 +94,13 @@ describe('Public Key Integration Tests', function() {
expect(e.status).to.equal(304);
}
});
it('should work for a key with an existing/verified email address to allow key update without an extra delete step in between', async () => {
await publicKey.put({publicKeyArmored, origin});
await publicKey.verify(mailsSent[1].params);
await publicKey.put({publicKeyArmored: publicKeyArmored2, origin});
expect(mailsSent.length).to.equal(5);
});
});
describe('_purgeOldUnverified', () => {
@ -166,23 +172,28 @@ 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 verify a second key for an already verified user id and delete the old key', async () => {
await publicKey.put({publicKeyArmored, origin});
expect(mailsSent.length).to.equal(4);
await publicKey.verify(mailsSent[1].params);
let firstKey = await publicKey.getVerified({keyId: mailsSent[1].params.keyId});
expect(firstKey).to.exist;
await publicKey.put({publicKeyArmored: publicKeyArmored2, origin});
expect(mailsSent.length).to.equal(5);
await publicKey.verify(mailsSent[4].params);
firstKey = await publicKey.getVerified({keyId: mailsSent[1].params.keyId});
expect(firstKey).to.not.exist;
const secondKey = await publicKey.getVerified({keyId: mailsSent[4].params.keyId});
expect(secondKey).to.exist;
});
try {
await publicKey.verify(mailsSent[0].params);
expect(true).to.be.false;
} catch (e) {
expect(e.status).to.equal(304);
}
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[1].params.nonce);
it('should delete other keys with the same user id when verifying', async () => {
await publicKey.put({publicKeyArmored, origin});
await publicKey.put({publicKeyArmored: publicKeyArmored2, origin});
expect(mailsSent[1].to).to.equal(mailsSent[4].to);
await publicKey.verify(mailsSent[1].params);
const firstKey = await publicKey.getVerified({keyId: mailsSent[1].params.keyId});
expect(firstKey).to.exist;
const secondKey = await mongo.get({keyId: mailsSent[4].params.keyId}, DB_TYPE);
expect(secondKey).to.not.exist;
});
it('should be able to verify multiple user ids', async () => {