1from enum import Enum
2
3from pydantic import ConfigDict, BaseModel, Field, field_validator
4
5from app.models.node import Node
6
7
8class ProxyTypes(str, Enum):
9 # proxy_type = protocol
10 VMess = "vmess"
11 VLESS = "vless"
12 Trojan = "trojan"
13 Shadowsocks = "shadowsocks"
14 Hysteria2 = "hysteria2"
15
16
17class InboundHostSecurity(str, Enum):
18 inbound_default = "inbound_default"
19 none = "none"
20 tls = "tls"
21
22
23InboundHostALPN = Enum(
24 "ProxyHostALPN",
25 {
26 "none": "none",
27 "h2": "h2",
28 "http/1.1": "http/1.1",
29 "h2,http/1.1": "h2,http/1.1",
30 "h3": "h3",
31 "h3,h2": "h3,h2",
32 "h3,h2,http/1.1": "h3,h2,http/1.1",
33 },
34)
35
36
37InboundHostFingerprint = Enum(
38 "ProxyHostFingerprint",
39 {
40 "none": "",
41 "chrome": "chrome",
42 "firefox": "firefox",
43 "safari": "safari",
44 "ios": "ios",
45 "android": "android",
46 "edge": "edge",
47 "360": "360",
48 "qq": "qq",
49 "random": "random",
50 "randomized": "randomized",
51 },
52)
53
54
55class FormatVariables(dict):
56 def __missing__(self, key):
57 return key.join("{}")
58
59
60class FragmentSettings(BaseModel):
61 packets: str = Field(pattern=r"^(:?tlshello|[\d-]{1,32})$")
62 length: str = Field(pattern=r"^[\d-]{1,32}$")
63 interval: str = Field(pattern=r"^[\d-]{1,32}$")
64
65
66class InboundHost(BaseModel):
67 remark: str
68 address: str
69 port: int | None = Field(None)
70 sni: str | None = Field(None)
71 host: str | None = Field(None)
72 path: str | None = Field(None)
73 security: InboundHostSecurity = InboundHostSecurity.inbound_default
74 alpn: InboundHostALPN = InboundHostALPN.none
75 fingerprint: InboundHostFingerprint = InboundHostFingerprint.none
76 allowinsecure: bool | None = None
77 is_disabled: bool | None = None
78 mux: bool = Field(False)
79 fragment: FragmentSettings | None = Field(None)
80 weight: int = 1
81 model_config = ConfigDict(from_attributes=True)
82
83 @field_validator("remark", "address", "path")
84 @classmethod
85 def validate_fmt_variables(cls, v: str) -> str:
86 if not v:
87 return v
88
89 v.format_map(FormatVariables())
90
91 return v
92
93 @field_validator("alpn", mode="before")
94 @classmethod
95 def validate_alpn(cls, v):
96 if not v:
97 return InboundHostALPN.none
98 return v
99
100
101class InboundHostResponse(InboundHost):
102 id: int
103
104
105class Inbound(BaseModel):
106 id: int
107 tag: str
108 protocol: ProxyTypes
109 config: str
110 node: Node
111 service_ids: list[int]
112 model_config = ConfigDict(from_attributes=True)