2016-06-09 15:07:51 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const fs = require('fs');
|
2017-08-18 10:01:34 +00:00
|
|
|
const log = require('winston');
|
2016-06-09 15:07:51 +00:00
|
|
|
const openpgp = require('openpgp');
|
|
|
|
const PGP = require('../../src/service/pgp');
|
|
|
|
|
|
|
|
describe('PGP Unit Tests', () => {
|
2019-02-08 16:04:28 +00:00
|
|
|
const sandbox = sinon.createSandbox();
|
2017-08-15 08:03:06 +00:00
|
|
|
let pgp;
|
|
|
|
let key1Armored;
|
|
|
|
let key2Armored;
|
|
|
|
let key3Armored;
|
2019-03-15 15:55:53 +00:00
|
|
|
let key5Armored;
|
|
|
|
|
|
|
|
before(() => {
|
|
|
|
key1Armored = fs.readFileSync(`${__dirname}/../fixtures/key1.asc`, 'utf8');
|
|
|
|
key2Armored = fs.readFileSync(`${__dirname}/../fixtures/key2.asc`, 'utf8');
|
|
|
|
key3Armored = fs.readFileSync(`${__dirname}/../fixtures/key3.asc`, 'utf8');
|
|
|
|
key5Armored = fs.readFileSync(`${__dirname}/../fixtures/key5.asc`, 'utf8');
|
|
|
|
});
|
2016-06-09 15:07:51 +00:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2017-08-16 08:55:28 +00:00
|
|
|
sandbox.stub(log);
|
2016-06-10 15:47:05 +00:00
|
|
|
pgp = new PGP();
|
2016-06-09 15:07:51 +00:00
|
|
|
});
|
|
|
|
|
2017-08-16 08:55:28 +00:00
|
|
|
afterEach(() => {
|
|
|
|
sandbox.restore();
|
|
|
|
});
|
|
|
|
|
2016-06-09 15:07:51 +00:00
|
|
|
describe('parseKey', () => {
|
2019-02-08 16:04:28 +00:00
|
|
|
it('should should throw error on key parsing', async () => {
|
2017-08-16 08:55:28 +00:00
|
|
|
sandbox.stub(openpgp.key, 'readArmored').returns({err: [new Error()]});
|
2019-02-08 16:04:28 +00:00
|
|
|
await expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/Failed to parse/);
|
2016-06-10 15:47:05 +00:00
|
|
|
expect(log.error.calledOnce).to.be.true;
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should should throw error when more than one key', () => {
|
2017-08-16 08:55:28 +00:00
|
|
|
sandbox.stub(openpgp.key, 'readArmored').returns({keys: [{}, {}]});
|
2019-02-08 16:04:28 +00:00
|
|
|
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/only one key/);
|
2016-06-10 15:47:05 +00:00
|
|
|
});
|
|
|
|
|
2019-02-08 16:04:28 +00:00
|
|
|
it('should should throw error when primaryKey not verfied', () => {
|
2017-08-16 08:55:28 +00:00
|
|
|
sandbox.stub(openpgp.key, 'readArmored').returns({
|
2016-06-10 15:47:05 +00:00
|
|
|
keys: [{
|
|
|
|
primaryKey: {},
|
2017-08-15 08:03:06 +00:00
|
|
|
verifyPrimaryKey() { return false; }
|
2016-06-10 15:47:05 +00:00
|
|
|
}]
|
|
|
|
});
|
2019-02-08 16:04:28 +00:00
|
|
|
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/primary key verification/);
|
2016-06-10 15:47:05 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should only accept 16 char key id', () => {
|
2017-08-16 08:55:28 +00:00
|
|
|
sandbox.stub(openpgp.key, 'readArmored').returns({
|
2016-06-10 15:47:05 +00:00
|
|
|
keys: [{
|
|
|
|
primaryKey: {
|
2019-02-08 16:04:28 +00:00
|
|
|
getFingerprint() {
|
|
|
|
return '4277257930867231ce393fb8dbc0b3d92b1b86e9';
|
|
|
|
},
|
2017-08-15 08:03:06 +00:00
|
|
|
getKeyId() {
|
2016-06-10 15:47:05 +00:00
|
|
|
return {
|
2017-08-15 08:03:06 +00:00
|
|
|
toHex() { return 'asdf'; }
|
2016-06-10 15:47:05 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
2017-08-15 08:03:06 +00:00
|
|
|
verifyPrimaryKey() { return openpgp.enums.keyStatus.valid; }
|
2016-06-10 15:47:05 +00:00
|
|
|
}]
|
|
|
|
});
|
2019-02-08 16:04:28 +00:00
|
|
|
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/only v4 keys/);
|
2016-06-10 15:47:05 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should only accept version 4 fingerprint', () => {
|
2017-08-16 08:55:28 +00:00
|
|
|
sandbox.stub(openpgp.key, 'readArmored').returns({
|
2016-06-10 15:47:05 +00:00
|
|
|
keys: [{
|
|
|
|
primaryKey: {
|
2019-02-08 16:04:28 +00:00
|
|
|
getFingerprint() {
|
|
|
|
return '4277257930867231ce393fb8dbc0b3d92b1b86e';
|
|
|
|
},
|
2017-08-15 08:03:06 +00:00
|
|
|
getKeyId() {
|
2016-06-10 15:47:05 +00:00
|
|
|
return {
|
2017-08-15 08:03:06 +00:00
|
|
|
toHex() { return 'dbc0b3d92b1b86e9'; }
|
2016-06-10 15:47:05 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
2017-08-15 08:03:06 +00:00
|
|
|
verifyPrimaryKey() { return openpgp.enums.keyStatus.valid; }
|
2016-06-10 15:47:05 +00:00
|
|
|
}]
|
|
|
|
});
|
2019-02-08 16:04:28 +00:00
|
|
|
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/only v4 keys/);
|
2016-06-10 15:47:05 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should only accept valid user ids', () => {
|
2017-08-16 08:55:28 +00:00
|
|
|
sandbox.stub(pgp, 'parseUserIds').returns([]);
|
2019-03-06 08:52:08 +00:00
|
|
|
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/invalid user IDs/);
|
2016-06-10 15:47:05 +00:00
|
|
|
});
|
|
|
|
|
2019-02-08 16:04:28 +00:00
|
|
|
it('should be able to parse RSA key', async () => {
|
|
|
|
const params = await pgp.parseKey(key1Armored);
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(params.keyId).to.equal('dbc0b3d92b1b86e9');
|
|
|
|
expect(params.fingerprint).to.equal('4277257930867231ce393fb8dbc0b3d92b1b86e9');
|
2016-06-10 15:47:05 +00:00
|
|
|
expect(params.userIds[0].name).to.equal('safewithme testuser');
|
|
|
|
expect(params.userIds[0].email).to.equal('safewithme.testuser@gmail.com');
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(params.created.getTime()).to.exist;
|
2017-08-22 03:26:12 +00:00
|
|
|
expect(params.uploaded.getTime()).to.exist;
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(params.algorithm).to.equal('rsa_encrypt_sign');
|
|
|
|
expect(params.keySize).to.equal(2048);
|
|
|
|
expect(params.publicKeyArmored).to.equal(key1Armored);
|
|
|
|
});
|
|
|
|
|
2019-02-08 16:04:28 +00:00
|
|
|
/* test key2 has expired */
|
|
|
|
it.skip('should be able to parse RSA/ECC key', async () => {
|
|
|
|
const params = await pgp.parseKey(key2Armored);
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(params.keyId).to.equal('b8e4105cc9dedc77');
|
|
|
|
expect(params.fingerprint).to.equal('e3317db04d3958fd5f662c37b8e4105cc9dedc77');
|
|
|
|
expect(params.userIds.length).to.equal(1);
|
|
|
|
expect(params.created.getTime()).to.exist;
|
2017-08-22 03:26:12 +00:00
|
|
|
expect(params.uploaded.getTime()).to.exist;
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(params.algorithm).to.equal('rsa_encrypt_sign');
|
|
|
|
expect(params.keySize).to.equal(4096);
|
|
|
|
expect(params.publicKeyArmored).to.equal(pgp.trimKey(key2Armored));
|
|
|
|
});
|
2016-06-10 15:47:05 +00:00
|
|
|
|
2019-02-08 16:04:28 +00:00
|
|
|
it('should be able to parse komplex key', async () => {
|
|
|
|
const params = await pgp.parseKey(key3Armored);
|
2016-06-10 15:47:05 +00:00
|
|
|
expect(params.keyId).to.equal('4001a127a90de8e1');
|
|
|
|
expect(params.fingerprint).to.equal('04062c70b446e33016e219a74001a127a90de8e1');
|
|
|
|
expect(params.userIds.length).to.equal(4);
|
|
|
|
expect(params.created.getTime()).to.exist;
|
2017-08-22 03:26:12 +00:00
|
|
|
expect(params.uploaded.getTime()).to.exist;
|
2016-06-10 15:47:05 +00:00
|
|
|
expect(params.algorithm).to.equal('rsa_encrypt_sign');
|
|
|
|
expect(params.keySize).to.equal(4096);
|
|
|
|
expect(params.publicKeyArmored).to.equal(pgp.trimKey(key3Armored));
|
|
|
|
});
|
2016-06-09 15:07:51 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('trimKey', () => {
|
|
|
|
it('should be the same as key1', () => {
|
2017-08-15 08:03:06 +00:00
|
|
|
const trimmed = pgp.trimKey(key1Armored);
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(trimmed).to.equal(key1Armored);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not be the same as key2', () => {
|
2017-08-15 08:03:06 +00:00
|
|
|
const trimmed = pgp.trimKey(key2Armored);
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(trimmed).to.not.equal(key2Armored);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('validateKeyBlock', () => {
|
|
|
|
const KEY_BEGIN = '-----BEGIN PGP PUBLIC KEY BLOCK-----';
|
|
|
|
const KEY_END = '-----END PGP PUBLIC KEY BLOCK-----';
|
|
|
|
|
|
|
|
it('should return true for valid key block', () => {
|
2017-08-15 08:03:06 +00:00
|
|
|
const input = KEY_BEGIN + KEY_END;
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(pgp.validateKeyBlock(input)).to.be.true;
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should return false for invalid key block', () => {
|
2017-08-15 08:03:06 +00:00
|
|
|
const input = KEY_END + KEY_BEGIN;
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(pgp.validateKeyBlock(input)).to.be.false;
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should return false for invalid key block', () => {
|
2017-08-15 08:03:06 +00:00
|
|
|
const input = KEY_END;
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(pgp.validateKeyBlock(input)).to.be.false;
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should return false for invalid key block', () => {
|
2017-08-15 08:03:06 +00:00
|
|
|
const input = KEY_BEGIN;
|
2016-06-09 15:07:51 +00:00
|
|
|
expect(pgp.validateKeyBlock(input)).to.be.false;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('parseUserIds', () => {
|
2016-06-10 15:47:05 +00:00
|
|
|
let key;
|
|
|
|
|
2019-02-08 16:04:28 +00:00
|
|
|
beforeEach(async () => {
|
|
|
|
key = (await openpgp.key.readArmored(key1Armored)).keys[0];
|
2016-06-09 15:07:51 +00:00
|
|
|
});
|
|
|
|
|
2019-02-08 16:04:28 +00:00
|
|
|
it('should parse a valid user id', async () => {
|
|
|
|
const parsed = await pgp.parseUserIds(key.users, key.primaryKey);
|
2016-06-10 15:47:05 +00:00
|
|
|
expect(parsed[0].name).to.equal('safewithme testuser');
|
|
|
|
expect(parsed[0].email).to.equal('safewithme.testuser@gmail.com');
|
2016-06-09 15:07:51 +00:00
|
|
|
});
|
|
|
|
|
2019-02-08 16:04:28 +00:00
|
|
|
it('should throw for an empty user ids array', () =>
|
2019-03-06 08:52:08 +00:00
|
|
|
expect(pgp.parseUserIds([], key.primaryKey)).to.eventually.be.rejectedWith(/no user ID/)
|
2019-02-08 16:04:28 +00:00
|
|
|
);
|
2016-06-09 15:07:51 +00:00
|
|
|
|
2019-02-08 16:04:28 +00:00
|
|
|
it('should return no user id for an invalid signature', async () => {
|
2016-06-10 15:47:05 +00:00
|
|
|
key.users[0].userId.userid = 'fake@example.com';
|
2019-02-08 16:04:28 +00:00
|
|
|
const parsed = await pgp.parseUserIds(key.users, key.primaryKey);
|
2016-06-10 15:47:05 +00:00
|
|
|
expect(parsed.length).to.equal(0);
|
2016-06-09 15:07:51 +00:00
|
|
|
});
|
|
|
|
|
2019-02-08 16:04:28 +00:00
|
|
|
it('should throw for an invalid email address', async () => {
|
2016-06-10 16:43:09 +00:00
|
|
|
key.users[0].userId.userid = 'safewithme testuser <safewithme.testusergmail.com>';
|
2019-02-08 16:04:28 +00:00
|
|
|
const parsed = await pgp.parseUserIds(key.users, key.primaryKey);
|
2016-06-10 16:43:09 +00:00
|
|
|
expect(parsed.length).to.equal(0);
|
2016-06-09 15:07:51 +00:00
|
|
|
});
|
|
|
|
});
|
2019-03-15 15:55:53 +00:00
|
|
|
|
|
|
|
describe('filterKeyByUserIds', () => {
|
|
|
|
it('should filter user IDs', async () => {
|
|
|
|
const email = 'test1@example.com';
|
|
|
|
const {keys: [key]} = await openpgp.key.readArmored(key3Armored);
|
|
|
|
expect(key.users.length).to.equal(4);
|
|
|
|
const filtered = await pgp.filterKeyByUserIds([{email}], key3Armored);
|
|
|
|
const {keys: [filteredKey]} = await openpgp.key.readArmored(filtered);
|
|
|
|
expect(filteredKey.users.length).to.equal(1);
|
|
|
|
expect(filteredKey.users[0].userId.email).to.equal(email);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not filter user attributes', async () => {
|
|
|
|
const email = 'test@example.com';
|
|
|
|
const {keys: [key]} = await openpgp.key.readArmored(key5Armored);
|
|
|
|
expect(key.users.length).to.equal(2);
|
|
|
|
const filtered = await pgp.filterKeyByUserIds([{email}], key5Armored);
|
|
|
|
const {keys: [filteredKey]} = await openpgp.key.readArmored(filtered);
|
|
|
|
expect(filteredKey.users.length).to.equal(2);
|
|
|
|
expect(filteredKey.users[0].userId).to.exist;
|
|
|
|
expect(filteredKey.users[1].userAttribute).to.exist;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('removeUserId', () => {
|
|
|
|
it('should remove user IDs', async () => {
|
|
|
|
const email = 'test1@example.com';
|
|
|
|
const {keys: [key]} = await openpgp.key.readArmored(key3Armored);
|
|
|
|
expect(key.users.length).to.equal(4);
|
|
|
|
const reduced = await pgp.removeUserId(email, key3Armored);
|
|
|
|
const {keys: [reducedKey]} = await openpgp.key.readArmored(reduced);
|
|
|
|
expect(reducedKey.users.length).to.equal(3);
|
|
|
|
expect(reducedKey.users.includes(({userId}) => userId.email === email)).to.be.false;
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not remove user attributes', async () => {
|
|
|
|
const email = 'test@example.com';
|
|
|
|
const {keys: [key]} = await openpgp.key.readArmored(key5Armored);
|
|
|
|
expect(key.users.length).to.equal(2);
|
|
|
|
const reduced = await pgp.removeUserId(email, key5Armored);
|
|
|
|
const {keys: [reducedKey]} = await openpgp.key.readArmored(reduced);
|
|
|
|
expect(reducedKey.users.length).to.equal(1);
|
|
|
|
expect(reducedKey.users[0].userAttribute).to.exist;
|
|
|
|
});
|
|
|
|
});
|
2017-08-15 08:03:06 +00:00
|
|
|
});
|