hiddifypanel 10.10.20__py3-none-any.whl → 10.11.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/hutils/__init__.py +3 -0
  4. hiddifypanel/hutils/crypto.py +29 -0
  5. hiddifypanel/hutils/encode.py +4 -0
  6. hiddifypanel/hutils/flask.py +4 -0
  7. hiddifypanel/hutils/github_issue.py +1 -1
  8. hiddifypanel/{models/utils.py → hutils/model.py} +14 -4
  9. hiddifypanel/hutils/network/net.py +46 -2
  10. hiddifypanel/hutils/proxy/__init__.py +4 -0
  11. hiddifypanel/hutils/proxy/clash.py +161 -0
  12. hiddifypanel/hutils/proxy/shared.py +414 -0
  13. hiddifypanel/hutils/proxy/singbox.py +338 -0
  14. hiddifypanel/hutils/proxy/xray.py +561 -0
  15. hiddifypanel/models/admin.py +16 -14
  16. hiddifypanel/models/base_account.py +4 -4
  17. hiddifypanel/models/config.py +1 -1
  18. hiddifypanel/models/proxy.py +17 -17
  19. hiddifypanel/models/user.py +15 -13
  20. hiddifypanel/panel/admin/AdminstratorAdmin.py +1 -1
  21. hiddifypanel/panel/admin/DomainAdmin.py +13 -27
  22. hiddifypanel/panel/admin/ProxyAdmin.py +3 -3
  23. hiddifypanel/panel/admin/SettingAdmin.py +22 -11
  24. hiddifypanel/panel/admin/UserAdmin.py +9 -7
  25. hiddifypanel/panel/cf_api.py +1 -2
  26. hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +5 -6
  27. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +1 -1
  28. hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +4 -7
  29. hiddifypanel/panel/common.py +5 -3
  30. hiddifypanel/panel/hiddify.py +0 -90
  31. hiddifypanel/panel/init_db.py +14 -9
  32. hiddifypanel/panel/user/__init__.py +0 -1
  33. hiddifypanel/panel/user/templates/all_configs copy.txt +2 -2
  34. hiddifypanel/panel/user/templates/all_configs.txt +2 -2
  35. hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +2 -1
  36. hiddifypanel/panel/user/templates/base_xray_config.json.j2 +125 -0
  37. hiddifypanel/panel/user/templates/clash_config copy.yml +1 -1
  38. hiddifypanel/panel/user/templates/clash_config.yml +4 -4
  39. hiddifypanel/panel/user/templates/clash_proxies.yml +1 -1
  40. hiddifypanel/panel/user/templates/home/all-configs.html +2 -2
  41. hiddifypanel/panel/user/templates/home/all-configs_old.html +1 -1
  42. hiddifypanel/panel/user/templates/home/ios copy.html +2 -2
  43. hiddifypanel/panel/user/user.py +50 -44
  44. hiddifypanel/templates/admin-layout.html +16 -24
  45. hiddifypanel/templates/fake.html +0 -276
  46. hiddifypanel/templates/flaskadmin-layout.html +2 -1
  47. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  48. hiddifypanel/translations/en/LC_MESSAGES/messages.po +16 -9
  49. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  50. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +12 -6
  51. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  52. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +9 -4
  53. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  54. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +12 -7
  55. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  56. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +9 -4
  57. hiddifypanel/translations.i18n/en.json +8 -7
  58. hiddifypanel/translations.i18n/fa.json +5 -4
  59. hiddifypanel/translations.i18n/pt.json +3 -2
  60. hiddifypanel/translations.i18n/ru.json +6 -5
  61. hiddifypanel/translations.i18n/zh.json +3 -2
  62. {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/METADATA +1 -1
  63. {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/RECORD +67 -61
  64. {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/WHEEL +1 -1
  65. hiddifypanel/panel/user/link_maker.py +0 -1089
  66. {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/LICENSE.md +0 -0
  67. {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/entry_points.txt +0 -0
  68. {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,414 @@
1
+ from flask import current_app, request, g
2
+ import glob
3
+ import random
4
+ import re
5
+ import json
6
+ from ipaddress import IPv4Address, IPv6Address
7
+ from hiddifypanel.cache import cache
8
+ from hiddifypanel.models import Proxy, ProxyProto, ProxyTransport, ProxyCDN, Domain, DomainType, ConfigEnum, hconfig, get_hconfigs
9
+ from hiddifypanel import hutils
10
+
11
+
12
+ def get_ssh_hostkeys(dojson=False) -> list[str] | str:
13
+ key_files = glob.glob(current_app.config['HIDDIFY_CONFIG_PATH'] + "/other/ssh/host_key/*_key.pub")
14
+ host_keys = []
15
+ for file_name in key_files:
16
+ with open(file_name, "r") as f:
17
+ host_key = f.read().strip()
18
+ host_key = host_key.split()
19
+ if len(host_key) > 2:
20
+ host_key = host_key[:2] # strip the hostname part
21
+ host_key = " ".join(host_key)
22
+ host_keys.append(host_key)
23
+ if dojson:
24
+ return json.dumps(host_keys)
25
+ return host_keys
26
+
27
+
28
+ def is_proxy_valid(proxy: Proxy, domain_db: Domain, port: int) -> dict | None:
29
+ name = proxy.name
30
+ l3 = proxy.l3
31
+ if not port:
32
+ return {'name': name, 'msg': "port not defined", 'type': 'error', 'proto': proxy.proto}
33
+ if "reality" not in l3 and domain_db.mode == DomainType.reality:
34
+ return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
35
+
36
+ if "reality" in l3 and domain_db.mode != DomainType.reality:
37
+ return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
38
+
39
+ if "reality" in l3 and domain_db.grpc and ProxyTransport.grpc != proxy.transport:
40
+ return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
41
+
42
+ if "reality" in l3 and (not domain_db.grpc) and ProxyTransport.grpc == proxy.transport:
43
+ return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
44
+
45
+ is_cdn = ProxyCDN.CDN == proxy.cdn or ProxyCDN.Fake == proxy.cdn
46
+ if is_cdn and domain_db.mode not in [DomainType.cdn, DomainType.auto_cdn_ip, DomainType.worker]:
47
+ # print("cdn proxy not in cdn domain", domain, name)
48
+ return {'name': name, 'msg': "cdn proxy not in cdn domain", 'type': 'debug', 'proto': proxy.proto}
49
+
50
+ if not is_cdn and domain_db.mode in [DomainType.cdn, DomainType.auto_cdn_ip, DomainType.worker]:
51
+ # print("not cdn proxy in cdn domain", domain, name, proxy.cdn)
52
+ return {'name': name, 'msg': "not cdn proxy in cdn domain", 'type': 'debug', 'proto': proxy.proto}
53
+
54
+ if proxy.cdn == ProxyCDN.relay and domain_db.mode not in [DomainType.relay]:
55
+ return {'name': name, 'msg': "relay proxy not in relay domain", 'type': 'debug', 'proto': proxy.proto}
56
+
57
+ if proxy.cdn != ProxyCDN.relay and domain_db.mode in [DomainType.relay]:
58
+ return {'name': name, 'msg': "relay proxy not in relay domain", 'type': 'debug', 'proto': proxy.proto}
59
+
60
+ if domain_db.mode == DomainType.worker and proxy.transport == ProxyTransport.grpc:
61
+ return {'name': name, 'msg': "worker does not support grpc", 'type': 'debug', 'proto': proxy.proto}
62
+
63
+ if domain_db.mode != DomainType.old_xtls_direct and "tls" in proxy.l3 and proxy.cdn == ProxyCDN.direct and proxy.transport in [ProxyTransport.tcp, ProxyTransport.XTLS]:
64
+ return {'name': name, 'msg': "only old_xtls_direct support this", 'type': 'debug', 'proto': proxy.proto}
65
+
66
+ if proxy.proto == "trojan" and not is_tls(l3):
67
+ return {'name': name, 'msg': "trojan but not tls", 'type': 'warning', 'proto': proxy.proto}
68
+
69
+ if l3 == "http" and ProxyTransport.XTLS in proxy.transport:
70
+ return {'name': name, 'msg': "http and xtls???", 'type': 'warning', 'proto': proxy.proto}
71
+
72
+ if l3 == "http" and proxy.proto in [ProxyProto.ss, ProxyProto.ssr]:
73
+ return {'name': name, 'msg': "http and ss or ssr???", 'type': 'warning', 'proto': proxy.proto}
74
+
75
+
76
+ def get_port(proxy: Proxy, hconfigs: dict, domain_db: Domain, ptls: int, phttp: int, pport: int | None) -> int:
77
+ l3 = proxy.l3
78
+ port = 443
79
+ if isinstance(phttp, str):
80
+ phttp = int(phttp) if phttp != "None" else None # type: ignore
81
+ if isinstance(ptls, str):
82
+ ptls = int(ptls) if ptls != "None" else None # type: ignore
83
+ if l3 == "kcp":
84
+ port = hconfigs[ConfigEnum.kcp_ports].split(",")[0]
85
+ elif proxy.proto == ProxyProto.wireguard:
86
+ port = hconfigs[ConfigEnum.wireguard_port]
87
+ elif proxy.proto == "tuic":
88
+ port = domain_db.internal_port_tuic
89
+ elif proxy.proto == "hysteria2":
90
+ port = domain_db.internal_port_hysteria2
91
+ elif l3 == 'ssh':
92
+ port = hconfigs[ConfigEnum.ssh_server_port]
93
+ elif is_tls(l3):
94
+ port = ptls
95
+ elif l3 == "http":
96
+ port = phttp
97
+ else:
98
+ port = int(pport) # type: ignore
99
+ return port
100
+
101
+
102
+ def is_tls(l3) -> bool:
103
+ return 'tls' in l3 or "reality" in l3
104
+
105
+
106
+ @cache.cache(ttl=300)
107
+ def get_proxies(child_id: int = 0, only_enabled=False) -> list['Proxy']:
108
+ proxies = Proxy.query.filter(Proxy.child_id == child_id).all()
109
+ proxies = [c for c in proxies if 'restls' not in c.transport]
110
+ # if not hconfig(ConfigEnum.tuic_enable, child_id):
111
+ # proxies = [c for c in proxies if c.proto != ProxyProto.tuic]
112
+ # if not hconfig(ConfigEnum.hysteria_enable, child_id):
113
+ # proxies = [c for c in proxies if c.proto != ProxyProto.hysteria2]
114
+ if not hconfig(ConfigEnum.shadowsocks2022_enable, child_id):
115
+ proxies = [c for c in proxies if 'shadowsocks' != c.transport]
116
+
117
+ if not hconfig(ConfigEnum.ssfaketls_enable, child_id):
118
+ proxies = [c for c in proxies if 'faketls' != c.transport]
119
+ if not hconfig(ConfigEnum.v2ray_enable, child_id):
120
+ proxies = [c for c in proxies if 'v2ray' != c.proto]
121
+ if not hconfig(ConfigEnum.shadowtls_enable, child_id):
122
+ proxies = [c for c in proxies if c.transport != 'shadowtls']
123
+ if not hconfig(ConfigEnum.ssr_enable, child_id):
124
+ proxies = [c for c in proxies if 'ssr' != c.proto]
125
+ if not hconfig(ConfigEnum.vmess_enable, child_id):
126
+ proxies = [c for c in proxies if 'vmess' not in c.proto]
127
+ if not hconfig(ConfigEnum.httpupgrade_enable, child_id):
128
+ proxies = [c for c in proxies if ProxyTransport.httpupgrade not in c.transport]
129
+ if not hconfig(ConfigEnum.ws_enable, child_id):
130
+ proxies = [c for c in proxies if ProxyTransport.WS not in c.transport]
131
+
132
+ if not hconfig(ConfigEnum.grpc_enable, child_id):
133
+ proxies = [c for c in proxies if ProxyTransport.grpc not in c.transport]
134
+ if not hconfig(ConfigEnum.kcp_enable, child_id):
135
+ proxies = [c for c in proxies if 'kcp' not in c.l3]
136
+
137
+ if not hconfig(ConfigEnum.http_proxy_enable, child_id):
138
+ proxies = [c for c in proxies if 'http' != c.l3]
139
+
140
+ if not Domain.query.filter(Domain.mode.in_([DomainType.cdn, DomainType.auto_cdn_ip])).first():
141
+ proxies = [c for c in proxies if c.cdn != "CDN"]
142
+
143
+ if not Domain.query.filter(Domain.mode.in_([DomainType.relay])).first():
144
+ proxies = [c for c in proxies if c.cdn != ProxyCDN.relay]
145
+
146
+ if not Domain.query.filter(Domain.mode.in_([DomainType.cdn, DomainType.auto_cdn_ip]), Domain.servernames != "", Domain.servernames != Domain.domain).first():
147
+ proxies = [c for c in proxies if 'Fake' not in c.cdn]
148
+ proxies = [c for c in proxies if not ('vless' == c.proto and ProxyTransport.tcp == c.transport and c.cdn == ProxyCDN.direct)]
149
+
150
+ if only_enabled:
151
+ proxies = [p for p in proxies if p.enable]
152
+ return proxies
153
+
154
+
155
+ def get_valid_proxies(domains: list[Domain]) -> list[dict]:
156
+ allp = []
157
+ allphttp = [p for p in request.args.get("phttp", "").split(',') if p]
158
+ allptls = [p for p in request.args.get("ptls", "").split(',') if p]
159
+ added_ip = {}
160
+ configsmap = {}
161
+ proxeismap = {}
162
+ for domain in domains:
163
+ if domain.child_id not in configsmap:
164
+ configsmap[domain.child_id] = get_hconfigs(domain.child_id)
165
+ proxeismap[domain.child_id] = get_proxies(domain.child_id, only_enabled=True)
166
+ hconfigs = configsmap[domain.child_id]
167
+
168
+ ip = hutils.network.get_domain_ip(domain.domain, version=4)
169
+ ip6 = hutils.network.get_domain_ip(domain.domain, version=6)
170
+ ips = [x for x in [ip, ip6] if x is not None]
171
+ for proxy in proxeismap[domain.child_id]:
172
+ noDomainProxies = False
173
+ if proxy.proto in [ProxyProto.ssh, ProxyProto.wireguard]:
174
+ noDomainProxies = True
175
+ if proxy.proto in [ProxyProto.ss] and proxy.transport not in [ProxyTransport.grpc, ProxyTransport.h2, ProxyTransport.WS, ProxyTransport.httpupgrade]:
176
+ noDomainProxies = True
177
+ options = []
178
+ key = f'{proxy.proto}{proxy.transport}{proxy.cdn}{proxy.l3}'
179
+ if key not in added_ip:
180
+ added_ip[key] = {}
181
+ if proxy.proto in [ProxyProto.ssh, ProxyProto.tuic, ProxyProto.hysteria2, ProxyProto.wireguard, ProxyProto.ss]:
182
+ if noDomainProxies and all([x in added_ip[key] for x in ips]):
183
+ continue
184
+
185
+ for x in ips:
186
+ added_ip[key][x] = 1
187
+
188
+ if proxy.proto in [ProxyProto.ssh, ProxyProto.wireguard, ProxyProto.ss]:
189
+ if domain.mode == 'fake':
190
+ continue
191
+ if proxy.proto in [ProxyProto.ssh]:
192
+ options = [{'pport': hconfigs[ConfigEnum.ssh_server_port]}]
193
+ elif proxy.proto in [ProxyProto.wireguard]:
194
+ options = [{'pport': hconfigs[ConfigEnum.wireguard_port]}]
195
+ elif proxy.transport in [ProxyTransport.shadowsocks]:
196
+ options = [{'pport': hconfigs[ConfigEnum.shadowsocks2022_port]}]
197
+ elif proxy.proto in [ProxyProto.ss]:
198
+ options = [{'pport': 443}]
199
+ elif proxy.proto == ProxyProto.tuic:
200
+ options = [{'pport': hconfigs[ConfigEnum.tuic_port]}]
201
+ elif proxy.proto == ProxyProto.hysteria2:
202
+ options = [{'pport': hconfigs[ConfigEnum.hysteria_port]}]
203
+ else:
204
+ protos = ['http', 'tls'] if hconfigs.get(ConfigEnum.http_proxy_enable) else ['tls']
205
+ for t in protos:
206
+ for port in hconfigs[ConfigEnum.http_ports if t == 'http' else ConfigEnum.tls_ports].split(','):
207
+ phttp = port if t == 'http' else None
208
+ ptls = port if t == 'tls' else None
209
+ if phttp and len(allphttp) and phttp not in allphttp:
210
+ continue
211
+ if ptls and len(allptls) and ptls not in allptls:
212
+ continue
213
+ options.append({'phttp': phttp, 'ptls': ptls})
214
+
215
+ for opt in options:
216
+ pinfo = make_proxy(hconfigs, proxy, domain, **opt)
217
+ if 'msg' not in pinfo:
218
+ allp.append(pinfo)
219
+ return allp
220
+
221
+
222
+ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=443, pport: int | None = None) -> dict:
223
+
224
+ l3 = proxy.l3
225
+ domain = domain_db.domain
226
+ child_id = domain_db.child_id
227
+ name = proxy.name
228
+ port = hutils.proxy.get_port(proxy, hconfigs, domain_db, ptls, phttp, pport)
229
+
230
+ if val_res := hutils.proxy.is_proxy_valid(proxy, domain_db, port):
231
+ # print(val_res)
232
+ return val_res
233
+
234
+ if 'reality' in proxy.l3:
235
+ alpn = "h2" if proxy.transport in ['h2', "grpc"] else 'http/1.1'
236
+ else:
237
+ alpn = "h2" if proxy.l3 in ['tls_h2'] or proxy.transport in ["grpc", 'h2'] else 'h2,http/1.1' if proxy.l3 == 'tls_h2_h1' else "http/1.1"
238
+ cdn_forced_host = domain_db.cdn_ip or (domain_db.domain if domain_db.mode != DomainType.reality else hutils.network.get_direct_host_or_ip(4))
239
+ is_cdn = ProxyCDN.CDN == proxy.cdn or ProxyCDN.Fake == proxy.cdn
240
+ base = {
241
+ 'name': name,
242
+ 'cdn': is_cdn,
243
+ 'mode': "CDN" if is_cdn else "direct",
244
+ 'l3': l3,
245
+ 'host': domain,
246
+ 'port': port,
247
+ 'server': cdn_forced_host,
248
+ 'sni': domain_db.servernames if is_cdn and domain_db.servernames else domain,
249
+ 'uuid': str(g.account.uuid),
250
+ 'proto': proxy.proto,
251
+ 'transport': proxy.transport,
252
+ 'proxy_path': hconfigs[ConfigEnum.proxy_path],
253
+ 'alpn': alpn,
254
+ 'extra_info': f'{domain_db.alias or domain}',
255
+ 'fingerprint': hconfigs[ConfigEnum.utls],
256
+ 'allow_insecure': domain_db.mode == DomainType.fake or "Fake" in proxy.cdn,
257
+ 'dbe': proxy,
258
+ 'dbdomain': domain_db
259
+ }
260
+ if proxy.proto in ['tuic', 'hysteria2']:
261
+ base['alpn'] = "h3"
262
+ return base
263
+ if proxy.proto in ['wireguard']:
264
+ base['wg_pub'] = g.account.wg_pub
265
+ base['wg_pk'] = g.account.wg_pk
266
+ base['wg_psk'] = g.account.wg_psk
267
+ base['wg_ipv4'] = hutils.network.add_number_to_ipv4(hconfigs[ConfigEnum.wireguard_ipv4], g.account.id)
268
+ base['wg_ipv6'] = hutils.network.add_number_to_ipv6(hconfigs[ConfigEnum.wireguard_ipv6], g.account.id)
269
+ base['wg_server_pub'] = hconfigs[ConfigEnum.wireguard_public_key]
270
+ base['wg_noise_trick'] = hconfigs[ConfigEnum.wireguard_noise_trick]
271
+ return base
272
+
273
+ if proxy.proto in [ProxyProto.vmess]:
274
+ base['cipher'] = "chacha20-poly1305"
275
+
276
+ if l3 in ['reality']:
277
+ base['reality_short_id'] = random.sample(hconfigs[ConfigEnum.reality_short_ids].split(','), 1)[0]
278
+ # base['flow']="xtls-rprx-vision"
279
+ base['reality_pbk'] = hconfigs[ConfigEnum.reality_public_key]
280
+ if (domain_db.servernames):
281
+ all_servernames = re.split('[ \t\r\n;,]+', domain_db.servernames)
282
+ base['sni'] = random.sample(all_servernames, 1)[0]
283
+ if hconfigs[ConfigEnum.core_type] == "singbox":
284
+ base['sni'] = all_servernames[0]
285
+ else:
286
+ base['sni'] = domain_db.domain
287
+
288
+ del base['host']
289
+ if base.get('fingerprint'):
290
+ base['fingerprint'] = hconfigs[ConfigEnum.utls]
291
+ # if not domain_db.cdn_ip:
292
+ # base['server']=hiddify.get_domain_ip(base['server'])
293
+
294
+ if "Fake" in proxy.cdn:
295
+ if not hconfigs[ConfigEnum.domain_fronting_domain]:
296
+ return {'name': name, 'msg': "no domain_fronting_domain", 'type': 'debug', 'proto': proxy.proto}
297
+ if l3 == "http" and not hconfigs[ConfigEnum.domain_fronting_http_enable]:
298
+ return {'name': name, 'msg': "no http in domain_fronting_domain", 'type': 'debug', 'proto': proxy.proto}
299
+ if l3 == "tls" and not hconfigs[ConfigEnum.domain_fronting_tls_enable]:
300
+ return {'name': name, 'msg': "no tls in domain_fronting_domain", 'type': 'debug', 'proto': proxy.proto}
301
+ base['server'] = hconfigs[ConfigEnum.domain_fronting_domain]
302
+ base['sni'] = hconfigs[ConfigEnum.domain_fronting_domain]
303
+ # base["host"]=domain
304
+ base['mode'] = 'Fake'
305
+ elif l3 == "http" and not hconfigs[ConfigEnum.http_proxy_enable]:
306
+ return {'name': name, 'msg': "http but http is disabled ", 'type': 'debug', 'proto': proxy.proto}
307
+
308
+ path = {
309
+ 'vless': f'{hconfigs[ConfigEnum.path_vless]}',
310
+ 'trojan': f'{hconfigs[ConfigEnum.path_trojan]}',
311
+ 'vmess': f'{hconfigs[ConfigEnum.path_vmess]}',
312
+ 'ss': f'{hconfigs[ConfigEnum.path_ss]}',
313
+ 'v2ray': f'{hconfigs[ConfigEnum.path_ss]}'
314
+ }
315
+
316
+ if base["proto"] in ['v2ray', 'ss', 'ssr']:
317
+ base['cipher'] = hconfigs[ConfigEnum.shadowsocks2022_method]
318
+ base['password'] = f'{hutils.encode.do_base_64(hconfigs[ConfigEnum.shared_secret].replace("-",""))}:{hutils.encode.do_base_64(g.account.uuid.replace("-",""))}'
319
+
320
+ if base['proto'] == 'trojan':
321
+ base['password'] = base['uuid']
322
+ if base["proto"] == "ssr":
323
+ base["ssr-obfs"] = "tls1.2_ticket_auth"
324
+ base["ssr-protocol"] = "auth_sha1_v4"
325
+ base["fakedomain"] = hconfigs[ConfigEnum.ssr_fakedomain]
326
+ base["mode"] = "FakeTLS"
327
+ return base
328
+ elif "faketls" in proxy.transport:
329
+ base['fakedomain'] = hconfigs[ConfigEnum.ssfaketls_fakedomain]
330
+ base['mode'] = 'FakeTLS'
331
+ return base
332
+ elif "shadowtls" in proxy.transport:
333
+ base['fakedomain'] = hconfigs[ConfigEnum.shadowtls_fakedomain]
334
+ # base['sni'] = hconfigs[ConfigEnum.shadowtls_fakedomain]
335
+ base['shared_secret'] = hconfigs[ConfigEnum.shared_secret]
336
+ base['mode'] = 'ShadowTLS'
337
+ return base
338
+ elif "shadowsocks" in proxy.transport:
339
+ return base
340
+ if ProxyTransport.XTLS in proxy.transport:
341
+ base['flow'] = 'xtls-rprx-vision'
342
+ return {**base, 'transport': 'tcp'}
343
+
344
+ if proxy.proto in {'vless', 'trojan', 'vmess'} and hconfigs.get(ConfigEnum.mux_enable):
345
+ if hconfigs[ConfigEnum.mux_enable]:
346
+ base['mux_enable'] = True
347
+ base['mux_protocol'] = hconfigs[ConfigEnum.mux_protocol]
348
+ base['mux_max_connections'] = hconfigs[ConfigEnum.mux_max_connections]
349
+ base['mux_min_streams'] = hconfigs[ConfigEnum.mux_min_streams]
350
+ base['mux_max_streams'] = hconfigs[ConfigEnum.mux_max_streams]
351
+ base['mux_padding_enable'] = hconfigs[ConfigEnum.mux_padding_enable]
352
+
353
+ # the hiddify next client doesn't support mux max streams
354
+ base['mux_max_streams'] = hconfigs[ConfigEnum.mux_max_streams]
355
+
356
+ if hconfigs[ConfigEnum.mux_brutal_enable]:
357
+ base['mux_brutal_enable'] = True
358
+ base['mux_brutal_up_mbps'] = hconfigs[ConfigEnum.mux_brutal_up_mbps]
359
+ base['mux_brutal_down_mbps'] = hconfigs[ConfigEnum.mux_brutal_down_mbps]
360
+
361
+ if is_cdn and proxy.proto in {'vless', 'trojan', "vmess"}:
362
+ if hconfigs[ConfigEnum.tls_fragment_enable]:
363
+ base["tls_fragment_enable"] = True
364
+ base["tls_fragment_size"] = hconfigs[ConfigEnum.tls_fragment_size]
365
+ base["tls_fragment_sleep"] = hconfigs[ConfigEnum.tls_fragment_sleep]
366
+
367
+ if hconfigs[ConfigEnum.tls_mixed_case]:
368
+ base["tls_mixed_case"] = hconfigs[ConfigEnum.tls_mixed_case]
369
+
370
+ if hconfigs[ConfigEnum.tls_padding_enable]:
371
+ base["tls_padding_enable"] = hconfigs[ConfigEnum.tls_padding_enable]
372
+ base["tls_padding_length"] = hconfigs[ConfigEnum.tls_padding_length]
373
+
374
+ if "tcp" in proxy.transport:
375
+ base['transport'] = 'tcp'
376
+ base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_tcp]}'
377
+ return base
378
+ if proxy.transport in ["ws", "WS"]:
379
+ base['transport'] = 'ws'
380
+ base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_ws]}'
381
+ base["host"] = domain
382
+ return base
383
+
384
+ if proxy.transport in [ProxyTransport.httpupgrade]:
385
+ base['transport'] = 'httpupgrade'
386
+ base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_httpupgrade]}'
387
+ base["host"] = domain
388
+ return base
389
+
390
+ if proxy.transport == "grpc":
391
+ base['transport'] = 'grpc'
392
+ # base['grpc_mode'] = "multi" if hconfigs[ConfigEnum.core_type]=='xray' else 'gun'
393
+ base['grpc_mode'] = 'gun'
394
+ base['grpc_service_name'] = f'{path[base["proto"]]}{hconfigs[ConfigEnum.path_grpc]}'
395
+ base['path'] = base['grpc_service_name']
396
+ return base
397
+
398
+ if "h1" in proxy.transport:
399
+ base['transport'] = 'tcp'
400
+ base['alpn'] = 'http/1.1'
401
+ return base
402
+ if ProxyProto.ssh == proxy.proto:
403
+ base['private_key'] = g.account.ed25519_private_key
404
+ base['host_key'] = hutils.proxy.get_ssh_hostkeys(False)
405
+ # base['ssh_port'] = hconfig(ConfigEnum.ssh_server_port)
406
+ return base
407
+ return {'name': name, 'msg': 'not valid', 'type': 'error', 'proto': proxy.proto}
408
+
409
+
410
+ class ProxyJsonEncoder(json.JSONEncoder):
411
+ def default(self, obj):
412
+ if isinstance(obj, IPv4Address) or isinstance(obj, IPv6Address):
413
+ return str(obj)
414
+ return super().default(obj)