Serve Bootstrap and jQuery from key server origin. Use EJS for view rendering.

This commit is contained in:
Thomas Oberndörfer 2019-06-14 11:17:25 +02:00
parent 3367f08647
commit f399da9614
11 changed files with 221 additions and 182 deletions

42
package-lock.json generated
View File

@ -187,6 +187,12 @@
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
}, },
"bootstrap": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz",
"integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==",
"dev": true
},
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -548,6 +554,11 @@
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
}, },
"ejs": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz",
"integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ=="
},
"emoji-regex": { "emoji-regex": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
@ -1205,6 +1216,12 @@
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true "dev": true
}, },
"jquery": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz",
"integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==",
"dev": true
},
"js-tokens": { "js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -1322,6 +1339,31 @@
} }
} }
}, },
"koa-ejs": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/koa-ejs/-/koa-ejs-4.2.0.tgz",
"integrity": "sha512-qNcKySHW0gTPSp7++xP/RET2Vuxs36aV76ezp3DmJZNnTOlylXFMv7c62iutZFsiC5ejTS6y9gcj6DmF5WR82g==",
"requires": {
"debug": "^2.6.1",
"ejs": "^2.6.1",
"mz": "^2.6.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"koa-is-json": { "koa-is-json": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz", "resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz",

View File

@ -13,7 +13,7 @@
"scripts": { "scripts": {
"start": "node index.js", "start": "node index.js",
"test": "npm run test:lint && npm run test:unit && npm run test:integration", "test": "npm run test:lint && npm run test:unit && npm run test:integration",
"test:lint": "eslint config src test *.js", "test:lint": "eslint --ignore-pattern \"**/*.min.js\" config src test *.js",
"test:unit": "mocha --opts test/mocha.opts ./test/unit/", "test:unit": "mocha --opts test/mocha.opts ./test/unit/",
"test:integration": "mocha --exit --opts test/mocha.opts ./test/integration", "test:integration": "mocha --exit --opts test/mocha.opts ./test/integration",
"release": "npm run release:install && npm run release:archive", "release": "npm run release:install && npm run release:archive",
@ -24,6 +24,7 @@
"co-body": "6.0.0", "co-body": "6.0.0",
"config": "3.1.0", "config": "3.1.0",
"koa": "2.7.0", "koa": "2.7.0",
"koa-ejs": "^4.2.0",
"koa-locales": "1.11.0", "koa-locales": "1.11.0",
"koa-router": "7.4.0", "koa-router": "7.4.0",
"koa-static": "5.0.0", "koa-static": "5.0.0",
@ -34,9 +35,11 @@
"winston-papertrail": "1.0.5" "winston-papertrail": "1.0.5"
}, },
"devDependencies": { "devDependencies": {
"bootstrap": "3.4.1",
"chai": "^4.1.1", "chai": "^4.1.1",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"jquery": "3.4.1",
"mocha": "^6.1.4", "mocha": "^6.1.4",
"sinon": "^7.3.2", "sinon": "^7.3.2",
"supertest": "^4.0.2" "supertest": "^4.0.2"

View File

@ -20,6 +20,7 @@
const Koa = require('koa'); const Koa = require('koa');
const serve = require('koa-static'); const serve = require('koa-static');
const router = require('koa-router')(); const router = require('koa-router')();
const render = require('koa-ejs');
const locales = require('koa-locales'); const locales = require('koa-locales');
const config = require('config'); const config = require('config');
const middleware = require('./middleware'); const middleware = require('./middleware');
@ -31,11 +32,19 @@ const PGP = require('../service/pgp');
const PublicKey = require('../service/public-key'); const PublicKey = require('../service/public-key');
const app = new Koa(); const app = new Koa();
render(app, {
root: `${__dirname}/../view`
});
locales(app); locales(app);
let hkp; let hkp;
let rest; let rest;
// UI views
router.get('/', ctx => ctx.render('index'));
router.redirect('/index.html', '/');
router.get('/manage.html', ctx => ctx.render('manage'));
// HKP and REST api routes // HKP and REST api routes
router.post('/pks/add', ctx => hkp.add(ctx)); router.post('/pks/add', ctx => hkp.add(ctx));
router.get('/pks/lookup', ctx => hkp.lookup(ctx)); router.get('/pks/lookup', ctx => hkp.lookup(ctx));

View File

@ -39,7 +39,7 @@ exports.setHTTPResponseHeaders = async function(ctx, next) {
ctx.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`); ctx.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`);
} }
// CSP // CSP
ctx.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; script-src 'self' code.jquery.com; style-src 'self' stackpath.bootstrapcdn.com 'unsafe-inline'; font-src 'self' stackpath.bootstrapcdn.com"); ctx.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'");
// Prevent rendering website in foreign iframe (Clickjacking) // Prevent rendering website in foreign iframe (Clickjacking)
ctx.set('X-Frame-Options', 'DENY'); ctx.set('X-Frame-Options', 'DENY');
// CORS // CORS

6
src/static/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,73 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="description" content="An OpenPGP public key server that verifies users by sending an encrypted verification email.">
<meta name="author" content="Tankred Hase">
<title>Mailvelope Key Server</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="css/jumbotron-narrow.css">
</head>
<body>
<div class="container">
<div class="header clearfix">
<nav>
<ul class="nav nav-pills pull-right">
<li role="presentation" class="active"><a href="/">Home</a></li>
<li role="presentation"><a href="manage.html">Manage Keys</a></li>
<li role="presentation"><a href="https://github.com/mailvelope/keyserver" target="_blank">GitHub</a></li>
</ul>
</nav>
<h3 class="text-muted">Mailvelope Key Server</h3>
</div>
<div class="jumbotron">
<h1>Secure. Easy.</h1>
<p class="lead">The Mailvelope OpenPGP public key server is the first of its kind. It allows automatic public key lookup to make email privacy <strong>just as painless as modern messengers</strong>.</p>
<p><a class="btn btn-lg btn-success" href="manage.html" role="button">Try it now</a></p>
</div>
<div class="row marketing">
<div class="col-lg-6">
<h4>Privacy made Easy</h4>
<p>Automatic key lookup in OpenPGP mail user agents makes reading and writing encrypted email just as painless as modern messenengers.</p>
<h4>No Web of Trust</h4>
<p>No more key signing parties or publishing your social network online. You can even delete your public key at anytime. <a href="https://github.com/mailvelope/keyserver/blob/master/README.md#why-not-use-web-of-trust" target="_blank">Learn more</a></p>
<h4>Secure REST API</h4>
<p>The server offers a modern REST API over HTTPS with HSTS and public key pinning that can be integrated into any app architecture. <a href="https://github.com/mailvelope/keyserver/blob/master/README.md#rest-api" target="_blank">Learn more</a></p>
</div>
<div class="col-lg-6">
<h4>Verify Yourself</h4>
<p>The server verifies email address ownership as well as private key ownership by sending an encrypted verification email.</p>
<h4>Completely Open</h4>
<p>The code is licensed under the AGPL v3.0 which means you are free to host your own key directory under your domain. <a href="https://github.com/mailvelope/keyserver" target="_blank">Learn more</a></p>
<h4>HKP Compatible</h4>
<p>No need to update your current OpenPGP plugin. Just copy and paste <a href="hkps://keys.mailvelope.com" target="_blank">hkps://keys.mailvelope.com</a> into your settings and go. <a href="https://github.com/mailvelope/keyserver/blob/master/README.md#hkp-api" target="_blank">Learn more</a></p>
</div>
</div>
<footer class="footer">
<nav>
<ul>
<li><a target="_blank" href="https://www.mailvelope.com/imprint">Imprint</a></li> |
<li><a target="_blank" href="https://www.mailvelope.com/privacy-service">Privacy</a></li>
</ul>
</nav>
<p>&copy; 2019 Mailvelope GmbH</p>
</footer>
</div> <!-- /container -->
</body>
</html>

2
src/static/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,107 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="description" content="An OpenPGP public key server that verifies users by sending an encrypted verification email.">
<meta name="author" content="Tankred Hase">
<title>Mailvelope Key Server</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="css/jumbotron-narrow.css">
</head>
<body>
<div class="container">
<div class="header clearfix">
<nav>
<ul class="nav nav-pills pull-right">
<li role="presentation"><a href="/">Home</a></li>
<li role="presentation" class="active"><a href="manage.html">Manage Keys</a></li>
<li role="presentation"><a href="https://github.com/mailvelope/keyserver" target="_blank">GitHub</a></li>
</ul>
</nav>
<h3 class="text-muted">Mailvelope Key Server</h3>
</div>
<div class="row marketing">
<div id="addKey" class="col-lg-12">
<h2>OpenPGP key upload</h2>
<div class="alert alert-success hidden" role="alert">
<strong>Success!</strong> <span></span>
</div>
<div class="alert alert-danger hidden" role="alert">
<strong>Error!</strong> <span></span>
</div>
<div class="progress hidden">
<div class="progress-bar progress-bar-striped active" role="progressbar"></div>
</div>
<form action="/pks/add" method="post">
<p><textarea class="form-control" name="keytext" rows="5" spellcheck="false" placeholder="Paste PGP PUBLIC KEY BLOCK here ..." required></textarea></p>
<input class="btn btn-primary btn-lg" type="submit" value="Upload">
</form>
<hr>
</div> <!-- /col-lg-12 -->
<div class="col-lg-12">
<h2>OpenPGP key lookup</h2>
<form action="/pks/lookup" method="get">
<input class="hidden" type="radio" name="op" value="get" checked="checked">
<div class="input-group input-group-lg">
<input class="form-control" name="search" type="text" spellcheck="false" placeholder="Email address or Key ID e.g. 0x11A1A9C84B18732F" required>
<span class="input-group-btn">
<input class="btn btn-default" type="submit" value="Search">
</span>
</div><!-- /input-group -->
</form>
<hr>
</div> <!-- /col-lg-12 -->
<div id="removeKey" class="col-lg-12">
<h2>OpenPGP key removal</h2>
<div class="alert alert-success hidden" role="alert">
<strong>Success!</strong> <span></span>
</div>
<div class="alert alert-danger hidden" role="alert">
<strong>Error!</strong> <span></span>
</div>
<div class="progress hidden">
<div class="progress-bar progress-bar-striped active" role="progressbar"></div>
</div>
<form>
<div class="input-group input-group-lg">
<input class="form-control" name="email" type="email" spellcheck="false" placeholder="Email address" required>
<span class="input-group-btn">
<input class="btn btn-default" type="submit" value="Delete">
</span>
</div><!-- /input-group -->
</form>
<hr>
</div> <!-- /col-lg-12 -->
<div class="col-lg-12">
<h2>HKP and REST Apis</h2>
<p>The server offers a modern REST api over HTTPS with HSTS and public key pinning that can be integrated into any app architecture. It is also compatible to the OpenPGP HTTP Keyserver Protocol (HKP). Just copy and paste <a href="hkps://keys.mailvelope.com" target="_blank">hkps://keys.mailvelope.com</a> into your current OpenPGP plugin and go. <a href="https://github.com/mailvelope/keyserver/blob/master/README.md#api" target="_blank">Learn more</a>.</p>
</div>
</div> <!-- /row marketing -->
<footer class="footer">
<nav>
<ul>
<li><a target="_blank" href="https://www.mailvelope.com/imprint">Imprint</a></li> |
<li><a target="_blank" href="https://www.mailvelope.com/privacy-service">Privacy</a></li>
</ul>
</nav>
<p>&copy; 2019 Mailvelope GmbH</p>
</footer>
</div> <!-- /container -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT" crossorigin="anonymous"></script>
<script src="js/manage.js"></script>
</body>
</html>

54
src/view/index.html Normal file
View File

@ -0,0 +1,54 @@
<div class="container">
<div class="header clearfix">
<nav>
<ul class="nav nav-pills pull-right">
<li role="presentation" class="active"><a href="/">Home</a></li>
<li role="presentation"><a href="manage.html">Manage Keys</a></li>
<li role="presentation"><a href="https://github.com/mailvelope/keyserver" target="_blank">GitHub</a></li>
</ul>
</nav>
<h3 class="text-muted">Mailvelope Key Server</h3>
</div>
<div class="jumbotron">
<h1>Secure. Easy.</h1>
<p class="lead">The Mailvelope OpenPGP public key server is the first of its kind. It allows automatic public key lookup to make email privacy <strong>just as painless as modern messengers</strong>.</p>
<p><a class="btn btn-lg btn-success" href="manage.html" role="button">Try it now</a></p>
</div>
<div class="row marketing">
<div class="col-lg-6">
<h4>Privacy made Easy</h4>
<p>Automatic key lookup in OpenPGP mail user agents makes reading and writing encrypted email just as painless as modern messenengers.</p>
<h4>No Web of Trust</h4>
<p>No more key signing parties or publishing your social network online. You can even delete your public key at anytime. <a href="https://github.com/mailvelope/keyserver/blob/master/README.md#why-not-use-web-of-trust" target="_blank">Learn more</a></p>
<h4>Secure REST API</h4>
<p>The server offers a modern REST API over HTTPS with HSTS and public key pinning that can be integrated into any app architecture. <a href="https://github.com/mailvelope/keyserver/blob/master/README.md#rest-api" target="_blank">Learn more</a></p>
</div>
<div class="col-lg-6">
<h4>Verify Yourself</h4>
<p>The server verifies email address ownership as well as private key ownership by sending an encrypted verification email.</p>
<h4>Completely Open</h4>
<p>The code is licensed under the AGPL v3.0 which means you are free to host your own key directory under your domain. <a href="https://github.com/mailvelope/keyserver" target="_blank">Learn more</a></p>
<h4>HKP Compatible</h4>
<p>No need to update your current OpenPGP plugin. Just copy and paste <a href="hkps://keys.mailvelope.com" target="_blank">hkps://keys.mailvelope.com</a> into your settings and go. <a href="https://github.com/mailvelope/keyserver/blob/master/README.md#hkp-api" target="_blank">Learn more</a></p>
</div>
</div>
<footer class="footer">
<nav>
<ul>
<li><a target="_blank" href="https://www.mailvelope.com/imprint">Imprint</a></li> |
<li><a target="_blank" href="https://www.mailvelope.com/privacy-service">Privacy</a></li>
</ul>
</nav>
<p>&copy; 2019 Mailvelope GmbH</p>
</footer>
</div> <!-- /container -->

15
src/view/layout.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="description" content="An OpenPGP public key server that verifies users by sending an encrypted verification email.">
<meta name="author" content="Mailvelope GmbH">
<title>Mailvelope Key Server</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/jumbotron-narrow.css">
</head>
<body>
<%- body %>
</body>
</html>

88
src/view/manage.html Normal file
View File

@ -0,0 +1,88 @@
<div class="container">
<div class="header clearfix">
<nav>
<ul class="nav nav-pills pull-right">
<li role="presentation"><a href="/">Home</a></li>
<li role="presentation" class="active"><a href="manage.html">Manage Keys</a></li>
<li role="presentation"><a href="https://github.com/mailvelope/keyserver" target="_blank">GitHub</a></li>
</ul>
</nav>
<h3 class="text-muted">Mailvelope Key Server</h3>
</div>
<div class="row marketing">
<div id="addKey" class="col-lg-12">
<h2>OpenPGP key upload</h2>
<div class="alert alert-success hidden" role="alert">
<strong>Success!</strong> <span></span>
</div>
<div class="alert alert-danger hidden" role="alert">
<strong>Error!</strong> <span></span>
</div>
<div class="progress hidden">
<div class="progress-bar progress-bar-striped active" role="progressbar"></div>
</div>
<form action="/pks/add" method="post">
<p><textarea class="form-control" name="keytext" rows="5" spellcheck="false" placeholder="Paste PGP PUBLIC KEY BLOCK here ..." required></textarea></p>
<input class="btn btn-primary btn-lg" type="submit" value="Upload">
</form>
<hr>
</div> <!-- /col-lg-12 -->
<div class="col-lg-12">
<h2>OpenPGP key lookup</h2>
<form action="/pks/lookup" method="get">
<input class="hidden" type="radio" name="op" value="get" checked="checked">
<div class="input-group input-group-lg">
<input class="form-control" name="search" type="text" spellcheck="false" placeholder="Email address or Key ID e.g. 0x11A1A9C84B18732F" required>
<span class="input-group-btn">
<input class="btn btn-default" type="submit" value="Search">
</span>
</div><!-- /input-group -->
</form>
<hr>
</div> <!-- /col-lg-12 -->
<div id="removeKey" class="col-lg-12">
<h2>OpenPGP key removal</h2>
<div class="alert alert-success hidden" role="alert">
<strong>Success!</strong> <span></span>
</div>
<div class="alert alert-danger hidden" role="alert">
<strong>Error!</strong> <span></span>
</div>
<div class="progress hidden">
<div class="progress-bar progress-bar-striped active" role="progressbar"></div>
</div>
<form>
<div class="input-group input-group-lg">
<input class="form-control" name="email" type="email" spellcheck="false" placeholder="Email address" required>
<span class="input-group-btn">
<input class="btn btn-default" type="submit" value="Delete">
</span>
</div><!-- /input-group -->
</form>
<hr>
</div> <!-- /col-lg-12 -->
<div class="col-lg-12">
<h2>HKP and REST Apis</h2>
<p>The server offers a modern REST api over HTTPS with HSTS and public key pinning that can be integrated into any app architecture. It is also compatible to the OpenPGP HTTP Keyserver Protocol (HKP). Just copy and paste <a href="hkps://keys.mailvelope.com" target="_blank">hkps://keys.mailvelope.com</a> into your current OpenPGP plugin and go. <a href="https://github.com/mailvelope/keyserver/blob/master/README.md#api" target="_blank">Learn more</a>.</p>
</div>
</div> <!-- /row marketing -->
<footer class="footer">
<nav>
<ul>
<li><a target="_blank" href="https://www.mailvelope.com/imprint">Imprint</a></li> |
<li><a target="_blank" href="https://www.mailvelope.com/privacy-service">Privacy</a></li>
</ul>
</nav>
<p>&copy; 2019 Mailvelope GmbH</p>
</footer>
</div> <!-- /container -->
<script src="js/jquery.min.js"></script>
<script src="js/manage.js"></script>