hiddifypanel 9.0.0.dev92__py3-none-any.whl → 10.5.0.dev0__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 (152) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/auth.py +30 -9
  4. hiddifypanel/base.py +58 -50
  5. hiddifypanel/cache.py +43 -25
  6. hiddifypanel/database.py +9 -0
  7. hiddifypanel/drivers/abstract_driver.py +2 -0
  8. hiddifypanel/drivers/singbox_api.py +17 -15
  9. hiddifypanel/drivers/ssh_liberty_bridge_api.py +3 -1
  10. hiddifypanel/drivers/user_driver.py +12 -6
  11. hiddifypanel/drivers/wireguard_api.py +7 -2
  12. hiddifypanel/drivers/xray_api.py +14 -9
  13. hiddifypanel/hutils/__init__.py +4 -0
  14. hiddifypanel/hutils/convert.py +13 -2
  15. hiddifypanel/hutils/crypto.py +48 -0
  16. hiddifypanel/hutils/encode.py +4 -1
  17. hiddifypanel/hutils/flask.py +38 -5
  18. hiddifypanel/hutils/github_issue.py +1 -1
  19. hiddifypanel/hutils/importer/xui.py +5 -2
  20. hiddifypanel/{models/utils.py → hutils/model.py} +14 -4
  21. hiddifypanel/hutils/network/auto_ip_selector.py +2 -0
  22. hiddifypanel/hutils/network/net.py +46 -2
  23. hiddifypanel/hutils/node/__init__.py +3 -0
  24. hiddifypanel/hutils/node/api_client.py +76 -0
  25. hiddifypanel/hutils/node/child.py +147 -0
  26. hiddifypanel/hutils/node/parent.py +100 -0
  27. hiddifypanel/hutils/node/shared.py +65 -0
  28. hiddifypanel/hutils/proxy/__init__.py +5 -0
  29. hiddifypanel/hutils/proxy/clash.py +161 -0
  30. hiddifypanel/hutils/proxy/shared.py +434 -0
  31. hiddifypanel/hutils/proxy/singbox.py +339 -0
  32. hiddifypanel/hutils/proxy/xray.py +235 -0
  33. hiddifypanel/hutils/proxy/xrayjson.py +391 -0
  34. hiddifypanel/hutils/random.py +4 -0
  35. hiddifypanel/hutils/utils.py +4 -1
  36. hiddifypanel/models/__init__.py +2 -2
  37. hiddifypanel/models/admin.py +31 -17
  38. hiddifypanel/models/base_account.py +7 -7
  39. hiddifypanel/models/child.py +30 -16
  40. hiddifypanel/models/config.py +45 -16
  41. hiddifypanel/models/config_enum.py +68 -17
  42. hiddifypanel/models/domain.py +28 -20
  43. hiddifypanel/models/parent_domain.py +2 -2
  44. hiddifypanel/models/proxy.py +29 -20
  45. hiddifypanel/models/report.py +2 -3
  46. hiddifypanel/models/usage.py +2 -2
  47. hiddifypanel/models/user.py +33 -22
  48. hiddifypanel/panel/admin/Actions.py +13 -19
  49. hiddifypanel/panel/admin/AdminstratorAdmin.py +14 -3
  50. hiddifypanel/panel/admin/Dashboard.py +5 -10
  51. hiddifypanel/panel/admin/DomainAdmin.py +35 -48
  52. hiddifypanel/panel/admin/NodeAdmin.py +6 -2
  53. hiddifypanel/panel/admin/ProxyAdmin.py +6 -5
  54. hiddifypanel/panel/admin/QuickSetup.py +21 -20
  55. hiddifypanel/panel/admin/SettingAdmin.py +107 -62
  56. hiddifypanel/panel/admin/UserAdmin.py +22 -21
  57. hiddifypanel/panel/admin/templates/index.html +1 -1
  58. hiddifypanel/panel/admin/templates/model/user_list.html +44 -20
  59. hiddifypanel/panel/admin/templates/parent_dash.html +2 -4
  60. hiddifypanel/panel/admin/templates/result.html +2 -3
  61. hiddifypanel/panel/cf_api.py +1 -2
  62. hiddifypanel/panel/cli.py +16 -16
  63. hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +16 -12
  64. hiddifypanel/panel/commercial/__init__.py +7 -5
  65. hiddifypanel/panel/commercial/restapi/v1/__init__.py +1 -1
  66. hiddifypanel/panel/commercial/restapi/v1/tgbot.py +1 -1
  67. hiddifypanel/panel/commercial/restapi/v1/tgmsg.py +14 -10
  68. hiddifypanel/panel/commercial/restapi/v2/admin/__init__.py +0 -5
  69. hiddifypanel/panel/commercial/restapi/v2/admin/admin_info_api.py +2 -2
  70. hiddifypanel/panel/commercial/restapi/v2/admin/admin_log_api.py +4 -5
  71. hiddifypanel/panel/commercial/restapi/v2/admin/admin_user_api.py +8 -25
  72. hiddifypanel/panel/commercial/restapi/v2/admin/admin_users_api.py +4 -4
  73. hiddifypanel/panel/commercial/restapi/v2/admin/schema.py +157 -0
  74. hiddifypanel/panel/commercial/restapi/v2/admin/server_status_api.py +3 -3
  75. hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +9 -66
  76. hiddifypanel/panel/commercial/restapi/v2/admin/users_api.py +1 -1
  77. hiddifypanel/panel/commercial/restapi/v2/child/__init__.py +18 -0
  78. hiddifypanel/panel/commercial/restapi/v2/child/actions.py +63 -0
  79. hiddifypanel/panel/commercial/restapi/v2/child/register_parent_api.py +34 -0
  80. hiddifypanel/panel/commercial/restapi/v2/child/schema.py +7 -0
  81. hiddifypanel/panel/commercial/restapi/v2/child/sync_parent_api.py +21 -0
  82. hiddifypanel/panel/commercial/restapi/v2/panel/__init__.py +13 -0
  83. hiddifypanel/panel/commercial/restapi/v2/panel/info.py +18 -0
  84. hiddifypanel/panel/commercial/restapi/v2/panel/ping_pong.py +23 -0
  85. hiddifypanel/panel/commercial/restapi/v2/panel/schema.py +7 -0
  86. hiddifypanel/panel/commercial/restapi/v2/parent/__init__.py +16 -0
  87. hiddifypanel/panel/commercial/restapi/v2/parent/register_api.py +65 -0
  88. hiddifypanel/panel/commercial/restapi/v2/parent/schema.py +115 -0
  89. hiddifypanel/panel/commercial/restapi/v2/parent/status_api.py +26 -0
  90. hiddifypanel/panel/commercial/restapi/v2/parent/sync_api.py +53 -0
  91. hiddifypanel/panel/commercial/restapi/v2/parent/usage_api.py +57 -0
  92. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +17 -23
  93. hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +23 -26
  94. hiddifypanel/panel/commercial/telegrambot/admin.py +1 -2
  95. hiddifypanel/panel/common.py +25 -8
  96. hiddifypanel/panel/common_bp/login.py +2 -2
  97. hiddifypanel/panel/hiddify.py +22 -185
  98. hiddifypanel/panel/init_db.py +102 -55
  99. hiddifypanel/panel/usage.py +33 -18
  100. hiddifypanel/panel/user/__init__.py +0 -1
  101. hiddifypanel/panel/user/templates/all_configs copy.txt +2 -2
  102. hiddifypanel/panel/user/templates/all_configs.txt +2 -2
  103. hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +2 -1
  104. hiddifypanel/panel/user/templates/base_xray_config.json.j2 +125 -0
  105. hiddifypanel/panel/user/templates/clash_config copy.yml +1 -1
  106. hiddifypanel/panel/user/templates/clash_config.yml +4 -4
  107. hiddifypanel/panel/user/templates/clash_proxies.yml +1 -1
  108. hiddifypanel/panel/user/templates/home/all-configs.html +2 -2
  109. hiddifypanel/panel/user/templates/home/all-configs_old.html +1 -1
  110. hiddifypanel/panel/user/templates/home/ios copy.html +2 -2
  111. hiddifypanel/panel/user/templates/home/usage.html +1 -1
  112. hiddifypanel/panel/user/templates/new.html +2 -2
  113. hiddifypanel/panel/user/user.py +56 -50
  114. hiddifypanel/static/css/custom.css +31 -0
  115. hiddifypanel/static/images/favicon.ico +0 -0
  116. hiddifypanel/static/images/hiddify-old.png +0 -0
  117. hiddifypanel/static/images/hiddify.png +0 -0
  118. hiddifypanel/static/images/hiddify2.png +0 -0
  119. hiddifypanel/static/new/assets/{index-1b891a7c.js → index-ccb9873c.js} +56 -56
  120. hiddifypanel/static/new/assets/index-fa00de9a.css +1 -0
  121. hiddifypanel/static/new/i18n/en.json +6 -6
  122. hiddifypanel/static/new/i18n/fa.json +2 -2
  123. hiddifypanel/templates/admin-layout.html +30 -43
  124. hiddifypanel/templates/fake.html +0 -4
  125. hiddifypanel/templates/flaskadmin-layout.html +7 -3
  126. hiddifypanel/templates/master.html +11 -6
  127. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  128. hiddifypanel/translations/en/LC_MESSAGES/messages.po +2082 -1977
  129. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  130. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +2035 -1924
  131. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  132. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +1911 -1848
  133. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  134. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +2019 -1874
  135. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  136. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +1873 -1742
  137. hiddifypanel/translations.i18n/en.json +992 -933
  138. hiddifypanel/translations.i18n/fa.json +994 -935
  139. hiddifypanel/translations.i18n/pt.json +1031 -972
  140. hiddifypanel/translations.i18n/ru.json +994 -935
  141. hiddifypanel/translations.i18n/zh.json +971 -912
  142. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/METADATA +47 -47
  143. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/RECORD +147 -120
  144. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/WHEEL +1 -1
  145. hiddifypanel/panel/commercial/restapi/v2/DTO.py +0 -9
  146. hiddifypanel/panel/commercial/restapi/v2/hello/__init__.py +0 -16
  147. hiddifypanel/panel/commercial/restapi/v2/hello/hello.py +0 -32
  148. hiddifypanel/panel/user/link_maker.py +0 -1083
  149. hiddifypanel/static/new/assets/index-669b32c8.css +0 -1
  150. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/LICENSE.md +0 -0
  151. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/entry_points.txt +0 -0
  152. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/top_level.txt +0 -0
@@ -1,1083 +0,0 @@
1
- from flask import g, request, render_template
2
- from ipaddress import IPv4Address, IPv6Address
3
- from hiddifypanel import hutils
4
- from hiddifypanel.models import *
5
- import yaml
6
- import json
7
- from hiddifypanel.panel import hiddify
8
- import random
9
- import re
10
- import datetime
11
- from flask_babel import gettext as _
12
-
13
-
14
- def all_proxies(child_id=0):
15
- all_proxies = hiddify.get_available_proxies(child_id)
16
- all_proxies = [p for p in all_proxies if p.enable]
17
-
18
- # all_proxies = [p for p in all_proxies if p.proto == ProxyProto.ss]
19
- # all_cfg=Proxy.query.filter(Proxy.enable==True).all()
20
- # if not hconfig(ConfigEnum.domain_fronting_domain):
21
- # all_cfg=[c for c in all_cfg if 'Fake' not in c.cdn]
22
- # if not g.is_cdn:
23
- # all_cfg=[c for c in all_cfg if 'CDN' not in c.cdn]
24
- # if not hconfig(ConfigEnum.ssfaketls_enable):
25
- # all_cfg=[c for c in all_cfg if 'faketls' not in c.transport and 'v2ray' not in c.proto]
26
- # if not hconfig(ConfigEnum.vmess_enable):
27
- # all_cfg=[c for c in all_cfg if 'vmess' not in c.proto]
28
-
29
- return all_proxies
30
-
31
-
32
- def proxy_info(name, mode="tls"):
33
- return "error"
34
-
35
-
36
- def check_proxy_incorrect(proxy, domain_db, port):
37
- name = proxy.name
38
- l3 = proxy.l3
39
- if not port:
40
- return {'name': name, 'msg': "port not defined", 'type': 'error', 'proto': proxy.proto}
41
- if "reality" not in l3 and domain_db.mode == DomainType.reality:
42
- return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
43
-
44
- if "reality" in l3 and domain_db.mode != DomainType.reality:
45
- return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
46
-
47
- if "reality" in l3 and domain_db.grpc and ProxyTransport.grpc != proxy.transport:
48
- return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
49
-
50
- if "reality" in l3 and (not domain_db.grpc) and ProxyTransport.grpc == proxy.transport:
51
- return {'name': name, 'msg': "reality proxy not in reality domain", 'type': 'debug', 'proto': proxy.proto}
52
-
53
- is_cdn = ProxyCDN.CDN == proxy.cdn or ProxyCDN.Fake == proxy.cdn
54
- if is_cdn and domain_db.mode not in [DomainType.cdn, DomainType.auto_cdn_ip, DomainType.worker]:
55
- # print("cdn proxy not in cdn domain", domain, name)
56
- return {'name': name, 'msg': "cdn proxy not in cdn domain", 'type': 'debug', 'proto': proxy.proto}
57
-
58
- if not is_cdn and domain_db.mode in [DomainType.cdn, DomainType.auto_cdn_ip, DomainType.worker]:
59
- # print("not cdn proxy in cdn domain", domain, name, proxy.cdn)
60
- return {'name': name, 'msg': "not cdn proxy in cdn domain", 'type': 'debug', 'proto': proxy.proto}
61
-
62
- if proxy.cdn == ProxyCDN.relay and domain_db.mode not in [DomainType.relay]:
63
- return {'name': name, 'msg': "relay proxy not in relay domain", 'type': 'debug', 'proto': proxy.proto}
64
-
65
- if proxy.cdn != ProxyCDN.relay and domain_db.mode in [DomainType.relay]:
66
- return {'name': name, 'msg': "relay proxy not in relay domain", 'type': 'debug', 'proto': proxy.proto}
67
-
68
- if domain_db.mode == DomainType.worker and proxy.transport == ProxyTransport.grpc:
69
- return {'name': name, 'msg': "worker does not support grpc", 'type': 'debug', 'proto': proxy.proto}
70
-
71
- 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]:
72
- return {'name': name, 'msg': "only old_xtls_direct support this", 'type': 'debug', 'proto': proxy.proto}
73
-
74
- if proxy.proto == "trojan" and not is_tls(l3):
75
- return {'name': name, 'msg': "trojan but not tls", 'type': 'warning', 'proto': proxy.proto}
76
-
77
- if l3 == "http" and ProxyTransport.XTLS in proxy.transport:
78
- return {'name': name, 'msg': "http and xtls???", 'type': 'warning', 'proto': proxy.proto}
79
-
80
- if l3 == "http" and proxy.proto in [ProxyProto.ss, ProxyProto.ssr]:
81
- return {'name': name, 'msg': "http and ss or ssr???", 'type': 'warning', 'proto': proxy.proto}
82
-
83
-
84
- def is_tls(l3):
85
- return 'tls' in l3 or "reality" in l3
86
-
87
-
88
- def get_port(proxy, hconfigs, domain_db, ptls, phttp, pport):
89
- l3 = proxy.l3
90
- port = None
91
- if isinstance(phttp, str):
92
- phttp = int(phttp) if phttp != "None" else None
93
- if isinstance(ptls, str):
94
- ptls = int(ptls) if ptls != "None" else None
95
- if l3 == "kcp":
96
- port = hconfigs[ConfigEnum.kcp_ports].split(",")[0]
97
- elif proxy.proto == ProxyProto.wireguard:
98
- port = hconfigs[ConfigEnum.wireguard_port]
99
- elif proxy.proto == "tuic":
100
- port = domain_db.internal_port_tuic
101
- elif proxy.proto == "hysteria2":
102
- port = domain_db.internal_port_hysteria2
103
- elif l3 == 'ssh':
104
- port = hconfigs[ConfigEnum.ssh_server_port]
105
- elif is_tls(l3):
106
- port = ptls
107
- elif l3 == "http":
108
- port = phttp
109
- else:
110
- port = int(pport)
111
- return port
112
-
113
-
114
- def make_proxy(hconfigs, proxy: Proxy, domain_db: Domain, phttp=80, ptls=443, pport=None) -> dict:
115
- l3 = proxy.l3
116
- domain = domain_db.domain
117
- child_id = domain_db.child_id
118
- name = proxy.name
119
- port = get_port(proxy, hconfigs, domain_db, ptls, phttp, pport)
120
- # if not port:
121
- # return {'name': name, 'msg': "port not defined", 'type': 'error', 'proto': proxy.proto}
122
- # print("=========",proxy)
123
- if val_res := check_proxy_incorrect(proxy, domain_db, port):
124
- # print(val_res)
125
- return val_res
126
-
127
- if 'reality' in proxy.l3:
128
- alpn = "h2" if proxy.transport in ['h2', "grpc"] else 'http/1.1'
129
- else:
130
- 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"
131
- 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))
132
- is_cdn = ProxyCDN.CDN == proxy.cdn or ProxyCDN.Fake == proxy.cdn
133
- base = {
134
- 'name': name,
135
- 'cdn': is_cdn,
136
- 'mode': "CDN" if is_cdn else "direct",
137
- 'l3': l3,
138
- 'host': domain,
139
- 'port': port,
140
- 'server': cdn_forced_host,
141
- 'sni': domain_db.servernames if is_cdn and domain_db.servernames else domain,
142
- 'uuid': str(g.account.uuid),
143
- 'proto': proxy.proto,
144
- 'transport': proxy.transport,
145
- 'proxy_path': hconfigs[ConfigEnum.proxy_path],
146
- 'alpn': alpn,
147
- 'extra_info': f'{domain_db.alias or domain}',
148
- 'fingerprint': hconfigs[ConfigEnum.utls],
149
- 'allow_insecure': domain_db.mode == DomainType.fake or "Fake" in proxy.cdn,
150
- 'dbe': proxy,
151
- 'dbdomain': domain_db
152
- }
153
- if proxy.proto in ['tuic', 'hysteria2']:
154
- base['alpn'] = "h3"
155
- return base
156
- if proxy.proto in ['wireguard']:
157
- base['wg_pub'] = g.account.wg_pub
158
- base['wg_pk'] = g.account.wg_pk
159
- base['wg_psk'] = g.account.wg_psk
160
- base['wg_ipv4'] = hutils.network.add_number_to_ipv4(hconfigs[ConfigEnum.wireguard_ipv4], g.account.id)
161
- base['wg_ipv6'] = hutils.network.add_number_to_ipv6(hconfigs[ConfigEnum.wireguard_ipv6], g.account.id)
162
- base['wg_server_pub'] = hconfigs[ConfigEnum.wireguard_public_key]
163
- base['wg_noise_trick'] = hconfigs[ConfigEnum.wireguard_noise_trick]
164
- return base
165
-
166
- if proxy.proto in [ProxyProto.vmess]:
167
- base['cipher'] = "chacha20-poly1305"
168
-
169
- if l3 in ['reality']:
170
- base['reality_short_id'] = random.sample(hconfigs[ConfigEnum.reality_short_ids].split(','), 1)[0]
171
- # base['flow']="xtls-rprx-vision"
172
- base['reality_pbk'] = hconfigs[ConfigEnum.reality_public_key]
173
- if (domain_db.servernames):
174
- all_servernames = re.split('[ \t\r\n;,]+', domain_db.servernames)
175
- base['sni'] = random.sample(all_servernames, 1)[0]
176
- if hconfigs[ConfigEnum.core_type] == "singbox":
177
- base['sni'] = all_servernames[0]
178
- else:
179
- base['sni'] = domain_db.domain
180
-
181
- del base['host']
182
- if base.get('fingerprint', 'none') != 'none':
183
- base['fingerprint'] = hconfigs[ConfigEnum.utls]
184
- # if not domain_db.cdn_ip:
185
- # base['server']=hiddify.get_domain_ip(base['server'])
186
-
187
- if "Fake" in proxy.cdn:
188
- if not hconfigs[ConfigEnum.domain_fronting_domain]:
189
- return {'name': name, 'msg': "no domain_fronting_domain", 'type': 'debug', 'proto': proxy.proto}
190
- if l3 == "http" and not hconfigs[ConfigEnum.domain_fronting_http_enable]:
191
- return {'name': name, 'msg': "no http in domain_fronting_domain", 'type': 'debug', 'proto': proxy.proto}
192
- if l3 == "tls" and not hconfigs[ConfigEnum.domain_fronting_tls_enable]:
193
- return {'name': name, 'msg': "no tls in domain_fronting_domain", 'type': 'debug', 'proto': proxy.proto}
194
- base['server'] = hconfigs[ConfigEnum.domain_fronting_domain]
195
- base['sni'] = hconfigs[ConfigEnum.domain_fronting_domain]
196
- # base["host"]=domain
197
- base['mode'] = 'Fake'
198
-
199
- elif l3 == "http" and not hconfigs[ConfigEnum.http_proxy_enable]:
200
- return {'name': name, 'msg': "http but http is disabled ", 'type': 'debug', 'proto': proxy.proto}
201
-
202
- path = {
203
- 'vless': f'{hconfigs[ConfigEnum.path_vless]}',
204
- 'trojan': f'{hconfigs[ConfigEnum.path_trojan]}',
205
- 'vmess': f'{hconfigs[ConfigEnum.path_vmess]}',
206
- 'ss': f'{hconfigs[ConfigEnum.path_ss]}',
207
- 'v2ray': f'{hconfigs[ConfigEnum.path_ss]}'
208
- }
209
-
210
- if base["proto"] in ['v2ray', 'ss', 'ssr']:
211
- base['cipher'] = hconfigs[ConfigEnum.shadowsocks2022_method]
212
- base['password'] = f'{hutils.encode.do_base_64(hconfigs[ConfigEnum.shared_secret].replace("-",""))}:{hutils.encode.do_base_64(g.account.uuid.replace("-",""))}'
213
-
214
- if base["proto"] == "ssr":
215
- base["ssr-obfs"] = "tls1.2_ticket_auth"
216
- base["ssr-protocol"] = "auth_sha1_v4"
217
- base["fakedomain"] = hconfigs[ConfigEnum.ssr_fakedomain]
218
- base["mode"] = "FakeTLS"
219
- return base
220
- elif "faketls" in proxy.transport:
221
- base['fakedomain'] = hconfigs[ConfigEnum.ssfaketls_fakedomain]
222
- base['mode'] = 'FakeTLS'
223
- return base
224
- elif "shadowtls" in proxy.transport:
225
-
226
- base['fakedomain'] = hconfigs[ConfigEnum.shadowtls_fakedomain]
227
- # base['sni'] = hconfigs[ConfigEnum.shadowtls_fakedomain]
228
- base['shared_secret'] = hconfigs[ConfigEnum.shared_secret]
229
- base['mode'] = 'ShadowTLS'
230
- return base
231
- elif "shadowsocks" in proxy.transport:
232
- return base
233
- if ProxyTransport.XTLS in proxy.transport:
234
- base['flow'] = 'xtls-rprx-vision'
235
- return {**base, 'transport': 'tcp'}
236
-
237
- if proxy.proto in {'vless', 'trojan', 'vmess'} and hconfigs.get(ConfigEnum.mux_enable):
238
- if hconfigs[ConfigEnum.mux_enable]:
239
- base['mux_enable'] = True
240
- base['mux_protocol'] = hconfigs[ConfigEnum.mux_protocol]
241
- base['mux_max_connections'] = hconfigs[ConfigEnum.mux_max_connections]
242
- base['mux_min_streams'] = hconfigs[ConfigEnum.mux_min_streams]
243
- base['mux_max_streams'] = hconfigs[ConfigEnum.mux_max_streams]
244
- base['mux_padding_enable'] = hconfigs[ConfigEnum.mux_padding_enable]
245
-
246
- # the hiddify next client doesn't support mux max streams
247
- base['mux_max_streams'] = hconfigs[ConfigEnum.mux_max_streams]
248
-
249
- if hconfigs[ConfigEnum.mux_brutal_enable]:
250
- base['mux_brutal_up_mbps'] = hconfigs[ConfigEnum.mux_brutal_up_mbps]
251
- base['mux_brutal_down_mbps'] = hconfigs[ConfigEnum.mux_brutal_down_mbps]
252
-
253
- if is_cdn and proxy.proto in {'vless', 'trojan', "vmess"}:
254
- if hconfigs[ConfigEnum.tls_fragment_enable]:
255
- base["tls_fragment_enable"] = True
256
- base["tls_fragment_size"] = hconfigs[ConfigEnum.tls_fragment_size]
257
- base["tls_fragment_sleep"] = hconfigs[ConfigEnum.tls_fragment_sleep]
258
-
259
- if hconfigs[ConfigEnum.tls_mixed_case]:
260
- base["tls_mixed_case"] = hconfigs[ConfigEnum.tls_mixed_case]
261
-
262
- if hconfigs[ConfigEnum.tls_padding_enable]:
263
- base["tls_padding_enable"] = hconfigs[ConfigEnum.tls_padding_enable]
264
- base["tls_padding_length"] = hconfigs[ConfigEnum.tls_padding_length]
265
-
266
- if "tcp" in proxy.transport:
267
- base['transport'] = 'tcp'
268
- base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_tcp]}'
269
- return base
270
- if proxy.transport in ["ws", "WS"]:
271
- base['transport'] = 'ws'
272
- base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_ws]}'
273
- base["host"] = domain
274
- return base
275
-
276
- if proxy.transport in [ProxyTransport.httpupgrade]:
277
- base['transport'] = 'httpupgrade'
278
- base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_httpupgrade]}'
279
- base["host"] = domain
280
- return base
281
-
282
- if proxy.transport == "grpc":
283
- base['transport'] = 'grpc'
284
- # base['grpc_mode'] = "multi" if hconfigs[ConfigEnum.core_type]=='xray' else 'gun'
285
- base['grpc_mode'] = 'gun'
286
- base['grpc_service_name'] = f'{path[base["proto"]]}{hconfigs[ConfigEnum.path_grpc]}'
287
- base['path'] = base['grpc_service_name']
288
- return base
289
-
290
- if "h1" in proxy.transport:
291
- base['transport'] = 'tcp'
292
- base['alpn'] = 'http/1.1'
293
- return base
294
- if ProxyProto.ssh == proxy.proto:
295
- base['private_key'] = g.account.ed25519_private_key
296
- base['host_key'] = hiddify.get_hostkeys(False)
297
- # base['ssh_port'] = hconfig(ConfigEnum.ssh_server_port)
298
- return base
299
- return {'name': name, 'msg': 'not valid', 'type': 'error', 'proto': proxy.proto}
300
-
301
-
302
- def to_link(proxy):
303
- if 'error' in proxy:
304
- return proxy
305
- orig_name_link = (proxy['extra_info'] + " " + proxy["name"]).strip()
306
- name_link = hutils.encode.url_encode(orig_name_link)
307
- if proxy['proto'] == 'vmess':
308
- # print(proxy)
309
- vmess_type = None
310
- if proxy["transport"] == 'tcp':
311
- vmess_type = 'http'
312
- if 'grpc_mode' in proxy:
313
- vmess_type = proxy['grpc_mode']
314
- vmess_data = {"v": "2",
315
- "ps": orig_name_link,
316
- "add": proxy['server'],
317
- "port": proxy['port'],
318
- "id": proxy["uuid"],
319
- "aid": 0,
320
- "scy": proxy['cipher'],
321
- "net": proxy["transport"],
322
- "type": vmess_type or "none",
323
- "host": proxy.get("host", ""),
324
- "alpn": proxy.get("alpn", "h2,http/1.1"),
325
- "path": proxy["path"] if "path" in proxy else "",
326
- "tls": "tls" if "tls" in proxy["l3"] else "",
327
- "sni": proxy["sni"],
328
- "fp": proxy["fingerprint"]
329
- }
330
- if 'reality' in proxy["l3"]:
331
- vmess_data['tls'] = "reality"
332
- vmess_data['pbk'] = proxy['reality_pbk']
333
- vmess_data['sid'] = proxy['reality_short_id']
334
-
335
- add_tls_tricks_to_dict(vmess_data, proxy)
336
- add_mux_to_dict(vmess_data, proxy)
337
-
338
- return "vmess://" + hutils.encode.do_base_64(f'{json.dumps(vmess_data,cls=CustomEncoder)}')
339
- if proxy['proto'] == 'ssh':
340
- strenssh = hutils.encode.do_base_64(f'{proxy["uuid"]}:0:{proxy["private_key"]}::@{proxy["server"]}:{proxy["port"]}')
341
- baseurl = f'ssh://{strenssh}#{name_link}'
342
- hk = hutils.encode.do_base_64(",".join(proxy["host_key"]))
343
- pk = hutils.encode.do_base_64(proxy["private_key"])
344
- baseurl += f'\nssh://{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}/?pk={pk}&hk={hk}#{name_link}'
345
-
346
- return baseurl
347
- if proxy['proto'] == "ssr":
348
- baseurl = f'ssr://{proxy["cipher"]}:{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}'
349
- return baseurl
350
- if proxy['proto'] in ['ss', 'v2ray']:
351
- baseurl = f'ss://{proxy["cipher"]}:{proxy["password"]}@{proxy["server"]}:{proxy["port"]}'
352
- if proxy['mode'] == 'faketls':
353
- return f'{baseurl}?plugin=obfs-local%3Bobfs%3Dtls%3Bobfs-host%3D{proxy["fakedomain"]}%3Budp-over-tcp=true#{name_link}'
354
- # if proxy['mode'] == 'shadowtls':
355
- # return f'{baseurl}?plugin=shadow-tls%3Bpassword%3D{proxy["proxy_path"]}%3Bhost%3D{proxy["fakedomain"]}%3Budp-over-tcp=true#{name_link}'
356
- if proxy['proto'] == 'v2ray':
357
- return f'{baseurl}?plugin=v2ray-plugin%3Bmode%3Dwebsocket%3Bpath%3D{proxy["path"]}%3Bhost%3D{proxy["host"]}%3Btls%3Budp-over-tcp=true#{name_link}'
358
- if proxy['transport'] == 'shadowsocks':
359
- return baseurl
360
- if proxy['proto'] == 'tuic':
361
- baseurl = f'tuic://{proxy["uuid"]}:{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}?congestion_control=cubic&udp_relay_mode=native&sni={proxy["sni"]}&alpn=h3'
362
- if proxy['mode'] == 'Fake' or proxy['allow_insecure']:
363
- baseurl += "&allow_insecure=1"
364
- return f"{baseurl}#{name_link}"
365
- if proxy['proto'] == 'hysteria2':
366
- baseurl = f'hysteria2://{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}?hiddify=1&obfs=salamander&obfs-password={hconfig(ConfigEnum.proxy_path)}&sni={proxy["sni"]}'
367
- if proxy['mode'] == 'Fake' or proxy['allow_insecure']:
368
- baseurl += "&insecure=1"
369
- return f"{baseurl}#{name_link}"
370
- if proxy['proto'] == ProxyProto.wireguard:
371
- if g.user_agent.get('is_streisand'):
372
- return f'wireguard://{proxy["server"]}:{proxy["port"]}?private_key={proxy["wg_pk"]}&peer_public_key={proxy["wg_server_pub"]}&pre_shared_key={proxy["wg_psk"]}&reserved=0,0,0#{name_link}'
373
- else:
374
- # hiddify_format =
375
- # 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}'
376
- 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}'
377
-
378
- baseurl = f'{proxy["proto"]}://{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}?hiddify=1'
379
- baseurl += f'&sni={proxy["sni"]}&type={proxy["transport"]}'
380
- baseurl += f"&alpn={proxy['alpn']}"
381
-
382
- # the ray2sing supports vless, vmess and trojan tls tricks and mux
383
- # the vmess handled already
384
-
385
- baseurl += add_mux_to_link(proxy)
386
- baseurl += add_tls_tricks_to_link(proxy)
387
-
388
- # infos+=f'&alpn={proxy["alpn"]}'
389
- baseurl += f'&path={proxy["path"]}' if "path" in proxy else ""
390
- baseurl += f'&host={proxy["host"]}' if "host" in proxy else ""
391
- if "grpc" == proxy["transport"]:
392
- baseurl += f'&serviceName={proxy["grpc_service_name"]}&mode={proxy["grpc_mode"]}'
393
- # print(proxy['cdn'],proxy["transport"])
394
- if request.args.get("fragment"):
395
- baseurl += f'&fragment=' + request.args.get("fragment") # type: ignore
396
- if "ws" == proxy["transport"] and proxy['cdn'] and request.args.get("fragment_v1"):
397
- baseurl += f'&fragment_v1=' + request.args.get("fragment_v1") # type: ignore
398
- if 'vless' == proxy['proto']:
399
- baseurl += "&encryption=none"
400
- if proxy.get('fingerprint', 'none') != 'none':
401
- baseurl += "&fp=" + proxy['fingerprint']
402
- if proxy['l3'] != 'quic':
403
- if g.user_agent.get('is_streisand') and proxy.get('l3') == ProxyL3.http and proxy.get('transport') == ProxyTransport.tcp and proxy['proto'] in [
404
- ProxyProto.vless, ProxyProto.vmess]:
405
- baseurl += '&headerType=http'
406
- else:
407
- baseurl += '&headerType=None' # if not quic
408
- if proxy['mode'] == 'Fake' or proxy['allow_insecure']:
409
- baseurl += "&allowInsecure=true"
410
- if proxy.get('flow'):
411
- baseurl += f'&flow={proxy["flow"]}'
412
-
413
- infos = f'#{name_link}'
414
-
415
- if 'reality' in proxy["l3"]:
416
- return f"{baseurl}&security=reality&pbk={proxy['reality_pbk']}&sid={proxy['reality_short_id']}{infos}"
417
- if 'tls' in proxy['l3']:
418
- return f'{baseurl}&security=tls{infos}'
419
- if proxy['l3'] == 'http':
420
- return f'{baseurl}&security=none{infos}'
421
- return proxy
422
-
423
- # region tls tricks & mux
424
- # notice: combining the functions into two function would make code less readable and difficult to maintain
425
-
426
-
427
- def add_tls_tricks_to_link(proxy) -> str:
428
- out = {}
429
- add_tls_tricks_to_dict(out, proxy)
430
- return convert_dict_to_url(out)
431
-
432
-
433
- def add_tls_tricks_to_dict(d: dict, proxy):
434
- if proxy.get('tls_fragment_enable'):
435
- if g.user_agent.get('is_shadowrocket'):
436
- d['fragment'] = f'1,{proxy["tls_fragment_size"]},{proxy["tls_fragment_sleep"]}'
437
- else:
438
- d['fragment'] = f'{proxy["tls_fragment_size"]},{proxy["tls_fragment_sleep"]},tlshello'
439
-
440
- if proxy.get("tls_mixed_case"):
441
- d['mc'] = 1
442
- if proxy.get("tls_padding_enable"):
443
- d['padsize'] = proxy["tls_padding_length"]
444
-
445
-
446
- def convert_dict_to_url(dict):
447
- return '&' + '&'.join([f'{k}={v}' for k, v in dict.items()]) if len(dict) else ''
448
-
449
-
450
- def add_mux_to_link(proxy) -> str:
451
- out = {}
452
- add_mux_to_dict(out, proxy)
453
- return convert_dict_to_url(out)
454
-
455
-
456
- def add_mux_to_dict(d: dict, proxy):
457
- if proxy.get('mux_enable'):
458
- # d['mux'] = proxy["mux_protocol"]
459
- # mux is equals to concurrency in clients
460
- d['mux'] = proxy["mux_max_streams"]
461
- d['mux_max'] = proxy["mux_max_connections"]
462
- d['mux_pad'] = proxy["mux_padding_enable"]
463
- # doesn't exist
464
- # d['mux_min'] = proxy["mux_min_connections"]
465
-
466
- if proxy.get('mux_brutal_enable'):
467
- d['mux_up'] = proxy["mux_brutal_up_mbps"]
468
- d['mux_down'] = proxy["mux_brutal_down_mbps"]
469
-
470
- # endregion
471
-
472
-
473
- # def to_clash_yml(proxy):
474
- # return yaml.dump(to_clash(proxy,'normal'))
475
-
476
-
477
- def to_clash(proxy, meta_or_normal):
478
-
479
- name = proxy['name']
480
- if proxy['l3'] == "kcp":
481
- return {'name': name, 'msg': "clash does not support kcp", 'type': 'debug'}
482
- if proxy['proto'] == "ssh":
483
- return {'name': name, 'msg': "clash does not support ssh", 'type': 'debug'}
484
- if meta_or_normal == "normal":
485
- if proxy['proto'] in ["vless", 'tuic', 'hysteria2']:
486
- return {'name': name, 'msg': f"{proxy['proto']} not supported in clash", 'type': 'debug'}
487
- if proxy.get('flow'):
488
- return {'name': name, 'msg': "xtls not supported in clash", 'type': 'debug'}
489
- if proxy['transport'] == "shadowtls":
490
- return {'name': name, 'msg': "shadowtls not supported in clash", 'type': 'debug'}
491
- if proxy['l3'] == ProxyL3.tls_h2 and proxy['proto'] in [ProxyProto.vmess, ProxyProto.vless] and proxy['dbe'].cdn == ProxyCDN.direct:
492
- return {'name': name, 'msg': "bug tls_h2 vmess and vless in clash meta", 'type': 'warning'}
493
- base = {}
494
- # vmess ws
495
- base["name"] = f"""{proxy['extra_info']} {proxy["name"]} § {proxy['port']} {proxy["dbdomain"].id}"""
496
- base["type"] = str(proxy["proto"])
497
- base["server"] = proxy["server"]
498
- base["port"] = proxy["port"]
499
- base['alpn'] = proxy['alpn'].split(',')
500
- if proxy["proto"] == "ssr":
501
- base["cipher"] = proxy["cipher"]
502
- base["password"] = proxy["uuid"]
503
- base["udp"] = True
504
- base["obfs"] = proxy["ssr-obfs"]
505
- base["protocol"] = proxy["ssr-protocol"]
506
- base["obfs-param"] = proxy["fakedomain"]
507
- return base
508
- elif proxy["proto"] == "tuic":
509
- base["uuid"] = proxy["uuid"]
510
- base["password"] = proxy["uuid"]
511
- base["disable-sni"] = proxy['allow_insecure']
512
- base["reduce-rtt"] = True
513
- base["request-timeout"] = 8000
514
- base["udp-relay-mode"] = 'native'
515
- base["congestion-controller"] = 'cubic'
516
- base['sni'] = proxy['sni']
517
- return base
518
- elif proxy["proto"] in ["ss", "v2ray"]:
519
- base["cipher"] = proxy["cipher"]
520
- base["password"] = proxy["password"]
521
- base["udp_over_tcp"] = True
522
- if proxy["transport"] == "faketls":
523
- base["plugin"] = "obfs"
524
- base["plugin-opts"] = {
525
- "mode": 'tls',
526
- "host": proxy["fakedomain"]
527
- }
528
- elif proxy["transport"] == "shadowtls":
529
- base["plugin"] = "shadow-tls"
530
- base["plugin-opts"] = {
531
- "host": proxy["fakedomain"],
532
- "password": proxy["proxy_path"],
533
- "version": 3 # support 1/2/3
534
-
535
- }
536
-
537
- elif proxy["proto"] == "v2ray":
538
- base["plugin"] = "v2ray-plugin"
539
- base["type"] = "ss"
540
- base["plugin-opts"] = {
541
- "mode": "websocket",
542
- "tls": "tls" in proxy["l3"],
543
- "skip-cert-verify": proxy["mode"] == "Fake" or proxy['allow_insecure'],
544
- "host": proxy['sni'],
545
- "path": proxy["path"]
546
- }
547
- return base
548
- elif proxy["proto"] == "trojan":
549
- base["password"] = proxy["uuid"]
550
- base["sni"] = proxy["sni"]
551
-
552
- else:
553
- base["uuid"] = proxy["uuid"]
554
- base["servername"] = proxy["sni"]
555
- base["tls"] = "tls" in proxy["l3"] or "reality" in proxy["l3"]
556
- if meta_or_normal == "meta":
557
- base['client-fingerprint'] = proxy['fingerprint']
558
- if proxy.get('flow'):
559
- base["flow"] = proxy['flow']
560
- # base["flow-show"] = True
561
-
562
- if proxy["proto"] == "vmess":
563
- base["alterId"] = 0
564
- base["cipher"] = proxy["cipher"]
565
- base["udp"] = True
566
-
567
- base["skip-cert-verify"] = proxy["mode"] == "Fake"
568
-
569
- base["network"] = proxy["transport"]
570
-
571
- if base["network"] == "ws":
572
- base["ws-opts"] = {
573
- "path": proxy["path"]
574
- }
575
- if "host" in proxy:
576
- base["ws-opts"]["headers"] = {"Host": proxy["host"]}
577
-
578
- if base["network"] == "tcp" and proxy['alpn'] != 'h2':
579
- if proxy['transport'] != ProxyTransport.XTLS:
580
- base["network"] = "http"
581
-
582
- if "path" in proxy:
583
- base["http-opts"] = {
584
- "path": [proxy["path"]]
585
- }
586
- if 'host' in proxy:
587
- base["http-opts"]["host"] = [proxy["host"]]
588
- if base["network"] == "tcp" and proxy['alpn'] == 'h2':
589
- base["network"] = "h2"
590
-
591
- if "path" in proxy:
592
- base["h2-opts"] = {
593
- "path": proxy["path"]
594
- }
595
- if 'host' in proxy:
596
- base["h2-opts"]["host"] = [proxy["host"]]
597
- if base["network"] == "grpc":
598
- base["grpc-opts"] = {
599
- "grpc-service-name": proxy["grpc_service_name"]
600
- }
601
- if proxy['l3'] == ProxyL3.reality:
602
- base["reality-opts"] = {
603
- "public-key": proxy['reality_pbk'],
604
- "short-id": proxy['reality_short_id'],
605
- }
606
- if proxy["transport"] != 'grpc':
607
- base["network"] = 'tcp'
608
-
609
- return base
610
-
611
-
612
- def get_clash_config_names(meta_or_normal, domains):
613
- allp = []
614
- for pinfo in get_all_validated_proxies(domains):
615
- clash = to_clash(pinfo, meta_or_normal)
616
- if 'msg' not in clash:
617
- allp.append(clash['name'])
618
-
619
- return yaml.dump(allp, sort_keys=False)
620
-
621
-
622
- def get_all_clash_configs(meta_or_normal, domains):
623
- allp = []
624
- for pinfo in get_all_validated_proxies(domains):
625
- clash = to_clash(pinfo, meta_or_normal)
626
- if 'msg' not in clash:
627
- allp.append(clash)
628
-
629
- return yaml.dump({"proxies": allp}, sort_keys=False)
630
-
631
-
632
- def to_singbox(proxy):
633
- name = proxy['name']
634
-
635
- all_base = []
636
- if proxy['l3'] == "kcp":
637
- return {'name': name, 'msg': "clash does not support kcp", 'type': 'debug'}
638
-
639
- base = {}
640
- all_base.append(base)
641
- # vmess ws
642
- base["tag"] = f"""{proxy['extra_info']} {proxy["name"]} § {proxy['port']} {proxy["dbdomain"].id}"""
643
- base["type"] = str(proxy["proto"])
644
- base["server"] = proxy["server"]
645
- base["server_port"] = int(proxy["port"])
646
- # base['alpn'] = proxy['alpn'].split(',')
647
- if proxy["proto"] == "ssr":
648
- add_singbox_ssr(base, proxy)
649
- return all_base
650
- if proxy["proto"] == ProxyProto.wireguard:
651
- add_singbox_wireguard(base, proxy)
652
- return all_base
653
-
654
- if proxy["proto"] in ["ss", "v2ray"]:
655
- add_singbox_shadowsocks_base(all_base, proxy)
656
- return all_base
657
- if proxy["proto"] == "ssh":
658
- add_singbox_ssh(all_base, proxy)
659
- return all_base
660
-
661
- if proxy["proto"] == "trojan":
662
- base["password"] = proxy["uuid"]
663
-
664
- if proxy['proto'] in ['vmess', 'vless']:
665
- base["uuid"] = proxy["uuid"]
666
-
667
- if proxy['proto'] in ['vmess', 'vless', 'trojan']:
668
- add_singbox_multiplex(base)
669
-
670
- add_singbox_tls(base, proxy)
671
-
672
- if g.user_agent.get('is_hiddify'):
673
- add_singbox_tls_tricks(base, proxy)
674
-
675
- if proxy.get('flow'):
676
- base["flow"] = proxy['flow']
677
- # base["flow-show"] = True
678
-
679
- if proxy["proto"] == "vmess":
680
- base["alter_id"] = 0
681
- base["security"] = proxy["cipher"]
682
-
683
- # base["udp"] = True
684
- if proxy["proto"] in ["vmess", "vless"]:
685
- base["packet_encoding"] = "xudp" # udp packet encoding
686
-
687
- if proxy["proto"] == "tuic":
688
- add_tuic(base, proxy)
689
- elif proxy["proto"] == "hysteria2":
690
- add_hysteria(base, proxy)
691
- else:
692
- add_singbox_transport(base, proxy)
693
-
694
- return all_base
695
-
696
-
697
- def add_tuic(base, proxy):
698
- base['congestion_control'] = "cubic"
699
- base['udp_relay_mode'] = 'native'
700
- base['zero_rtt_handshake'] = True
701
- base['heartbeat'] = "10s"
702
- base['password'] = proxy['uuid']
703
- base['uuid'] = proxy['uuid']
704
-
705
-
706
- def add_hysteria(base, proxy):
707
- base['up_mbps'] = int(hconfig(ConfigEnum.hysteria_up_mbps))
708
- base['down_mbps'] = int(hconfig(ConfigEnum.hysteria_down_mbps))
709
- # TODO: check the obfs should be empty or not exists at all
710
- if hconfig(ConfigEnum.hysteria_obfs_enable):
711
- base['obfs'] = {
712
- "type": "salamander",
713
- "password": hconfig(ConfigEnum.proxy_path)
714
- }
715
- base['password'] = proxy['uuid']
716
-
717
-
718
- def add_singbox_multiplex(base):
719
- if not hconfig(ConfigEnum.mux_enable):
720
- return
721
- base['multiplex'] = {
722
- "enabled": True,
723
- "protocol": hconfig(ConfigEnum.mux_protocol),
724
- "padding": hconfig(ConfigEnum.mux_padding_enable)
725
- }
726
- # Conflicts: max_streams with max_connections and min_streams
727
- mux_max_streams = int(hconfig(ConfigEnum.mux_max_streams))
728
- if mux_max_streams and mux_max_streams != 0:
729
- base['multiplex']['max_streams'] = mux_max_streams
730
- else:
731
- base['multiplex']['max_connections'] = int(hconfig(ConfigEnum.mux_max_connections))
732
- base['multiplex']['min_streams'] = int(hconfig(ConfigEnum.mux_min_streams))
733
-
734
- add_singbox_tcp_brutal(base)
735
-
736
-
737
- def add_singbox_tcp_brutal(base):
738
- if 'multiplex' in base:
739
- base['multiplex']['brutal'] = {
740
- "enabled": hconfig(ConfigEnum.mux_brutal_enable),
741
- "up_mbps": int(hconfig(ConfigEnum.mux_brutal_up_mbps)),
742
- "down_mbps": int(hconfig(ConfigEnum.mux_brutal_down_mbps))
743
- }
744
-
745
-
746
- def add_singbox_udp_over_tcp(base):
747
- base['udp_over_tcp'] = {
748
- "enabled": True,
749
- "version": 2
750
- }
751
-
752
-
753
- def add_singbox_tls(base, proxy):
754
- if not ("tls" in proxy["l3"] or "reality" in proxy["l3"]):
755
- return
756
- base["tls"] = {
757
- "enabled": True,
758
- "server_name": proxy["sni"]
759
- }
760
- if proxy['proto'] not in ["tuic", "hysteria2"]:
761
- base["tls"]["utls"] = {
762
- "enabled": True,
763
- "fingerprint": proxy.get('fingerprint', 'none')
764
- }
765
-
766
- if "reality" in proxy["l3"]:
767
- base["tls"]["reality"] = {
768
- "enabled": True,
769
- "public_key": proxy['reality_pbk'],
770
- "short_id": proxy['reality_short_id']
771
- }
772
- base["tls"]['insecure'] = proxy['allow_insecure'] or (proxy["mode"] == "Fake")
773
- base["tls"]["alpn"] = proxy['alpn'].split(',')
774
- # base['ech'] = {
775
- # "enabled": True,
776
- # }
777
-
778
-
779
- def add_singbox_tls_tricks(base, proxy):
780
- if proxy.get('tls_fragment_enable'):
781
- base['tls_fragment'] = {
782
- # 'enable': True,
783
- 'size': proxy["tls_fragment_size"],
784
- 'sleep': proxy["tls_fragment_sleep"]
785
- }
786
-
787
- if 'tls' in base:
788
- if proxy.get("tls_padding_enable") or proxy.get("tls_mixed_case"):
789
- base['tls']['tls_tricks'] = {}
790
- if proxy.get("tls_padding_enable"):
791
- base['tls']['tls_tricks']['padding_size'] = proxy["tls_padding_length"]
792
-
793
- if proxy.get("tls_mixed_case"):
794
- base['tls']['tls_tricks']['mixedcase_sni'] = True
795
-
796
-
797
- def add_singbox_transport(base, proxy):
798
- if proxy['l3'] == 'reality' and proxy['transport'] not in ["grpc"]:
799
- return
800
- base["transport"] = {}
801
- if proxy['transport'] in ["ws", "WS"]:
802
- base["transport"] = {
803
- "type": "ws",
804
- "path": proxy["path"],
805
- "early_data_header_name": "Sec-WebSocket-Protocol"
806
- }
807
- if "host" in proxy:
808
- base["transport"]["headers"] = {"Host": proxy["host"]}
809
-
810
- if proxy['transport'] in [ProxyTransport.httpupgrade]:
811
- base["transport"] = {
812
- "type": "httpupgrade",
813
- "path": proxy["path"]
814
- }
815
- if "host" in proxy:
816
- base["transport"]["headers"] = {"Host": proxy["host"]}
817
-
818
- if proxy["transport"] in ["tcp", "h2"]:
819
- base["transport"] = {
820
- "type": "http",
821
- "path": proxy.get("path", ""),
822
- # "method": "",
823
- # "headers": {},
824
- "idle_timeout": "15s",
825
- "ping_timeout": "15s"
826
- }
827
-
828
- if 'host' in proxy:
829
- base["transport"]["host"] = [proxy["host"]]
830
-
831
- if proxy["transport"] == "grpc":
832
- base["transport"] = {
833
- "type": "grpc",
834
- "service_name": proxy["grpc_service_name"],
835
- "idle_timeout": "115s",
836
- "ping_timeout": "15s",
837
- # "permit_without_stream": false
838
- }
839
-
840
-
841
- def add_singbox_ssr(base, proxy):
842
-
843
- base["method"] = proxy["cipher"]
844
- base["password"] = proxy["uuid"]
845
- # base["udp"] = True
846
- base["obfs"] = proxy["ssr-obfs"]
847
- base["protocol"] = proxy["ssr-protocol"]
848
- base["protocol-param"] = proxy["fakedomain"]
849
-
850
-
851
- def add_singbox_wireguard(base, proxy):
852
-
853
- base["local_address"] = f'{proxy["wg_ipv4"]}/32'
854
- base["private_key"] = proxy["wg_pk"]
855
- base["peer_public_key"] = proxy["wg_server_pub"]
856
-
857
- base["pre_shared_key"] = proxy["wg_psk"]
858
-
859
- base["mtu"] = 1380
860
- if g.user_agent.get('is_hiddify') and hiddify.is_hiddify_next_version(0, 15, 0):
861
- base["fake_packets"] = proxy["wg_noise_trick"]
862
-
863
-
864
- def add_singbox_shadowsocks_base(all_base, proxy):
865
- base = all_base[0]
866
- base["type"] = "shadowsocks"
867
- base["method"] = proxy["cipher"]
868
- base["password"] = proxy["password"]
869
- add_singbox_udp_over_tcp(base)
870
- add_singbox_multiplex(base)
871
- if proxy["transport"] == "faketls":
872
- base["plugin"] = "obfs-local"
873
- base["plugin_opts"] = f'obfs=tls;obfs-host={proxy["fakedomain"]}'
874
- if proxy['proto'] == 'v2ray':
875
- base["plugin"] = "v2ray-plugin"
876
- # "skip-cert-verify": proxy["mode"] == "Fake" or proxy['allow_insecure'],
877
- base["plugin_opts"] = f'mode=websocket;path={proxy["path"]};host={proxy["host"]};tls'
878
-
879
- if proxy["transport"] == "shadowtls":
880
- base['detour'] = base['tag'] + "_shadowtls-out §hide§"
881
-
882
- shadowtls_base = {
883
- "type": "shadowtls",
884
- "tag": base['detour'],
885
- "server": base['server'],
886
- "server_port": base['server_port'],
887
- "version": 3,
888
- "password": proxy["shared_secret"],
889
- "tls": {
890
- "enabled": True,
891
- "server_name": proxy["fakedomain"],
892
- "utls": {
893
- "enabled": True,
894
- "fingerprint": proxy.get('fingerprint', 'none')
895
- },
896
- # "alpn": proxy['alpn'].split(',')
897
- }
898
- }
899
- # add_singbox_utls(shadowtls_base)
900
- del base['server']
901
- del base['server_port']
902
- all_base.append(shadowtls_base)
903
-
904
-
905
- def add_singbox_ssh(all_base, proxy):
906
- base = all_base[0]
907
- # base["client_version"]= "{{ssh_client_version}}"
908
- base["user"] = proxy['uuid']
909
- base["private_key"] = proxy['private_key'] # .replace('\n', '\\n')
910
-
911
- base["host_key"] = proxy.get('host_key', [])
912
-
913
- socks_front = {
914
- "type": "socks",
915
- "tag": base['tag'] + "+UDP",
916
- "server": "127.0.0.1",
917
- "server_port": 2000,
918
- "version": "5",
919
- "udp_over_tcp": True,
920
- "network": "tcp",
921
- "detour": base['tag']
922
- }
923
- all_base.append(socks_front)
924
-
925
-
926
- def make_full_singbox_config(domains, **kwargs):
927
- ua = hutils.flask.get_user_agent()
928
- base_config = json.loads(render_template('base_singbox_config.json.j2'))
929
- allphttp = [p for p in request.args.get("phttp", "").split(',') if p]
930
- allptls = [p for p in request.args.get("ptls", "").split(',') if p]
931
-
932
- allp = []
933
- for d in domains:
934
- base_config['dns']['rules'][0]['domain'].append(d.domain)
935
- for pinfo in get_all_validated_proxies(domains):
936
- sing = to_singbox(pinfo)
937
- if 'msg' not in sing:
938
- allp += sing
939
- base_config['outbounds'] += allp
940
-
941
- select = {
942
- "type": "selector",
943
- "tag": "Select",
944
- "outbounds": [p['tag'] for p in allp if 'shadowtls-out' not in p['tag']],
945
- "default": "Auto"
946
- }
947
- select['outbounds'].insert(0, "Auto")
948
- base_config['outbounds'].insert(0, select)
949
- smart = {
950
- "type": "urltest",
951
- "tag": "Auto",
952
- "outbounds": [p['tag'] for p in allp if 'shadowtls-out' not in p],
953
- "url": "https://www.gstatic.com/generate_204",
954
- "interval": "10m",
955
- "tolerance": 200
956
- }
957
- base_config['outbounds'].insert(1, smart)
958
- res = json.dumps(base_config, indent=4, cls=CustomEncoder)
959
- # if ua['is_hiddify']:
960
- # res = res[:-1]+',"experimental": {}}'
961
- return res
962
-
963
-
964
- def make_v2ray_configs(user, user_activate, domains, expire_days, ip_debug, db_domain, has_auto_cdn, asn, profile_title, **kwargs):
965
- res = []
966
-
967
- ua = hutils.flask.get_user_agent()
968
- if hconfig(ConfigEnum.show_usage_in_sublink):
969
-
970
- if not ua['is_hiddify']:
971
-
972
- fake_ip_for_sub_link = datetime.datetime.now().strftime(f"%H.%M--%Y.%m.%d.time:%H%M")
973
- # if ua['app'] == "Fair1":
974
- # res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{round(user.current_usage_GB,3)}/{user.usage_limit_GB}GB_Remain:{expire_days}days')
975
- # else:
976
-
977
- # res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{hutils.encode.url_encode(profile_title)}')
978
-
979
- name = '⏳' if user_activate else '✖'
980
- if user.usage_limit_GB < 1000:
981
- name += f'{round(user.current_usage_GB,3)}/{str(user.usage_limit_GB).rstrip(".0")}GB'
982
- elif user.usage_limit_GB < 100000:
983
- name += f'{round(user.current_usage_GB/1000,3)}/{str(round(user.usage_limit_GB/1000,1)).rstrip(".0")}TB'
984
- else:
985
- res.append("#No Usage Limit")
986
- if expire_days < 1000:
987
- name += " " + _(f'📅%(expire_days)s days', expire_days=expire_days)
988
- else:
989
- res.append("#No Time Limit")
990
-
991
- name = name.strip()
992
- if len(name) > 3:
993
- res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{hutils.encode.url_encode(name)}')
994
-
995
- if ua['is_browser']:
996
- res.append(f'#Hiddify auto ip: {ip_debug}')
997
-
998
- if not user_activate:
999
-
1000
- if hconfig(ConfigEnum.lang) == 'fa':
1001
- res.append('trojan://1@1.1.1.1#' + hutils.encode.url_encode('✖بسته شما به پایان رسید'))
1002
- else:
1003
- res.append('trojan://1@1.1.1.1#' + hutils.encode.url_encode('✖Package_Ended'))
1004
- return "\n".join(res)
1005
-
1006
- for pinfo in get_all_validated_proxies(domains):
1007
- link = to_link(pinfo)
1008
- if 'msg' not in link:
1009
- res.append(link)
1010
- return "\n".join(res)
1011
-
1012
-
1013
- def get_all_validated_proxies(domains):
1014
- allp = []
1015
- allphttp = [p for p in request.args.get("phttp", "").split(',') if p]
1016
- allptls = [p for p in request.args.get("ptls", "").split(',') if p]
1017
- added_ip = {}
1018
- configsmap = {}
1019
- proxeismap = {}
1020
- for d in domains:
1021
- if d.child_id not in configsmap:
1022
- configsmap[d.child_id] = get_hconfigs(d.child_id)
1023
- proxeismap[d.child_id] = all_proxies(d.child_id)
1024
- hconfigs = configsmap[d.child_id]
1025
-
1026
- ip = hutils.network.get_domain_ip(d.domain, version=4)
1027
- ip6 = hutils.network.get_domain_ip(d.domain, version=6)
1028
- ips = [x for x in [ip, ip6] if x is not None]
1029
- for type in proxeismap[d.child_id]:
1030
- noDomainProxies = False
1031
- if type.proto in [ProxyProto.ssh, ProxyProto.wireguard]:
1032
- noDomainProxies = True
1033
- if type.proto in [ProxyProto.ss] and type.transport not in [ProxyTransport.grpc, ProxyTransport.h2, ProxyTransport.WS, ProxyTransport.httpupgrade]:
1034
- noDomainProxies = True
1035
- options = []
1036
- key = f'{type.proto}{type.transport}{type.cdn}{type.l3}'
1037
- if key not in added_ip:
1038
- added_ip[key] = {}
1039
- if type.proto in [ProxyProto.ssh, ProxyProto.tuic, ProxyProto.hysteria2, ProxyProto.wireguard, ProxyProto.ss]:
1040
- if noDomainProxies and all([x in added_ip[key] for x in ips]):
1041
- continue
1042
-
1043
- for x in ips:
1044
- added_ip[key][x] = 1
1045
-
1046
- if type.proto in [ProxyProto.ssh, ProxyProto.wireguard, ProxyProto.ss]:
1047
- if d.mode == 'fake':
1048
- continue
1049
- if type.proto in [ProxyProto.ssh]:
1050
- options = [{'pport': hconfigs[ConfigEnum.ssh_server_port]}]
1051
- elif type.proto in [ProxyProto.wireguard]:
1052
- options = [{'pport': hconfigs[ConfigEnum.wireguard_port]}]
1053
- elif type.transport in [ProxyTransport.shadowsocks]:
1054
- options = [{'pport': hconfigs[ConfigEnum.shadowsocks2022_port]}]
1055
- elif type.proto in [ProxyProto.ss]:
1056
- options = [{'pport': 443}]
1057
- elif type.proto == ProxyProto.tuic:
1058
- options = [{'pport': hconfigs[ConfigEnum.tuic_port]}]
1059
- elif type.proto == ProxyProto.hysteria2:
1060
- options = [{'pport': hconfigs[ConfigEnum.hysteria_port]}]
1061
- else:
1062
- for t in (['http', 'tls'] if hconfigs[ConfigEnum.http_proxy_enable] else ['tls']):
1063
- for port in hconfigs[ConfigEnum.http_ports if t == 'http' else ConfigEnum.tls_ports].split(','):
1064
- phttp = port if t == 'http' else None
1065
- ptls = port if t == 'tls' else None
1066
- if phttp and len(allphttp) and phttp not in allphttp:
1067
- continue
1068
- if ptls and len(allptls) and ptls not in allptls:
1069
- continue
1070
- options.append({'phttp': phttp, 'ptls': ptls})
1071
-
1072
- for opt in options:
1073
- pinfo = make_proxy(hconfigs, type, d, **opt)
1074
- if 'msg' not in pinfo:
1075
- allp.append(pinfo)
1076
- return allp
1077
-
1078
-
1079
- class CustomEncoder(json.JSONEncoder):
1080
- def default(self, obj):
1081
- if isinstance(obj, IPv4Address) or isinstance(obj, IPv6Address):
1082
- return str(obj)
1083
- return super().default(obj)