2018-01-10 08:14:05 +00:00
|
|
|
'use strict';
|
|
|
|
|
2018-01-10 21:54:08 +00:00
|
|
|
module.exports.create = function (cli, engine/*, dnsd*/) {
|
2018-01-12 09:03:41 +00:00
|
|
|
var subparts = (cli.subject || '').split('@');
|
|
|
|
/*
|
|
|
|
{
|
|
|
|
"kty": "EC",
|
|
|
|
"use": "sig",
|
|
|
|
"crv": "P-256",
|
|
|
|
"x": "ogbK2nP6SiEIIp4w8oXBn3dcs6kljFfTbgZYG591tUU",
|
|
|
|
"y": "sB0AekMYwpvbQfAoW-2LlEWdapNhxynfj1zBtWpE9lo",
|
|
|
|
"alg": "ES256"
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
var jwt;
|
|
|
|
var jwk;
|
|
|
|
var privpem;
|
|
|
|
var pubpem;
|
|
|
|
if (!subparts[1]) {
|
|
|
|
subparts = [ 'root', 'localhost' ];
|
|
|
|
// TODO generate new random key and store it
|
2018-01-30 08:33:19 +00:00
|
|
|
jwk = cli.privkey || require('../samples/privkey.js');
|
2018-01-12 09:03:41 +00:00
|
|
|
jwt = require('jsonwebtoken');
|
|
|
|
privpem = require('jwk-to-pem')(jwk, { private: true });
|
|
|
|
pubpem = require('jwk-to-pem')(jwk, { private: false });
|
2018-01-24 10:06:32 +00:00
|
|
|
console.info("====================");
|
|
|
|
console.info(" EC256 Private PEM: ");
|
|
|
|
console.info("====================");
|
|
|
|
console.info(privpem);
|
|
|
|
console.info();
|
|
|
|
console.info("================================");
|
|
|
|
console.info(" JWT Write Authorization Token: ");
|
|
|
|
console.info("================================");
|
|
|
|
console.info(jwt.sign(
|
2018-01-12 09:03:41 +00:00
|
|
|
{ sub: subparts[0]
|
|
|
|
, iss: subparts[1]
|
|
|
|
, aud: 'localhost'
|
|
|
|
, scp: '+rw@adns.org'
|
|
|
|
}
|
|
|
|
, privpem
|
|
|
|
, { notBefore: 0 // from now
|
|
|
|
, expiresIn: '2h'
|
|
|
|
, algorithm: 'ES256'
|
|
|
|
}
|
|
|
|
));
|
|
|
|
// expressed as "from now"
|
|
|
|
/*
|
|
|
|
{ NotBeforeError: jwt not active
|
|
|
|
at Object.module.exports [as verify] (digd.js/node_modules/jsonwebtoken/verify.js:117:19)
|
|
|
|
at digd.js/lib/httpd.js:112:15
|
|
|
|
at Layer.handle [as handle_request] (digd.js/node_modules/express/lib/router/layer.js:95:5)
|
|
|
|
at trim_prefix (digd.js/node_modules/express/lib/router/index.js:317:13)
|
|
|
|
at digd.js/node_modules/express/lib/router/index.js:284:7
|
|
|
|
at Function.process_params (digd.js/node_modules/express/lib/router/index.js:335:12)
|
|
|
|
at next (digd.js/node_modules/express/lib/router/index.js:275:10)
|
|
|
|
at expressInit (digd.js/node_modules/express/lib/middleware/init.js:40:5)
|
|
|
|
at Layer.handle [as handle_request] (digd.js/node_modules/express/lib/router/layer.js:95:5)
|
|
|
|
at trim_prefix (digd.js/node_modules/express/lib/router/index.js:317:13)
|
|
|
|
name: 'NotBeforeError',
|
|
|
|
message: 'jwt not active',
|
|
|
|
date: +050046-12-28T01:12:58.000Z }
|
|
|
|
*/
|
2018-01-24 10:06:32 +00:00
|
|
|
console.info("===============================");
|
|
|
|
console.info(" JWT Read Authorization Token: ");
|
|
|
|
console.info("===============================");
|
|
|
|
console.info(jwt.sign(
|
2018-01-12 09:03:41 +00:00
|
|
|
{ sub: subparts[0]
|
|
|
|
, iss: subparts[1]
|
|
|
|
, aud: 'localhost'
|
|
|
|
, scp: '+r@adns.org'
|
|
|
|
}
|
|
|
|
, privpem
|
|
|
|
, { notBefore: 0 // from now
|
|
|
|
, algorithm: 'ES256'
|
|
|
|
}
|
|
|
|
));
|
2018-01-24 10:06:32 +00:00
|
|
|
console.info("==========================");
|
2018-01-12 09:03:41 +00:00
|
|
|
}
|
2018-01-10 08:14:05 +00:00
|
|
|
|
|
|
|
function runHttp() {
|
|
|
|
var path = require('path');
|
|
|
|
var express = require('express');
|
2018-01-24 10:06:32 +00:00
|
|
|
var jsonParser = require('body-parser').json({ strict: true, limit: '100kb' });
|
2018-01-10 08:14:05 +00:00
|
|
|
var app = express();
|
|
|
|
var httpServer = require('http').createServer(app);
|
|
|
|
|
2018-01-23 22:21:20 +00:00
|
|
|
function hasClaim(claim) {
|
|
|
|
return function (req, res, next) {
|
|
|
|
if ((req.token.scp||'').split(/[\s,]/g).some(function (c) {
|
|
|
|
return claim === c;
|
|
|
|
})) {
|
|
|
|
next();
|
|
|
|
} else {
|
2018-01-26 08:42:24 +00:00
|
|
|
res.send({ error: { message: "no claim to '" + claim + "' in token" } });
|
|
|
|
return;
|
2018-01-23 22:21:20 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-01-12 09:03:41 +00:00
|
|
|
app.use('/api', function (req, res, next) {
|
|
|
|
var auth = (req.headers.authorization || req.query.token || '').split(/\s+/)[1];
|
|
|
|
var token;
|
|
|
|
|
|
|
|
if (!auth) {
|
|
|
|
res.statusCode = 403;
|
|
|
|
res.send({ error: { message: "need authorization" } });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
jwt = jwt || require('jsonwebtoken');
|
|
|
|
try {
|
|
|
|
token = jwt.decode(auth);
|
|
|
|
} catch (e) {
|
|
|
|
token = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!token || !token.iss) {
|
|
|
|
res.statusCode = 403;
|
|
|
|
res.send({ error: { message: "need jwt-format authorization" } });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subparts[0] === token.sub && subparts[1] === token.iss) {
|
|
|
|
try {
|
|
|
|
/*
|
|
|
|
// { algorithm: 'ES256' }
|
|
|
|
{ JsonWebTokenError: invalid algorithm
|
|
|
|
at Object.module.exports [as verify] (digd.js/node_modules/jsonwebtoken/verify.js:90:17)
|
|
|
|
at digd.js/lib/httpd.js:82:15
|
|
|
|
at Layer.handle [as handle_request] (digd.js/node_modules/express/lib/router/layer.js:95:5)
|
|
|
|
at trim_prefix (digd.js/node_modules/express/lib/router/index.js:317:13)
|
|
|
|
at digd.js/node_modules/express/lib/router/index.js:284:7
|
|
|
|
at Function.process_params (digd.js/node_modules/express/lib/router/index.js:335:12)
|
|
|
|
at next (digd.js/node_modules/express/lib/router/index.js:275:10)
|
|
|
|
at expressInit (digd.js/node_modules/express/lib/middleware/init.js:40:5)
|
|
|
|
at Layer.handle [as handle_request] (digd.js/node_modules/express/lib/router/layer.js:95:5)
|
|
|
|
at trim_prefix (digd.js/node_modules/express/lib/router/index.js:317:13) name: 'JsonWebTokenError', message: 'invalid algorithm' }
|
|
|
|
*/
|
|
|
|
// could be that it's private but expecting public, or public but expecting private
|
|
|
|
/*
|
|
|
|
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
|
|
|
|
at Verify.verify (crypto.js:381:23)
|
|
|
|
at verify (digd.js/node_modules/jwa/index.js:68:21)
|
|
|
|
at Object.verify (digd.js/node_modules/jwa/index.js:85:18)
|
|
|
|
at Object.jwsVerify [as verify] (digd.js/node_modules/jws/lib/verify-stream.js:54:15)
|
|
|
|
at Object.module.exports [as verify] (digd.js/node_modules/jsonwebtoken/verify.js:96:17)
|
|
|
|
at digd.js/lib/httpd.js:82:15
|
|
|
|
at Layer.handle [as handle_request] (digd.js/node_modules/express/lib/router/layer.js:95:5)
|
|
|
|
at trim_prefix (digd.js/node_modules/express/lib/router/index.js:317:13)
|
|
|
|
at digd.js/node_modules/express/lib/router/index.js:284:7
|
|
|
|
at Function.process_params (digd.js/node_modules/express/lib/router/index.js:335:12)
|
|
|
|
*/
|
|
|
|
jwt.verify(auth, pubpem, { algorithms: [ 'ES256' ] });
|
|
|
|
} catch(e) {
|
|
|
|
res.statusCode = 403;
|
|
|
|
console.error(e);
|
|
|
|
console.log(auth);
|
|
|
|
console.log(jwt.decode(auth, { complete: true }));
|
|
|
|
res.send({ error: { message: "jwt was not verified authorization" } });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
req.auth = auth;
|
|
|
|
req.token = token;
|
|
|
|
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/api/verify-auth', function (req, res) {
|
|
|
|
res.send({ success: true });
|
|
|
|
});
|
2018-01-10 08:14:05 +00:00
|
|
|
app.get('/api/peers', function (req, res) {
|
2018-01-10 21:54:08 +00:00
|
|
|
engine.peers.all(function (err, peers) {
|
|
|
|
res.send({ peers: peers });
|
|
|
|
});
|
2018-01-10 08:14:05 +00:00
|
|
|
});
|
|
|
|
app.get('/api/zones', function (req, res) {
|
2018-01-10 08:25:56 +00:00
|
|
|
engine.zones.all(function (err, zones) {
|
2018-01-10 08:14:05 +00:00
|
|
|
res.send({ zones: zones });
|
|
|
|
});
|
|
|
|
});
|
2018-01-31 05:03:05 +00:00
|
|
|
app.post('/api/zones', jsonParser, hasClaim('+rw@adns.org'), function (req, res) {
|
|
|
|
var upzone = req.body || {};
|
|
|
|
console.log('create zone', upzone);
|
|
|
|
engine.zones.save(upzone, function (err, zone) {
|
|
|
|
if (err) { res.send({ error: { message: err.message } }); return; }
|
|
|
|
console.log('create zone result', zone);
|
|
|
|
res.send(zone);
|
|
|
|
});
|
|
|
|
});
|
2018-01-10 21:54:08 +00:00
|
|
|
function mapRecord(r) {
|
|
|
|
return {
|
|
|
|
id: r.id
|
|
|
|
, zone: r.zone
|
|
|
|
, name: r.name
|
|
|
|
, tld: r.tld
|
|
|
|
, type: r.type
|
|
|
|
, class: r.class
|
|
|
|
, ttl: r.ttl
|
|
|
|
, data: r.data
|
|
|
|
, address: r.address
|
|
|
|
, exchange: r.exchange
|
|
|
|
, priority: r.priority
|
|
|
|
, value: r.value
|
|
|
|
, aname: r.aname
|
|
|
|
, flag: r.flag
|
|
|
|
, tag: r.tag
|
|
|
|
, weight: r.weight
|
|
|
|
, port: r.port
|
|
|
|
, target: r.target
|
|
|
|
};
|
|
|
|
}
|
|
|
|
app.get('/api/zones/:zone/records', function (req, res) {
|
2018-01-17 08:03:05 +00:00
|
|
|
var zonename = req.params.zone;
|
2018-01-26 08:42:24 +00:00
|
|
|
// [{ name: zonename }]
|
2018-01-17 08:03:05 +00:00
|
|
|
engine.zones.get({ names: [ zonename ] }, function (err, zones) {
|
2018-01-26 08:42:24 +00:00
|
|
|
console.log('zone:');
|
|
|
|
console.log(zones[0]);
|
2018-01-17 08:03:05 +00:00
|
|
|
var zone = engine.zoneToSoa(zones[0]);
|
2018-01-26 08:42:24 +00:00
|
|
|
console.log(zone);
|
2018-01-17 08:03:05 +00:00
|
|
|
zone.class = zone.className;
|
|
|
|
zone.type = zone.typeName;
|
|
|
|
engine.records.all(function (err, records) {
|
|
|
|
records = records.filter(function (r) {
|
|
|
|
return r.zone === zonename;
|
|
|
|
}).map(mapRecord);
|
|
|
|
records.unshift(zone);
|
|
|
|
res.send({ records: records });
|
|
|
|
});
|
2018-01-10 21:54:08 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
app.get('/api/records', function (req, res) {
|
2018-01-10 08:25:56 +00:00
|
|
|
engine.records.all(function (err, records) {
|
2018-01-10 21:54:08 +00:00
|
|
|
res.send({ records: records.map(mapRecord) });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
app.get('/api/records/:name', function (req, res) {
|
|
|
|
engine.records.all(function (err, records) {
|
|
|
|
res.send({ records: records.filter(function (r) {
|
|
|
|
if (r.name === req.params.name) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
var parts = req.params.name.split('.');
|
|
|
|
parts.shift();
|
|
|
|
if ('*.' + parts.join('.') === r.name) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}).map(mapRecord) });
|
2018-01-10 08:14:05 +00:00
|
|
|
});
|
|
|
|
});
|
2018-01-24 10:06:32 +00:00
|
|
|
app.post('/api/records/:id?', jsonParser, hasClaim('+rw@adns.org'), function (req, res) {
|
2018-01-23 22:21:20 +00:00
|
|
|
var record = req.body || {};
|
|
|
|
record.id = req.params.id || record.id;
|
|
|
|
|
|
|
|
if ('SOA' === record.type) {
|
|
|
|
// TODO be strict about what can be edited
|
2018-01-31 05:03:05 +00:00
|
|
|
engine.zones.save(record, function (err, zone) {
|
|
|
|
if (err) {
|
|
|
|
res.send({ error: { message: err.message } });
|
2018-01-29 21:54:03 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-01-31 05:03:05 +00:00
|
|
|
// { success: true }
|
|
|
|
res.send(zone);
|
2018-01-23 22:21:20 +00:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
engine.records.save(record, function (err, record) {
|
2018-01-29 18:35:34 +00:00
|
|
|
res.send({ success: true, id: record.id });
|
2018-01-23 22:21:20 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2018-01-29 21:54:03 +00:00
|
|
|
app.delete('/api/records/:id', jsonParser, hasClaim('+rw@adns.org'), function (req, res) {
|
|
|
|
var id = req.params.id;
|
|
|
|
|
|
|
|
engine.records.one(id, function (err, record) {
|
|
|
|
if (err) {
|
|
|
|
res.send({ error: { message: err.message } });
|
|
|
|
return;
|
|
|
|
}
|
2018-01-29 22:01:10 +00:00
|
|
|
if (!record) {
|
|
|
|
res.send({ error: { message: "no record with id '" + id + "' found" } });
|
|
|
|
return;
|
|
|
|
}
|
2018-01-29 21:54:03 +00:00
|
|
|
|
|
|
|
if ('SOA' === record.type) {
|
|
|
|
// TODO be strict about what can be edited
|
|
|
|
engine.zones.destroy(id, function (err, record) {
|
|
|
|
if (!err) {
|
|
|
|
res.send(record);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
res.send({ error: { message: err.message } });
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
engine.records.destroy(id, function (err, record) {
|
|
|
|
if (!err) {
|
|
|
|
res.send(record || { error: { message: "no record with id '" + id + "' found" } });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
res.send({ error: { message: err.message } });
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2018-01-10 08:14:05 +00:00
|
|
|
|
2018-01-12 09:03:41 +00:00
|
|
|
app.use('/', express.static(path.join(__dirname, 'public')));
|
|
|
|
|
2018-01-10 08:25:56 +00:00
|
|
|
httpServer.listen(cli.http, function () {
|
2018-01-24 10:06:32 +00:00
|
|
|
console.info(httpServer.address().address + '#' + httpServer.address().port + ' (http)');
|
2018-01-10 08:25:56 +00:00
|
|
|
});
|
2018-01-10 08:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
runHttp();
|
|
|
|
|
|
|
|
};
|