hiddifypanel 10.85.0b21__py3-none-any.whl → 10.86.0b2__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.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +2 -2
- hiddifypanel/hutils/network/auto_ip_selector.py +19 -10
- hiddifypanel/hutils/network/net.py +25 -5
- hiddifypanel/hutils/proxy/clash.py +1 -1
- hiddifypanel/hutils/proxy/shared.py +118 -56
- hiddifypanel/hutils/proxy/xray.py +57 -40
- hiddifypanel/hutils/proxy/xrayjson.py +48 -28
- hiddifypanel/models/config.py +1 -1
- hiddifypanel/models/config_enum.py +4 -0
- hiddifypanel/models/domain.py +33 -8
- hiddifypanel/models/proxy.py +6 -2
- hiddifypanel/panel/admin/DomainAdmin.py +22 -25
- hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +13 -4
- hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +1 -1
- hiddifypanel/panel/custom_widgets.py +45 -0
- hiddifypanel/panel/init_db.py +102 -184
- hiddifypanel/panel/user/user.py +12 -12
- hiddifypanel/static/js/custom-rtl.js +1 -1
- hiddifypanel/templates/fake.html +11 -2
- hiddifypanel/templates/flaskadmin-layout.html +11 -9
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations/my/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations.i18n/en.json +19 -0
- hiddifypanel/translations.i18n/fa.json +19 -0
- hiddifypanel/translations.i18n/pt.json +19 -0
- hiddifypanel/translations.i18n/ru.json +19 -0
- hiddifypanel/translations.i18n/zh.json +19 -0
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b2.dist-info}/METADATA +1 -1
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b2.dist-info}/RECORD +43 -43
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b2.dist-info}/WHEEL +0 -0
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b2.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b2.dist-info}/licenses/LICENSE.md +0 -0
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b2.dist-info}/top_level.txt +0 -0
hiddifypanel/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
10.
|
1
|
+
10.86.0b2
|
hiddifypanel/VERSION.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# import importlib.metadata
|
2
2
|
from datetime import datetime
|
3
3
|
|
4
|
-
__version__ = '10.
|
5
|
-
__release_time__= datetime.strptime('2025-07-
|
4
|
+
__version__ = '10.86.0b2'
|
5
|
+
__release_time__= datetime.strptime('2025-07-06T19:45:39','%Y-%m-%dT%H:%M:%S')
|
6
6
|
is_released_version=True
|
@@ -38,10 +38,10 @@ apt.ircf.space APT
|
|
38
38
|
"""
|
39
39
|
|
40
40
|
try:
|
41
|
-
|
41
|
+
|
42
42
|
IPASN = maxminddb.open_database('GeoLite2-ASN.mmdb')
|
43
43
|
IPCOUNTRY = maxminddb.open_database('GeoLite2-Country.mmdb')
|
44
|
-
# __ipcity = maxminddb.open_database('GeoLite2-City.mmdb')
|
44
|
+
# __ipcity = maxminddb.open_database('GeoLite2-City.mmdb')
|
45
45
|
except BaseException as e:
|
46
46
|
logger.error("Error can not load maxminddb")
|
47
47
|
IPASN = {}
|
@@ -163,12 +163,23 @@ def __get_host_base_on_asn(ips: Union[str, List[str]], asn_short: str) -> str:
|
|
163
163
|
return selected
|
164
164
|
|
165
165
|
|
166
|
-
def get_clean_ip(ips: Union[str, List[str]], resolve: bool = False
|
167
|
-
if not ips:
|
168
|
-
ips = DEFAULT_IPs
|
169
|
-
|
170
|
-
ips = re.split('[ \t\r\n;,]+', ips.strip())
|
166
|
+
def get_clean_ip(ips: Union[str, List[str]], resolve: bool = False) -> str:
|
171
167
|
user_ip = get_real_user_ip()
|
168
|
+
default_asn = request.args.get("asn", '')
|
169
|
+
return get_clean_ip_user(user_ip, ips, default_asn)
|
170
|
+
|
171
|
+
|
172
|
+
split_pattern = re.compile(r'[ \t\r\n;,]+')
|
173
|
+
|
174
|
+
|
175
|
+
@cache.cache(300)
|
176
|
+
def get_clean_ip_user(user_ip, ipliststr: str, default_asn: str = '') -> tuple[str, str]:
|
177
|
+
ipliststr = ipliststr.strip()
|
178
|
+
if not ipliststr:
|
179
|
+
ipliststr = DEFAULT_IPs.strip()
|
180
|
+
|
181
|
+
ips = split_pattern.split(ipliststr)
|
182
|
+
|
172
183
|
asn_short = get_asn_short_name(user_ip)
|
173
184
|
country = get_country(user_ip)
|
174
185
|
# print("Real user ip",get_real_user_ip_debug(), user_ip,asn_short,country)
|
@@ -181,6 +192,4 @@ def get_clean_ip(ips: Union[str, List[str]], resolve: bool = False, default_asn:
|
|
181
192
|
else:
|
182
193
|
selected_server = random.sample(ips, 1)[0]
|
183
194
|
# print("selected_server",selected_server)
|
184
|
-
|
185
|
-
selected_server = hutils.network.get_domain_ip(selected_server) or selected_server
|
186
|
-
return str(selected_server)
|
195
|
+
return str(selected_server), asn_short
|
@@ -20,7 +20,7 @@ from hiddifypanel.models import *
|
|
20
20
|
from hiddifypanel.cache import cache
|
21
21
|
|
22
22
|
|
23
|
-
def
|
23
|
+
def get_domain_ip_old(domain: str, retry: int = 3, version: Literal[4, 6] | None = None) -> Union[ipaddress.IPv4Address, ipaddress.IPv6Address, None]:
|
24
24
|
res = None
|
25
25
|
if not version:
|
26
26
|
try:
|
@@ -41,14 +41,28 @@ def get_domain_ip(domain: str, retry: int = 3, version: Literal[4, 6] | None = N
|
|
41
41
|
except BaseException:
|
42
42
|
pass
|
43
43
|
|
44
|
-
if retry
|
45
|
-
return
|
46
|
-
if not res:
|
47
|
-
return get_domain_ip(domain, retry=retry - 1, version=version)
|
44
|
+
if retry > 0:
|
45
|
+
return get_domain_ip_old(domain, retry=retry - 1, version=version)
|
48
46
|
|
47
|
+
if not res:
|
48
|
+
return None
|
49
49
|
return ipaddress.ip_address(res)
|
50
50
|
|
51
51
|
|
52
|
+
def get_domain_ip(domain: str, retry: int = 3, version: Literal[4, 6] | None = None) -> Union[ipaddress.IPv4Address, ipaddress.IPv6Address, None]:
|
53
|
+
ips=get_domain_ips_cached(domain)
|
54
|
+
ips=[ip for ip in ips if version==None or (version==4 and isinstance(ip,ipaddress.IPv4Address)) or (version==6 and isinstance(ip,ipaddress.IPv6Address)) ]
|
55
|
+
if ips:
|
56
|
+
return random.sample(ips,1)[0]
|
57
|
+
return get_domain_ip_old(domain,0)
|
58
|
+
|
59
|
+
@cache.cache(300)
|
60
|
+
def get_domain_ips_cached(domain: str, retry: int = 3) -> Set[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
|
61
|
+
try:
|
62
|
+
return set(ipaddress.ip_address(domain))
|
63
|
+
except:
|
64
|
+
return get_domain_ips(domain,retry)
|
65
|
+
|
52
66
|
def get_domain_ips(domain: str, retry: int = 3) -> Set[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
|
53
67
|
res = set()
|
54
68
|
if retry < 0:
|
@@ -171,6 +185,12 @@ def get_ip(version: Literal[4, 6], retry: int = 5) -> ipaddress.IPv4Address | ip
|
|
171
185
|
return ip
|
172
186
|
|
173
187
|
|
188
|
+
def get_random_user_agent():
|
189
|
+
|
190
|
+
uas = requests.get('https://cdn.jsdelivr.net/gh/microlinkhq/top-user-agents@master/src/index.json').json()
|
191
|
+
if uas:
|
192
|
+
return random.sample(uas,1)[0]
|
193
|
+
return
|
174
194
|
def get_random_domains(count: int = 1, retry: int = 3) -> List[str]:
|
175
195
|
try:
|
176
196
|
irurl = "https://api.ooni.io/api/v1/measurements?probe_cc=IR&test_name=web_connectivity&anomaly=false&confirmed=false&failure=false&order_by=test_start_time&limit=1000"
|
@@ -155,7 +155,7 @@ def to_clash(proxy, meta_or_normal):
|
|
155
155
|
base["ws-opts"]["headers"] = {"Host": proxy["host"]}
|
156
156
|
|
157
157
|
if base["network"] == "tcp" and proxy['alpn'] != 'h2':
|
158
|
-
if proxy['transport'] !=
|
158
|
+
if proxy['transport'] != ProxyL3.reality:
|
159
159
|
base["network"] = "http"
|
160
160
|
|
161
161
|
if "path" in proxy:
|
@@ -11,11 +11,11 @@ from hiddifypanel.models import Proxy, ProxyProto, ProxyL3, ProxyTransport, Prox
|
|
11
11
|
from hiddifypanel import hutils
|
12
12
|
|
13
13
|
|
14
|
-
def get_ssh_hostkeys(hconfigs,dojson=False) -> list[str] | str:
|
14
|
+
def get_ssh_hostkeys(hconfigs, dojson=False) -> list[str] | str:
|
15
15
|
host_keys = [
|
16
16
|
# hconfigs[ConfigEnum.ssh_host_dsa_pub],
|
17
17
|
hconfigs[ConfigEnum.ssh_host_ed25519_pub],
|
18
|
-
hconfigs[ConfigEnum.ssh_host_ecdsa_pub],
|
18
|
+
hconfigs[ConfigEnum.ssh_host_ecdsa_pub],
|
19
19
|
hconfigs[ConfigEnum.ssh_host_rsa_pub],
|
20
20
|
]
|
21
21
|
if dojson:
|
@@ -28,13 +28,13 @@ def is_proxy_valid(proxy: Proxy, domain_db: Domain, port: int) -> dict | None:
|
|
28
28
|
l3 = proxy.l3
|
29
29
|
if not port:
|
30
30
|
return {'name': name, 'msg': "port not defined", 'type': 'error', 'proto': proxy.proto}
|
31
|
-
if "reality" not in l3 and domain_db.mode
|
31
|
+
if "reality" not in l3 and 'reality' in domain_db.mode:
|
32
32
|
return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
|
33
33
|
|
34
|
-
if "reality" in l3 and domain_db.mode
|
34
|
+
if "reality" in l3 and 'reality' not in domain_db.mode:
|
35
35
|
return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
|
36
36
|
|
37
|
-
if "reality" in l3 and domain_db.
|
37
|
+
if "reality" in l3 and domain_db.mode in [DomainType.special_reality_grpc] and ProxyTransport.grpc != proxy.transport:
|
38
38
|
return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
|
39
39
|
|
40
40
|
if "reality" in l3 and (not domain_db.grpc) and ProxyTransport.grpc == proxy.transport:
|
@@ -58,18 +58,22 @@ def is_proxy_valid(proxy: Proxy, domain_db: Domain, port: int) -> dict | None:
|
|
58
58
|
if domain_db.mode == DomainType.worker and proxy.transport == ProxyTransport.grpc:
|
59
59
|
return {'name': name, 'msg': "worker does not support grpc", 'type': 'debug', 'proto': proxy.proto}
|
60
60
|
|
61
|
-
if domain_db.mode
|
62
|
-
return {'name': name, 'msg': "
|
61
|
+
if domain_db.mode == DomainType.old_xtls_direct:
|
62
|
+
return {'name': name, 'msg': "unsupported", 'type': 'debug', 'proto': proxy.proto}
|
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}
|
63
65
|
|
64
66
|
if proxy.proto == "trojan" and not is_tls(l3):
|
65
67
|
return {'name': name, 'msg': "trojan but not tls", 'type': 'warning', 'proto': proxy.proto}
|
66
68
|
|
67
|
-
if l3 == "http" and ProxyTransport.XTLS in proxy.transport:
|
68
|
-
|
69
|
+
# if l3 == "http" and ProxyTransport.XTLS in proxy.transport:
|
70
|
+
# return {'name': name, 'msg': "http and xtls???", 'type': 'warning', 'proto': proxy.proto}
|
69
71
|
|
70
72
|
if l3 == "http" and proxy.proto in [ProxyProto.ss, ProxyProto.ssr]:
|
71
73
|
return {'name': name, 'msg': "http and ss or ssr???", 'type': 'warning', 'proto': proxy.proto}
|
72
74
|
|
75
|
+
return
|
76
|
+
|
73
77
|
|
74
78
|
def get_port(proxy: Proxy, hconfigs: dict, domain_db: Domain, ptls: int, phttp: int, pport: int | None) -> int:
|
75
79
|
l3 = proxy.l3
|
@@ -235,6 +239,70 @@ def get_valid_proxies(domains: list[Domain]) -> list[dict]:
|
|
235
239
|
return allp
|
236
240
|
|
237
241
|
|
242
|
+
def random_or_none(inp: list):
|
243
|
+
if not inp:
|
244
|
+
return
|
245
|
+
return random.sample(inp, 1)[0]
|
246
|
+
|
247
|
+
|
248
|
+
split_pattern = re.compile(r'[ \t\r\n;,]+')
|
249
|
+
|
250
|
+
|
251
|
+
def sni_host_server_extractor(domain_db: Domain, hconfigs):
|
252
|
+
|
253
|
+
server=sni=host = domain_db.domain.replace("*", hutils.random.get_random_string(5, 15))
|
254
|
+
is_cdn = domain_db.mode in [DomainType.cdn, DomainType.auto_cdn_ip]
|
255
|
+
if auto_ip:=domain_db.auto_cdn_ip():
|
256
|
+
server=auto_ip
|
257
|
+
elif 'special' in domain_db.mode.value or domain_db.mode in [DomainType.fake]:
|
258
|
+
server=hutils.network.get_direct_host_or_ip(4)
|
259
|
+
|
260
|
+
if hconfig(ConfigEnum.use_ip_in_config):
|
261
|
+
server = random_or_none(hutils.network.get_domain_ips_cached(server)) or server
|
262
|
+
|
263
|
+
|
264
|
+
allow_insecure=not domain_db.need_valid_ssl
|
265
|
+
if all_snis := split_pattern.split((domain_db.servernames or "").strip()):
|
266
|
+
sni = random_or_none(all_snis) or sni
|
267
|
+
if 'reality' in domain_db.mode:
|
268
|
+
allow_insecure=False
|
269
|
+
if hconfigs[ConfigEnum.core_type] == "singbox": #TODO
|
270
|
+
sni = all_snis[0]
|
271
|
+
|
272
|
+
else:
|
273
|
+
allow_insecure=True
|
274
|
+
|
275
|
+
base = {
|
276
|
+
'sni': sni,
|
277
|
+
'host': host,
|
278
|
+
'server': server,
|
279
|
+
'mode': domain_db.mode,
|
280
|
+
'allow_insecure': allow_insecure,
|
281
|
+
'cdn': is_cdn,
|
282
|
+
}
|
283
|
+
if 'reality' in domain_db.mode:
|
284
|
+
base['reality_short_id'] = random.sample(hconfigs[ConfigEnum.reality_short_ids].split(','), 1)[0]
|
285
|
+
# base['flow']="xtls-rprx-vision"
|
286
|
+
base['reality_pbk'] = hconfigs[ConfigEnum.reality_public_key]
|
287
|
+
# del base['host']
|
288
|
+
|
289
|
+
# if not domain_db.cdn_ip:
|
290
|
+
# base['server']=hiddify.get_domain_ip(base['server'])
|
291
|
+
|
292
|
+
return base
|
293
|
+
|
294
|
+
def put_default_header(parmas:dict):
|
295
|
+
|
296
|
+
if not isinstance(parmas.get('headers'),dict):
|
297
|
+
parmas['headers']={}
|
298
|
+
|
299
|
+
if not parmas['headers'].get('User-Agent'):
|
300
|
+
parmas['headers']['User-Agent']=hconfig(ConfigEnum.default_useragent_string)
|
301
|
+
if not parmas['headers'].get('Pragma'):
|
302
|
+
parmas['headers']['Pragma']="no-cache"
|
303
|
+
|
304
|
+
|
305
|
+
|
238
306
|
def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=443, pport: int | None = None) -> dict:
|
239
307
|
|
240
308
|
l3 = proxy.l3
|
@@ -254,17 +322,19 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
254
322
|
if proxy.l3 in [ProxyL3.h3_quic]:
|
255
323
|
alpn = "h3"
|
256
324
|
|
257
|
-
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))
|
258
|
-
is_cdn = ProxyCDN.CDN == proxy.cdn or ProxyCDN.Fake == proxy.cdn
|
325
|
+
# 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))
|
326
|
+
# is_cdn = ProxyCDN.CDN == proxy.cdn or ProxyCDN.Fake == proxy.cdn
|
327
|
+
domain_data=sni_host_server_extractor(domain_db, hconfigs)
|
259
328
|
base = {
|
329
|
+
**domain_data,
|
260
330
|
'name': name,
|
261
|
-
'cdn': is_cdn,
|
262
|
-
'mode': "CDN" if is_cdn else "direct",
|
331
|
+
# 'cdn': is_cdn,
|
332
|
+
# 'mode': "CDN" if is_cdn else "direct",
|
263
333
|
'l3': l3,
|
264
|
-
'host': domain,
|
334
|
+
# 'host': domain,
|
265
335
|
'port': port,
|
266
|
-
'server': cdn_forced_host,
|
267
|
-
'sni': domain_db.servernames if is_cdn and domain_db.servernames else domain,
|
336
|
+
# 'server': cdn_forced_host,
|
337
|
+
# 'sni': domain_db.servernames if is_cdn and domain_db.servernames else domain,
|
268
338
|
'uuid': str(g.account.uuid),
|
269
339
|
'proto': proxy.proto,
|
270
340
|
'transport': proxy.transport,
|
@@ -272,10 +342,29 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
272
342
|
'alpn': alpn,
|
273
343
|
'extra_info': f'{domain_db.alias or domain}',
|
274
344
|
'fingerprint': hconfigs[ConfigEnum.utls],
|
275
|
-
'allow_insecure': domain_db.mode == DomainType.fake or "Fake" in proxy.cdn,
|
345
|
+
# 'allow_insecure': domain_db.mode == DomainType.fake or "Fake" in proxy.cdn,
|
276
346
|
'dbe': proxy,
|
277
|
-
'dbdomain': domain_db
|
347
|
+
'dbdomain': domain_db,
|
348
|
+
'params': proxy.params or {},
|
278
349
|
}
|
350
|
+
put_default_header(base['params'])
|
351
|
+
|
352
|
+
|
353
|
+
if domain_db.download_domain:
|
354
|
+
base['download'] = sni_host_server_extractor(domain_db.download_domain,hconfigs)
|
355
|
+
else:
|
356
|
+
base['download']=domain_data
|
357
|
+
|
358
|
+
if 'download' not in base['params']:
|
359
|
+
base['params']['download']={}
|
360
|
+
base['download']['params']=base['params']['download']
|
361
|
+
put_default_header(base['download']['params'])
|
362
|
+
|
363
|
+
base['download']['alpn']=base['params']['download'].get('alpn',alpn)
|
364
|
+
|
365
|
+
|
366
|
+
|
367
|
+
|
279
368
|
if proxy.proto in ['tuic', 'hysteria2']:
|
280
369
|
base['alpn'] = "h3"
|
281
370
|
if proxy.proto == 'hysteria2':
|
@@ -297,36 +386,8 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
297
386
|
if proxy.proto in [ProxyProto.vmess]:
|
298
387
|
base['cipher'] = "auto" # "chacha20-poly1305"
|
299
388
|
|
300
|
-
|
301
|
-
|
302
|
-
# base['flow']="xtls-rprx-vision"
|
303
|
-
base['reality_pbk'] = hconfigs[ConfigEnum.reality_public_key]
|
304
|
-
if (domain_db.servernames):
|
305
|
-
all_servernames = re.split('[ \t\r\n;,]+', domain_db.servernames)
|
306
|
-
base['sni'] = random.sample(all_servernames, 1)[0]
|
307
|
-
if hconfigs[ConfigEnum.core_type] == "singbox":
|
308
|
-
base['sni'] = all_servernames[0]
|
309
|
-
else:
|
310
|
-
base['sni'] = domain_db.domain
|
311
|
-
|
312
|
-
del base['host']
|
313
|
-
if base.get('fingerprint'):
|
314
|
-
base['fingerprint'] = hconfigs[ConfigEnum.utls]
|
315
|
-
# if not domain_db.cdn_ip:
|
316
|
-
# base['server']=hiddify.get_domain_ip(base['server'])
|
317
|
-
|
318
|
-
if "Fake" in proxy.cdn:
|
319
|
-
if not hconfigs[ConfigEnum.domain_fronting_domain]:
|
320
|
-
return {'name': name, 'msg': "no domain_fronting_domain", 'type': 'debug', 'proto': proxy.proto}
|
321
|
-
if l3 == "http" and not hconfigs[ConfigEnum.domain_fronting_http_enable]:
|
322
|
-
return {'name': name, 'msg': "no http in domain_fronting_domain", 'type': 'debug', 'proto': proxy.proto}
|
323
|
-
if l3 == "tls" and not hconfigs[ConfigEnum.domain_fronting_tls_enable]:
|
324
|
-
return {'name': name, 'msg': "no tls in domain_fronting_domain", 'type': 'debug', 'proto': proxy.proto}
|
325
|
-
base['server'] = hconfigs[ConfigEnum.domain_fronting_domain]
|
326
|
-
base['sni'] = hconfigs[ConfigEnum.domain_fronting_domain]
|
327
|
-
# base["host"]=domain
|
328
|
-
base['mode'] = 'Fake'
|
329
|
-
elif l3 == "http" and not hconfigs[ConfigEnum.http_proxy_enable]:
|
389
|
+
|
390
|
+
if l3 == "http" and not hconfigs[ConfigEnum.http_proxy_enable]:
|
330
391
|
return {'name': name, 'msg': "http but http is disabled ", 'type': 'debug', 'proto': proxy.proto}
|
331
392
|
|
332
393
|
path = {
|
@@ -361,7 +422,7 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
361
422
|
return base
|
362
423
|
elif "shadowsocks" in proxy.transport:
|
363
424
|
return base
|
364
|
-
if proxy.l3 in [ProxyL3.reality] and
|
425
|
+
if proxy.l3 in [ProxyL3.reality] and proxy.transport in [ProxyTransport.tcp]:
|
365
426
|
base['flow'] = 'xtls-rprx-vision'
|
366
427
|
return {**base, 'transport': 'tcp'}
|
367
428
|
|
@@ -380,7 +441,7 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
380
441
|
base['mux_brutal_up_mbps'] = hconfigs.get(ConfigEnum.mux_brutal_up_mbps, 10)
|
381
442
|
base['mux_brutal_down_mbps'] = hconfigs.get(ConfigEnum.mux_brutal_down_mbps, 10)
|
382
443
|
|
383
|
-
if
|
444
|
+
if base['cdn'] and proxy.proto in {'vless', 'trojan', "vmess"}:
|
384
445
|
if hconfigs[ConfigEnum.tls_fragment_enable] and "tls" in base["l3"]:
|
385
446
|
base["tls_fragment_enable"] = True
|
386
447
|
base["tls_fragment_size"] = hconfigs[ConfigEnum.tls_fragment_size]
|
@@ -402,6 +463,7 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
402
463
|
base['transport'] = 'tcp'
|
403
464
|
base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_tcp]}'
|
404
465
|
return base
|
466
|
+
|
405
467
|
if proxy.transport in ["ws", "WS"]:
|
406
468
|
base['transport'] = 'ws'
|
407
469
|
base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_ws]}'
|
@@ -413,14 +475,14 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
413
475
|
base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_httpupgrade]}'
|
414
476
|
base["host"] = domain
|
415
477
|
return base
|
478
|
+
|
416
479
|
if proxy.transport in [ProxyTransport.xhttp]:
|
417
480
|
base['transport'] = 'xhttp'
|
418
481
|
base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_xhttp]}'
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
base["host"] = domain
|
482
|
+
base['xhttp_mode']=base['params'].get('mode',"auto")
|
483
|
+
if dl:=base.get('download'):
|
484
|
+
dl['path']=base['path']
|
485
|
+
dl['xhttp_mode']=dl['params'].get('mode',"auto")
|
424
486
|
return base
|
425
487
|
|
426
488
|
if proxy.transport == "grpc":
|
@@ -437,7 +499,7 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
437
499
|
return base
|
438
500
|
if ProxyProto.ssh == proxy.proto:
|
439
501
|
base['private_key'] = g.account.ed25519_private_key
|
440
|
-
base['host_keys'] = hutils.proxy.get_ssh_hostkeys(hconfigs,False)
|
502
|
+
base['host_keys'] = hutils.proxy.get_ssh_hostkeys(hconfigs, False)
|
441
503
|
# base['ssh_port'] = hconfig(ConfigEnum.ssh_server_port)
|
442
504
|
return base
|
443
505
|
return {'name': name, 'msg': 'not valid', 'type': 'error', 'proto': proxy.proto}
|
@@ -4,7 +4,7 @@ from flask import request, g
|
|
4
4
|
from hiddifypanel import hutils
|
5
5
|
from hiddifypanel.models import ProxyTransport, ProxyL3, ProxyProto, Domain, User, ConfigEnum, hconfig
|
6
6
|
from flask_babel import gettext as _
|
7
|
-
|
7
|
+
from urllib.parse import urlencode,quote
|
8
8
|
OUTBOUND_LEVEL = 8
|
9
9
|
|
10
10
|
|
@@ -43,16 +43,18 @@ def to_link(proxy: dict) -> str | dict:
|
|
43
43
|
"host": proxy.get("host", ""),
|
44
44
|
"alpn": proxy.get("alpn", "h2,http/1.1"),
|
45
45
|
"path": proxy["path"] if "path" in proxy else "",
|
46
|
-
"tls": "tls" if "tls" in proxy["l3"] else "",
|
46
|
+
"tls": "tls" if "tls" in proxy["l3"] or "quic" in proxy['l3'] else "",
|
47
47
|
"sni": proxy["sni"],
|
48
48
|
"fp": proxy["fingerprint"]
|
49
49
|
}
|
50
|
-
|
50
|
+
|
51
51
|
if 'reality' in proxy["l3"]:
|
52
52
|
vmess_data['tls'] = "reality"
|
53
53
|
vmess_data['pbk'] = proxy['reality_pbk']
|
54
54
|
vmess_data['sid'] = proxy['reality_short_id']
|
55
|
-
|
55
|
+
if proxy.get('transport') in {ProxyTransport.xhttp}:
|
56
|
+
vmess_data['core']='xray'
|
57
|
+
_add_xhttp_extra(vmess_data,proxy)
|
56
58
|
add_tls_tricks_to_dict(vmess_data, proxy)
|
57
59
|
add_mux_to_dict(vmess_data, proxy)
|
58
60
|
|
@@ -102,52 +104,72 @@ def to_link(proxy: dict) -> str | dict:
|
|
102
104
|
# f'wg://{proxy["server"]}:{proxy["port"]}/?pk={proxy["wg_pk"]}&local_address={proxy["wg_ipv4"]}/32&peer_pk={proxy["wg_server_pub"]}&pre_shared_key={proxy["wg_psk"]}&workers=4&mtu=1380&reserved=0,0,0&ifp={proxy["wg_noise_trick"]}#{name_link}'
|
103
105
|
return f'wg://{proxy["server"]}:{proxy["port"]}?publicKey={proxy["wg_pub"]}&privateKey={proxy["wg_pk"]}=&presharedKey={proxy["wg_psk"]}&ip=10.0.0.1&mtu=1380&keepalive=30&udp=1&reserved=0,0,0&ifp={proxy["wg_noise_trick"]}#{name_link}'
|
104
106
|
|
105
|
-
|
106
|
-
baseurl
|
107
|
-
|
107
|
+
|
108
|
+
baseurl = f'{proxy["proto"]}://{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}'
|
109
|
+
|
110
|
+
q = {
|
111
|
+
'hiddify': 1,
|
112
|
+
'sni': proxy['sni'],
|
113
|
+
'type': proxy['transport'],
|
114
|
+
'alpn': proxy['alpn']
|
115
|
+
}
|
108
116
|
|
109
117
|
# the ray2sing supports vless, vmess and trojan tls tricks and mux
|
110
118
|
# the vmess handled already
|
111
119
|
|
112
|
-
|
113
|
-
|
114
|
-
|
120
|
+
add_mux_to_dict(q,proxy)
|
121
|
+
add_tls_tricks_to_dict(q,proxy)
|
122
|
+
if "path" in proxy:
|
123
|
+
q['path']=proxy["path"]
|
124
|
+
if "host" in proxy :
|
125
|
+
q['host']=proxy["host"]
|
115
126
|
# infos+=f'&alpn={proxy["alpn"]}'
|
116
|
-
|
117
|
-
baseurl += f'&host={proxy["host"]}' if "host" in proxy else ""
|
127
|
+
|
118
128
|
if "grpc" == proxy["transport"]:
|
119
|
-
|
129
|
+
q['serviceName']=proxy["grpc_service_name"]
|
130
|
+
q['mode']=proxy["grpc_mode"]
|
120
131
|
# print(proxy['cdn'],proxy["transport"])
|
121
132
|
if request.args.get("fragment"):
|
122
|
-
|
133
|
+
q['fragment']= request.args.get("fragment") # type: ignore
|
123
134
|
if "ws" == proxy["transport"] and proxy['cdn'] and request.args.get("fragment_v1"):
|
124
|
-
|
135
|
+
q['fragment_v1']= request.args.get("fragment_v1") # type: ignore
|
125
136
|
if 'vless' == proxy['proto']:
|
126
|
-
|
137
|
+
q['encryption']='none'
|
138
|
+
|
127
139
|
if proxy.get('fingerprint', 'none') != 'none':
|
128
|
-
|
140
|
+
q['fp']=proxy['fingerprint']
|
129
141
|
if proxy.get('transport') in {ProxyTransport.xhttp}:
|
130
|
-
|
142
|
+
q['core']='xray'
|
143
|
+
_add_xhttp_extra(q,proxy)
|
131
144
|
if proxy['l3'] != 'quic':
|
132
145
|
if proxy.get('l3') != ProxyL3.reality and (proxy.get('transport') in {ProxyTransport.tcp, ProxyTransport.httpupgrade, ProxyTransport.xhttp}) and proxy['proto'] in [ProxyProto.vless, ProxyProto.trojan]:
|
133
|
-
|
146
|
+
q['headerType']='http'
|
134
147
|
else:
|
135
|
-
|
148
|
+
q['headerType']='none'
|
136
149
|
|
137
150
|
if proxy['mode'] == 'Fake' or proxy['allow_insecure']:
|
138
|
-
|
151
|
+
q['allowInsecure']='true'
|
152
|
+
q['insecure']='true'
|
139
153
|
if proxy.get('flow'):
|
140
|
-
|
141
|
-
|
142
|
-
infos = f'#{name_link}'
|
154
|
+
q['flow']=proxy["flow"]
|
143
155
|
|
156
|
+
|
144
157
|
if 'reality' in proxy["l3"]:
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
158
|
+
q['security']='reality'
|
159
|
+
q['pbk']=proxy['reality_pbk']
|
160
|
+
q['sid']=proxy['reality_short_id']
|
161
|
+
|
162
|
+
|
163
|
+
elif 'tls' in proxy['l3'] or "quic" in proxy['l3']:
|
164
|
+
q['security']='tls'
|
165
|
+
|
166
|
+
elif proxy['l3'] == 'http':
|
167
|
+
q['security']='none'
|
168
|
+
|
169
|
+
for k,v in q['params'].items():
|
170
|
+
if k not in q:
|
171
|
+
q[k]=v
|
172
|
+
return f"{baseurl}?{urlencode(q,quote_via=quote)}#{name_link}"
|
151
173
|
|
152
174
|
|
153
175
|
def make_v2ray_configs(domains: list[Domain], user: User, expire_days: int, ip_debug=None) -> str:
|
@@ -230,13 +252,8 @@ def add_mux_to_dict(d: dict, proxy):
|
|
230
252
|
d['muxdown'] = proxy["mux_brutal_down_mbps"]
|
231
253
|
|
232
254
|
|
233
|
-
def
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
def add_mux_to_link(proxy: dict) -> str:
|
240
|
-
out = {}
|
241
|
-
add_mux_to_dict(out, proxy)
|
242
|
-
return hutils.encode.convert_dict_to_url(out)
|
255
|
+
def _add_xhttp_extra(d:dict,proxy):
|
256
|
+
from .xrayjson import _add_xhttp_details
|
257
|
+
xhttp_dict={}
|
258
|
+
_add_xhttp_details(xhttp_dict,proxy)
|
259
|
+
d['extra']=json.dumps(xhttp_dict['xhttpSettings']['extra'],separators=(',', ':'))
|