@tradetrust-tt/dnsprove 2.8.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/CHANGELOG.md +1 -0
- package/LICENSE +201 -0
- package/README.md +160 -0
- package/dist/common/error.js +31 -0
- package/dist/index.js +285 -0
- package/dist/records/dnsDid.js +56 -0
- package/dist/records/dnsTxt.js +48 -0
- package/dist/ts/common/error.d.ts +8 -0
- package/dist/ts/index.d.ts +43 -0
- package/dist/ts/index.test.d.ts +1 -0
- package/dist/ts/records/dnsDid.d.ts +15 -0
- package/dist/ts/records/dnsDid.test.d.ts +1 -0
- package/dist/ts/records/dnsTxt.d.ts +29 -0
- package/dist/ts/util/logger.d.ts +9 -0
- package/dist/util/logger.js +31 -0
- package/package.json +101 -0
- package/src/common/error.ts +14 -0
- package/src/index.test.ts +257 -0
- package/src/index.ts +219 -0
- package/src/records/dnsDid.test.ts +17 -0
- package/src/records/dnsDid.ts +29 -0
- package/src/records/dnsTxt.ts +51 -0
- package/src/util/logger.ts +12 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.OpenAttestationDnsDidRecordT = exports.PublicKeyT = exports.VersionT = exports.AlgorithmT = exports.RecordTypesT = exports.validateDid = void 0;
|
|
7
|
+
|
|
8
|
+
var _runtypes = require("runtypes");
|
|
9
|
+
|
|
10
|
+
function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableRest(); }
|
|
11
|
+
|
|
12
|
+
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."); }
|
|
13
|
+
|
|
14
|
+
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); }
|
|
15
|
+
|
|
16
|
+
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; }
|
|
17
|
+
|
|
18
|
+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
19
|
+
|
|
20
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
21
|
+
|
|
22
|
+
// References https://www.w3.org/TR/did-core/#did-syntax
|
|
23
|
+
const validateDid = maybeDid => {
|
|
24
|
+
const _maybeDid$split = maybeDid.split(":"),
|
|
25
|
+
_maybeDid$split2 = _toArray(_maybeDid$split),
|
|
26
|
+
did = _maybeDid$split2[0],
|
|
27
|
+
methodName = _maybeDid$split2[1],
|
|
28
|
+
methodSpecificIdParts = _maybeDid$split2.slice(2);
|
|
29
|
+
|
|
30
|
+
const methodSpecificId = methodSpecificIdParts.join(":");
|
|
31
|
+
if (did !== "did" || !methodName || !methodSpecificId || !/[a-z]+/.test(methodName)) return false;
|
|
32
|
+
return true;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
exports.validateDid = validateDid;
|
|
36
|
+
const RecordTypesT = (0, _runtypes.Literal)("openatts");
|
|
37
|
+
exports.RecordTypesT = RecordTypesT;
|
|
38
|
+
const AlgorithmT = (0, _runtypes.Union)((0, _runtypes.Literal)("dns-did"));
|
|
39
|
+
exports.AlgorithmT = AlgorithmT;
|
|
40
|
+
const VersionT = _runtypes.String;
|
|
41
|
+
exports.VersionT = VersionT;
|
|
42
|
+
|
|
43
|
+
const PublicKeyT = _runtypes.String.withConstraint(maybeDid => {
|
|
44
|
+
return validateDid(maybeDid) || `${maybeDid} is not a valid did`;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
exports.PublicKeyT = PublicKeyT;
|
|
48
|
+
const OpenAttestationDnsDidRecordT = (0, _runtypes.Record)({
|
|
49
|
+
type: RecordTypesT,
|
|
50
|
+
algorithm: AlgorithmT,
|
|
51
|
+
publicKey: PublicKeyT,
|
|
52
|
+
version: VersionT
|
|
53
|
+
}).And((0, _runtypes.Partial)({
|
|
54
|
+
dnssec: _runtypes.Boolean
|
|
55
|
+
}));
|
|
56
|
+
exports.OpenAttestationDnsDidRecordT = OpenAttestationDnsDidRecordT;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.OpenAttestationDNSTextRecordT = exports.EthereumNetworkIdT = exports.EthereumNetworks = exports.EthereumAddressT = exports.BlockchainNetworkT = exports.RecordTypesT = void 0;
|
|
7
|
+
|
|
8
|
+
var _runtypes = require("runtypes");
|
|
9
|
+
|
|
10
|
+
const RecordTypesT = (0, _runtypes.Literal)("openatts");
|
|
11
|
+
exports.RecordTypesT = RecordTypesT;
|
|
12
|
+
const BlockchainNetworkT = (0, _runtypes.Literal)("ethereum");
|
|
13
|
+
exports.BlockchainNetworkT = BlockchainNetworkT;
|
|
14
|
+
|
|
15
|
+
const EthereumAddressT = _runtypes.String.withConstraint(maybeAddress => {
|
|
16
|
+
return /0x[a-fA-F0-9]{40}/.test(maybeAddress) || `${maybeAddress} is not a valid ethereum address`;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
exports.EthereumAddressT = EthereumAddressT;
|
|
20
|
+
let EthereumNetworks;
|
|
21
|
+
exports.EthereumNetworks = EthereumNetworks;
|
|
22
|
+
|
|
23
|
+
(function (EthereumNetworks) {
|
|
24
|
+
EthereumNetworks["homestead"] = "1";
|
|
25
|
+
EthereumNetworks["ropsten"] = "3";
|
|
26
|
+
EthereumNetworks["rinkeby"] = "4";
|
|
27
|
+
EthereumNetworks["goerli"] = "5";
|
|
28
|
+
EthereumNetworks["sepolia"] = "11155111";
|
|
29
|
+
EthereumNetworks["polygon"] = "137";
|
|
30
|
+
EthereumNetworks["polygonMumbai"] = "80001";
|
|
31
|
+
EthereumNetworks["local"] = "1337";
|
|
32
|
+
EthereumNetworks["xdc"] = "50";
|
|
33
|
+
EthereumNetworks["xdcapothem"] = "51";
|
|
34
|
+
})(EthereumNetworks || (exports.EthereumNetworks = EthereumNetworks = {}));
|
|
35
|
+
|
|
36
|
+
const 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.polygonMumbai), (0, _runtypes.Literal)(EthereumNetworks.xdc), (0, _runtypes.Literal)(EthereumNetworks.xdcapothem), (0, _runtypes.Literal)(EthereumNetworks.local));
|
|
37
|
+
exports.EthereumNetworkIdT = EthereumNetworkIdT;
|
|
38
|
+
const OpenAttestationDNSTextRecordT = (0, _runtypes.Record)({
|
|
39
|
+
type: RecordTypesT,
|
|
40
|
+
net: BlockchainNetworkT,
|
|
41
|
+
// key names are directly lifted from the dns-txt record format
|
|
42
|
+
netId: EthereumNetworkIdT,
|
|
43
|
+
// they are abbreviated because of 255 char constraint on dns-txt records
|
|
44
|
+
addr: EthereumAddressT
|
|
45
|
+
}).And((0, _runtypes.Partial)({
|
|
46
|
+
dnssec: _runtypes.Boolean
|
|
47
|
+
}));
|
|
48
|
+
exports.OpenAttestationDNSTextRecordT = OpenAttestationDNSTextRecordT;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { OpenAttestationDNSTextRecord } from "./records/dnsTxt";
|
|
2
|
+
import { OpenAttestationDnsDidRecord } from "./records/dnsDid";
|
|
3
|
+
export interface IDNSRecord {
|
|
4
|
+
name: string;
|
|
5
|
+
type: number;
|
|
6
|
+
TTL: number;
|
|
7
|
+
data: string;
|
|
8
|
+
}
|
|
9
|
+
export interface IDNSQueryResponse {
|
|
10
|
+
AD: boolean;
|
|
11
|
+
Answer: IDNSRecord[];
|
|
12
|
+
}
|
|
13
|
+
interface GenericObject {
|
|
14
|
+
[key: string]: string;
|
|
15
|
+
}
|
|
16
|
+
export declare type CustomDnsResolver = (domain: string) => Promise<IDNSQueryResponse>;
|
|
17
|
+
export declare const defaultDnsResolvers: CustomDnsResolver[];
|
|
18
|
+
export declare const queryDns: (domain: string, customDnsResolvers: CustomDnsResolver[]) => Promise<IDNSQueryResponse>;
|
|
19
|
+
/**
|
|
20
|
+
* Parses one openattestation DNS-TXT record and turns it into an OpenAttestationsDNSTextRecord object
|
|
21
|
+
* @param record e.g: '"openatts net=ethereum netId=3 addr=0x0c9d5E6C766030cc6f0f49951D275Ad0701F81EC"'
|
|
22
|
+
*/
|
|
23
|
+
export declare const parseOpenAttestationRecord: (record: string) => GenericObject;
|
|
24
|
+
/**
|
|
25
|
+
* Takes a DNS-TXT Record set and returns openattestation document store records if any
|
|
26
|
+
* @param recordSet Refer to tests for examples
|
|
27
|
+
*/
|
|
28
|
+
export declare const parseDocumentStoreResults: (recordSet: IDNSRecord[] | undefined, dnssec: boolean) => OpenAttestationDNSTextRecord[];
|
|
29
|
+
export declare const parseDnsDidResults: (recordSet: IDNSRecord[] | undefined, dnssec: boolean) => OpenAttestationDnsDidRecord[];
|
|
30
|
+
/**
|
|
31
|
+
* Queries a given domain and parses the results to retrieve openattestation document store records if any
|
|
32
|
+
* @param domain e.g: "example.openattestation.com"
|
|
33
|
+
* @example
|
|
34
|
+
* > getDocumentStoreRecords("example.openattestation.com")
|
|
35
|
+
* > [ { type: 'openatts',
|
|
36
|
+
net: 'ethereum',
|
|
37
|
+
netId: '3',
|
|
38
|
+
addr: '0x2f60375e8144e16Adf1979936301D8341D58C36C',
|
|
39
|
+
dnssec: true } ]
|
|
40
|
+
*/
|
|
41
|
+
export declare const getDocumentStoreRecords: (domain: string, customDnsResolvers?: CustomDnsResolver[] | undefined) => Promise<OpenAttestationDNSTextRecord[]>;
|
|
42
|
+
export declare const getDnsDidRecords: (domain: string, customDnsResolvers?: CustomDnsResolver[] | undefined) => Promise<OpenAttestationDnsDidRecord[]>;
|
|
43
|
+
export { OpenAttestationDNSTextRecord, OpenAttestationDnsDidRecord };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Static, Boolean, String, Literal, Record, Union, Partial } from "runtypes";
|
|
2
|
+
export declare const validateDid: (maybeDid: string) => boolean;
|
|
3
|
+
export declare const RecordTypesT: Literal<"openatts">;
|
|
4
|
+
export declare const AlgorithmT: Union<[Literal<"dns-did">]>;
|
|
5
|
+
export declare const VersionT: String;
|
|
6
|
+
export declare const PublicKeyT: import("runtypes").Constraint<String, string, unknown>;
|
|
7
|
+
export declare const OpenAttestationDnsDidRecordT: import("runtypes").Intersect<[Record<{
|
|
8
|
+
type: Literal<"openatts">;
|
|
9
|
+
algorithm: Union<[Literal<"dns-did">]>;
|
|
10
|
+
publicKey: import("runtypes").Constraint<String, string, unknown>;
|
|
11
|
+
version: String;
|
|
12
|
+
}, false>, Partial<{
|
|
13
|
+
dnssec: Boolean;
|
|
14
|
+
}, false>]>;
|
|
15
|
+
export declare type OpenAttestationDnsDidRecord = Static<typeof OpenAttestationDnsDidRecordT>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Static, Boolean, String, Literal, Record, Union, Partial } from "runtypes";
|
|
2
|
+
export declare const RecordTypesT: Literal<"openatts">;
|
|
3
|
+
export declare const BlockchainNetworkT: Literal<"ethereum">;
|
|
4
|
+
export declare const EthereumAddressT: import("runtypes").Constraint<String, string, unknown>;
|
|
5
|
+
export declare enum EthereumNetworks {
|
|
6
|
+
homestead = "1",
|
|
7
|
+
ropsten = "3",
|
|
8
|
+
rinkeby = "4",
|
|
9
|
+
goerli = "5",
|
|
10
|
+
sepolia = "11155111",
|
|
11
|
+
polygon = "137",
|
|
12
|
+
polygonMumbai = "80001",
|
|
13
|
+
local = "1337",
|
|
14
|
+
xdc = "50",
|
|
15
|
+
xdcapothem = "51"
|
|
16
|
+
}
|
|
17
|
+
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.polygonMumbai>, Literal<EthereumNetworks.xdc>, Literal<EthereumNetworks.xdcapothem>, Literal<EthereumNetworks.local>]>;
|
|
18
|
+
export declare const OpenAttestationDNSTextRecordT: import("runtypes").Intersect<[Record<{
|
|
19
|
+
type: Literal<"openatts">;
|
|
20
|
+
net: Literal<"ethereum">;
|
|
21
|
+
netId: Union<[Literal<EthereumNetworks.homestead>, Literal<EthereumNetworks.ropsten>, Literal<EthereumNetworks.rinkeby>, Literal<EthereumNetworks.goerli>, Literal<EthereumNetworks.sepolia>, Literal<EthereumNetworks.polygon>, Literal<EthereumNetworks.polygonMumbai>, Literal<EthereumNetworks.xdc>, Literal<EthereumNetworks.xdcapothem>, Literal<EthereumNetworks.local>]>;
|
|
22
|
+
addr: import("runtypes").Constraint<String, string, unknown>;
|
|
23
|
+
}, false>, Partial<{
|
|
24
|
+
dnssec: Boolean;
|
|
25
|
+
}, false>]>;
|
|
26
|
+
export declare type BlockchainNetwork = Static<typeof BlockchainNetworkT>;
|
|
27
|
+
export declare type EthereumAddress = Static<typeof EthereumAddressT>;
|
|
28
|
+
export declare type OpenAttestationDNSTextRecord = Static<typeof OpenAttestationDNSTextRecordT>;
|
|
29
|
+
export declare type RecordTypes = Static<typeof RecordTypesT>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="debug" />
|
|
2
|
+
export declare const trace: (namespace: string) => import("debug").Debugger;
|
|
3
|
+
export declare const info: (namespace: string) => import("debug").Debugger;
|
|
4
|
+
export declare const error: (namespace: string) => import("debug").Debugger;
|
|
5
|
+
export declare const getLogger: (namespace: string) => {
|
|
6
|
+
trace: import("debug").Debugger;
|
|
7
|
+
info: import("debug").Debugger;
|
|
8
|
+
error: import("debug").Debugger;
|
|
9
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getLogger = exports.error = exports.info = exports.trace = void 0;
|
|
7
|
+
|
|
8
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
9
|
+
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
|
|
12
|
+
// not using .extends because of next.js resolve modules bug where its picking up old version of debug
|
|
13
|
+
const trace = namespace => (0, _debug.default)(`dnsprove:trace:${namespace}`);
|
|
14
|
+
|
|
15
|
+
exports.trace = trace;
|
|
16
|
+
|
|
17
|
+
const info = namespace => (0, _debug.default)(`dnsprove:info:${namespace}`);
|
|
18
|
+
|
|
19
|
+
exports.info = info;
|
|
20
|
+
|
|
21
|
+
const error = namespace => (0, _debug.default)(`dnsprove:error:${namespace}`);
|
|
22
|
+
|
|
23
|
+
exports.error = error;
|
|
24
|
+
|
|
25
|
+
const getLogger = namespace => ({
|
|
26
|
+
trace: trace(namespace),
|
|
27
|
+
info: info(namespace),
|
|
28
|
+
error: error(namespace)
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
exports.getLogger = getLogger;
|
package/package.json
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tradetrust-tt/dnsprove",
|
|
3
|
+
"version": "2.8.0",
|
|
4
|
+
"description": "Helper utility for retrieving OpenAttestations document store address records from DNS",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/TradeTrust/dnsprove.git"
|
|
9
|
+
},
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "RJ Chow",
|
|
13
|
+
"email": "me@rjchow.com",
|
|
14
|
+
"url": "https://github.com/rjchow"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"type-check": "tsc --noEmit",
|
|
22
|
+
"test": "jest",
|
|
23
|
+
"coverage": "npm test -- --coverage",
|
|
24
|
+
"postcoverage": "open-cli coverage/lcov-report/index.html",
|
|
25
|
+
"commit": "git-cz",
|
|
26
|
+
"commit:retry": "git-cz --retry",
|
|
27
|
+
"lint": "eslint . --ext js,ts,tsx",
|
|
28
|
+
"lint:fix": "npm run lint -- --fix",
|
|
29
|
+
"docs": "documentation readme src/index.ts --section=API --document-exported --babel=./.babelrc --parse-extension=ts",
|
|
30
|
+
"postdocs": "git add README.md",
|
|
31
|
+
"clean": "rimraf dist",
|
|
32
|
+
"prebuild": "npm run docs && npm run clean",
|
|
33
|
+
"build": "tsc --emitDeclarationOnly && babel src -d dist --ignore **/*.d.ts,src/**/*.spec.ts,src/**/*.test.ts -x .js,.ts,.tsx",
|
|
34
|
+
"preversion": "npm run lint && npm test && npm run build",
|
|
35
|
+
"semantic-release": "semantic-release"
|
|
36
|
+
},
|
|
37
|
+
"types": "dist/ts",
|
|
38
|
+
"husky": {
|
|
39
|
+
"hooks": {
|
|
40
|
+
"pre-commit": "lint-staged"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"lint-staged": {
|
|
44
|
+
"*.{js,ts,tsx}": [
|
|
45
|
+
"eslint --fix --ext js,ts,tsx",
|
|
46
|
+
"git add"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"generator-nod"
|
|
51
|
+
],
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"axios": "^0.21.1",
|
|
54
|
+
"debug": "^4.3.1",
|
|
55
|
+
"runtypes": "^6.3.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@babel/cli": "^7.13.16",
|
|
59
|
+
"@babel/core": "^7.13.16",
|
|
60
|
+
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
|
61
|
+
"@babel/preset-env": "^7.13.15",
|
|
62
|
+
"@babel/preset-typescript": "^7.13.0",
|
|
63
|
+
"@commitlint/cli": "^12.1.1",
|
|
64
|
+
"@commitlint/config-conventional": "^12.1.1",
|
|
65
|
+
"@commitlint/prompt": "^12.1.1",
|
|
66
|
+
"@ls-age/commitlint-circle": "^1.0.0",
|
|
67
|
+
"@types/axios": "^0.14.0",
|
|
68
|
+
"@types/debug": "^4.1.5",
|
|
69
|
+
"@types/jest": "^26.0.23",
|
|
70
|
+
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
|
71
|
+
"@typescript-eslint/parser": "^4.22.0",
|
|
72
|
+
"babel-eslint": "^10.1.0",
|
|
73
|
+
"babel-jest": "^26.6.3",
|
|
74
|
+
"commitizen": "^4.2.3",
|
|
75
|
+
"documentation": "^13.2.5",
|
|
76
|
+
"eslint": "^7.25.0",
|
|
77
|
+
"eslint-config-airbnb-base": "^14.2.1",
|
|
78
|
+
"eslint-config-prettier": "^8.3.0",
|
|
79
|
+
"eslint-plugin-import": "^2.22.1",
|
|
80
|
+
"eslint-plugin-prettier": "^3.4.0",
|
|
81
|
+
"git-cz": "^4.7.6",
|
|
82
|
+
"husky": "^6.0.0",
|
|
83
|
+
"jest": "^26.6.3",
|
|
84
|
+
"lint-staged": "^10.5.4",
|
|
85
|
+
"msw": "0.35.0",
|
|
86
|
+
"open-cli": "^6.0.1",
|
|
87
|
+
"prettier": "^2.2.1",
|
|
88
|
+
"rimraf": "^3.0.2",
|
|
89
|
+
"semantic-release": "^17.4.2",
|
|
90
|
+
"ts-jest": "^26.5.5",
|
|
91
|
+
"typescript": "^4.2.4"
|
|
92
|
+
},
|
|
93
|
+
"publishConfig": {
|
|
94
|
+
"access": "public"
|
|
95
|
+
},
|
|
96
|
+
"config": {
|
|
97
|
+
"commitizen": {
|
|
98
|
+
"path": "node_modules/@commitlint/prompt"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export enum DnsproveStatusCode {
|
|
2
|
+
IDNS_QUERY_ERROR_GENERAL = 0,
|
|
3
|
+
}
|
|
4
|
+
export class CodedError extends Error {
|
|
5
|
+
code: number;
|
|
6
|
+
|
|
7
|
+
codeString: string;
|
|
8
|
+
|
|
9
|
+
constructor(message: string, code: DnsproveStatusCode, codeString: string) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.codeString = codeString;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { setupServer, SetupServerApi } from "msw/node";
|
|
3
|
+
import { rest } from "msw";
|
|
4
|
+
import { CustomDnsResolver, getDocumentStoreRecords, queryDns, parseDocumentStoreResults, getDnsDidRecords } from ".";
|
|
5
|
+
import { DnsproveStatusCode } from "./common/error";
|
|
6
|
+
|
|
7
|
+
describe("getCertStoreRecords", () => {
|
|
8
|
+
const sampleDnsTextRecordWithDnssec = {
|
|
9
|
+
type: "openatts",
|
|
10
|
+
net: "ethereum",
|
|
11
|
+
netId: "3",
|
|
12
|
+
dnssec: true,
|
|
13
|
+
addr: "0x2f60375e8144e16Adf1979936301D8341D58C36C",
|
|
14
|
+
};
|
|
15
|
+
test("it should work", async () => {
|
|
16
|
+
const records = await getDocumentStoreRecords("donotuse.openattestation.com");
|
|
17
|
+
expect(records).toStrictEqual([sampleDnsTextRecordWithDnssec]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("it should return an empty array if there is no openatts record", async () => {
|
|
21
|
+
expect(await getDocumentStoreRecords("google.com")).toStrictEqual([]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("it should return an empty array with a non-existent domain", async () => {
|
|
25
|
+
expect(await getDocumentStoreRecords("thisdoesnotexist.gov.sg")).toStrictEqual([]);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe("getDnsDidRecords", () => {
|
|
30
|
+
test("it should work", async () => {
|
|
31
|
+
const records = await getDnsDidRecords("donotuse.openattestation.com");
|
|
32
|
+
expect(records).toStrictEqual([
|
|
33
|
+
{
|
|
34
|
+
type: "openatts",
|
|
35
|
+
algorithm: "dns-did",
|
|
36
|
+
publicKey: "did:ethr:0xE712878f6E8d5d4F9e87E10DA604F9cB564C9a89#controller",
|
|
37
|
+
version: "1.0",
|
|
38
|
+
dnssec: true,
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("it should return an empty array if there is no openatts record", async () => {
|
|
44
|
+
const records = await getDnsDidRecords("google.com");
|
|
45
|
+
expect(records).toStrictEqual([]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("it should return an empty array with a non-existent domain", async () => {
|
|
49
|
+
const records = await getDnsDidRecords("thisdoesnotexist.gov.sg");
|
|
50
|
+
expect(records).toStrictEqual([]);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("parseDocumentStoreResults", () => {
|
|
55
|
+
test("it should return one record in an array if there is one openatts record", () => {
|
|
56
|
+
const sampleRecord = [
|
|
57
|
+
{
|
|
58
|
+
name: "example.openattestation.com.",
|
|
59
|
+
type: 16,
|
|
60
|
+
TTL: 110,
|
|
61
|
+
data: '"openatts net=ethereum netId=3 addr=0x2f60375e8144e16Adf1979936301D8341D58C36C"',
|
|
62
|
+
dnssec: true,
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
expect(parseDocumentStoreResults(sampleRecord, true)).toStrictEqual([
|
|
66
|
+
{
|
|
67
|
+
type: "openatts",
|
|
68
|
+
net: "ethereum",
|
|
69
|
+
netId: "3",
|
|
70
|
+
addr: "0x2f60375e8144e16Adf1979936301D8341D58C36C",
|
|
71
|
+
dnssec: true,
|
|
72
|
+
},
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
test("it should correctly handle cases where the TXT record is not double quoted", () => {
|
|
76
|
+
const sampleRecord = [
|
|
77
|
+
{
|
|
78
|
+
name: "example.openattestation.com.",
|
|
79
|
+
type: 16,
|
|
80
|
+
TTL: 110,
|
|
81
|
+
data: "openatts net=ethereum netId=3 addr=0x2f60375e8144e16Adf1979936301D8341D58C36C",
|
|
82
|
+
dnssec: true,
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
expect(parseDocumentStoreResults(sampleRecord, true)).toStrictEqual([
|
|
86
|
+
{
|
|
87
|
+
type: "openatts",
|
|
88
|
+
net: "ethereum",
|
|
89
|
+
netId: "3",
|
|
90
|
+
addr: "0x2f60375e8144e16Adf1979936301D8341D58C36C",
|
|
91
|
+
dnssec: true,
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
});
|
|
95
|
+
test("it should return two record items if there are two openatts record", () => {
|
|
96
|
+
const sampleRecord = [
|
|
97
|
+
{
|
|
98
|
+
name: "example.openattestation.com.",
|
|
99
|
+
type: 16,
|
|
100
|
+
TTL: 110,
|
|
101
|
+
data: '"openatts net=ethereum netId=3 addr=0x2f60375e8144e16Adf1979936301D8341D58C36C"',
|
|
102
|
+
dnssec: true,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: "example.openattestation.com.",
|
|
106
|
+
type: 16,
|
|
107
|
+
TTL: 110,
|
|
108
|
+
data: '"openatts net=ethereum netId=1 addr=0x007d40224f6562461633ccfbaffd359ebb2fc9ba"',
|
|
109
|
+
dnssec: true,
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
expect(parseDocumentStoreResults(sampleRecord, true)).toStrictEqual([
|
|
114
|
+
{
|
|
115
|
+
addr: "0x2f60375e8144e16Adf1979936301D8341D58C36C",
|
|
116
|
+
net: "ethereum",
|
|
117
|
+
netId: "3",
|
|
118
|
+
type: "openatts",
|
|
119
|
+
dnssec: true,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
addr: "0x007d40224f6562461633ccfbaffd359ebb2fc9ba",
|
|
123
|
+
net: "ethereum",
|
|
124
|
+
netId: "1",
|
|
125
|
+
type: "openatts",
|
|
126
|
+
dnssec: true,
|
|
127
|
+
},
|
|
128
|
+
]);
|
|
129
|
+
});
|
|
130
|
+
test("it should omit malformed records even if it has openatts header", () => {
|
|
131
|
+
const sampleRecord = [
|
|
132
|
+
{
|
|
133
|
+
name: "example.openattestation.com.",
|
|
134
|
+
type: 16,
|
|
135
|
+
TTL: 110,
|
|
136
|
+
data: '"openatts foobarbar"',
|
|
137
|
+
dnssec: true,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: "example.openattestation.com.",
|
|
141
|
+
type: 16,
|
|
142
|
+
TTL: 110,
|
|
143
|
+
data: '"openatts net=ethereum netId=1 addr=0x007d40224f6562461633ccfbaffd359ebb2fc9ba"',
|
|
144
|
+
dnssec: true,
|
|
145
|
+
},
|
|
146
|
+
];
|
|
147
|
+
expect(parseDocumentStoreResults(sampleRecord, true)).toStrictEqual([
|
|
148
|
+
{
|
|
149
|
+
addr: "0x007d40224f6562461633ccfbaffd359ebb2fc9ba",
|
|
150
|
+
net: "ethereum",
|
|
151
|
+
netId: "1",
|
|
152
|
+
type: "openatts",
|
|
153
|
+
dnssec: true,
|
|
154
|
+
},
|
|
155
|
+
]);
|
|
156
|
+
});
|
|
157
|
+
test("should not return a record if addr fails ethereum regex", () => {
|
|
158
|
+
const sampleRecord = [
|
|
159
|
+
{
|
|
160
|
+
name: "example.openattestation.com.",
|
|
161
|
+
type: 16,
|
|
162
|
+
TTL: 110,
|
|
163
|
+
data: '"openatts net=ethereum netId=3 addr=0x2f60375e8144e16Adf19=79936301D8341D58C36C"',
|
|
164
|
+
dnssec: true,
|
|
165
|
+
},
|
|
166
|
+
];
|
|
167
|
+
expect(parseDocumentStoreResults(sampleRecord, true)).toStrictEqual([]);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe("queryDns", () => {
|
|
172
|
+
let server: SetupServerApi;
|
|
173
|
+
|
|
174
|
+
const sampleResponse = {
|
|
175
|
+
AD: false,
|
|
176
|
+
Answer: [
|
|
177
|
+
{
|
|
178
|
+
name: "google.com",
|
|
179
|
+
type: 16,
|
|
180
|
+
TTL: 3529,
|
|
181
|
+
data: '"docusign=1b0a6754-49b1-4db5-8540-d2c12664b289"',
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const testDnsResolvers: CustomDnsResolver[] = [
|
|
187
|
+
async (domain) => {
|
|
188
|
+
const { data } = await axios({
|
|
189
|
+
method: "GET",
|
|
190
|
+
url: `https://dns.google/resolve?name=${domain}&type=TXT`,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return data;
|
|
194
|
+
},
|
|
195
|
+
async (domain) => {
|
|
196
|
+
const { data } = await axios({
|
|
197
|
+
method: "GET",
|
|
198
|
+
url: `https://cloudflare-dns.com/dns-query?name=${domain}&type=TXT`,
|
|
199
|
+
headers: { accept: "application/dns-json", contentType: "application/json", connection: "keep-alive" },
|
|
200
|
+
});
|
|
201
|
+
return data;
|
|
202
|
+
},
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
afterEach(() => {
|
|
206
|
+
server.close();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("Should work for first dns if first dns is not down", async () => {
|
|
210
|
+
const handlers = [
|
|
211
|
+
rest.get("https://dns.google/resolve", (_, res, ctx) => {
|
|
212
|
+
return res(ctx.json(sampleResponse));
|
|
213
|
+
}),
|
|
214
|
+
];
|
|
215
|
+
|
|
216
|
+
server = setupServer(...handlers);
|
|
217
|
+
server.listen();
|
|
218
|
+
|
|
219
|
+
const records = await queryDns("https://google.com", testDnsResolvers);
|
|
220
|
+
expect(sampleResponse).toStrictEqual(records);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test("Should fallback to second dns when first dns is down", async () => {
|
|
224
|
+
const handlers = [
|
|
225
|
+
rest.get("https://dns.google/resolve", (_, res, ctx) => {
|
|
226
|
+
return res(ctx.status(500));
|
|
227
|
+
}),
|
|
228
|
+
rest.get("https://cloudflare-dns.com/dns-query", (_, res, ctx) => {
|
|
229
|
+
return res(ctx.json(sampleResponse));
|
|
230
|
+
}),
|
|
231
|
+
];
|
|
232
|
+
server = setupServer(...handlers);
|
|
233
|
+
server.listen();
|
|
234
|
+
|
|
235
|
+
const records = await queryDns("https://google.com", testDnsResolvers);
|
|
236
|
+
|
|
237
|
+
expect(sampleResponse).toStrictEqual(records);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test("Should throw error when all dns provided are down", async () => {
|
|
241
|
+
const handlers = [
|
|
242
|
+
rest.get("https://dns.google/resolve", (_, res, ctx) => {
|
|
243
|
+
return res(ctx.status(500));
|
|
244
|
+
}),
|
|
245
|
+
rest.get("https://cloudflare-dns.com/dns-query", (_, res, ctx) => {
|
|
246
|
+
return res(ctx.status(500));
|
|
247
|
+
}),
|
|
248
|
+
];
|
|
249
|
+
server = setupServer(...handlers);
|
|
250
|
+
server.listen();
|
|
251
|
+
try {
|
|
252
|
+
await queryDns("https://google.com", testDnsResolvers);
|
|
253
|
+
} catch (e: any) {
|
|
254
|
+
expect(e.code).toStrictEqual(DnsproveStatusCode.IDNS_QUERY_ERROR_GENERAL);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
});
|