update existing records

This commit is contained in:
AJ ONeal 2018-01-26 01:42:24 -07:00
parent 77e3096cd3
commit 77b69d59a1
4 changed files with 182 additions and 47 deletions

View File

@ -100,7 +100,8 @@ module.exports.create = function (cli, engine/*, dnsd*/) {
})) { })) {
next(); next();
} else { } else {
next(new Error("no claim to '" + claim + "' in token")); res.send({ error: { message: "no claim to '" + claim + "' in token" } });
return;
} }
}; };
} }
@ -212,8 +213,12 @@ module.exports.create = function (cli, engine/*, dnsd*/) {
} }
app.get('/api/zones/:zone/records', function (req, res) { app.get('/api/zones/:zone/records', function (req, res) {
var zonename = req.params.zone; var zonename = req.params.zone;
// [{ name: zonename }]
engine.zones.get({ names: [ zonename ] }, function (err, zones) { engine.zones.get({ names: [ zonename ] }, function (err, zones) {
console.log('zone:');
console.log(zones[0]);
var zone = engine.zoneToSoa(zones[0]); var zone = engine.zoneToSoa(zones[0]);
console.log(zone);
zone.class = zone.className; zone.class = zone.className;
zone.type = zone.typeName; zone.type = zone.typeName;
engine.records.all(function (err, records) { engine.records.all(function (err, records) {
@ -251,7 +256,7 @@ module.exports.create = function (cli, engine/*, dnsd*/) {
if ('SOA' === record.type) { if ('SOA' === record.type) {
// TODO be strict about what can be edited // TODO be strict about what can be edited
engine.records.save(record, function (err, record) { engine.zones.save(record, function (err, record) {
res.send({ success: true }); res.send({ success: true });
}); });
} else { } else {

View File

@ -117,30 +117,30 @@
<label>Select Type:</label> <label>Select Type:</label>
<select class="js-record-form-type"> <select class="js-record-form-type">
<option value="" selected disabled>Record Type</option> <option value="" selected disabled>Record Type</option>
<option value="soa">SOA</option> <option value="SOA">SOA</option>
<option value="ns">NS</option> <option value="NS">NS</option>
<option value="a">A</option> <option value="A">A</option>
<option value="aaaa">AAAA</option> <option value="AAAA">AAAA</option>
<option value="aname">ANAME</option> <option value="ANAME">ANAME</option>
<option value="cname">CNAME</option> <option value="CNAME">CNAME</option>
<option value="caa">CAA</option> <option value="CAA">CAA</option>
<option value="mx">MX</option> <option value="MX">MX</option>
<option value="ptr">PTR</option> <option value="PTR">PTR</option>
<option value="srv">SRV</option> <option value="SRV">SRV</option>
<option value="txt">TXT</option> <option value="TXT">TXT</option>
<option value="typex">typeX</option> <option value="typeX">typeX</option>
</select> </select>
<div class="js-record-form-tpl"> <div class="js-record-form-tpl">
<form class="js-record-form-soa"> <form class="js-record-form-soa">
<input type="hidden" class="js-record-id" /> <input type="hidden" class="js-record-id" />
<span class="js-record-type">SOA</span> <span class="js-record-type">SOA</span>
<input type="text" class="js-record-host">.<span class="js-record-zone">example.com</span> <input type="text" class="js-record-name">
<input type="text" class="js-record-primary"> <input type="text" class="js-record-primary">
<input type="text" class="js-record-admin"> <input type="text" class="js-record-admin">
<input type="text" class="js-record-expiration"> <input type="text" class="js-record-expiration">
<input type="text" class="js-record-minimum"> <input type="text" class="js-record-minimum">
<input type="text" class="js-record-serial"> <input type="text" class="js-record-serial" disabled>
<input type="text" class="js-record-retry"> <input type="text" class="js-record-retry">
<input type="text" class="js-record-refresh"> <input type="text" class="js-record-refresh">
<input type="text" class="js-record-ttl"> <input type="text" class="js-record-ttl">
@ -150,8 +150,8 @@
<input type="hidden" class="js-record-id" /> <input type="hidden" class="js-record-id" />
<span class="js-record-type">A / AAAA</span> <span class="js-record-type">A / AAAA</span>
<input type="text" class="js-record-host">.<span class="js-record-zone">example.com</span> <input type="text" class="js-record-host">.<span class="js-record-zone">example.com</span>
<input type="text" class="js-record-address"> <input type="text" class="js-record-address" placeholder="ex: 127.0.0.1">
<input type="text" class="js-record-ttl"> <input type="text" class="js-record-ttl" placeholder="ex: 300">
<button type="button" class="js-record-save">save</button> <button type="button" class="js-record-save">save</button>
</form> </form>
<form class="js-record-form-aname js-record-form-cname js-record-form-ns"> <form class="js-record-form-aname js-record-form-cname js-record-form-ns">

View File

@ -2,6 +2,8 @@
'use strict'; 'use strict';
var cache = { recordsMap: {} }; var cache = { recordsMap: {} };
var myZone;
window.ADNS = { cache: cache, $qs: $qs };
if (!Element.prototype.matches) { if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector; Element.prototype.matches = Element.prototype.msMatchesSelector;
@ -152,8 +154,7 @@
console.log(tpls.recordsMap); console.log(tpls.recordsMap);
cache.records.forEach(function (record) { cache.records.forEach(function (record) {
el = document.createElement('div'); el = document.createElement('div');
console.log('record.type:'); console.log('record.type:', record.type);
console.log(record.type);
el.innerHTML = tpls.recordsMap[record.type.toLowerCase()]; el.innerHTML = tpls.recordsMap[record.type.toLowerCase()];
console.log(el); console.log(el);
console.log($qs('.js-record-name', el)); console.log($qs('.js-record-name', el));
@ -220,62 +221,74 @@
$on('button.js-zone-name', 'click', function (ev) { $on('button.js-zone-name', 'click', function (ev) {
var zone = ev.target.dataset.name; var zone = ev.target.dataset.name;
myZone = zone;
return fetchRecords(zone);/*.then(function () { return fetchRecords(zone);/*.then(function () {
});*/ });*/
}); });
$on('select.js-record-form-type', 'change', function (ev) { $on('select.js-record-form-type', 'change', function (ev) {
var type = ev.target.value; var type = ev.target.value;
var $tpl;
console.log("form type:", type); console.log("form type:", type);
if (!tpls.formsMap) { if (!tpls.formsMap) {
tpls.formsMap = {}; tpls.formsMap = {};
tpls.formsMap.soa = $qs('.js-record-form-soa').outerHTML; tpls.formsMap.SOA = $qs('.js-record-form-soa').outerHTML;
tpls.formsMap.ns = $qs('.js-record-form-ns').outerHTML; tpls.formsMap.NS = $qs('.js-record-form-ns').outerHTML;
tpls.formsMap.a = $qs('.js-record-form-a').outerHTML; tpls.formsMap.A = $qs('.js-record-form-a').outerHTML;
tpls.formsMap.aaaa = $qs('.js-record-form-aaaa').outerHTML; tpls.formsMap.AAAA = $qs('.js-record-form-aaaa').outerHTML;
tpls.formsMap.aname = $qs('.js-record-form-aname').outerHTML; tpls.formsMap.ANAME = $qs('.js-record-form-aname').outerHTML;
tpls.formsMap.caa = $qs('.js-record-form-caa').outerHTML; tpls.formsMap.CAA = $qs('.js-record-form-caa').outerHTML;
tpls.formsMap.cname = $qs('.js-record-form-cname').outerHTML; tpls.formsMap.CNAME = $qs('.js-record-form-cname').outerHTML;
tpls.formsMap.mx = $qs('.js-record-form-mx').outerHTML; tpls.formsMap.MX = $qs('.js-record-form-mx').outerHTML;
tpls.formsMap.ptr = $qs('.js-record-form-ptr').outerHTML; tpls.formsMap.PTR = $qs('.js-record-form-ptr').outerHTML;
tpls.formsMap.srv = $qs('.js-record-form-srv').outerHTML; tpls.formsMap.SRV = $qs('.js-record-form-srv').outerHTML;
tpls.formsMap.txt = $qs('.js-record-form-txt').outerHTML; tpls.formsMap.TXT = $qs('.js-record-form-txt').outerHTML;
tpls.formsMap.typex = $qs('.js-record-form-typex').outerHTML; tpls.formsMap.typeX = $qs('.js-record-form-typex').outerHTML;
} }
$qs('.js-record-form-tpl').innerHTML = tpls.formsMap[type] || ''; $tpl = $qs('.js-record-form-tpl');
$tpl.innerHTML = tpls.formsMap[type] || '';
$qs('.js-record-type', $tpl).innerText = type;
$qs('.js-record-zone', $tpl).innerText = myZone;
}); });
$on('button.js-record-edit', 'click', function (ev) { $on('button.js-record-edit', 'click', function (ev) {
var id = ev.target.parentElement.querySelector('.js-record-id').value; var id = ev.target.parentElement.querySelector('.js-record-id').value;
var record = cache.recordsMap[id]; var record = cache.recordsMap[id];
var formTpl = tpls.formsMap[record.type.toLowerCase()]; var formTpl = tpls.formsMap[record.type];
var $tpl;
if (!formTpl) { if (!formTpl) {
formTpl = tpls.formsMap.typex; formTpl = tpls.formsMap.typeX;
} }
console.log(ev.target); console.log(ev.target);
console.log(id); console.log(id);
console.log(record); console.log(record);
formTpl = tpls.formsMap[(record.type||'typex').toLowerCase()]; formTpl = tpls.formsMap[(record.type||'typeX')];
$qs('select.js-record-form-type').value = (record.type||'typex').toLowerCase(); $qs('select.js-record-form-type').value = (record.type||'typeX');
$qs('select.js-record-form-type').dispatchEvent(new Event('change', { bubbles: true })); $qs('select.js-record-form-type').dispatchEvent(new Event('change', { bubbles: true }));
$qs('.js-record-form-tpl').innerHTML = formTpl || ''; $tpl = $qs('.js-record-form-tpl');
$tpl.innerHTML = formTpl || '';
record.host = record.name.replace(new RegExp('\\.?' + (record.zone || record.name).replace(/\./g, '\\.') + '$'), ''); record.host = record.name.replace(new RegExp('\\.?' + (record.zone || record.name).replace(/\./g, '\\.') + '$'), '');
console.log('record.type:'); console.log('record.type:');
console.log(record.type.toLowerCase()); console.log(record.type);
Object.keys(record).forEach(function (key) { Object.keys(record).forEach(function (key) {
var $el = $qs('.js-record-' + key, $qs('.js-record-form-tpl')); var $el = $qs('.js-record-' + key, $tpl);
if (!$el) { if (!$el) {
return; return;
} }
$el.value = record[key]; $el.value = record[key];
}); });
if (!record.host) { $qs('.js-record-host').placeholder = '@'; } if ('SOA' === record.type) {
$qs('.js-record-type', $qs('.js-record-form-tpl')).innerHTML = record.type; $qs('.js-record-name').disabled = 'disabled';
} else {
if (!record.host) { $qs('.js-record-host', $tpl).placeholder = '@'; }
}
$qs('.js-record-type', $tpl).innerHTML = record.type;
$qs('.js-record-zone', $tpl).innerText = myZone;
}); });
$on('button.js-record-save', 'click', function (ev) { $on('button.js-record-save', 'click', function (ev) {
@ -302,6 +315,16 @@
if (!record.id) { if (!record.id) {
record.id = ''; record.id = '';
} }
if (!record.zone) {
record.zone = myZone;
}
if (!record.name) {
if (record.host) {
record.name = record.host + '.' + myZone;
} else {
record.name = myZone;
}
}
record.type = record.type || $qs('.js-record-type', $pel).innerHTML || $qs('.js-record-type', $pel).value; record.type = record.type || $qs('.js-record-type', $pel).innerHTML || $qs('.js-record-type', $pel).value;
console.log('record.type:', record.type); console.log('record.type:', record.type);
@ -318,7 +341,8 @@
} else { } else {
console.log('keys:', Object.keys(record)); console.log('keys:', Object.keys(record));
Object.keys(record).forEach(function (key) { Object.keys(record).forEach(function (key) {
console.log(key); console.log('key:', key);
//if ('SOA' === record.type && 'zone' === key) { return; }
if (existingRecord[key].toString() !== record[key].toString()) { if (existingRecord[key].toString() !== record[key].toString()) {
change = true; change = true;
existingRecord[key] = record[key]; existingRecord[key] = record[key];
@ -340,6 +364,11 @@
} }
).then(function (resp) { ).then(function (resp) {
return resp.json().then(function (data) { return resp.json().then(function (data) {
if (data.error) {
console.error(data);
window.alert(data.error.message);
return;
}
console.log('result:', data); console.log('result:', data);
}); });
}); });

View File

@ -5,6 +5,7 @@ module.exports.create = function (opts) {
var engine = { db: null }; var engine = { db: null };
var db = require(opts.filepath); var db = require(opts.filepath);
var stat = require('fs').statSync(opts.filepath);
var crypto = require('crypto'); var crypto = require('crypto');
db.primaryNameservers.forEach(function (ns) { db.primaryNameservers.forEach(function (ns) {
if (!ns.id) { if (!ns.id) {
@ -19,6 +20,8 @@ module.exports.create = function (opts) {
if (!zone.id) { if (!zone.id) {
zone.id = crypto.randomBytes(16).toString('hex'); zone.id = crypto.randomBytes(16).toString('hex');
} }
if (!zone.createdAt) { zone.createdAt = stat.mtime.valueOf(); }
if (!zone.updatedAt) { zone.updatedAt = stat.mtime.valueOf(); }
}); });
db.records.forEach(function (record) { db.records.forEach(function (record) {
if (!record.id) { if (!record.id) {
@ -57,7 +60,8 @@ module.exports.create = function (opts) {
var index = Math.floor(Math.random() * nameservers.length) % nameservers.length; var index = Math.floor(Math.random() * nameservers.length) % nameservers.length;
var nameserver = nameservers[index]; var nameserver = nameservers[index];
return { return {
name: domain.name id: domain.id
, name: domain.name
, typeName: 'SOA' , typeName: 'SOA'
, className: 'IN' , className: 'IN'
, ttl: domain.ttl || 60 , ttl: domain.ttl || 60
@ -119,6 +123,70 @@ module.exports.create = function (opts) {
cb(null, myDomains); cb(null, myDomains);
}); });
} }
, touch: function (zone, cb) {
var existing;
db.zones.some(function (z) {
if (z.id && zone.id === z.id) { existing = z; return true; }
if (z.name && zone.name === z.name) { existing = z; return true; }
});
if (!existing) {
cb(null, null);
return;
}
existing.updatedAt = new Date().valueOf(); // toISOString();
console.log('touch saving...');
db.save(function (err) {
cb(err, !err && existing || null);
});
}
, save: function (zone, cb) {
if (zone.id) {
console.log('update zone!');
engine.zones.update(zone, cb);
} else {
engine.zones.create(zone, cb);
}
}
, update: function (zone, cb) {
var existing;
var dirty;
db.zones.some(function (z) {
if (z.id === zone.id) {
existing = z;
return true;
}
});
if (!existing) {
console.log('no existing zone');
cb(new Error("zone for '" + zone.id + "' does not exist"), null);
return;
}
console.log('found existing zone');
console.log(existing);
console.log(zone);
Object.keys(zone).forEach(function (key) {
var keys = [ 'name', 'id', 'revokedAt', 'changedAt', 'insertedAt', 'updatedAt', 'deletedAt' ];
if (-1 !== keys.indexOf(key)) { return; }
if (existing[key] !== zone[key]) {
dirty = true;
console.log('existing key', key, existing[key], zone[key]);
existing[key] = zone[key];
}
});
zone.updatedAt = new Date().valueOf(); // toISOString(); // Math.round(Date.now() / 1000);
if (dirty) {
zone.changedAt = zone.updatedAt;
}
console.log('saving...');
db.save(function (err) {
cb(err, !err && existing || null);
});
}
}; };
engine.records = { engine.records = {
all: function (cb) { all: function (cb) {
@ -144,11 +212,17 @@ module.exports.create = function (opts) {
}); });
} }
, save: function (record, cb) { , save: function (record, cb) {
function touchZone(err, r) {
if (err) { cb(err); }
if (!r) { cb(null, null); }
engine.zones.touch({ name: r.zone }, cb);
}
if (record.id) { if (record.id) {
console.log('update record!'); console.log('update record!');
engine.records.update(record, cb); engine.records.update(record, touchZone);
} else { } else {
engine.records.create(record, cb); engine.records.create(record, touchZone);
} }
} }
, update: function (record, cb) { , update: function (record, cb) {
@ -172,6 +246,8 @@ module.exports.create = function (opts) {
console.log(existing); console.log(existing);
console.log(record); console.log(record);
Object.keys(record).forEach(function (key) { Object.keys(record).forEach(function (key) {
var keys = [ 'name', 'id', 'zone', 'revokedAt', 'changedAt', 'insertedAt', 'updatedAt', 'deletedAt' ];
if (-1 !== keys.indexOf(key)) { return; }
if (existing[key] !== record[key]) { if (existing[key] !== record[key]) {
dirty = true; dirty = true;
console.log(existing[key], record[key]); console.log(existing[key], record[key]);
@ -179,7 +255,7 @@ module.exports.create = function (opts) {
} }
}); });
record.updatedAt = new Date().toISOString(); // Math.round(Date.now() / 1000); record.updatedAt = new Date().valueOf(); // toISOString(); // Math.round(Date.now() / 1000);
if (dirty) { if (dirty) {
record.changedAt = record.updatedAt; record.changedAt = record.updatedAt;
} }
@ -189,6 +265,31 @@ module.exports.create = function (opts) {
cb(err, !err && existing || null); cb(err, !err && existing || null);
}); });
} }
, create: function (record, cb) {
var obj = { id: crypto.randomBytes(16).toString('hex') };
console.log('found existing record');
console.log(record);
//var keys = [ 'name', 'id', 'zone', 'revokedAt', 'changedAt', 'insertedAt', 'updatedAt', 'deletedAt' ];
//var okeys = [ 'name', 'zone', 'admin', 'data', 'expiration', 'minimum', 'serial', 'retry', 'refresh', 'ttl', 'type' ]; // primary
var okeys = [ 'name', 'zone', 'type', 'data', 'class', 'ttl', 'address'
, 'exchange', 'priority', 'port', 'value', 'tag', 'flag', 'aname' ];
okeys.forEach(function (key) {
if ('undefined' !== typeof record[key]) {
obj[key] = record[key];
}
});
record.updatedAt = new Date().valueOf(); // toISOString(); // Math.round(Date.now() / 1000);
//record.changedAt = record.updatedAt;
record.insertedAt = record.updatedAt;
record.createdAt = record.updatedAt;
console.log('saving new...');
db.records.push(record);
db.save(function (err) {
cb(err, record);
});
}
}; };
return engine; return engine;