Update dependencies, fix package conflicts, add packages (ejs, email-templates)

This commit is contained in:
webwitcher 2019-02-07 13:53:49 +01:00 committed by Martin Hauck
parent 0baf3fc857
commit a2b941b0ae
No known key found for this signature in database
GPG Key ID: 16A77ADCADE027B1
10 changed files with 55 additions and 31 deletions

View File

@ -21,22 +21,24 @@
}, },
"dependencies": { "dependencies": {
"addressparser": "^1.0.1", "addressparser": "^1.0.1",
"co-body": "^5.1.1", "co-body": "^6.0.0",
"config": "^1.20.4", "config": "^3.0.1",
"ejs": "^2.6.1",
"email-templates": "^5.0.3",
"koa": "^2.3.0", "koa": "^2.3.0",
"koa-router": "^7.2.1", "koa-router": "^7.2.1",
"koa-static": "^4.0.1", "koa-static": "^5.0.0",
"mongodb": "^2.2.31", "mongodb": "^3.1.13",
"nodemailer": "^4.0.1", "nodemailer": "^5.1.1",
"openpgp": "^2.3.0", "openpgp": "^4.4.6",
"winston": "^2.3.1", "winston": "^3.2.1",
"winston-papertrail": "^1.0.5" "winston-papertrail": "^1.0.5"
}, },
"devDependencies": { "devDependencies": {
"chai": "^4.1.1", "chai": "^4.1.1",
"eslint": "^4.4.1", "eslint": "^5.13.0",
"mocha": "^3.2.0", "mocha": "^5.2.0",
"sinon": "^1.17.4", "sinon": "^7.2.3",
"supertest": "^3.0.0" "supertest": "^3.0.0"
}, },
"greenkeeper": { "greenkeeper": {

View File

@ -34,7 +34,8 @@ class Mongo {
async init({uri, user, pass}) { async init({uri, user, pass}) {
log.info('mongo', 'Connecting to MongoDB ...'); log.info('mongo', 'Connecting to MongoDB ...');
const url = `mongodb://${user}:${pass}@${uri}`; const url = `mongodb://${user}:${pass}@${uri}`;
this._db = await MongoClient.connect(url); const client = await MongoClient.connect(url, {useNewUrlParser: true});
this._db = client.db();
} }
/** /**

View File

@ -18,19 +18,36 @@
'use strict'; 'use strict';
const log = require('winston'); const log = require('winston');
const {SPLAT} = require('triple-beam');
const config = require('config'); const config = require('config');
require('winston-papertrail'); require('winston-papertrail');
log.exitOnError = false; log.exitOnError = false;
log.level = config.log.level; log.level = config.log.level;
// Reformat logging text, due to deprecated logger usage
const formatLogs = log.format(info => {
info.message = `${info.message} -> ${info[SPLAT].join(', ')}`;
return info;
});
exports.init = function({host, port}) { exports.init = function({host, port}) {
if (!host || !port) { if (!host || !port) {
if (process.env.NODE_ENV !== 'production') {
log.add(new log.transports.Console({
format: log.format.combine(
formatLogs(),
log.format.simple()
)
}));
}
return; return;
} }
log.add(log.transports.Papertrail, { log.add(new log.transports.Papertrail({
format: formatLogs(),
level: config.log.level, level: config.log.level,
host, host,
port port
}); }));
}; };

View File

@ -37,7 +37,7 @@ class Email {
* @param {boolean} pgp (optional) if outgoing emails are encrypted to the user's public key. * @param {boolean} pgp (optional) if outgoing emails are encrypted to the user's public key.
*/ */
init({host, port = 465, auth, tls, starttls, pgp, sender}) { init({host, port = 465, auth, tls, starttls, pgp, sender}) {
this._transport = nodemailer.createTransport({ const transporter = nodemailer.createTransport({
host, host,
port, port,
auth, auth,

View File

@ -0,0 +1,2 @@
<p>Hello <%= name %>,</p>
<p>please <a href="<%= `${baseUrl}/api/v1/key?op=verify&keyId=${keyId}&nonce=${nonce}` %>">click here to verify</a> your key.</p>

View File

@ -0,0 +1 @@
Verify Your Key

View File

@ -0,0 +1,2 @@
<p>Hello <%= name %>,</p>
<p>please <a href="<%= `${baseUrl}/api/v1/key?op=verifyRemove&keyId=${keyId}&nonce=${nonce}` %>">click here to verify</a> the removal of your key.</p>

View File

@ -0,0 +1 @@
Verify Key Removal

View File

@ -34,10 +34,10 @@ class PGP {
* @param {String} publicKeyArmored ascii armored pgp key block * @param {String} publicKeyArmored ascii armored pgp key block
* @return {Object} public key document to persist * @return {Object} public key document to persist
*/ */
parseKey(publicKeyArmored) { async parseKey(publicKeyArmored) {
publicKeyArmored = this.trimKey(publicKeyArmored); publicKeyArmored = this.trimKey(publicKeyArmored);
const r = openpgp.key.readArmored(publicKeyArmored); const r = await openpgp.key.readArmored(publicKeyArmored);
if (r.err) { if (r.err) {
const error = r.err[0]; const error = r.err[0];
log.error('pgp', 'Failed to parse PGP key:\n%s', publicKeyArmored, error); log.error('pgp', 'Failed to parse PGP key:\n%s', publicKeyArmored, error);
@ -49,23 +49,26 @@ class PGP {
// verify primary key // verify primary key
const key = r.keys[0]; const key = r.keys[0];
const primaryKey = key.primaryKey; const primaryKey = key.primaryKey;
if (key.verifyPrimaryKey() !== openpgp.enums.keyStatus.valid) { if (await key.verifyPrimaryKey() !== openpgp.enums.keyStatus.valid) {
util.throw(400, 'Invalid PGP key: primary key verification failed'); util.throw(400, 'Invalid PGP key: primary key verification failed');
} }
// accept version 4 keys only // accept version 4 keys only
const keyId = primaryKey.getKeyId().toHex(); const keyId = primaryKey.getKeyId().toHex();
const fingerprint = primaryKey.fingerprint; const fingerprint = primaryKey.getFingerprint();
if (!util.isKeyId(keyId) || !util.isFingerPrint(fingerprint)) { if (!util.isKeyId(keyId) || !util.isFingerPrint(fingerprint)) {
util.throw(400, 'Invalid PGP key: only v4 keys are accepted'); util.throw(400, 'Invalid PGP key: only v4 keys are accepted');
} }
// check for at least one valid user id // check for at least one valid user id
const userIds = this.parseUserIds(key.users, primaryKey); const userIds = await this.parseUserIds(key.users, primaryKey);
if (!userIds.length) { if (!userIds.length) {
util.throw(400, 'Invalid PGP key: invalid user ids'); util.throw(400, 'Invalid PGP key: invalid user ids');
} }
// get algorithm details from primary key
const keyInfo = key.primaryKey.getAlgorithmInfo();
// public key document that is stored in the database // public key document that is stored in the database
return { return {
keyId, keyId,
@ -73,8 +76,8 @@ class PGP {
userIds, userIds,
created: primaryKey.created, created: primaryKey.created,
uploaded: new Date(), uploaded: new Date(),
algorithm: primaryKey.algorithm, algorithm: keyInfo.algorithm,
keySize: primaryKey.getBitSize(), keySize: keyInfo.bits,
publicKeyArmored publicKeyArmored
}; };
} }
@ -110,20 +113,15 @@ class PGP {
* @param {Array} users A list of openpgp.js user objects * @param {Array} users A list of openpgp.js user objects
* @return {Array} An array of user id objects * @return {Array} An array of user id objects
*/ */
parseUserIds(users, primaryKey) { async parseUserIds(users, primaryKey) {
if (!users || !users.length) { if (!users || !users.length) {
util.throw(400, 'Invalid PGP key: no user id found'); util.throw(400, 'Invalid PGP key: no user id found');
} }
// at least one user id signature must be valid // at least one user id must be valid, revoked or expired
const result = []; const result = [];
for (const user of users) { for (const user of users) {
let oneValid = false; const userStatus = await user.verify(primaryKey);
for (const cert of user.selfCertifications) { if (userStatus !== openpgp.enums.keyStatus.invalid && user.userId && user.userId.userid) {
if (user.isValidSelfCertificate(primaryKey, cert)) {
oneValid = true;
}
}
if (oneValid && user.userId && user.userId.userid) {
const uid = addressparser(user.userId.userid)[0]; const uid = addressparser(user.userId.userid)[0];
if (util.isEmail(uid.address)) { if (util.isEmail(uid.address)) {
result.push(uid); result.push(uid);

View File

@ -70,7 +70,7 @@ class PublicKey {
// lazily purge old/unverified keys on every key upload // lazily purge old/unverified keys on every key upload
await this._purgeOldUnverified(); await this._purgeOldUnverified();
// parse key block // parse key block
const key = this._pgp.parseKey(publicKeyArmored); const key = await this._pgp.parseKey(publicKeyArmored);
// check for existing verified key with same id // check for existing verified key with same id
const verified = await this.getVerified({keyId: key.keyId}); const verified = await this.getVerified({keyId: key.keyId});
if (verified) { if (verified) {