Skip to content

Commit 7d6f766

Browse files
committed
subdomain endpoint
1 parent bd5d93a commit 7d6f766

File tree

12 files changed

+297
-271
lines changed

12 files changed

+297
-271
lines changed

public/favicon.ico

15 KB
Binary file not shown.

src/endpoints/domain.ts

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
import { OpenAPIHono } from "@hono/zod-openapi";
22

3-
import { query as crtQuery, route as crtRoute } from "../helpers/crt";
3+
import {
4+
query as DoHQuery,
5+
DNSQueryRoute,
6+
NSLookupRoute,
7+
} from "../helpers/doh";
8+
import {
9+
query as crtQuery,
10+
route as crtRoute,
11+
subdomainsRoute,
12+
} from "../helpers/crt";
413
import { query as whoisQuery, route as whoisRoute } from "../helpers/whois";
14+
import {
15+
domainQuery as reputationQuery,
16+
domainRoute as reputationRoute,
17+
} from "../helpers/reputation";
518

619
export const domain = new OpenAPIHono();
720

@@ -15,10 +28,44 @@ domain.openapi(crtRoute, async (c: any) => {
1528
});
1629

1730
/* SUBDOMAINS */
18-
19-
/* DNS LOOKUP */
31+
domain.openapi(subdomainsRoute, async (c: any) => {
32+
// TODO fix c type
33+
const { domain } = c.req.valid("param");
34+
const response = await crtQuery(domain);
35+
const subdomains = [
36+
...new Set(
37+
response
38+
.map((obj) => obj.common_name)
39+
.filter((name) => !name.startsWith("*"))
40+
),
41+
];
42+
return c.json(subdomains);
43+
});
2044

2145
/* DNS QUERY */
46+
domain.openapi(DNSQueryRoute, async (c: any) => {
47+
// TODO fix c type
48+
const { type, DO, CD } = c.req.valid("query");
49+
const { resolver, domain } = c.req.valid("param");
50+
const response = await DoHQuery(resolver, domain, type, DO, CD);
51+
return c.json(response);
52+
});
53+
54+
/* DNS LOOKUP */
55+
domain.openapi(NSLookupRoute, async (c: any) => {
56+
// TODO fix c type
57+
const { resolver, domain } = c.req.valid("param");
58+
const [A, AAAA, CNAME, TXT, NS, MX] = await Promise.all([
59+
DoHQuery(resolver, domain, "A"),
60+
DoHQuery(resolver, domain, "AAAA"),
61+
DoHQuery(resolver, domain, "CNAME"),
62+
DoHQuery(resolver, domain, "TXT"),
63+
DoHQuery(resolver, domain, "NS"),
64+
DoHQuery(resolver, domain, "MX"),
65+
]);
66+
const response = { A, AAAA, CNAME, TXT, NS, MX };
67+
return c.json(response);
68+
});
2269

2370
/* WHOIS */
2471
domain.openapi(whoisRoute, async (c: any) => {
@@ -29,3 +76,8 @@ domain.openapi(whoisRoute, async (c: any) => {
2976
});
3077

3178
/* REPUTATION */
79+
domain.openapi(reputationRoute, async (c: any) => {
80+
const { domain } = c.req.valid("param");
81+
const response = await reputationQuery(domain);
82+
return c.json(response);
83+
});

src/endpoints/ip.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
import { OpenAPIHono } from "@hono/zod-openapi";
22

3+
import { query as IPInfoQuery, route as IPInfoRoute } from "../helpers/ipinfo";
34
import {
45
query as reverseDNSQuery,
56
route as reverseDNSRoute,
67
} from "../helpers/reverse-dns";
8+
import {
9+
IPQuery as reputationQuery,
10+
IPRoute as reputationRoute,
11+
} from "../helpers/reputation";
712

813
export const ip = new OpenAPIHono();
914

15+
/* IP INFO */
16+
ip.openapi(IPInfoRoute, async (c: any) => {
17+
const { ip } = c.req.valid("param");
18+
const response = await IPInfoQuery(ip);
19+
return c.json(response);
20+
});
21+
1022
/* REVERSE DNS */
1123
ip.openapi(reverseDNSRoute, async (c: any) => {
1224
// TODO fix c type
@@ -15,3 +27,10 @@ ip.openapi(reverseDNSRoute, async (c: any) => {
1527
const response = await reverseDNSQuery(ip);
1628
return c.json(response);
1729
});
30+
31+
/* REPUTATION */
32+
ip.openapi(reputationRoute, async (c: any) => {
33+
const { ip } = c.req.valid("param");
34+
const response = await reputationQuery(ip);
35+
return c.json(response);
36+
});

src/helpers/crt.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ const QuerySchema = z.object({
7373
}),
7474
}); // TODO refactor the parameters and add "limit" parameter
7575

76-
const ResponseSchema = z
76+
const CertsResponseSchema = z
7777
.array(
7878
z.object({
7979
issuer_ca_id: z.number().openapi({ example: 185752 }),
@@ -106,7 +106,12 @@ const ResponseSchema = z
106106
)
107107
.openapi("Certificates");
108108

109+
const SubdomainsResponseSchema = z
110+
.array(z.string().openapi({ example: "www.example.com" }))
111+
.openapi("Subdomains");
112+
109113
/* ROUTE */
114+
// CERTIFICATE
110115
export const route = createRoute({
111116
tags: ["Domain"],
112117
method: "get",
@@ -116,7 +121,7 @@ export const route = createRoute({
116121
200: {
117122
content: {
118123
"application/json": {
119-
schema: ResponseSchema,
124+
schema: CertsResponseSchema,
120125
},
121126
},
122127
description: "Fetch crt.sh data",
@@ -125,3 +130,22 @@ export const route = createRoute({
125130
description: "Certificate Transparency",
126131
externalDocs: { description: "crt.sh", url: "https://crt.sh/" },
127132
});
133+
134+
// SUBDOMAINS
135+
export const subdomainsRoute = createRoute({
136+
tags: ["Domain"],
137+
method: "get",
138+
path: "/subdomains/{domain}",
139+
request: { params: ParamsSchema },
140+
responses: {
141+
200: {
142+
content: {
143+
"application/json": {
144+
schema: SubdomainsResponseSchema,
145+
},
146+
},
147+
description: "Search for subdomains",
148+
},
149+
},
150+
description: "Subdomains",
151+
});
Lines changed: 64 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,58 @@
1-
import { OpenAPIHono, z, createRoute } from "@hono/zod-openapi";
2-
3-
/* DNS-QUERY */
1+
import { z, createRoute } from "@hono/zod-openapi";
42

53
const resolvers = {
64
cloudflare: "cloudflare-dns.com/dns-query",
75
google: "dns.google/resolve",
86
quad9: "dns.quad9.net:5053/dns-query",
97
};
108

9+
/* QUERY */
10+
interface NSLookupResponse {
11+
A: DoHResponse;
12+
AAAA: DoHResponse;
13+
CNAME: DoHResponse;
14+
TXT: DoHResponse;
15+
NS: DoHResponse;
16+
MX: DoHResponse;
17+
}
18+
19+
interface DoHResponse {
20+
Status: number;
21+
TC: boolean;
22+
RD: boolean;
23+
RA: boolean;
24+
AD: boolean;
25+
CD: boolean;
26+
Question: { name: string; type: number }[];
27+
Answer: { name: string; type: number; TTL: number; data: string }[];
28+
}
29+
30+
export async function query(
31+
resolver: keyof typeof resolvers,
32+
name: string,
33+
type: string = "A",
34+
DO: boolean = false,
35+
CD: boolean = false
36+
): Promise<DoHResponse> {
37+
const endpoint = resolvers[resolver];
38+
const url = `https://${endpoint}?name=${name}${type ? `&type=${type}` : ""}${
39+
DO ? `do=${DO}` : ""
40+
}${CD ? `$cd=${CD}` : ""}`;
41+
const response = await fetch(url, {
42+
method: "GET",
43+
headers: {
44+
accept: "application/dns-json",
45+
},
46+
});
47+
if (!response.ok) {
48+
throw new Error(
49+
`Failed to fetch data: ${response.status} ${response.statusText}`
50+
);
51+
} // TODO handle returned errors
52+
return (await response.json()) as DoHResponse;
53+
}
54+
55+
/*SCHEMAS */
1156
const ParamsSchema = z.object({
1257
resolver: z.enum(Object.keys(resolvers)).openapi({
1358
param: {
@@ -60,17 +105,6 @@ const DoHQuerySchema = z.object({
60105
}),
61106
});
62107

63-
interface DoHResponse {
64-
Status: number;
65-
TC: boolean;
66-
RD: boolean;
67-
RA: boolean;
68-
AD: boolean;
69-
CD: boolean;
70-
Question: { name: string; type: number }[];
71-
Answer: { name: string; type: number; TTL: number; data: string }[];
72-
}
73-
74108
const DoHResponseSchema = z
75109
.object({
76110
Status: z.number().openapi({ example: 0 }),
@@ -98,37 +132,22 @@ const DoHResponseSchema = z
98132
})
99133
.openapi("DoH Record");
100134

101-
async function query(
102-
resolver: keyof typeof resolvers,
103-
name: string,
104-
type: string = "A",
105-
DO: boolean = false,
106-
CD: boolean = false
107-
): Promise<DoHResponse> {
108-
const endpoint = resolvers[resolver];
109-
const url = `https://${endpoint}?name=${name}${type ? `&type=${type}` : ""}${
110-
DO ? `do=${DO}` : ""
111-
}${CD ? `$cd=${CD}` : ""}`;
112-
const response = await fetch(url, {
113-
method: "GET",
114-
headers: {
115-
accept: "application/dns-json",
116-
},
117-
});
118-
if (!response.ok) {
119-
throw new Error(
120-
`Failed to fetch data: ${response.status} ${response.statusText}`
121-
);
122-
} // TODO handle returned errors
123-
return (await response.json()) as DoHResponse;
124-
}
125-
126-
export const dnsQuery = new OpenAPIHono();
135+
const NSLookupResponseSchema = z
136+
.object({
137+
A: DoHResponseSchema,
138+
AAAA: DoHResponseSchema,
139+
CNAME: DoHResponseSchema,
140+
TXT: DoHResponseSchema,
141+
NS: DoHResponseSchema,
142+
MX: DoHResponseSchema,
143+
})
144+
.openapi("Nslookup");
127145

128-
const dnsQueryRoute = createRoute({
146+
/* ROUTE */
147+
export const DNSQueryRoute = createRoute({
129148
tags: ["Domain"],
130149
method: "get",
131-
path: "/{resolver}/{domain}",
150+
path: "/dns-query/{resolver}/{domain}",
132151
request: { params: ParamsSchema, query: DoHQuerySchema },
133152
responses: {
134153
// TODO customize error responses (https://github.com/honojs/middleware/tree/main/packages/zod-openapi)
@@ -148,46 +167,17 @@ const dnsQueryRoute = createRoute({
148167
},
149168
});
150169

151-
dnsQuery.openapi(dnsQueryRoute, async (c: any) => {
152-
const { type, DO, CD } = c.req.valid("query");
153-
const { resolver, domain } = c.req.valid("param");
154-
const response: DoHResponse = await query(resolver, domain, type, DO, CD);
155-
return c.json(response);
156-
});
157-
158-
/* NSLOOKUP */
159-
160-
interface NslookupResponse {
161-
A: DoHResponse;
162-
AAAA: DoHResponse;
163-
CNAME: DoHResponse;
164-
TXT: DoHResponse;
165-
NS: DoHResponse;
166-
MX: DoHResponse;
167-
}
168-
169-
const NslookupResponseSchema = z
170-
.object({
171-
A: DoHResponseSchema,
172-
AAAA: DoHResponseSchema,
173-
CNAME: DoHResponseSchema,
174-
TXT: DoHResponseSchema,
175-
NS: DoHResponseSchema,
176-
MX: DoHResponseSchema,
177-
})
178-
.openapi("Nslookup");
179-
180-
const nslookupRoute = createRoute({
170+
export const NSLookupRoute = createRoute({
181171
tags: ["Domain"],
182172
method: "get",
183-
path: "/{resolver}/{domain}",
173+
path: "/nslookup/{resolver}/{domain}",
184174
request: { params: ParamsSchema },
185175
responses: {
186176
// TODO customize error responses (https://github.com/honojs/middleware/tree/main/packages/zod-openapi)
187177
200: {
188178
content: {
189179
"application/json": {
190-
schema: NslookupResponseSchema,
180+
schema: NSLookupResponseSchema,
191181
},
192182
},
193183
description: "Fetch DoH Lookup",
@@ -199,19 +189,3 @@ const nslookupRoute = createRoute({
199189
url: "https://www.rfc-editor.org/rfc/rfc8484",
200190
},
201191
});
202-
203-
export const nslookup = new OpenAPIHono();
204-
205-
nslookup.openapi(nslookupRoute, async (c: any) => {
206-
const { resolver, domain } = c.req.valid("param");
207-
const [A, AAAA, CNAME, TXT, NS, MX] = await Promise.all([
208-
query(resolver, domain, "A"),
209-
query(resolver, domain, "AAAA"),
210-
query(resolver, domain, "CNAME"),
211-
query(resolver, domain, "TXT"),
212-
query(resolver, domain, "NS"),
213-
query(resolver, domain, "MX"),
214-
]);
215-
const response: NslookupResponse = { A, AAAA, CNAME, TXT, NS, MX };
216-
return c.json(response);
217-
});

0 commit comments

Comments
 (0)