Skip to content

Commit 825c95b

Browse files
fix(subscription): handle enum values
1 parent 525040f commit 825c95b

File tree

5 files changed

+46
-32
lines changed

5 files changed

+46
-32
lines changed

app/subscription/base.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import re
3+
from enum import Enum
34

45
from app.templates import render_template
56
from config import GRPC_USER_AGENT_TEMPLATE, USER_AGENT_TEMPLATE
@@ -33,7 +34,18 @@ def _remark_validation(self, remark):
3334
return new
3435
c += 1
3536

36-
def _remove_none_values(self, data: dict) -> dict:
37+
def _normalize_and_remove_none_values(self, data: dict) -> dict:
38+
"""
39+
Clean dictionary by removing None, empty strings, and 0 values.
40+
Converts Enum values and recursively cleans nested dictionaries.
41+
42+
Args:
43+
data: Input dictionary to clean
44+
45+
Returns:
46+
Cleaned dictionary with empty values removed
47+
"""
48+
3749
def clean_dict(d: dict) -> dict:
3850
new_dict = {}
3951
for k, v in d.items():
@@ -42,7 +54,10 @@ def clean_dict(d: dict) -> dict:
4254
if cleaned_dict := clean_dict(v):
4355
new_dict[k] = cleaned_dict
4456
else:
45-
new_dict[k] = v
57+
if isinstance(v, Enum):
58+
new_dict[k] = v.value
59+
else:
60+
new_dict[k] = v
4661
return new_dict
4762

4863
return clean_dict(data)

app/subscription/clash.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def http_config(
6060
if random_user_agent:
6161
config["headers"]["User-Agent"] = choice(self.user_agent_list)
6262

63-
return self._remove_none_values(config)
63+
return self._normalize_and_remove_none_values(config)
6464

6565
def ws_config(
6666
self,
@@ -83,18 +83,18 @@ def ws_config(
8383
if random_user_agent:
8484
config["headers"]["User-Agent"] = choice(self.user_agent_list)
8585

86-
return self._remove_none_values(config)
86+
return self._normalize_and_remove_none_values(config)
8787

8888
def grpc_config(self, path=""):
8989
config = {"grpc-service-name": path}
90-
return self._remove_none_values(config)
90+
return self._normalize_and_remove_none_values(config)
9191

9292
def h2_config(self, path="", host=""):
9393
config = {
9494
"path": path,
9595
"host": [host] if host else None,
9696
}
97-
return self._remove_none_values(config)
97+
return self._normalize_and_remove_none_values(config)
9898

9999
def tcp_config(
100100
self,
@@ -106,7 +106,7 @@ def tcp_config(
106106
"path": [path] if path else None,
107107
"headers": {**http_headers, "Host": host} if http_headers else {"Host": host},
108108
}
109-
return self._remove_none_values(config)
109+
return self._normalize_and_remove_none_values(config)
110110

111111
def make_node(
112112
self,
@@ -206,7 +206,7 @@ def make_node(
206206
if mux_settings and (clash_mux := mux_settings.get("clash")):
207207
clash_mux = {
208208
"enabled": clash_mux.get("enable"),
209-
"protocol": clash_mux.get("protocol"),
209+
"protocol": clash_mux.get("protocol", "smux"),
210210
"max-connections": clash_mux.get("max_connections"),
211211
"min-streams": clash_mux.get("min_streams"),
212212
"max-streams": clash_mux.get("max_streams"),
@@ -221,7 +221,7 @@ def make_node(
221221
if clash_mux.get("brutal")
222222
else None,
223223
}
224-
node["smux"] = self._remove_none_values(clash_mux)
224+
node["smux"] = self._normalize_and_remove_none_values(clash_mux)
225225

226226
return node
227227

app/subscription/links.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import base64
22
import json
33
import urllib.parse as urlparse
4-
from enum import Enum
54
from random import choice
65
from typing import Union
76
from urllib.parse import quote
@@ -154,7 +153,6 @@ def _make_net_settings(
154153
elif net in ("splithttp", "xhttp"):
155154
payload["path"] = path
156155
payload["host"] = host
157-
mode = mode.value if isinstance(mode, Enum) else mode
158156
if protocol == "vmess":
159157
payload["type"] = mode
160158
else:
@@ -176,7 +174,7 @@ def _make_net_settings(
176174
else:
177175
extra["headers"]["User-Agent"] = choice(self.user_agent_list)
178176

179-
extra = self._remove_none_values(extra)
177+
extra = self._normalize_and_remove_none_values(extra)
180178

181179
if extra:
182180
payload["extra"] = (json.dumps(extra)).replace(" ", "")
@@ -312,6 +310,7 @@ def vmess(
312310
self._make_tls_settings(
313311
payload, tls, sni, fp, alpn, pbk, sid, spx, fs, ais, ech_config_list, mldsa65_verify
314312
)
313+
payload = self._normalize_and_remove_none_values(payload)
315314
return "vmess://" + base64.b64encode(json.dumps(payload, sort_keys=True).encode("utf-8")).decode()
316315

317316
def vless(
@@ -379,6 +378,7 @@ def vless(
379378
self._make_tls_settings(
380379
payload, tls, sni, fp, alpn, pbk, sid, spx, fs, ais, ech_config_list, mldsa65_verify
381380
)
381+
payload = self._normalize_and_remove_none_values(payload)
382382
return "vless://" + f"{id}@{address}:{port}?" + urlparse.urlencode(payload) + f"#{(urlparse.quote(remark))}"
383383

384384
def trojan(
@@ -445,6 +445,7 @@ def trojan(
445445
self._make_tls_settings(
446446
payload, tls, sni, fp, alpn, pbk, sid, spx, fs, ais, ech_config_list, mldsa65_verify
447447
)
448+
payload = self._normalize_and_remove_none_values(payload)
448449
return (
449450
"trojan://"
450451
+ f"{urlparse.quote(password, safe=':')}@{address}:{port}?"

app/subscription/singbox.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def tls_config(
6262
if fragment and (singbox_fragment := fragment.get("sing_box")):
6363
config.update(singbox_fragment)
6464

65-
return self._remove_none_values(config)
65+
return self._normalize_and_remove_none_values(config)
6666

6767
def http_config(
6868
self,
@@ -87,7 +87,7 @@ def http_config(
8787
if random_user_agent:
8888
config["headers"]["User-Agent"] = choice(self.user_agent_list)
8989

90-
return self._remove_none_values(config)
90+
return self._normalize_and_remove_none_values(config)
9191

9292
def ws_config(
9393
self,
@@ -108,7 +108,7 @@ def ws_config(
108108
if random_user_agent:
109109
config["headers"]["User-Agent"] = [choice(self.user_agent_list)]
110110

111-
return self._remove_none_values(config)
111+
return self._normalize_and_remove_none_values(config)
112112

113113
def grpc_config(self, path="", idle_timeout: str = "", ping_timeout: str = "", permit_without_stream: bool = False):
114114
config = {
@@ -117,7 +117,7 @@ def grpc_config(self, path="", idle_timeout: str = "", ping_timeout: str = "", p
117117
"ping_timeout": f"{ping_timeout}s" if ping_timeout else "15s",
118118
"permit_without_stream": permit_without_stream,
119119
}
120-
return self._remove_none_values(config)
120+
return self._normalize_and_remove_none_values(config)
121121

122122
def httpupgrade_config(self, host="", path="", random_user_agent: bool = False, http_headers: dict | None = None):
123123
config = {
@@ -127,7 +127,7 @@ def httpupgrade_config(self, host="", path="", random_user_agent: bool = False,
127127
}
128128
if random_user_agent:
129129
config["headers"]["User-Agent"] = choice(self.user_agent_list)
130-
return self._remove_none_values(config)
130+
return self._normalize_and_remove_none_values(config)
131131

132132
def transport_config(
133133
self,
@@ -277,7 +277,7 @@ def make_outbound(
277277
)
278278

279279
if mux_settings and (singbox_mux := mux_settings.get("sing_box")):
280-
singbox_mux = self._remove_none_values(singbox_mux)
280+
singbox_mux = self._normalize_and_remove_none_values(singbox_mux)
281281
config["multiplex"] = singbox_mux
282282

283283
return config

app/subscription/xray.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import json
2-
from enum import Enum
32
from random import choice
43
from typing import Union
54

@@ -39,7 +38,7 @@ def tls_config(self, sni=None, fp=None, alpn=None, ais=False, ech_config_list=No
3938
if alpn:
4039
tls_settings["alpn"] = alpn
4140

42-
return self._remove_none_values(tls_settings)
41+
return self._normalize_and_remove_none_values(tls_settings)
4342

4443
def reality_config(self, sni=None, fp=None, pbk=None, sid=None, spx=None, mldsa65_verify=None) -> dict:
4544
reality_settings = {
@@ -52,7 +51,7 @@ def reality_config(self, sni=None, fp=None, pbk=None, sid=None, spx=None, mldsa6
5251
"mldsa65Verify": mldsa65_verify,
5352
}
5453

55-
return self._remove_none_values(reality_settings)
54+
return self._normalize_and_remove_none_values(reality_settings)
5655

5756
def ws_config(
5857
self,
@@ -70,7 +69,7 @@ def ws_config(
7069
}
7170
if random_user_agent:
7271
ws_settings["headers"]["User-Agent"] = choice(self.user_agent_list)
73-
return self._remove_none_values(ws_settings)
72+
return self._normalize_and_remove_none_values(ws_settings)
7473

7574
def httpupgrade_config(
7675
self, path: str = "", host: str = "", random_user_agent: bool = False, http_headers=None
@@ -83,7 +82,7 @@ def httpupgrade_config(
8382
if random_user_agent:
8483
httpupgrade_settings["headers"]["User-Agent"] = choice(self.user_agent_list)
8584

86-
return self._remove_none_values(httpupgrade_settings)
85+
return self._normalize_and_remove_none_values(httpupgrade_settings)
8786

8887
def xhttp_config(
8988
self,
@@ -102,7 +101,6 @@ def xhttp_config(
102101
) -> dict:
103102
xhttp_settings = {}
104103

105-
mode = mode.value if isinstance(mode, Enum) else mode
106104
xhttp_settings["mode"] = mode
107105
if path:
108106
xhttp_settings["path"] = path
@@ -125,7 +123,7 @@ def xhttp_config(
125123
extra["headers"]["User-Agent"] = choice(self.user_agent_list)
126124

127125
xhttp_settings["extra"] = extra
128-
return self._remove_none_values(xhttp_settings)
126+
return self._normalize_and_remove_none_values(xhttp_settings)
129127

130128
def grpc_config(
131129
self,
@@ -152,7 +150,7 @@ def grpc_config(
152150
grpc_settings["user_agent"] = http_headers["user-agent"]
153151
if random_user_agent:
154152
grpc_settings["user_agent"] = choice(self.grpc_user_agent_data)
155-
return self._remove_none_values(grpc_settings)
153+
return self._normalize_and_remove_none_values(grpc_settings)
156154

157155
def tcp_config(
158156
self,
@@ -220,7 +218,7 @@ def tcp_config(
220218
if random_user_agent:
221219
tcp_settings["header"]["request"]["headers"]["User-Agent"] = [choice(self.user_agent_list)]
222220

223-
return self._remove_none_values(tcp_settings)
221+
return self._normalize_and_remove_none_values(tcp_settings)
224222

225223
def http_config(
226224
self, path: str = "", host: str = "", random_user_agent: bool = False, http_headers: dict | None = None
@@ -232,11 +230,11 @@ def http_config(
232230
}
233231
if random_user_agent:
234232
http_settings["headers"]["User-Agent"] = [choice(self.user_agent_list)]
235-
return self._remove_none_values(http_settings)
233+
return self._normalize_and_remove_none_values(http_settings)
236234

237235
def quic_config(self, path=None, host=None, header="none") -> dict:
238236
quicSettings = {"security": host, "header": {"type": header}, "key": path}
239-
return self._remove_none_values(quicSettings)
237+
return self._normalize_and_remove_none_values(quicSettings)
240238

241239
def kcp_config(
242240
self,
@@ -262,7 +260,7 @@ def kcp_config(
262260
"writeBufferSize": writeBufferSize if writeBufferSize else 2,
263261
"seed": seed,
264262
}
265-
return self._remove_none_values(kcp_settings)
263+
return self._normalize_and_remove_none_values(kcp_settings)
266264

267265
@staticmethod
268266
def stream_setting_config(
@@ -424,7 +422,7 @@ def make_dialer_outbound(
424422
"fragment": fragment.get("xray") if fragment else None,
425423
"noises": [{self.snake_to_camel(k): v for k, v in noise.items()} for noise in xray_noises] or None,
426424
}
427-
dialer_settings = self._remove_none_values(dialer_settings)
425+
dialer_settings = self._normalize_and_remove_none_values(dialer_settings)
428426

429427
if dialer_settings:
430428
return {"tag": dialer_tag, "protocol": "freedom", "settings": dialer_settings}
@@ -665,7 +663,7 @@ def add(self, remark: str, address: str, inbound: dict, settings: dict):
665663

666664
mux_settings: dict = inbound.get("mux_settings", {})
667665
if mux_settings and (xray_mux := mux_settings.get("xray")):
668-
xray_mux = self._remove_none_values(xray_mux)
666+
xray_mux = self._normalize_and_remove_none_values(xray_mux)
669667
outbound["mux"] = xray_mux
670668

671669
self.add_config(remarks=remark, outbounds=outbounds)

0 commit comments

Comments
 (0)