jsonified-whois 1.1.0 → 1.1.2
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/dist/index.cjs +316 -0
- package/dist/index.d.cts +34 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +283 -0
- package/package.json +2 -2
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
default: () => index_default
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// src/constants.ts
|
|
38
|
+
var timeoutSeconds = 60;
|
|
39
|
+
var ianaWhoIsServer = "whois.iana.org";
|
|
40
|
+
var parserInitialData = {
|
|
41
|
+
createdAt: "",
|
|
42
|
+
domainName: "",
|
|
43
|
+
expiresAt: "",
|
|
44
|
+
ipAddresses: {
|
|
45
|
+
ipv4: [],
|
|
46
|
+
ipv6: []
|
|
47
|
+
},
|
|
48
|
+
nameServers: [],
|
|
49
|
+
registrar: "",
|
|
50
|
+
updateAt: "",
|
|
51
|
+
queriedWhoisServer: "",
|
|
52
|
+
raw: ""
|
|
53
|
+
};
|
|
54
|
+
var ianaFieldMatchers = [
|
|
55
|
+
{
|
|
56
|
+
keywords: ["creation", "created", "registered"],
|
|
57
|
+
targetKey: "createdAt"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
keywords: ["updated", "changed", "last updated"],
|
|
61
|
+
targetKey: "updateAt"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
keywords: ["expiry", "expiration", "expires"],
|
|
65
|
+
targetKey: "expiresAt"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
keywords: ["name server", "nameserver", "nserver"],
|
|
69
|
+
targetKey: "nameServers",
|
|
70
|
+
isArray: true
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
keywords: ["whois"],
|
|
74
|
+
targetKey: "registrar"
|
|
75
|
+
}
|
|
76
|
+
];
|
|
77
|
+
var gtldFiledMatchers = [
|
|
78
|
+
{
|
|
79
|
+
keywords: ["creation", "created", "registered"],
|
|
80
|
+
targetKey: "createdAt"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
keywords: ["updated", "changed", "last updated"],
|
|
84
|
+
targetKey: "updateAt"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
keywords: ["expiry", "expiration", "expires"],
|
|
88
|
+
targetKey: "expiresAt"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
keywords: [
|
|
92
|
+
"name server",
|
|
93
|
+
"nameserver",
|
|
94
|
+
"nserver",
|
|
95
|
+
"nameservers",
|
|
96
|
+
"hostname"
|
|
97
|
+
],
|
|
98
|
+
targetKey: "nameServers",
|
|
99
|
+
isArray: true
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
keywords: ["registrar whois server"],
|
|
103
|
+
targetKey: "registrar"
|
|
104
|
+
}
|
|
105
|
+
];
|
|
106
|
+
var warnColor = "\x1B[33m";
|
|
107
|
+
var errorColor = "\x1B[31m";
|
|
108
|
+
|
|
109
|
+
// src/utils/normalizer.ts
|
|
110
|
+
var normalizer = (str) => {
|
|
111
|
+
return str.toLowerCase().replace(/[^a-z\s]/g, "").trim();
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// src/parser/index.ts
|
|
115
|
+
var nameServers = "nameServers";
|
|
116
|
+
var parser = (data, isIana) => {
|
|
117
|
+
const splitter = data.endsWith("\r\n") ? "\r\n" : "\n";
|
|
118
|
+
const matchers = isIana ? ianaFieldMatchers : gtldFiledMatchers;
|
|
119
|
+
const arr = data.split(">>>");
|
|
120
|
+
const responses = arr[0].split(splitter);
|
|
121
|
+
const result = { ...parserInitialData };
|
|
122
|
+
responses.forEach((item) => {
|
|
123
|
+
const [key, value] = item.split(/:(.*)/s);
|
|
124
|
+
if (!key || !value) return;
|
|
125
|
+
const normalizedKey = normalizer(key);
|
|
126
|
+
const trimmedValue = value.trim();
|
|
127
|
+
for (const matcher of matchers) {
|
|
128
|
+
const includesKeyword = matcher.keywords.some(
|
|
129
|
+
(kw) => normalizedKey.includes(kw)
|
|
130
|
+
);
|
|
131
|
+
if (!includesKeyword) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (matcher.targetKey === nameServers) {
|
|
135
|
+
const values = trimmedValue.split("\r\n").map((v) => v.trim()).filter(Boolean);
|
|
136
|
+
result.nameServers = [...result.nameServers || [], ...values];
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
result[matcher.targetKey] = trimmedValue;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
return result;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// src/utils/getIpAddresses.ts
|
|
147
|
+
var import_promises = require("dns/promises");
|
|
148
|
+
|
|
149
|
+
// src/utils/log.ts
|
|
150
|
+
var logWarning = (message) => {
|
|
151
|
+
console.warn(warnColor, message);
|
|
152
|
+
};
|
|
153
|
+
var logError = (message) => {
|
|
154
|
+
console.error(errorColor, message);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/utils/getIpAddresses.ts
|
|
158
|
+
var getIpv6 = async (domain) => {
|
|
159
|
+
try {
|
|
160
|
+
return await (0, import_promises.resolve6)(domain);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
logWarning("Unable to find IPv6 addresses for " + domain + "\n");
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
var getIpv4 = async (domain) => {
|
|
167
|
+
try {
|
|
168
|
+
return await (0, import_promises.resolve4)(domain);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
logWarning("Unable to find IPv4 addresses for " + domain + "\n");
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
var getIpAddresses = async (domain) => {
|
|
175
|
+
const ipv4 = await getIpv4(domain);
|
|
176
|
+
const ipv6 = await getIpv6(domain);
|
|
177
|
+
return {
|
|
178
|
+
ipv4,
|
|
179
|
+
ipv6
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// src/utils/verifyDomains.ts
|
|
184
|
+
var import_tldts = __toESM(require("tldts"), 1);
|
|
185
|
+
var verifyDomain = (domain) => {
|
|
186
|
+
if (!domain.length) {
|
|
187
|
+
throw new Error("Domain input is required");
|
|
188
|
+
}
|
|
189
|
+
const domainWithoutSuffix = import_tldts.default.getDomainWithoutSuffix(domain);
|
|
190
|
+
if (!domainWithoutSuffix) {
|
|
191
|
+
throw new Error("Domain is not valid");
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// src/utils/queryWhoisServer.ts
|
|
196
|
+
var import_net = __toESM(require("net"), 1);
|
|
197
|
+
var queryWhoisServer = async (domain, whoisServer, port) => {
|
|
198
|
+
return new Promise((resolve, reject) => {
|
|
199
|
+
let data = "";
|
|
200
|
+
const socket = import_net.default.createConnection(
|
|
201
|
+
{ host: whoisServer, port },
|
|
202
|
+
() => socket.write(domain + "\r\n")
|
|
203
|
+
);
|
|
204
|
+
socket.setTimeout(timeoutSeconds * 1e3);
|
|
205
|
+
socket.on("data", (chunk) => data += chunk);
|
|
206
|
+
socket.on("close", () => resolve(data));
|
|
207
|
+
socket.on("timeout", () => socket.destroy(new Error("Timeout")));
|
|
208
|
+
socket.on("error", reject);
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// src/index.ts
|
|
213
|
+
var import_tldts2 = __toESM(require("tldts"), 1);
|
|
214
|
+
|
|
215
|
+
// src/utils/getFallbackData.ts
|
|
216
|
+
var getFallbackData = (results) => {
|
|
217
|
+
const reversedArr = [...results].reverse();
|
|
218
|
+
let counter = [];
|
|
219
|
+
for (let index in reversedArr) {
|
|
220
|
+
counter[index] = 0;
|
|
221
|
+
for (let key in reversedArr[index]) {
|
|
222
|
+
if (reversedArr[index][key]) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
counter[index]++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const minLossIndex = counter.indexOf(Math.min(...counter));
|
|
229
|
+
return { ...reversedArr[minLossIndex] };
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// src/index.ts
|
|
233
|
+
var WhoisClient = class {
|
|
234
|
+
constructor({ url, fallback, port, whoisServer }) {
|
|
235
|
+
try {
|
|
236
|
+
url && verifyDomain(url);
|
|
237
|
+
this.port = port || 43;
|
|
238
|
+
this.whoisServer = whoisServer || ianaWhoIsServer;
|
|
239
|
+
this.fallbackEnabled = fallback || false;
|
|
240
|
+
this.domain = import_tldts2.default.getDomain(url) || "";
|
|
241
|
+
this.hostname = import_tldts2.default.getHostname(url) || "";
|
|
242
|
+
} catch (error) {
|
|
243
|
+
logError("Something went wrong when initializing the client \n");
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
port = 43;
|
|
248
|
+
whoisServer = ianaWhoIsServer;
|
|
249
|
+
ipAddresses = {
|
|
250
|
+
ipv4: [],
|
|
251
|
+
ipv6: []
|
|
252
|
+
};
|
|
253
|
+
hostname = "";
|
|
254
|
+
domain = "";
|
|
255
|
+
fallbackEnabled = false;
|
|
256
|
+
whoisResults = [];
|
|
257
|
+
/**
|
|
258
|
+
* Fetch data for the instantiated domain
|
|
259
|
+
*/
|
|
260
|
+
async fetchData() {
|
|
261
|
+
this.ipAddresses = await getIpAddresses(this.hostname);
|
|
262
|
+
const response = await this.collectWhoisChain(
|
|
263
|
+
this.domain,
|
|
264
|
+
this.whoisServer
|
|
265
|
+
);
|
|
266
|
+
let lastQuery = { ...response.at(-1) };
|
|
267
|
+
if (this.fallbackEnabled) {
|
|
268
|
+
lastQuery = getFallbackData(response);
|
|
269
|
+
}
|
|
270
|
+
delete lastQuery.raw;
|
|
271
|
+
const data = {
|
|
272
|
+
queryData: response,
|
|
273
|
+
...lastQuery
|
|
274
|
+
};
|
|
275
|
+
return JSON.stringify(data);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Queries whois servers and collects whois info recursively
|
|
279
|
+
*/
|
|
280
|
+
async collectWhoisChain(domain, whoisServer) {
|
|
281
|
+
const existingRegistryData = this.whoisResults.find(
|
|
282
|
+
(item) => item.queriedWhoisServer === whoisServer
|
|
283
|
+
);
|
|
284
|
+
if (existingRegistryData && (existingRegistryData.registrar.length === 0 || existingRegistryData.registrar === whoisServer)) {
|
|
285
|
+
return this.whoisResults;
|
|
286
|
+
}
|
|
287
|
+
const response = await this.queryWhoisServer(domain, whoisServer);
|
|
288
|
+
this.whoisResults.push({
|
|
289
|
+
...response,
|
|
290
|
+
ipAddresses: this.ipAddresses
|
|
291
|
+
});
|
|
292
|
+
if (!response.registrar) {
|
|
293
|
+
return this.whoisResults;
|
|
294
|
+
}
|
|
295
|
+
return await this.collectWhoisChain(domain, response.registrar);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Query given whois server and return parsed data with matched keys.
|
|
299
|
+
*/
|
|
300
|
+
async queryWhoisServer(domain, whoisServer) {
|
|
301
|
+
try {
|
|
302
|
+
const response = await queryWhoisServer(domain, whoisServer, this.port);
|
|
303
|
+
const isIana = whoisServer === ianaWhoIsServer;
|
|
304
|
+
const conversionResult = parser(response, isIana);
|
|
305
|
+
conversionResult.domainName = this.domain;
|
|
306
|
+
conversionResult.queriedWhoisServer = whoisServer;
|
|
307
|
+
conversionResult.raw = response;
|
|
308
|
+
conversionResult.ipAddresses = this.ipAddresses;
|
|
309
|
+
return conversionResult;
|
|
310
|
+
} catch (error) {
|
|
311
|
+
logError(error);
|
|
312
|
+
return parserInitialData;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
var index_default = WhoisClient;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
interface WhoisClientConstructor {
|
|
2
|
+
fallback?: boolean;
|
|
3
|
+
url: string;
|
|
4
|
+
port?: number;
|
|
5
|
+
whoisServer?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A client to get basic whois information
|
|
10
|
+
*/
|
|
11
|
+
declare class WhoisClient {
|
|
12
|
+
constructor({ url, fallback, port, whoisServer }: WhoisClientConstructor);
|
|
13
|
+
private port;
|
|
14
|
+
private whoisServer;
|
|
15
|
+
private ipAddresses;
|
|
16
|
+
private hostname;
|
|
17
|
+
private domain;
|
|
18
|
+
private fallbackEnabled;
|
|
19
|
+
private whoisResults;
|
|
20
|
+
/**
|
|
21
|
+
* Fetch data for the instantiated domain
|
|
22
|
+
*/
|
|
23
|
+
fetchData(): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Queries whois servers and collects whois info recursively
|
|
26
|
+
*/
|
|
27
|
+
private collectWhoisChain;
|
|
28
|
+
/**
|
|
29
|
+
* Query given whois server and return parsed data with matched keys.
|
|
30
|
+
*/
|
|
31
|
+
private queryWhoisServer;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { WhoisClient as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
interface WhoisClientConstructor {
|
|
2
|
+
fallback?: boolean;
|
|
3
|
+
url: string;
|
|
4
|
+
port?: number;
|
|
5
|
+
whoisServer?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A client to get basic whois information
|
|
10
|
+
*/
|
|
11
|
+
declare class WhoisClient {
|
|
12
|
+
constructor({ url, fallback, port, whoisServer }: WhoisClientConstructor);
|
|
13
|
+
private port;
|
|
14
|
+
private whoisServer;
|
|
15
|
+
private ipAddresses;
|
|
16
|
+
private hostname;
|
|
17
|
+
private domain;
|
|
18
|
+
private fallbackEnabled;
|
|
19
|
+
private whoisResults;
|
|
20
|
+
/**
|
|
21
|
+
* Fetch data for the instantiated domain
|
|
22
|
+
*/
|
|
23
|
+
fetchData(): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Queries whois servers and collects whois info recursively
|
|
26
|
+
*/
|
|
27
|
+
private collectWhoisChain;
|
|
28
|
+
/**
|
|
29
|
+
* Query given whois server and return parsed data with matched keys.
|
|
30
|
+
*/
|
|
31
|
+
private queryWhoisServer;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { WhoisClient as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var timeoutSeconds = 60;
|
|
3
|
+
var ianaWhoIsServer = "whois.iana.org";
|
|
4
|
+
var parserInitialData = {
|
|
5
|
+
createdAt: "",
|
|
6
|
+
domainName: "",
|
|
7
|
+
expiresAt: "",
|
|
8
|
+
ipAddresses: {
|
|
9
|
+
ipv4: [],
|
|
10
|
+
ipv6: []
|
|
11
|
+
},
|
|
12
|
+
nameServers: [],
|
|
13
|
+
registrar: "",
|
|
14
|
+
updateAt: "",
|
|
15
|
+
queriedWhoisServer: "",
|
|
16
|
+
raw: ""
|
|
17
|
+
};
|
|
18
|
+
var ianaFieldMatchers = [
|
|
19
|
+
{
|
|
20
|
+
keywords: ["creation", "created", "registered"],
|
|
21
|
+
targetKey: "createdAt"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
keywords: ["updated", "changed", "last updated"],
|
|
25
|
+
targetKey: "updateAt"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
keywords: ["expiry", "expiration", "expires"],
|
|
29
|
+
targetKey: "expiresAt"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
keywords: ["name server", "nameserver", "nserver"],
|
|
33
|
+
targetKey: "nameServers",
|
|
34
|
+
isArray: true
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
keywords: ["whois"],
|
|
38
|
+
targetKey: "registrar"
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
var gtldFiledMatchers = [
|
|
42
|
+
{
|
|
43
|
+
keywords: ["creation", "created", "registered"],
|
|
44
|
+
targetKey: "createdAt"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
keywords: ["updated", "changed", "last updated"],
|
|
48
|
+
targetKey: "updateAt"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
keywords: ["expiry", "expiration", "expires"],
|
|
52
|
+
targetKey: "expiresAt"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
keywords: [
|
|
56
|
+
"name server",
|
|
57
|
+
"nameserver",
|
|
58
|
+
"nserver",
|
|
59
|
+
"nameservers",
|
|
60
|
+
"hostname"
|
|
61
|
+
],
|
|
62
|
+
targetKey: "nameServers",
|
|
63
|
+
isArray: true
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
keywords: ["registrar whois server"],
|
|
67
|
+
targetKey: "registrar"
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
var warnColor = "\x1B[33m";
|
|
71
|
+
var errorColor = "\x1B[31m";
|
|
72
|
+
|
|
73
|
+
// src/utils/normalizer.ts
|
|
74
|
+
var normalizer = (str) => {
|
|
75
|
+
return str.toLowerCase().replace(/[^a-z\s]/g, "").trim();
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// src/parser/index.ts
|
|
79
|
+
var nameServers = "nameServers";
|
|
80
|
+
var parser = (data, isIana) => {
|
|
81
|
+
const splitter = data.endsWith("\r\n") ? "\r\n" : "\n";
|
|
82
|
+
const matchers = isIana ? ianaFieldMatchers : gtldFiledMatchers;
|
|
83
|
+
const arr = data.split(">>>");
|
|
84
|
+
const responses = arr[0].split(splitter);
|
|
85
|
+
const result = { ...parserInitialData };
|
|
86
|
+
responses.forEach((item) => {
|
|
87
|
+
const [key, value] = item.split(/:(.*)/s);
|
|
88
|
+
if (!key || !value) return;
|
|
89
|
+
const normalizedKey = normalizer(key);
|
|
90
|
+
const trimmedValue = value.trim();
|
|
91
|
+
for (const matcher of matchers) {
|
|
92
|
+
const includesKeyword = matcher.keywords.some(
|
|
93
|
+
(kw) => normalizedKey.includes(kw)
|
|
94
|
+
);
|
|
95
|
+
if (!includesKeyword) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (matcher.targetKey === nameServers) {
|
|
99
|
+
const values = trimmedValue.split("\r\n").map((v) => v.trim()).filter(Boolean);
|
|
100
|
+
result.nameServers = [...result.nameServers || [], ...values];
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
result[matcher.targetKey] = trimmedValue;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return result;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// src/utils/getIpAddresses.ts
|
|
111
|
+
import { resolve4, resolve6 } from "dns/promises";
|
|
112
|
+
|
|
113
|
+
// src/utils/log.ts
|
|
114
|
+
var logWarning = (message) => {
|
|
115
|
+
console.warn(warnColor, message);
|
|
116
|
+
};
|
|
117
|
+
var logError = (message) => {
|
|
118
|
+
console.error(errorColor, message);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/utils/getIpAddresses.ts
|
|
122
|
+
var getIpv6 = async (domain) => {
|
|
123
|
+
try {
|
|
124
|
+
return await resolve6(domain);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
logWarning("Unable to find IPv6 addresses for " + domain + "\n");
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
var getIpv4 = async (domain) => {
|
|
131
|
+
try {
|
|
132
|
+
return await resolve4(domain);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
logWarning("Unable to find IPv4 addresses for " + domain + "\n");
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
var getIpAddresses = async (domain) => {
|
|
139
|
+
const ipv4 = await getIpv4(domain);
|
|
140
|
+
const ipv6 = await getIpv6(domain);
|
|
141
|
+
return {
|
|
142
|
+
ipv4,
|
|
143
|
+
ipv6
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// src/utils/verifyDomains.ts
|
|
148
|
+
import tldts from "tldts";
|
|
149
|
+
var verifyDomain = (domain) => {
|
|
150
|
+
if (!domain.length) {
|
|
151
|
+
throw new Error("Domain input is required");
|
|
152
|
+
}
|
|
153
|
+
const domainWithoutSuffix = tldts.getDomainWithoutSuffix(domain);
|
|
154
|
+
if (!domainWithoutSuffix) {
|
|
155
|
+
throw new Error("Domain is not valid");
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// src/utils/queryWhoisServer.ts
|
|
160
|
+
import net from "net";
|
|
161
|
+
var queryWhoisServer = async (domain, whoisServer, port) => {
|
|
162
|
+
return new Promise((resolve, reject) => {
|
|
163
|
+
let data = "";
|
|
164
|
+
const socket = net.createConnection(
|
|
165
|
+
{ host: whoisServer, port },
|
|
166
|
+
() => socket.write(domain + "\r\n")
|
|
167
|
+
);
|
|
168
|
+
socket.setTimeout(timeoutSeconds * 1e3);
|
|
169
|
+
socket.on("data", (chunk) => data += chunk);
|
|
170
|
+
socket.on("close", () => resolve(data));
|
|
171
|
+
socket.on("timeout", () => socket.destroy(new Error("Timeout")));
|
|
172
|
+
socket.on("error", reject);
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/index.ts
|
|
177
|
+
import tldts2 from "tldts";
|
|
178
|
+
|
|
179
|
+
// src/utils/getFallbackData.ts
|
|
180
|
+
var getFallbackData = (results) => {
|
|
181
|
+
const reversedArr = [...results].reverse();
|
|
182
|
+
let counter = [];
|
|
183
|
+
for (let index in reversedArr) {
|
|
184
|
+
counter[index] = 0;
|
|
185
|
+
for (let key in reversedArr[index]) {
|
|
186
|
+
if (reversedArr[index][key]) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
counter[index]++;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const minLossIndex = counter.indexOf(Math.min(...counter));
|
|
193
|
+
return { ...reversedArr[minLossIndex] };
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// src/index.ts
|
|
197
|
+
var WhoisClient = class {
|
|
198
|
+
constructor({ url, fallback, port, whoisServer }) {
|
|
199
|
+
try {
|
|
200
|
+
url && verifyDomain(url);
|
|
201
|
+
this.port = port || 43;
|
|
202
|
+
this.whoisServer = whoisServer || ianaWhoIsServer;
|
|
203
|
+
this.fallbackEnabled = fallback || false;
|
|
204
|
+
this.domain = tldts2.getDomain(url) || "";
|
|
205
|
+
this.hostname = tldts2.getHostname(url) || "";
|
|
206
|
+
} catch (error) {
|
|
207
|
+
logError("Something went wrong when initializing the client \n");
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
port = 43;
|
|
212
|
+
whoisServer = ianaWhoIsServer;
|
|
213
|
+
ipAddresses = {
|
|
214
|
+
ipv4: [],
|
|
215
|
+
ipv6: []
|
|
216
|
+
};
|
|
217
|
+
hostname = "";
|
|
218
|
+
domain = "";
|
|
219
|
+
fallbackEnabled = false;
|
|
220
|
+
whoisResults = [];
|
|
221
|
+
/**
|
|
222
|
+
* Fetch data for the instantiated domain
|
|
223
|
+
*/
|
|
224
|
+
async fetchData() {
|
|
225
|
+
this.ipAddresses = await getIpAddresses(this.hostname);
|
|
226
|
+
const response = await this.collectWhoisChain(
|
|
227
|
+
this.domain,
|
|
228
|
+
this.whoisServer
|
|
229
|
+
);
|
|
230
|
+
let lastQuery = { ...response.at(-1) };
|
|
231
|
+
if (this.fallbackEnabled) {
|
|
232
|
+
lastQuery = getFallbackData(response);
|
|
233
|
+
}
|
|
234
|
+
delete lastQuery.raw;
|
|
235
|
+
const data = {
|
|
236
|
+
queryData: response,
|
|
237
|
+
...lastQuery
|
|
238
|
+
};
|
|
239
|
+
return JSON.stringify(data);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Queries whois servers and collects whois info recursively
|
|
243
|
+
*/
|
|
244
|
+
async collectWhoisChain(domain, whoisServer) {
|
|
245
|
+
const existingRegistryData = this.whoisResults.find(
|
|
246
|
+
(item) => item.queriedWhoisServer === whoisServer
|
|
247
|
+
);
|
|
248
|
+
if (existingRegistryData && (existingRegistryData.registrar.length === 0 || existingRegistryData.registrar === whoisServer)) {
|
|
249
|
+
return this.whoisResults;
|
|
250
|
+
}
|
|
251
|
+
const response = await this.queryWhoisServer(domain, whoisServer);
|
|
252
|
+
this.whoisResults.push({
|
|
253
|
+
...response,
|
|
254
|
+
ipAddresses: this.ipAddresses
|
|
255
|
+
});
|
|
256
|
+
if (!response.registrar) {
|
|
257
|
+
return this.whoisResults;
|
|
258
|
+
}
|
|
259
|
+
return await this.collectWhoisChain(domain, response.registrar);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Query given whois server and return parsed data with matched keys.
|
|
263
|
+
*/
|
|
264
|
+
async queryWhoisServer(domain, whoisServer) {
|
|
265
|
+
try {
|
|
266
|
+
const response = await queryWhoisServer(domain, whoisServer, this.port);
|
|
267
|
+
const isIana = whoisServer === ianaWhoIsServer;
|
|
268
|
+
const conversionResult = parser(response, isIana);
|
|
269
|
+
conversionResult.domainName = this.domain;
|
|
270
|
+
conversionResult.queriedWhoisServer = whoisServer;
|
|
271
|
+
conversionResult.raw = response;
|
|
272
|
+
conversionResult.ipAddresses = this.ipAddresses;
|
|
273
|
+
return conversionResult;
|
|
274
|
+
} catch (error) {
|
|
275
|
+
logError(error);
|
|
276
|
+
return parserInitialData;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
var index_default = WhoisClient;
|
|
281
|
+
export {
|
|
282
|
+
index_default as default
|
|
283
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsonified-whois",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "A simple, open-source WHOIS client for Node.js that returns unified data as json",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"homepage": "https://github.com/Ping-Home/jsonified-whois#readme",
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/node": "*",
|
|
23
|
-
"tsup": "^8.5.
|
|
23
|
+
"tsup": "^8.5.1",
|
|
24
24
|
"typescript": "*"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|