mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-15 00:56:08 +00:00
1cfd7b49b0
The notification/test email carried only From/To/Subject/MIME headers, and
the From header was the raw SMTP username. Two problems:
- When the SMTP login is not a bare email address (common with relays and
submission services), the From header has no valid address and strict
receivers reject the message — e.g. Gmail returns "550-5.7.1 ... Messages
missing a valid address in From: header".
- There was no Date (mandatory per RFC 5322 section 3.6) and no Message-ID,
which also raises spam score.
Add smtpFrom (sender address) and smtpFromName (display name) settings and
assemble the message with net/mail: a name-addr From ("Name" <addr>), a
Date, a Message-ID, and an RFC 2047 encoded Subject, in a deterministic
header order. From falls back to the username when smtpFrom is empty, so
existing setups keep working. Wire the settings through the model, the SMTP
send and test paths, the Email settings UI, and all 13 locale files;
regenerate the Zod/OpenAPI artifacts.
Validate smtpFrom in AllSetting.CheckValid (reject anything net/mail cannot
parse), which surfaces a bad address at configuration time and prevents CRLF
header injection; strip CR/LF in buildMessage as defense in depth. Add
buildMessage and CheckValid tests.
606 lines
18 KiB
TypeScript
606 lines
18 KiB
TypeScript
// Code generated by tools/openapigen. DO NOT EDIT.
|
|
import { z } from 'zod';
|
|
export const OnlineAPISupportSchema = z.number().int();
|
|
export type OnlineAPISupport = z.infer<typeof OnlineAPISupportSchema>;
|
|
|
|
export const ProcessStateSchema = z.string();
|
|
export type ProcessState = z.infer<typeof ProcessStateSchema>;
|
|
|
|
export const ProtocolSchema = z.string();
|
|
export type Protocol = z.infer<typeof ProtocolSchema>;
|
|
|
|
export const SubLinkProviderSchema = z.unknown();
|
|
export type SubLinkProvider = z.infer<typeof SubLinkProviderSchema>;
|
|
|
|
export const staticEgressResolverSchema = z.string();
|
|
export type staticEgressResolver = z.infer<typeof staticEgressResolverSchema>;
|
|
|
|
export const transportBitsSchema = z.number().int();
|
|
export type transportBits = z.infer<typeof transportBitsSchema>;
|
|
|
|
export const AllSettingSchema = z.object({
|
|
datepicker: z.string(),
|
|
expireDiff: z.number().int().min(0),
|
|
externalTrafficInformEnable: z.boolean(),
|
|
externalTrafficInformURI: z.string(),
|
|
ldapAutoCreate: z.boolean(),
|
|
ldapAutoDelete: z.boolean(),
|
|
ldapBaseDN: z.string(),
|
|
ldapBindDN: z.string(),
|
|
ldapDefaultExpiryDays: z.number().int().min(0),
|
|
ldapDefaultLimitIP: z.number().int().min(0),
|
|
ldapDefaultTotalGB: z.number().int().min(0),
|
|
ldapEnable: z.boolean(),
|
|
ldapFlagField: z.string(),
|
|
ldapHost: z.string(),
|
|
ldapInboundTags: z.string(),
|
|
ldapInsecureSkipVerify: z.boolean(),
|
|
ldapInvertFlag: z.boolean(),
|
|
ldapPassword: z.string(),
|
|
ldapPort: z.number().int().min(0).max(65535),
|
|
ldapSyncCron: z.string(),
|
|
ldapTruthyValues: z.string(),
|
|
ldapUseTLS: z.boolean(),
|
|
ldapUserAttr: z.string(),
|
|
ldapUserFilter: z.string(),
|
|
ldapVlessField: z.string(),
|
|
pageSize: z.number().int().min(0).max(1000),
|
|
panelOutbound: z.string(),
|
|
remarkTemplate: z.string(),
|
|
restartXrayOnClientDisable: z.boolean(),
|
|
sessionMaxAge: z.number().int().min(1).max(525600),
|
|
smtpCpu: z.number().int().min(0).max(100),
|
|
smtpEnable: z.boolean(),
|
|
smtpEnabledEvents: z.string(),
|
|
smtpEncryptionType: z.string(),
|
|
smtpFrom: z.string(),
|
|
smtpFromName: z.string(),
|
|
smtpHost: z.string(),
|
|
smtpMemory: z.number().int().min(0).max(100),
|
|
smtpPassword: z.string(),
|
|
smtpPort: z.number().int().min(1).max(65535),
|
|
smtpTo: z.string(),
|
|
smtpUsername: z.string(),
|
|
subAnnounce: z.string(),
|
|
subCertFile: z.string(),
|
|
subClashEnable: z.boolean(),
|
|
subClashEnableRouting: z.boolean(),
|
|
subClashPath: z.string(),
|
|
subClashRules: z.string(),
|
|
subClashURI: z.string(),
|
|
subDomain: z.string(),
|
|
subEnable: z.boolean(),
|
|
subEnableRouting: z.boolean(),
|
|
subEncrypt: z.boolean(),
|
|
subHideSettings: z.boolean(),
|
|
subIncyEnableRouting: z.boolean(),
|
|
subIncyRoutingRules: z.string(),
|
|
subJsonEnable: z.boolean(),
|
|
subJsonFinalMask: z.string(),
|
|
subJsonMux: z.string(),
|
|
subJsonPath: z.string(),
|
|
subJsonRules: z.string(),
|
|
subJsonURI: z.string(),
|
|
subKeyFile: z.string(),
|
|
subListen: z.string(),
|
|
subPath: z.string(),
|
|
subPort: z.number().int().min(1).max(65535),
|
|
subProfileUrl: z.string(),
|
|
subRoutingRules: z.string(),
|
|
subSupportUrl: z.string(),
|
|
subThemeDir: z.string(),
|
|
subTitle: z.string(),
|
|
subURI: z.string(),
|
|
subUpdates: z.number().int().min(0).max(525600),
|
|
tgBotAPIServer: z.string(),
|
|
tgBotBackup: z.boolean(),
|
|
tgBotChatId: z.string(),
|
|
tgBotEnable: z.boolean(),
|
|
tgBotProxy: z.string(),
|
|
tgBotToken: z.string(),
|
|
tgCpu: z.number().int().min(0).max(100),
|
|
tgEnabledEvents: z.string(),
|
|
tgLang: z.string(),
|
|
tgMemory: z.number().int().min(0).max(100),
|
|
tgRunTime: z.string(),
|
|
timeLocation: z.string(),
|
|
trafficDiff: z.number().int().min(0).max(100),
|
|
trustedProxyCIDRs: z.string(),
|
|
twoFactorEnable: z.boolean(),
|
|
twoFactorToken: z.string(),
|
|
warpUpdateInterval: z.number().int().min(0),
|
|
webBasePath: z.string(),
|
|
webCertFile: z.string(),
|
|
webDomain: z.string(),
|
|
webKeyFile: z.string(),
|
|
webListen: z.string(),
|
|
webPort: z.number().int().min(1).max(65535),
|
|
});
|
|
export type AllSetting = z.infer<typeof AllSettingSchema>;
|
|
|
|
export const AllSettingViewSchema = z.object({
|
|
datepicker: z.string(),
|
|
expireDiff: z.number().int().min(0),
|
|
externalTrafficInformEnable: z.boolean(),
|
|
externalTrafficInformURI: z.string(),
|
|
hasApiToken: z.boolean(),
|
|
hasLdapPassword: z.boolean(),
|
|
hasNordSecret: z.boolean(),
|
|
hasSmtpPassword: z.boolean(),
|
|
hasTgBotToken: z.boolean(),
|
|
hasTwoFactorToken: z.boolean(),
|
|
hasWarpSecret: z.boolean(),
|
|
ldapAutoCreate: z.boolean(),
|
|
ldapAutoDelete: z.boolean(),
|
|
ldapBaseDN: z.string(),
|
|
ldapBindDN: z.string(),
|
|
ldapDefaultExpiryDays: z.number().int().min(0),
|
|
ldapDefaultLimitIP: z.number().int().min(0),
|
|
ldapDefaultTotalGB: z.number().int().min(0),
|
|
ldapEnable: z.boolean(),
|
|
ldapFlagField: z.string(),
|
|
ldapHost: z.string(),
|
|
ldapInboundTags: z.string(),
|
|
ldapInsecureSkipVerify: z.boolean(),
|
|
ldapInvertFlag: z.boolean(),
|
|
ldapPassword: z.string(),
|
|
ldapPort: z.number().int().min(0).max(65535),
|
|
ldapSyncCron: z.string(),
|
|
ldapTruthyValues: z.string(),
|
|
ldapUseTLS: z.boolean(),
|
|
ldapUserAttr: z.string(),
|
|
ldapUserFilter: z.string(),
|
|
ldapVlessField: z.string(),
|
|
pageSize: z.number().int().min(0).max(1000),
|
|
panelOutbound: z.string(),
|
|
remarkTemplate: z.string(),
|
|
restartXrayOnClientDisable: z.boolean(),
|
|
sessionMaxAge: z.number().int().min(1).max(525600),
|
|
smtpCpu: z.number().int().min(0).max(100),
|
|
smtpEnable: z.boolean(),
|
|
smtpEnabledEvents: z.string(),
|
|
smtpEncryptionType: z.string(),
|
|
smtpFrom: z.string(),
|
|
smtpFromName: z.string(),
|
|
smtpHost: z.string(),
|
|
smtpMemory: z.number().int().min(0).max(100),
|
|
smtpPassword: z.string(),
|
|
smtpPort: z.number().int().min(1).max(65535),
|
|
smtpTo: z.string(),
|
|
smtpUsername: z.string(),
|
|
subAnnounce: z.string(),
|
|
subCertFile: z.string(),
|
|
subClashEnable: z.boolean(),
|
|
subClashEnableRouting: z.boolean(),
|
|
subClashPath: z.string(),
|
|
subClashRules: z.string(),
|
|
subClashURI: z.string(),
|
|
subDomain: z.string(),
|
|
subEnable: z.boolean(),
|
|
subEnableRouting: z.boolean(),
|
|
subEncrypt: z.boolean(),
|
|
subHideSettings: z.boolean(),
|
|
subIncyEnableRouting: z.boolean(),
|
|
subIncyRoutingRules: z.string(),
|
|
subJsonEnable: z.boolean(),
|
|
subJsonFinalMask: z.string(),
|
|
subJsonMux: z.string(),
|
|
subJsonPath: z.string(),
|
|
subJsonRules: z.string(),
|
|
subJsonURI: z.string(),
|
|
subKeyFile: z.string(),
|
|
subListen: z.string(),
|
|
subPath: z.string(),
|
|
subPort: z.number().int().min(1).max(65535),
|
|
subProfileUrl: z.string(),
|
|
subRoutingRules: z.string(),
|
|
subSupportUrl: z.string(),
|
|
subThemeDir: z.string(),
|
|
subTitle: z.string(),
|
|
subURI: z.string(),
|
|
subUpdates: z.number().int().min(0).max(525600),
|
|
tgBotAPIServer: z.string(),
|
|
tgBotBackup: z.boolean(),
|
|
tgBotChatId: z.string(),
|
|
tgBotEnable: z.boolean(),
|
|
tgBotProxy: z.string(),
|
|
tgBotToken: z.string(),
|
|
tgCpu: z.number().int().min(0).max(100),
|
|
tgEnabledEvents: z.string(),
|
|
tgLang: z.string(),
|
|
tgMemory: z.number().int().min(0).max(100),
|
|
tgRunTime: z.string(),
|
|
timeLocation: z.string(),
|
|
trafficDiff: z.number().int().min(0).max(100),
|
|
trustedProxyCIDRs: z.string(),
|
|
twoFactorEnable: z.boolean(),
|
|
twoFactorToken: z.string(),
|
|
warpUpdateInterval: z.number().int().min(0),
|
|
webBasePath: z.string(),
|
|
webCertFile: z.string(),
|
|
webDomain: z.string(),
|
|
webKeyFile: z.string(),
|
|
webListen: z.string(),
|
|
webPort: z.number().int().min(1).max(65535),
|
|
});
|
|
export type AllSettingView = z.infer<typeof AllSettingViewSchema>;
|
|
|
|
export const ApiTokenSchema = z.object({
|
|
createdAt: z.number().int(),
|
|
enabled: z.boolean(),
|
|
id: z.number().int(),
|
|
name: z.string(),
|
|
token: z.string(),
|
|
});
|
|
export type ApiToken = z.infer<typeof ApiTokenSchema>;
|
|
|
|
export const ApiTokenViewSchema = z.object({
|
|
createdAt: z.number().int(),
|
|
enabled: z.boolean(),
|
|
id: z.number().int(),
|
|
name: z.string(),
|
|
token: z.string().optional(),
|
|
});
|
|
export type ApiTokenView = z.infer<typeof ApiTokenViewSchema>;
|
|
|
|
export const ClientSchema = z.object({
|
|
adTag: z.string().optional(),
|
|
allowedIPs: z.array(z.string()).optional(),
|
|
auth: z.string().optional(),
|
|
comment: z.string(),
|
|
created_at: z.number().int().optional(),
|
|
email: z.string(),
|
|
enable: z.boolean(),
|
|
expiryTime: z.number().int(),
|
|
flow: z.string().optional(),
|
|
group: z.string().optional(),
|
|
id: z.string().optional(),
|
|
keepAlive: z.number().int().optional(),
|
|
limitIp: z.number().int(),
|
|
password: z.string().optional(),
|
|
preSharedKey: z.string().optional(),
|
|
privateKey: z.string().optional(),
|
|
publicKey: z.string().optional(),
|
|
reset: z.number().int(),
|
|
reverse: z.lazy(() => ClientReverseSchema).nullable().optional(),
|
|
secret: z.string().optional(),
|
|
security: z.string(),
|
|
subId: z.string(),
|
|
tgId: z.number().int(),
|
|
totalGB: z.number().int(),
|
|
updated_at: z.number().int().optional(),
|
|
});
|
|
export type Client = z.infer<typeof ClientSchema>;
|
|
|
|
export const ClientInboundSchema = z.object({
|
|
clientId: z.number().int(),
|
|
createdAt: z.number().int(),
|
|
flowOverride: z.string(),
|
|
inboundId: z.number().int(),
|
|
});
|
|
export type ClientInbound = z.infer<typeof ClientInboundSchema>;
|
|
|
|
export const ClientRecordSchema = z.object({
|
|
adTag: z.string(),
|
|
allowedIPs: z.string(),
|
|
auth: z.string(),
|
|
comment: z.string(),
|
|
createdAt: z.number().int(),
|
|
email: z.string(),
|
|
enable: z.boolean(),
|
|
expiryTime: z.number().int(),
|
|
flow: z.string(),
|
|
group: z.string(),
|
|
id: z.number().int(),
|
|
keepAlive: z.number().int(),
|
|
limitIp: z.number().int(),
|
|
password: z.string(),
|
|
preSharedKey: z.string(),
|
|
privateKey: z.string(),
|
|
publicKey: z.string(),
|
|
reset: z.number().int(),
|
|
reverse: z.unknown(),
|
|
secret: z.string(),
|
|
security: z.string(),
|
|
subId: z.string(),
|
|
tgId: z.number().int(),
|
|
totalGB: z.number().int(),
|
|
updatedAt: z.number().int(),
|
|
uuid: z.string(),
|
|
});
|
|
export type ClientRecord = z.infer<typeof ClientRecordSchema>;
|
|
|
|
export const ClientReverseSchema = z.object({
|
|
tag: z.string(),
|
|
});
|
|
export type ClientReverse = z.infer<typeof ClientReverseSchema>;
|
|
|
|
export const ClientTrafficSchema = z.object({
|
|
down: z.number().int(),
|
|
email: z.string(),
|
|
enable: z.boolean(),
|
|
expiryTime: z.number().int(),
|
|
id: z.number().int(),
|
|
inboundId: z.number().int(),
|
|
lastOnline: z.number().int(),
|
|
reset: z.number().int(),
|
|
subId: z.string(),
|
|
total: z.number().int(),
|
|
up: z.number().int(),
|
|
uuid: z.string(),
|
|
});
|
|
export type ClientTraffic = z.infer<typeof ClientTrafficSchema>;
|
|
|
|
export const FallbackParentInfoSchema = z.object({
|
|
masterId: z.number().int(),
|
|
path: z.string().optional(),
|
|
});
|
|
export type FallbackParentInfo = z.infer<typeof FallbackParentInfoSchema>;
|
|
|
|
export const HistoryOfSeedersSchema = z.object({
|
|
id: z.number().int(),
|
|
seederName: z.string(),
|
|
});
|
|
export type HistoryOfSeeders = z.infer<typeof HistoryOfSeedersSchema>;
|
|
|
|
export const HostSchema = z.object({
|
|
address: z.string(),
|
|
allowInsecure: z.boolean(),
|
|
alpn: z.array(z.string()),
|
|
createdAt: z.number().int(),
|
|
echConfigList: z.string(),
|
|
excludeFromSubTypes: z.array(z.string()),
|
|
finalMask: z.string(),
|
|
fingerprint: z.string(),
|
|
groupId: z.string(),
|
|
hostHeader: z.string(),
|
|
id: z.number().int(),
|
|
inboundId: z.number().int(),
|
|
isDisabled: z.boolean(),
|
|
isHidden: z.boolean(),
|
|
keepSniBlank: z.boolean(),
|
|
mihomoIpVersion: z.enum(['dual', 'ipv4', 'ipv6', 'ipv4-prefer', 'ipv6-prefer']),
|
|
mihomoX25519: z.boolean(),
|
|
muxParams: z.unknown(),
|
|
nodeGuids: z.array(z.string()).optional(),
|
|
overrideSniFromAddress: z.boolean(),
|
|
path: z.string(),
|
|
pinnedPeerCertSha256: z.array(z.string()),
|
|
port: z.number().int().min(0).max(65535),
|
|
remark: z.string().max(256),
|
|
security: z.enum(['same', 'tls', 'none', 'reality']),
|
|
serverDescription: z.string().max(64),
|
|
shuffleHost: z.boolean(),
|
|
sni: z.string(),
|
|
sockoptParams: z.unknown(),
|
|
sortOrder: z.number().int(),
|
|
tags: z.array(z.string()),
|
|
updatedAt: z.number().int(),
|
|
verifyPeerCertByName: z.string(),
|
|
vlessRoute: z.string(),
|
|
});
|
|
export type Host = z.infer<typeof HostSchema>;
|
|
|
|
export const HostGroupSchema = z.object({
|
|
allowInsecure: z.boolean(),
|
|
alpn: z.array(z.string()),
|
|
echConfigList: z.string(),
|
|
excludeFromSubTypes: z.array(z.string()),
|
|
finalMask: z.string(),
|
|
fingerprint: z.string(),
|
|
groupId: z.string(),
|
|
hostHeader: z.string(),
|
|
hosts: z.array(z.string()),
|
|
inboundIds: z.array(z.number().int()),
|
|
isDisabled: z.boolean(),
|
|
isHidden: z.boolean(),
|
|
keepSniBlank: z.boolean(),
|
|
mihomoIpVersion: z.enum(['dual', 'ipv4', 'ipv6', 'ipv4-prefer', 'ipv6-prefer']),
|
|
mihomoX25519: z.boolean(),
|
|
muxParams: z.string(),
|
|
nodeGuids: z.array(z.string()),
|
|
overrideSniFromAddress: z.boolean(),
|
|
path: z.string(),
|
|
pinnedPeerCertSha256: z.array(z.string()),
|
|
port: z.number().int().min(0).max(65535),
|
|
remark: z.string().max(256),
|
|
security: z.enum(['same', 'tls', 'none', 'reality']),
|
|
serverDescription: z.string().max(64),
|
|
shuffleHost: z.boolean(),
|
|
sni: z.string(),
|
|
sockoptParams: z.string(),
|
|
sortOrder: z.number().int(),
|
|
tags: z.array(z.string()),
|
|
verifyPeerCertByName: z.string(),
|
|
vlessRoute: z.string(),
|
|
});
|
|
export type HostGroup = z.infer<typeof HostGroupSchema>;
|
|
|
|
export const InboundSchema = z.object({
|
|
clientStats: z.array(z.lazy(() => ClientTrafficSchema)),
|
|
down: z.number().int(),
|
|
enable: z.boolean(),
|
|
expiryTime: z.number().int(),
|
|
fallbackParent: z.lazy(() => FallbackParentInfoSchema).nullable().optional(),
|
|
id: z.number().int(),
|
|
lastTrafficResetTime: z.number().int(),
|
|
listen: z.string(),
|
|
nodeId: z.number().int().nullable().optional(),
|
|
originNodeGuid: z.string().optional(),
|
|
port: z.number().int().min(0).max(65535),
|
|
protocol: z.enum(['vmess', 'vless', 'trojan', 'shadowsocks', 'wireguard', 'hysteria', 'http', 'mixed', 'tunnel', 'tun', 'mtproto']),
|
|
remark: z.string(),
|
|
settings: z.unknown(),
|
|
shareAddr: z.string(),
|
|
shareAddrStrategy: z.enum(['node', 'listen', 'custom']),
|
|
sniffing: z.unknown(),
|
|
streamSettings: z.unknown(),
|
|
subSortIndex: z.number().int().min(1),
|
|
tag: z.string(),
|
|
total: z.number().int(),
|
|
trafficReset: z.enum(['never', 'hourly', 'daily', 'weekly', 'monthly']),
|
|
up: z.number().int(),
|
|
});
|
|
export type Inbound = z.infer<typeof InboundSchema>;
|
|
|
|
export const InboundClientIpsSchema = z.object({
|
|
clientEmail: z.string(),
|
|
id: z.number().int(),
|
|
ips: z.unknown(),
|
|
});
|
|
export type InboundClientIps = z.infer<typeof InboundClientIpsSchema>;
|
|
|
|
export const InboundFallbackSchema = z.object({
|
|
alpn: z.string(),
|
|
childId: z.number().int(),
|
|
dest: z.string(),
|
|
id: z.number().int(),
|
|
masterId: z.number().int(),
|
|
name: z.string(),
|
|
path: z.string(),
|
|
sortOrder: z.number().int(),
|
|
xver: z.number().int(),
|
|
});
|
|
export type InboundFallback = z.infer<typeof InboundFallbackSchema>;
|
|
|
|
export const InboundOptionSchema = z.object({
|
|
enable: z.boolean(),
|
|
id: z.number().int(),
|
|
listen: z.string().optional(),
|
|
mtprotoDomain: z.string().optional(),
|
|
nodeAddress: z.string().optional(),
|
|
nodeId: z.number().int().nullable().optional(),
|
|
port: z.number().int(),
|
|
protocol: z.string(),
|
|
remark: z.string(),
|
|
shareAddr: z.string().optional(),
|
|
shareAddrStrategy: z.string().optional(),
|
|
ssMethod: z.string(),
|
|
tag: z.string(),
|
|
tlsFlowCapable: z.boolean(),
|
|
wgDns: z.string().optional(),
|
|
wgMtu: z.number().int().optional(),
|
|
wgPublicKey: z.string().optional(),
|
|
});
|
|
export type InboundOption = z.infer<typeof InboundOptionSchema>;
|
|
|
|
export const MsgSchema = z.object({
|
|
msg: z.string(),
|
|
obj: z.unknown(),
|
|
success: z.boolean(),
|
|
});
|
|
export type Msg = z.infer<typeof MsgSchema>;
|
|
|
|
export const NodeSchema = z.object({
|
|
activeCount: z.number().int(),
|
|
address: z.string(),
|
|
allowPrivateAddress: z.boolean(),
|
|
apiToken: z.string(),
|
|
basePath: z.string(),
|
|
clientCount: z.number().int(),
|
|
configDirty: z.boolean(),
|
|
configDirtyAt: z.number().int(),
|
|
cpuPct: z.number(),
|
|
createdAt: z.number().int(),
|
|
depletedCount: z.number().int(),
|
|
disabledCount: z.number().int(),
|
|
enable: z.boolean(),
|
|
guid: z.string(),
|
|
id: z.number().int(),
|
|
inboundCount: z.number().int(),
|
|
inboundSyncMode: z.enum(['all', 'selected']),
|
|
inboundTags: z.array(z.string()),
|
|
lastError: z.string(),
|
|
lastHeartbeat: z.number().int(),
|
|
latencyMs: z.number().int(),
|
|
memPct: z.number(),
|
|
name: z.string(),
|
|
netDown: z.number().int(),
|
|
netUp: z.number().int(),
|
|
onlineCount: z.number().int(),
|
|
outboundTag: z.string(),
|
|
panelVersion: z.string(),
|
|
parentGuid: z.string().optional(),
|
|
pinnedCertSha256: z.string(),
|
|
port: z.number().int().min(1).max(65535),
|
|
remark: z.string(),
|
|
scheme: z.enum(['http', 'https']),
|
|
status: z.string(),
|
|
tlsVerifyMode: z.enum(['verify', 'skip', 'pin', 'mtls']),
|
|
transitive: z.boolean().optional(),
|
|
updatedAt: z.number().int(),
|
|
uptimeSecs: z.number().int(),
|
|
xrayError: z.string(),
|
|
xrayState: z.string(),
|
|
xrayVersion: z.string(),
|
|
});
|
|
export type Node = z.infer<typeof NodeSchema>;
|
|
|
|
export const OutboundTrafficsSchema = z.object({
|
|
down: z.number().int(),
|
|
id: z.number().int(),
|
|
tag: z.string(),
|
|
total: z.number().int(),
|
|
up: z.number().int(),
|
|
});
|
|
export type OutboundTraffics = z.infer<typeof OutboundTrafficsSchema>;
|
|
|
|
export const PanelUpdateStatusSchema = z.object({
|
|
exitCode: z.number().int(),
|
|
finishedAt: z.number().int(),
|
|
runId: z.string(),
|
|
state: z.string(),
|
|
});
|
|
export type PanelUpdateStatus = z.infer<typeof PanelUpdateStatusSchema>;
|
|
|
|
export const ProbeResultUISchema = z.object({
|
|
cpuPct: z.number(),
|
|
error: z.string(),
|
|
latencyMs: z.number().int(),
|
|
memPct: z.number(),
|
|
panelVersion: z.string(),
|
|
status: z.string(),
|
|
uptimeSecs: z.number().int(),
|
|
xrayError: z.string(),
|
|
xrayState: z.string(),
|
|
xrayVersion: z.string(),
|
|
});
|
|
export type ProbeResultUI = z.infer<typeof ProbeResultUISchema>;
|
|
|
|
export const RealityScanResultSchema = z.object({
|
|
alpn: z.string(),
|
|
certIssuer: z.string(),
|
|
certSubject: z.string(),
|
|
certValid: z.boolean(),
|
|
curveID: z.string(),
|
|
feasible: z.boolean(),
|
|
h2: z.boolean(),
|
|
host: z.string(),
|
|
ip: z.string(),
|
|
latencyMs: z.number().int(),
|
|
notAfter: z.string(),
|
|
port: z.number().int(),
|
|
reason: z.string(),
|
|
serverNames: z.array(z.string()),
|
|
target: z.string(),
|
|
tls13: z.boolean(),
|
|
tlsVersion: z.string(),
|
|
x25519: z.boolean(),
|
|
});
|
|
export type RealityScanResult = z.infer<typeof RealityScanResultSchema>;
|
|
|
|
export const SettingSchema = z.object({
|
|
id: z.number().int(),
|
|
key: z.string(),
|
|
value: z.string(),
|
|
});
|
|
export type Setting = z.infer<typeof SettingSchema>;
|
|
|
|
export const UserSchema = z.object({
|
|
id: z.number().int(),
|
|
password: z.string(),
|
|
username: z.string(),
|
|
});
|
|
export type User = z.infer<typeof UserSchema>;
|
|
|