Cleanup url handling

This commit is contained in:
Tankred Hase 2016-06-10 12:06:08 +02:00
parent 405bb84ca6
commit d5bd65b4bc
8 changed files with 92 additions and 25 deletions

View File

@ -2,6 +2,10 @@ module.exports = {
log: {
level: 'error'
}
},
server: {
upgradeHTTP: true
},
};

View File

@ -22,6 +22,7 @@ const app = require('koa')();
const log = require('npmlog');
const config = require('config');
const router = require('koa-router')();
const util = require('./service/util');
const Mongo = require('./dao/mongo');
const Email = require('./email/email');
const PGP = require('./service/pgp');
@ -85,7 +86,7 @@ app.use(function *(next) {
// Redirect all http traffic to https
app.use(function *(next) {
if (process.env.NODE_ENV === 'production' && !this.secure && this.get('X-Forwarded-Proto') === 'http') {
if (config.server.upgradeHTTP && util.checkHTTP(this)) {
this.redirect('https://' + this.hostname + this.url);
} else {
yield next;

View File

@ -69,7 +69,7 @@ class Email {
html: template.html,
params: {
name: userId.name,
baseUrl: origin.protocol + '://' + origin.host,
baseUrl: util.url(origin),
keyId: encodeURIComponent(keyId),
nonce: encodeURIComponent(userId.nonce)
}

View File

@ -44,7 +44,7 @@ class HKP {
if (!publicKeyArmored) {
ctx.throw(400, 'Invalid request!');
}
let origin = util.getOrigin(ctx);
let origin = util.origin(ctx);
yield this._publicKey.put({ publicKeyArmored, origin });
ctx.status = 201;
}

View File

@ -1,23 +1,34 @@
'use strict';
const util = require('../service/util');
module.exports = function () {
let tls = this.secure || process.env.NODE_ENV === 'production' && this.get('X-Forwarded-Proto') === 'https';
let hkp = (tls ? 'hkps://' : 'hkp://') + this.host;
let del = (tls ? 'https://' : 'http://') + this.host + '/api/v1/removeKey?email=user@example.com';
let hkpLink = util.hkpUrl(this);
let removeLink = util.url(util.origin(this), '/api/v1/removeKey?email=user@example.com');
this.body =
`
<h1>Welcome to the OpenPGP key server</h1>
<p>This server verifies email address as well as private key ownership by sending an encrypted verification email.</p>
<h2>Try it out</h2>
<ol>
<li>Configure this key server in your HKP compatible OpenPGP client using this url: <a href="${hkp}" target="_blank">${hkp}</a></li>
<li>Now just upload a public key like you always do.</li>
<li>Check your inbox and click on the verification link inside the encrypted message.</li>
<li>You can delete all your data from the server at any time using this link: <a href="${del}" target="_blank">${del}</a></li>
</ol>
<h2>Documentation and code</h2>
<p>Please refer to <a href="https://github.com/mailvelope/keyserver" target="_blank">the documentation</a> to learn more about the api.</p>
<p>License AGPL v3.0</p>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenPGP key server</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
</head>
<body>
<h1>Welcome to the OpenPGP key server</h1>
<p>This server verifies email address as well as private key ownership by sending an encrypted verification email.</p>
<h2>Try it out</h2>
<ol>
<li>Configure this key server in your HKP compatible OpenPGP client using this url: <a href="${hkpLink}" target="_blank">${hkpLink}</a></li>
<li>Now just upload a public key like you always do.</li>
<li>Check your inbox and click on the verification link inside the encrypted message.</li>
<li>You can delete all your data from the server at any time using this link: <a href="${removeLink}" target="_blank">${removeLink}</a></li>
</ol>
<h2>Documentation and code</h2>
<p>Please refer to <a href="https://github.com/mailvelope/keyserver" target="_blank">the documentation</a> to learn more about the api.</p>
<p>License AGPL v3.0</p>
</body>
</html>
`;
this.set('Content-Type', 'text/html; charset=utf-8');

View File

@ -44,7 +44,7 @@ class REST {
if (!publicKeyArmored || (primaryEmail && !util.isEmail(primaryEmail))) {
ctx.throw(400, 'Invalid request!');
}
let origin = util.getOrigin(ctx);
let origin = util.origin(ctx);
yield this._publicKey.put({ publicKeyArmored, primaryEmail, origin });
ctx.status = 201;
}
@ -91,7 +91,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.getOrigin(ctx) };
let 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!');
}

View File

@ -102,6 +102,25 @@ exports.random = function(bytes) {
return crypto.randomBytes(bytes).toString('hex');
};
/**
* Check if the user is connecting over a plaintext http connection.
* This can be used as an indicator to upgrade their connection to https.
* @param {Object} ctx The koa request/repsonse context
* @return {boolean} If http is used
*/
exports.checkHTTP = function(ctx) {
return !ctx.secure && ctx.get('X-Forwarded-Proto') === 'http';
};
/**
* Check if the user is connecting over a https connection.
* @param {Object} ctx The koa request/repsonse context
* @return {boolean} If https is used
*/
exports.checkHTTPS = function(ctx) {
return ctx.secure || ctx.get('X-Forwarded-Proto') === 'https';
};
/**
* Get the server's own origin host and protocol. Required for sending
* verification links via email. If the PORT environmane variable
@ -110,9 +129,29 @@ exports.random = function(bytes) {
* @param {Object} ctx The koa request/repsonse context
* @return {Object} The server origin
*/
exports.getOrigin = function(ctx) {
exports.origin = function(ctx) {
return {
protocol: process.env.PORT ? 'https' : ctx.protocol,
protocol: this.checkHTTPS(ctx) ? 'https' : ctx.protocol,
host: ctx.host
};
};
/**
* Helper to create urls pointing to this server
* @param {Object} origin The server's origin
* @param {string} resource (optional) The resource to point to
* @return {string} The complete url
*/
exports.url = function(origin, resource) {
return origin.protocol + '://' + origin.host + (resource || '');
};
/**
* Helper to create a url for hkp clients to connect to this server via
* the hkp protocol.
* @param {Object} ctx The koa request/repsonse context
* @return {string} The complete url
*/
exports.hkpUrl = function(ctx) {
return (this.checkHTTPS(ctx) ? 'hkps://' : 'hkp://') + ctx.host;
};

View File

@ -135,9 +135,21 @@ describe('Util Unit Tests', () => {
});
});
describe('getOrigin', () => {
describe('origin', () => {
it('should work', () => {
expect(util.getOrigin({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');
expect(url).to.equal('http://localhost/foo');
});
it('should work without resource', () => {
let url = util.url({ host:'localhost', protocol:'http'});
expect(url).to.equal('http://localhost');
});
});