Design class architecture and HTTP api
This commit is contained in:
parent
e23b65ac0f
commit
82fcb819e9
@ -17,6 +17,16 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database documents have the format:
|
||||||
|
* {
|
||||||
|
* _id: "02C134D079701934", // the 16 byte key id
|
||||||
|
* email: "jon@example.com", // the primary and verified email address
|
||||||
|
* publicKeyArmored: "-----BEGIN PGP PUBLIC KEY BLOCK----- ... -----END PGP PUBLIC KEY BLOCK-----"
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
const DB_TYPE = 'publickey';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A controller that handlers PGP public keys queries to the database
|
* A controller that handlers PGP public keys queries to the database
|
||||||
*/
|
*/
|
||||||
@ -30,6 +40,38 @@ class PublicKey {
|
|||||||
this._mongo = mongo;
|
this._mongo = mongo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create/Update
|
||||||
|
//
|
||||||
|
|
||||||
|
put(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read
|
||||||
|
//
|
||||||
|
|
||||||
|
get(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Delete
|
||||||
|
//
|
||||||
|
|
||||||
|
remove(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyRemove(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = PublicKey;
|
module.exports = PublicKey;
|
29
src/dao/email.js
Normal file
29
src/dao/email.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Mailvelope - secure email with OpenPGP encryption for Webmail
|
||||||
|
* Copyright (C) 2016 Mailvelope GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License version 3
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple wrapper around Nodemailer to send verification emails
|
||||||
|
*/
|
||||||
|
class Email {
|
||||||
|
|
||||||
|
send(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -31,30 +31,35 @@ class HKP {
|
|||||||
this._publicKey = publicKey;
|
this._publicKey = publicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Public key lookup via http GET
|
|
||||||
* @param {Object} ctx The koa request/response context
|
|
||||||
*/
|
|
||||||
*lookup(ctx) {
|
|
||||||
var params = this.parseQueryString(ctx);
|
|
||||||
if (!params) {
|
|
||||||
return; // invalid request
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setHeaders(ctx);
|
|
||||||
if (params.mr) {
|
|
||||||
this.setGetMRHEaders(ctx);
|
|
||||||
}
|
|
||||||
ctx.body = yield Promise.resolve('----- BEGIN PUBLIC PGP KEY -----');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public key upload via http POST
|
* Public key upload via http POST
|
||||||
* @param {Object} ctx The koa request/response context
|
* @param {Object} ctx The koa request/response context
|
||||||
*/
|
*/
|
||||||
*add(ctx) {
|
*add(ctx) {
|
||||||
ctx.throw(501, 'Not implemented!');
|
ctx.throw(501, 'Not implemented!');
|
||||||
return yield Promise.resolve();
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public key lookup via http GET
|
||||||
|
* @param {Object} ctx The koa request/response context
|
||||||
|
*/
|
||||||
|
*lookup(ctx) {
|
||||||
|
let params = this.parseQueryString(ctx);
|
||||||
|
if (!params) {
|
||||||
|
return; // invalid request
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = yield this._publicKey.get(params);
|
||||||
|
if (key) {
|
||||||
|
ctx.body = key.publicKeyArmored;
|
||||||
|
if (params.mr) {
|
||||||
|
this.setGetMRHEaders(ctx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.status = 404;
|
||||||
|
ctx.body = 'Not found!';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,20 +69,22 @@ class HKP {
|
|||||||
* @return {Object} The query parameters or undefined for an invalid request
|
* @return {Object} The query parameters or undefined for an invalid request
|
||||||
*/
|
*/
|
||||||
parseQueryString(ctx) {
|
parseQueryString(ctx) {
|
||||||
let q = ctx.query;
|
|
||||||
let params = {
|
let params = {
|
||||||
op: q.op, // operation ... only 'get' is supported
|
op: ctx.query.op, // operation ... only 'get' is supported
|
||||||
mr: q.options === 'mr', // machine readable
|
mr: ctx.query.options === 'mr' // machine readable
|
||||||
keyid: this.checkId(q.search) ? q.search.replace('0x', '') : null,
|
|
||||||
email: this.checkEmail(q.search) ? q.search : null,
|
|
||||||
};
|
};
|
||||||
|
if (this.checkId(ctx.query.search)) {
|
||||||
|
params._id = ctx.query.search.replace(/^0x/, '');
|
||||||
|
} else if(this.checkEmail(ctx.query.search)) {
|
||||||
|
params.email = ctx.query.search;
|
||||||
|
}
|
||||||
|
|
||||||
if (params.op !== 'get') {
|
if (params.op !== 'get') {
|
||||||
ctx.status = 501;
|
ctx.status = 501;
|
||||||
ctx.body = 'Not implemented!';
|
ctx.body = 'Not implemented!';
|
||||||
return;
|
return;
|
||||||
} else if (!params.keyid && !params.email) {
|
} else if (!params._id && !params.email) {
|
||||||
ctx.status = 404;
|
ctx.status = 400;
|
||||||
ctx.body = 'Invalid request!';
|
ctx.body = 'Invalid request!';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -101,18 +108,7 @@ class HKP {
|
|||||||
* @return {Boolean} If the key id is valid
|
* @return {Boolean} If the key id is valid
|
||||||
*/
|
*/
|
||||||
checkId(keyid) {
|
checkId(keyid) {
|
||||||
return /^0x[a-fA-F0-9]{8,40}/.test(keyid);
|
return /^0x[a-fA-F0-9]{8,40}$/.test(keyid);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set HTTP headers for the HKP requests.
|
|
||||||
* @param {Object} ctx The koa request/response context
|
|
||||||
*/
|
|
||||||
setHeaders(ctx) {
|
|
||||||
ctx.set('Access-Control-Allow-Origin', '*');
|
|
||||||
ctx.set('Cache-Control', 'no-cache');
|
|
||||||
ctx.set('Pragma', 'no-cache');
|
|
||||||
ctx.set('Connection', 'keep-alive');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
56
src/routes/rest.js
Normal file
56
src/routes/rest.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Mailvelope - secure email with OpenPGP encryption for Webmail
|
||||||
|
* Copyright (C) 2016 Mailvelope GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License version 3
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The REST api to provide additional functionality on top of HKP
|
||||||
|
*/
|
||||||
|
class REST {
|
||||||
|
|
||||||
|
constructor(publicKey) {
|
||||||
|
this._publicKey = publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
*create(ctx) {
|
||||||
|
ctx.throw(501, 'Not implemented!');
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
*verify(ctx) {
|
||||||
|
ctx.throw(501, 'Not implemented!');
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
*read(ctx) {
|
||||||
|
ctx.throw(501, 'Not implemented!');
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
*remove(ctx) {
|
||||||
|
ctx.throw(501, 'Not implemented!');
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
*verifyRemove(ctx) {
|
||||||
|
ctx.throw(501, 'Not implemented!');
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = REST;
|
@ -25,18 +25,53 @@ const router = require('koa-router')();
|
|||||||
const Mongo = require('./dao/mongo');
|
const Mongo = require('./dao/mongo');
|
||||||
const PublicKey = require('./ctrl/public-key');
|
const PublicKey = require('./ctrl/public-key');
|
||||||
const HKP = require('./routes/hkp');
|
const HKP = require('./routes/hkp');
|
||||||
|
const REST = require('./routes/rest');
|
||||||
|
|
||||||
let mongo, publicKey, hkp;
|
let mongo, publicKey, hkp, rest;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Configure koa router
|
// Configure koa HTTP server
|
||||||
//
|
//
|
||||||
|
|
||||||
router.get('/pks/lookup', function *() {
|
// HKP routes
|
||||||
|
router.post('/pks/add', function *() { // no query params
|
||||||
|
yield hkp.add(this);
|
||||||
|
});
|
||||||
|
router.get('/pks/lookup', function *() { // ?op=get&search=0x1234567890123456
|
||||||
yield hkp.lookup(this);
|
yield hkp.lookup(this);
|
||||||
});
|
});
|
||||||
router.post('/pks/add', function *() {
|
|
||||||
yield hkp.add(this);
|
// REST api routes
|
||||||
|
router.post('/api/key', function *() { // no query params
|
||||||
|
yield rest.create(this);
|
||||||
|
});
|
||||||
|
router.get('/api/key', function *() { // ?id=keyid OR ?email=email
|
||||||
|
yield rest.read(this);
|
||||||
|
});
|
||||||
|
router.del('/api/key', function *() { // ?id=keyid OR ?email=email
|
||||||
|
yield rest.remove(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
// links for verification and sharing
|
||||||
|
router.get('/api/verify', function *() { // ?id=keyid&nonce=nonce
|
||||||
|
yield rest.verify(this);
|
||||||
|
});
|
||||||
|
router.get('/api/verifyRemove', function *() { // ?id=keyid&nonce=nonce
|
||||||
|
yield rest.verifyRemove(this);
|
||||||
|
});
|
||||||
|
router.get('/:email', function *() { // shorthand link for sharing
|
||||||
|
yield rest.read(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set HTTP response headers
|
||||||
|
app.use(function *(next) {
|
||||||
|
this.set('Access-Control-Allow-Origin', '*');
|
||||||
|
this.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
||||||
|
this.set('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
this.set('Cache-Control', 'no-cache');
|
||||||
|
this.set('Pragma', 'no-cache');
|
||||||
|
this.set('Connection', 'keep-alive');
|
||||||
|
yield next;
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(router.routes());
|
app.use(router.routes());
|
||||||
@ -56,6 +91,7 @@ function injectDependencies() {
|
|||||||
});
|
});
|
||||||
publicKey = new PublicKey(mongo);
|
publicKey = new PublicKey(mongo);
|
||||||
hkp = new HKP(publicKey);
|
hkp = new HKP(publicKey);
|
||||||
|
rest = new REST(publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
function readCredentials() {
|
function readCredentials() {
|
||||||
|
Loading…
Reference in New Issue
Block a user