@tradetrust-tt/dnsprove 2.18.0 → 2.20.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/records/dnsTxt.js +2 -19
- package/dist/ts/index.d.ts +3 -0
- package/dist/ts/records/dnsTxt.d.ts +3 -19
- 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 +126 -33
- package/src/index.ts +11 -20
- package/src/records/dnsTxt.ts +3 -33
- 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/records/dnsTxt.js
CHANGED
|
@@ -3,31 +3,14 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.RecordTypesT = exports.OpenAttestationDNSTextRecordT = exports.
|
|
6
|
+
exports.RecordTypesT = exports.OpenAttestationDNSTextRecordT = exports.EthereumNetworkIdT = exports.EthereumAddressT = exports.BlockchainNetworkT = void 0;
|
|
7
7
|
var _runtypes = require("runtypes");
|
|
8
8
|
const RecordTypesT = exports.RecordTypesT = (0, _runtypes.Literal)("openatts");
|
|
9
9
|
const BlockchainNetworkT = exports.BlockchainNetworkT = (0, _runtypes.Literal)("ethereum");
|
|
10
10
|
const EthereumAddressT = exports.EthereumAddressT = _runtypes.String.withConstraint(maybeAddress => {
|
|
11
11
|
return /0x[a-fA-F0-9]{40}/.test(maybeAddress) || `${maybeAddress} is not a valid ethereum address`;
|
|
12
12
|
});
|
|
13
|
-
|
|
14
|
-
(function (EthereumNetworks) {
|
|
15
|
-
EthereumNetworks["homestead"] = "1";
|
|
16
|
-
EthereumNetworks["ropsten"] = "3";
|
|
17
|
-
EthereumNetworks["rinkeby"] = "4";
|
|
18
|
-
EthereumNetworks["goerli"] = "5";
|
|
19
|
-
EthereumNetworks["sepolia"] = "11155111";
|
|
20
|
-
EthereumNetworks["polygon"] = "137";
|
|
21
|
-
EthereumNetworks["polygonAmoy"] = "80002";
|
|
22
|
-
EthereumNetworks["local"] = "1337";
|
|
23
|
-
EthereumNetworks["xdc"] = "50";
|
|
24
|
-
EthereumNetworks["xdcapothem"] = "51";
|
|
25
|
-
EthereumNetworks["stabilityTestnet"] = "20180427";
|
|
26
|
-
EthereumNetworks["stability"] = "101010";
|
|
27
|
-
EthereumNetworks["astronTestnet"] = "21002";
|
|
28
|
-
EthereumNetworks["astron"] = "1338";
|
|
29
|
-
})(EthereumNetworks || (exports.EthereumNetworks = EthereumNetworks = {}));
|
|
30
|
-
const EthereumNetworkIdT = exports.EthereumNetworkIdT = (0, _runtypes.Union)((0, _runtypes.Literal)(EthereumNetworks.homestead), (0, _runtypes.Literal)(EthereumNetworks.ropsten), (0, _runtypes.Literal)(EthereumNetworks.rinkeby), (0, _runtypes.Literal)(EthereumNetworks.goerli), (0, _runtypes.Literal)(EthereumNetworks.sepolia), (0, _runtypes.Literal)(EthereumNetworks.polygon), (0, _runtypes.Literal)(EthereumNetworks.polygonAmoy), (0, _runtypes.Literal)(EthereumNetworks.xdc), (0, _runtypes.Literal)(EthereumNetworks.xdcapothem), (0, _runtypes.Literal)(EthereumNetworks.stabilityTestnet), (0, _runtypes.Literal)(EthereumNetworks.stability), (0, _runtypes.Literal)(EthereumNetworks.local), (0, _runtypes.Literal)(EthereumNetworks.astronTestnet), (0, _runtypes.Literal)(EthereumNetworks.astron));
|
|
13
|
+
const EthereumNetworkIdT = exports.EthereumNetworkIdT = _runtypes.String.withConstraint(maybeNetId => /^\d+$/.test(maybeNetId) || `${maybeNetId} is not a valid numeric network id`);
|
|
31
14
|
const OpenAttestationDNSTextRecordT = exports.OpenAttestationDNSTextRecordT = (0, _runtypes.Record)({
|
|
32
15
|
type: RecordTypesT,
|
|
33
16
|
net: BlockchainNetworkT,
|
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";
|
|
@@ -1,28 +1,12 @@
|
|
|
1
|
-
import { Static, Boolean, String, Literal, Record,
|
|
1
|
+
import { Static, Boolean, String, Literal, Record, Partial } from "runtypes";
|
|
2
2
|
export declare const RecordTypesT: Literal<"openatts">;
|
|
3
3
|
export declare const BlockchainNetworkT: Literal<"ethereum">;
|
|
4
4
|
export declare const EthereumAddressT: import("runtypes").Constraint<String, string, unknown>;
|
|
5
|
-
export declare
|
|
6
|
-
homestead = "1",
|
|
7
|
-
ropsten = "3",
|
|
8
|
-
rinkeby = "4",
|
|
9
|
-
goerli = "5",
|
|
10
|
-
sepolia = "11155111",
|
|
11
|
-
polygon = "137",
|
|
12
|
-
polygonAmoy = "80002",
|
|
13
|
-
local = "1337",
|
|
14
|
-
xdc = "50",
|
|
15
|
-
xdcapothem = "51",
|
|
16
|
-
stabilityTestnet = "20180427",
|
|
17
|
-
stability = "101010",
|
|
18
|
-
astronTestnet = "21002",
|
|
19
|
-
astron = "1338"
|
|
20
|
-
}
|
|
21
|
-
export declare const EthereumNetworkIdT: Union<[Literal<EthereumNetworks.homestead>, Literal<EthereumNetworks.ropsten>, Literal<EthereumNetworks.rinkeby>, Literal<EthereumNetworks.goerli>, Literal<EthereumNetworks.sepolia>, Literal<EthereumNetworks.polygon>, Literal<EthereumNetworks.polygonAmoy>, Literal<EthereumNetworks.xdc>, Literal<EthereumNetworks.xdcapothem>, Literal<EthereumNetworks.stabilityTestnet>, Literal<EthereumNetworks.stability>, Literal<EthereumNetworks.local>, Literal<EthereumNetworks.astronTestnet>, Literal<EthereumNetworks.astron>]>;
|
|
5
|
+
export declare const EthereumNetworkIdT: import("runtypes").Constraint<String, string, unknown>;
|
|
22
6
|
export declare const OpenAttestationDNSTextRecordT: import("runtypes").Intersect<[Record<{
|
|
23
7
|
type: Literal<"openatts">;
|
|
24
8
|
net: Literal<"ethereum">;
|
|
25
|
-
netId:
|
|
9
|
+
netId: import("runtypes").Constraint<String, string, unknown>;
|
|
26
10
|
addr: import("runtypes").Constraint<String, string, unknown>;
|
|
27
11
|
}, false>, Partial<{
|
|
28
12
|
dnssec: Boolean;
|
|
@@ -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
|
});
|
|
@@ -165,6 +173,76 @@ describe("parseDocumentStoreResults", () => {
|
|
|
165
173
|
];
|
|
166
174
|
expect(parseDocumentStoreResults(sampleRecord, true)).toStrictEqual([]);
|
|
167
175
|
});
|
|
176
|
+
|
|
177
|
+
test("it should accept any numeric netId (e.g. Mantle mainnet 5000)", () => {
|
|
178
|
+
const addr = "0x2f60375e8144e16Adf1979936301D8341D58C36C";
|
|
179
|
+
const sampleRecord = [
|
|
180
|
+
{
|
|
181
|
+
name: "example.example.com.",
|
|
182
|
+
type: 16,
|
|
183
|
+
TTL: 110,
|
|
184
|
+
data: `"openatts net=ethereum netId=5000 addr=${addr}"`,
|
|
185
|
+
dnssec: false,
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
expect(parseDocumentStoreResults(sampleRecord, false)).toStrictEqual([
|
|
189
|
+
{
|
|
190
|
+
type: "openatts",
|
|
191
|
+
net: "ethereum",
|
|
192
|
+
netId: "5000",
|
|
193
|
+
addr,
|
|
194
|
+
dnssec: false,
|
|
195
|
+
},
|
|
196
|
+
]);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("it should accept an arbitrary previously-unknown numeric netId", () => {
|
|
200
|
+
const addr = "0x2f60375e8144e16Adf1979936301D8341D58C36C";
|
|
201
|
+
const sampleRecord = [
|
|
202
|
+
{
|
|
203
|
+
name: "example.example.com.",
|
|
204
|
+
type: 16,
|
|
205
|
+
TTL: 110,
|
|
206
|
+
data: `"openatts net=ethereum netId=99999 addr=${addr}"`,
|
|
207
|
+
dnssec: false,
|
|
208
|
+
},
|
|
209
|
+
];
|
|
210
|
+
expect(parseDocumentStoreResults(sampleRecord, false)).toStrictEqual([
|
|
211
|
+
{
|
|
212
|
+
type: "openatts",
|
|
213
|
+
net: "ethereum",
|
|
214
|
+
netId: "99999",
|
|
215
|
+
addr,
|
|
216
|
+
dnssec: false,
|
|
217
|
+
},
|
|
218
|
+
]);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test("it should reject a non-numeric netId", () => {
|
|
222
|
+
const sampleRecord = [
|
|
223
|
+
{
|
|
224
|
+
name: "example.example.com.",
|
|
225
|
+
type: 16,
|
|
226
|
+
TTL: 110,
|
|
227
|
+
data: '"openatts net=ethereum netId=abc addr=0x2f60375e8144e16Adf1979936301D8341D58C36C"',
|
|
228
|
+
dnssec: false,
|
|
229
|
+
},
|
|
230
|
+
];
|
|
231
|
+
expect(parseDocumentStoreResults(sampleRecord, false)).toStrictEqual([]);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("it should reject an alphanumeric netId", () => {
|
|
235
|
+
const sampleRecord = [
|
|
236
|
+
{
|
|
237
|
+
name: "example.example.com.",
|
|
238
|
+
type: 16,
|
|
239
|
+
TTL: 110,
|
|
240
|
+
data: '"openatts net=ethereum netId=1abc addr=0x2f60375e8144e16Adf1979936301D8341D58C36C"',
|
|
241
|
+
dnssec: false,
|
|
242
|
+
},
|
|
243
|
+
];
|
|
244
|
+
expect(parseDocumentStoreResults(sampleRecord, false)).toStrictEqual([]);
|
|
245
|
+
});
|
|
168
246
|
});
|
|
169
247
|
|
|
170
248
|
describe("queryDns", () => {
|
|
@@ -177,29 +255,29 @@ describe("queryDns", () => {
|
|
|
177
255
|
RA: true,
|
|
178
256
|
AD: true,
|
|
179
257
|
CD: false,
|
|
180
|
-
Question: [{ name: "donotuse.
|
|
258
|
+
Question: [{ name: "donotuse.trustvc.io.", type: 16 }],
|
|
181
259
|
Answer: [
|
|
182
260
|
{
|
|
183
|
-
name: "donotuse.
|
|
261
|
+
name: "donotuse.trustvc.io.",
|
|
184
262
|
type: 16,
|
|
185
263
|
TTL: 300,
|
|
186
264
|
data: "openatts a=dns-did; p=did:ethr:0xE712878f6E8d5d4F9e87E10DA604F9cB564C9a89#controller; v=1.0;",
|
|
187
265
|
},
|
|
188
266
|
{
|
|
189
|
-
name: "donotuse.
|
|
267
|
+
name: "donotuse.trustvc.io.",
|
|
190
268
|
type: 16,
|
|
191
269
|
TTL: 300,
|
|
192
270
|
data:
|
|
193
271
|
"openatts DO NOT ADD ANY RECORDS BEYOND THIS AS THIS DOMAIN IS USED FOR DNSPROVE NPM LIBRARY INTEGRATION TESTS",
|
|
194
272
|
},
|
|
195
273
|
{
|
|
196
|
-
name: "donotuse.
|
|
274
|
+
name: "donotuse.trustvc.io.",
|
|
197
275
|
type: 16,
|
|
198
276
|
TTL: 300,
|
|
199
277
|
data: "openatts fooooooobarrrrrrrrr this entry exists to ensure validation works",
|
|
200
278
|
},
|
|
201
279
|
{
|
|
202
|
-
name: "donotuse.
|
|
280
|
+
name: "donotuse.trustvc.io.",
|
|
203
281
|
type: 16,
|
|
204
282
|
TTL: 300,
|
|
205
283
|
data: "openatts net=ethereum netId=3 addr=0x2f60375e8144e16Adf1979936301D8341D58C36C",
|
|
@@ -208,22 +286,7 @@ describe("queryDns", () => {
|
|
|
208
286
|
Comment: "Response from 205.251.199.177.",
|
|
209
287
|
};
|
|
210
288
|
|
|
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
|
-
];
|
|
289
|
+
const testDnsResolvers = [googleDnsResolver, cloudflareDnsResolver, aliDnsResolver];
|
|
227
290
|
|
|
228
291
|
afterEach(() => {
|
|
229
292
|
server.close();
|
|
@@ -239,7 +302,7 @@ describe("queryDns", () => {
|
|
|
239
302
|
server = setupServer(...handlers);
|
|
240
303
|
server.listen();
|
|
241
304
|
|
|
242
|
-
const records = await queryDns("https://donotuse.
|
|
305
|
+
const records = await queryDns("https://donotuse.trustvc.io", testDnsResolvers);
|
|
243
306
|
const sortedAnswer = records?.Answer.sort((a, b) => a.data.localeCompare(b.data));
|
|
244
307
|
expect(sortedAnswer).toMatchObject(sampleResponse.Answer);
|
|
245
308
|
});
|
|
@@ -256,7 +319,28 @@ describe("queryDns", () => {
|
|
|
256
319
|
server = setupServer(...handlers);
|
|
257
320
|
server.listen();
|
|
258
321
|
|
|
259
|
-
const records = await queryDns("https://donotuse.
|
|
322
|
+
const records = await queryDns("https://donotuse.trustvc.io", testDnsResolvers);
|
|
323
|
+
|
|
324
|
+
const sortedAnswer = records?.Answer.sort((a, b) => a.data.localeCompare(b.data));
|
|
325
|
+
expect(sortedAnswer).toMatchObject(sampleResponse.Answer);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test("Should fallback to third dns when first and second dns is down", async () => {
|
|
329
|
+
const handlers = [
|
|
330
|
+
http.get("https://dns.google/resolve", (_) => {
|
|
331
|
+
return new HttpResponse(null, { status: 500 });
|
|
332
|
+
}),
|
|
333
|
+
http.get("https://cloudflare-dns.com/dns-query", (_) => {
|
|
334
|
+
return new HttpResponse(null, { status: 500 });
|
|
335
|
+
}),
|
|
336
|
+
http.get("https://dns.alidns.com/resolve", (_) => {
|
|
337
|
+
return HttpResponse.json(sampleResponse);
|
|
338
|
+
}),
|
|
339
|
+
];
|
|
340
|
+
server = setupServer(...handlers);
|
|
341
|
+
server.listen();
|
|
342
|
+
|
|
343
|
+
const records = await queryDns("https://donotuse.trustvc.io", testDnsResolvers);
|
|
260
344
|
|
|
261
345
|
const sortedAnswer = records?.Answer.sort((a, b) => a.data.localeCompare(b.data));
|
|
262
346
|
expect(sortedAnswer).toMatchObject(sampleResponse.Answer);
|
|
@@ -270,14 +354,16 @@ describe("queryDns", () => {
|
|
|
270
354
|
http.get("https://cloudflare-dns.com/dns-query", (_) => {
|
|
271
355
|
return new HttpResponse(null, { status: 500 });
|
|
272
356
|
}),
|
|
357
|
+
http.get("https://dns.alidns.com/resolve", (_) => {
|
|
358
|
+
return new HttpResponse(null, { status: 500 });
|
|
359
|
+
}),
|
|
273
360
|
];
|
|
274
361
|
server = setupServer(...handlers);
|
|
275
362
|
server.listen();
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
363
|
+
|
|
364
|
+
await expect(queryDns("https://donotuse.trustvc.io", testDnsResolvers)).rejects.toMatchObject({
|
|
365
|
+
code: DnsproveStatusCode.IDNS_QUERY_ERROR_GENERAL,
|
|
366
|
+
});
|
|
281
367
|
});
|
|
282
368
|
});
|
|
283
369
|
|
|
@@ -321,6 +407,13 @@ describe("getDocumentStoreRecords for Astron", () => {
|
|
|
321
407
|
addr: "0x18bc0127Ae33389cD96593a1a612774fD14c0737",
|
|
322
408
|
dnssec: false,
|
|
323
409
|
},
|
|
410
|
+
{
|
|
411
|
+
type: "openatts",
|
|
412
|
+
net: "ethereum",
|
|
413
|
+
netId: "1338",
|
|
414
|
+
addr: "0x94FD21A026E29E0686583b8be71Cb28a8ca1A8d4",
|
|
415
|
+
dnssec: false,
|
|
416
|
+
},
|
|
324
417
|
{
|
|
325
418
|
type: "openatts",
|
|
326
419
|
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";
|
package/src/records/dnsTxt.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Static, Boolean, String, Literal, Record,
|
|
1
|
+
import { Static, Boolean, String, Literal, Record, Partial } from "runtypes";
|
|
2
2
|
|
|
3
3
|
export const RecordTypesT = Literal("openatts");
|
|
4
4
|
|
|
@@ -8,38 +8,8 @@ export const EthereumAddressT = String.withConstraint((maybeAddress: string) =>
|
|
|
8
8
|
return /0x[a-fA-F0-9]{40}/.test(maybeAddress) || `${maybeAddress} is not a valid ethereum address`;
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
ropsten = "3",
|
|
14
|
-
rinkeby = "4",
|
|
15
|
-
goerli = "5",
|
|
16
|
-
sepolia = "11155111",
|
|
17
|
-
polygon = "137",
|
|
18
|
-
polygonAmoy = "80002",
|
|
19
|
-
local = "1337",
|
|
20
|
-
xdc = "50",
|
|
21
|
-
xdcapothem = "51",
|
|
22
|
-
stabilityTestnet = "20180427",
|
|
23
|
-
stability = "101010",
|
|
24
|
-
astronTestnet = "21002",
|
|
25
|
-
astron = "1338",
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const EthereumNetworkIdT = Union(
|
|
29
|
-
Literal(EthereumNetworks.homestead),
|
|
30
|
-
Literal(EthereumNetworks.ropsten),
|
|
31
|
-
Literal(EthereumNetworks.rinkeby),
|
|
32
|
-
Literal(EthereumNetworks.goerli),
|
|
33
|
-
Literal(EthereumNetworks.sepolia),
|
|
34
|
-
Literal(EthereumNetworks.polygon),
|
|
35
|
-
Literal(EthereumNetworks.polygonAmoy),
|
|
36
|
-
Literal(EthereumNetworks.xdc),
|
|
37
|
-
Literal(EthereumNetworks.xdcapothem),
|
|
38
|
-
Literal(EthereumNetworks.stabilityTestnet),
|
|
39
|
-
Literal(EthereumNetworks.stability),
|
|
40
|
-
Literal(EthereumNetworks.local),
|
|
41
|
-
Literal(EthereumNetworks.astronTestnet),
|
|
42
|
-
Literal(EthereumNetworks.astron)
|
|
11
|
+
export const EthereumNetworkIdT = String.withConstraint(
|
|
12
|
+
(maybeNetId: string) => /^\d+$/.test(maybeNetId) || `${maybeNetId} is not a valid numeric network id`
|
|
43
13
|
);
|
|
44
14
|
|
|
45
15
|
export const OpenAttestationDNSTextRecordT = Record({
|
|
@@ -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
|
+
};
|