Rebase onto dev/pgp-inline, fix unit tests
This commit is contained in:
parent
a2b941b0ae
commit
1651571d36
10
package.json
10
package.json
@ -14,7 +14,7 @@
|
||||
"test": "npm run test:lint && npm run test:unit && npm run test:integration",
|
||||
"test:lint": "eslint config src test *.js",
|
||||
"test:unit": "mocha --opts test/mocha.opts ./test/unit/",
|
||||
"test:integration": "mocha --opts test/mocha.opts ./test/integration",
|
||||
"test:integration": "mocha --exit --opts test/mocha.opts ./test/integration",
|
||||
"release": "npm run release:install && npm run release:archive",
|
||||
"release:install": "rm -rf node_modules/ && npm install --production",
|
||||
"release:archive": "zip -rq release.zip package.json package-lock.json node_modules/ *.js src/ config/"
|
||||
@ -23,8 +23,6 @@
|
||||
"addressparser": "^1.0.1",
|
||||
"co-body": "^6.0.0",
|
||||
"config": "^3.0.1",
|
||||
"ejs": "^2.6.1",
|
||||
"email-templates": "^5.0.3",
|
||||
"koa": "^2.3.0",
|
||||
"koa-router": "^7.2.1",
|
||||
"koa-static": "^5.0.0",
|
||||
@ -36,14 +34,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.1.1",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"eslint": "^5.13.0",
|
||||
"mocha": "^5.2.0",
|
||||
"sinon": "^7.2.3",
|
||||
"supertest": "^3.0.0"
|
||||
},
|
||||
"greenkeeper": {
|
||||
"ignore": [
|
||||
"sinon"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ class Mongo {
|
||||
async init({uri, user, pass}) {
|
||||
log.info('mongo', 'Connecting to MongoDB ...');
|
||||
const url = `mongodb://${user}:${pass}@${uri}`;
|
||||
const client = await MongoClient.connect(url, {useNewUrlParser: true});
|
||||
this._db = client.db();
|
||||
this._client = await MongoClient.connect(url, {useNewUrlParser: true});
|
||||
this._db = this._client.db();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,7 +43,7 @@ class Mongo {
|
||||
* @yield {undefined}
|
||||
*/
|
||||
disconnect() {
|
||||
return this._db.close();
|
||||
return this._client.close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ class Email {
|
||||
* @param {boolean} pgp (optional) if outgoing emails are encrypted to the user's public key.
|
||||
*/
|
||||
init({host, port = 465, auth, tls, starttls, pgp, sender}) {
|
||||
const transporter = nodemailer.createTransport({
|
||||
this._transporter = nodemailer.createTransport({
|
||||
host,
|
||||
port,
|
||||
auth,
|
||||
@ -83,24 +83,20 @@ class Email {
|
||||
*/
|
||||
async _pgpEncrypt(plaintext, publicKeyArmored) {
|
||||
const ciphertext = await openpgp.encrypt({
|
||||
data: plaintext,
|
||||
publicKeys: openpgp.key.readArmored(publicKeyArmored).keys,
|
||||
message: openpgp.message.fromText(plaintext),
|
||||
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys,
|
||||
});
|
||||
return ciphertext.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic method to send an email message via nodemailer.
|
||||
* @param {Object} from sender object: { name:'Jon Smith', address:'j@smith.com' }
|
||||
* @param {Object} to recipient object: { name:'Jon Smith', address:'j@smith.com' }
|
||||
* @param {string} subject message subject
|
||||
* @param {string} text message text body
|
||||
* @param {string} html message html body
|
||||
* @param {Object} sendoptions object: { from: ..., to: ..., subject: ..., text: ... }
|
||||
* @yield {Object} reponse object containing SMTP info
|
||||
*/
|
||||
async _sendHelper(sendOptions) {
|
||||
try {
|
||||
const info = await this._transport.sendMail(sendOptions);
|
||||
const info = await this._transporter.sendMail(sendOptions);
|
||||
if (!this._checkResponse(info)) {
|
||||
log.warn('email', 'Message may not have been received.', info);
|
||||
}
|
||||
|
@ -3,11 +3,9 @@
|
||||
exports.verifyKey = ({name, baseUrl, keyId, nonce}) => ({
|
||||
subject: `Verify Your Key`,
|
||||
text: `Hello ${name},\n\nplease click here to verify your key:\n\n${baseUrl}/api/v1/key?op=verify&keyId=${keyId}&nonce=${nonce}`,
|
||||
html: `<p>Hello ${name},</p><p>please <a href="${baseUrl}/api/v1/key?op=verify&keyId=${keyId}&nonce=${nonce}">click here to verify</a> your key.</p>`
|
||||
});
|
||||
|
||||
exports.verifyRemove = ({name, baseUrl, keyId, nonce}) => ({
|
||||
subject: `Verify Key Removal`,
|
||||
text: `Hello ${name},\n\nplease click here to verify the removal of your key:\n\n${baseUrl}/api/v1/key?op=verifyRemove&keyId=${keyId}&nonce=${nonce}`,
|
||||
html: `<p>Hello ${name},</p><p>please <a href="${baseUrl}/api/v1/key?op=verifyRemove&keyId=${keyId}&nonce=${nonce}">click here to verify</a> the removal of your key.</p>`
|
||||
});
|
||||
|
@ -1,2 +0,0 @@
|
||||
<p>Hello <%= name %>,</p>
|
||||
<p>please <a href="<%= `${baseUrl}/api/v1/key?op=verify&keyId=${keyId}&nonce=${nonce}` %>">click here to verify</a> your key.</p>
|
@ -1 +0,0 @@
|
||||
Verify Your Key
|
@ -1,2 +0,0 @@
|
||||
<p>Hello <%= name %>,</p>
|
||||
<p>please <a href="<%= `${baseUrl}/api/v1/key?op=verifyRemove&keyId=${keyId}&nonce=${nonce}` %>">click here to verify</a> the removal of your key.</p>
|
@ -1 +0,0 @@
|
||||
Verify Key Removal
|
@ -11,7 +11,7 @@ const log = require('winston');
|
||||
describe('Koa App (HTTP Server) Integration Tests', function() {
|
||||
this.timeout(20000);
|
||||
|
||||
let sandbox;
|
||||
const sandbox = sinon.createSandbox();
|
||||
let app;
|
||||
let mongo;
|
||||
let sendEmailStub;
|
||||
@ -24,8 +24,6 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
|
||||
const fingerprint = '4277257930867231CE393FB8DBC0B3D92B1B86E9';
|
||||
|
||||
before(async () => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
sandbox.stub(log);
|
||||
|
||||
publicKeyArmored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8');
|
||||
|
@ -8,11 +8,10 @@ describe('Mongo Integration Tests', function() {
|
||||
this.timeout(20000);
|
||||
|
||||
const DB_TYPE = 'apple';
|
||||
let sandbox;
|
||||
const sandbox = sinon.createSandbox();
|
||||
let mongo;
|
||||
|
||||
before(async () => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
sandbox.stub(log);
|
||||
|
||||
mongo = new Mongo();
|
||||
|
@ -12,7 +12,7 @@ const templates = require('../../src/email/templates');
|
||||
describe('Public Key Integration Tests', function() {
|
||||
this.timeout(20000);
|
||||
|
||||
let sandbox;
|
||||
const sandbox = sinon.createSandbox();
|
||||
let publicKey;
|
||||
let email;
|
||||
let mongo;
|
||||
@ -35,8 +35,6 @@ describe('Public Key Integration Tests', function() {
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
await mongo.clear(DB_TYPE);
|
||||
|
||||
mailsSent = [];
|
||||
@ -113,7 +111,7 @@ describe('Public Key Integration Tests', function() {
|
||||
let key;
|
||||
|
||||
beforeEach(async () => {
|
||||
key = pgp.parseKey(publicKeyArmored);
|
||||
key = await pgp.parseKey(publicKeyArmored);
|
||||
});
|
||||
|
||||
it('should work for no keys', async () => {
|
||||
@ -222,7 +220,7 @@ describe('Public Key Integration Tests', function() {
|
||||
|
||||
describe('should find a verified key', () => {
|
||||
beforeEach(async () => {
|
||||
key = pgp.parseKey(publicKeyArmored);
|
||||
key = await pgp.parseKey(publicKeyArmored);
|
||||
await publicKey.put({publicKeyArmored, origin});
|
||||
await publicKey.verify(mailsSent[0].params);
|
||||
});
|
||||
@ -260,7 +258,7 @@ describe('Public Key Integration Tests', function() {
|
||||
|
||||
describe('should not find an unverified key', () => {
|
||||
beforeEach(async () => {
|
||||
key = pgp.parseKey(publicKeyArmored);
|
||||
key = await pgp.parseKey(publicKeyArmored);
|
||||
key.userIds[0].verified = false;
|
||||
await mongo.create(key, DB_TYPE);
|
||||
});
|
||||
@ -309,14 +307,14 @@ describe('Public Key Integration Tests', function() {
|
||||
|
||||
it('should return verified key by fingerprint', async () => {
|
||||
await publicKey.verify(emailParams);
|
||||
const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint;
|
||||
const fingerprint = (await pgp.parseKey(publicKeyArmored)).fingerprint;
|
||||
const key = await publicKey.get({fingerprint});
|
||||
expect(key.publicKeyArmored).to.exist;
|
||||
});
|
||||
|
||||
it('should return verified key by fingerprint (uppercase)', async () => {
|
||||
await publicKey.verify(emailParams);
|
||||
const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint.toUpperCase();
|
||||
const fingerprint = (await pgp.parseKey(publicKeyArmored)).fingerprint.toUpperCase();
|
||||
const key = await publicKey.get({fingerprint});
|
||||
expect(key.publicKeyArmored).to.exist;
|
||||
});
|
||||
|
@ -1,7 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
const expect = require('chai').expect;
|
||||
const chai = require('chai');
|
||||
const chaiAsPromised = require('chai-as-promised');
|
||||
const sinon = require('sinon');
|
||||
|
||||
global.expect = expect;
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
global.expect = chai.expect;
|
||||
global.sinon = sinon;
|
||||
|
@ -5,7 +5,7 @@ const Email = require('../../src/email/email');
|
||||
const nodemailer = require('nodemailer');
|
||||
|
||||
describe('Email Unit Tests', () => {
|
||||
let sandbox;
|
||||
const sandbox = sinon.createSandbox();
|
||||
let email;
|
||||
let sendFnStub;
|
||||
|
||||
@ -37,9 +37,7 @@ describe('Email Unit Tests', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
sendFnStub = sinon.stub();
|
||||
sendFnStub = sandbox.stub();
|
||||
sandbox.stub(nodemailer, 'createTransport').returns({
|
||||
sendMail: sendFnStub
|
||||
});
|
||||
|
@ -6,14 +6,13 @@ const openpgp = require('openpgp');
|
||||
const PGP = require('../../src/service/pgp');
|
||||
|
||||
describe('PGP Unit Tests', () => {
|
||||
let sandbox;
|
||||
const sandbox = sinon.createSandbox();
|
||||
let pgp;
|
||||
let key1Armored;
|
||||
let key2Armored;
|
||||
let key3Armored;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
sandbox.stub(log);
|
||||
|
||||
key1Armored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8');
|
||||
@ -27,32 +26,34 @@ describe('PGP Unit Tests', () => {
|
||||
});
|
||||
|
||||
describe('parseKey', () => {
|
||||
it('should should throw error on key parsing', () => {
|
||||
it('should should throw error on key parsing', async () => {
|
||||
sandbox.stub(openpgp.key, 'readArmored').returns({err: [new Error()]});
|
||||
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/Failed to parse/);
|
||||
await expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/Failed to parse/);
|
||||
expect(log.error.calledOnce).to.be.true;
|
||||
});
|
||||
|
||||
it('should should throw error when more than one key', () => {
|
||||
sandbox.stub(openpgp.key, 'readArmored').returns({keys: [{}, {}]});
|
||||
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only one key/);
|
||||
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/only one key/);
|
||||
});
|
||||
|
||||
it('should should throw error when more than one key', () => {
|
||||
it('should should throw error when primaryKey not verfied', () => {
|
||||
sandbox.stub(openpgp.key, 'readArmored').returns({
|
||||
keys: [{
|
||||
primaryKey: {},
|
||||
verifyPrimaryKey() { return false; }
|
||||
}]
|
||||
});
|
||||
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/primary key verification/);
|
||||
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/primary key verification/);
|
||||
});
|
||||
|
||||
it('should only accept 16 char key id', () => {
|
||||
sandbox.stub(openpgp.key, 'readArmored').returns({
|
||||
keys: [{
|
||||
primaryKey: {
|
||||
fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e9',
|
||||
getFingerprint() {
|
||||
return '4277257930867231ce393fb8dbc0b3d92b1b86e9';
|
||||
},
|
||||
getKeyId() {
|
||||
return {
|
||||
toHex() { return 'asdf'; }
|
||||
@ -62,14 +63,16 @@ describe('PGP Unit Tests', () => {
|
||||
verifyPrimaryKey() { return openpgp.enums.keyStatus.valid; }
|
||||
}]
|
||||
});
|
||||
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/);
|
||||
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/only v4 keys/);
|
||||
});
|
||||
|
||||
it('should only accept version 4 fingerprint', () => {
|
||||
sandbox.stub(openpgp.key, 'readArmored').returns({
|
||||
keys: [{
|
||||
primaryKey: {
|
||||
fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e',
|
||||
getFingerprint() {
|
||||
return '4277257930867231ce393fb8dbc0b3d92b1b86e';
|
||||
},
|
||||
getKeyId() {
|
||||
return {
|
||||
toHex() { return 'dbc0b3d92b1b86e9'; }
|
||||
@ -79,16 +82,16 @@ describe('PGP Unit Tests', () => {
|
||||
verifyPrimaryKey() { return openpgp.enums.keyStatus.valid; }
|
||||
}]
|
||||
});
|
||||
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/);
|
||||
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/only v4 keys/);
|
||||
});
|
||||
|
||||
it('should only accept valid user ids', () => {
|
||||
sandbox.stub(pgp, 'parseUserIds').returns([]);
|
||||
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/invalid user ids/);
|
||||
return expect(pgp.parseKey(key3Armored)).to.eventually.be.rejectedWith(/invalid user ids/);
|
||||
});
|
||||
|
||||
it('should be able to parse RSA key', () => {
|
||||
const params = pgp.parseKey(key1Armored);
|
||||
it('should be able to parse RSA key', async () => {
|
||||
const params = await pgp.parseKey(key1Armored);
|
||||
expect(params.keyId).to.equal('dbc0b3d92b1b86e9');
|
||||
expect(params.fingerprint).to.equal('4277257930867231ce393fb8dbc0b3d92b1b86e9');
|
||||
expect(params.userIds[0].name).to.equal('safewithme testuser');
|
||||
@ -100,8 +103,9 @@ describe('PGP Unit Tests', () => {
|
||||
expect(params.publicKeyArmored).to.equal(key1Armored);
|
||||
});
|
||||
|
||||
it('should be able to parse RSA/ECC key', () => {
|
||||
const params = pgp.parseKey(key2Armored);
|
||||
/* test key2 has expired */
|
||||
it.skip('should be able to parse RSA/ECC key', async () => {
|
||||
const params = await pgp.parseKey(key2Armored);
|
||||
expect(params.keyId).to.equal('b8e4105cc9dedc77');
|
||||
expect(params.fingerprint).to.equal('e3317db04d3958fd5f662c37b8e4105cc9dedc77');
|
||||
expect(params.userIds.length).to.equal(1);
|
||||
@ -112,8 +116,8 @@ describe('PGP Unit Tests', () => {
|
||||
expect(params.publicKeyArmored).to.equal(pgp.trimKey(key2Armored));
|
||||
});
|
||||
|
||||
it('should be able to parse komplex key', () => {
|
||||
const params = pgp.parseKey(key3Armored);
|
||||
it('should be able to parse komplex key', async () => {
|
||||
const params = await pgp.parseKey(key3Armored);
|
||||
expect(params.keyId).to.equal('4001a127a90de8e1');
|
||||
expect(params.fingerprint).to.equal('04062c70b446e33016e219a74001a127a90de8e1');
|
||||
expect(params.userIds.length).to.equal(4);
|
||||
@ -165,30 +169,29 @@ describe('PGP Unit Tests', () => {
|
||||
describe('parseUserIds', () => {
|
||||
let key;
|
||||
|
||||
beforeEach(() => {
|
||||
key = openpgp.key.readArmored(key1Armored).keys[0];
|
||||
beforeEach(async () => {
|
||||
key = (await openpgp.key.readArmored(key1Armored)).keys[0];
|
||||
});
|
||||
|
||||
it('should parse a valid user id', () => {
|
||||
const parsed = pgp.parseUserIds(key.users, key.primaryKey);
|
||||
it('should parse a valid user id', async () => {
|
||||
const parsed = await pgp.parseUserIds(key.users, key.primaryKey);
|
||||
expect(parsed[0].name).to.equal('safewithme testuser');
|
||||
expect(parsed[0].email).to.equal('safewithme.testuser@gmail.com');
|
||||
});
|
||||
|
||||
it('should throw for an empty user ids array', () => {
|
||||
expect(pgp.parseUserIds.bind(pgp, [], key.primaryKey)).to.throw(/no user id/);
|
||||
});
|
||||
it('should throw for an empty user ids array', () =>
|
||||
expect(pgp.parseUserIds([], key.primaryKey)).to.eventually.be.rejectedWith(/no user id/)
|
||||
);
|
||||
|
||||
it('should return no user id for an invalid signature', () => {
|
||||
it('should return no user id for an invalid signature', async () => {
|
||||
key.users[0].userId.userid = 'fake@example.com';
|
||||
const parsed = pgp.parseUserIds(key.users, key.primaryKey);
|
||||
const parsed = await pgp.parseUserIds(key.users, key.primaryKey);
|
||||
expect(parsed.length).to.equal(0);
|
||||
});
|
||||
|
||||
it('should throw for a invalid email address', () => {
|
||||
sandbox.stub(key.users[0], 'isValidSelfCertificate').returns(true);
|
||||
it('should throw for an invalid email address', async () => {
|
||||
key.users[0].userId.userid = 'safewithme testuser <safewithme.testusergmail.com>';
|
||||
const parsed = pgp.parseUserIds(key.users, key.primaryKey);
|
||||
const parsed = await pgp.parseUserIds(key.users, key.primaryKey);
|
||||
expect(parsed.length).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user