1import { z } from "zod";
2import { HostSchema, TlsSchema } from "@marzneshin/modules/hosts";
3import { SplitHttpSettingsSchema } from "./split-http-settings.schema";
4import { MuxSettingsSchema } from "./mux-settings.schema";
5import i18n from "i18next";
6
7const numberInterval = (v: string | null | undefined) => {
8 return v ? /^[\d-]{1,32}$/.test(v) : false;
9};
10
11const packetsInterval = (v: string | null | undefined) => {
12 return v ? /^(:?tlshello|[\d-]{1,32})$/.test(v) : false;
13};
14
15export const alpnOptions = [
16 "none",
17 "h2",
18 "h3",
19 "h3,h2",
20 "http/1.1",
21 "h2,http/1.1",
22 "h3,h2,http/1.1",
23];
24
25export const noiseTypes = ["rand", "str", "base64"] as const;
26
27const FragmentSchema = z.object({
28 interval: z
29 .string()
30 .refine(
31 (v) => numberInterval(v),
32 i18n.t("page.hosts.fragment.interval-error"),
33 ),
34 length: z
35 .string()
36 .refine(
37 (v) => numberInterval(v),
38 i18n.t("page.hosts.fragment.length-error"),
39 ),
40 packets: z
41 .string()
42 .refine(
43 (v) => packetsInterval(v),
44 i18n.t("page.hosts.fragment.packets-error"),
45 ),
46});
47
48const NoiseSchema = z.array(
49 z.object({
50 delay: z
51 .string()
52 .refine(
53 (v) => numberInterval(v),
54 i18n.t("page.hosts.noise.delay-error"),
55 ),
56 type: z.enum(noiseTypes).default("rand"),
57 packet: z.string(),
58 }),
59);
60
61const FingerprintSchema = z.enum([
62 "",
63 "none",
64 "chrome",
65 "firefox",
66 "safari",
67 "ios",
68 "android",
69 "edge",
70 "360",
71 "qq",
72 "random",
73 "randomized",
74]);
75
76export const GeneralSchema = HostSchema.merge(TlsSchema).extend({
77 path: z.string().nullable().optional().nullish().default(null),
78 host: z.string().nullable().optional(),
79 mux_settings: MuxSettingsSchema.nullable().optional().default(null),
80 http_headers: z.any().nullable().optional().default(null),
81 fragment: FragmentSchema.nullable().optional().default(null),
82 fingerprint: FingerprintSchema.optional().default("none"),
83 splithttp_settings: SplitHttpSettingsSchema.nullable()
84 .optional()
85 .default(null),
86 noise: NoiseSchema.nullable().optional(),
87 early_data: z.preprocess(
88 (val) =>
89 val === "" || val === undefined || val === null
90 ? null
91 : Number(val),
92 z.union([
93 z
94 .number()
95 .int()
96 .gte(1, "Port must be more than 1")
97 .lte(65535, "Port cannot be more than 65535"),
98 z.null(),
99 ]),
100 ),
101 security: z
102 .enum(["inbound_default", "none", "tls"])
103 .default("inbound_default"),
104});
105
106export type GeneralSchemaType = z.infer<typeof GeneralSchema>;