Localize verification messages with koa-locales
This commit is contained in:
@@ -18,18 +18,20 @@
|
||||
'use strict';
|
||||
|
||||
const Koa = require('koa');
|
||||
const config = require('config');
|
||||
const serve = require('koa-static');
|
||||
const router = require('koa-router')();
|
||||
const locales = require('koa-locales');
|
||||
const config = require('config');
|
||||
const middleware = require('./middleware');
|
||||
const Mongo = require('../dao/mongo');
|
||||
const Email = require('../email/email');
|
||||
const PGP = require('../service/pgp');
|
||||
const PublicKey = require('../service/public-key');
|
||||
const HKP = require('../route/hkp');
|
||||
const REST = require('../route/rest');
|
||||
const PGP = require('../service/pgp');
|
||||
const PublicKey = require('../service/public-key');
|
||||
|
||||
const app = new Koa();
|
||||
locales(app);
|
||||
|
||||
let hkp;
|
||||
let rest;
|
||||
|
||||
@@ -58,10 +58,9 @@ class Email {
|
||||
*/
|
||||
async send({template, userId, keyId, origin, publicKeyArmored}) {
|
||||
const compiled = template({
|
||||
name: userId.name,
|
||||
baseUrl: util.url(origin),
|
||||
keyId,
|
||||
nonce: userId.nonce
|
||||
...userId,
|
||||
origin,
|
||||
keyId
|
||||
});
|
||||
if (this._usePGPEncryption && publicKeyArmored) {
|
||||
compiled.text = await this._pgpEncrypt(compiled.text, publicKeyArmored);
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
exports.verifyKey = ({name, baseUrl, keyId, nonce}) => ({
|
||||
subject: 'Verify Your Key',
|
||||
text: `Hello ${name},\n\nplease click here to verify your email address:\n\n${baseUrl}/api/v1/key?op=verify&keyId=${keyId}&nonce=${nonce}`,
|
||||
});
|
||||
const util = require('../service/util');
|
||||
|
||||
exports.verifyRemove = ({name, baseUrl, keyId, nonce}) => ({
|
||||
subject: 'Verify Key Removal',
|
||||
text: `Hello ${name},\n\nplease click here to verify the removal of your email address:\n\n${baseUrl}/api/v1/key?op=verifyRemove&keyId=${keyId}&nonce=${nonce}`,
|
||||
});
|
||||
function verifyKey(ctx, {name, email, nonce, origin, keyId}) {
|
||||
const link = `${util.url(origin)}/api/v1/key?op=verify&keyId=${keyId}&nonce=${nonce}`;
|
||||
return {
|
||||
subject: ctx.__('verify_key_subject'),
|
||||
text: ctx.__('verify_key_text', [name, email, link, origin.host])
|
||||
};
|
||||
}
|
||||
|
||||
function verifyRemove(ctx, {name, email, nonce, origin, keyId}) {
|
||||
const link = `${util.url(origin)}/api/v1/key?op=verifyRemove&keyId=${keyId}&nonce=${nonce}`;
|
||||
return {
|
||||
subject: ctx.__('verify_removal_subject'),
|
||||
text: ctx.__('verify_removal_text', [name, email, origin.host, link])
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {verifyKey, verifyRemove};
|
||||
|
||||
@@ -43,7 +43,7 @@ class HKP {
|
||||
ctx.throw(400, 'Invalid request!');
|
||||
}
|
||||
const origin = util.origin(ctx);
|
||||
await this._publicKey.put({publicKeyArmored, origin});
|
||||
await this._publicKey.put({publicKeyArmored, origin}, ctx);
|
||||
ctx.body = 'Upload successful. Check your inbox to verify your email address.';
|
||||
ctx.status = 201;
|
||||
}
|
||||
@@ -54,7 +54,7 @@ class HKP {
|
||||
*/
|
||||
async lookup(ctx) {
|
||||
const params = this.parseQueryString(ctx);
|
||||
const key = await this._publicKey.get(params);
|
||||
const key = await this._publicKey.get(params, ctx);
|
||||
this.setGetHeaders(ctx, params);
|
||||
this.setGetBody(ctx, params, key);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class REST {
|
||||
ctx.throw(400, 'Invalid request!');
|
||||
}
|
||||
const origin = util.origin(ctx);
|
||||
await this._publicKey.put({emails, publicKeyArmored, origin});
|
||||
await this._publicKey.put({emails, publicKeyArmored, origin}, ctx);
|
||||
ctx.body = 'Upload successful. Check your inbox to verify your email address.';
|
||||
ctx.status = 201;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class REST {
|
||||
if (!util.isKeyId(q.keyId) && !util.isFingerPrint(q.fingerprint) && !util.isEmail(q.email)) {
|
||||
ctx.throw(400, 'Invalid request!');
|
||||
}
|
||||
ctx.body = await this._publicKey.get(q);
|
||||
ctx.body = await this._publicKey.get(q, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,10 +74,10 @@ class REST {
|
||||
if (!util.isKeyId(q.keyId) || !util.isString(q.nonce)) {
|
||||
ctx.throw(400, 'Invalid request!');
|
||||
}
|
||||
await this._publicKey.verify(q);
|
||||
const {email} = await this._publicKey.verify(q);
|
||||
// create link for sharing
|
||||
const link = util.url(util.origin(ctx), `/pks/lookup?op=get&search=0x${q.keyId.toUpperCase()}`);
|
||||
ctx.body = `<p>Email address successfully verified!</p><p>Link to share your key: <a href="${link}" target="_blank">${link}</a></p>`;
|
||||
const link = util.url(util.origin(ctx), `/pks/lookup?op=get&search=${email}`);
|
||||
ctx.body = ctx.__('verify_success', [email, link]);
|
||||
ctx.set('Content-Type', 'text/html; charset=utf-8');
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class REST {
|
||||
if (!util.isKeyId(q.keyId) && !util.isEmail(q.email)) {
|
||||
ctx.throw(400, 'Invalid request!');
|
||||
}
|
||||
await this._publicKey.requestRemove(q);
|
||||
await this._publicKey.requestRemove(q, ctx);
|
||||
ctx.body = 'Check your inbox to verify the removal of your email address.';
|
||||
ctx.status = 202;
|
||||
}
|
||||
|
||||
@@ -66,9 +66,10 @@ class PublicKey {
|
||||
* @param {Array} emails (optional) The emails to upload/update
|
||||
* @param {String} publicKeyArmored The ascii armored pgp key block
|
||||
* @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' }
|
||||
* @param {Object} ctx Context
|
||||
* @return {Promise}
|
||||
*/
|
||||
async put({emails = [], publicKeyArmored, origin}) {
|
||||
async put({emails = [], publicKeyArmored, origin}, ctx) {
|
||||
emails = emails.map(util.normalizeEmail);
|
||||
// lazily purge old/unverified keys on every key upload
|
||||
await this._purgeOldUnverified();
|
||||
@@ -100,7 +101,7 @@ class PublicKey {
|
||||
key.publicKeyArmored = null;
|
||||
}
|
||||
// send mails to verify user ids
|
||||
await this._sendVerifyEmail(key, origin);
|
||||
await this._sendVerifyEmail(key, origin, ctx);
|
||||
// store key in database
|
||||
await this._persistKey(key);
|
||||
}
|
||||
@@ -162,14 +163,15 @@ class PublicKey {
|
||||
* If a primary email address is provided only one email will be sent.
|
||||
* @param {Array} userIds user id documents containg the verification nonces
|
||||
* @param {Object} origin the server's origin (required for email links)
|
||||
* @param {Object} ctx Context
|
||||
* @return {Promise}
|
||||
*/
|
||||
async _sendVerifyEmail({userIds, keyId}, origin) {
|
||||
async _sendVerifyEmail({userIds, keyId}, origin, ctx) {
|
||||
for (const userId of userIds) {
|
||||
if (userId.notify && userId.notify === true) {
|
||||
// generate nonce for verification
|
||||
userId.nonce = util.random();
|
||||
await this._email.send({template: tpl.verifyKey, userId, keyId, origin, publicKeyArmored: userId.publicKeyArmored});
|
||||
await this._email.send({template: tpl.verifyKey.bind(null, ctx), userId, keyId, origin, publicKeyArmored: userId.publicKeyArmored});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,7 +202,7 @@ class PublicKey {
|
||||
* Verify a user id by proving knowledge of the nonce.
|
||||
* @param {string} keyId Correspronding public key id
|
||||
* @param {string} nonce The verification nonce proving email address ownership
|
||||
* @return {Promise}
|
||||
* @return {Promise} The email that has been verified
|
||||
*/
|
||||
async verify({keyId, nonce}) {
|
||||
// look for verification nonce in database
|
||||
@@ -210,7 +212,7 @@ class PublicKey {
|
||||
util.throw(404, 'User ID not found');
|
||||
}
|
||||
await this._removeKeysWithSameEmail(key, nonce);
|
||||
let {publicKeyArmored} = key.userIds.find(userId => userId.nonce === nonce);
|
||||
let {publicKeyArmored, email} = key.userIds.find(userId => userId.nonce === nonce);
|
||||
// update armored key
|
||||
if (key.publicKeyArmored) {
|
||||
publicKeyArmored = await this._pgp.updateKey(key.publicKeyArmored, publicKeyArmored);
|
||||
@@ -222,6 +224,7 @@ class PublicKey {
|
||||
'userIds.$.nonce': null,
|
||||
'userIds.$.publicKeyArmored': null
|
||||
}, DB_TYPE);
|
||||
return {email};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,14 +286,15 @@ class PublicKey {
|
||||
* @param {string} fingerprint (optional) The public key fingerprint
|
||||
* @param {string} keyId (optional) The public key id
|
||||
* @param {String} email (optional) The user's email address
|
||||
* @param {Object} ctx Context
|
||||
* @return {Object} The public key document
|
||||
*/
|
||||
async get({fingerprint, keyId, email}) {
|
||||
async get({fingerprint, keyId, email}, ctx) {
|
||||
// look for verified key
|
||||
const userIds = email ? [{email}] : undefined;
|
||||
const key = await this.getVerified({keyId, fingerprint, userIds});
|
||||
if (!key) {
|
||||
util.throw(404, 'Key not found');
|
||||
util.throw(404, ctx.__('key_not_found'));
|
||||
}
|
||||
// clean json return value (_id, nonce)
|
||||
delete key._id;
|
||||
@@ -310,9 +314,10 @@ class PublicKey {
|
||||
* @param {String} keyId (optional) The public key id
|
||||
* @param {String} email (optional) The user's email address
|
||||
* @param {Object} origin Required for links to the keyserver e.g. { protocol:'https', host:'openpgpkeys@example.com' }
|
||||
* @param {Object} ctx Context
|
||||
* @return {Promise}
|
||||
*/
|
||||
async requestRemove({keyId, email, origin}) {
|
||||
async requestRemove({keyId, email, origin}, ctx) {
|
||||
// flag user ids for removal
|
||||
const key = await this._flagForRemove(keyId, email);
|
||||
if (!key) {
|
||||
@@ -321,7 +326,7 @@ class PublicKey {
|
||||
// send verification mails
|
||||
keyId = key.keyId; // get keyId in case request was by email
|
||||
for (const userId of key.userIds) {
|
||||
await this._email.send({template: tpl.verifyRemove, userId, keyId, origin});
|
||||
await this._email.send({template: tpl.verifyRemove.bind(null, ctx), userId, keyId, origin});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user