Merge pull request #40 from mailvelope/dev/async-await

Dev/async await
This commit is contained in:
Tankred Hase 2017-08-17 17:46:49 +08:00 committed by GitHub
commit 8c76281666
15 changed files with 299 additions and 299 deletions

View File

@ -1,7 +1,7 @@
{
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 6
"ecmaVersion": 2017
},
"env": {
"node": true,
@ -41,7 +41,11 @@
"semi": ["warn", "always"], // require or disallow semicolons instead of ASI
"semi-spacing": 1, // enforce consistent spacing before and after semicolons
"space-before-blocks": 1, // enforce consistent spacing before blocks
"space-before-function-paren": ["warn", "never"], // enforce consistent spacing before function definition opening parenthesis
"space-before-function-paren": ["warn", {
"anonymous": "never",
"named": "never",
"asyncArrow": "always"
}], // enforce consistent spacing before function definition opening parenthesis
"space-in-parens": ["warn", "never"], // enforce consistent spacing inside parentheses
"space-infix-ops": 1, // require spacing around operators
/* ES6 */

View File

@ -21,12 +21,11 @@
},
"dependencies": {
"addressparser": "^1.0.1",
"co": "^4.6.0",
"co-body": "^5.1.1",
"config": "^1.20.4",
"koa": "^1.2.0",
"koa-router": "^5.4.0",
"koa-static": "^2.0.0",
"koa": "^2.3.0",
"koa-body": "^2.3.0",
"koa-router": "^7.2.1",
"koa-static": "^4.0.1",
"mongodb": "^2.2.31",
"nodemailer": "^2.4.2",
"nodemailer-openpgp": "^1.0.2",
@ -35,7 +34,6 @@
},
"devDependencies": {
"chai": "^4.1.1",
"co-mocha": "^1.1.2",
"eslint": "^4.4.1",
"mocha": "^3.2.0",
"sinon": "^1.17.4",

View File

@ -17,8 +17,8 @@
'use strict';
const co = require('co');
const app = require('koa')();
const Koa = require('koa');
const koaBody = require('koa-body');
const log = require('npmlog');
const config = require('config');
const serve = require('koa-static');
@ -31,6 +31,8 @@ const PublicKey = require('./service/public-key');
const HKP = require('./route/hkp');
const REST = require('./route/rest');
const app = new Koa();
let mongo;
let email;
let pgp;
@ -43,55 +45,50 @@ let rest;
//
// HKP routes
router.post('/pks/add', function *() {
yield hkp.add(this);
});
router.get('/pks/lookup', function *() {
yield hkp.lookup(this);
});
router.post('/pks/add', ctx => hkp.add(ctx));
router.get('/pks/lookup', ctx => hkp.lookup(ctx));
// REST api routes
router.post('/api/v1/key', function *() {
yield rest.create(this);
});
router.get('/api/v1/key', function *() {
yield rest.query(this);
});
router.del('/api/v1/key', function *() {
yield rest.remove(this);
});
router.post('/api/v1/key', ctx => rest.create(ctx));
router.get('/api/v1/key', ctx => rest.query(ctx));
router.del('/api/v1/key', ctx => rest.remove(ctx));
// Redirect all http traffic to https
app.use(function *(next) {
if (util.isTrue(config.server.httpsUpgrade) && util.checkHTTP(this)) {
this.redirect(`https://${this.hostname}${this.url}`);
app.use(async (ctx, next) => {
if (util.isTrue(config.server.httpsUpgrade) && util.checkHTTP(ctx)) {
ctx.redirect(`https://${ctx.hostname}${ctx.url}`);
} else {
yield next;
await next();
}
});
// Set HTTP response headers
app.use(function *(next) {
app.use(async (ctx, next) => {
// HSTS
if (util.isTrue(config.server.httpsUpgrade)) {
this.set('Strict-Transport-Security', 'max-age=16070400');
ctx.set('Strict-Transport-Security', 'max-age=16070400');
}
// HPKP
if (config.server.httpsKeyPin && config.server.httpsKeyPinBackup) {
this.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`);
ctx.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`);
}
// CSP
this.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; script-src 'self' code.jquery.com; style-src 'self' maxcdn.bootstrapcdn.com; font-src 'self' maxcdn.bootstrapcdn.com");
ctx.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; script-src 'self' code.jquery.com; style-src 'self' maxcdn.bootstrapcdn.com; font-src 'self' maxcdn.bootstrapcdn.com");
// Prevent rendering website in foreign iframe (Clickjacking)
this.set('X-Frame-Options', 'DENY');
ctx.set('X-Frame-Options', 'DENY');
// CORS
this.set('Access-Control-Allow-Origin', '*');
this.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
this.set('Access-Control-Allow-Headers', 'Content-Type');
this.set('Connection', 'keep-alive');
yield next;
ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
ctx.set('Access-Control-Allow-Headers', 'Content-Type');
ctx.set('Connection', 'keep-alive');
await next();
});
app.use(koaBody({
multipart: true,
formLimit: '1mb'
}));
app.use(router.routes());
app.use(router.allowedMethods());
@ -124,19 +121,23 @@ function injectDependencies() {
//
if (!global.testing) { // don't automatically start server in tests
co(function *() {
const app = yield init();
app.listen(config.server.port);
log.info('app', `Ready to rock! Listening on http://localhost:${config.server.port}`);
}).catch(err => log.error('app', 'Initialization failed!', err));
(async () => {
try {
const app = await init();
app.listen(config.server.port);
log.info('app', `Ready to rock! Listening on http://localhost:${config.server.port}`);
} catch (err) {
log.error('app', 'Initialization failed!', err);
}
})();
}
function *init() {
async function init() {
log.level = config.log.level; // set log level depending on process.env.NODE_ENV
injectDependencies();
email.init(config.email);
log.info('app', 'Connecting to MongoDB ...');
yield mongo.init(config.mongo);
await mongo.init(config.mongo);
return app;
}

View File

@ -30,9 +30,9 @@ class Mongo {
* @param {String} pass The database user's password
* @yield {undefined}
*/
*init({uri, user, pass}) {
async init({uri, user, pass}) {
const url = `mongodb://${user}:${pass}@${uri}`;
this._db = yield MongoClient.connect(url);
this._db = await MongoClient.connect(url);
}
/**

View File

@ -58,7 +58,7 @@ class Email {
* @param {Object} origin origin of the server
* @yield {Object} send response from the SMTP server
*/
*send({template, userId, keyId, origin}) {
async send({template, userId, keyId, origin}) {
const message = {
from: this._sender,
to: userId,
@ -72,7 +72,7 @@ class Email {
nonce: userId.nonce
}
};
return yield this._sendHelper(message);
return this._sendHelper(message);
}
/**
@ -85,7 +85,7 @@ class Email {
* @param {Object} params (optional) nodermailer template parameters
* @yield {Object} reponse object containing SMTP info
*/
*_sendHelper({from, to, subject, text, html, params = {}}) {
async _sendHelper({from, to, subject, text, html, params = {}}) {
const template = {
subject,
text,
@ -107,7 +107,7 @@ class Email {
try {
const sendFn = this._transport.templateSender(template, sender);
const info = yield sendFn(recipient, params);
const info = await sendFn(recipient, params);
if (!this._checkResponse(info)) {
log.warn('email', 'Message may not have been received.', info);
}

View File

@ -17,7 +17,6 @@
'use strict';
const parse = require('co-body');
const util = require('../service/util');
/**
@ -37,13 +36,13 @@ class HKP {
* Public key upload via http POST
* @param {Object} ctx The koa request/response context
*/
*add(ctx) {
const {keytext: publicKeyArmored} = yield parse.form(ctx, {limit: '1mb'});
async add(ctx) {
const publicKeyArmored = ctx.request.body.keytext;
if (!publicKeyArmored) {
ctx.throw(400, 'Invalid request!');
}
const origin = util.origin(ctx);
yield this._publicKey.put({publicKeyArmored, origin});
await this._publicKey.put({publicKeyArmored, origin});
ctx.body = 'Upload successful. Check your inbox to verify your email address.';
ctx.status = 201;
}
@ -52,9 +51,9 @@ class HKP {
* Public key lookup via http GET
* @param {Object} ctx The koa request/response context
*/
*lookup(ctx) {
async lookup(ctx) {
const params = this.parseQueryString(ctx);
const key = yield this._publicKey.get(params);
const key = await this._publicKey.get(params);
this.setGetHeaders(ctx, params);
this.setGetBody(ctx, params, key);
}

View File

@ -17,7 +17,6 @@
'use strict';
const parse = require('co-body');
const util = require('../service/util');
/**
@ -37,13 +36,13 @@ class REST {
* Public key upload via http POST
* @param {Object} ctx The koa request/response context
*/
*create(ctx) {
const {publicKeyArmored, primaryEmail} = yield parse.json(ctx, {limit: '1mb'});
async create(ctx) {
const {publicKeyArmored, primaryEmail} = ctx.request.body;
if (!publicKeyArmored || (primaryEmail && !util.isEmail(primaryEmail))) {
ctx.throw(400, 'Invalid request!');
}
const origin = util.origin(ctx);
yield this._publicKey.put({publicKeyArmored, primaryEmail, origin});
await this._publicKey.put({publicKeyArmored, primaryEmail, origin});
ctx.body = 'Upload successful. Check your inbox to verify your email address.';
ctx.status = 201;
}
@ -52,29 +51,29 @@ class REST {
* Public key query via http GET
* @param {Object} ctx The koa request/response context
*/
*query(ctx) {
async query(ctx) {
const op = ctx.query.op;
if (op === 'verify' || op === 'verifyRemove') {
return yield this[op](ctx); // delegate operation
return this[op](ctx); // delegate operation
}
// do READ if no 'op' provided
const q = {keyId: ctx.query.keyId, fingerprint: ctx.query.fingerprint, email: ctx.query.email};
if (!util.isKeyId(q.keyId) && !util.isFingerPrint(q.fingerprint) && !util.isEmail(q.email)) {
ctx.throw(400, 'Invalid request!');
}
ctx.body = yield this._publicKey.get(q);
ctx.body = await this._publicKey.get(q);
}
/**
* Verify a public key's user id via http GET
* @param {Object} ctx The koa request/response context
*/
*verify(ctx) {
async verify(ctx) {
const q = {keyId: ctx.query.keyId, nonce: ctx.query.nonce};
if (!util.isKeyId(q.keyId) || !util.isString(q.nonce)) {
ctx.throw(400, 'Invalid request!');
}
yield this._publicKey.verify(q);
await this._publicKey.verify(q);
// create link for sharing
const link = util.url(util.origin(ctx), `/pks/lookup?op=get&search=0x${q.keyId.toUpperCase()}`);
ctx.body = `<p>Email address successfully verified!</p><p>Link to share your key: <a href="${link}" target="_blank">${link}</a></p>`;
@ -85,12 +84,12 @@ class REST {
* Request public key removal via http DELETE
* @param {Object} ctx The koa request/response context
*/
*remove(ctx) {
async remove(ctx) {
const q = {keyId: ctx.query.keyId, email: ctx.query.email, origin: util.origin(ctx)};
if (!util.isKeyId(q.keyId) && !util.isEmail(q.email)) {
ctx.throw(400, 'Invalid request!');
}
yield this._publicKey.requestRemove(q);
await this._publicKey.requestRemove(q);
ctx.body = 'Check your inbox to verify the removal of your key.';
ctx.status = 202;
}
@ -99,12 +98,12 @@ class REST {
* Verify public key removal via http GET
* @param {Object} ctx The koa request/response context
*/
*verifyRemove(ctx) {
async verifyRemove(ctx) {
const q = {keyId: ctx.query.keyId, nonce: ctx.query.nonce};
if (!util.isKeyId(q.keyId) || !util.isString(q.nonce)) {
ctx.throw(400, 'Invalid request!');
}
yield this._publicKey.verifyRemove(q);
await this._publicKey.verifyRemove(q);
ctx.body = 'Key successfully removed!';
}
}

View File

@ -65,18 +65,18 @@ class PublicKey {
* @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' }
* @yield {undefined}
*/
*put({publicKeyArmored, primaryEmail, origin}) {
async put({publicKeyArmored, primaryEmail, origin}) {
// parse key block
const key = this._pgp.parseKey(publicKeyArmored);
// check for existing verfied key by id or email addresses
const verified = yield this.getVerified(key);
const verified = await this.getVerified(key);
if (verified) {
util.throw(304, 'Key for this user already exists');
}
// store key in database
yield this._persisKey(key);
await this._persisKey(key);
// send mails to verify user ids (send only one if primary email is provided)
yield this._sendVerifyEmail(key, primaryEmail, origin);
await this._sendVerifyEmail(key, primaryEmail, origin);
}
/**
@ -84,15 +84,15 @@ class PublicKey {
* @param {Object} key public key parameters
* @yield {undefined} The persisted user id documents
*/
*_persisKey(key) {
async _persisKey(key) {
// delete old/unverified key
yield this._mongo.remove({keyId: key.keyId}, DB_TYPE);
await this._mongo.remove({keyId: key.keyId}, DB_TYPE);
// generate nonces for verification
for (const uid of key.userIds) {
uid.nonce = util.random();
}
// persist new key
const r = yield this._mongo.create(key, DB_TYPE);
const r = await this._mongo.create(key, DB_TYPE);
if (r.insertedCount !== 1) {
util.throw(500, 'Failed to persist key');
}
@ -106,7 +106,7 @@ class PublicKey {
* @param {Object} origin the server's origin (required for email links)
* @yield {undefined}
*/
*_sendVerifyEmail({userIds, keyId, publicKeyArmored}, primaryEmail, origin) {
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) {
@ -115,7 +115,7 @@ class PublicKey {
// send emails
for (const userId of userIds) {
userId.publicKeyArmored = publicKeyArmored; // set key for encryption
yield this._email.send({template: tpl.verifyKey, userId, keyId, origin});
await this._email.send({template: tpl.verifyKey, userId, keyId, origin});
}
}
@ -125,20 +125,20 @@ class PublicKey {
* @param {string} nonce The verification nonce proving email address ownership
* @yield {undefined}
*/
*verify({keyId, nonce}) {
async verify({keyId, nonce}) {
// look for verification nonce in database
const query = {keyId, 'userIds.nonce': nonce};
const key = yield this._mongo.get(query, DB_TYPE);
const key = await this._mongo.get(query, DB_TYPE);
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 = yield this.getVerified(key);
const verified = await this.getVerified(key);
if (verified && verified.keyId !== keyId) {
util.throw(304, 'Key for this user already exists');
}
// flag the user id as verified
yield this._mongo.update(query, {
await this._mongo.update(query, {
'userIds.$.verified': true,
'userIds.$.nonce': null
}, DB_TYPE);
@ -153,7 +153,7 @@ class PublicKey {
* @param {string} keyId (optional) The public key id
* @yield {Object} The verified key document
*/
*getVerified({userIds, fingerprint, keyId}) {
async getVerified({userIds, fingerprint, keyId}) {
let queries = [];
// query by fingerprint
if (fingerprint) {
@ -180,7 +180,7 @@ class PublicKey {
}
})));
}
return yield this._mongo.get({$or: queries}, DB_TYPE);
return this._mongo.get({$or: queries}, DB_TYPE);
}
/**
@ -191,10 +191,10 @@ class PublicKey {
* @param {String} email (optional) The user's email address
* @yield {Object} The public key document
*/
*get({fingerprint, keyId, email}) {
async get({fingerprint, keyId, email}) {
// look for verified key
const userIds = email ? [{email}] : undefined;
const key = yield this.getVerified({keyId, fingerprint, userIds});
const key = await this.getVerified({keyId, fingerprint, userIds});
if (!key) {
util.throw(404, 'Key not found');
}
@ -218,16 +218,16 @@ class PublicKey {
* @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' }
* @yield {undefined}
*/
*requestRemove({keyId, email, origin}) {
async requestRemove({keyId, email, origin}) {
// flag user ids for removal
const key = yield this._flagForRemove(keyId, email);
const key = await this._flagForRemove(keyId, email);
if (!key) {
util.throw(404, 'User id not found');
}
// send verification mails
keyId = key.keyId; // get keyId in case request was by email
for (const userId of key.userIds) {
yield this._email.send({template: tpl.verifyRemove, userId, keyId, origin});
await this._email.send({template: tpl.verifyRemove, userId, keyId, origin});
}
}
@ -238,16 +238,16 @@ class PublicKey {
* @param {String} email (optional) The user's email address
* @yield {Array} A list of user ids with nonces
*/
*_flagForRemove(keyId, email) {
async _flagForRemove(keyId, email) {
const query = email ? {'userIds.email': email} : {keyId};
const key = yield this._mongo.get(query, DB_TYPE);
const key = await this._mongo.get(query, DB_TYPE);
if (!key) {
return;
}
// flag only the provided user id
if (email) {
const nonce = util.random();
yield this._mongo.update(query, {'userIds.$.nonce': nonce}, DB_TYPE);
await this._mongo.update(query, {'userIds.$.nonce': nonce}, DB_TYPE);
const uid = key.userIds.find(u => u.email === email);
uid.nonce = nonce;
return {userIds: [uid], keyId: key.keyId};
@ -256,7 +256,7 @@ class PublicKey {
if (keyId) {
for (const uid of key.userIds) {
const nonce = util.random();
yield this._mongo.update({'userIds.email': uid.email}, {'userIds.$.nonce': nonce}, DB_TYPE);
await this._mongo.update({'userIds.email': uid.email}, {'userIds.$.nonce': nonce}, DB_TYPE);
uid.nonce = nonce;
}
return key;
@ -270,14 +270,14 @@ class PublicKey {
* @param {string} nonce The verification nonce proving email address ownership
* @yield {undefined}
*/
*verifyRemove({keyId, nonce}) {
async verifyRemove({keyId, nonce}) {
// check if key exists in database
const flagged = yield this._mongo.get({keyId, 'userIds.nonce': nonce}, DB_TYPE);
const flagged = await this._mongo.get({keyId, 'userIds.nonce': nonce}, DB_TYPE);
if (!flagged) {
util.throw(404, 'User id not found');
}
// delete the key
yield this._mongo.remove({keyId}, DB_TYPE);
await this._mongo.remove({keyId}, DB_TYPE);
}
}

View File

@ -10,6 +10,7 @@ const log = require('npmlog');
describe('Koa App (HTTP Server) Integration Tests', function() {
this.timeout(20000);
let sandbox;
let app;
let mongo;
let sendEmailStub;
@ -21,40 +22,41 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
const primaryEmail = 'safewithme.testuser@gmail.com';
const fingerprint = '4277257930867231CE393FB8DBC0B3D92B1B86E9';
before(function *() {
before(async () => {
sandbox = sinon.sandbox.create();
publicKeyArmored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8');
mongo = new Mongo();
yield mongo.init(config.mongo);
await mongo.init(config.mongo);
sendEmailStub = sinon.stub().returns(Promise.resolve({response: '250'}));
sendEmailStub = sandbox.stub().returns(Promise.resolve({response: '250'}));
sendEmailStub.withArgs(sinon.match(recipient => recipient.to.address === primaryEmail), sinon.match(params => {
emailParams = params;
return Boolean(params.nonce);
}));
sinon.stub(nodemailer, 'createTransport').returns({
sandbox.stub(nodemailer, 'createTransport').returns({
templateSender: () => sendEmailStub,
use() {}
});
sinon.stub(log);
sandbox.stub(log);
global.testing = true;
const init = require('../../src/app');
app = yield init();
app = await init();
});
beforeEach(function *() {
yield mongo.clear(DB_TYPE_PUB_KEY);
yield mongo.clear(DB_TYPE_USER_ID);
beforeEach(async () => {
await mongo.clear(DB_TYPE_PUB_KEY);
await mongo.clear(DB_TYPE_USER_ID);
emailParams = null;
});
after(function *() {
sinon.restore(log);
nodemailer.createTransport.restore();
yield mongo.clear(DB_TYPE_PUB_KEY);
yield mongo.clear(DB_TYPE_USER_ID);
yield mongo.disconnect();
after(async () => {
sandbox.restore();
await mongo.clear(DB_TYPE_PUB_KEY);
await mongo.clear(DB_TYPE_USER_ID);
await mongo.disconnect();
});
describe('REST api', () => {

View File

@ -36,7 +36,7 @@ describe('Email Integration Tests', function() {
});
describe("_sendHelper", () => {
it('should work', function *() {
it('should work', async () => {
const mailOptions = {
from: email._sender,
to: recipient,
@ -44,30 +44,30 @@ describe('Email Integration Tests', function() {
text: 'Hello world 🐴', // plaintext body
html: '<b>Hello world 🐴</b>' // html body
};
const info = yield email._sendHelper(mailOptions);
const info = await email._sendHelper(mailOptions);
expect(info).to.exist;
});
});
describe("send verifyKey template", () => {
it('should send plaintext email', function *() {
it('should send plaintext email', async () => {
delete userId.publicKeyArmored;
yield email.send({template: tpl.verifyKey, userId, keyId, origin});
await email.send({template: tpl.verifyKey, userId, keyId, origin});
});
it('should send pgp encrypted email', function *() {
yield email.send({template: tpl.verifyKey, userId, keyId, origin});
it('should send pgp encrypted email', async () => {
await email.send({template: tpl.verifyKey, userId, keyId, origin});
});
});
describe("send verifyRemove template", () => {
it('should send plaintext email', function *() {
it('should send plaintext email', async () => {
delete userId.publicKeyArmored;
yield email.send({template: tpl.verifyRemove, userId, keyId, origin});
await email.send({template: tpl.verifyRemove, userId, keyId, origin});
});
it('should send pgp encrypted email', function *() {
yield email.send({template: tpl.verifyRemove, userId, keyId, origin});
it('should send pgp encrypted email', async () => {
await email.send({template: tpl.verifyRemove, userId, keyId, origin});
});
});
});

View File

@ -9,31 +9,31 @@ describe('Mongo Integration Tests', function() {
const DB_TYPE = 'apple';
let mongo;
before(function *() {
before(async () => {
mongo = new Mongo();
yield mongo.init(config.mongo);
await mongo.init(config.mongo);
});
beforeEach(function *() {
yield mongo.clear(DB_TYPE);
beforeEach(async () => {
await mongo.clear(DB_TYPE);
});
after(function *() {
yield mongo.clear(DB_TYPE);
yield mongo.disconnect();
after(async () => {
await mongo.clear(DB_TYPE);
await mongo.disconnect();
});
describe("create", () => {
it('should insert a document', function *() {
const r = yield mongo.create({_id: '0'}, DB_TYPE);
it('should insert a document', async () => {
const r = await mongo.create({_id: '0'}, DB_TYPE);
expect(r.insertedCount).to.equal(1);
});
it('should fail if two with the same ID are inserted', function *() {
let r = yield mongo.create({_id: '0'}, DB_TYPE);
it('should fail if two with the same ID are inserted', async () => {
let r = await mongo.create({_id: '0'}, DB_TYPE);
expect(r.insertedCount).to.equal(1);
try {
r = yield mongo.create({_id: '0'}, DB_TYPE);
r = await mongo.create({_id: '0'}, DB_TYPE);
} catch (e) {
expect(e.message).to.match(/duplicate/);
}
@ -41,16 +41,16 @@ describe('Mongo Integration Tests', function() {
});
describe("batch", () => {
it('should insert a document', function *() {
const r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE);
it('should insert a document', async () => {
const r = await mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE);
expect(r.insertedCount).to.equal(2);
});
it('should fail if docs with the same ID are inserted', function *() {
let r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE);
it('should fail if docs with the same ID are inserted', async () => {
let r = await mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE);
expect(r.insertedCount).to.equal(2);
try {
r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE);
r = await mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE);
} catch (e) {
expect(e.message).to.match(/duplicate/);
}
@ -58,36 +58,36 @@ describe('Mongo Integration Tests', function() {
});
describe("update", () => {
it('should update a document', function *() {
let r = yield mongo.create({_id: '0'}, DB_TYPE);
r = yield mongo.update({_id: '0'}, {foo: 'bar'}, DB_TYPE);
it('should update a document', async () => {
let r = await mongo.create({_id: '0'}, DB_TYPE);
r = await mongo.update({_id: '0'}, {foo: 'bar'}, DB_TYPE);
expect(r.modifiedCount).to.equal(1);
r = yield mongo.get({_id: '0'}, DB_TYPE);
r = await mongo.get({_id: '0'}, DB_TYPE);
expect(r.foo).to.equal('bar');
});
});
describe("get", () => {
it('should get a document', function *() {
let r = yield mongo.create({_id: '0'}, DB_TYPE);
r = yield mongo.get({_id: '0'}, DB_TYPE);
it('should get a document', async () => {
let r = await mongo.create({_id: '0'}, DB_TYPE);
r = await mongo.get({_id: '0'}, DB_TYPE);
expect(r).to.exist;
});
});
describe("list", () => {
it('should list documents', function *() {
let r = yield mongo.batch([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE);
r = yield mongo.list({foo: 'bar'}, DB_TYPE);
it('should list documents', async () => {
let r = await mongo.batch([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE);
r = await mongo.list({foo: 'bar'}, DB_TYPE);
expect(r).to.deep.equal([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE);
});
});
describe("remove", () => {
it('should remove a document', function *() {
let r = yield mongo.create({_id: '0'}, DB_TYPE);
r = yield mongo.remove({_id: '0'}, DB_TYPE);
r = yield mongo.get({_id: '0'}, DB_TYPE);
it('should remove a document', async () => {
let r = await mongo.create({_id: '0'}, DB_TYPE);
r = await mongo.remove({_id: '0'}, DB_TYPE);
r = await mongo.get({_id: '0'}, DB_TYPE);
expect(r).to.not.exist;
});
});

View File

@ -10,6 +10,7 @@ const PublicKey = require('../../src/service/public-key');
describe('Public Key Integration Tests', function() {
this.timeout(20000);
let sandbox;
let publicKey;
let email;
let mongo;
@ -24,15 +25,17 @@ describe('Public Key Integration Tests', function() {
const primaryEmail2 = 'test2@example.com';
const origin = {host: 'localhost', protocol: 'http'};
before(function *() {
before(async () => {
publicKeyArmored = require('fs').readFileSync(`${__dirname}/../key3.asc`, 'utf8');
publicKeyArmored2 = require('fs').readFileSync(`${__dirname}/../key4.asc`, 'utf8');
mongo = new Mongo();
yield mongo.init(config.mongo);
await mongo.init(config.mongo);
});
beforeEach(function *() {
yield mongo.clear(DB_TYPE);
beforeEach(async () => {
sandbox = sinon.sandbox.create();
await mongo.clear(DB_TYPE);
mailsSent = [];
sendEmailStub = sinon.stub().returns(Promise.resolve({response: '250'}));
sendEmailStub.withArgs(sinon.match(recipient => {
@ -44,7 +47,7 @@ describe('Public Key Integration Tests', function() {
expect(params.keyId).to.exist;
return true;
}));
sinon.stub(nodemailer, 'createTransport').returns({
sandbox.stub(nodemailer, 'createTransport').returns({
templateSender: () => sendEmailStub
});
email = new Email(nodemailer);
@ -58,39 +61,39 @@ describe('Public Key Integration Tests', function() {
});
afterEach(() => {
nodemailer.createTransport.restore();
sandbox.restore();
});
after(function *() {
yield mongo.clear(DB_TYPE);
yield mongo.disconnect();
after(async () => {
await mongo.clear(DB_TYPE);
await mongo.disconnect();
});
describe('put', () => {
it('should persist key and send verification email with primaryEmail', function *() {
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
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', function *() {
yield publicKey.put({publicKeyArmored, origin});
it('should persist key and send verification email without primaryEmail', async () => {
await publicKey.put({publicKeyArmored, origin});
expect(mailsSent.length).to.equal(4);
});
it('should work twice if not yet verified', function *() {
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
it('should work twice if not yet verified', async () => {
await publicKey.put({publicKeyArmored, primaryEmail, origin});
expect(mailsSent.length).to.equal(1);
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
await publicKey.put({publicKeyArmored, primaryEmail, origin});
expect(mailsSent.length).to.equal(2);
});
it('should throw 304 if key already exists', function *() {
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
yield publicKey.verify(mailsSent[0].params);
it('should throw 304 if key already exists', async () => {
await publicKey.put({publicKeyArmored, primaryEmail, origin});
await publicKey.verify(mailsSent[0].params);
try {
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
await publicKey.put({publicKeyArmored, primaryEmail, origin});
expect(false).to.be.true;
} catch (e) {
expect(e.status).to.equal(304);
@ -99,60 +102,60 @@ describe('Public Key Integration Tests', function() {
});
describe('verify', () => {
it('should update the document', function *() {
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
it('should update the document', async () => {
await publicKey.put({publicKeyArmored, primaryEmail, origin});
const emailParams = mailsSent[0].params;
yield publicKey.verify(emailParams);
const gotten = yield mongo.get({keyId: emailParams.keyId}, DB_TYPE);
await publicKey.verify(emailParams);
const gotten = await mongo.get({keyId: emailParams.keyId}, DB_TYPE);
expect(gotten.userIds[0].verified).to.be.true;
expect(gotten.userIds[0].nonce).to.be.null;
expect(gotten.userIds[1].verified).to.be.false;
expect(gotten.userIds[1].nonce).to.exist;
});
it('should not find the document', function *() {
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
it('should not find the document', async () => {
await publicKey.put({publicKeyArmored, primaryEmail, origin});
const emailParams = mailsSent[0].params;
try {
yield publicKey.verify({keyId: emailParams.keyId, nonce: 'fake_nonce'});
await publicKey.verify({keyId: emailParams.keyId, nonce: 'fake_nonce'});
expect(true).to.be.false;
} catch (e) {
expect(e.status).to.equal(404);
}
const gotten = yield mongo.get({keyId: emailParams.keyId}, DB_TYPE);
const gotten = await mongo.get({keyId: emailParams.keyId}, DB_TYPE);
expect(gotten.userIds[0].verified).to.be.false;
expect(gotten.userIds[0].nonce).to.equal(emailParams.nonce);
expect(gotten.userIds[1].verified).to.be.false;
expect(gotten.userIds[1].nonce).to.exist;
});
it('should not verify a second key for already verified user id of another key', function *() {
yield publicKey.put({publicKeyArmored, primaryEmail: primaryEmail2, origin});
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);
yield publicKey.put({publicKeyArmored: publicKeyArmored2, primaryEmail: primaryEmail2, origin});
await publicKey.put({publicKeyArmored: publicKeyArmored2, primaryEmail: primaryEmail2, origin});
expect(mailsSent.length).to.equal(2);
yield publicKey.verify(mailsSent[1].params);
await publicKey.verify(mailsSent[1].params);
try {
yield publicKey.verify(mailsSent[0].params);
await publicKey.verify(mailsSent[0].params);
expect(true).to.be.false;
} catch (e) {
expect(e.status).to.equal(304);
}
const gotten = yield mongo.get({keyId: mailsSent[0].params.keyId}, DB_TYPE);
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);
});
it('should be able to verify multiple user ids', function *() {
yield publicKey.put({publicKeyArmored, origin});
it('should be able to verify multiple user ids', async () => {
await publicKey.put({publicKeyArmored, origin});
expect(mailsSent.length).to.equal(4);
yield publicKey.verify(mailsSent[0].params);
yield publicKey.verify(mailsSent[1].params);
yield publicKey.verify(mailsSent[2].params);
yield publicKey.verify(mailsSent[3].params);
const gotten = yield mongo.get({keyId: mailsSent[0].params.keyId}, DB_TYPE);
await publicKey.verify(mailsSent[0].params);
await publicKey.verify(mailsSent[1].params);
await publicKey.verify(mailsSent[2].params);
await publicKey.verify(mailsSent[3].params);
const gotten = await mongo.get({keyId: mailsSent[0].params.keyId}, DB_TYPE);
expect(gotten.userIds[0].verified).to.be.true;
expect(gotten.userIds[1].verified).to.be.true;
expect(gotten.userIds[2].verified).to.be.true;
@ -164,67 +167,67 @@ describe('Public Key Integration Tests', function() {
let key;
describe('should find a verified key', () => {
beforeEach(function *() {
beforeEach(async () => {
key = pgp.parseKey(publicKeyArmored);
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
yield publicKey.verify(mailsSent[0].params);
await publicKey.put({publicKeyArmored, primaryEmail, origin});
await publicKey.verify(mailsSent[0].params);
});
it('by fingerprint', function *() {
const verified = yield publicKey.getVerified({fingerprint: key.fingerprint});
it('by fingerprint', async () => {
const verified = await publicKey.getVerified({fingerprint: key.fingerprint});
expect(verified).to.exist;
});
it('by all userIds', function *() {
const verified = yield publicKey.getVerified({userIds: key.userIds});
it('by all userIds', async () => {
const verified = await publicKey.getVerified({userIds: key.userIds});
expect(verified).to.exist;
});
it('by verified userId', function *() {
const verified = yield publicKey.getVerified({userIds: [key.userIds[0]]});
it('by verified userId', async () => {
const verified = await publicKey.getVerified({userIds: [key.userIds[0]]});
expect(verified).to.exist;
});
it('by unverified userId', function *() {
const verified = yield publicKey.getVerified({userIds: [key.userIds[1]]});
it('by unverified userId', async () => {
const verified = await publicKey.getVerified({userIds: [key.userIds[1]]});
expect(verified).to.not.exist;
});
it('by keyId', function *() {
const verified = yield publicKey.getVerified({keyId: key.keyId});
it('by keyId', async () => {
const verified = await publicKey.getVerified({keyId: key.keyId});
expect(verified).to.exist;
});
it('by all params', function *() {
const verified = yield publicKey.getVerified(key);
it('by all params', async () => {
const verified = await publicKey.getVerified(key);
expect(verified).to.exist;
});
});
describe('should not find an unverified key', () => {
beforeEach(function *() {
beforeEach(async () => {
key = pgp.parseKey(publicKeyArmored);
key.userIds[0].verified = false;
yield mongo.create(key, DB_TYPE);
await mongo.create(key, DB_TYPE);
});
it('by fingerprint', function *() {
const verified = yield publicKey.getVerified({fingerprint: key.fingerprint});
it('by fingerprint', async () => {
const verified = await publicKey.getVerified({fingerprint: key.fingerprint});
expect(verified).to.not.exist;
});
it('by userIds', function *() {
const verified = yield publicKey.getVerified({userIds: key.userIds});
it('by userIds', async () => {
const verified = await publicKey.getVerified({userIds: key.userIds});
expect(verified).to.not.exist;
});
it('by keyId', function *() {
const verified = yield publicKey.getVerified({keyId: key.keyId});
it('by keyId', async () => {
const verified = await publicKey.getVerified({keyId: key.keyId});
expect(verified).to.not.exist;
});
it('by all params', function *() {
const verified = yield publicKey.getVerified(key);
it('by all params', async () => {
const verified = await publicKey.getVerified(key);
expect(verified).to.not.exist;
});
});
@ -233,52 +236,52 @@ describe('Public Key Integration Tests', function() {
describe('get', () => {
let emailParams;
beforeEach(function *() {
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
beforeEach(async () => {
await publicKey.put({publicKeyArmored, primaryEmail, origin});
emailParams = mailsSent[0].params;
});
it('should return verified key by key id', function *() {
yield publicKey.verify(emailParams);
const key = yield publicKey.get({keyId: emailParams.keyId});
it('should return verified key by key id', async () => {
await publicKey.verify(emailParams);
const key = await publicKey.get({keyId: emailParams.keyId});
expect(key.publicKeyArmored).to.exist;
});
it('should return verified key by key id (uppercase)', function *() {
yield publicKey.verify(emailParams);
const key = yield publicKey.get({keyId: emailParams.keyId.toUpperCase()});
it('should return verified key by key id (uppercase)', async () => {
await publicKey.verify(emailParams);
const key = await publicKey.get({keyId: emailParams.keyId.toUpperCase()});
expect(key.publicKeyArmored).to.exist;
});
it('should return verified key by fingerprint', function *() {
yield publicKey.verify(emailParams);
it('should return verified key by fingerprint', async () => {
await publicKey.verify(emailParams);
const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint;
const key = yield publicKey.get({fingerprint});
const key = await publicKey.get({fingerprint});
expect(key.publicKeyArmored).to.exist;
});
it('should return verified key by fingerprint (uppercase)', function *() {
yield publicKey.verify(emailParams);
it('should return verified key by fingerprint (uppercase)', async () => {
await publicKey.verify(emailParams);
const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint.toUpperCase();
const key = yield publicKey.get({fingerprint});
const key = await publicKey.get({fingerprint});
expect(key.publicKeyArmored).to.exist;
});
it('should return verified key by email address', function *() {
yield publicKey.verify(emailParams);
const key = yield publicKey.get({email: primaryEmail});
it('should return verified key by email address', async () => {
await publicKey.verify(emailParams);
const key = await publicKey.get({email: primaryEmail});
expect(key.publicKeyArmored).to.exist;
});
it('should return verified key by email address (uppercase)', function *() {
yield publicKey.verify(emailParams);
const key = yield publicKey.get({email: primaryEmail.toUpperCase()});
it('should return verified key by email address (uppercase)', async () => {
await publicKey.verify(emailParams);
const key = await publicKey.get({email: primaryEmail.toUpperCase()});
expect(key.publicKeyArmored).to.exist;
});
it('should throw 404 for unverified key', function *() {
it('should throw 404 for unverified key', async () => {
try {
yield publicKey.get({keyId: emailParams.keyId});
await publicKey.get({keyId: emailParams.keyId});
expect(false).to.be.true;
} catch (e) {
expect(e.status).to.equal(404);
@ -289,31 +292,31 @@ describe('Public Key Integration Tests', function() {
describe('requestRemove', () => {
let keyId;
beforeEach(function *() {
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
beforeEach(async () => {
await publicKey.put({publicKeyArmored, primaryEmail, origin});
keyId = mailsSent[0].params.keyId;
});
it('should work for verified key', function *() {
yield publicKey.verify(mailsSent[0].params);
yield publicKey.requestRemove({keyId, origin});
it('should work for verified key', async () => {
await publicKey.verify(mailsSent[0].params);
await publicKey.requestRemove({keyId, origin});
expect(mailsSent.length).to.equal(5);
});
it('should work for unverified key', function *() {
yield publicKey.requestRemove({keyId, origin});
it('should work for unverified key', async () => {
await publicKey.requestRemove({keyId, origin});
expect(mailsSent.length).to.equal(5);
});
it('should work by email address', function *() {
yield publicKey.requestRemove({email: primaryEmail, origin});
it('should work by email address', async () => {
await publicKey.requestRemove({email: primaryEmail, origin});
expect(mailsSent.length).to.equal(2);
});
it('should throw 404 for no key', function *() {
yield mongo.remove({keyId}, DB_TYPE);
it('should throw 404 for no key', async () => {
await mongo.remove({keyId}, DB_TYPE);
try {
yield publicKey.requestRemove({keyId, origin});
await publicKey.requestRemove({keyId, origin});
expect(false).to.be.true;
} catch (e) {
expect(e.status).to.equal(404);
@ -324,22 +327,22 @@ describe('Public Key Integration Tests', function() {
describe('verifyRemove', () => {
let keyId;
beforeEach(function *() {
yield publicKey.put({publicKeyArmored, primaryEmail, origin});
beforeEach(async () => {
await publicKey.put({publicKeyArmored, primaryEmail, origin});
keyId = mailsSent[0].params.keyId;
yield publicKey.requestRemove({keyId, origin});
await publicKey.requestRemove({keyId, origin});
});
it('should remove key', function *() {
yield publicKey.verifyRemove(mailsSent[1].params);
const key = yield mongo.get({keyId}, DB_TYPE);
it('should remove key', async () => {
await publicKey.verifyRemove(mailsSent[1].params);
const key = await mongo.get({keyId}, DB_TYPE);
expect(key).to.not.exist;
});
it('should throw 404 for no key', function *() {
yield mongo.remove({keyId}, DB_TYPE);
it('should throw 404 for no key', async () => {
await mongo.remove({keyId}, DB_TYPE);
try {
yield publicKey.verifyRemove(mailsSent[1].params);
await publicKey.verifyRemove(mailsSent[1].params);
expect(false).to.be.true;
} catch (e) {
expect(e.status).to.equal(404);

View File

@ -1,7 +1,5 @@
'use strict';
require('co-mocha')(require('mocha')); // monkey patch mocha for generators
const expect = require('chai').expect;
const sinon = require('sinon');

View File

@ -5,6 +5,7 @@ const Email = require('../../src/email/email');
const nodemailer = require('nodemailer');
describe('Email Unit Tests', () => {
let sandbox;
let email;
let sendFnStub;
@ -36,13 +37,14 @@ describe('Email Unit Tests', () => {
};
beforeEach(() => {
sandbox = sinon.sandbox.create();
sendFnStub = sinon.stub();
sinon.stub(nodemailer, 'createTransport').returns({
sandbox.stub(nodemailer, 'createTransport').returns({
templateSender: () => sendFnStub
});
sinon.stub(log, 'warn');
sinon.stub(log, 'error');
sandbox.stub(log);
email = new Email(nodemailer);
email.init({
@ -54,50 +56,44 @@ describe('Email Unit Tests', () => {
});
afterEach(() => {
nodemailer.createTransport.restore();
log.warn.restore();
log.error.restore();
sandbox.restore();
});
describe("send", () => {
beforeEach(() => {
sinon.stub(email, '_sendHelper').returns(Promise.resolve({response: '250'}));
sandbox.stub(email, '_sendHelper').returns(Promise.resolve({response: '250'}));
});
afterEach(() => {
email._sendHelper.restore();
});
it('should work', function *() {
const info = yield email.send({template, userId: userId1, keyId, origin});
it('should work', async () => {
const info = await email.send({template, userId: userId1, keyId, origin});
expect(info.response).to.match(/^250/);
});
});
describe("_sendHelper", () => {
it('should work', function *() {
it('should work', async () => {
sendFnStub.returns(Promise.resolve({response: '250'}));
const info = yield email._sendHelper(mailOptions);
const info = await email._sendHelper(mailOptions);
expect(info.response).to.match(/^250/);
});
it('should log warning for reponse error', function *() {
it('should log warning for reponse error', async () => {
sendFnStub.returns(Promise.resolve({response: '554'}));
const info = yield email._sendHelper(mailOptions);
const info = await email._sendHelper(mailOptions);
expect(info.response).to.match(/^554/);
expect(log.warn.calledOnce).to.be.true;
});
it('should fail', function *() {
it('should fail', async () => {
sendFnStub.returns(Promise.reject(new Error('boom')));
try {
yield email._sendHelper(mailOptions);
await email._sendHelper(mailOptions);
} catch (e) {
expect(log.error.calledOnce).to.be.true;
expect(e.status).to.equal(500);

View File

@ -6,47 +6,50 @@ const openpgp = require('openpgp');
const PGP = require('../../src/service/pgp');
describe('PGP Unit Tests', () => {
let sandbox;
let pgp;
let key1Armored;
let key2Armored;
let key3Armored;
beforeEach(() => {
sandbox = sinon.sandbox.create();
sandbox.stub(log);
key1Armored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8');
key2Armored = fs.readFileSync(`${__dirname}/../key2.asc`, 'utf8');
key3Armored = fs.readFileSync(`${__dirname}/../key3.asc`, 'utf8');
pgp = new PGP();
});
afterEach(() => {
sandbox.restore();
});
describe('parseKey', () => {
it('should should throw error on key parsing', () => {
const readStub = sinon.stub(openpgp.key, 'readArmored').returns({err: [new Error()]});
sinon.stub(log, 'error');
sandbox.stub(openpgp.key, 'readArmored').returns({err: [new Error()]});
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/Failed to parse/);
expect(log.error.calledOnce).to.be.true;
log.error.restore();
readStub.restore();
});
it('should should throw error when more than one key', () => {
const readStub = sinon.stub(openpgp.key, 'readArmored').returns({keys: [{}, {}]});
sandbox.stub(openpgp.key, 'readArmored').returns({keys: [{}, {}]});
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only one key/);
readStub.restore();
});
it('should should throw error when more than one key', () => {
const readStub = sinon.stub(openpgp.key, 'readArmored').returns({
sandbox.stub(openpgp.key, 'readArmored').returns({
keys: [{
primaryKey: {},
verifyPrimaryKey() { return false; }
}]
});
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/primary key verification/);
readStub.restore();
});
it('should only accept 16 char key id', () => {
const readStub = sinon.stub(openpgp.key, 'readArmored').returns({
sandbox.stub(openpgp.key, 'readArmored').returns({
keys: [{
primaryKey: {
fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e9',
@ -60,11 +63,10 @@ describe('PGP Unit Tests', () => {
}]
});
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/);
readStub.restore();
});
it('should only accept version 4 fingerprint', () => {
const readStub = sinon.stub(openpgp.key, 'readArmored').returns({
sandbox.stub(openpgp.key, 'readArmored').returns({
keys: [{
primaryKey: {
fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e',
@ -78,11 +80,10 @@ describe('PGP Unit Tests', () => {
}]
});
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/);
readStub.restore();
});
it('should only accept valid user ids', () => {
sinon.stub(pgp, 'parseUserIds').returns([]);
sandbox.stub(pgp, 'parseUserIds').returns([]);
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/invalid user ids/);
});
@ -182,11 +183,10 @@ describe('PGP Unit Tests', () => {
});
it('should throw for a invalid email address', () => {
const verifyStub = sinon.stub(key.users[0], 'isValidSelfCertificate').returns(true);
sandbox.stub(key.users[0], 'isValidSelfCertificate').returns(true);
key.users[0].userId.userid = 'safewithme testuser <safewithme.testusergmail.com>';
const parsed = pgp.parseUserIds(key.users, key.primaryKey);
expect(parsed.length).to.equal(0);
verifyStub.restore();
});
});
});