mtproto.ts 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { z } from 'zod';
  2. // mtg's [domain-fronting] section: where the sidecar forwards non-Telegram
  3. // traffic (e.g. an NGINX fake site). All optional — omitted keys fall back to
  4. // mtg's defaults (DNS-resolve the FakeTLS host, port 443, no proxy protocol).
  5. export const MtprotoDomainFrontingSchema = z.object({
  6. ip: z.string().optional(),
  7. port: z.number().int().min(0).max(65535).optional(),
  8. proxyProtocol: z.boolean().optional(),
  9. });
  10. export type MtprotoDomainFronting = z.infer<typeof MtprotoDomainFrontingSchema>;
  11. // An MTProto (Telegram) inbound client (multi-client model). Each client is one
  12. // named FakeTLS secret the mtg-multi sidecar serves through its [secrets]
  13. // section; `secret` is the ee-prefixed FakeTLS secret whose trailing domain the
  14. // backend rebuilds on save. `fakeTlsDomain` is stored on the inbound as the
  15. // default domain used when generating a new client's secret.
  16. export const MtprotoClientSchema = z.object({
  17. secret: z.string().default(''),
  18. adTag: z
  19. .string()
  20. .regex(/^[0-9a-fA-F]{32}$/, 'pages.inbounds.form.mtgAdTagInvalid')
  21. .or(z.literal(''))
  22. .optional(),
  23. email: z.string().min(1),
  24. limitIp: z.number().int().min(0).default(0),
  25. totalGB: z.number().int().min(0).default(0),
  26. expiryTime: z.number().int().default(0),
  27. enable: z.boolean().default(true),
  28. tgId: z.union([z.number(), z.string()]).transform((v) => Number(v) || 0).default(0),
  29. subId: z.string().default(''),
  30. comment: z.string().default(''),
  31. reset: z.number().int().min(0).default(0),
  32. created_at: z.number().int().optional(),
  33. updated_at: z.number().int().optional(),
  34. });
  35. export type MtprotoClient = z.infer<typeof MtprotoClientSchema>;
  36. // MTProto (Telegram) inbound. Served by an mtg-multi sidecar process, not Xray,
  37. // so it has no stream settings. Each client carries its own FakeTLS secret and
  38. // is served on the shared inbound port. The remaining fields map to optional mtg
  39. // config knobs and are written to the generated mtg config only when set.
  40. export const MtprotoInboundSettingsSchema = z.object({
  41. fakeTlsDomain: z.string().default('www.cloudflare.com'),
  42. clients: z.array(MtprotoClientSchema).default([]),
  43. proxyProtocolListener: z.boolean().optional(),
  44. preferIp: z.enum(['prefer-ipv6', 'prefer-ipv4', 'only-ipv6', 'only-ipv4']).optional(),
  45. debug: z.boolean().optional(),
  46. domainFronting: MtprotoDomainFrontingSchema.optional(),
  47. // Caps concurrent connections across all users with a fair-share algorithm;
  48. // 0 or unset disables throttling.
  49. throttleMaxConnections: z.number().int().min(0).optional(),
  50. // When set, the mtg sidecar dials Telegram through a loopback SOCKS bridge in
  51. // the Xray config so the egress obeys routing rules. `outboundTag` optionally
  52. // forces that traffic out a specific outbound/balancer. `routeXrayPort` is the
  53. // bridge port; it is allocated and owned by the backend (never edited here).
  54. routeThroughXray: z.boolean().optional(),
  55. outboundTag: z.string().optional(),
  56. routeXrayPort: z.number().int().min(0).max(65535).optional(),
  57. // publicIpv4/publicIpv6 pin this server's reachable address the Telegram
  58. // middle proxy needs when clients carry ad-tags; blank = mtg auto-detects.
  59. publicIpv4: z.string().optional(),
  60. publicIpv6: z.string().optional(),
  61. });
  62. export type MtprotoInboundSettings = z.infer<typeof MtprotoInboundSettingsSchema>;