Fix eslint errors
This commit is contained in:
19
src/app.js
19
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;
|
||||
module.exports = init;
|
||||
|
||||
@@ -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;
|
||||
module.exports = Mongo;
|
||||
|
||||
@@ -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;
|
||||
module.exports = Email;
|
||||
|
||||
@@ -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;
|
||||
module.exports = HKP;
|
||||
|
||||
@@ -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 = `<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');
|
||||
}
|
||||
@@ -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;
|
||||
module.exports = REST;
|
||||
|
||||
@@ -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;
|
||||
module.exports = PGP;
|
||||
|
||||
@@ -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;
|
||||
module.exports = PublicKey;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
}(jQuery));
|
||||
|
||||
Reference in New Issue
Block a user