@tradetrust-tt/dnsprove 2.18.0 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.js +43 -41
- package/dist/ts/index.d.ts +3 -0
- package/dist/ts/util/dns-resolvers/ali-dns-resolver.d.ts +2 -0
- package/dist/ts/util/dns-resolvers/cloudflare-dns-resolver.d.ts +2 -0
- package/dist/ts/util/dns-resolvers/dns-resolvers.test.d.ts +1 -0
- package/dist/ts/util/dns-resolvers/google-dns-resolver.d.ts +2 -0
- package/dist/ts/util/dns-resolvers/index.d.ts +3 -0
- package/dist/util/dns-resolvers/ali-dns-resolver.js +34 -0
- package/dist/util/dns-resolvers/cloudflare-dns-resolver.js +36 -0
- package/dist/util/dns-resolvers/google-dns-resolver.js +32 -0
- package/dist/util/dns-resolvers/index.js +38 -0
- package/package.json +1 -1
- package/src/index.test.ts +56 -33
- package/src/index.ts +11 -20
- package/src/util/dns-resolvers/ali-dns-resolver.ts +29 -0
- package/src/util/dns-resolvers/cloudflare-dns-resolver.ts +29 -0
- package/src/util/dns-resolvers/dns-resolvers.test.ts +120 -0
- package/src/util/dns-resolvers/google-dns-resolver.ts +27 -0
- package/src/util/dns-resolvers/index.ts +3 -0
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ Takes a DNS-TXT Record set and returns openattestation document store records if
|
|
|
111
111
|
#### Parameters
|
|
112
112
|
|
|
113
113
|
* `recordSet` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[IDNSRecord](#idnsrecord)>** Refer to tests for examples (optional, default `[]`)
|
|
114
|
-
* `dnssec` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)
|
|
114
|
+
* `dnssec` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Resolver AD (authenticated data) flag; applied as each record's `dnssec` field
|
|
115
115
|
|
|
116
116
|
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[OpenAttestationDNSTextRecord](#openattestationdnstextrecord)>** 
|
|
117
117
|
|
|
@@ -131,7 +131,7 @@ Queries a given domain and parses the results to retrieve openattestation docume
|
|
|
131
131
|
#### Parameters
|
|
132
132
|
|
|
133
133
|
* `domain` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** e.g: "example.openattestation.com"
|
|
134
|
-
* `customDnsResolvers` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[CustomDnsResolver](#customdnsresolver)
|
|
134
|
+
* `customDnsResolvers` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[CustomDnsResolver](#customdnsresolver)>?** Optional resolver list; built-in HTTP DNS chain is used when omitted
|
|
135
135
|
|
|
136
136
|
#### Examples
|
|
137
137
|
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
var _exportNames = {
|
|
7
|
+
defaultDnsResolvers: true,
|
|
8
|
+
queryDns: true,
|
|
9
|
+
parseOpenAttestationRecord: true,
|
|
10
|
+
parseDocumentStoreResults: true,
|
|
11
|
+
parseDnsDidResults: true,
|
|
12
|
+
getDocumentStoreRecords: true,
|
|
13
|
+
getDnsDidRecords: true,
|
|
14
|
+
OpenAttestationDNSTextRecord: true,
|
|
15
|
+
OpenAttestationDnsDidRecord: true
|
|
16
|
+
};
|
|
6
17
|
Object.defineProperty(exports, "OpenAttestationDNSTextRecord", {
|
|
7
18
|
enumerable: true,
|
|
8
19
|
get: function get() {
|
|
@@ -20,47 +31,34 @@ var _dnsTxt = require("./records/dnsTxt");
|
|
|
20
31
|
var _dnsDid = require("./records/dnsDid");
|
|
21
32
|
var _logger = require("./util/logger");
|
|
22
33
|
var _error = require("./common/error");
|
|
34
|
+
var _dnsResolvers = require("./util/dns-resolvers");
|
|
35
|
+
Object.keys(_dnsResolvers).forEach(function (key) {
|
|
36
|
+
if (key === "default" || key === "__esModule") return;
|
|
37
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
38
|
+
if (key in exports && exports[key] === _dnsResolvers[key]) return;
|
|
39
|
+
Object.defineProperty(exports, key, {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
get: function get() {
|
|
42
|
+
return _dnsResolvers[key];
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
23
46
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
24
47
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
25
48
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
26
49
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
|
|
27
50
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
51
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
52
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
28
53
|
function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableRest(); }
|
|
29
54
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
30
55
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
31
56
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
32
57
|
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
33
58
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
34
|
-
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
35
|
-
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
36
59
|
const _getLogger = (0, _logger.getLogger)("index"),
|
|
37
60
|
trace = _getLogger.trace;
|
|
38
|
-
const defaultDnsResolvers = exports.defaultDnsResolvers = [
|
|
39
|
-
var _ref = _asyncToGenerator(function* (domain) {
|
|
40
|
-
const data = yield fetch(`https://dns.google/resolve?name=${domain}&type=TXT`, {
|
|
41
|
-
method: "GET"
|
|
42
|
-
});
|
|
43
|
-
return data.json();
|
|
44
|
-
});
|
|
45
|
-
return function (_x) {
|
|
46
|
-
return _ref.apply(this, arguments);
|
|
47
|
-
};
|
|
48
|
-
}()), ( /*#__PURE__*/function () {
|
|
49
|
-
var _ref2 = _asyncToGenerator(function* (domain) {
|
|
50
|
-
const data = yield fetch(`https://cloudflare-dns.com/dns-query?name=${domain}&type=TXT`, {
|
|
51
|
-
method: "GET",
|
|
52
|
-
headers: {
|
|
53
|
-
accept: "application/dns-json",
|
|
54
|
-
contentType: "application/json",
|
|
55
|
-
connection: "keep-alive"
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
return data.json();
|
|
59
|
-
});
|
|
60
|
-
return function (_x2) {
|
|
61
|
-
return _ref2.apply(this, arguments);
|
|
62
|
-
};
|
|
63
|
-
}())];
|
|
61
|
+
const defaultDnsResolvers = exports.defaultDnsResolvers = [_dnsResolvers.googleDnsResolver, _dnsResolvers.cloudflareDnsResolver, _dnsResolvers.aliDnsResolver];
|
|
64
62
|
|
|
65
63
|
/**
|
|
66
64
|
* Returns true for strings that are openattestation records
|
|
@@ -104,7 +102,7 @@ const formatDnsDidRecord = ({
|
|
|
104
102
|
};
|
|
105
103
|
};
|
|
106
104
|
const queryDns = exports.queryDns = /*#__PURE__*/function () {
|
|
107
|
-
var
|
|
105
|
+
var _ref = _asyncToGenerator(function* (domain, customDnsResolvers) {
|
|
108
106
|
let data;
|
|
109
107
|
let i = 0;
|
|
110
108
|
if (domain.includes("://")) {
|
|
@@ -124,8 +122,8 @@ const queryDns = exports.queryDns = /*#__PURE__*/function () {
|
|
|
124
122
|
}
|
|
125
123
|
return data;
|
|
126
124
|
});
|
|
127
|
-
return function queryDns(
|
|
128
|
-
return
|
|
125
|
+
return function queryDns(_x, _x2) {
|
|
126
|
+
return _ref.apply(this, arguments);
|
|
129
127
|
};
|
|
130
128
|
}();
|
|
131
129
|
|
|
@@ -137,8 +135,10 @@ const parseOpenAttestationRecord = record => {
|
|
|
137
135
|
trace(`Parsing record: ${record}`);
|
|
138
136
|
const keyValuePairs = record.trim().split(" "); // tokenize into key=value elements
|
|
139
137
|
const recordObject = {};
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
const typeToken = keyValuePairs.shift();
|
|
139
|
+
if (typeToken !== undefined) {
|
|
140
|
+
recordObject.type = typeToken;
|
|
141
|
+
}
|
|
142
142
|
keyValuePairs.reduce(addKeyValuePairToObject, recordObject);
|
|
143
143
|
return recordObject;
|
|
144
144
|
};
|
|
@@ -175,6 +175,7 @@ const parseOpenAttestationRecords = (recordSet = []) => {
|
|
|
175
175
|
/**
|
|
176
176
|
* Takes a DNS-TXT Record set and returns openattestation document store records if any
|
|
177
177
|
* @param recordSet Refer to tests for examples
|
|
178
|
+
* @param dnssec Resolver AD (authenticated data) flag; applied as each record's `dnssec` field
|
|
178
179
|
*/
|
|
179
180
|
const parseDocumentStoreResults = (recordSet = [], dnssec) => {
|
|
180
181
|
return parseOpenAttestationRecords(recordSet).reduce((prev, curr) => {
|
|
@@ -191,6 +192,7 @@ const parseDnsDidResults = (recordSet = [], dnssec) => {
|
|
|
191
192
|
/**
|
|
192
193
|
* Queries a given domain and parses the results to retrieve openattestation document store records if any
|
|
193
194
|
* @param domain e.g: "example.openattestation.com"
|
|
195
|
+
* @param customDnsResolvers Optional resolver list; built-in HTTP DNS chain is used when omitted
|
|
194
196
|
* @example
|
|
195
197
|
* > getDocumentStoreRecords("example.openattestation.com")
|
|
196
198
|
* > [ { type: 'openatts',
|
|
@@ -201,28 +203,28 @@ const parseDnsDidResults = (recordSet = [], dnssec) => {
|
|
|
201
203
|
*/
|
|
202
204
|
exports.parseDnsDidResults = parseDnsDidResults;
|
|
203
205
|
const getDocumentStoreRecords = exports.getDocumentStoreRecords = /*#__PURE__*/function () {
|
|
204
|
-
var
|
|
206
|
+
var _ref2 = _asyncToGenerator(function* (domain, customDnsResolvers) {
|
|
205
207
|
trace(`Received request to resolve ${domain}`);
|
|
206
|
-
const dnsResolvers = customDnsResolvers
|
|
208
|
+
const dnsResolvers = customDnsResolvers !== null && customDnsResolvers !== void 0 ? customDnsResolvers : defaultDnsResolvers;
|
|
207
209
|
const results = yield queryDns(domain, dnsResolvers);
|
|
208
210
|
const answers = results.Answer || [];
|
|
209
211
|
trace(`Lookup results: ${JSON.stringify(answers)}`);
|
|
210
212
|
return parseDocumentStoreResults(answers, results.AD);
|
|
211
213
|
});
|
|
212
|
-
return function getDocumentStoreRecords(
|
|
213
|
-
return
|
|
214
|
+
return function getDocumentStoreRecords(_x3, _x4) {
|
|
215
|
+
return _ref2.apply(this, arguments);
|
|
214
216
|
};
|
|
215
217
|
}();
|
|
216
218
|
const getDnsDidRecords = exports.getDnsDidRecords = /*#__PURE__*/function () {
|
|
217
|
-
var
|
|
219
|
+
var _ref3 = _asyncToGenerator(function* (domain, customDnsResolvers) {
|
|
218
220
|
trace(`Received request to resolve ${domain}`);
|
|
219
|
-
const dnsResolvers = customDnsResolvers
|
|
221
|
+
const dnsResolvers = customDnsResolvers !== null && customDnsResolvers !== void 0 ? customDnsResolvers : defaultDnsResolvers;
|
|
220
222
|
const results = yield queryDns(domain, dnsResolvers);
|
|
221
223
|
const answers = results.Answer || [];
|
|
222
224
|
trace(`Lookup results: ${JSON.stringify(answers)}`);
|
|
223
225
|
return parseDnsDidResults(answers, results.AD);
|
|
224
226
|
});
|
|
225
|
-
return function getDnsDidRecords(
|
|
226
|
-
return
|
|
227
|
+
return function getDnsDidRecords(_x5, _x6) {
|
|
228
|
+
return _ref3.apply(this, arguments);
|
|
227
229
|
};
|
|
228
230
|
}();
|
package/dist/ts/index.d.ts
CHANGED
|
@@ -24,12 +24,14 @@ export declare const parseOpenAttestationRecord: (record: string) => GenericObje
|
|
|
24
24
|
/**
|
|
25
25
|
* Takes a DNS-TXT Record set and returns openattestation document store records if any
|
|
26
26
|
* @param recordSet Refer to tests for examples
|
|
27
|
+
* @param dnssec Resolver AD (authenticated data) flag; applied as each record's `dnssec` field
|
|
27
28
|
*/
|
|
28
29
|
export declare const parseDocumentStoreResults: (recordSet: IDNSRecord[] | undefined, dnssec: boolean) => OpenAttestationDNSTextRecord[];
|
|
29
30
|
export declare const parseDnsDidResults: (recordSet: IDNSRecord[] | undefined, dnssec: boolean) => OpenAttestationDnsDidRecord[];
|
|
30
31
|
/**
|
|
31
32
|
* Queries a given domain and parses the results to retrieve openattestation document store records if any
|
|
32
33
|
* @param domain e.g: "example.openattestation.com"
|
|
34
|
+
* @param customDnsResolvers Optional resolver list; built-in HTTP DNS chain is used when omitted
|
|
33
35
|
* @example
|
|
34
36
|
* > getDocumentStoreRecords("example.openattestation.com")
|
|
35
37
|
* > [ { type: 'openatts',
|
|
@@ -41,3 +43,4 @@ export declare const parseDnsDidResults: (recordSet: IDNSRecord[] | undefined, d
|
|
|
41
43
|
export declare const getDocumentStoreRecords: (domain: string, customDnsResolvers?: CustomDnsResolver[]) => Promise<OpenAttestationDNSTextRecord[]>;
|
|
42
44
|
export declare const getDnsDidRecords: (domain: string, customDnsResolvers?: CustomDnsResolver[]) => Promise<OpenAttestationDnsDidRecord[]>;
|
|
43
45
|
export { OpenAttestationDNSTextRecord, OpenAttestationDnsDidRecord };
|
|
46
|
+
export * from "./util/dns-resolvers";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.aliDnsResolver = void 0;
|
|
7
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
8
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
9
|
+
/** Ali DNS JSON API uses numeric RRTYPE; 16 = TXT */
|
|
10
|
+
const ALI_DNS_TXT_QUERY_TYPE = "16";
|
|
11
|
+
const aliDnsResolver = exports.aliDnsResolver = /*#__PURE__*/function () {
|
|
12
|
+
var _ref = _asyncToGenerator(function* (domain) {
|
|
13
|
+
const url = new URL("https://dns.alidns.com/resolve");
|
|
14
|
+
if (!domain) {
|
|
15
|
+
throw new Error("Domain is required");
|
|
16
|
+
}
|
|
17
|
+
url.searchParams.set("name", domain);
|
|
18
|
+
url.searchParams.set("type", ALI_DNS_TXT_QUERY_TYPE);
|
|
19
|
+
const res = yield fetch(url);
|
|
20
|
+
if (!res.ok) {
|
|
21
|
+
throw new Error(`Ali DNS request failed: HTTP ${res.status}`);
|
|
22
|
+
}
|
|
23
|
+
let data;
|
|
24
|
+
try {
|
|
25
|
+
data = yield res.json();
|
|
26
|
+
} catch (_unused) {
|
|
27
|
+
throw new Error("Failed to parse DNS response JSON");
|
|
28
|
+
}
|
|
29
|
+
return data;
|
|
30
|
+
});
|
|
31
|
+
return function aliDnsResolver(_x) {
|
|
32
|
+
return _ref.apply(this, arguments);
|
|
33
|
+
};
|
|
34
|
+
}();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.cloudflareDnsResolver = void 0;
|
|
7
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
8
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
9
|
+
const cloudflareDnsResolver = exports.cloudflareDnsResolver = /*#__PURE__*/function () {
|
|
10
|
+
var _ref = _asyncToGenerator(function* (domain) {
|
|
11
|
+
const url = new URL("https://cloudflare-dns.com/dns-query");
|
|
12
|
+
if (!domain) {
|
|
13
|
+
throw new Error("Domain is required");
|
|
14
|
+
}
|
|
15
|
+
url.searchParams.set("name", domain);
|
|
16
|
+
url.searchParams.set("type", "TXT");
|
|
17
|
+
const res = yield fetch(url, {
|
|
18
|
+
headers: {
|
|
19
|
+
Accept: "application/dns-json"
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
throw new Error(`Cloudflare DNS request failed: HTTP ${res.status}`);
|
|
24
|
+
}
|
|
25
|
+
let data;
|
|
26
|
+
try {
|
|
27
|
+
data = yield res.json();
|
|
28
|
+
} catch (_unused) {
|
|
29
|
+
throw new Error("Failed to parse DNS response JSON");
|
|
30
|
+
}
|
|
31
|
+
return data;
|
|
32
|
+
});
|
|
33
|
+
return function cloudflareDnsResolver(_x) {
|
|
34
|
+
return _ref.apply(this, arguments);
|
|
35
|
+
};
|
|
36
|
+
}();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.googleDnsResolver = void 0;
|
|
7
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
8
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
9
|
+
const googleDnsResolver = exports.googleDnsResolver = /*#__PURE__*/function () {
|
|
10
|
+
var _ref = _asyncToGenerator(function* (domain) {
|
|
11
|
+
const url = new URL("https://dns.google/resolve");
|
|
12
|
+
if (!domain) {
|
|
13
|
+
throw new Error("Domain is required");
|
|
14
|
+
}
|
|
15
|
+
url.searchParams.set("name", domain);
|
|
16
|
+
url.searchParams.set("type", "TXT");
|
|
17
|
+
const res = yield fetch(url);
|
|
18
|
+
if (!res.ok) {
|
|
19
|
+
throw new Error(`Google DNS request failed: HTTP ${res.status}`);
|
|
20
|
+
}
|
|
21
|
+
let data;
|
|
22
|
+
try {
|
|
23
|
+
data = yield res.json();
|
|
24
|
+
} catch (_unused) {
|
|
25
|
+
throw new Error("Failed to parse DNS response JSON");
|
|
26
|
+
}
|
|
27
|
+
return data;
|
|
28
|
+
});
|
|
29
|
+
return function googleDnsResolver(_x) {
|
|
30
|
+
return _ref.apply(this, arguments);
|
|
31
|
+
};
|
|
32
|
+
}();
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _googleDnsResolver = require("./google-dns-resolver");
|
|
7
|
+
Object.keys(_googleDnsResolver).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _googleDnsResolver[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function get() {
|
|
13
|
+
return _googleDnsResolver[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
var _cloudflareDnsResolver = require("./cloudflare-dns-resolver");
|
|
18
|
+
Object.keys(_cloudflareDnsResolver).forEach(function (key) {
|
|
19
|
+
if (key === "default" || key === "__esModule") return;
|
|
20
|
+
if (key in exports && exports[key] === _cloudflareDnsResolver[key]) return;
|
|
21
|
+
Object.defineProperty(exports, key, {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function get() {
|
|
24
|
+
return _cloudflareDnsResolver[key];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
var _aliDnsResolver = require("./ali-dns-resolver");
|
|
29
|
+
Object.keys(_aliDnsResolver).forEach(function (key) {
|
|
30
|
+
if (key === "default" || key === "__esModule") return;
|
|
31
|
+
if (key in exports && exports[key] === _aliDnsResolver[key]) return;
|
|
32
|
+
Object.defineProperty(exports, key, {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function get() {
|
|
35
|
+
return _aliDnsResolver[key];
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
package/package.json
CHANGED
package/src/index.test.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { setupServer, SetupServerApi } from "msw/node";
|
|
2
2
|
import { http, HttpResponse } from "msw";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
aliDnsResolver,
|
|
5
|
+
cloudflareDnsResolver,
|
|
6
|
+
getDocumentStoreRecords,
|
|
7
|
+
getDnsDidRecords,
|
|
8
|
+
googleDnsResolver,
|
|
9
|
+
parseDocumentStoreResults,
|
|
10
|
+
queryDns,
|
|
11
|
+
} from ".";
|
|
4
12
|
import { DnsproveStatusCode } from "./common/error";
|
|
5
13
|
|
|
6
14
|
describe("getCertStoreRecords", () => {
|
|
@@ -8,11 +16,11 @@ describe("getCertStoreRecords", () => {
|
|
|
8
16
|
type: "openatts",
|
|
9
17
|
net: "ethereum",
|
|
10
18
|
netId: "3",
|
|
11
|
-
dnssec:
|
|
19
|
+
dnssec: false,
|
|
12
20
|
addr: "0x2f60375e8144e16Adf1979936301D8341D58C36C",
|
|
13
21
|
};
|
|
14
22
|
test("it should work", async () => {
|
|
15
|
-
const records = await getDocumentStoreRecords("donotuse.
|
|
23
|
+
const records = await getDocumentStoreRecords("donotuse.trustvc.io");
|
|
16
24
|
expect(records).toStrictEqual([sampleDnsTextRecordWithDnssec]);
|
|
17
25
|
});
|
|
18
26
|
|
|
@@ -27,14 +35,14 @@ describe("getCertStoreRecords", () => {
|
|
|
27
35
|
|
|
28
36
|
describe("getDnsDidRecords", () => {
|
|
29
37
|
test("it should work", async () => {
|
|
30
|
-
const records = await getDnsDidRecords("donotuse.
|
|
38
|
+
const records = await getDnsDidRecords("donotuse.trustvc.io");
|
|
31
39
|
expect(records).toStrictEqual([
|
|
32
40
|
{
|
|
33
41
|
type: "openatts",
|
|
34
42
|
algorithm: "dns-did",
|
|
35
43
|
publicKey: "did:ethr:0xE712878f6E8d5d4F9e87E10DA604F9cB564C9a89#controller",
|
|
36
44
|
version: "1.0",
|
|
37
|
-
dnssec:
|
|
45
|
+
dnssec: false,
|
|
38
46
|
},
|
|
39
47
|
]);
|
|
40
48
|
});
|
|
@@ -177,29 +185,29 @@ describe("queryDns", () => {
|
|
|
177
185
|
RA: true,
|
|
178
186
|
AD: true,
|
|
179
187
|
CD: false,
|
|
180
|
-
Question: [{ name: "donotuse.
|
|
188
|
+
Question: [{ name: "donotuse.trustvc.io.", type: 16 }],
|
|
181
189
|
Answer: [
|
|
182
190
|
{
|
|
183
|
-
name: "donotuse.
|
|
191
|
+
name: "donotuse.trustvc.io.",
|
|
184
192
|
type: 16,
|
|
185
193
|
TTL: 300,
|
|
186
194
|
data: "openatts a=dns-did; p=did:ethr:0xE712878f6E8d5d4F9e87E10DA604F9cB564C9a89#controller; v=1.0;",
|
|
187
195
|
},
|
|
188
196
|
{
|
|
189
|
-
name: "donotuse.
|
|
197
|
+
name: "donotuse.trustvc.io.",
|
|
190
198
|
type: 16,
|
|
191
199
|
TTL: 300,
|
|
192
200
|
data:
|
|
193
201
|
"openatts DO NOT ADD ANY RECORDS BEYOND THIS AS THIS DOMAIN IS USED FOR DNSPROVE NPM LIBRARY INTEGRATION TESTS",
|
|
194
202
|
},
|
|
195
203
|
{
|
|
196
|
-
name: "donotuse.
|
|
204
|
+
name: "donotuse.trustvc.io.",
|
|
197
205
|
type: 16,
|
|
198
206
|
TTL: 300,
|
|
199
207
|
data: "openatts fooooooobarrrrrrrrr this entry exists to ensure validation works",
|
|
200
208
|
},
|
|
201
209
|
{
|
|
202
|
-
name: "donotuse.
|
|
210
|
+
name: "donotuse.trustvc.io.",
|
|
203
211
|
type: 16,
|
|
204
212
|
TTL: 300,
|
|
205
213
|
data: "openatts net=ethereum netId=3 addr=0x2f60375e8144e16Adf1979936301D8341D58C36C",
|
|
@@ -208,22 +216,7 @@ describe("queryDns", () => {
|
|
|
208
216
|
Comment: "Response from 205.251.199.177.",
|
|
209
217
|
};
|
|
210
218
|
|
|
211
|
-
const testDnsResolvers
|
|
212
|
-
async (domain) => {
|
|
213
|
-
const data = await fetch(`https://dns.google/resolve?name=${domain}&type=TXT`, {
|
|
214
|
-
method: "GET",
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
return data.json();
|
|
218
|
-
},
|
|
219
|
-
async (domain) => {
|
|
220
|
-
const data = await fetch(`https://cloudflare-dns.com/dns-query?name=${domain}&type=TXT`, {
|
|
221
|
-
method: "GET",
|
|
222
|
-
headers: { accept: "application/dns-json", contentType: "application/json", connection: "keep-alive" },
|
|
223
|
-
});
|
|
224
|
-
return data.json();
|
|
225
|
-
},
|
|
226
|
-
];
|
|
219
|
+
const testDnsResolvers = [googleDnsResolver, cloudflareDnsResolver, aliDnsResolver];
|
|
227
220
|
|
|
228
221
|
afterEach(() => {
|
|
229
222
|
server.close();
|
|
@@ -239,7 +232,7 @@ describe("queryDns", () => {
|
|
|
239
232
|
server = setupServer(...handlers);
|
|
240
233
|
server.listen();
|
|
241
234
|
|
|
242
|
-
const records = await queryDns("https://donotuse.
|
|
235
|
+
const records = await queryDns("https://donotuse.trustvc.io", testDnsResolvers);
|
|
243
236
|
const sortedAnswer = records?.Answer.sort((a, b) => a.data.localeCompare(b.data));
|
|
244
237
|
expect(sortedAnswer).toMatchObject(sampleResponse.Answer);
|
|
245
238
|
});
|
|
@@ -256,7 +249,28 @@ describe("queryDns", () => {
|
|
|
256
249
|
server = setupServer(...handlers);
|
|
257
250
|
server.listen();
|
|
258
251
|
|
|
259
|
-
const records = await queryDns("https://donotuse.
|
|
252
|
+
const records = await queryDns("https://donotuse.trustvc.io", testDnsResolvers);
|
|
253
|
+
|
|
254
|
+
const sortedAnswer = records?.Answer.sort((a, b) => a.data.localeCompare(b.data));
|
|
255
|
+
expect(sortedAnswer).toMatchObject(sampleResponse.Answer);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("Should fallback to third dns when first and second dns is down", async () => {
|
|
259
|
+
const handlers = [
|
|
260
|
+
http.get("https://dns.google/resolve", (_) => {
|
|
261
|
+
return new HttpResponse(null, { status: 500 });
|
|
262
|
+
}),
|
|
263
|
+
http.get("https://cloudflare-dns.com/dns-query", (_) => {
|
|
264
|
+
return new HttpResponse(null, { status: 500 });
|
|
265
|
+
}),
|
|
266
|
+
http.get("https://dns.alidns.com/resolve", (_) => {
|
|
267
|
+
return HttpResponse.json(sampleResponse);
|
|
268
|
+
}),
|
|
269
|
+
];
|
|
270
|
+
server = setupServer(...handlers);
|
|
271
|
+
server.listen();
|
|
272
|
+
|
|
273
|
+
const records = await queryDns("https://donotuse.trustvc.io", testDnsResolvers);
|
|
260
274
|
|
|
261
275
|
const sortedAnswer = records?.Answer.sort((a, b) => a.data.localeCompare(b.data));
|
|
262
276
|
expect(sortedAnswer).toMatchObject(sampleResponse.Answer);
|
|
@@ -270,14 +284,16 @@ describe("queryDns", () => {
|
|
|
270
284
|
http.get("https://cloudflare-dns.com/dns-query", (_) => {
|
|
271
285
|
return new HttpResponse(null, { status: 500 });
|
|
272
286
|
}),
|
|
287
|
+
http.get("https://dns.alidns.com/resolve", (_) => {
|
|
288
|
+
return new HttpResponse(null, { status: 500 });
|
|
289
|
+
}),
|
|
273
290
|
];
|
|
274
291
|
server = setupServer(...handlers);
|
|
275
292
|
server.listen();
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
293
|
+
|
|
294
|
+
await expect(queryDns("https://donotuse.trustvc.io", testDnsResolvers)).rejects.toMatchObject({
|
|
295
|
+
code: DnsproveStatusCode.IDNS_QUERY_ERROR_GENERAL,
|
|
296
|
+
});
|
|
281
297
|
});
|
|
282
298
|
});
|
|
283
299
|
|
|
@@ -321,6 +337,13 @@ describe("getDocumentStoreRecords for Astron", () => {
|
|
|
321
337
|
addr: "0x18bc0127Ae33389cD96593a1a612774fD14c0737",
|
|
322
338
|
dnssec: false,
|
|
323
339
|
},
|
|
340
|
+
{
|
|
341
|
+
type: "openatts",
|
|
342
|
+
net: "ethereum",
|
|
343
|
+
netId: "1338",
|
|
344
|
+
addr: "0x94FD21A026E29E0686583b8be71Cb28a8ca1A8d4",
|
|
345
|
+
dnssec: false,
|
|
346
|
+
},
|
|
324
347
|
{
|
|
325
348
|
type: "openatts",
|
|
326
349
|
net: "ethereum",
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { OpenAttestationDNSTextRecord, OpenAttestationDNSTextRecordT } from "./r
|
|
|
2
2
|
import { OpenAttestationDnsDidRecord, OpenAttestationDnsDidRecordT } from "./records/dnsDid";
|
|
3
3
|
import { getLogger } from "./util/logger";
|
|
4
4
|
import { CodedError, DnsproveStatusCode } from "./common/error";
|
|
5
|
+
import { aliDnsResolver, cloudflareDnsResolver, googleDnsResolver } from "./util/dns-resolvers";
|
|
5
6
|
|
|
6
7
|
const { trace } = getLogger("index");
|
|
7
8
|
|
|
@@ -23,22 +24,7 @@ interface GenericObject {
|
|
|
23
24
|
|
|
24
25
|
export type CustomDnsResolver = (domain: string) => Promise<IDNSQueryResponse>;
|
|
25
26
|
|
|
26
|
-
export const defaultDnsResolvers: CustomDnsResolver[] = [
|
|
27
|
-
async (domain) => {
|
|
28
|
-
const data = await fetch(`https://dns.google/resolve?name=${domain}&type=TXT`, {
|
|
29
|
-
method: "GET",
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
return data.json();
|
|
33
|
-
},
|
|
34
|
-
async (domain) => {
|
|
35
|
-
const data = await fetch(`https://cloudflare-dns.com/dns-query?name=${domain}&type=TXT`, {
|
|
36
|
-
method: "GET",
|
|
37
|
-
headers: { accept: "application/dns-json", contentType: "application/json", connection: "keep-alive" },
|
|
38
|
-
});
|
|
39
|
-
return data.json();
|
|
40
|
-
},
|
|
41
|
-
];
|
|
27
|
+
export const defaultDnsResolvers: CustomDnsResolver[] = [googleDnsResolver, cloudflareDnsResolver, aliDnsResolver];
|
|
42
28
|
|
|
43
29
|
/**
|
|
44
30
|
* Returns true for strings that are openattestation records
|
|
@@ -115,8 +101,10 @@ export const parseOpenAttestationRecord = (record: string): GenericObject => {
|
|
|
115
101
|
trace(`Parsing record: ${record}`);
|
|
116
102
|
const keyValuePairs = record.trim().split(" "); // tokenize into key=value elements
|
|
117
103
|
const recordObject = {} as GenericObject;
|
|
118
|
-
|
|
119
|
-
|
|
104
|
+
const typeToken = keyValuePairs.shift();
|
|
105
|
+
if (typeToken !== undefined) {
|
|
106
|
+
recordObject.type = typeToken;
|
|
107
|
+
}
|
|
120
108
|
keyValuePairs.reduce<GenericObject>(addKeyValuePairToObject, recordObject);
|
|
121
109
|
return recordObject;
|
|
122
110
|
};
|
|
@@ -153,6 +141,7 @@ const parseOpenAttestationRecords = (recordSet: IDNSRecord[] = []): GenericObjec
|
|
|
153
141
|
/**
|
|
154
142
|
* Takes a DNS-TXT Record set and returns openattestation document store records if any
|
|
155
143
|
* @param recordSet Refer to tests for examples
|
|
144
|
+
* @param dnssec Resolver AD (authenticated data) flag; applied as each record's `dnssec` field
|
|
156
145
|
*/
|
|
157
146
|
export const parseDocumentStoreResults = (
|
|
158
147
|
recordSet: IDNSRecord[] = [],
|
|
@@ -177,6 +166,7 @@ export const parseDnsDidResults = (recordSet: IDNSRecord[] = [], dnssec: boolean
|
|
|
177
166
|
/**
|
|
178
167
|
* Queries a given domain and parses the results to retrieve openattestation document store records if any
|
|
179
168
|
* @param domain e.g: "example.openattestation.com"
|
|
169
|
+
* @param customDnsResolvers Optional resolver list; built-in HTTP DNS chain is used when omitted
|
|
180
170
|
* @example
|
|
181
171
|
* > getDocumentStoreRecords("example.openattestation.com")
|
|
182
172
|
* > [ { type: 'openatts',
|
|
@@ -191,7 +181,7 @@ export const getDocumentStoreRecords = async (
|
|
|
191
181
|
): Promise<OpenAttestationDNSTextRecord[]> => {
|
|
192
182
|
trace(`Received request to resolve ${domain}`);
|
|
193
183
|
|
|
194
|
-
const dnsResolvers = customDnsResolvers
|
|
184
|
+
const dnsResolvers = customDnsResolvers ?? defaultDnsResolvers;
|
|
195
185
|
|
|
196
186
|
const results = await queryDns(domain, dnsResolvers);
|
|
197
187
|
const answers = results.Answer || [];
|
|
@@ -207,7 +197,7 @@ export const getDnsDidRecords = async (
|
|
|
207
197
|
): Promise<OpenAttestationDnsDidRecord[]> => {
|
|
208
198
|
trace(`Received request to resolve ${domain}`);
|
|
209
199
|
|
|
210
|
-
const dnsResolvers = customDnsResolvers
|
|
200
|
+
const dnsResolvers = customDnsResolvers ?? defaultDnsResolvers;
|
|
211
201
|
|
|
212
202
|
const results = await queryDns(domain, dnsResolvers);
|
|
213
203
|
const answers = results.Answer || [];
|
|
@@ -218,3 +208,4 @@ export const getDnsDidRecords = async (
|
|
|
218
208
|
};
|
|
219
209
|
|
|
220
210
|
export { OpenAttestationDNSTextRecord, OpenAttestationDnsDidRecord };
|
|
211
|
+
export * from "./util/dns-resolvers";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CustomDnsResolver, IDNSQueryResponse } from "../..";
|
|
2
|
+
|
|
3
|
+
/** Ali DNS JSON API uses numeric RRTYPE; 16 = TXT */
|
|
4
|
+
const ALI_DNS_TXT_QUERY_TYPE = "16";
|
|
5
|
+
export const aliDnsResolver: CustomDnsResolver = async (domain) => {
|
|
6
|
+
const url = new URL("https://dns.alidns.com/resolve");
|
|
7
|
+
|
|
8
|
+
if (!domain) {
|
|
9
|
+
throw new Error("Domain is required");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
url.searchParams.set("name", domain);
|
|
13
|
+
url.searchParams.set("type", ALI_DNS_TXT_QUERY_TYPE);
|
|
14
|
+
|
|
15
|
+
const res = await fetch(url);
|
|
16
|
+
|
|
17
|
+
if (!res.ok) {
|
|
18
|
+
throw new Error(`Ali DNS request failed: HTTP ${res.status}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let data;
|
|
22
|
+
try {
|
|
23
|
+
data = await res.json();
|
|
24
|
+
} catch {
|
|
25
|
+
throw new Error("Failed to parse DNS response JSON");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return data as IDNSQueryResponse;
|
|
29
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CustomDnsResolver, IDNSQueryResponse } from "../..";
|
|
2
|
+
|
|
3
|
+
export const cloudflareDnsResolver: CustomDnsResolver = async (domain) => {
|
|
4
|
+
const url = new URL("https://cloudflare-dns.com/dns-query");
|
|
5
|
+
|
|
6
|
+
if (!domain) {
|
|
7
|
+
throw new Error("Domain is required");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
url.searchParams.set("name", domain);
|
|
11
|
+
url.searchParams.set("type", "TXT");
|
|
12
|
+
|
|
13
|
+
const res = await fetch(url, {
|
|
14
|
+
headers: { Accept: "application/dns-json" },
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (!res.ok) {
|
|
18
|
+
throw new Error(`Cloudflare DNS request failed: HTTP ${res.status}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let data;
|
|
22
|
+
try {
|
|
23
|
+
data = await res.json();
|
|
24
|
+
} catch {
|
|
25
|
+
throw new Error("Failed to parse DNS response JSON");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return data as IDNSQueryResponse;
|
|
29
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { setupServer, SetupServerApi } from "msw/node";
|
|
2
|
+
import { http, HttpResponse } from "msw";
|
|
3
|
+
import { aliDnsResolver } from "./ali-dns-resolver";
|
|
4
|
+
import { cloudflareDnsResolver } from "./cloudflare-dns-resolver";
|
|
5
|
+
import { googleDnsResolver } from "./google-dns-resolver";
|
|
6
|
+
|
|
7
|
+
const emptyDnsJson = {
|
|
8
|
+
Status: 0,
|
|
9
|
+
TC: false,
|
|
10
|
+
RD: true,
|
|
11
|
+
RA: true,
|
|
12
|
+
AD: false,
|
|
13
|
+
CD: false,
|
|
14
|
+
Answer: [] as [],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
describe("googleDnsResolver", () => {
|
|
18
|
+
let server: SetupServerApi | undefined;
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
server?.close();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("requests Google DNS JSON with name, TXT type, and encoded query", async () => {
|
|
25
|
+
server = setupServer(
|
|
26
|
+
http.get("https://dns.google/resolve", ({ request }) => {
|
|
27
|
+
const url = new URL(request.url);
|
|
28
|
+
expect(url.searchParams.get("name")).toBe("my domain.test");
|
|
29
|
+
expect(url.searchParams.get("type")).toBe("TXT");
|
|
30
|
+
return HttpResponse.json(emptyDnsJson);
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
server.listen();
|
|
34
|
+
|
|
35
|
+
const out = await googleDnsResolver("my domain.test");
|
|
36
|
+
expect(out).toMatchObject({ Status: 0, Answer: [] });
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("throws when Google DNS returns non-2xx", async () => {
|
|
40
|
+
server = setupServer(http.get("https://dns.google/resolve", () => new HttpResponse(null, { status: 503 })));
|
|
41
|
+
server.listen();
|
|
42
|
+
|
|
43
|
+
await expect(googleDnsResolver("my.domain.test")).rejects.toThrow(/HTTP 503/);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("throws when domain is empty", async () => {
|
|
47
|
+
await expect(googleDnsResolver("")).rejects.toThrow("Domain is required");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe("cloudflareDnsResolver", () => {
|
|
52
|
+
let server: SetupServerApi | undefined;
|
|
53
|
+
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
server?.close();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("requests Cloudflare DNS JSON with name, TXT type, Accept header, and encoded query", async () => {
|
|
59
|
+
server = setupServer(
|
|
60
|
+
http.get("https://cloudflare-dns.com/dns-query", ({ request }) => {
|
|
61
|
+
const url = new URL(request.url);
|
|
62
|
+
expect(url.searchParams.get("name")).toBe("cf example.test");
|
|
63
|
+
expect(url.searchParams.get("type")).toBe("TXT");
|
|
64
|
+
expect(request.headers.get("accept")).toBe("application/dns-json");
|
|
65
|
+
return HttpResponse.json(emptyDnsJson);
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
server.listen();
|
|
69
|
+
|
|
70
|
+
const out = await cloudflareDnsResolver("cf example.test");
|
|
71
|
+
expect(out).toMatchObject({ Status: 0, Answer: [] });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("throws when Cloudflare DNS returns non-2xx", async () => {
|
|
75
|
+
server = setupServer(
|
|
76
|
+
http.get("https://cloudflare-dns.com/dns-query", () => new HttpResponse(null, { status: 502 }))
|
|
77
|
+
);
|
|
78
|
+
server.listen();
|
|
79
|
+
|
|
80
|
+
await expect(cloudflareDnsResolver("cf.example.test")).rejects.toThrow(/HTTP 502/);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("throws when domain is empty", async () => {
|
|
84
|
+
await expect(cloudflareDnsResolver("")).rejects.toThrow("Domain is required");
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("aliDnsResolver", () => {
|
|
89
|
+
let server: SetupServerApi | undefined;
|
|
90
|
+
|
|
91
|
+
afterEach(() => {
|
|
92
|
+
server?.close();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("requests Ali DNS JSON with name, type 16 (TXT), and encoded query", async () => {
|
|
96
|
+
server = setupServer(
|
|
97
|
+
http.get("https://dns.alidns.com/resolve", ({ request }) => {
|
|
98
|
+
const url = new URL(request.url);
|
|
99
|
+
expect(url.searchParams.get("name")).toBe("ali example.test");
|
|
100
|
+
expect(url.searchParams.get("type")).toBe("16");
|
|
101
|
+
return HttpResponse.json(emptyDnsJson);
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
server.listen();
|
|
105
|
+
|
|
106
|
+
const out = await aliDnsResolver("ali example.test");
|
|
107
|
+
expect(out).toMatchObject({ Status: 0, Answer: [] });
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("throws when Ali DNS returns non-2xx", async () => {
|
|
111
|
+
server = setupServer(http.get("https://dns.alidns.com/resolve", () => new HttpResponse(null, { status: 503 })));
|
|
112
|
+
server.listen();
|
|
113
|
+
|
|
114
|
+
await expect(aliDnsResolver("ali.example.test")).rejects.toThrow(/HTTP 503/);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("throws when domain is empty", async () => {
|
|
118
|
+
await expect(aliDnsResolver("")).rejects.toThrow("Domain is required");
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CustomDnsResolver, IDNSQueryResponse } from "../..";
|
|
2
|
+
|
|
3
|
+
export const googleDnsResolver: CustomDnsResolver = async (domain) => {
|
|
4
|
+
const url = new URL("https://dns.google/resolve");
|
|
5
|
+
|
|
6
|
+
if (!domain) {
|
|
7
|
+
throw new Error("Domain is required");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
url.searchParams.set("name", domain);
|
|
11
|
+
url.searchParams.set("type", "TXT");
|
|
12
|
+
|
|
13
|
+
const res = await fetch(url);
|
|
14
|
+
|
|
15
|
+
if (!res.ok) {
|
|
16
|
+
throw new Error(`Google DNS request failed: HTTP ${res.status}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let data;
|
|
20
|
+
try {
|
|
21
|
+
data = await res.json();
|
|
22
|
+
} catch {
|
|
23
|
+
throw new Error("Failed to parse DNS response JSON");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return data as IDNSQueryResponse;
|
|
27
|
+
};
|