From 750cf3d897283d2a018fc3938bbdf9bb72cf471f Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Tue, 15 Aug 2017 15:22:15 +0800 Subject: [PATCH 1/7] Use eslint instead of jscs/jshint Add .eslint.rc and test/.eslint.rc --- .eslintrc | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 8 +++---- test/.eslintrc | 13 +++++++++++ 3 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 .eslintrc create mode 100644 test/.eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..322a0f0 --- /dev/null +++ b/.eslintrc @@ -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 +} diff --git a/package.json b/package.json index db7a497..5ae7d09 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,8 @@ }, "scripts": { "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:jshint": "jshint *.js src/**/*.js test/**/*.js", - "test:jscs": "jscs *.js src/**/*.js test/**/*.js", + "test": ": ${NODE_ENV=development} && npm run test:lint && npm run test:unit && npm run test:integration", + "test:lint": "eslint config src test *.js", "test:unit": "mocha --opts test/mocha.opts ./test/unit/", "test:integration": "mocha --opts test/mocha.opts ./test/integration", "release": "npm run release:install && npm run release:archive", @@ -37,8 +36,7 @@ "devDependencies": { "chai": "^4.1.1", "co-mocha": "^1.1.2", - "jscs": "^3.0.7", - "jshint": "^2.9.4", + "eslint": "^4.4.1", "mocha": "^3.2.0", "sinon": "^1.17.4", "supertest": "^3.0.0" diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 0000000..4623dd0 --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,13 @@ +{ + "extends": "../.eslintrc", + "rules": { + "no-shadow": 1 + }, + "globals": { + "expect": true, + "sinon": true + }, + "env": { + "mocha": true + } +} From e9251d5203224a67b40b6df4a0ce46d97ca1eddf Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Tue, 15 Aug 2017 16:03:06 +0800 Subject: [PATCH 2/7] Fix eslint errors --- config/default.js | 4 +- config/integration.js | 4 +- config/production.js | 4 +- index.js | 2 +- src/app.js | 19 ++-- src/dao/mongo.js | 24 +++-- src/email/email.js | 26 +++--- src/route/hkp.js | 40 ++++---- src/route/rest.js | 23 ++--- src/service/pgp.js | 25 +++-- src/service/public-key.js | 77 ++++++++------- src/service/util.js | 8 +- src/static/js/demo.js | 32 ++++--- test/integration/app-test.js | 92 +++++++++--------- test/integration/email-test.js | 29 +++--- test/integration/mongo-test.js | 41 ++++---- test/integration/public-key-test.js | 139 ++++++++++++++-------------- test/unit/email-test.js | 38 ++++---- test/unit/pgp-test.js | 64 ++++++------- test/unit/util-test.js | 11 +-- 20 files changed, 355 insertions(+), 347 deletions(-) diff --git a/config/default.js b/config/default.js index fb0c886..a6fb1dc 100644 --- a/config/default.js +++ b/config/default.js @@ -1,3 +1,5 @@ +'use strict'; + module.exports = { log: { @@ -33,4 +35,4 @@ module.exports = { } } -}; \ No newline at end of file +}; diff --git a/config/integration.js b/config/integration.js index c4537d6..96e3d8d 100644 --- a/config/integration.js +++ b/config/integration.js @@ -1,7 +1,9 @@ +'use strict'; + module.exports = { log: { level: 'warn' } -}; \ No newline at end of file +}; diff --git a/config/production.js b/config/production.js index a8dba5b..4c258ce 100644 --- a/config/production.js +++ b/config/production.js @@ -1,7 +1,9 @@ +'use strict'; + module.exports = { log: { level: 'error' } -}; \ No newline at end of file +}; diff --git a/index.js b/index.js index 3d571fc..d42c166 100644 --- a/index.js +++ b/index.js @@ -58,4 +58,4 @@ process.on('SIGINT', () => { process.on('uncaughtException', err => { log.error('index', 'Uncaught exception', err); process.exit(1); -}); \ No newline at end of file +}); diff --git a/src/app.js b/src/app.js index 276bf94..61bbf94 100644 --- a/src/app.js +++ b/src/app.js @@ -31,7 +31,12 @@ const PublicKey = require('./service/public-key'); const HKP = require('./route/hkp'); 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 @@ -59,7 +64,7 @@ router.del('/api/v1/key', function *() { // Redirect all http traffic to https app.use(function *(next) { if (util.isTrue(config.server.httpsUpgrade) && util.checkHTTP(this)) { - this.redirect('https://' + this.hostname + this.url); + this.redirect(`https://${this.hostname}${this.url}`); } else { yield next; } @@ -73,7 +78,7 @@ app.use(function *(next) { } // HPKP if (config.server.httpsKeyPin && config.server.httpsKeyPinBackup) { - this.set('Public-Key-Pins', 'pin-sha256="' + config.server.httpsKeyPin + '"; pin-sha256="' + config.server.httpsKeyPinBackup + '"; max-age=16070400'); + this.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`); } // CSP this.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; script-src 'self' code.jquery.com; style-src 'self' maxcdn.bootstrapcdn.com; font-src 'self' maxcdn.bootstrapcdn.com"); @@ -91,7 +96,7 @@ app.use(router.routes()); app.use(router.allowedMethods()); // serve static files -app.use(serve(__dirname + '/static')); +app.use(serve(`${__dirname}/static`)); app.on('error', (error, ctx) => { if (error.status) { @@ -120,9 +125,9 @@ function injectDependencies() { if (!global.testing) { // don't automatically start server in tests co(function *() { - let app = yield init(); + const app = yield init(); 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)); } @@ -135,4 +140,4 @@ function *init() { return app; } -module.exports = init; \ No newline at end of file +module.exports = init; diff --git a/src/dao/mongo.js b/src/dao/mongo.js index 6658729..f1ccecc 100644 --- a/src/dao/mongo.js +++ b/src/dao/mongo.js @@ -23,7 +23,6 @@ const MongoClient = require('mongodb').MongoClient; * A simple wrapper around the official MongoDB client. */ class Mongo { - /** * Initializes the database client by connecting to the MongoDB. * @param {String} uri The mongodb uri @@ -31,8 +30,8 @@ class Mongo { * @param {String} pass The database user's password * @yield {undefined} */ - *init({ uri, user, pass }) { - let url = 'mongodb://' + user + ':' + pass + '@' + uri; + *init({uri, user, pass}) { + const url = `mongodb://${user}:${pass}@${uri}`; this._db = yield MongoClient.connect(url); } @@ -51,7 +50,7 @@ class Mongo { * @yield {Object} The operation result */ create(document, type) { - let col = this._db.collection(type); + const col = this._db.collection(type); return col.insertOne(document); } @@ -62,7 +61,7 @@ class Mongo { * @yield {Object} The operation result */ batch(documents, type) { - let col = this._db.collection(type); + const col = this._db.collection(type); return col.insertMany(documents); } @@ -74,8 +73,8 @@ class Mongo { * @yield {Object} The operation result */ update(query, diff, type) { - let col = this._db.collection(type); - return col.updateOne(query, { $set:diff }); + const col = this._db.collection(type); + return col.updateOne(query, {$set: diff}); } /** @@ -85,7 +84,7 @@ class Mongo { * @yield {Object} The document object */ get(query, type) { - let col = this._db.collection(type); + const col = this._db.collection(type); return col.findOne(query); } @@ -96,7 +95,7 @@ class Mongo { * @yield {Array} An array of document objects */ list(query, type) { - let col = this._db.collection(type); + const col = this._db.collection(type); return col.find(query).toArray(); } @@ -107,7 +106,7 @@ class Mongo { * @yield {Object} The operation result */ remove(query, type) { - let col = this._db.collection(type); + const col = this._db.collection(type); return col.deleteMany(query); } @@ -117,10 +116,9 @@ class Mongo { * @yield {Object} The operation result */ clear(type) { - let col = this._db.collection(type); + const col = this._db.collection(type); return col.deleteMany({}); } - } -module.exports = Mongo; \ No newline at end of file +module.exports = Mongo; diff --git a/src/email/email.js b/src/email/email.js index 92f4b67..060bf22 100644 --- a/src/email/email.js +++ b/src/email/email.js @@ -26,7 +26,6 @@ const openpgpEncrypt = require('nodemailer-openpgp').openpgpEncrypt; * A simple wrapper around Nodemailer to send verification emails */ class Email { - /** * Create an instance of the reusable nodemailer SMTP transport. * @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} 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({ host, port, @@ -59,8 +58,8 @@ class Email { * @param {Object} origin origin of the server * @yield {Object} send response from the SMTP server */ - *send({ template, userId, keyId, origin }) { - let message = { + *send({template, userId, keyId, origin}) { + const message = { from: this._sender, to: userId, subject: template.subject, @@ -69,7 +68,7 @@ class Email { params: { name: userId.name, baseUrl: util.url(origin), - keyId: keyId, + keyId, nonce: userId.nonce } }; @@ -86,20 +85,20 @@ class Email { * @param {Object} params (optional) nodermailer template parameters * @yield {Object} reponse object containing SMTP info */ - *_sendHelper({ from, to, subject, text, html, params={} }) { - let template = { + *_sendHelper({from, to, subject, text, html, params = {}}) { + const template = { subject, text, html, encryptionKeys: [to.publicKeyArmored] }; - let sender = { + const sender = { from: { name: from.name, address: from.email } }; - let recipient = { + const recipient = { to: { name: to.name, address: to.email @@ -107,13 +106,13 @@ class Email { }; try { - let sendFn = this._transport.templateSender(template, sender); - let info = yield sendFn(recipient, params); + const sendFn = this._transport.templateSender(template, sender); + const info = yield sendFn(recipient, params); if (!this._checkResponse(info)) { log.warn('email', 'Message may not have been received.', info); } return info; - } catch(error) { + } catch (error) { log.error('email', 'Sending message failed.', error); util.throw(500, 'Sending email to user failed'); } @@ -128,7 +127,6 @@ class Email { _checkResponse(info) { return /^2/.test(info.response); } - } -module.exports = Email; \ No newline at end of file +module.exports = Email; diff --git a/src/route/hkp.js b/src/route/hkp.js index 78d11b0..15372a3 100644 --- a/src/route/hkp.js +++ b/src/route/hkp.js @@ -25,7 +25,6 @@ const util = require('../service/util'); * See https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00 */ class HKP { - /** * Create an instance of the HKP server * @param {Object} publicKey An instance of the public key service @@ -39,13 +38,12 @@ class HKP { * @param {Object} ctx The koa request/response context */ *add(ctx) { - let body = yield parse.form(ctx, { limit: '1mb' }); - let publicKeyArmored = body.keytext; + const {keytext: publicKeyArmored} = yield parse.form(ctx, {limit: '1mb'}); if (!publicKeyArmored) { ctx.throw(400, 'Invalid request!'); } - let origin = util.origin(ctx); - yield this._publicKey.put({ publicKeyArmored, origin }); + const origin = util.origin(ctx); + yield this._publicKey.put({publicKeyArmored, origin}); ctx.body = 'Upload successful. Check your inbox to verify your email address.'; ctx.status = 201; } @@ -55,8 +53,8 @@ class HKP { * @param {Object} ctx The koa request/response context */ *lookup(ctx) { - let params = this.parseQueryString(ctx); - let key = yield this._publicKey.get(params); + const params = this.parseQueryString(ctx); + const key = yield this._publicKey.get(params); this.setGetHeaders(ctx, params); this.setGetBody(ctx, params, key); } @@ -68,19 +66,19 @@ class HKP { * @return {Object} The query parameters or undefined for an invalid request */ parseQueryString(ctx) { - let params = { + const params = { op: ctx.query.op, // operation ... only 'get' is supported mr: ctx.query.options === 'mr' // machine readable }; 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.fingerprint = util.isFingerPrint(id) ? id : undefined; } else if (util.isEmail(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!'); } else if (!params.keyId && !params.fingerprint && !params.email) { ctx.throw(501, 'Not implemented!'); @@ -124,21 +122,21 @@ class HKP { setGetBody(ctx, params, key) { if (params.op === 'get') { ctx.body = key.publicKeyArmored; - } else if (['index','vindex'].indexOf(params.op) !== -1) { - const VERSION = 1, COUNT = 1; // number of keys - let fp = key.fingerprint.toUpperCase(); - let algo = (key.algorithm.indexOf('rsa') !== -1) ? 1 : ''; - let created = key.created ? (key.created.getTime() / 1000) : ''; + } else if (['index', 'vindex'].indexOf(params.op) !== -1) { + const VERSION = 1; + const COUNT = 1; // number of keys + const fp = key.fingerprint.toUpperCase(); + const algo = (key.algorithm.indexOf('rsa') !== -1) ? 1 : ''; + const created = key.created ? (key.created.getTime() / 1000) : ''; - ctx.body = 'info:' + VERSION + ':' + COUNT + '\n' + - 'pub:' + fp + ':' + algo + ':' + key.keySize + ':' + created + '::\n'; + ctx.body = `info:${VERSION}:${COUNT}\n` + + `pub:${fp}:${algo}:${key.keySize}:${created}::\n`; - for (let uid of key.userIds) { - ctx.body += 'uid:' + encodeURIComponent(uid.name + ' <' + uid.email + '>') + ':::\n'; + for (const uid of key.userIds) { + ctx.body += `uid:${encodeURIComponent(`${uid.name} <${uid.email}>`)}:::\n`; } } } - } -module.exports = HKP; \ No newline at end of file +module.exports = HKP; diff --git a/src/route/rest.js b/src/route/rest.js index bf60bf3..ae47f29 100644 --- a/src/route/rest.js +++ b/src/route/rest.js @@ -24,7 +24,6 @@ const util = require('../service/util'); * The REST api to provide additional functionality on top of HKP */ class REST { - /** * Create an instance of the REST server * @param {Object} publicKey An instance of the public key service @@ -39,13 +38,12 @@ class REST { * @param {Object} ctx The koa request/response context */ *create(ctx) { - let q = yield parse.json(ctx, { limit: '1mb' }); - let publicKeyArmored = q.publicKeyArmored, primaryEmail = q.primaryEmail; + const {publicKeyArmored, primaryEmail} = yield parse.json(ctx, {limit: '1mb'}); if (!publicKeyArmored || (primaryEmail && !util.isEmail(primaryEmail))) { ctx.throw(400, 'Invalid request!'); } - let origin = util.origin(ctx); - yield this._publicKey.put({ publicKeyArmored, primaryEmail, origin }); + const origin = util.origin(ctx); + yield this._publicKey.put({publicKeyArmored, primaryEmail, origin}); ctx.body = 'Upload successful. Check your inbox to verify your email address.'; ctx.status = 201; } @@ -55,12 +53,12 @@ class REST { * @param {Object} ctx The koa request/response context */ *query(ctx) { - let op = ctx.query.op; + const op = ctx.query.op; if (op === 'verify' || op === 'verifyRemove') { return yield this[op](ctx); // delegate operation } // 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)) { ctx.throw(400, 'Invalid request!'); } @@ -72,13 +70,13 @@ class REST { * @param {Object} ctx The koa request/response context */ *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)) { ctx.throw(400, 'Invalid request!'); } yield this._publicKey.verify(q); // 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 = `

Email address successfully verified!

Link to share your key: ${link}

`; ctx.set('Content-Type', 'text/html; charset=utf-8'); } @@ -88,7 +86,7 @@ class REST { * @param {Object} ctx The koa request/response context */ *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)) { ctx.throw(400, 'Invalid request!'); } @@ -102,14 +100,13 @@ class REST { * @param {Object} ctx The koa request/response context */ *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)) { ctx.throw(400, 'Invalid request!'); } yield this._publicKey.verifyRemove(q); ctx.body = 'Key successfully removed!'; } - } -module.exports = REST; \ No newline at end of file +module.exports = REST; diff --git a/src/service/pgp.js b/src/service/pgp.js index 36dfe62..f7c049a 100644 --- a/src/service/pgp.js +++ b/src/service/pgp.js @@ -29,7 +29,6 @@ const KEY_END = '-----END PGP PUBLIC KEY BLOCK-----'; * A simple wrapper around OpenPGP.js */ class PGP { - /** * Parse an ascii armored pgp key block and get its parameters. * @param {String} publicKeyArmored ascii armored pgp key block @@ -38,9 +37,9 @@ class PGP { parseKey(publicKeyArmored) { publicKeyArmored = this.trimKey(publicKeyArmored); - let r = openpgp.key.readArmored(publicKeyArmored); + const r = openpgp.key.readArmored(publicKeyArmored); 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); util.throw(500, 'Failed to parse PGP key'); } else if (!r.keys || r.keys.length !== 1 || !r.keys[0].primaryKey) { @@ -48,21 +47,21 @@ class PGP { } // verify primary key - let key = r.keys[0]; - let primaryKey = key.primaryKey; + const key = r.keys[0]; + const primaryKey = key.primaryKey; if (key.verifyPrimaryKey() !== openpgp.enums.keyStatus.valid) { util.throw(400, 'Invalid PGP key: primary key verification failed'); } // accept version 4 keys only - let keyId = primaryKey.getKeyId().toHex(); - let fingerprint = primaryKey.fingerprint; + const keyId = primaryKey.getKeyId().toHex(); + const fingerprint = primaryKey.fingerprint; if (!util.isKeyId(keyId) || !util.isFingerPrint(fingerprint)) { util.throw(400, 'Invalid PGP key: only v4 keys are accepted'); } // 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) { 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'); } // at least one user id signature must be valid - let result = []; - for (let user of users) { + const result = []; + for (const user of users) { let oneValid = false; - for (let cert of user.selfCertifications) { + for (const cert of user.selfCertifications) { if (user.isValidSelfCertificate(primaryKey, cert)) { oneValid = true; } } 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)) { result.push(uid); } @@ -139,4 +138,4 @@ class PGP { } } -module.exports = PGP; \ No newline at end of file +module.exports = PGP; diff --git a/src/service/public-key.js b/src/service/public-key.js index f2d9a93..3e567ab 100644 --- a/src/service/public-key.js +++ b/src/service/public-key.js @@ -46,7 +46,6 @@ const DB_TYPE = 'publickey'; * A service that handlers PGP public keys queries to the database */ class PublicKey { - /** * Create an instance of the service * @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' } * @yield {undefined} */ - *put({ publicKeyArmored, primaryEmail, origin }) { + *put({publicKeyArmored, primaryEmail, origin}) { // 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 - let verified = yield this.getVerified(key); + const verified = yield this.getVerified(key); if (verified) { util.throw(304, 'Key for this user already exists'); } @@ -87,13 +86,13 @@ class PublicKey { */ *_persisKey(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 - for (let uid of key.userIds) { + for (const uid of key.userIds) { uid.nonce = util.random(); } // 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) { util.throw(500, 'Failed to persist key'); } @@ -107,17 +106,16 @@ class PublicKey { * @param {Object} origin the server's origin (required for email links) * @yield {undefined} */ - *_sendVerifyEmail(key, primaryEmail, origin) { - let userIds = key.userIds, keyId = key.keyId; + *_sendVerifyEmail({userIds, keyId, publicKeyArmored}, primaryEmail, origin) { // 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) { userIds = [primaryUserId]; } // send emails - for (let userId of userIds) { - userId.publicKeyArmored = key.publicKeyArmored; // set key for encryption - yield this._email.send({ template:tpl.verifyKey, userId, keyId, origin }); + for (const userId of userIds) { + userId.publicKeyArmored = publicKeyArmored; // set key for encryption + 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 * @yield {undefined} */ - *verify({ keyId, nonce }) { + *verify({keyId, nonce}) { // look for verification nonce in database - let query = { keyId, 'userIds.nonce':nonce }; - let key = yield this._mongo.get(query, DB_TYPE); + const query = {keyId, 'userIds.nonce': nonce}; + const key = yield this._mongo.get(query, DB_TYPE); if (!key) { util.throw(404, 'User id not found'); } // check if user ids of this key have already been verified in another key - let verified = yield this.getVerified(key); + const verified = yield this.getVerified(key); if (verified && verified.keyId !== keyId) { util.throw(304, 'Key for this user already exists'); } @@ -155,7 +153,7 @@ class PublicKey { * @param {string} keyId (optional) The public key id * @yield {Object} The verified key document */ - *getVerified({ userIds, fingerprint, keyId }) { + *getVerified({userIds, fingerprint, keyId}) { let queries = []; // query by 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 * @yield {Object} The public key document */ - *get({ fingerprint, keyId, email }) { + *get({fingerprint, keyId, email}) { // look for verified key - let userIds = email ? [{ email:email }] : undefined; - let key = yield this.getVerified({ keyId, fingerprint, userIds }); + const userIds = email ? [{email}] : undefined; + const key = yield this.getVerified({keyId, fingerprint, userIds}); if (!key) { 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' } * @yield {undefined} */ - *requestRemove({ keyId, email, origin }) { + *requestRemove({keyId, email, origin}) { // flag user ids for removal - let key = yield this._flagForRemove(keyId, email); + const key = yield this._flagForRemove(keyId, email); if (!key) { util.throw(404, 'User id not found'); } // send verification mails keyId = key.keyId; // get keyId in case request was by email - for (let userId of key.userIds) { - yield this._email.send({ template:tpl.verifyRemove, userId, keyId, origin }); + for (const userId of key.userIds) { + 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 */ *_flagForRemove(keyId, email) { - let query = email ? { 'userIds.email':email } : { keyId }; - let key = yield this._mongo.get(query, DB_TYPE); + const query = email ? {'userIds.email': email} : {keyId}; + const key = yield this._mongo.get(query, DB_TYPE); if (!key) { return; } // flag only the provided user id if (email) { - let nonce = util.random(); - yield this._mongo.update(query, { 'userIds.$.nonce':nonce }, DB_TYPE); - let uid = key.userIds.find(u => u.email === email); + const nonce = util.random(); + yield this._mongo.update(query, {'userIds.$.nonce': nonce}, DB_TYPE); + const uid = key.userIds.find(u => u.email === email); uid.nonce = nonce; - return { userIds:[uid], keyId:key.keyId }; + return {userIds: [uid], keyId: key.keyId}; } // flag all key user ids if (keyId) { - for (let uid of key.userIds) { - let nonce = util.random(); - yield this._mongo.update({ 'userIds.email':uid.email }, { 'userIds.$.nonce':nonce }, DB_TYPE); + for (const uid of key.userIds) { + const nonce = util.random(); + yield this._mongo.update({'userIds.email': uid.email}, {'userIds.$.nonce': nonce}, DB_TYPE); uid.nonce = nonce; } return key; @@ -272,16 +270,15 @@ class PublicKey { * @param {string} nonce The verification nonce proving email address ownership * @yield {undefined} */ - *verifyRemove({ keyId, nonce }) { + *verifyRemove({keyId, nonce}) { // 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) { util.throw(404, 'User id not found'); } // delete the key - yield this._mongo.remove({ keyId }, DB_TYPE); + yield this._mongo.remove({keyId}, DB_TYPE); } - } -module.exports = PublicKey; \ No newline at end of file +module.exports = PublicKey; diff --git a/src/service/util.js b/src/service/util.js index e15ee20..816cb85 100644 --- a/src/service/util.js +++ b/src/service/util.js @@ -37,7 +37,7 @@ exports.isTrue = function(data) { if (this.isString(data)) { return data === 'true'; } else { - return !!data; + return Boolean(data); } }; @@ -85,7 +85,7 @@ exports.isEmail = function(data) { * @return {Error} The resulting error object */ exports.throw = function(status, message) { - let err = new Error(message); + const err = new Error(message); err.status = status; err.expose = true; // display message to the client throw err; @@ -143,7 +143,7 @@ exports.origin = function(ctx) { * @return {string} The complete url */ exports.url = function(origin, resource) { - return origin.protocol + '://' + origin.host + (resource || ''); + return `${origin.protocol}://${origin.host}${resource || ''}`; }; /** @@ -154,4 +154,4 @@ exports.url = function(origin, resource) { */ exports.hkpUrl = function(ctx) { return (this.checkHTTPS(ctx) ? 'hkps://' : 'hkp://') + ctx.host; -}; \ No newline at end of file +}; diff --git a/src/static/js/demo.js b/src/static/js/demo.js index 2e02a8a..2317515 100644 --- a/src/static/js/demo.js +++ b/src/static/js/demo.js @@ -1,51 +1,53 @@ -;(function($) { +/* eslint strict: 0 */ +/* global jQuery */ + +(function($) { 'use strict'; $('.progress-bar').css('width', '100%'); // POST key form - $('#addKey form').submit(function(e) { + $('#addKey form').submit(e => { e.preventDefault(); $('#addKey .alert').addClass('hidden'); $('#addKey .progress').removeClass('hidden'); $.ajax({ method: 'POST', url: '/api/v1/key', - data: JSON.stringify({ publicKeyArmored:$('#addKey textarea').val() }), + data: JSON.stringify({publicKeyArmored: $('#addKey textarea').val()}), contentType: 'application/json', - }).done(function(data, textStatus, xhr) { + }).done((data, textStatus, xhr) => { if (xhr.status === 304) { alert('addKey', 'danger', 'Key already exists!'); } else { alert('addKey', 'success', xhr.responseText); } }) - .fail(function(xhr) { + .fail(xhr => { alert('addKey', 'danger', xhr.responseText); }); }); // DELETE key form - $('#removeKey form').submit(function(e) { + $('#removeKey form').submit(e => { e.preventDefault(); $('#removeKey .alert').addClass('hidden'); $('#removeKey .progress').removeClass('hidden'); - var email = $('#removeKey input[type="email"]').val(); + const email = $('#removeKey input[type="email"]').val(); $.ajax({ method: 'DELETE', - url: '/api/v1/key?email=' + encodeURIComponent(email) - }).done(function(data, textStatus, xhr) { + url: `/api/v1/key?email=${encodeURIComponent(email)}` + }).done((data, textStatus, xhr) => { alert('removeKey', 'success', xhr.responseText); }) - .fail(function(xhr) { + .fail(xhr => { alert('removeKey', 'danger', xhr.responseText); }); }); function alert(region, outcome, text) { - $('#' + region + ' .progress').addClass('hidden'); - $('#' + region + ' .alert-' + outcome + ' span').text(text); - $('#' + region + ' .alert-' + outcome).removeClass('hidden'); + $(`#${region} .progress`).addClass('hidden'); + $(`#${region} .alert-${outcome} span`).text(text); + $(`#${region} .alert-${outcome}`).removeClass('hidden'); } - -}(jQuery)); \ No newline at end of file +}(jQuery)); diff --git a/test/integration/app-test.js b/test/integration/app-test.js index 7615287..5352278 100644 --- a/test/integration/app-test.js +++ b/test/integration/app-test.js @@ -9,8 +9,11 @@ const fs = require('fs'); describe('Koa App (HTTP Server) Integration Tests', function() { this.timeout(20000); - let app, mongo, - sendEmailStub, publicKeyArmored, emailParams; + let app; + let mongo; + let sendEmailStub; + let publicKeyArmored; + let emailParams; const DB_TYPE_PUB_KEY = 'publickey'; const DB_TYPE_USER_ID = 'userid'; @@ -18,24 +21,22 @@ describe('Koa App (HTTP Server) Integration Tests', function() { const fingerprint = '4277257930867231CE393FB8DBC0B3D92B1B86E9'; before(function *() { - publicKeyArmored = fs.readFileSync(__dirname + '/../key1.asc', 'utf8'); + publicKeyArmored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8'); mongo = new Mongo(); yield mongo.init(config.mongo); - sendEmailStub = sinon.stub().returns(Promise.resolve({ response:'250' })); - sendEmailStub.withArgs(sinon.match(recipient => { - return recipient.to.address === primaryEmail; - }), sinon.match(params => { + sendEmailStub = sinon.stub().returns(Promise.resolve({response: '250'})); + sendEmailStub.withArgs(sinon.match(recipient => recipient.to.address === primaryEmail), sinon.match(params => { emailParams = params; - return !!params.nonce; + return Boolean(params.nonce); })); sinon.stub(nodemailer, 'createTransport').returns({ - templateSender: () => { return sendEmailStub; }, - use: function() {} + templateSender: () => sendEmailStub, + use() {} }); global.testing = true; - let init = require('../../src/app'); + const init = require('../../src/app'); app = yield init(); }); @@ -57,7 +58,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { it('should return 400 for an invalid pgp key', done => { request(app.listen()) .post('/api/v1/key') - .send({ publicKeyArmored:'foo' }) + .send({publicKeyArmored: 'foo'}) .expect(400) .end(done); }); @@ -65,7 +66,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { it('should return 400 for an invalid primaryEmail', done => { request(app.listen()) .post('/api/v1/key') - .send({ publicKeyArmored, primaryEmail:'foo' }) + .send({publicKeyArmored, primaryEmail: 'foo'}) .expect(400) .end(done); }); @@ -73,7 +74,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { it('should return 201 with primaryEmail', done => { request(app.listen()) .post('/api/v1/key') - .send({ publicKeyArmored, primaryEmail }) + .send({publicKeyArmored, primaryEmail}) .expect(201) .end(() => { expect(emailParams).to.exist; @@ -84,7 +85,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { it('should return 201 without primaryEmail', done => { request(app.listen()) .post('/api/v1/key') - .send({ publicKeyArmored }) + .send({publicKeyArmored}) .expect(201) .end(() => { expect(emailParams).to.exist; @@ -97,28 +98,28 @@ describe('Koa App (HTTP Server) Integration Tests', function() { beforeEach(done => { request(app.listen()) .post('/api/v1/key') - .send({ publicKeyArmored, primaryEmail }) + .send({publicKeyArmored, primaryEmail}) .expect(201) .end(done); }); it('should return 200 for valid params', done => { 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) .end(done); }); it('should return 400 for missing keyid and', done => { request(app.listen()) - .get('/api/v1/key?op=verify&nonce=' + emailParams.nonce) + .get(`/api/v1/key?op=verify&nonce=${emailParams.nonce}`) .expect(400) .end(done); }); it('should return 400 for missing nonce', done => { request(app.listen()) - .get('/api/v1/key?op=verify&keyId=' + emailParams.keyId) + .get(`/api/v1/key?op=verify&keyId=${emailParams.keyId}`) .expect(400) .end(done); }); @@ -128,7 +129,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { beforeEach(done => { request(app.listen()) .post('/api/v1/key') - .send({ publicKeyArmored, primaryEmail }) + .send({publicKeyArmored, primaryEmail}) .expect(201) .end(done); }); @@ -136,7 +137,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { describe('Not yet verified', () => { it('should return 404', done => { request(app.listen()) - .get('/api/v1/key?keyId=' + emailParams.keyId) + .get(`/api/v1/key?keyId=${emailParams.keyId}`) .expect(404).end(done); }); }); @@ -144,21 +145,21 @@ describe('Koa App (HTTP Server) Integration Tests', function() { describe('Verified', () => { beforeEach(done => { 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) .end(done); }); it('should return 200 and get key by id', done => { request(app.listen()) - .get('/api/v1/key?keyId=' + emailParams.keyId) + .get(`/api/v1/key?keyId=${emailParams.keyId}`) .expect(200) .end(done); }); it('should return 200 and get key email address', done => { request(app.listen()) - .get('/api/v1/key?email=' + primaryEmail) + .get(`/api/v1/key?email=${primaryEmail}`) .expect(200) .end(done); }); @@ -190,21 +191,21 @@ describe('Koa App (HTTP Server) Integration Tests', function() { beforeEach(done => { request(app.listen()) .post('/api/v1/key') - .send({ publicKeyArmored, primaryEmail }) + .send({publicKeyArmored, primaryEmail}) .expect(201) .end(done); }); it('should return 202 for key id', done => { request(app.listen()) - .del('/api/v1/key?keyId=' + emailParams.keyId) + .del(`/api/v1/key?keyId=${emailParams.keyId}`) .expect(202) .end(done); }); it('should return 202 for email address', done => { request(app.listen()) - .del('/api/v1/key?email=' + primaryEmail) + .del(`/api/v1/key?email=${primaryEmail}`) .expect(202) .end(done); }); @@ -228,11 +229,11 @@ describe('Koa App (HTTP Server) Integration Tests', function() { beforeEach(done => { request(app.listen()) .post('/api/v1/key') - .send({ publicKeyArmored, primaryEmail }) + .send({publicKeyArmored, primaryEmail}) .expect(201) - .end(function() { + .end(() => { request(app.listen()) - .del('/api/v1/key?keyId=' + emailParams.keyId) + .del(`/api/v1/key?keyId=${emailParams.keyId}`) .expect(202) .end(done); }); @@ -240,7 +241,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { it('should return 200 for key id', done => { 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) .end(done); }); @@ -254,7 +255,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { it('should return 404 for unknown key id', done => { 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) .end(done); }); @@ -276,7 +277,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { request(app.listen()) .post('/pks/add') .type('form') - .send('keytext=' + encodeURIComponent(publicKeyArmored)) + .send(`keytext=${encodeURIComponent(publicKeyArmored)}`) .expect(201) .end(done); }); @@ -287,7 +288,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { request(app.listen()) .post('/pks/add') .type('form') - .send('keytext=' + encodeURIComponent(publicKeyArmored)) + .send(`keytext=${encodeURIComponent(publicKeyArmored)}`) .expect(201) .end(done); }); @@ -295,7 +296,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { describe('Not yet verified', () => { it('should return 404', done => { request(app.listen()) - .get('/pks/lookup?op=get&search=0x' + emailParams.keyId) + .get(`/pks/lookup?op=get&search=0x${emailParams.keyId}`) .expect(404) .end(done); }); @@ -304,35 +305,35 @@ describe('Koa App (HTTP Server) Integration Tests', function() { describe('Verified', () => { beforeEach(done => { 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) .end(done); }); it('should return 200 for key id', done => { request(app.listen()) - .get('/pks/lookup?op=get&search=0x' + emailParams.keyId) + .get(`/pks/lookup?op=get&search=0x${emailParams.keyId}`) .expect(200, publicKeyArmored) .end(done); }); it('should return 200 for fingerprint', done => { request(app.listen()) - .get('/pks/lookup?op=get&search=0x' + fingerprint) + .get(`/pks/lookup?op=get&search=0x${fingerprint}`) .expect(200, publicKeyArmored) .end(done); }); it('should return 200 for correct email address', done => { request(app.listen()) - .get('/pks/lookup?op=get&search=' + primaryEmail) + .get(`/pks/lookup?op=get&search=${primaryEmail}`) .expect(200, publicKeyArmored) .end(done); }); it('should return 200 for "mr" option', done => { 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-Disposition', 'attachment; filename=openpgpkey.asc') .expect(200, publicKeyArmored) @@ -341,14 +342,14 @@ describe('Koa App (HTTP Server) Integration Tests', function() { it('should return 200 for "vindex" op', done => { request(app.listen()) - .get('/pks/lookup?op=vindex&search=0x' + emailParams.keyId) + .get(`/pks/lookup?op=vindex&search=0x${emailParams.keyId}`) .expect(200) .end(done); }); it('should return 200 for "index" with "mr" option', done => { 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(200) .end(done); @@ -377,7 +378,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { it('should return 501 for a invalid key id format', done => { request(app.listen()) - .get('/pks/lookup?op=get&search=' + emailParams.keyId) + .get(`/pks/lookup?op=get&search=${emailParams.keyId}`) .expect(501) .end(done); }); @@ -398,12 +399,11 @@ describe('Koa App (HTTP Server) Integration Tests', function() { it('should return 501 (Not implemented) for "x-email" op', done => { 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) .end(done); }); }); }); }); - -}); \ No newline at end of file +}); diff --git a/test/integration/email-test.js b/test/integration/email-test.js index 2b0101b..e414132 100644 --- a/test/integration/email-test.js +++ b/test/integration/email-test.js @@ -7,15 +7,19 @@ const tpl = require('../../src/email/templates.json'); describe('Email Integration Tests', function() { 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() { - publicKeyArmored = require('fs').readFileSync(__dirname + '/../key1.asc', 'utf8'); + before(() => { + publicKeyArmored = require('fs').readFileSync(`${__dirname}/../key1.asc`, 'utf8'); origin = { protocol: 'http', - host: 'localhost:' + config.server.port + host: `localhost:${config.server.port}` }; email = new Email(); email.init(config.email); @@ -33,14 +37,14 @@ describe('Email Integration Tests', function() { describe("_sendHelper", () => { it('should work', function *() { - let mailOptions = { + const mailOptions = { from: email._sender, to: recipient, subject: 'Hello ✔', // Subject line text: 'Hello world 🐴', // plaintext body html: 'Hello world 🐴' // html body }; - let info = yield email._sendHelper(mailOptions); + const info = yield email._sendHelper(mailOptions); expect(info).to.exist; }); }); @@ -48,23 +52,22 @@ describe('Email Integration Tests', function() { describe("send verifyKey template", () => { it('should send plaintext email', function *() { 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 *() { - yield email.send({ template:tpl.verifyKey, userId, keyId, origin }); + yield email.send({template: tpl.verifyKey, userId, keyId, origin}); }); }); describe("send verifyRemove template", () => { it('should send plaintext email', function *() { 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 *() { - yield email.send({ template:tpl.verifyRemove, userId, keyId, origin }); + yield email.send({template: tpl.verifyRemove, userId, keyId, origin}); }); }); - -}); \ No newline at end of file +}); diff --git a/test/integration/mongo-test.js b/test/integration/mongo-test.js index b7254c8..fdc2abd 100644 --- a/test/integration/mongo-test.js +++ b/test/integration/mongo-test.js @@ -25,16 +25,16 @@ describe('Mongo Integration Tests', function() { describe("create", () => { 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); }); 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); try { - r = yield mongo.create({ _id:'0' }, DB_TYPE); - } catch(e) { + r = yield mongo.create({_id: '0'}, DB_TYPE); + } catch (e) { expect(e.message).to.match(/duplicate/); } }); @@ -42,16 +42,16 @@ describe('Mongo Integration Tests', function() { describe("batch", () => { 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); }); 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); try { - r = yield mongo.batch([{ _id:'0' }, { _id:'1' }], DB_TYPE); - } catch(e) { + r = yield mongo.batch([{_id: '0'}, {_id: '1'}], DB_TYPE); + } catch (e) { expect(e.message).to.match(/duplicate/); } }); @@ -59,37 +59,36 @@ describe('Mongo Integration Tests', function() { describe("update", () => { it('should update a document', function *() { - let r = yield mongo.create({ _id:'0' }, DB_TYPE); - r = yield mongo.update({ _id:'0' }, { foo:'bar' }, DB_TYPE); + let r = yield mongo.create({_id: '0'}, DB_TYPE); + r = yield mongo.update({_id: '0'}, {foo: 'bar'}, DB_TYPE); 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'); }); }); describe("get", () => { it('should get a document', function *() { - let r = yield mongo.create({ _id:'0' }, DB_TYPE); - r = yield mongo.get({ _id:'0' }, DB_TYPE); + let r = yield mongo.create({_id: '0'}, DB_TYPE); + r = yield mongo.get({_id: '0'}, DB_TYPE); expect(r).to.exist; }); }); describe("list", () => { it('should list documents', function *() { - let r = yield mongo.batch([{ _id:'0', foo:'bar' }, { _id:'1', foo:'bar' }], DB_TYPE); - r = yield mongo.list({ foo:'bar' }, DB_TYPE); - expect(r).to.deep.equal([{ _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); + expect(r).to.deep.equal([{_id: '0', foo: 'bar'}, {_id: '1', foo: 'bar'}], DB_TYPE); }); }); describe("remove", () => { it('should remove a document', function *() { - let r = yield mongo.create({ _id:'0' }, DB_TYPE); - r = yield mongo.remove({ _id:'0' }, DB_TYPE); - r = yield mongo.get({ _id:'0' }, DB_TYPE); + let r = yield mongo.create({_id: '0'}, DB_TYPE); + r = yield mongo.remove({_id: '0'}, DB_TYPE); + r = yield mongo.get({_id: '0'}, DB_TYPE); expect(r).to.not.exist; }); }); - -}); \ No newline at end of file +}); diff --git a/test/integration/public-key-test.js b/test/integration/public-key-test.js index a682f11..964323a 100644 --- a/test/integration/public-key-test.js +++ b/test/integration/public-key-test.js @@ -10,17 +10,23 @@ const PublicKey = require('../../src/service/public-key'); describe('Public Key Integration Tests', function() { this.timeout(20000); - let publicKey, email, mongo, pgp, - sendEmailStub, publicKeyArmored, publicKeyArmored2, mailsSent; + let publicKey; + let email; + let mongo; + let pgp; + let sendEmailStub; + let publicKeyArmored; + let publicKeyArmored2; + let mailsSent; const DB_TYPE = 'publickey'; const primaryEmail = 'test1@example.com'; const primaryEmail2 = 'test2@example.com'; - const origin = { host:'localhost', protocol:'http' }; + const origin = {host: 'localhost', protocol: 'http'}; before(function *() { - publicKeyArmored = require('fs').readFileSync(__dirname + '/../key3.asc', 'utf8'); - publicKeyArmored2 = require('fs').readFileSync(__dirname + '/../key4.asc', 'utf8'); + publicKeyArmored = require('fs').readFileSync(`${__dirname}/../key3.asc`, 'utf8'); + publicKeyArmored2 = require('fs').readFileSync(`${__dirname}/../key4.asc`, 'utf8'); mongo = new Mongo(); yield mongo.init(config.mongo); }); @@ -28,9 +34,9 @@ describe('Public Key Integration Tests', function() { beforeEach(function *() { yield mongo.clear(DB_TYPE); mailsSent = []; - sendEmailStub = sinon.stub().returns(Promise.resolve({ response:'250' })); + sendEmailStub = sinon.stub().returns(Promise.resolve({response: '250'})); sendEmailStub.withArgs(sinon.match(recipient => { - mailsSent[mailsSent.length] = {to:recipient.to.address}; + mailsSent[mailsSent.length] = {to: recipient.to.address}; return true; }), sinon.match(params => { mailsSent[mailsSent.length - 1].params = params; @@ -39,13 +45,13 @@ describe('Public Key Integration Tests', function() { return true; })); sinon.stub(nodemailer, 'createTransport').returns({ - templateSender: () => { return sendEmailStub; } + templateSender: () => sendEmailStub }); email = new Email(nodemailer); email.init({ host: 'localhost', - auth: { user:'user', pass:'pass' }, - sender: { name:'Foo Bar', email:'foo@bar.com' } + auth: {user: 'user', pass: 'pass'}, + sender: {name: 'Foo Bar', email: 'foo@bar.com'} }); pgp = new PGP(); publicKey = new PublicKey(pgp, mongo, email); @@ -62,31 +68,31 @@ describe('Public Key Integration Tests', function() { describe('put', () => { 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[0].to).to.equal(primaryEmail); expect(mailsSent[0].params.keyId).to.exist; expect(mailsSent[0].params.nonce).to.exist; }); it('should persist key and send verification email without primaryEmail', function *() { - yield publicKey.put({ publicKeyArmored, origin }); + yield publicKey.put({publicKeyArmored, origin}); expect(mailsSent.length).to.equal(4); }); it('should work twice if not yet verified', function *() { - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(mailsSent.length).to.equal(1); - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(mailsSent.length).to.equal(2); }); it('should throw 304 if key already exists', function *() { - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); yield publicKey.verify(mailsSent[0].params); try { - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); expect(false).to.be.true; - } catch(e) { + } catch (e) { expect(e.status).to.equal(304); } }); @@ -94,10 +100,10 @@ describe('Public Key Integration Tests', function() { describe('verify', () => { it('should update the document', function *() { - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); - let emailParams = mailsSent[0].params; + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + const emailParams = mailsSent[0].params; 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].nonce).to.be.null; 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 *() { - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); - let emailParams = mailsSent[0].params; + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); + const emailParams = mailsSent[0].params; try { - yield publicKey.verify({ keyId:emailParams.keyId, nonce:'fake_nonce' }); + yield publicKey.verify({keyId: emailParams.keyId, nonce: 'fake_nonce'}); expect(true).to.be.false; - } catch(e) { + } catch (e) { 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].nonce).to.equal(emailParams.nonce); 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 *() { - yield publicKey.put({ publicKeyArmored, primaryEmail:primaryEmail2, origin }); + yield publicKey.put({publicKeyArmored, primaryEmail: primaryEmail2, origin}); 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); yield publicKey.verify(mailsSent[1].params); try { yield publicKey.verify(mailsSent[0].params); expect(true).to.be.false; - } catch(e) { + } catch (e) { 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].verified).to.be.false; expect(gotten.userIds[1].nonce).to.equal(mailsSent[0].params.nonce); }); it('should be able to verify multiple user ids', function *() { - yield publicKey.put({ publicKeyArmored, origin }); + yield publicKey.put({publicKeyArmored, origin}); expect(mailsSent.length).to.equal(4); yield publicKey.verify(mailsSent[0].params); yield publicKey.verify(mailsSent[1].params); yield publicKey.verify(mailsSent[2].params); yield publicKey.verify(mailsSent[3].params); - 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[1].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', () => { beforeEach(function *() { key = pgp.parseKey(publicKeyArmored); - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); yield publicKey.verify(mailsSent[0].params); }); it('by fingerprint', function *() { - let verified = yield publicKey.getVerified({ fingerprint:key.fingerprint }); + const verified = yield publicKey.getVerified({fingerprint: key.fingerprint}); expect(verified).to.exist; }); 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; }); 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; }); 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; }); it('by keyId', function *() { - let verified = yield publicKey.getVerified({ keyId:key.keyId }); + const verified = yield publicKey.getVerified({keyId: key.keyId}); expect(verified).to.exist; }); it('by all params', function *() { - let verified = yield publicKey.getVerified(key); + const verified = yield publicKey.getVerified(key); expect(verified).to.exist; }); }); @@ -203,22 +209,22 @@ describe('Public Key Integration Tests', 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; }); 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; }); 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; }); it('by all params', function *() { - let verified = yield publicKey.getVerified(key); + const verified = yield publicKey.getVerified(key); expect(verified).to.not.exist; }); }); @@ -228,53 +234,53 @@ describe('Public Key Integration Tests', function() { let emailParams; beforeEach(function *() { - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); emailParams = mailsSent[0].params; }); it('should return verified key by key id', function *() { 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; }); it('should return verified key by key id (uppercase)', function *() { 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; }); it('should return verified key by fingerprint', function *() { yield publicKey.verify(emailParams); - let fingerprint = pgp.parseKey(publicKeyArmored).fingerprint; - let key = yield publicKey.get({ fingerprint }); + const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint; + const key = yield publicKey.get({fingerprint}); expect(key.publicKeyArmored).to.exist; }); it('should return verified key by fingerprint (uppercase)', function *() { yield publicKey.verify(emailParams); - let fingerprint = pgp.parseKey(publicKeyArmored).fingerprint.toUpperCase(); - let key = yield publicKey.get({ fingerprint }); + const fingerprint = pgp.parseKey(publicKeyArmored).fingerprint.toUpperCase(); + const key = yield publicKey.get({fingerprint}); expect(key.publicKeyArmored).to.exist; }); it('should return verified key by email address', function *() { yield publicKey.verify(emailParams); - let key = yield publicKey.get({ email:primaryEmail }); + const key = yield publicKey.get({email: primaryEmail}); expect(key.publicKeyArmored).to.exist; }); it('should return verified key by email address (uppercase)', function *() { 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; }); it('should throw 404 for unverified key', function *() { try { - yield publicKey.get({ keyId:emailParams.keyId }); + yield publicKey.get({keyId: emailParams.keyId}); expect(false).to.be.true; - } catch(e) { + } catch (e) { expect(e.status).to.equal(404); } }); @@ -284,32 +290,32 @@ describe('Public Key Integration Tests', function() { let keyId; beforeEach(function *() { - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); keyId = mailsSent[0].params.keyId; }); it('should work for verified key', function *() { yield publicKey.verify(mailsSent[0].params); - yield publicKey.requestRemove({ keyId, origin }); + yield publicKey.requestRemove({keyId, origin}); expect(mailsSent.length).to.equal(5); }); it('should work for unverified key', function *() { - yield publicKey.requestRemove({ keyId, origin }); + yield publicKey.requestRemove({keyId, origin}); expect(mailsSent.length).to.equal(5); }); 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); }); it('should throw 404 for no key', function *() { - yield mongo.remove({ keyId }, DB_TYPE); + yield mongo.remove({keyId}, DB_TYPE); try { - yield publicKey.requestRemove({ keyId, origin }); + yield publicKey.requestRemove({keyId, origin}); expect(false).to.be.true; - } catch(e) { + } catch (e) { expect(e.status).to.equal(404); } }); @@ -319,26 +325,25 @@ describe('Public Key Integration Tests', function() { let keyId; beforeEach(function *() { - yield publicKey.put({ publicKeyArmored, primaryEmail, origin }); + yield publicKey.put({publicKeyArmored, primaryEmail, origin}); keyId = mailsSent[0].params.keyId; - yield publicKey.requestRemove({ keyId, origin }); + yield publicKey.requestRemove({keyId, origin}); }); it('should remove key', function *() { 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; }); it('should throw 404 for no key', function *() { - yield mongo.remove({ keyId }, DB_TYPE); + yield mongo.remove({keyId}, DB_TYPE); try { yield publicKey.verifyRemove(mailsSent[1].params); expect(false).to.be.true; - } catch(e) { + } catch (e) { expect(e.status).to.equal(404); } }); }); - -}); \ No newline at end of file +}); diff --git a/test/unit/email-test.js b/test/unit/email-test.js index 5905787..7c14b6b 100644 --- a/test/unit/email-test.js +++ b/test/unit/email-test.js @@ -5,28 +5,29 @@ const Email = require('../../src/email/email'); const nodemailer = require('nodemailer'); describe('Email Unit Tests', () => { - let email, sendFnStub; + let email; + let sendFnStub; - let template = { + const template = { subject: 'foo', text: 'bar', html: 'bar' }; - let sender = { + const sender = { name: 'Foo Bar', email: 'foo@bar.com' }; - let userId1 = { + const userId1 = { name: 'name1', email: 'email1', nonce: 'qwertzuioasdfghjkqwertzuio' }; - let keyId = '0123456789ABCDF0'; - let origin = { + const keyId = '0123456789ABCDF0'; + const origin = { protocol: 'http', host: 'localhost:8888' }; - let mailOptions = { + const mailOptions = { from: sender, to: sender, subject: 'Hello ✔', // Subject line @@ -37,7 +38,7 @@ describe('Email Unit Tests', () => { beforeEach(() => { sendFnStub = sinon.stub(); sinon.stub(nodemailer, 'createTransport').returns({ - templateSender: () => { return sendFnStub; } + templateSender: () => sendFnStub }); sinon.stub(log, 'warn'); @@ -46,8 +47,8 @@ describe('Email Unit Tests', () => { email = new Email(nodemailer); email.init({ host: 'host', - auth: { user:'user', pass:'pass' }, - sender: sender + auth: {user: 'user', pass: 'pass'}, + sender }); expect(email._sender).to.equal(sender); }); @@ -60,7 +61,7 @@ describe('Email Unit Tests', () => { describe("send", () => { beforeEach(() => { - sinon.stub(email, '_sendHelper').returns(Promise.resolve({ response:'250' })); + sinon.stub(email, '_sendHelper').returns(Promise.resolve({response: '250'})); }); afterEach(() => { @@ -68,7 +69,7 @@ describe('Email Unit Tests', () => { }); 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/); }); @@ -76,17 +77,17 @@ describe('Email Unit Tests', () => { describe("_sendHelper", () => { 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/); }); 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(log.warn.calledOnce).to.be.true; @@ -97,12 +98,11 @@ describe('Email Unit Tests', () => { try { yield email._sendHelper(mailOptions); - } catch(e) { + } catch (e) { expect(log.error.calledOnce).to.be.true; expect(e.status).to.equal(500); expect(e.message).to.match(/failed/); } }); }); - -}); \ No newline at end of file +}); diff --git a/test/unit/pgp-test.js b/test/unit/pgp-test.js index e56a5e3..455e273 100644 --- a/test/unit/pgp-test.js +++ b/test/unit/pgp-test.js @@ -6,18 +6,21 @@ const openpgp = require('openpgp'); const PGP = require('../../src/service/pgp'); describe('PGP Unit Tests', () => { - let pgp, key1Armored, key2Armored, key3Armored; + let pgp; + let key1Armored; + let key2Armored; + let key3Armored; beforeEach(() => { - key1Armored = fs.readFileSync(__dirname + '/../key1.asc', 'utf8'); - key2Armored = fs.readFileSync(__dirname + '/../key2.asc', 'utf8'); - key3Armored = fs.readFileSync(__dirname + '/../key3.asc', 'utf8'); + key1Armored = fs.readFileSync(`${__dirname}/../key1.asc`, 'utf8'); + key2Armored = fs.readFileSync(`${__dirname}/../key2.asc`, 'utf8'); + key3Armored = fs.readFileSync(`${__dirname}/../key3.asc`, 'utf8'); pgp = new PGP(); }); describe('parseKey', () => { 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'); expect(pgp.parseKey.bind(pgp, key3Armored)).to.throw(/Failed to parse/); 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', () => { - 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/); readStub.restore(); }); 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: [{ primaryKey: {}, - verifyPrimaryKey: function() { return false; } + verifyPrimaryKey() { return false; } }] }); 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', () => { - let readStub = sinon.stub(openpgp.key, 'readArmored').returns({ + const readStub = sinon.stub(openpgp.key, 'readArmored').returns({ keys: [{ primaryKey: { fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e9', - getKeyId: function() { + getKeyId() { 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/); @@ -61,17 +64,17 @@ describe('PGP Unit Tests', () => { }); it('should only accept version 4 fingerprint', () => { - let readStub = sinon.stub(openpgp.key, 'readArmored').returns({ + const readStub = sinon.stub(openpgp.key, 'readArmored').returns({ keys: [{ primaryKey: { fingerprint: '4277257930867231ce393fb8dbc0b3d92b1b86e', - getKeyId: function() { + getKeyId() { 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/); @@ -84,7 +87,7 @@ describe('PGP Unit Tests', () => { }); 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.fingerprint).to.equal('4277257930867231ce393fb8dbc0b3d92b1b86e9'); 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', () => { - let params = pgp.parseKey(key2Armored); + const params = pgp.parseKey(key2Armored); expect(params.keyId).to.equal('b8e4105cc9dedc77'); expect(params.fingerprint).to.equal('e3317db04d3958fd5f662c37b8e4105cc9dedc77'); expect(params.userIds.length).to.equal(1); @@ -107,7 +110,7 @@ describe('PGP Unit Tests', () => { }); 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.fingerprint).to.equal('04062c70b446e33016e219a74001a127a90de8e1'); expect(params.userIds.length).to.equal(4); @@ -120,12 +123,12 @@ describe('PGP Unit Tests', () => { describe('trimKey', () => { it('should be the same as key1', () => { - let trimmed = pgp.trimKey(key1Armored); + const trimmed = pgp.trimKey(key1Armored); expect(trimmed).to.equal(key1Armored); }); it('should not be the same as key2', () => { - let trimmed = pgp.trimKey(key2Armored); + const trimmed = pgp.trimKey(key2Armored); expect(trimmed).to.not.equal(key2Armored); }); }); @@ -135,22 +138,22 @@ describe('PGP Unit Tests', () => { const KEY_END = '-----END PGP PUBLIC 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; }); 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; }); it('should return false for invalid key block', () => { - let input = KEY_END; + const input = KEY_END; expect(pgp.validateKeyBlock(input)).to.be.false; }); it('should return false for invalid key block', () => { - let input = KEY_BEGIN; + const input = KEY_BEGIN; expect(pgp.validateKeyBlock(input)).to.be.false; }); }); @@ -163,7 +166,7 @@ describe('PGP Unit Tests', () => { }); 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].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', () => { 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); }); 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 '; - let parsed = pgp.parseUserIds(key.users, key.primaryKey); + const parsed = pgp.parseUserIds(key.users, key.primaryKey); expect(parsed.length).to.equal(0); verifyStub.restore(); }); }); - -}); \ No newline at end of file +}); diff --git a/test/unit/util-test.js b/test/unit/util-test.js index 7f989d7..f1d2c22 100644 --- a/test/unit/util-test.js +++ b/test/unit/util-test.js @@ -116,7 +116,7 @@ describe('Util Unit Tests', () => { try { util.throw(500, 'boom'); expect(true).to.be.false; - } catch(e) { + } catch (e) { expect(e.message).to.equal('boom'); expect(e.status).to.equal(500); expect(e.expose).to.be.true; @@ -136,20 +136,19 @@ describe('Util Unit Tests', () => { describe('origin', () => { 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', () => { 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'); }); 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'); }); }); - -}); \ No newline at end of file +}); From d8039ea97683cce480f8b74ef967126c25964b04 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Tue, 15 Aug 2017 16:12:51 +0800 Subject: [PATCH 3/7] Stub npmlog in integration tests --- test/integration/app-test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/integration/app-test.js b/test/integration/app-test.js index 5352278..756e85c 100644 --- a/test/integration/app-test.js +++ b/test/integration/app-test.js @@ -5,6 +5,7 @@ const Mongo = require('../../src/dao/mongo'); const nodemailer = require('nodemailer'); const config = require('config'); const fs = require('fs'); +const log = require('npmlog'); describe('Koa App (HTTP Server) Integration Tests', function() { this.timeout(20000); @@ -35,6 +36,8 @@ describe('Koa App (HTTP Server) Integration Tests', function() { use() {} }); + sinon.stub(log); + global.testing = true; const init = require('../../src/app'); app = yield init(); @@ -47,6 +50,7 @@ describe('Koa App (HTTP Server) Integration Tests', function() { }); after(function *() { + sinon.restore(log); nodemailer.createTransport.restore(); yield mongo.clear(DB_TYPE_PUB_KEY); yield mongo.clear(DB_TYPE_USER_ID); From 80a8028f8621aea790593acf4d606f50530616c0 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Tue, 15 Aug 2017 16:14:21 +0800 Subject: [PATCH 4/7] Remove jshint and jscs configs --- .jscsrc | 4 ---- .jshintrc | 28 ---------------------------- 2 files changed, 32 deletions(-) delete mode 100644 .jscsrc delete mode 100644 .jshintrc diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index 7d15b2b..0000000 --- a/.jscsrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "disallowTrailingWhitespace": true, - "validateIndentation": 2 -} \ No newline at end of file diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 598d3c1..0000000 --- a/.jshintrc +++ /dev/null @@ -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 - } -} \ No newline at end of file From c773da3f604a6a623e22fc274d6319041aeb982a Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Tue, 15 Aug 2017 16:19:31 +0800 Subject: [PATCH 5/7] Fix config/development.js --- config/development.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/development.js b/config/development.js index dda452d..4e28b5d 100644 --- a/config/development.js +++ b/config/development.js @@ -1,3 +1,5 @@ +'use strict'; + module.exports = { mongo: { @@ -22,4 +24,4 @@ module.exports = { } } -}; \ No newline at end of file +}; From 21118c0b1df0644978ce3374be732f0f2c02fd66 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Tue, 15 Aug 2017 16:27:12 +0800 Subject: [PATCH 6/7] Fix string in hkp --- src/route/hkp.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/route/hkp.js b/src/route/hkp.js index 15372a3..5bd1f4a 100644 --- a/src/route/hkp.js +++ b/src/route/hkp.js @@ -129,8 +129,7 @@ class HKP { const algo = (key.algorithm.indexOf('rsa') !== -1) ? 1 : ''; const created = key.created ? (key.created.getTime() / 1000) : ''; - ctx.body = `info:${VERSION}:${COUNT}\n` + - `pub:${fp}:${algo}:${key.keySize}:${created}::\n`; + ctx.body = `info:${VERSION}:${COUNT}\npub:${fp}:${algo}:${key.keySize}:${created}::\n`; for (const uid of key.userIds) { ctx.body += `uid:${encodeURIComponent(`${uid.name} <${uid.email}>`)}:::\n`; From 20593a0adc34ad1dd2a9c1191f60b3642b1e58fb Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Tue, 15 Aug 2017 16:32:50 +0800 Subject: [PATCH 7/7] Revert static/demo.js since it is not transpiled --- src/static/js/demo.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/static/js/demo.js b/src/static/js/demo.js index 2317515..923e9d2 100644 --- a/src/static/js/demo.js +++ b/src/static/js/demo.js @@ -1,53 +1,53 @@ -/* eslint strict: 0 */ -/* global jQuery */ +/* eslint-disable */ -(function($) { +;(function($) { 'use strict'; $('.progress-bar').css('width', '100%'); // POST key form - $('#addKey form').submit(e => { + $('#addKey form').submit(function(e) { e.preventDefault(); $('#addKey .alert').addClass('hidden'); $('#addKey .progress').removeClass('hidden'); $.ajax({ method: 'POST', url: '/api/v1/key', - data: JSON.stringify({publicKeyArmored: $('#addKey textarea').val()}), + data: JSON.stringify({ publicKeyArmored:$('#addKey textarea').val() }), contentType: 'application/json', - }).done((data, textStatus, xhr) => { + }).done(function(data, textStatus, xhr) { if (xhr.status === 304) { alert('addKey', 'danger', 'Key already exists!'); } else { alert('addKey', 'success', xhr.responseText); } }) - .fail(xhr => { + .fail(function(xhr) { alert('addKey', 'danger', xhr.responseText); }); }); // DELETE key form - $('#removeKey form').submit(e => { + $('#removeKey form').submit(function(e) { e.preventDefault(); $('#removeKey .alert').addClass('hidden'); $('#removeKey .progress').removeClass('hidden'); - const email = $('#removeKey input[type="email"]').val(); + var email = $('#removeKey input[type="email"]').val(); $.ajax({ method: 'DELETE', - url: `/api/v1/key?email=${encodeURIComponent(email)}` - }).done((data, textStatus, xhr) => { + url: '/api/v1/key?email=' + encodeURIComponent(email) + }).done(function(data, textStatus, xhr) { alert('removeKey', 'success', xhr.responseText); }) - .fail(xhr => { + .fail(function(xhr) { alert('removeKey', 'danger', xhr.responseText); }); }); function alert(region, outcome, text) { - $(`#${region} .progress`).addClass('hidden'); - $(`#${region} .alert-${outcome} span`).text(text); - $(`#${region} .alert-${outcome}`).removeClass('hidden'); + $('#' + region + ' .progress').addClass('hidden'); + $('#' + region + ' .alert-' + outcome + ' span').text(text); + $('#' + region + ' .alert-' + outcome).removeClass('hidden'); } -}(jQuery)); + +}(jQuery)); \ No newline at end of file