blockstack-zones
Version:
A DNS zone file parser and generator
255 lines (226 loc) • 7.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.parseZoneFile = parseZoneFile;
function parseZoneFile(text) {
text = removeComments(text);
text = flatten(text);
return parseRRs(text);
};
var removeComments = function removeComments(text) {
var re = /(^|[^\\]);.*/g;
return text.replace(re, function (m, g1) {
return g1 ? g1 : ""; // if g1 is set/matched, re-insert it, else remove
});
};
var flatten = function flatten(text) {
var captured = [];
var re = /\([\s\S]*?\)/gim;
var match = re.exec(text);
while (match !== null) {
match.replacement = match[0].replace(/\s+/gm, ' ');
captured.push(match);
// captured Text, index, input
match = re.exec(text);
}
var arrText = text.split('');
for (var i in captured) {
match = captured[i];
arrText.splice(match.index, match[0].length, match.replacement);
}
return arrText.join('').replace(/\(|\)/gim, ' ');
};
var parseRRs = function parseRRs(text) {
var ret = {};
var rrs = text.split('\n');
for (var i in rrs) {
var rr = rrs[i];
if (!rr || !rr.trim()) {
continue;
}
var uRR = rr.toUpperCase();
if (/\s+TXT\s+/.test(uRR)) {
ret.txt = ret.txt || [];
ret.txt.push(parseTXT(rr));
} else if (uRR.indexOf('$ORIGIN') === 0) {
ret.$origin = rr.split(/\s+/g)[1];
} else if (uRR.indexOf('$TTL') === 0) {
ret.$ttl = parseInt(rr.split(/\s+/g)[1], 10);
} else if (/\s+SOA\s+/.test(uRR)) {
ret.soa = parseSOA(rr);
} else if (/\s+NS\s+/.test(uRR)) {
ret.ns = ret.ns || [];
ret.ns.push(parseNS(rr));
} else if (/\s+A\s+/.test(uRR)) {
ret.a = ret.a || [];
ret.a.push(parseA(rr, ret.a));
} else if (/\s+AAAA\s+/.test(uRR)) {
ret.aaaa = ret.aaaa || [];
ret.aaaa.push(parseAAAA(rr));
} else if (/\s+CNAME\s+/.test(uRR)) {
ret.cname = ret.cname || [];
ret.cname.push(parseCNAME(rr));
} else if (/\s+MX\s+/.test(uRR)) {
ret.mx = ret.mx || [];
ret.mx.push(parseMX(rr));
} else if (/\s+PTR\s+/.test(uRR)) {
ret.ptr = ret.ptr || [];
ret.ptr.push(parsePTR(rr, ret.ptr, ret.$origin));
} else if (/\s+SRV\s+/.test(uRR)) {
ret.srv = ret.srv || [];
ret.srv.push(parseSRV(rr));
} else if (/\s+SPF\s+/.test(uRR)) {
ret.spf = ret.spf || [];
ret.spf.push(parseSPF(rr));
} else if (/\s+URI\s+/.test(uRR)) {
ret.uri = ret.uri || [];
ret.uri.push(parseURI(rr));
}
}
return ret;
};
var parseSOA = function parseSOA(rr) {
var soa = {};
var rrTokens = rr.trim().split(/\s+/g);
var l = rrTokens.length;
soa.name = rrTokens[0];
soa.minimum = parseInt(rrTokens[l - 1], 10);
soa.expire = parseInt(rrTokens[l - 2], 10);
soa.retry = parseInt(rrTokens[l - 3], 10);
soa.refresh = parseInt(rrTokens[l - 4], 10);
soa.serial = parseInt(rrTokens[l - 5], 10);
soa.rname = rrTokens[l - 6];
soa.mname = rrTokens[l - 7];
if (!isNaN(rrTokens[1])) soa.ttl = parseInt(rrTokens[1], 10);
return soa;
};
var parseNS = function parseNS(rr) {
var rrTokens = rr.trim().split(/\s+/g);
var l = rrTokens.length;
var result = {
name: rrTokens[0],
host: rrTokens[l - 1]
};
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};
var parseA = function parseA(rr, recordsSoFar) {
var rrTokens = rr.trim().split(/\s+/g);
var urrTokens = rr.trim().toUpperCase().split(/\s+/g);
var l = rrTokens.length;
var result = {
name: rrTokens[0],
ip: rrTokens[l - 1]
};
if (urrTokens.lastIndexOf('A') === 0) {
if (recordsSoFar.length) {
result.name = recordsSoFar[recordsSoFar.length - 1].name;
} else {
result.name = '@';
}
}
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};
var parseAAAA = function parseAAAA(rr) {
var rrTokens = rr.trim().split(/\s+/g);
var l = rrTokens.length;
var result = {
name: rrTokens[0],
ip: rrTokens[l - 1]
};
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};
var parseCNAME = function parseCNAME(rr) {
var rrTokens = rr.trim().split(/\s+/g);
var l = rrTokens.length;
var result = {
name: rrTokens[0],
alias: rrTokens[l - 1]
};
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};
var parseMX = function parseMX(rr) {
var rrTokens = rr.trim().split(/\s+/g);
var l = rrTokens.length;
var result = {
name: rrTokens[0],
preference: parseInt(rrTokens[l - 2], 10),
host: rrTokens[l - 1]
};
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};
var parseTXT = function parseTXT(rr) {
var rrTokens = rr.trim().match(/[^\s\"']+|\"[^\"]*\"|'[^']*'/g);
var l = rrTokens.length;
var tokenTxt = rrTokens[l - 1];
if (tokenTxt.indexOf('\"') > -1) {
tokenTxt = tokenTxt.split('\"')[1];
}
if (tokenTxt.indexOf('"') > -1) {
tokenTxt = tokenTxt.split('"')[1];
}
var result = {
name: rrTokens[0],
txt: tokenTxt
};
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};
var parsePTR = function parsePTR(rr, recordsSoFar, currentOrigin) {
var rrTokens = rr.trim().split(/\s+/g);
var urrTokens = rr.trim().toUpperCase().split(/\s+/g);
if (urrTokens.lastIndexOf('PTR') === 0 && recordsSoFar[recordsSoFar.length - 1]) {
rrTokens.unshift(recordsSoFar[recordsSoFar.length - 1].name);
}
var l = rrTokens.length;
var result = {
name: rrTokens[0],
fullname: rrTokens[0] + '.' + currentOrigin,
host: rrTokens[l - 1]
};
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};
var parseSRV = function parseSRV(rr) {
var rrTokens = rr.trim().split(/\s+/g);
var l = rrTokens.length;
var result = {
name: rrTokens[0],
target: rrTokens[l - 1],
priority: parseInt(rrTokens[l - 4], 10),
weight: parseInt(rrTokens[l - 3], 10),
port: parseInt(rrTokens[l - 2], 10)
};
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};
var parseSPF = function parseSPF(rr) {
var rrTokens = rr.trim().split(/\s+/g);
var result = {
name: rrTokens[0],
data: ''
};
var l = rrTokens.length;
while (l-- > 4) {
result.data = rrTokens[l] + ' ' + result.data.trim();
}
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};
var parseURI = function parseURI(rr) {
var rrTokens = rr.trim().split(/\s+/g);
var l = rrTokens.length;
var result = {
name: rrTokens[0],
target: rrTokens[l - 1].replace(/"/g, ''),
priority: parseInt(rrTokens[l - 3], 10),
weight: parseInt(rrTokens[l - 2], 10)
};
if (!isNaN(rrTokens[1])) result.ttl = parseInt(rrTokens[1], 10);
return result;
};