|
|
|
@ -1,15 +1,16 @@ |
|
|
|
|
const db = require('../db.js'); |
|
|
|
|
const redis = require('../redis.js'); |
|
|
|
|
const url = require('url'); |
|
|
|
|
const { isIPv4, isIPv6 } = require('net'); |
|
|
|
|
const { dynamicResponse } = require('../util.js'); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* GET /dns/:domain |
|
|
|
|
* domains page |
|
|
|
|
* domains records page |
|
|
|
|
*/ |
|
|
|
|
exports.dnsDomainPage = async (app, req, res) => { |
|
|
|
|
if (!res.locals.user.domains.includes(req.params.domain)) { |
|
|
|
|
return res.redirect('/domains'); |
|
|
|
|
return dynamicResponse(req, res, 302, { redirect: '/domains' }); |
|
|
|
|
} |
|
|
|
|
const recordSetsRaw = await redis.hgetall(`${req.params.domain}.`); |
|
|
|
|
const recordSets = recordSetsRaw && Object.keys(recordSetsRaw) |
|
|
|
@ -24,11 +25,11 @@ exports.dnsDomainPage = async (app, req, res) => { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* GET /dns/:domain/:zone/:type |
|
|
|
|
* domains page |
|
|
|
|
* record set page |
|
|
|
|
*/ |
|
|
|
|
exports.dnsRecordPage = async (app, req, res) => { |
|
|
|
|
if (!res.locals.user.domains.includes(req.params.domain)) { |
|
|
|
|
return res.redirect('/domains'); |
|
|
|
|
return dynamicResponse(req, res, 302, { redirect: '/domains' }); |
|
|
|
|
} |
|
|
|
|
let recordSet = [{}]; |
|
|
|
|
if (req.params.zone && req.params.type) { |
|
|
|
@ -44,7 +45,7 @@ exports.dnsRecordPage = async (app, req, res) => { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* GET /dns/:domain.json |
|
|
|
|
* domains json data |
|
|
|
|
* domain record json |
|
|
|
|
*/ |
|
|
|
|
exports.dnsDomainJson = async (req, res) => { |
|
|
|
|
if (!res.locals.user.domains.includes(req.params.domain)) { |
|
|
|
@ -64,7 +65,7 @@ exports.dnsDomainJson = async (req, res) => { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* GET /dns/:domain/:zone/:type.json |
|
|
|
|
* domains json data |
|
|
|
|
* record set json |
|
|
|
|
*/ |
|
|
|
|
exports.dnsRecordJson = async (req, res) => { |
|
|
|
|
if (!res.locals.user.domains.includes(req.params.domain)) { |
|
|
|
@ -84,34 +85,111 @@ exports.dnsRecordJson = async (req, res) => { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* POST /post/:domain/:zone/:type/delete |
|
|
|
|
* delete record |
|
|
|
|
*/ |
|
|
|
|
exports.dnsRecordDelete = async (req, res) => { |
|
|
|
|
if (!res.locals.user.domains.includes(req.params.domain)) { |
|
|
|
|
return dynamicResponse(req, res, 302, { redirect: '/domains' }); |
|
|
|
|
} |
|
|
|
|
if (req.params.zone && req.params.type) { |
|
|
|
|
const recordSetRaw = await redis.hget(`${req.params.domain}.`, req.params.zone); |
|
|
|
|
if (!recordSetRaw) { |
|
|
|
|
recordSetRaw = {}; |
|
|
|
|
} |
|
|
|
|
delete recordSetRaw[req.params.type]; |
|
|
|
|
await redis.hset(`${req.params.domain}.`, req.params.zone, recordSetRaw); |
|
|
|
|
} |
|
|
|
|
return dynamicResponse(req, res, 302, { redirect: `/dns/${req.params.domain}` }); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* POST /post/:domain/:zone/:type |
|
|
|
|
* domains json data |
|
|
|
|
* add/update record |
|
|
|
|
*/ |
|
|
|
|
exports.dnsRecordUpdate = async (req, res) => { |
|
|
|
|
if (!res.locals.user.domains.includes(req.params.domain)) { |
|
|
|
|
return dynamicResponse(req, res, 403, { error: 'No permission for this domain' }); |
|
|
|
|
} |
|
|
|
|
const { ttl, selection } = req.body; |
|
|
|
|
if (Object.values(req.body).some(v => typeof v !== "string")) { |
|
|
|
|
return dynamicResponse(req, res, 400, { error: 'Invalid input' }); |
|
|
|
|
} |
|
|
|
|
let { ttl, selection } = req.body; |
|
|
|
|
const { domain, zone, type } = req.params; |
|
|
|
|
const records = []; |
|
|
|
|
for (let i = 0; i < 100; i++) { |
|
|
|
|
const { |
|
|
|
|
[`id_${i}`]: id, |
|
|
|
|
for (let i = 0; i < (type == "soa" ? 1 : 100); i++) { |
|
|
|
|
let { |
|
|
|
|
[`value_${i}`]: value, |
|
|
|
|
[`health_${i}`]: h, |
|
|
|
|
//geo
|
|
|
|
|
[`geok_${i}`]: geok, |
|
|
|
|
[`geov_${i}`]: geov, |
|
|
|
|
[`pref_${i}`]: preference, |
|
|
|
|
[`port_${i}`]: port, |
|
|
|
|
//health
|
|
|
|
|
[`id_${i}`]: id, |
|
|
|
|
[`health_${i}`]: h, |
|
|
|
|
[`fallbacks_${i}`]: fb, |
|
|
|
|
[`sel_${i}`]: sel, |
|
|
|
|
[`bsel_${i}`]: bsel, |
|
|
|
|
[`pref_${i}`]: preference, |
|
|
|
|
//other (numbers)
|
|
|
|
|
[`weight_${i}`]: weight, |
|
|
|
|
[`priority_${i}`]: priority, |
|
|
|
|
[`flag_${i}`]: flag, |
|
|
|
|
[`refresh_${i}`]: refresh, |
|
|
|
|
[`retry_${i}`]: retry, |
|
|
|
|
[`expire_${i}`]: expire, |
|
|
|
|
//other
|
|
|
|
|
[`tag_${i}`]: tag, |
|
|
|
|
[`mbox_${i}`]: MBox, |
|
|
|
|
} = req.body; |
|
|
|
|
if (!value) { break; } |
|
|
|
|
try { |
|
|
|
|
if (geok && !["cn", "cc"].includes(geok) |
|
|
|
|
|| sel && !["0", "1", "2", "3"].includes(sel) |
|
|
|
|
|| bsel && !["0", "1", "2", "3"].includes(bsel) |
|
|
|
|
|| flag && (isNaN(flag) || parseInt(flag) !== +flag) |
|
|
|
|
|| ttl && (isNaN(ttl) || parseInt(ttl) !== +ttl) |
|
|
|
|
|| preference && (isNaN(preference) || parseInt(preference) !== +preference) |
|
|
|
|
|| port && (isNaN(port) || parseInt(port) !== +port) |
|
|
|
|
|| weight && (isNaN(weight) || parseInt(weight) !== +weight) |
|
|
|
|
|| priority && (isNaN(priority) || parseInt(priority) !== +priority) |
|
|
|
|
|| refresh && (isNaN(refresh) || parseInt(refresh) !== +refresh) |
|
|
|
|
|| retry && (isNaN(retry) || parseInt(retry) !== +retry) |
|
|
|
|
|| expire && (isNaN(expire) || parseInt(expire) !== +expire)) { |
|
|
|
|
return dynamicResponse(req, res, 400, { error: 'Invalid input' }); |
|
|
|
|
} |
|
|
|
|
flag && (flag = parseInt(flag)); |
|
|
|
|
ttl && (ttl = parseInt(ttl)); |
|
|
|
|
preference && (preference = parseInt(preference)); |
|
|
|
|
port && (port = parseInt(port)); |
|
|
|
|
weight && (weight = parseInt(weight)); |
|
|
|
|
priority && (priority = parseInt(priority)); |
|
|
|
|
refresh && (refresh = parseInt(refresh)); |
|
|
|
|
retry && (retry = parseInt(retry)); |
|
|
|
|
expire && (expire = parseInt(expire)); |
|
|
|
|
sel && (sel = parseInt(sel)); |
|
|
|
|
bsel && (bsel = parseInt(bsel)); |
|
|
|
|
h && (h = (h != null ? true : false)); |
|
|
|
|
geov && (geov = geov.split(',').map(x => x.trim())); |
|
|
|
|
fb && (fb = fb.split(',').map(x => x.trim())); |
|
|
|
|
} catch(e) { |
|
|
|
|
console.error(e); |
|
|
|
|
return dynamicResponse(req, res, 400, { error: 'Invalid input' }); |
|
|
|
|
} |
|
|
|
|
let record; |
|
|
|
|
switch(type) { |
|
|
|
|
case "a": |
|
|
|
|
if (!isIPv4(value)) { |
|
|
|
|
return dynamicResponse(req, res, 400, { error: 'Invalid input' }); |
|
|
|
|
} |
|
|
|
|
record = { ttl, id, ip: value, geok, geov, h, sel, bsel, fb }; |
|
|
|
|
break; |
|
|
|
|
case "aaaa": |
|
|
|
|
record = { ttl, id, ip: value, geok, geov, h, geok, geov, sel, bsel }; |
|
|
|
|
if (!isIPv6(value)) { |
|
|
|
|
return dynamicResponse(req, res, 400, { error: 'Invalid input' }); |
|
|
|
|
} |
|
|
|
|
record = { ttl, id, ip: value, geok, geov, h, sel, bsel, fb }; |
|
|
|
|
break; |
|
|
|
|
case "txt": |
|
|
|
|
record = { ttl, text: value }; |
|
|
|
@ -121,23 +199,34 @@ exports.dnsRecordUpdate = async (req, res) => { |
|
|
|
|
record = { ttl, host: value }; |
|
|
|
|
break; |
|
|
|
|
case "mx": |
|
|
|
|
record = { ttl, host: value, preference }; //TODO: preference
|
|
|
|
|
record = { ttl, host: value, preference }; |
|
|
|
|
break; |
|
|
|
|
case "srv": |
|
|
|
|
record = { ttl, target: value, preference, port, weight, priority }; //TODO: preference, port, weight, prio
|
|
|
|
|
record = { ttl, target: value, port, weight, priority }; |
|
|
|
|
break; |
|
|
|
|
case "caa": |
|
|
|
|
record = { ttl, value, flag, tag }; //TODO: flag, tag
|
|
|
|
|
record = { ttl, value, flag, tag }; |
|
|
|
|
break; |
|
|
|
|
case "soa": |
|
|
|
|
record = { ttl, ns, MBox, refresh, retry, expire, minttl }; //TODO: MBox, refresh, retry, expire, minttl
|
|
|
|
|
record = { ttl, ns: value, MBox, refresh, retry, expire }; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
return dynamicResponse(req, res, 400, { error: 'Invalid input' }); |
|
|
|
|
} |
|
|
|
|
//TODO: filter
|
|
|
|
|
records.push(record); |
|
|
|
|
} |
|
|
|
|
console.log(JSON.stringify({ [type]: records }, null, 4)) |
|
|
|
|
return dynamicResponse(req, res, 403, { error: 'Not implemented' }); |
|
|
|
|
if (records.lencth === 0) { |
|
|
|
|
return dynamicResponse(req, res, 400, { error: 'Invalid input' }); |
|
|
|
|
} |
|
|
|
|
let recordSetRaw = await redis.hget(`${req.params.domain}.`, req.params.zone); |
|
|
|
|
if (!recordSetRaw) { |
|
|
|
|
recordSetRaw = {}; |
|
|
|
|
} |
|
|
|
|
if (type == "soa") { |
|
|
|
|
recordSetRaw[type] = records[0]; |
|
|
|
|
} else { |
|
|
|
|
recordSetRaw[type] = records; |
|
|
|
|
} |
|
|
|
|
await redis.hset(`${domain}.`, zone, recordSetRaw); |
|
|
|
|
return dynamicResponse(req, res, 302, { redirect: `/dns/${domain}` }); |
|
|
|
|
}; |
|
|
|
|