Merge pull request #39 from mailvelope/dev/eslint

Dev/eslint
This commit is contained in:
Tankred Hase 2017-08-15 16:38:10 +08:00 committed by GitHub
commit 158a7418d0
26 changed files with 421 additions and 370 deletions

59
.eslintrc Normal file
View File

@ -0,0 +1,59 @@
{
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 6
},
"env": {
"node": true,
"es6": true
},
"rules": {
"strict": ["error", "global"],
/* possible errors */
"no-console": 0,
"no-empty": ["error", { "allowEmptyCatch": true }], // disallow empty block statements
/* best practices */
"curly": 2, // enforce consistent brace style for all control statements
"no-eval": 2, // disallow the use of eval()
"no-extend-native": 2, // disallow extending native types
"no-global-assign": 2, // disallow assignments to native objects or read-only global variables
"no-implicit-coercion": 2, // disallow shorthand type conversions
"no-implicit-globals": 2, // disallow var and named function declarations in the global scope
"no-implied-eval": 2, // disallow the use of eval()-like methods
"no-lone-blocks": 2, // disallow unnecessary nested blocks
"no-useless-escape": 0, // disallow unnecessary escape characters
/* Stylistic Issues */
"array-bracket-spacing": 1, // enforce consistent spacing inside array brackets
"block-spacing": 1, // enforce consistent spacing inside single-line blocks
"comma-spacing": 1, // enforce consistent spacing before and after commas
"computed-property-spacing": 1, // enforce consistent spacing inside computed property brackets
"eol-last": 1, // enforce at least one newline at the end of files
"func-call-spacing": 1, // require or disallow spacing between function identifiers and their invocations
"indent": ["warn", 2, {"MemberExpression": 0, "SwitchCase": 1}], // enforce consistent indentation
"key-spacing": ["warn", { "mode": "minimum" }], // enforce consistent spacing before and after keywords
"keyword-spacing": 1, // enforce consistent spacing between keys and values in object literal properties
"linebreak-style": 1, // enforce consistent linebreak style
"no-trailing-spaces": 1, // disallow trailing whitespace at the end of lines
"no-var": 1, // require let or const instead of var
"object-curly-spacing": ["warn", "never"], // enforce consistent spacing inside braces
"one-var": ["warn", "never"], // enforce variables to be declared either together or separately in functions
"padded-blocks": ["warn", "never"], // require or disallow padding within blocks
"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-in-parens": ["warn", "never"], // enforce consistent spacing inside parentheses
"space-infix-ops": 1, // require spacing around operators
/* ES6 */
"arrow-body-style": ["warn", "as-needed"], // require braces around arrow function bodies
"arrow-parens": ["warn", "as-needed"], // require parentheses around arrow function arguments
"arrow-spacing": 1, // enforce consistent spacing before and after the arrow in arrow functions
"no-useless-constructor": 1, // disallow unnecessary constructors
"object-shorthand": ["warn", "always", {"avoidQuotes": true}], // require or disallow method and property shorthand syntax for object literals
"prefer-arrow-callback": ["warn", {"allowNamedFunctions": true}], // require arrow functions as callbacks
"prefer-const": 1, // require const declarations for variables that are never reassigned after declared
"prefer-template": 1, // require template literals instead of string concatenation
"template-curly-spacing": ["warn", "never"] // require or disallow spacing around embedded expressions of template strings
},
"root": true
}

View File

@ -1,4 +0,0 @@
{
"disallowTrailingWhitespace": true,
"validateIndentation": 2
}

View File

@ -1,28 +0,0 @@
{
"strict": true,
"node": true,
"nonew": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"newcap": true,
"regexp": true,
"evil": true,
"eqnull": true,
"expr": true,
"undef": true,
"unused": true,
"esnext": true,
"globals": {
"expect": true,
"sinon": true,
"describe" : true,
"it" : true,
"before" : true,
"beforeEach" : true,
"after" : true,
"afterEach" : true,
"jQuery" : true
}
}

View File

@ -1,3 +1,5 @@
'use strict';
module.exports = { module.exports = {
log: { log: {

View File

@ -1,3 +1,5 @@
'use strict';
module.exports = { module.exports = {
mongo: { mongo: {

View File

@ -1,3 +1,5 @@
'use strict';
module.exports = { module.exports = {
log: { log: {

View File

@ -1,3 +1,5 @@
'use strict';
module.exports = { module.exports = {
log: { log: {

View File

@ -11,9 +11,8 @@
}, },
"scripts": { "scripts": {
"start": ": ${NODE_ENV=development} && node index.js", "start": ": ${NODE_ENV=development} && node index.js",
"test": ": ${NODE_ENV=development} && npm run test:jshint && npm run test:jscs && npm run test:unit && npm run test:integration", "test": ": ${NODE_ENV=development} && npm run test:lint && npm run test:unit && npm run test:integration",
"test:jshint": "jshint *.js src/**/*.js test/**/*.js", "test:lint": "eslint config src test *.js",
"test:jscs": "jscs *.js src/**/*.js test/**/*.js",
"test:unit": "mocha --opts test/mocha.opts ./test/unit/", "test:unit": "mocha --opts test/mocha.opts ./test/unit/",
"test:integration": "mocha --opts test/mocha.opts ./test/integration", "test:integration": "mocha --opts test/mocha.opts ./test/integration",
"release": "npm run release:install && npm run release:archive", "release": "npm run release:install && npm run release:archive",
@ -37,8 +36,7 @@
"devDependencies": { "devDependencies": {
"chai": "^4.1.1", "chai": "^4.1.1",
"co-mocha": "^1.1.2", "co-mocha": "^1.1.2",
"jscs": "^3.0.7", "eslint": "^4.4.1",
"jshint": "^2.9.4",
"mocha": "^3.2.0", "mocha": "^3.2.0",
"sinon": "^1.17.4", "sinon": "^1.17.4",
"supertest": "^3.0.0" "supertest": "^3.0.0"

View File

@ -31,7 +31,12 @@ const PublicKey = require('./service/public-key');
const HKP = require('./route/hkp'); const HKP = require('./route/hkp');
const REST = require('./route/rest'); const REST = require('./route/rest');
let mongo, email, pgp, publicKey, hkp, rest; let mongo;
let email;
let pgp;
let publicKey;
let hkp;
let rest;
// //
// Configure koa HTTP server // Configure koa HTTP server
@ -59,7 +64,7 @@ router.del('/api/v1/key', function *() {
// Redirect all http traffic to https // Redirect all http traffic to https
app.use(function *(next) { app.use(function *(next) {
if (util.isTrue(config.server.httpsUpgrade) && util.checkHTTP(this)) { if (util.isTrue(config.server.httpsUpgrade) && util.checkHTTP(this)) {
this.redirect('https://' + this.hostname + this.url); this.redirect(`https://${this.hostname}${this.url}`);
} else { } else {
yield next; yield next;
} }
@ -73,7 +78,7 @@ app.use(function *(next) {
} }
// HPKP // HPKP
if (config.server.httpsKeyPin && config.server.httpsKeyPinBackup) { 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'); this.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`);
} }
// CSP // 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"); 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");
@ -91,7 +96,7 @@ app.use(router.routes());
app.use(router.allowedMethods()); app.use(router.allowedMethods());
// serve static files // serve static files
app.use(serve(__dirname + '/static')); app.use(serve(`${__dirname}/static`));
app.on('error', (error, ctx) => { app.on('error', (error, ctx) => {
if (error.status) { if (error.status) {
@ -120,9 +125,9 @@ function injectDependencies() {
if (!global.testing) { // don't automatically start server in tests if (!global.testing) { // don't automatically start server in tests
co(function *() { co(function *() {
let app = yield init(); const app = yield init();
app.listen(config.server.port); app.listen(config.server.port);
log.info('app', 'Ready to rock! Listening on http://localhost:' + config.server.port); log.info('app', `Ready to rock! Listening on http://localhost:${config.server.port}`);
}).catch(err => log.error('app', 'Initialization failed!', err)); }).catch(err => log.error('app', 'Initialization failed!', err));
} }

View File

@ -23,7 +23,6 @@ const MongoClient = require('mongodb').MongoClient;
* A simple wrapper around the official MongoDB client. * A simple wrapper around the official MongoDB client.
*/ */
class Mongo { class Mongo {
/** /**
* Initializes the database client by connecting to the MongoDB. * Initializes the database client by connecting to the MongoDB.
* @param {String} uri The mongodb uri * @param {String} uri The mongodb uri
@ -31,8 +30,8 @@ class Mongo {
* @param {String} pass The database user's password * @param {String} pass The database user's password
* @yield {undefined} * @yield {undefined}
*/ */
*init({ uri, user, pass }) { *init({uri, user, pass}) {
let url = 'mongodb://' + user + ':' + pass + '@' + uri; const url = `mongodb://${user}:${pass}@${uri}`;
this._db = yield MongoClient.connect(url); this._db = yield MongoClient.connect(url);
} }
@ -51,7 +50,7 @@ class Mongo {
* @yield {Object} The operation result * @yield {Object} The operation result
*/ */
create(document, type) { create(document, type) {
let col = this._db.collection(type); const col = this._db.collection(type);
return col.insertOne(document); return col.insertOne(document);
} }
@ -62,7 +61,7 @@ class Mongo {
* @yield {Object} The operation result * @yield {Object} The operation result
*/ */
batch(documents, type) { batch(documents, type) {
let col = this._db.collection(type); const col = this._db.collection(type);
return col.insertMany(documents); return col.insertMany(documents);
} }
@ -74,8 +73,8 @@ class Mongo {
* @yield {Object} The operation result * @yield {Object} The operation result
*/ */
update(query, diff, type) { update(query, diff, type) {
let col = this._db.collection(type); const col = this._db.collection(type);
return col.updateOne(query, { $set:diff }); return col.updateOne(query, {$set: diff});
} }
/** /**
@ -85,7 +84,7 @@ class Mongo {
* @yield {Object} The document object * @yield {Object} The document object
*/ */
get(query, type) { get(query, type) {
let col = this._db.collection(type); const col = this._db.collection(type);
return col.findOne(query); return col.findOne(query);
} }
@ -96,7 +95,7 @@ class Mongo {
* @yield {Array} An array of document objects * @yield {Array} An array of document objects
*/ */
list(query, type) { list(query, type) {
let col = this._db.collection(type); const col = this._db.collection(type);
return col.find(query).toArray(); return col.find(query).toArray();
} }
@ -107,7 +106,7 @@ class Mongo {
* @yield {Object} The operation result * @yield {Object} The operation result
*/ */
remove(query, type) { remove(query, type) {
let col = this._db.collection(type); const col = this._db.collection(type);
return col.deleteMany(query); return col.deleteMany(query);
} }
@ -117,10 +116,9 @@ class Mongo {
* @yield {Object} The operation result * @yield {Object} The operation result
*/ */
clear(type) { clear(type) {
let col = this._db.collection(type); const col = this._db.collection(type);
return col.deleteMany({}); return col.deleteMany({});
} }
} }
module.exports = Mongo; module.exports = Mongo;

View File

@ -26,7 +26,6 @@ const openpgpEncrypt = require('nodemailer-openpgp').openpgpEncrypt;
* A simple wrapper around Nodemailer to send verification emails * A simple wrapper around Nodemailer to send verification emails
*/ */
class Email { class Email {
/** /**
* Create an instance of the reusable nodemailer SMTP transport. * Create an instance of the reusable nodemailer SMTP transport.
* @param {string} host SMTP server's hostname: 'smtp.gmail.com' * @param {string} host SMTP server's hostname: 'smtp.gmail.com'
@ -37,7 +36,7 @@ class Email {
* @param {boolean} starttls (optional) force STARTTLS to prevent downgrade attack. Defaults to true. * @param {boolean} starttls (optional) force STARTTLS to prevent downgrade attack. Defaults to true.
* @param {boolean} pgp (optional) if outgoing emails are encrypted to the user's public key. * @param {boolean} pgp (optional) if outgoing emails are encrypted to the user's public key.
*/ */
init({ host, port=465, auth, tls, starttls, pgp, sender }) { init({host, port = 465, auth, tls, starttls, pgp, sender}) {
this._transport = nodemailer.createTransport({ this._transport = nodemailer.createTransport({
host, host,
port, port,
@ -59,8 +58,8 @@ class Email {
* @param {Object} origin origin of the server * @param {Object} origin origin of the server
* @yield {Object} send response from the SMTP server * @yield {Object} send response from the SMTP server
*/ */
*send({ template, userId, keyId, origin }) { *send({template, userId, keyId, origin}) {
let message = { const message = {
from: this._sender, from: this._sender,
to: userId, to: userId,
subject: template.subject, subject: template.subject,
@ -69,7 +68,7 @@ class Email {
params: { params: {
name: userId.name, name: userId.name,
baseUrl: util.url(origin), baseUrl: util.url(origin),
keyId: keyId, keyId,
nonce: userId.nonce nonce: userId.nonce
} }
}; };
@ -86,20 +85,20 @@ class Email {
* @param {Object} params (optional) nodermailer template parameters * @param {Object} params (optional) nodermailer template parameters
* @yield {Object} reponse object containing SMTP info * @yield {Object} reponse object containing SMTP info
*/ */
*_sendHelper({ from, to, subject, text, html, params={} }) { *_sendHelper({from, to, subject, text, html, params = {}}) {
let template = { const template = {
subject, subject,
text, text,
html, html,
encryptionKeys: [to.publicKeyArmored] encryptionKeys: [to.publicKeyArmored]
}; };
let sender = { const sender = {
from: { from: {
name: from.name, name: from.name,
address: from.email address: from.email
} }
}; };
let recipient = { const recipient = {
to: { to: {
name: to.name, name: to.name,
address: to.email address: to.email
@ -107,13 +106,13 @@ class Email {
}; };
try { try {
let sendFn = this._transport.templateSender(template, sender); const sendFn = this._transport.templateSender(template, sender);
let info = yield sendFn(recipient, params); const info = yield sendFn(recipient, params);
if (!this._checkResponse(info)) { if (!this._checkResponse(info)) {
log.warn('email', 'Message may not have been received.', info); log.warn('email', 'Message may not have been received.', info);
} }
return info; return info;
} catch(error) { } catch (error) {
log.error('email', 'Sending message failed.', error); log.error('email', 'Sending message failed.', error);
util.throw(500, 'Sending email to user failed'); util.throw(500, 'Sending email to user failed');
} }
@ -128,7 +127,6 @@ class Email {
_checkResponse(info) { _checkResponse(info) {
return /^2/.test(info.response); return /^2/.test(info.response);
} }
} }
module.exports = Email; module.exports = Email;

View File

@ -25,7 +25,6 @@ const util = require('../service/util');
* See https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00 * See https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00
*/ */
class HKP { class HKP {
/** /**
* Create an instance of the HKP server * Create an instance of the HKP server
* @param {Object} publicKey An instance of the public key service * @param {Object} publicKey An instance of the public key service
@ -39,13 +38,12 @@ class HKP {
* @param {Object} ctx The koa request/response context * @param {Object} ctx The koa request/response context
*/ */
*add(ctx) { *add(ctx) {
let body = yield parse.form(ctx, { limit: '1mb' }); const {keytext: publicKeyArmored} = yield parse.form(ctx, {limit: '1mb'});
let publicKeyArmored = body.keytext;
if (!publicKeyArmored) { if (!publicKeyArmored) {
ctx.throw(400, 'Invalid request!'); ctx.throw(400, 'Invalid request!');
} }
let origin = util.origin(ctx); const origin = util.origin(ctx);
yield this._publicKey.put({ publicKeyArmored, origin }); yield this._publicKey.put({publicKeyArmored, origin});
ctx.body = 'Upload successful. Check your inbox to verify your email address.'; ctx.body = 'Upload successful. Check your inbox to verify your email address.';
ctx.status = 201; ctx.status = 201;
} }
@ -55,8 +53,8 @@ class HKP {
* @param {Object} ctx The koa request/response context * @param {Object} ctx The koa request/response context
*/ */
*lookup(ctx) { *lookup(ctx) {
let params = this.parseQueryString(ctx); const params = this.parseQueryString(ctx);
let key = yield this._publicKey.get(params); const key = yield this._publicKey.get(params);
this.setGetHeaders(ctx, params); this.setGetHeaders(ctx, params);
this.setGetBody(ctx, params, key); this.setGetBody(ctx, params, key);
} }
@ -68,19 +66,19 @@ class HKP {
* @return {Object} The query parameters or undefined for an invalid request * @return {Object} The query parameters or undefined for an invalid request
*/ */
parseQueryString(ctx) { parseQueryString(ctx) {
let params = { const params = {
op: ctx.query.op, // operation ... only 'get' is supported op: ctx.query.op, // operation ... only 'get' is supported
mr: ctx.query.options === 'mr' // machine readable mr: ctx.query.options === 'mr' // machine readable
}; };
if (this.checkId(ctx.query.search)) { if (this.checkId(ctx.query.search)) {
let id = ctx.query.search.replace(/^0x/, ''); const id = ctx.query.search.replace(/^0x/, '');
params.keyId = util.isKeyId(id) ? id : undefined; params.keyId = util.isKeyId(id) ? id : undefined;
params.fingerprint = util.isFingerPrint(id) ? id : undefined; params.fingerprint = util.isFingerPrint(id) ? id : undefined;
} else if (util.isEmail(ctx.query.search)) { } else if (util.isEmail(ctx.query.search)) {
params.email = ctx.query.search; params.email = ctx.query.search;
} }
if (['get','index','vindex'].indexOf(params.op) === -1) { if (['get', 'index', 'vindex'].indexOf(params.op) === -1) {
ctx.throw(501, 'Not implemented!'); ctx.throw(501, 'Not implemented!');
} else if (!params.keyId && !params.fingerprint && !params.email) { } else if (!params.keyId && !params.fingerprint && !params.email) {
ctx.throw(501, 'Not implemented!'); ctx.throw(501, 'Not implemented!');
@ -124,21 +122,20 @@ class HKP {
setGetBody(ctx, params, key) { setGetBody(ctx, params, key) {
if (params.op === 'get') { if (params.op === 'get') {
ctx.body = key.publicKeyArmored; ctx.body = key.publicKeyArmored;
} else if (['index','vindex'].indexOf(params.op) !== -1) { } else if (['index', 'vindex'].indexOf(params.op) !== -1) {
const VERSION = 1, COUNT = 1; // number of keys const VERSION = 1;
let fp = key.fingerprint.toUpperCase(); const COUNT = 1; // number of keys
let algo = (key.algorithm.indexOf('rsa') !== -1) ? 1 : ''; const fp = key.fingerprint.toUpperCase();
let created = key.created ? (key.created.getTime() / 1000) : ''; const algo = (key.algorithm.indexOf('rsa') !== -1) ? 1 : '';
const created = key.created ? (key.created.getTime() / 1000) : '';
ctx.body = 'info:' + VERSION + ':' + COUNT + '\n' + ctx.body = `info:${VERSION}:${COUNT}\npub:${fp}:${algo}:${key.keySize}:${created}::\n`;
'pub:' + fp + ':' + algo + ':' + key.keySize + ':' + created + '::\n';
for (let uid of key.userIds) { for (const uid of key.userIds) {
ctx.body += 'uid:' + encodeURIComponent(uid.name + ' <' + uid.email + '>') + ':::\n'; ctx.body += `uid:${encodeURIComponent(`${uid.name} <${uid.email}>`)}:::\n`;
} }
} }
} }
} }
module.exports = HKP; module.exports = HKP;

View File

@ -24,7 +24,6 @@ const util = require('../service/util');
* The REST api to provide additional functionality on top of HKP * The REST api to provide additional functionality on top of HKP
*/ */
class REST { class REST {
/** /**
* Create an instance of the REST server * Create an instance of the REST server
* @param {Object} publicKey An instance of the public key service * @param {Object} publicKey An instance of the public key service
@ -39,13 +38,12 @@ class REST {
* @param {Object} ctx The koa request/response context * @param {Object} ctx The koa request/response context
*/ */
*create(ctx) { *create(ctx) {
let q = yield parse.json(ctx, { limit: '1mb' }); const {publicKeyArmored, primaryEmail} = yield parse.json(ctx, {limit: '1mb'});
let publicKeyArmored = q.publicKeyArmored, primaryEmail = q.primaryEmail;
if (!publicKeyArmored || (primaryEmail && !util.isEmail(primaryEmail))) { if (!publicKeyArmored || (primaryEmail && !util.isEmail(primaryEmail))) {
ctx.throw(400, 'Invalid request!'); ctx.throw(400, 'Invalid request!');
} }
let origin = util.origin(ctx); const origin = util.origin(ctx);
yield this._publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield this._publicKey.put({publicKeyArmored, primaryEmail, origin});
ctx.body = 'Upload successful. Check your inbox to verify your email address.'; ctx.body = 'Upload successful. Check your inbox to verify your email address.';
ctx.status = 201; ctx.status = 201;
} }
@ -55,12 +53,12 @@ class REST {
* @param {Object} ctx The koa request/response context * @param {Object} ctx The koa request/response context
*/ */
*query(ctx) { *query(ctx) {
let op = ctx.query.op; const op = ctx.query.op;
if (op === 'verify' || op === 'verifyRemove') { if (op === 'verify' || op === 'verifyRemove') {
return yield this[op](ctx); // delegate operation return yield this[op](ctx); // delegate operation
} }
// do READ if no 'op' provided // do READ if no 'op' provided
let q = { keyId:ctx.query.keyId, fingerprint:ctx.query.fingerprint, email:ctx.query.email }; 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)) { if (!util.isKeyId(q.keyId) && !util.isFingerPrint(q.fingerprint) && !util.isEmail(q.email)) {
ctx.throw(400, 'Invalid request!'); ctx.throw(400, 'Invalid request!');
} }
@ -72,13 +70,13 @@ class REST {
* @param {Object} ctx The koa request/response context * @param {Object} ctx The koa request/response context
*/ */
*verify(ctx) { *verify(ctx) {
let q = { keyId:ctx.query.keyId, nonce:ctx.query.nonce }; const q = {keyId: ctx.query.keyId, nonce: ctx.query.nonce};
if (!util.isKeyId(q.keyId) || !util.isString(q.nonce)) { if (!util.isKeyId(q.keyId) || !util.isString(q.nonce)) {
ctx.throw(400, 'Invalid request!'); ctx.throw(400, 'Invalid request!');
} }
yield this._publicKey.verify(q); yield this._publicKey.verify(q);
// create link for sharing // create link for sharing
let link = util.url(util.origin(ctx), '/pks/lookup?op=get&search=0x' + q.keyId.toUpperCase()); 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>`; ctx.body = `<p>Email address successfully verified!</p><p>Link to share your key: <a href="${link}" target="_blank">${link}</a></p>`;
ctx.set('Content-Type', 'text/html; charset=utf-8'); ctx.set('Content-Type', 'text/html; charset=utf-8');
} }
@ -88,7 +86,7 @@ class REST {
* @param {Object} ctx The koa request/response context * @param {Object} ctx The koa request/response context
*/ */
*remove(ctx) { *remove(ctx) {
let q = { keyId:ctx.query.keyId, email:ctx.query.email, origin:util.origin(ctx) }; const q = {keyId: ctx.query.keyId, email: ctx.query.email, origin: util.origin(ctx)};
if (!util.isKeyId(q.keyId) && !util.isEmail(q.email)) { if (!util.isKeyId(q.keyId) && !util.isEmail(q.email)) {
ctx.throw(400, 'Invalid request!'); ctx.throw(400, 'Invalid request!');
} }
@ -102,14 +100,13 @@ class REST {
* @param {Object} ctx The koa request/response context * @param {Object} ctx The koa request/response context
*/ */
*verifyRemove(ctx) { *verifyRemove(ctx) {
let q = { keyId:ctx.query.keyId, nonce:ctx.query.nonce }; const q = {keyId: ctx.query.keyId, nonce: ctx.query.nonce};
if (!util.isKeyId(q.keyId) || !util.isString(q.nonce)) { if (!util.isKeyId(q.keyId) || !util.isString(q.nonce)) {
ctx.throw(400, 'Invalid request!'); ctx.throw(400, 'Invalid request!');
} }
yield this._publicKey.verifyRemove(q); yield this._publicKey.verifyRemove(q);
ctx.body = 'Key successfully removed!'; ctx.body = 'Key successfully removed!';
} }
} }
module.exports = REST; module.exports = REST;

View File

@ -29,7 +29,6 @@ const KEY_END = '-----END PGP PUBLIC KEY BLOCK-----';
* A simple wrapper around OpenPGP.js * A simple wrapper around OpenPGP.js
*/ */
class PGP { class PGP {
/** /**
* Parse an ascii armored pgp key block and get its parameters. * Parse an ascii armored pgp key block and get its parameters.
* @param {String} publicKeyArmored ascii armored pgp key block * @param {String} publicKeyArmored ascii armored pgp key block
@ -38,9 +37,9 @@ class PGP {
parseKey(publicKeyArmored) { parseKey(publicKeyArmored) {
publicKeyArmored = this.trimKey(publicKeyArmored); publicKeyArmored = this.trimKey(publicKeyArmored);
let r = openpgp.key.readArmored(publicKeyArmored); const r = openpgp.key.readArmored(publicKeyArmored);
if (r.err) { if (r.err) {
let error = r.err[0]; const error = r.err[0];
log.error('pgp', 'Failed to parse PGP key:\n%s', publicKeyArmored, error); log.error('pgp', 'Failed to parse PGP key:\n%s', publicKeyArmored, error);
util.throw(500, 'Failed to parse PGP key'); util.throw(500, 'Failed to parse PGP key');
} else if (!r.keys || r.keys.length !== 1 || !r.keys[0].primaryKey) { } else if (!r.keys || r.keys.length !== 1 || !r.keys[0].primaryKey) {
@ -48,21 +47,21 @@ class PGP {
} }
// verify primary key // verify primary key
let key = r.keys[0]; const key = r.keys[0];
let primaryKey = key.primaryKey; const primaryKey = key.primaryKey;
if (key.verifyPrimaryKey() !== openpgp.enums.keyStatus.valid) { if (key.verifyPrimaryKey() !== openpgp.enums.keyStatus.valid) {
util.throw(400, 'Invalid PGP key: primary key verification failed'); util.throw(400, 'Invalid PGP key: primary key verification failed');
} }
// accept version 4 keys only // accept version 4 keys only
let keyId = primaryKey.getKeyId().toHex(); const keyId = primaryKey.getKeyId().toHex();
let fingerprint = primaryKey.fingerprint; const fingerprint = primaryKey.fingerprint;
if (!util.isKeyId(keyId) || !util.isFingerPrint(fingerprint)) { if (!util.isKeyId(keyId) || !util.isFingerPrint(fingerprint)) {
util.throw(400, 'Invalid PGP key: only v4 keys are accepted'); util.throw(400, 'Invalid PGP key: only v4 keys are accepted');
} }
// check for at least one valid user id // check for at least one valid user id
let userIds = this.parseUserIds(key.users, primaryKey); const userIds = this.parseUserIds(key.users, primaryKey);
if (!userIds.length) { if (!userIds.length) {
util.throw(400, 'Invalid PGP key: invalid user ids'); util.throw(400, 'Invalid PGP key: invalid user ids');
} }
@ -115,16 +114,16 @@ class PGP {
util.throw(400, 'Invalid PGP key: no user id found'); util.throw(400, 'Invalid PGP key: no user id found');
} }
// at least one user id signature must be valid // at least one user id signature must be valid
let result = []; const result = [];
for (let user of users) { for (const user of users) {
let oneValid = false; let oneValid = false;
for (let cert of user.selfCertifications) { for (const cert of user.selfCertifications) {
if (user.isValidSelfCertificate(primaryKey, cert)) { if (user.isValidSelfCertificate(primaryKey, cert)) {
oneValid = true; oneValid = true;
} }
} }
if (oneValid && user.userId && user.userId.userid) { if (oneValid && user.userId && user.userId.userid) {
let uid = addressparser(user.userId.userid)[0]; const uid = addressparser(user.userId.userid)[0];
if (util.isEmail(uid.address)) { if (util.isEmail(uid.address)) {
result.push(uid); result.push(uid);
} }

View File

@ -46,7 +46,6 @@ const DB_TYPE = 'publickey';
* A service that handlers PGP public keys queries to the database * A service that handlers PGP public keys queries to the database
*/ */
class PublicKey { class PublicKey {
/** /**
* Create an instance of the service * Create an instance of the service
* @param {Object} pgp An instance of the OpenPGP.js wrapper * @param {Object} pgp An instance of the OpenPGP.js wrapper
@ -66,11 +65,11 @@ class PublicKey {
* @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' } * @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' }
* @yield {undefined} * @yield {undefined}
*/ */
*put({ publicKeyArmored, primaryEmail, origin }) { *put({publicKeyArmored, primaryEmail, origin}) {
// parse key block // parse key block
let key = this._pgp.parseKey(publicKeyArmored); const key = this._pgp.parseKey(publicKeyArmored);
// check for existing verfied key by id or email addresses // check for existing verfied key by id or email addresses
let verified = yield this.getVerified(key); const verified = yield this.getVerified(key);
if (verified) { if (verified) {
util.throw(304, 'Key for this user already exists'); util.throw(304, 'Key for this user already exists');
} }
@ -87,13 +86,13 @@ class PublicKey {
*/ */
*_persisKey(key) { *_persisKey(key) {
// delete old/unverified key // delete old/unverified key
yield this._mongo.remove({ keyId:key.keyId }, DB_TYPE); yield this._mongo.remove({keyId: key.keyId}, DB_TYPE);
// generate nonces for verification // generate nonces for verification
for (let uid of key.userIds) { for (const uid of key.userIds) {
uid.nonce = util.random(); uid.nonce = util.random();
} }
// persist new key // persist new key
let r = yield this._mongo.create(key, DB_TYPE); const r = yield this._mongo.create(key, DB_TYPE);
if (r.insertedCount !== 1) { if (r.insertedCount !== 1) {
util.throw(500, 'Failed to persist key'); util.throw(500, 'Failed to persist key');
} }
@ -107,17 +106,16 @@ class PublicKey {
* @param {Object} origin the server's origin (required for email links) * @param {Object} origin the server's origin (required for email links)
* @yield {undefined} * @yield {undefined}
*/ */
*_sendVerifyEmail(key, primaryEmail, origin) { *_sendVerifyEmail({userIds, keyId, publicKeyArmored}, primaryEmail, origin) {
let userIds = key.userIds, keyId = key.keyId;
// check for primary email (send only one email) // check for primary email (send only one email)
let primaryUserId = userIds.find(uid => uid.email === primaryEmail); const primaryUserId = userIds.find(uid => uid.email === primaryEmail);
if (primaryUserId) { if (primaryUserId) {
userIds = [primaryUserId]; userIds = [primaryUserId];
} }
// send emails // send emails
for (let userId of userIds) { for (const userId of userIds) {
userId.publicKeyArmored = key.publicKeyArmored; // set key for encryption userId.publicKeyArmored = publicKeyArmored; // set key for encryption
yield this._email.send({ template:tpl.verifyKey, userId, keyId, origin }); yield this._email.send({template: tpl.verifyKey, userId, keyId, origin});
} }
} }
@ -127,15 +125,15 @@ class PublicKey {
* @param {string} nonce The verification nonce proving email address ownership * @param {string} nonce The verification nonce proving email address ownership
* @yield {undefined} * @yield {undefined}
*/ */
*verify({ keyId, nonce }) { *verify({keyId, nonce}) {
// look for verification nonce in database // look for verification nonce in database
let query = { keyId, 'userIds.nonce':nonce }; const query = {keyId, 'userIds.nonce': nonce};
let key = yield this._mongo.get(query, DB_TYPE); const key = yield this._mongo.get(query, DB_TYPE);
if (!key) { if (!key) {
util.throw(404, 'User id not found'); util.throw(404, 'User id not found');
} }
// check if user ids of this key have already been verified in another key // check if user ids of this key have already been verified in another key
let verified = yield this.getVerified(key); const verified = yield this.getVerified(key);
if (verified && verified.keyId !== keyId) { if (verified && verified.keyId !== keyId) {
util.throw(304, 'Key for this user already exists'); util.throw(304, 'Key for this user already exists');
} }
@ -155,7 +153,7 @@ class PublicKey {
* @param {string} keyId (optional) The public key id * @param {string} keyId (optional) The public key id
* @yield {Object} The verified key document * @yield {Object} The verified key document
*/ */
*getVerified({ userIds, fingerprint, keyId }) { *getVerified({userIds, fingerprint, keyId}) {
let queries = []; let queries = [];
// query by fingerprint // query by fingerprint
if (fingerprint) { if (fingerprint) {
@ -182,7 +180,7 @@ class PublicKey {
} }
}))); })));
} }
return yield this._mongo.get({ $or:queries }, DB_TYPE); return yield this._mongo.get({$or: queries}, DB_TYPE);
} }
/** /**
@ -193,10 +191,10 @@ class PublicKey {
* @param {String} email (optional) The user's email address * @param {String} email (optional) The user's email address
* @yield {Object} The public key document * @yield {Object} The public key document
*/ */
*get({ fingerprint, keyId, email }) { *get({fingerprint, keyId, email}) {
// look for verified key // look for verified key
let userIds = email ? [{ email:email }] : undefined; const userIds = email ? [{email}] : undefined;
let key = yield this.getVerified({ keyId, fingerprint, userIds }); const key = yield this.getVerified({keyId, fingerprint, userIds});
if (!key) { if (!key) {
util.throw(404, 'Key not found'); util.throw(404, 'Key not found');
} }
@ -220,16 +218,16 @@ class PublicKey {
* @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' } * @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' }
* @yield {undefined} * @yield {undefined}
*/ */
*requestRemove({ keyId, email, origin }) { *requestRemove({keyId, email, origin}) {
// flag user ids for removal // flag user ids for removal
let key = yield this._flagForRemove(keyId, email); const key = yield this._flagForRemove(keyId, email);
if (!key) { if (!key) {
util.throw(404, 'User id not found'); util.throw(404, 'User id not found');
} }
// send verification mails // send verification mails
keyId = key.keyId; // get keyId in case request was by email keyId = key.keyId; // get keyId in case request was by email
for (let userId of key.userIds) { for (const userId of key.userIds) {
yield this._email.send({ template:tpl.verifyRemove, userId, keyId, origin }); yield this._email.send({template: tpl.verifyRemove, userId, keyId, origin});
} }
} }
@ -241,24 +239,24 @@ class PublicKey {
* @yield {Array} A list of user ids with nonces * @yield {Array} A list of user ids with nonces
*/ */
*_flagForRemove(keyId, email) { *_flagForRemove(keyId, email) {
let query = email ? { 'userIds.email':email } : { keyId }; const query = email ? {'userIds.email': email} : {keyId};
let key = yield this._mongo.get(query, DB_TYPE); const key = yield this._mongo.get(query, DB_TYPE);
if (!key) { if (!key) {
return; return;
} }
// flag only the provided user id // flag only the provided user id
if (email) { if (email) {
let nonce = util.random(); const nonce = util.random();
yield this._mongo.update(query, { 'userIds.$.nonce':nonce }, DB_TYPE); yield this._mongo.update(query, {'userIds.$.nonce': nonce}, DB_TYPE);
let uid = key.userIds.find(u => u.email === email); const uid = key.userIds.find(u => u.email === email);
uid.nonce = nonce; uid.nonce = nonce;
return { userIds:[uid], keyId:key.keyId }; return {userIds: [uid], keyId: key.keyId};
} }
// flag all key user ids // flag all key user ids
if (keyId) { if (keyId) {
for (let uid of key.userIds) { for (const uid of key.userIds) {
let nonce = util.random(); const nonce = util.random();
yield this._mongo.update({ 'userIds.email':uid.email }, { 'userIds.$.nonce':nonce }, DB_TYPE); yield this._mongo.update({'userIds.email': uid.email}, {'userIds.$.nonce': nonce}, DB_TYPE);
uid.nonce = nonce; uid.nonce = nonce;
} }
return key; return key;
@ -272,16 +270,15 @@ class PublicKey {
* @param {string} nonce The verification nonce proving email address ownership * @param {string} nonce The verification nonce proving email address ownership
* @yield {undefined} * @yield {undefined}
*/ */
*verifyRemove({ keyId, nonce }) { *verifyRemove({keyId, nonce}) {
// check if key exists in database // check if key exists in database
let flagged = yield this._mongo.get({ keyId, 'userIds.nonce':nonce }, DB_TYPE); const flagged = yield this._mongo.get({keyId, 'userIds.nonce': nonce}, DB_TYPE);
if (!flagged) { if (!flagged) {
util.throw(404, 'User id not found'); util.throw(404, 'User id not found');
} }
// delete the key // delete the key
yield this._mongo.remove({ keyId }, DB_TYPE); yield this._mongo.remove({keyId}, DB_TYPE);
} }
} }
module.exports = PublicKey; module.exports = PublicKey;

View File

@ -37,7 +37,7 @@ exports.isTrue = function(data) {
if (this.isString(data)) { if (this.isString(data)) {
return data === 'true'; return data === 'true';
} else { } else {
return !!data; return Boolean(data);
} }
}; };
@ -85,7 +85,7 @@ exports.isEmail = function(data) {
* @return {Error} The resulting error object * @return {Error} The resulting error object
*/ */
exports.throw = function(status, message) { exports.throw = function(status, message) {
let err = new Error(message); const err = new Error(message);
err.status = status; err.status = status;
err.expose = true; // display message to the client err.expose = true; // display message to the client
throw err; throw err;
@ -143,7 +143,7 @@ exports.origin = function(ctx) {
* @return {string} The complete url * @return {string} The complete url
*/ */
exports.url = function(origin, resource) { exports.url = function(origin, resource) {
return origin.protocol + '://' + origin.host + (resource || ''); return `${origin.protocol}://${origin.host}${resource || ''}`;
}; };
/** /**

View File

@ -1,3 +1,5 @@
/* eslint-disable */
;(function($) { ;(function($) {
'use strict'; 'use strict';

13
test/.eslintrc Normal file
View File

@ -0,0 +1,13 @@
{
"extends": "../.eslintrc",
"rules": {
"no-shadow": 1
},
"globals": {
"expect": true,
"sinon": true
},
"env": {
"mocha": true
}
}

View File

@ -5,12 +5,16 @@ const Mongo = require('../../src/dao/mongo');
const nodemailer = require('nodemailer'); const nodemailer = require('nodemailer');
const config = require('config'); const config = require('config');
const fs = require('fs'); const fs = require('fs');
const log = require('npmlog');
describe('Koa App (HTTP Server) Integration Tests', function() { describe('Koa App (HTTP Server) Integration Tests', function() {
this.timeout(20000); this.timeout(20000);
let app, mongo, let app;
sendEmailStub, publicKeyArmored, emailParams; let mongo;
let sendEmailStub;
let publicKeyArmored;
let emailParams;
const DB_TYPE_PUB_KEY = 'publickey'; const DB_TYPE_PUB_KEY = 'publickey';
const DB_TYPE_USER_ID = 'userid'; const DB_TYPE_USER_ID = 'userid';
@ -18,24 +22,24 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
const fingerprint = '4277257930867231CE393FB8DBC0B3D92B1B86E9'; const fingerprint = '4277257930867231CE393FB8DBC0B3D92B1B86E9';
before(function *() { before(function *() {
publicKeyArmored = fs.readFileSync(__dirname + '/../key1.asc', 'utf8'); publicKeyArmored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8');
mongo = new Mongo(); mongo = new Mongo();
yield mongo.init(config.mongo); yield mongo.init(config.mongo);
sendEmailStub = sinon.stub().returns(Promise.resolve({ response:'250' })); sendEmailStub = sinon.stub().returns(Promise.resolve({response: '250'}));
sendEmailStub.withArgs(sinon.match(recipient => { sendEmailStub.withArgs(sinon.match(recipient => recipient.to.address === primaryEmail), sinon.match(params => {
return recipient.to.address === primaryEmail;
}), sinon.match(params => {
emailParams = params; emailParams = params;
return !!params.nonce; return Boolean(params.nonce);
})); }));
sinon.stub(nodemailer, 'createTransport').returns({ sinon.stub(nodemailer, 'createTransport').returns({
templateSender: () => { return sendEmailStub; }, templateSender: () => sendEmailStub,
use: function() {} use() {}
}); });
sinon.stub(log);
global.testing = true; global.testing = true;
let init = require('../../src/app'); const init = require('../../src/app');
app = yield init(); app = yield init();
}); });
@ -46,6 +50,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
}); });
after(function *() { after(function *() {
sinon.restore(log);
nodemailer.createTransport.restore(); nodemailer.createTransport.restore();
yield mongo.clear(DB_TYPE_PUB_KEY); yield mongo.clear(DB_TYPE_PUB_KEY);
yield mongo.clear(DB_TYPE_USER_ID); yield mongo.clear(DB_TYPE_USER_ID);
@ -57,7 +62,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
it('should return 400 for an invalid pgp key', done => { it('should return 400 for an invalid pgp key', done => {
request(app.listen()) request(app.listen())
.post('/api/v1/key') .post('/api/v1/key')
.send({ publicKeyArmored:'foo' }) .send({publicKeyArmored: 'foo'})
.expect(400) .expect(400)
.end(done); .end(done);
}); });
@ -65,7 +70,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
it('should return 400 for an invalid primaryEmail', done => { it('should return 400 for an invalid primaryEmail', done => {
request(app.listen()) request(app.listen())
.post('/api/v1/key') .post('/api/v1/key')
.send({ publicKeyArmored, primaryEmail:'foo' }) .send({publicKeyArmored, primaryEmail: 'foo'})
.expect(400) .expect(400)
.end(done); .end(done);
}); });
@ -73,7 +78,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
it('should return 201 with primaryEmail', done => { it('should return 201 with primaryEmail', done => {
request(app.listen()) request(app.listen())
.post('/api/v1/key') .post('/api/v1/key')
.send({ publicKeyArmored, primaryEmail }) .send({publicKeyArmored, primaryEmail})
.expect(201) .expect(201)
.end(() => { .end(() => {
expect(emailParams).to.exist; expect(emailParams).to.exist;
@ -84,7 +89,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
it('should return 201 without primaryEmail', done => { it('should return 201 without primaryEmail', done => {
request(app.listen()) request(app.listen())
.post('/api/v1/key') .post('/api/v1/key')
.send({ publicKeyArmored }) .send({publicKeyArmored})
.expect(201) .expect(201)
.end(() => { .end(() => {
expect(emailParams).to.exist; expect(emailParams).to.exist;
@ -97,28 +102,28 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
beforeEach(done => { beforeEach(done => {
request(app.listen()) request(app.listen())
.post('/api/v1/key') .post('/api/v1/key')
.send({ publicKeyArmored, primaryEmail }) .send({publicKeyArmored, primaryEmail})
.expect(201) .expect(201)
.end(done); .end(done);
}); });
it('should return 200 for valid params', done => { it('should return 200 for valid params', done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?op=verify&keyId=' + emailParams.keyId + '&nonce=' + emailParams.nonce) .get(`/api/v1/key?op=verify&keyId=${emailParams.keyId}&nonce=${emailParams.nonce}`)
.expect(200) .expect(200)
.end(done); .end(done);
}); });
it('should return 400 for missing keyid and', done => { it('should return 400 for missing keyid and', done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?op=verify&nonce=' + emailParams.nonce) .get(`/api/v1/key?op=verify&nonce=${emailParams.nonce}`)
.expect(400) .expect(400)
.end(done); .end(done);
}); });
it('should return 400 for missing nonce', done => { it('should return 400 for missing nonce', done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?op=verify&keyId=' + emailParams.keyId) .get(`/api/v1/key?op=verify&keyId=${emailParams.keyId}`)
.expect(400) .expect(400)
.end(done); .end(done);
}); });
@ -128,7 +133,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
beforeEach(done => { beforeEach(done => {
request(app.listen()) request(app.listen())
.post('/api/v1/key') .post('/api/v1/key')
.send({ publicKeyArmored, primaryEmail }) .send({publicKeyArmored, primaryEmail})
.expect(201) .expect(201)
.end(done); .end(done);
}); });
@ -136,7 +141,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
describe('Not yet verified', () => { describe('Not yet verified', () => {
it('should return 404', done => { it('should return 404', done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?keyId=' + emailParams.keyId) .get(`/api/v1/key?keyId=${emailParams.keyId}`)
.expect(404).end(done); .expect(404).end(done);
}); });
}); });
@ -144,21 +149,21 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
describe('Verified', () => { describe('Verified', () => {
beforeEach(done => { beforeEach(done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?op=verify&keyId=' + emailParams.keyId + '&nonce=' + emailParams.nonce) .get(`/api/v1/key?op=verify&keyId=${emailParams.keyId}&nonce=${emailParams.nonce}`)
.expect(200) .expect(200)
.end(done); .end(done);
}); });
it('should return 200 and get key by id', done => { it('should return 200 and get key by id', done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?keyId=' + emailParams.keyId) .get(`/api/v1/key?keyId=${emailParams.keyId}`)
.expect(200) .expect(200)
.end(done); .end(done);
}); });
it('should return 200 and get key email address', done => { it('should return 200 and get key email address', done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?email=' + primaryEmail) .get(`/api/v1/key?email=${primaryEmail}`)
.expect(200) .expect(200)
.end(done); .end(done);
}); });
@ -190,21 +195,21 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
beforeEach(done => { beforeEach(done => {
request(app.listen()) request(app.listen())
.post('/api/v1/key') .post('/api/v1/key')
.send({ publicKeyArmored, primaryEmail }) .send({publicKeyArmored, primaryEmail})
.expect(201) .expect(201)
.end(done); .end(done);
}); });
it('should return 202 for key id', done => { it('should return 202 for key id', done => {
request(app.listen()) request(app.listen())
.del('/api/v1/key?keyId=' + emailParams.keyId) .del(`/api/v1/key?keyId=${emailParams.keyId}`)
.expect(202) .expect(202)
.end(done); .end(done);
}); });
it('should return 202 for email address', done => { it('should return 202 for email address', done => {
request(app.listen()) request(app.listen())
.del('/api/v1/key?email=' + primaryEmail) .del(`/api/v1/key?email=${primaryEmail}`)
.expect(202) .expect(202)
.end(done); .end(done);
}); });
@ -228,11 +233,11 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
beforeEach(done => { beforeEach(done => {
request(app.listen()) request(app.listen())
.post('/api/v1/key') .post('/api/v1/key')
.send({ publicKeyArmored, primaryEmail }) .send({publicKeyArmored, primaryEmail})
.expect(201) .expect(201)
.end(function() { .end(() => {
request(app.listen()) request(app.listen())
.del('/api/v1/key?keyId=' + emailParams.keyId) .del(`/api/v1/key?keyId=${emailParams.keyId}`)
.expect(202) .expect(202)
.end(done); .end(done);
}); });
@ -240,7 +245,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
it('should return 200 for key id', done => { it('should return 200 for key id', done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?op=verifyRemove&keyId=' + emailParams.keyId + '&nonce=' + emailParams.nonce) .get(`/api/v1/key?op=verifyRemove&keyId=${emailParams.keyId}&nonce=${emailParams.nonce}`)
.expect(200) .expect(200)
.end(done); .end(done);
}); });
@ -254,7 +259,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
it('should return 404 for unknown key id', done => { it('should return 404 for unknown key id', done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?op=verifyRemove&keyId=0123456789ABCDEF&nonce=' + emailParams.nonce) .get(`/api/v1/key?op=verifyRemove&keyId=0123456789ABCDEF&nonce=${emailParams.nonce}`)
.expect(404) .expect(404)
.end(done); .end(done);
}); });
@ -276,7 +281,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
request(app.listen()) request(app.listen())
.post('/pks/add') .post('/pks/add')
.type('form') .type('form')
.send('keytext=' + encodeURIComponent(publicKeyArmored)) .send(`keytext=${encodeURIComponent(publicKeyArmored)}`)
.expect(201) .expect(201)
.end(done); .end(done);
}); });
@ -287,7 +292,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
request(app.listen()) request(app.listen())
.post('/pks/add') .post('/pks/add')
.type('form') .type('form')
.send('keytext=' + encodeURIComponent(publicKeyArmored)) .send(`keytext=${encodeURIComponent(publicKeyArmored)}`)
.expect(201) .expect(201)
.end(done); .end(done);
}); });
@ -295,7 +300,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
describe('Not yet verified', () => { describe('Not yet verified', () => {
it('should return 404', done => { it('should return 404', done => {
request(app.listen()) request(app.listen())
.get('/pks/lookup?op=get&search=0x' + emailParams.keyId) .get(`/pks/lookup?op=get&search=0x${emailParams.keyId}`)
.expect(404) .expect(404)
.end(done); .end(done);
}); });
@ -304,35 +309,35 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
describe('Verified', () => { describe('Verified', () => {
beforeEach(done => { beforeEach(done => {
request(app.listen()) request(app.listen())
.get('/api/v1/key?op=verify&keyId=' + emailParams.keyId + '&nonce=' + emailParams.nonce) .get(`/api/v1/key?op=verify&keyId=${emailParams.keyId}&nonce=${emailParams.nonce}`)
.expect(200) .expect(200)
.end(done); .end(done);
}); });
it('should return 200 for key id', done => { it('should return 200 for key id', done => {
request(app.listen()) request(app.listen())
.get('/pks/lookup?op=get&search=0x' + emailParams.keyId) .get(`/pks/lookup?op=get&search=0x${emailParams.keyId}`)
.expect(200, publicKeyArmored) .expect(200, publicKeyArmored)
.end(done); .end(done);
}); });
it('should return 200 for fingerprint', done => { it('should return 200 for fingerprint', done => {
request(app.listen()) request(app.listen())
.get('/pks/lookup?op=get&search=0x' + fingerprint) .get(`/pks/lookup?op=get&search=0x${fingerprint}`)
.expect(200, publicKeyArmored) .expect(200, publicKeyArmored)
.end(done); .end(done);
}); });
it('should return 200 for correct email address', done => { it('should return 200 for correct email address', done => {
request(app.listen()) request(app.listen())
.get('/pks/lookup?op=get&search=' + primaryEmail) .get(`/pks/lookup?op=get&search=${primaryEmail}`)
.expect(200, publicKeyArmored) .expect(200, publicKeyArmored)
.end(done); .end(done);
}); });
it('should return 200 for "mr" option', done => { it('should return 200 for "mr" option', done => {
request(app.listen()) request(app.listen())
.get('/pks/lookup?op=get&options=mr&search=' + primaryEmail) .get(`/pks/lookup?op=get&options=mr&search=${primaryEmail}`)
.expect('Content-Type', 'application/pgp-keys; charset=utf-8') .expect('Content-Type', 'application/pgp-keys; charset=utf-8')
.expect('Content-Disposition', 'attachment; filename=openpgpkey.asc') .expect('Content-Disposition', 'attachment; filename=openpgpkey.asc')
.expect(200, publicKeyArmored) .expect(200, publicKeyArmored)
@ -341,14 +346,14 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
it('should return 200 for "vindex" op', done => { it('should return 200 for "vindex" op', done => {
request(app.listen()) request(app.listen())
.get('/pks/lookup?op=vindex&search=0x' + emailParams.keyId) .get(`/pks/lookup?op=vindex&search=0x${emailParams.keyId}`)
.expect(200) .expect(200)
.end(done); .end(done);
}); });
it('should return 200 for "index" with "mr" option', done => { it('should return 200 for "index" with "mr" option', done => {
request(app.listen()) request(app.listen())
.get('/pks/lookup?op=index&options=mr&search=0x' + emailParams.keyId) .get(`/pks/lookup?op=index&options=mr&search=0x${emailParams.keyId}`)
.expect('Content-Type', 'text/plain; charset=utf-8') .expect('Content-Type', 'text/plain; charset=utf-8')
.expect(200) .expect(200)
.end(done); .end(done);
@ -377,7 +382,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
it('should return 501 for a invalid key id format', done => { it('should return 501 for a invalid key id format', done => {
request(app.listen()) request(app.listen())
.get('/pks/lookup?op=get&search=' + emailParams.keyId) .get(`/pks/lookup?op=get&search=${emailParams.keyId}`)
.expect(501) .expect(501)
.end(done); .end(done);
}); });
@ -398,12 +403,11 @@ describe('Koa App (HTTP Server) Integration Tests', function() {
it('should return 501 (Not implemented) for "x-email" op', done => { it('should return 501 (Not implemented) for "x-email" op', done => {
request(app.listen()) request(app.listen())
.get('/pks/lookup?op=x-email&search=0x' + emailParams.keyId) .get(`/pks/lookup?op=x-email&search=0x${emailParams.keyId}`)
.expect(501) .expect(501)
.end(done); .end(done);
}); });
}); });
}); });
}); });
}); });

View File

@ -7,15 +7,19 @@ const tpl = require('../../src/email/templates.json');
describe('Email Integration Tests', function() { describe('Email Integration Tests', function() {
this.timeout(20000); this.timeout(20000);
let email, keyId, userId, origin, publicKeyArmored; let email;
let keyId;
let userId;
let origin;
let publicKeyArmored;
const recipient = { name:'Test User', email:'safewithme.testuser@gmail.com' }; const recipient = {name: 'Test User', email: 'safewithme.testuser@gmail.com'};
before(function() { before(() => {
publicKeyArmored = require('fs').readFileSync(__dirname + '/../key1.asc', 'utf8'); publicKeyArmored = require('fs').readFileSync(`${__dirname}/../key1.asc`, 'utf8');
origin = { origin = {
protocol: 'http', protocol: 'http',
host: 'localhost:' + config.server.port host: `localhost:${config.server.port}`
}; };
email = new Email(); email = new Email();
email.init(config.email); email.init(config.email);
@ -33,14 +37,14 @@ describe('Email Integration Tests', function() {
describe("_sendHelper", () => { describe("_sendHelper", () => {
it('should work', function *() { it('should work', function *() {
let mailOptions = { const mailOptions = {
from: email._sender, from: email._sender,
to: recipient, to: recipient,
subject: 'Hello ✔', // Subject line subject: 'Hello ✔', // Subject line
text: 'Hello world 🐴', // plaintext body text: 'Hello world 🐴', // plaintext body
html: '<b>Hello world 🐴</b>' // html body html: '<b>Hello world 🐴</b>' // html body
}; };
let info = yield email._sendHelper(mailOptions); const info = yield email._sendHelper(mailOptions);
expect(info).to.exist; expect(info).to.exist;
}); });
}); });
@ -48,23 +52,22 @@ describe('Email Integration Tests', function() {
describe("send verifyKey template", () => { describe("send verifyKey template", () => {
it('should send plaintext email', function *() { it('should send plaintext email', function *() {
delete userId.publicKeyArmored; delete userId.publicKeyArmored;
yield email.send({ template:tpl.verifyKey, userId, keyId, origin }); yield email.send({template: tpl.verifyKey, userId, keyId, origin});
}); });
it('should send pgp encrypted email', function *() { it('should send pgp encrypted email', function *() {
yield email.send({ template:tpl.verifyKey, userId, keyId, origin }); yield email.send({template: tpl.verifyKey, userId, keyId, origin});
}); });
}); });
describe("send verifyRemove template", () => { describe("send verifyRemove template", () => {
it('should send plaintext email', function *() { it('should send plaintext email', function *() {
delete userId.publicKeyArmored; delete userId.publicKeyArmored;
yield email.send({ template:tpl.verifyRemove, userId, keyId, origin }); yield email.send({template: tpl.verifyRemove, userId, keyId, origin});
}); });
it('should send pgp encrypted email', function *() { it('should send pgp encrypted email', function *() {
yield email.send({ template:tpl.verifyRemove, userId, keyId, origin }); yield email.send({template: tpl.verifyRemove, userId, keyId, origin});
}); });
}); });
}); });

View File

@ -25,16 +25,16 @@ describe('Mongo Integration Tests', function() {
describe("create", () => { describe("create", () => {
it('should insert a document', function *() { it('should insert a document', function *() {
let r = yield mongo.create({ _id:'0' }, DB_TYPE); const r = yield mongo.create({_id: '0'}, DB_TYPE);
expect(r.insertedCount).to.equal(1); expect(r.insertedCount).to.equal(1);
}); });
it('should fail if two with the same ID are inserted', function *() { it('should fail if two with the same ID are inserted', function *() {
let r = yield mongo.create({ _id:'0' }, DB_TYPE); let r = yield mongo.create({_id: '0'}, DB_TYPE);
expect(r.insertedCount).to.equal(1); expect(r.insertedCount).to.equal(1);
try { try {
r = yield mongo.create({ _id:'0' }, DB_TYPE); r = yield mongo.create({_id: '0'}, DB_TYPE);
} catch(e) { } catch (e) {
expect(e.message).to.match(/duplicate/); expect(e.message).to.match(/duplicate/);
} }
}); });
@ -42,16 +42,16 @@ describe('Mongo Integration Tests', function() {
describe("batch", () => { describe("batch", () => {
it('should insert a document', function *() { it('should insert a document', function *() {
let r = yield mongo.batch([{ _id:'0' }, { _id:'1' }], DB_TYPE); const r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE);
expect(r.insertedCount).to.equal(2); expect(r.insertedCount).to.equal(2);
}); });
it('should fail if docs with the same ID are inserted', function *() { it('should fail if docs with the same ID are inserted', function *() {
let r = yield mongo.batch([{ _id:'0' }, { _id:'1' }], DB_TYPE); let r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE);
expect(r.insertedCount).to.equal(2); expect(r.insertedCount).to.equal(2);
try { try {
r = yield mongo.batch([{ _id:'0' }, { _id:'1' }], DB_TYPE); r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE);
} catch(e) { } catch (e) {
expect(e.message).to.match(/duplicate/); expect(e.message).to.match(/duplicate/);
} }
}); });
@ -59,37 +59,36 @@ describe('Mongo Integration Tests', function() {
describe("update", () => { describe("update", () => {
it('should update a document', function *() { it('should update a document', function *() {
let r = yield mongo.create({ _id:'0' }, DB_TYPE); let r = yield mongo.create({_id: '0'}, DB_TYPE);
r = yield mongo.update({ _id:'0' }, { foo:'bar' }, DB_TYPE); r = yield mongo.update({_id: '0'}, {foo: 'bar'}, DB_TYPE);
expect(r.modifiedCount).to.equal(1); expect(r.modifiedCount).to.equal(1);
r = yield mongo.get({ _id:'0' }, DB_TYPE); r = yield mongo.get({_id: '0'}, DB_TYPE);
expect(r.foo).to.equal('bar'); expect(r.foo).to.equal('bar');
}); });
}); });
describe("get", () => { describe("get", () => {
it('should get a document', function *() { it('should get a document', function *() {
let r = yield mongo.create({ _id:'0' }, DB_TYPE); let r = yield mongo.create({_id: '0'}, DB_TYPE);
r = yield mongo.get({ _id:'0' }, DB_TYPE); r = yield mongo.get({_id: '0'}, DB_TYPE);
expect(r).to.exist; expect(r).to.exist;
}); });
}); });
describe("list", () => { describe("list", () => {
it('should list documents', function *() { it('should list documents', function *() {
let r = yield mongo.batch([{ _id:'0', foo:'bar' }, { _id:'1', foo:'bar' }], DB_TYPE); let r = yield mongo.batch([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE);
r = yield mongo.list({ foo:'bar' }, DB_TYPE); r = yield mongo.list({foo: 'bar'}, DB_TYPE);
expect(r).to.deep.equal([{ _id:'0', foo:'bar' }, { _id:'1', foo:'bar' }], DB_TYPE); expect(r).to.deep.equal([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE);
}); });
}); });
describe("remove", () => { describe("remove", () => {
it('should remove a document', function *() { it('should remove a document', function *() {
let r = yield mongo.create({ _id:'0' }, DB_TYPE); let r = yield mongo.create({_id: '0'}, DB_TYPE);
r = yield mongo.remove({ _id:'0' }, DB_TYPE); r = yield mongo.remove({_id: '0'}, DB_TYPE);
r = yield mongo.get({ _id:'0' }, DB_TYPE); r = yield mongo.get({_id: '0'}, DB_TYPE);
expect(r).to.not.exist; expect(r).to.not.exist;
}); });
}); });
}); });

View File

@ -10,17 +10,23 @@ const PublicKey = require('../../src/service/public-key');
describe('Public Key Integration Tests', function() { describe('Public Key Integration Tests', function() {
this.timeout(20000); this.timeout(20000);
let publicKey, email, mongo, pgp, let publicKey;
sendEmailStub, publicKeyArmored, publicKeyArmored2, mailsSent; let email;
let mongo;
let pgp;
let sendEmailStub;
let publicKeyArmored;
let publicKeyArmored2;
let mailsSent;
const DB_TYPE = 'publickey'; const DB_TYPE = 'publickey';
const primaryEmail = 'test1@example.com'; const primaryEmail = 'test1@example.com';
const primaryEmail2 = 'test2@example.com'; const primaryEmail2 = 'test2@example.com';
const origin = { host:'localhost', protocol:'http' }; const origin = {host: 'localhost', protocol: 'http'};
before(function *() { before(function *() {
publicKeyArmored = require('fs').readFileSync(__dirname + '/../key3.asc', 'utf8'); publicKeyArmored = require('fs').readFileSync(`${__dirname}/../key3.asc`, 'utf8');
publicKeyArmored2 = require('fs').readFileSync(__dirname + '/../key4.asc', 'utf8'); publicKeyArmored2 = require('fs').readFileSync(`${__dirname}/../key4.asc`, 'utf8');
mongo = new Mongo(); mongo = new Mongo();
yield mongo.init(config.mongo); yield mongo.init(config.mongo);
}); });
@ -28,9 +34,9 @@ describe('Public Key Integration Tests', function() {
beforeEach(function *() { beforeEach(function *() {
yield mongo.clear(DB_TYPE); yield mongo.clear(DB_TYPE);
mailsSent = []; mailsSent = [];
sendEmailStub = sinon.stub().returns(Promise.resolve({ response:'250' })); sendEmailStub = sinon.stub().returns(Promise.resolve({response: '250'}));
sendEmailStub.withArgs(sinon.match(recipient => { sendEmailStub.withArgs(sinon.match(recipient => {
mailsSent[mailsSent.length] = {to:recipient.to.address}; mailsSent[mailsSent.length] = {to: recipient.to.address};
return true; return true;
}), sinon.match(params => { }), sinon.match(params => {
mailsSent[mailsSent.length - 1].params = params; mailsSent[mailsSent.length - 1].params = params;
@ -39,13 +45,13 @@ describe('Public Key Integration Tests', function() {
return true; return true;
})); }));
sinon.stub(nodemailer, 'createTransport').returns({ sinon.stub(nodemailer, 'createTransport').returns({
templateSender: () => { return sendEmailStub; } templateSender: () => sendEmailStub
}); });
email = new Email(nodemailer); email = new Email(nodemailer);
email.init({ email.init({
host: 'localhost', host: 'localhost',
auth: { user:'user', pass:'pass' }, auth: {user: 'user', pass: 'pass'},
sender: { name:'Foo Bar', email:'foo@bar.com' } sender: {name: 'Foo Bar', email: 'foo@bar.com'}
}); });
pgp = new PGP(); pgp = new PGP();
publicKey = new PublicKey(pgp, mongo, email); publicKey = new PublicKey(pgp, mongo, email);
@ -62,31 +68,31 @@ describe('Public Key Integration Tests', function() {
describe('put', () => { describe('put', () => {
it('should persist key and send verification email with primaryEmail', function *() { it('should persist key and send verification email with primaryEmail', function *() {
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
expect(mailsSent.length).to.equal(1); expect(mailsSent.length).to.equal(1);
expect(mailsSent[0].to).to.equal(primaryEmail); expect(mailsSent[0].to).to.equal(primaryEmail);
expect(mailsSent[0].params.keyId).to.exist; expect(mailsSent[0].params.keyId).to.exist;
expect(mailsSent[0].params.nonce).to.exist; expect(mailsSent[0].params.nonce).to.exist;
}); });
it('should persist key and send verification email without primaryEmail', function *() { it('should persist key and send verification email without primaryEmail', function *() {
yield publicKey.put({ publicKeyArmored, origin }); yield publicKey.put({publicKeyArmored, origin});
expect(mailsSent.length).to.equal(4); expect(mailsSent.length).to.equal(4);
}); });
it('should work twice if not yet verified', function *() { it('should work twice if not yet verified', function *() {
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
expect(mailsSent.length).to.equal(1); expect(mailsSent.length).to.equal(1);
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
expect(mailsSent.length).to.equal(2); expect(mailsSent.length).to.equal(2);
}); });
it('should throw 304 if key already exists', function *() { it('should throw 304 if key already exists', function *() {
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
yield publicKey.verify(mailsSent[0].params); yield publicKey.verify(mailsSent[0].params);
try { try {
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
expect(false).to.be.true; expect(false).to.be.true;
} catch(e) { } catch (e) {
expect(e.status).to.equal(304); expect(e.status).to.equal(304);
} }
}); });
@ -94,10 +100,10 @@ describe('Public Key Integration Tests', function() {
describe('verify', () => { describe('verify', () => {
it('should update the document', function *() { it('should update the document', function *() {
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
let emailParams = mailsSent[0].params; const emailParams = mailsSent[0].params;
yield publicKey.verify(emailParams); yield publicKey.verify(emailParams);
let gotten = yield mongo.get({ keyId:emailParams.keyId }, DB_TYPE); const gotten = yield mongo.get({keyId: emailParams.keyId}, DB_TYPE);
expect(gotten.userIds[0].verified).to.be.true; expect(gotten.userIds[0].verified).to.be.true;
expect(gotten.userIds[0].nonce).to.be.null; expect(gotten.userIds[0].nonce).to.be.null;
expect(gotten.userIds[1].verified).to.be.false; expect(gotten.userIds[1].verified).to.be.false;
@ -105,15 +111,15 @@ describe('Public Key Integration Tests', function() {
}); });
it('should not find the document', function *() { it('should not find the document', function *() {
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
let emailParams = mailsSent[0].params; const emailParams = mailsSent[0].params;
try { try {
yield publicKey.verify({ keyId:emailParams.keyId, nonce:'fake_nonce' }); yield publicKey.verify({keyId: emailParams.keyId, nonce: 'fake_nonce'});
expect(true).to.be.false; expect(true).to.be.false;
} catch(e) { } catch (e) {
expect(e.status).to.equal(404); expect(e.status).to.equal(404);
} }
let gotten = yield mongo.get({ keyId:emailParams.keyId }, DB_TYPE); const gotten = yield mongo.get({keyId: emailParams.keyId}, DB_TYPE);
expect(gotten.userIds[0].verified).to.be.false; expect(gotten.userIds[0].verified).to.be.false;
expect(gotten.userIds[0].nonce).to.equal(emailParams.nonce); expect(gotten.userIds[0].nonce).to.equal(emailParams.nonce);
expect(gotten.userIds[1].verified).to.be.false; expect(gotten.userIds[1].verified).to.be.false;
@ -121,32 +127,32 @@ describe('Public Key Integration Tests', function() {
}); });
it('should not verify a second key for already verified user id of another key', function *() { it('should not verify a second key for already verified user id of another key', function *() {
yield publicKey.put({ publicKeyArmored, primaryEmail:primaryEmail2, origin }); yield publicKey.put({publicKeyArmored, primaryEmail: primaryEmail2, origin});
expect(mailsSent.length).to.equal(1); expect(mailsSent.length).to.equal(1);
yield publicKey.put({ publicKeyArmored:publicKeyArmored2, primaryEmail:primaryEmail2, origin }); yield publicKey.put({publicKeyArmored: publicKeyArmored2, primaryEmail: primaryEmail2, origin});
expect(mailsSent.length).to.equal(2); expect(mailsSent.length).to.equal(2);
yield publicKey.verify(mailsSent[1].params); yield publicKey.verify(mailsSent[1].params);
try { try {
yield publicKey.verify(mailsSent[0].params); yield publicKey.verify(mailsSent[0].params);
expect(true).to.be.false; expect(true).to.be.false;
} catch(e) { } catch (e) {
expect(e.status).to.equal(304); expect(e.status).to.equal(304);
} }
let gotten = yield mongo.get({ keyId:mailsSent[0].params.keyId }, DB_TYPE); const gotten = yield mongo.get({keyId: mailsSent[0].params.keyId}, DB_TYPE);
expect(gotten.userIds[1].email).to.equal(primaryEmail2); expect(gotten.userIds[1].email).to.equal(primaryEmail2);
expect(gotten.userIds[1].verified).to.be.false; 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[0].params.nonce);
}); });
it('should be able to verify multiple user ids', function *() { it('should be able to verify multiple user ids', function *() {
yield publicKey.put({ publicKeyArmored, origin }); yield publicKey.put({publicKeyArmored, origin});
expect(mailsSent.length).to.equal(4); expect(mailsSent.length).to.equal(4);
yield publicKey.verify(mailsSent[0].params); yield publicKey.verify(mailsSent[0].params);
yield publicKey.verify(mailsSent[1].params); yield publicKey.verify(mailsSent[1].params);
yield publicKey.verify(mailsSent[2].params); yield publicKey.verify(mailsSent[2].params);
yield publicKey.verify(mailsSent[3].params); yield publicKey.verify(mailsSent[3].params);
let gotten = yield mongo.get({ keyId:mailsSent[0].params.keyId }, DB_TYPE); const gotten = yield mongo.get({keyId: mailsSent[0].params.keyId}, DB_TYPE);
expect(gotten.userIds[0].verified).to.be.true; expect(gotten.userIds[0].verified).to.be.true;
expect(gotten.userIds[1].verified).to.be.true; expect(gotten.userIds[1].verified).to.be.true;
expect(gotten.userIds[2].verified).to.be.true; expect(gotten.userIds[2].verified).to.be.true;
@ -160,37 +166,37 @@ describe('Public Key Integration Tests', function() {
describe('should find a verified key', () => { describe('should find a verified key', () => {
beforeEach(function *() { beforeEach(function *() {
key = pgp.parseKey(publicKeyArmored); key = pgp.parseKey(publicKeyArmored);
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
yield publicKey.verify(mailsSent[0].params); yield publicKey.verify(mailsSent[0].params);
}); });
it('by fingerprint', function *() { it('by fingerprint', function *() {
let verified = yield publicKey.getVerified({ fingerprint:key.fingerprint }); const verified = yield publicKey.getVerified({fingerprint: key.fingerprint});
expect(verified).to.exist; expect(verified).to.exist;
}); });
it('by all userIds', function *() { it('by all userIds', function *() {
let verified = yield publicKey.getVerified({ userIds:key.userIds }); const verified = yield publicKey.getVerified({userIds: key.userIds});
expect(verified).to.exist; expect(verified).to.exist;
}); });
it('by verified userId', function *() { it('by verified userId', function *() {
let verified = yield publicKey.getVerified({ userIds:[key.userIds[0]] }); const verified = yield publicKey.getVerified({userIds: [key.userIds[0]]});
expect(verified).to.exist; expect(verified).to.exist;
}); });
it('by unverified userId', function *() { it('by unverified userId', function *() {
let verified = yield publicKey.getVerified({ userIds:[key.userIds[1]] }); const verified = yield publicKey.getVerified({userIds: [key.userIds[1]]});
expect(verified).to.not.exist; expect(verified).to.not.exist;
}); });
it('by keyId', function *() { it('by keyId', function *() {
let verified = yield publicKey.getVerified({ keyId:key.keyId }); const verified = yield publicKey.getVerified({keyId: key.keyId});
expect(verified).to.exist; expect(verified).to.exist;
}); });
it('by all params', function *() { it('by all params', function *() {
let verified = yield publicKey.getVerified(key); const verified = yield publicKey.getVerified(key);
expect(verified).to.exist; expect(verified).to.exist;
}); });
}); });
@ -203,22 +209,22 @@ describe('Public Key Integration Tests', function() {
}); });
it('by fingerprint', function *() { it('by fingerprint', function *() {
let verified = yield publicKey.getVerified({ fingerprint:key.fingerprint }); const verified = yield publicKey.getVerified({fingerprint: key.fingerprint});
expect(verified).to.not.exist; expect(verified).to.not.exist;
}); });
it('by userIds', function *() { it('by userIds', function *() {
let verified = yield publicKey.getVerified({ userIds:key.userIds }); const verified = yield publicKey.getVerified({userIds: key.userIds});
expect(verified).to.not.exist; expect(verified).to.not.exist;
}); });
it('by keyId', function *() { it('by keyId', function *() {
let verified = yield publicKey.getVerified({ keyId:key.keyId }); const verified = yield publicKey.getVerified({keyId: key.keyId});
expect(verified).to.not.exist; expect(verified).to.not.exist;
}); });
it('by all params', function *() { it('by all params', function *() {
let verified = yield publicKey.getVerified(key); const verified = yield publicKey.getVerified(key);
expect(verified).to.not.exist; expect(verified).to.not.exist;
}); });
}); });
@ -228,53 +234,53 @@ describe('Public Key Integration Tests', function() {
let emailParams; let emailParams;
beforeEach(function *() { beforeEach(function *() {
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
emailParams = mailsSent[0].params; emailParams = mailsSent[0].params;
}); });
it('should return verified key by key id', function *() { it('should return verified key by key id', function *() {
yield publicKey.verify(emailParams); yield publicKey.verify(emailParams);
let key = yield publicKey.get({ keyId:emailParams.keyId }); const key = yield publicKey.get({keyId: emailParams.keyId});
expect(key.publicKeyArmored).to.exist; expect(key.publicKeyArmored).to.exist;
}); });
it('should return verified key by key id (uppercase)', function *() { it('should return verified key by key id (uppercase)', function *() {
yield publicKey.verify(emailParams); yield publicKey.verify(emailParams);
let key = yield publicKey.get({ keyId:emailParams.keyId.toUpperCase() }); const key = yield publicKey.get({keyId: emailParams.keyId.toUpperCase()});
expect(key.publicKeyArmored).to.exist; expect(key.publicKeyArmored).to.exist;
}); });
it('should return verified key by fingerprint', function *() { it('should return verified key by fingerprint', function *() {
yield publicKey.verify(emailParams); yield publicKey.verify(emailParams);
let fingerprint = pgp.parseKey(publicKeyArmored).fingerprint; const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint;
let key = yield publicKey.get({ fingerprint }); const key = yield publicKey.get({fingerprint});
expect(key.publicKeyArmored).to.exist; expect(key.publicKeyArmored).to.exist;
}); });
it('should return verified key by fingerprint (uppercase)', function *() { it('should return verified key by fingerprint (uppercase)', function *() {
yield publicKey.verify(emailParams); yield publicKey.verify(emailParams);
let fingerprint = pgp.parseKey(publicKeyArmored).fingerprint.toUpperCase(); const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint.toUpperCase();
let key = yield publicKey.get({ fingerprint }); const key = yield publicKey.get({fingerprint});
expect(key.publicKeyArmored).to.exist; expect(key.publicKeyArmored).to.exist;
}); });
it('should return verified key by email address', function *() { it('should return verified key by email address', function *() {
yield publicKey.verify(emailParams); yield publicKey.verify(emailParams);
let key = yield publicKey.get({ email:primaryEmail }); const key = yield publicKey.get({email: primaryEmail});
expect(key.publicKeyArmored).to.exist; expect(key.publicKeyArmored).to.exist;
}); });
it('should return verified key by email address (uppercase)', function *() { it('should return verified key by email address (uppercase)', function *() {
yield publicKey.verify(emailParams); yield publicKey.verify(emailParams);
let key = yield publicKey.get({ email:primaryEmail.toUpperCase() }); const key = yield publicKey.get({email: primaryEmail.toUpperCase()});
expect(key.publicKeyArmored).to.exist; expect(key.publicKeyArmored).to.exist;
}); });
it('should throw 404 for unverified key', function *() { it('should throw 404 for unverified key', function *() {
try { try {
yield publicKey.get({ keyId:emailParams.keyId }); yield publicKey.get({keyId: emailParams.keyId});
expect(false).to.be.true; expect(false).to.be.true;
} catch(e) { } catch (e) {
expect(e.status).to.equal(404); expect(e.status).to.equal(404);
} }
}); });
@ -284,32 +290,32 @@ describe('Public Key Integration Tests', function() {
let keyId; let keyId;
beforeEach(function *() { beforeEach(function *() {
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
keyId = mailsSent[0].params.keyId; keyId = mailsSent[0].params.keyId;
}); });
it('should work for verified key', function *() { it('should work for verified key', function *() {
yield publicKey.verify(mailsSent[0].params); yield publicKey.verify(mailsSent[0].params);
yield publicKey.requestRemove({ keyId, origin }); yield publicKey.requestRemove({keyId, origin});
expect(mailsSent.length).to.equal(5); expect(mailsSent.length).to.equal(5);
}); });
it('should work for unverified key', function *() { it('should work for unverified key', function *() {
yield publicKey.requestRemove({ keyId, origin }); yield publicKey.requestRemove({keyId, origin});
expect(mailsSent.length).to.equal(5); expect(mailsSent.length).to.equal(5);
}); });
it('should work by email address', function *() { it('should work by email address', function *() {
yield publicKey.requestRemove({ email:primaryEmail, origin }); yield publicKey.requestRemove({email: primaryEmail, origin});
expect(mailsSent.length).to.equal(2); expect(mailsSent.length).to.equal(2);
}); });
it('should throw 404 for no key', function *() { it('should throw 404 for no key', function *() {
yield mongo.remove({ keyId }, DB_TYPE); yield mongo.remove({keyId}, DB_TYPE);
try { try {
yield publicKey.requestRemove({ keyId, origin }); yield publicKey.requestRemove({keyId, origin});
expect(false).to.be.true; expect(false).to.be.true;
} catch(e) { } catch (e) {
expect(e.status).to.equal(404); expect(e.status).to.equal(404);
} }
}); });
@ -319,26 +325,25 @@ describe('Public Key Integration Tests', function() {
let keyId; let keyId;
beforeEach(function *() { beforeEach(function *() {
yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); yield publicKey.put({publicKeyArmored, primaryEmail, origin});
keyId = mailsSent[0].params.keyId; keyId = mailsSent[0].params.keyId;
yield publicKey.requestRemove({ keyId, origin }); yield publicKey.requestRemove({keyId, origin});
}); });
it('should remove key', function *() { it('should remove key', function *() {
yield publicKey.verifyRemove(mailsSent[1].params); yield publicKey.verifyRemove(mailsSent[1].params);
let key = yield mongo.get({ keyId }, DB_TYPE); const key = yield mongo.get({keyId}, DB_TYPE);
expect(key).to.not.exist; expect(key).to.not.exist;
}); });
it('should throw 404 for no key', function *() { it('should throw 404 for no key', function *() {
yield mongo.remove({ keyId }, DB_TYPE); yield mongo.remove({keyId}, DB_TYPE);
try { try {
yield publicKey.verifyRemove(mailsSent[1].params); yield publicKey.verifyRemove(mailsSent[1].params);
expect(false).to.be.true; expect(false).to.be.true;
} catch(e) { } catch (e) {
expect(e.status).to.equal(404); expect(e.status).to.equal(404);
} }
}); });
}); });
}); });

View File

@ -5,28 +5,29 @@ const Email = require('../../src/email/email');
const nodemailer = require('nodemailer'); const nodemailer = require('nodemailer');
describe('Email Unit Tests', () => { describe('Email Unit Tests', () => {
let email, sendFnStub; let email;
let sendFnStub;
let template = { const template = {
subject: 'foo', subject: 'foo',
text: 'bar', text: 'bar',
html: '<strong>bar</strong>' html: '<strong>bar</strong>'
}; };
let sender = { const sender = {
name: 'Foo Bar', name: 'Foo Bar',
email: 'foo@bar.com' email: 'foo@bar.com'
}; };
let userId1 = { const userId1 = {
name: 'name1', name: 'name1',
email: 'email1', email: 'email1',
nonce: 'qwertzuioasdfghjkqwertzuio' nonce: 'qwertzuioasdfghjkqwertzuio'
}; };
let keyId = '0123456789ABCDF0'; const keyId = '0123456789ABCDF0';
let origin = { const origin = {
protocol: 'http', protocol: 'http',
host: 'localhost:8888' host: 'localhost:8888'
}; };
let mailOptions = { const mailOptions = {
from: sender, from: sender,
to: sender, to: sender,
subject: 'Hello ✔', // Subject line subject: 'Hello ✔', // Subject line
@ -37,7 +38,7 @@ describe('Email Unit Tests', () => {
beforeEach(() => { beforeEach(() => {
sendFnStub = sinon.stub(); sendFnStub = sinon.stub();
sinon.stub(nodemailer, 'createTransport').returns({ sinon.stub(nodemailer, 'createTransport').returns({
templateSender: () => { return sendFnStub; } templateSender: () => sendFnStub
}); });
sinon.stub(log, 'warn'); sinon.stub(log, 'warn');
@ -46,8 +47,8 @@ describe('Email Unit Tests', () => {
email = new Email(nodemailer); email = new Email(nodemailer);
email.init({ email.init({
host: 'host', host: 'host',
auth: { user:'user', pass:'pass' }, auth: {user: 'user', pass: 'pass'},
sender: sender sender
}); });
expect(email._sender).to.equal(sender); expect(email._sender).to.equal(sender);
}); });
@ -60,7 +61,7 @@ describe('Email Unit Tests', () => {
describe("send", () => { describe("send", () => {
beforeEach(() => { beforeEach(() => {
sinon.stub(email, '_sendHelper').returns(Promise.resolve({ response:'250' })); sinon.stub(email, '_sendHelper').returns(Promise.resolve({response: '250'}));
}); });
afterEach(() => { afterEach(() => {
@ -68,7 +69,7 @@ describe('Email Unit Tests', () => {
}); });
it('should work', function *() { it('should work', function *() {
let info = yield email.send({ template, userId:userId1, keyId, origin}); const info = yield email.send({template, userId: userId1, keyId, origin});
expect(info.response).to.match(/^250/); expect(info.response).to.match(/^250/);
}); });
@ -76,17 +77,17 @@ describe('Email Unit Tests', () => {
describe("_sendHelper", () => { describe("_sendHelper", () => {
it('should work', function *() { it('should work', function *() {
sendFnStub.returns(Promise.resolve({ response:'250' })); sendFnStub.returns(Promise.resolve({response: '250'}));
let info = yield email._sendHelper(mailOptions); const info = yield email._sendHelper(mailOptions);
expect(info.response).to.match(/^250/); expect(info.response).to.match(/^250/);
}); });
it('should log warning for reponse error', function *() { it('should log warning for reponse error', function *() {
sendFnStub.returns(Promise.resolve({ response:'554' })); sendFnStub.returns(Promise.resolve({response: '554'}));
let info = yield email._sendHelper(mailOptions); const info = yield email._sendHelper(mailOptions);
expect(info.response).to.match(/^554/); expect(info.response).to.match(/^554/);
expect(log.warn.calledOnce).to.be.true; expect(log.warn.calledOnce).to.be.true;
@ -97,12 +98,11 @@ describe('Email Unit Tests', () => {
try { try {
yield email._sendHelper(mailOptions); yield email._sendHelper(mailOptions);
} catch(e) { } catch (e) {
expect(log.error.calledOnce).to.be.true; expect(log.error.calledOnce).to.be.true;
expect(e.status).to.equal(500); expect(e.status).to.equal(500);
expect(e.message).to.match(/failed/); expect(e.message).to.match(/failed/);
} }
}); });
}); });
}); });

View File

@ -6,18 +6,21 @@ const openpgp = require('openpgp');
const PGP = require('../../src/service/pgp'); const PGP = require('../../src/service/pgp');
describe('PGP Unit Tests', () => { describe('PGP Unit Tests', () => {
let pgp, key1Armored, key2Armored, key3Armored; let pgp;
let key1Armored;
let key2Armored;
let key3Armored;
beforeEach(() => { beforeEach(() => {
key1Armored = fs.readFileSync(__dirname + '/../key1.asc', 'utf8'); key1Armored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8');
key2Armored = fs.readFileSync(__dirname + '/../key2.asc', 'utf8'); key2Armored = fs.readFileSync(`${__dirname}/../key2.asc`, 'utf8');
key3Armored = fs.readFileSync(__dirname + '/../key3.asc', 'utf8'); key3Armored = fs.readFileSync(`${__dirname}/../key3.asc`, 'utf8');
pgp = new PGP(); pgp = new PGP();
}); });
describe('parseKey', () => { describe('parseKey', () => {
it('should should throw error on key parsing', () => { it('should should throw error on key parsing', () => {
let readStub = sinon.stub(openpgp.key, 'readArmored').returns({err:[new Error()]}); const readStub = sinon.stub(openpgp.key, 'readArmored').returns({err: [new Error()]});
sinon.stub(log, 'error'); sinon.stub(log, 'error');
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/Failed to parse/); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/Failed to parse/);
expect(log.error.calledOnce).to.be.true; expect(log.error.calledOnce).to.be.true;
@ -26,16 +29,16 @@ describe('PGP Unit Tests', () => {
}); });
it('should should throw error when more than one key', () => { it('should should throw error when more than one key', () => {
let readStub = sinon.stub(openpgp.key, 'readArmored').returns({keys:[{},{}]}); const readStub = sinon.stub(openpgp.key, 'readArmored').returns({keys: [{}, {}]});
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only one key/); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only one key/);
readStub.restore(); readStub.restore();
}); });
it('should should throw error when more than one key', () => { it('should should throw error when more than one key', () => {
let readStub = sinon.stub(openpgp.key, 'readArmored').returns({ const readStub = sinon.stub(openpgp.key, 'readArmored').returns({
keys: [{ keys: [{
primaryKey: {}, primaryKey: {},
verifyPrimaryKey: function() { return false; } verifyPrimaryKey() { return false; }
}] }]
}); });
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/primary key verification/); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/primary key verification/);
@ -43,17 +46,17 @@ describe('PGP Unit Tests', () => {
}); });
it('should only accept 16 char key id', () => { it('should only accept 16 char key id', () => {
let readStub = sinon.stub(openpgp.key, 'readArmored').returns({ const readStub = sinon.stub(openpgp.key, 'readArmored').returns({
keys: [{ keys: [{
primaryKey: { primaryKey: {
fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e9', fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e9',
getKeyId: function() { getKeyId() {
return { return {
toHex:function() { return 'asdf'; } toHex() { return 'asdf'; }
}; };
} }
}, },
verifyPrimaryKey: function() { return openpgp.enums.keyStatus.valid; } verifyPrimaryKey() { return openpgp.enums.keyStatus.valid; }
}] }]
}); });
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/);
@ -61,17 +64,17 @@ describe('PGP Unit Tests', () => {
}); });
it('should only accept version 4 fingerprint', () => { it('should only accept version 4 fingerprint', () => {
let readStub = sinon.stub(openpgp.key, 'readArmored').returns({ const readStub = sinon.stub(openpgp.key, 'readArmored').returns({
keys: [{ keys: [{
primaryKey: { primaryKey: {
fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e', fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e',
getKeyId: function() { getKeyId() {
return { return {
toHex:function() { return 'dbc0b3d92b1b86e9'; } toHex() { return 'dbc0b3d92b1b86e9'; }
}; };
} }
}, },
verifyPrimaryKey: function() { return openpgp.enums.keyStatus.valid; } verifyPrimaryKey() { return openpgp.enums.keyStatus.valid; }
}] }]
}); });
expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/only v4 keys/);
@ -84,7 +87,7 @@ describe('PGP Unit Tests', () => {
}); });
it('should be able to parse RSA key', () => { it('should be able to parse RSA key', () => {
let params = pgp.parseKey(key1Armored); const params = pgp.parseKey(key1Armored);
expect(params.keyId).to.equal('dbc0b3d92b1b86e9'); expect(params.keyId).to.equal('dbc0b3d92b1b86e9');
expect(params.fingerprint).to.equal('4277257930867231ce393fb8dbc0b3d92b1b86e9'); expect(params.fingerprint).to.equal('4277257930867231ce393fb8dbc0b3d92b1b86e9');
expect(params.userIds[0].name).to.equal('safewithme testuser'); expect(params.userIds[0].name).to.equal('safewithme testuser');
@ -96,7 +99,7 @@ describe('PGP Unit Tests', () => {
}); });
it('should be able to parse RSA/ECC key', () => { it('should be able to parse RSA/ECC key', () => {
let params = pgp.parseKey(key2Armored); const params = pgp.parseKey(key2Armored);
expect(params.keyId).to.equal('b8e4105cc9dedc77'); expect(params.keyId).to.equal('b8e4105cc9dedc77');
expect(params.fingerprint).to.equal('e3317db04d3958fd5f662c37b8e4105cc9dedc77'); expect(params.fingerprint).to.equal('e3317db04d3958fd5f662c37b8e4105cc9dedc77');
expect(params.userIds.length).to.equal(1); expect(params.userIds.length).to.equal(1);
@ -107,7 +110,7 @@ describe('PGP Unit Tests', () => {
}); });
it('should be able to parse komplex key', () => { it('should be able to parse komplex key', () => {
let params = pgp.parseKey(key3Armored); const params = pgp.parseKey(key3Armored);
expect(params.keyId).to.equal('4001a127a90de8e1'); expect(params.keyId).to.equal('4001a127a90de8e1');
expect(params.fingerprint).to.equal('04062c70b446e33016e219a74001a127a90de8e1'); expect(params.fingerprint).to.equal('04062c70b446e33016e219a74001a127a90de8e1');
expect(params.userIds.length).to.equal(4); expect(params.userIds.length).to.equal(4);
@ -120,12 +123,12 @@ describe('PGP Unit Tests', () => {
describe('trimKey', () => { describe('trimKey', () => {
it('should be the same as key1', () => { it('should be the same as key1', () => {
let trimmed = pgp.trimKey(key1Armored); const trimmed = pgp.trimKey(key1Armored);
expect(trimmed).to.equal(key1Armored); expect(trimmed).to.equal(key1Armored);
}); });
it('should not be the same as key2', () => { it('should not be the same as key2', () => {
let trimmed = pgp.trimKey(key2Armored); const trimmed = pgp.trimKey(key2Armored);
expect(trimmed).to.not.equal(key2Armored); expect(trimmed).to.not.equal(key2Armored);
}); });
}); });
@ -135,22 +138,22 @@ describe('PGP Unit Tests', () => {
const KEY_END = '-----END PGP PUBLIC KEY BLOCK-----'; const KEY_END = '-----END PGP PUBLIC KEY BLOCK-----';
it('should return true for valid key block', () => { it('should return true for valid key block', () => {
let input = KEY_BEGIN + KEY_END; const input = KEY_BEGIN + KEY_END;
expect(pgp.validateKeyBlock(input)).to.be.true; expect(pgp.validateKeyBlock(input)).to.be.true;
}); });
it('should return false for invalid key block', () => { it('should return false for invalid key block', () => {
let input = KEY_END + KEY_BEGIN; const input = KEY_END + KEY_BEGIN;
expect(pgp.validateKeyBlock(input)).to.be.false; expect(pgp.validateKeyBlock(input)).to.be.false;
}); });
it('should return false for invalid key block', () => { it('should return false for invalid key block', () => {
let input = KEY_END; const input = KEY_END;
expect(pgp.validateKeyBlock(input)).to.be.false; expect(pgp.validateKeyBlock(input)).to.be.false;
}); });
it('should return false for invalid key block', () => { it('should return false for invalid key block', () => {
let input = KEY_BEGIN; const input = KEY_BEGIN;
expect(pgp.validateKeyBlock(input)).to.be.false; expect(pgp.validateKeyBlock(input)).to.be.false;
}); });
}); });
@ -163,7 +166,7 @@ describe('PGP Unit Tests', () => {
}); });
it('should parse a valid user id', () => { it('should parse a valid user id', () => {
let parsed = pgp.parseUserIds(key.users, key.primaryKey); const parsed = pgp.parseUserIds(key.users, key.primaryKey);
expect(parsed[0].name).to.equal('safewithme testuser'); expect(parsed[0].name).to.equal('safewithme testuser');
expect(parsed[0].email).to.equal('safewithme.testuser@gmail.com'); expect(parsed[0].email).to.equal('safewithme.testuser@gmail.com');
}); });
@ -174,17 +177,16 @@ describe('PGP Unit Tests', () => {
it('should return no user id for an invalid signature', () => { it('should return no user id for an invalid signature', () => {
key.users[0].userId.userid = 'fake@example.com'; key.users[0].userId.userid = 'fake@example.com';
let parsed = pgp.parseUserIds(key.users, key.primaryKey); const parsed = pgp.parseUserIds(key.users, key.primaryKey);
expect(parsed.length).to.equal(0); expect(parsed.length).to.equal(0);
}); });
it('should throw for a invalid email address', () => { it('should throw for a invalid email address', () => {
let verifyStub = sinon.stub(key.users[0], 'isValidSelfCertificate').returns(true); const verifyStub = sinon.stub(key.users[0], 'isValidSelfCertificate').returns(true);
key.users[0].userId.userid = 'safewithme testuser <safewithme.testusergmail.com>'; key.users[0].userId.userid = 'safewithme testuser <safewithme.testusergmail.com>';
let parsed = pgp.parseUserIds(key.users, key.primaryKey); const parsed = pgp.parseUserIds(key.users, key.primaryKey);
expect(parsed.length).to.equal(0); expect(parsed.length).to.equal(0);
verifyStub.restore(); verifyStub.restore();
}); });
}); });
}); });

View File

@ -116,7 +116,7 @@ describe('Util Unit Tests', () => {
try { try {
util.throw(500, 'boom'); util.throw(500, 'boom');
expect(true).to.be.false; expect(true).to.be.false;
} catch(e) { } catch (e) {
expect(e.message).to.equal('boom'); expect(e.message).to.equal('boom');
expect(e.status).to.equal(500); expect(e.status).to.equal(500);
expect(e.expose).to.be.true; expect(e.expose).to.be.true;
@ -136,20 +136,19 @@ describe('Util Unit Tests', () => {
describe('origin', () => { describe('origin', () => {
it('should work', () => { it('should work', () => {
expect(util.origin({ secure:true, host:'h', protocol:'p' })).to.exist; expect(util.origin({secure: true, host: 'h', protocol: 'p'})).to.exist;
}); });
}); });
describe('url', () => { describe('url', () => {
it('should work with resource', () => { it('should work with resource', () => {
let url = util.url({ host:'localhost', protocol:'http'}, '/foo'); const url = util.url({host: 'localhost', protocol: 'http'}, '/foo');
expect(url).to.equal('http://localhost/foo'); expect(url).to.equal('http://localhost/foo');
}); });
it('should work without resource', () => { it('should work without resource', () => {
let url = util.url({ host:'localhost', protocol:'http'}); const url = util.url({host: 'localhost', protocol: 'http'});
expect(url).to.equal('http://localhost'); expect(url).to.equal('http://localhost');
}); });
}); });
}); });