diff --git a/lib/digd.js b/lib/digd.js index 309cebb..63c797b 100644 --- a/lib/digd.js +++ b/lib/digd.js @@ -187,7 +187,7 @@ function getNs(engine, zs, results, cb) { return -1 !== engine.primaryNameservers.indexOf(ns.data.toLowerCase()); })) { results.authority.length = 0; - results.authority.push(engine.zoneToSoa(z)); + results.authority.push(engine.zones._toSoa(z)); results.header.rcode = NXDOMAIN; } cb(null, results); @@ -199,9 +199,9 @@ function getSoa(engine, domain, results, cb, answerSoa) { console.log('[DEV] getSoa entered'); if (!answerSoa) { - results.authority.push(engine.zoneToSoa(domain)); + results.authority.push(engine.zones._toSoa(domain)); } else { - results.answer.push(engine.zoneToSoa(domain)); + results.answer.push(engine.zones._toSoa(domain)); } cb(null, results); diff --git a/lib/httpd.js b/lib/httpd.js index e04ad67..3218ff3 100644 --- a/lib/httpd.js +++ b/lib/httpd.js @@ -189,6 +189,14 @@ module.exports.create = function (cli, engine/*, dnsd*/) { res.send(zone); }); }); + app.delete('/api/zones/:id', hasClaim('+rw@adns.org'), function (req, res) { + var zoneId = req.params.id; + engine.zones.destroy(zoneId, function (err, zone) { + if (err) { res.send({ error: { message: err.message } }); return; } + // zone + records + res.send(zone); + }); + }); function mapRecord(r) { return { id: r.id @@ -217,8 +225,7 @@ module.exports.create = function (cli, engine/*, dnsd*/) { engine.zones.get({ names: [ zonename ] }, function (err, zones) { console.log('zone:'); console.log(zones[0]); - var zone = engine.zoneToSoa(zones[0]); - console.log(zone); + var zone = engine.zones._toSoa(zones[0]); zone.class = zone.className; zone.type = zone.typeName; engine.records.all(function (err, records) { diff --git a/lib/public/js/app.js b/lib/public/js/app.js index a1652b4..788a071 100644 --- a/lib/public/js/app.js +++ b/lib/public/js/app.js @@ -225,7 +225,48 @@ $qs('a.js-name').href = $qs('a.js-name').dataset.href.replace(/:name/, ev.target.value || ':name'); }); + $on('button.js-zone-destroy', 'click', function (ev) { + var zoneId = ev.target.parentElement.dataset.id; + var zoneName = ev.target.parentElement.dataset.name; + if (!window.confirm("Remove zone '" + zoneName + "' and all associated records?")) { + return; + } + + return window.fetch( + '/api/zones/' + zoneId + , { method: 'DELETE' + , headers: new window.Headers({ + 'Authorization': 'Bearer ' + auth + , 'Content-Type': 'application/json;charset=UTF-8' + }) + } + ).then(function (resp) { + return resp.json().then(function (data) { + var zone; + if (data.error) { + console.error(data); + window.alert(data.error.message); + return; + } + console.log('zone undo data:'); + console.log(data); + zone = cache.recordsMap[zoneId]; + delete cache.recordsMap[zoneId]; + function removeRecord(r, i) { + if (r.zone === zone.name) { + cache.records.splice(i, 1); + return true; + } + } + while (cache.records.some(removeRecord)) { continue; } + + renderZones(); + renderRecords(); + console.log('result:', data); + }); + }); + }); $on('button.js-zone-view', 'click', function (ev) { var zone = ev.target.parentElement.dataset.name; myZone = zone; diff --git a/lib/store.json.js b/lib/store.json.js index 225b3c4..9777b0e 100644 --- a/lib/store.json.js +++ b/lib/store.json.js @@ -73,47 +73,6 @@ module.exports.create = function (opts) { db.save._pending = []; engine.primaryNameservers = db.primaryNameservers; - engine.zoneToSoa = function (domain) { - var nameservers = domain.vanityNs || engine.primaryNameservers.map(function (n) { return n.name; }); - - var index = Math.floor(Math.random() * nameservers.length) % nameservers.length; - var nameserver = nameservers[index]; - return { - id: domain.id - , name: domain.name - , typeName: 'SOA' - , className: 'IN' - , ttl: domain.ttl || 60 - - // nameserver -- select an NS at random if they're all in sync - , primary: nameserver - , name_server: nameserver - - // admin -- email address or domain for admin - , admin: domain.admin || ('admin.' + domain.name) - , email_addr: domain.admin || ('admin.' + domain.name) - - // serial -- the version, for cache-busting of secondary nameservers. suggested format: YYYYMMDDnn - , serial: domain.serial || engine.zones._dateToSerial(domain.updatedAt || domain.createdAt || Date.now()) - , sn: domain.serial || engine.zones._dateToSerial(domain.updatedAt || domain.createdAt || Date.now()) - - // refresh -- only used when nameservers following the DNS NOTIFY spec talk - , refresh: domain.refresh || 1800 - , ref: domain.refresh || 1800 - - // retry -- only used when nameservers following the DNS NOTIFY spec talk - , retry: domain.retry || 600 - , ret: domain.retry || 600 - - // expiration -- how long other nameservers should continue when the primary goes down - , expiration: domain.expiration || 2419200 // 4 weeks - , ex: domain.expiration || 2419200 // 4 weeks - - // minimum -- how long to cache a non-existent domain (also the default ttl for BIND) - , minimum: domain.minimum || 5 - , nx: domain.minimum || 5 - }; - }; engine.peers = { all: function (cb) { var dns = require('dns'); @@ -146,6 +105,47 @@ module.exports.create = function (opts) { // epoch in seconds will do return parseInt(Math.round(date/1000).toString().slice(-10), 10); } + , _toSoa: function (domain) { + var nameservers = domain.vanityNs || engine.primaryNameservers.map(function (n) { return n.name; }); + + var index = Math.floor(Math.random() * nameservers.length) % nameservers.length; + var nameserver = nameservers[index]; + return { + id: domain.id + , name: domain.name + , typeName: 'SOA' + , className: 'IN' + , ttl: domain.ttl || 60 + + // nameserver -- select an NS at random if they're all in sync + , primary: nameserver + , name_server: nameserver + + // admin -- email address or domain for admin + , admin: domain.admin || ('admin.' + domain.name) + , email_addr: domain.admin || ('admin.' + domain.name) + + // serial -- the version, for cache-busting of secondary nameservers. suggested format: YYYYMMDDnn + , serial: domain.serial || engine.zones._dateToSerial(domain.updatedAt || domain.createdAt || Date.now()) + , sn: domain.serial || engine.zones._dateToSerial(domain.updatedAt || domain.createdAt || Date.now()) + + // refresh -- only used when nameservers following the DNS NOTIFY spec talk + , refresh: domain.refresh || 1800 + , ref: domain.refresh || 1800 + + // retry -- only used when nameservers following the DNS NOTIFY spec talk + , retry: domain.retry || 600 + , ret: domain.retry || 600 + + // expiration -- how long other nameservers should continue when the primary goes down + , expiration: domain.expiration || 2419200 // 4 weeks + , ex: domain.expiration || 2419200 // 4 weeks + + // minimum -- how long to cache a non-existent domain (also the default ttl for BIND) + , minimum: domain.minimum || 5 + , nx: domain.minimum || 5 + }; + } , all: function (cb) { process.nextTick(function () { cb(null, db.zones.slice(0).filter(notDeleted)); @@ -307,11 +307,41 @@ module.exports.create = function (opts) { db.records.push(ns); }); - console.log('saving...'); + console.log('[zone] [create] saving...'); db.save(function (err) { cb(err, !err && newZone || null); }); } + , destroy: function (zoneId, cb) { + var zone; + var records; + db.zones.filter(notDeleted).some(function (z) { + if (zoneId === z.id) { + zone = z; + return true; + } + }); + + if (!zone) { + process.nextTick(function () { + cb(null, null); + }); + return; + } + + records = []; + db.records.filter(notDeleted).forEach(function (r) { + if (zone.name === r.zone) { + records.push(r); + } + }); + + console.log('[zone] [destroy] saving...'); + db.save(function (err) { + zone.records = records; + cb(err, !err && zone || null); + }); + } }; engine.records = { all: function (cb) {