mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-09 14:16:07 +00:00
43500a5470
Catch the panel up to the mtg-multi README (v1.14.0): - Each client can now carry its own 32-hex advertising tag overriding the inbound-level one. The tag lives on the client (settings JSON is the source of truth, clients.ad_tag is the UI projection), is rendered into the fork's [secret-ad-tags] section for active secrets only (mtg rejects a config whose override names an unknown secret), is pushed per entry through PUT /secrets, and is part of the reload fingerprint so a tag edit hot-applies without dropping connections. - The loopback management API can replace the whole secret set, so every mtg process now gets a random per-process api-token; the manager sends it as a bearer token on PUT /secrets and GET /stats and reuses it across config rewrites, because mtg reads the token only at startup. - Malformed tags are rejected at every save path and additionally dropped in InstanceFromInbound: one bad tag would otherwise fail the whole generated config and take every client of the inbound down with it. - SyncInbound never copied a re-keyed mtproto secret into the canonical clients table, so the clients page and subscription links kept serving the old secret, which mtg then rejects. It is now guarded-copied like the other credentials.
73 lines
3.5 KiB
TypeScript
73 lines
3.5 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
// mtg's [domain-fronting] section: where the sidecar forwards non-Telegram
|
|
// traffic (e.g. an NGINX fake site). All optional — omitted keys fall back to
|
|
// mtg's defaults (DNS-resolve the FakeTLS host, port 443, no proxy protocol).
|
|
export const MtprotoDomainFrontingSchema = z.object({
|
|
ip: z.string().optional(),
|
|
port: z.number().int().min(0).max(65535).optional(),
|
|
proxyProtocol: z.boolean().optional(),
|
|
});
|
|
export type MtprotoDomainFronting = z.infer<typeof MtprotoDomainFrontingSchema>;
|
|
|
|
// An MTProto (Telegram) inbound client (multi-client model). Each client is one
|
|
// named FakeTLS secret the mtg-multi sidecar serves through its [secrets]
|
|
// section; `secret` is the ee-prefixed FakeTLS secret whose trailing domain the
|
|
// backend rebuilds on save. `fakeTlsDomain` is stored on the inbound as the
|
|
// default domain used when generating a new client's secret.
|
|
export const MtprotoClientSchema = z.object({
|
|
secret: z.string().default(''),
|
|
adTag: z
|
|
.string()
|
|
.regex(/^[0-9a-fA-F]{32}$/, 'pages.inbounds.form.mtgAdTagInvalid')
|
|
.or(z.literal(''))
|
|
.optional(),
|
|
email: z.string().min(1),
|
|
limitIp: z.number().int().min(0).default(0),
|
|
totalGB: z.number().int().min(0).default(0),
|
|
expiryTime: z.number().int().default(0),
|
|
enable: z.boolean().default(true),
|
|
tgId: z.union([z.number(), z.string()]).transform((v) => Number(v) || 0).default(0),
|
|
subId: z.string().default(''),
|
|
comment: z.string().default(''),
|
|
reset: z.number().int().min(0).default(0),
|
|
created_at: z.number().int().optional(),
|
|
updated_at: z.number().int().optional(),
|
|
});
|
|
export type MtprotoClient = z.infer<typeof MtprotoClientSchema>;
|
|
|
|
// MTProto (Telegram) inbound. Served by an mtg-multi sidecar process, not Xray,
|
|
// so it has no stream settings. Each client carries its own FakeTLS secret and
|
|
// is served on the shared inbound port. The remaining fields map to optional mtg
|
|
// config knobs and are written to the generated mtg config only when set.
|
|
export const MtprotoInboundSettingsSchema = z.object({
|
|
fakeTlsDomain: z.string().default('www.cloudflare.com'),
|
|
clients: z.array(MtprotoClientSchema).default([]),
|
|
proxyProtocolListener: z.boolean().optional(),
|
|
preferIp: z.enum(['prefer-ipv6', 'prefer-ipv4', 'only-ipv6', 'only-ipv4']).optional(),
|
|
debug: z.boolean().optional(),
|
|
domainFronting: MtprotoDomainFrontingSchema.optional(),
|
|
// Caps concurrent connections across all users with a fair-share algorithm;
|
|
// 0 or unset disables throttling.
|
|
throttleMaxConnections: z.number().int().min(0).optional(),
|
|
// When set, the mtg sidecar dials Telegram through a loopback SOCKS bridge in
|
|
// the Xray config so the egress obeys routing rules. `outboundTag` optionally
|
|
// forces that traffic out a specific outbound/balancer. `routeXrayPort` is the
|
|
// bridge port; it is allocated and owned by the backend (never edited here).
|
|
routeThroughXray: z.boolean().optional(),
|
|
outboundTag: z.string().optional(),
|
|
routeXrayPort: z.number().int().min(0).max(65535).optional(),
|
|
// A 32-hex Telegram advertising tag: when set, mtg routes clients through
|
|
// Telegram middle proxies so a sponsored channel appears in their chat list.
|
|
// publicIpv4/publicIpv6 pin this server's reachable address the middle proxy
|
|
// needs; leave them blank to let mtg auto-detect it.
|
|
adTag: z
|
|
.string()
|
|
.regex(/^[0-9a-fA-F]{32}$/, 'pages.inbounds.form.mtgAdTagInvalid')
|
|
.or(z.literal(''))
|
|
.optional(),
|
|
publicIpv4: z.string().optional(),
|
|
publicIpv6: z.string().optional(),
|
|
});
|
|
export type MtprotoInboundSettings = z.infer<typeof MtprotoInboundSettingsSchema>;
|