mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-05 12:45:00 +03:00
814cda3fb4
Bump xtls/xray-core to 50231eaf (v26.7.11) and the three binary pins (DockerInit.sh, release.yml x2) in lockstep. Adapt the panel to the upstream changes: - Shadowsocks "none"/"plain" and VMess "none"/"zero" were removed from the core. A migration rewrites stored none/plain SS methods to a supported cipher and none/zero VMess security to "auto" (on both the clients column and inbound settings JSON); the SS build-time heal does the same so a row injected after boot cannot brick startup. The removed values are dropped from every frontend option list, schema and adapter, and coerced to "auto" at the Go link/sub/Clash emit sites and both link importers. Fix the CipherType_NONE sentinel that no longer compiles. - Unencrypted vless/trojan outbounds to a public address are now refused by the core. Validate outbounds through the vendored config loader when saving the xray template and when storing/merging outbound subscriptions, so one such outbound cannot keep the core from starting. - New TCP finalmask type "xmc" (Minecraft mimicry): add it to the sub link allowlist, the frontend enum and the FinalMask form (hostname, usernames, required password), and document it. - streamSettings gained a "method" alias for "network"; canonicalize it to "network" at inbound save time and in the form adapters/schema so a method-keyed config keeps its transport. - New root "env" config key is passed through xray.Config, compared in Equals, and forces a restart in the hot diff. - REALITY now defaults minClientVer to 26.3.27; update the form placeholder.
89 lines
3.6 KiB
TypeScript
89 lines
3.6 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
// FinalMask is xray-core's late-layer obfuscation wrapper applied AFTER
|
|
// the network/security layers. It models per-type masks on TCP and UDP
|
|
// plus optional QUIC tuning. The `settings` sub-object is polymorphic on
|
|
// `type`; we model the wire-faithful shape with a permissive
|
|
// record-of-unknown for `settings` and leave per-type tightening to
|
|
// Step 6 — there are 8 UDP mask types plus 4 TCP mask types, each with
|
|
// distinct setting fields, and modeling them all as discriminated unions
|
|
// here would dwarf the rest of the stream module without buying anything
|
|
// the safety net doesn't already cover.
|
|
|
|
export const TcpMaskTypeSchema = z.enum(['fragment', 'sudoku', 'header-custom', 'xmc']);
|
|
export type TcpMaskType = z.infer<typeof TcpMaskTypeSchema>;
|
|
|
|
export const TcpMaskSchema = z.object({
|
|
type: TcpMaskTypeSchema,
|
|
settings: z.record(z.string(), z.unknown()).optional(),
|
|
});
|
|
export type TcpMask = z.infer<typeof TcpMaskSchema>;
|
|
|
|
export const UdpMaskTypeSchema = z.enum([
|
|
'salamander',
|
|
'mkcp-legacy',
|
|
'header-custom',
|
|
'xdns',
|
|
'xicmp',
|
|
'noise',
|
|
'sudoku',
|
|
'realm',
|
|
]);
|
|
export type UdpMaskType = z.infer<typeof UdpMaskTypeSchema>;
|
|
|
|
export const UdpMaskSchema = z.object({
|
|
type: UdpMaskTypeSchema,
|
|
settings: z.record(z.string(), z.unknown()).optional(),
|
|
});
|
|
export type UdpMask = z.infer<typeof UdpMaskSchema>;
|
|
|
|
export const QuicCongestionSchema = z.enum(['reno', 'bbr', 'brutal', 'force-brutal']);
|
|
export type QuicCongestion = z.infer<typeof QuicCongestionSchema>;
|
|
|
|
export const BbrProfileSchema = z.enum(['conservative', 'standard', 'aggressive']);
|
|
export type BbrProfile = z.infer<typeof BbrProfileSchema>;
|
|
|
|
// udpHop randomizes the QUIC port between a range every `interval` seconds
|
|
// to dodge port-based blocking. Both fields are dash-range strings on the
|
|
// wire (e.g. '20000-50000', '5-10'). preprocess coerces legacy DB rows
|
|
// where interval was stored as a number (UI bug — see B19 in commit history).
|
|
const StringRangeSchema = z.preprocess(
|
|
(v) => (typeof v === 'number' ? String(v) : v),
|
|
z.string(),
|
|
);
|
|
|
|
export const QuicUdpHopSchema = z.object({
|
|
ports: StringRangeSchema.default('20000-50000'),
|
|
interval: StringRangeSchema.default('5-10'),
|
|
});
|
|
export type QuicUdpHop = z.infer<typeof QuicUdpHopSchema>;
|
|
|
|
export const QuicParamsSchema = z.object({
|
|
congestion: QuicCongestionSchema.default('bbr'),
|
|
bbrProfile: BbrProfileSchema.optional(),
|
|
debug: z.boolean().optional(),
|
|
brutalUp: z.string().optional(),
|
|
brutalDown: z.string().optional(),
|
|
udpHop: QuicUdpHopSchema.optional(),
|
|
initStreamReceiveWindow: z.number().int().min(0).optional(),
|
|
maxStreamReceiveWindow: z.number().int().min(0).optional(),
|
|
initConnectionReceiveWindow: z.number().int().min(0).optional(),
|
|
maxConnectionReceiveWindow: z.number().int().min(0).optional(),
|
|
maxIdleTimeout: z.number().int().min(4).max(120).optional(),
|
|
keepAlivePeriod: z.number().int().min(2).max(60).optional(),
|
|
disablePathMTUDiscovery: z.boolean().optional(),
|
|
maxIncomingStreams: z.number().int().min(8).optional(),
|
|
});
|
|
export type QuicParams = z.infer<typeof QuicParamsSchema>;
|
|
|
|
// `tcp` and `udp` are omitted from the wire entirely when their arrays
|
|
// are empty (legacy toJson() drops them). Our default([]) here mirrors
|
|
// the parsed-in shape; the shadow harness already treats empty arrays as
|
|
// equivalent to absence so both pipelines converge.
|
|
export const FinalMaskStreamSettingsSchema = z.object({
|
|
tcp: z.array(TcpMaskSchema).default([]),
|
|
udp: z.array(UdpMaskSchema).default([]),
|
|
quicParams: QuicParamsSchema.optional(),
|
|
});
|
|
export type FinalMaskStreamSettings = z.infer<typeof FinalMaskStreamSettingsSchema>;
|