@opensecurity/zonzon-core 0.1.1 → 0.1.3
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/audit.d.ts +10 -0
- package/dist/audit.js +39 -0
- package/dist/cache-layer.test.d.ts +1 -0
- package/dist/cache-layer.test.js +205 -0
- package/dist/cache-multi-question.test.d.ts +1 -0
- package/dist/cache-multi-question.test.js +187 -0
- package/dist/dns-handler.d.ts +27 -0
- package/dist/dns-handler.js +323 -0
- package/dist/dns-service.d.ts +45 -0
- package/dist/dns-service.js +546 -0
- package/dist/dns-service.test.d.ts +1 -0
- package/dist/dns-service.test.js +306 -0
- package/dist/dns-wireformat.test.d.ts +1 -0
- package/dist/dns-wireformat.test.js +669 -0
- package/dist/firewall.d.ts +9 -0
- package/dist/firewall.js +62 -0
- package/dist/http-body-forwarding-integration.test.d.ts +1 -0
- package/dist/http-body-forwarding-integration.test.js +318 -0
- package/dist/http-body-forwarding.test.d.ts +1 -0
- package/dist/http-body-forwarding.test.js +84 -0
- package/dist/http-handler.d.ts +21 -0
- package/dist/http-handler.js +429 -0
- package/dist/http-proxy.d.ts +14 -0
- package/dist/http-proxy.js +135 -0
- package/dist/http-proxy.test.d.ts +1 -0
- package/dist/http-proxy.test.js +375 -0
- package/{src/index.ts → dist/index.d.ts} +1 -1
- package/dist/index.js +10 -0
- package/dist/rate-limiter.d.ts +11 -0
- package/dist/rate-limiter.js +33 -0
- package/dist/rate-limiter.test.d.ts +1 -0
- package/dist/rate-limiter.test.js +149 -0
- package/dist/schema.d.ts +12 -0
- package/dist/schema.js +124 -0
- package/dist/schema.test.d.ts +1 -0
- package/dist/schema.test.js +586 -0
- package/dist/sni-proxy.d.ts +12 -0
- package/dist/sni-proxy.js +141 -0
- package/dist/srv-record.test.d.ts +1 -0
- package/dist/srv-record.test.js +186 -0
- package/dist/tcp-connection-limit.test.d.ts +1 -0
- package/dist/tcp-connection-limit.test.js +89 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.js +34 -0
- package/dist/wildcard-matching.test.d.ts +1 -0
- package/dist/wildcard-matching.test.js +162 -0
- package/package.json +4 -1
- package/src/audit.ts +0 -43
- package/src/cache-layer.test.ts +0 -236
- package/src/cache-multi-question.test.ts +0 -263
- package/src/dns-handler.ts +0 -355
- package/src/dns-service.test.ts +0 -371
- package/src/dns-service.ts +0 -655
- package/src/dns-wireformat.test.ts +0 -771
- package/src/env.d.ts +0 -1
- package/src/firewall.ts +0 -66
- package/src/http-body-forwarding-integration.test.ts +0 -357
- package/src/http-body-forwarding.test.ts +0 -101
- package/src/http-handler.ts +0 -489
- package/src/http-proxy.test.ts +0 -440
- package/src/http-proxy.ts +0 -148
- package/src/rate-limiter.test.ts +0 -144
- package/src/rate-limiter.ts +0 -50
- package/src/schema.test.ts +0 -685
- package/src/schema.ts +0 -137
- package/src/sni-proxy.ts +0 -164
- package/src/srv-record.test.ts +0 -211
- package/src/tcp-connection-limit.test.ts +0 -110
- package/src/types.ts +0 -168
- package/src/wildcard-matching.test.ts +0 -196
- package/tsconfig.json +0 -9
package/dist/schema.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import * as net from "net";
|
|
3
|
+
const CrlfFreeString = z.string().refine((val) => !/[\r\n]/.test(val), "Contains CR/LF");
|
|
4
|
+
const Ipv4Schema = z.string().refine((ip) => net.isIPv4(ip), "Invalid IPv4");
|
|
5
|
+
const Ipv6Schema = z.string().refine((ip) => net.isIPv6(ip), "Invalid IPv6");
|
|
6
|
+
const HostnameSchema = z.string().max(253).refine((hostname) => {
|
|
7
|
+
const parts = hostname.split(".");
|
|
8
|
+
const hostPattern = /^[a-zA-Z0-9_]([a-zA-Z0-9_-]{0,61}[a-zA-Z0-9])?$/;
|
|
9
|
+
return parts.every((part) => part.length > 0 && part.length <= 63 && hostPattern.test(part));
|
|
10
|
+
}, "Invalid hostname");
|
|
11
|
+
const PortSchema = z.number().int().min(1).max(65535);
|
|
12
|
+
const ARecordSchema = z.object({ type: z.literal("A"), address: Ipv4Schema });
|
|
13
|
+
const AAAARecordSchema = z.object({ type: z.literal("AAAA"), address: Ipv6Schema });
|
|
14
|
+
const CNAMERecordSchema = z.object({ type: z.literal("CNAME"), target: HostnameSchema });
|
|
15
|
+
const TXTRecordSchema = z.object({ type: z.literal("TXT"), data: z.array(z.string().max(255).refine((val) => !/[\r\n]/.test(val), "Contains CR/LF")) });
|
|
16
|
+
const MXRecordSchema = z.object({ type: z.literal("MX"), priority: z.number().int().min(0).max(65535), exchange: HostnameSchema });
|
|
17
|
+
const NSRecordSchema = z.object({ type: z.literal("NS"), target: HostnameSchema });
|
|
18
|
+
const SRVRecordSchema = z.object({ type: z.literal("SRV"), priority: z.number().int().min(0).max(65535), weight: z.number().int().min(0).max(65535), port: PortSchema, target: HostnameSchema });
|
|
19
|
+
const PTRRecordSchema = z.object({ type: z.literal("PTR"), target: HostnameSchema });
|
|
20
|
+
const DnsRecordSchema = z.discriminatedUnion("type", [
|
|
21
|
+
ARecordSchema,
|
|
22
|
+
AAAARecordSchema,
|
|
23
|
+
CNAMERecordSchema,
|
|
24
|
+
TXTRecordSchema,
|
|
25
|
+
MXRecordSchema,
|
|
26
|
+
NSRecordSchema,
|
|
27
|
+
SRVRecordSchema,
|
|
28
|
+
PTRRecordSchema,
|
|
29
|
+
]);
|
|
30
|
+
const HttpProxySchema = z.object({
|
|
31
|
+
enabled: z.boolean(),
|
|
32
|
+
upstream: CrlfFreeString.optional(),
|
|
33
|
+
headers: z.record(z.string().regex(/^[a-zA-Z0-9\-]+$/), CrlfFreeString).default({}),
|
|
34
|
+
forwardRequestBody: z.boolean().default(false),
|
|
35
|
+
maxRequestBodyBytes: z.number().int().min(0).max(10485760).default(5242880),
|
|
36
|
+
}).refine(data => !data.enabled || !!data.upstream, {
|
|
37
|
+
message: "HTTP proxy requires 'upstream' URL when enabled",
|
|
38
|
+
path: ["upstream"]
|
|
39
|
+
});
|
|
40
|
+
const RedirectSchema = z.object({
|
|
41
|
+
enabled: z.boolean().default(true),
|
|
42
|
+
code: z.union([z.literal(301), z.literal(302), z.literal(303), z.literal(307), z.literal(308)]),
|
|
43
|
+
target: CrlfFreeString,
|
|
44
|
+
});
|
|
45
|
+
const HostConfigSchema = z.object({
|
|
46
|
+
records: z.array(DnsRecordSchema).default([]),
|
|
47
|
+
http_proxy: HttpProxySchema.optional(),
|
|
48
|
+
redirect: RedirectSchema.optional(),
|
|
49
|
+
});
|
|
50
|
+
const FirewallSchema = z.object({
|
|
51
|
+
defaultPolicy: z.enum(["allow", "deny"]).default("deny"),
|
|
52
|
+
allowlist_domains: z.array(z.string().max(253)).default([]),
|
|
53
|
+
blocklist_domains: z.array(z.string().max(253)).default([]),
|
|
54
|
+
allowlist_ranges: z.array(z.string().max(40)).default([]),
|
|
55
|
+
blocklist_ranges: z.array(z.string().max(40)).default([]),
|
|
56
|
+
allowlist_ips: z.array(z.string().max(40)).default([]),
|
|
57
|
+
blocklist_ips: z.array(z.string().max(40)).default([]),
|
|
58
|
+
});
|
|
59
|
+
const ControlPlaneSchema = z.object({
|
|
60
|
+
enabled: z.boolean().default(true).optional(),
|
|
61
|
+
port: z.coerce.number().int().min(1).max(65535).default(8080).optional(),
|
|
62
|
+
apiKey: z.string().optional()
|
|
63
|
+
});
|
|
64
|
+
const ServerConfigSchema = z.object({
|
|
65
|
+
port: z.coerce.number().int().min(1).max(65535).default(53),
|
|
66
|
+
fallbackDns: Ipv4Schema.optional(),
|
|
67
|
+
firewall: FirewallSchema.optional(),
|
|
68
|
+
controlPlane: ControlPlaneSchema.optional(),
|
|
69
|
+
dnsCacheMaxSize: z.coerce.number().int().min(1).max(100000).default(1024),
|
|
70
|
+
dnsCacheTtlMs: z.coerce.number().int().min(0).max(3600000).default(0),
|
|
71
|
+
maxTcpConnections: z.coerce.number().int().min(1).max(10000).default(100),
|
|
72
|
+
tcpIdleTimeoutMs: z.coerce.number().int().min(1000).max(600000).default(30000),
|
|
73
|
+
rateLimitMaxRequests: z.coerce.number().int().min(0).max(100000).default(0),
|
|
74
|
+
rateLimitWindowMs: z.coerce.number().int().min(100).max(60000).default(1000),
|
|
75
|
+
hosts: z.record(z.string(), HostConfigSchema).default({}),
|
|
76
|
+
}).refine(data => {
|
|
77
|
+
for (const key of Object.keys(data.hosts)) {
|
|
78
|
+
const normalized = key.toLowerCase();
|
|
79
|
+
if (normalized === "*")
|
|
80
|
+
continue;
|
|
81
|
+
if (normalized.startsWith("*.")) {
|
|
82
|
+
HostnameSchema.parse(normalized.slice(2));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
HostnameSchema.parse(normalized);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}, "Contains invalid hostnames in configuration keys");
|
|
90
|
+
export function validateARecord(record) { return ARecordSchema.parse(record); }
|
|
91
|
+
export function validateAAAARecord(record) { return AAAARecordSchema.parse(record); }
|
|
92
|
+
export function validateCNAME(record) { return CNAMERecordSchema.parse(record); }
|
|
93
|
+
export function validateTXT(record) { return TXTRecordSchema.parse(record); }
|
|
94
|
+
export function validateMX(record) { return MXRecordSchema.parse(record); }
|
|
95
|
+
export function validateNS(record) { return NSRecordSchema.parse(record); }
|
|
96
|
+
export function validateSRV(record) { return SRVRecordSchema.parse(record); }
|
|
97
|
+
export function validatePTR(record) { return PTRRecordSchema.parse(record); }
|
|
98
|
+
export function validateRecord(record) {
|
|
99
|
+
if (!record || typeof record !== "object" || !("type" in record)) {
|
|
100
|
+
throw new Error("DNS record must be an object with a 'type' field");
|
|
101
|
+
}
|
|
102
|
+
return DnsRecordSchema.parse(record);
|
|
103
|
+
}
|
|
104
|
+
export function validateHostConfig(config) {
|
|
105
|
+
try {
|
|
106
|
+
return HostConfigSchema.parse(config);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
throw new Error(`Host validation error: ${error}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export function validateServerConfig(config) {
|
|
113
|
+
try {
|
|
114
|
+
const parsed = ServerConfigSchema.parse(config);
|
|
115
|
+
const lowercaseHosts = {};
|
|
116
|
+
for (const [key, value] of Object.entries(parsed.hosts)) {
|
|
117
|
+
lowercaseHosts[key.toLowerCase()] = value;
|
|
118
|
+
}
|
|
119
|
+
return { ...parsed, hosts: lowercaseHosts };
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
throw new Error(`Configuration validation error: ${error}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|