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.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +2 -2
- hiddifypanel/hutils/__init__.py +3 -0
- hiddifypanel/hutils/crypto.py +29 -0
- hiddifypanel/hutils/encode.py +4 -0
- hiddifypanel/hutils/flask.py +4 -0
- hiddifypanel/hutils/github_issue.py +1 -1
- hiddifypanel/{models/utils.py → hutils/model.py} +14 -4
- hiddifypanel/hutils/network/net.py +46 -2
- hiddifypanel/hutils/proxy/__init__.py +4 -0
- hiddifypanel/hutils/proxy/clash.py +161 -0
- hiddifypanel/hutils/proxy/shared.py +414 -0
- hiddifypanel/hutils/proxy/singbox.py +338 -0
- hiddifypanel/hutils/proxy/xray.py +561 -0
- hiddifypanel/models/admin.py +16 -14
- hiddifypanel/models/base_account.py +4 -4
- hiddifypanel/models/config.py +1 -1
- hiddifypanel/models/proxy.py +17 -17
- hiddifypanel/models/user.py +15 -13
- hiddifypanel/panel/admin/AdminstratorAdmin.py +1 -1
- hiddifypanel/panel/admin/DomainAdmin.py +13 -27
- hiddifypanel/panel/admin/ProxyAdmin.py +3 -3
- hiddifypanel/panel/admin/SettingAdmin.py +22 -11
- hiddifypanel/panel/admin/UserAdmin.py +9 -7
- hiddifypanel/panel/cf_api.py +1 -2
- hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +5 -6
- hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +1 -1
- hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +4 -7
- hiddifypanel/panel/common.py +5 -3
- hiddifypanel/panel/hiddify.py +0 -90
- hiddifypanel/panel/init_db.py +14 -9
- hiddifypanel/panel/user/__init__.py +0 -1
- hiddifypanel/panel/user/templates/all_configs copy.txt +2 -2
- hiddifypanel/panel/user/templates/all_configs.txt +2 -2
- hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +2 -1
- hiddifypanel/panel/user/templates/base_xray_config.json.j2 +125 -0
- hiddifypanel/panel/user/templates/clash_config copy.yml +1 -1
- hiddifypanel/panel/user/templates/clash_config.yml +4 -4
- hiddifypanel/panel/user/templates/clash_proxies.yml +1 -1
- hiddifypanel/panel/user/templates/home/all-configs.html +2 -2
- hiddifypanel/panel/user/templates/home/all-configs_old.html +1 -1
- hiddifypanel/panel/user/templates/home/ios copy.html +2 -2
- hiddifypanel/panel/user/user.py +50 -44
- hiddifypanel/templates/admin-layout.html +16 -24
- hiddifypanel/templates/fake.html +0 -276
- hiddifypanel/templates/flaskadmin-layout.html +2 -1
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +16 -9
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +12 -6
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +9 -4
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +12 -7
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +9 -4
- hiddifypanel/translations.i18n/en.json +8 -7
- hiddifypanel/translations.i18n/fa.json +5 -4
- hiddifypanel/translations.i18n/pt.json +3 -2
- hiddifypanel/translations.i18n/ru.json +6 -5
- hiddifypanel/translations.i18n/zh.json +3 -2
- {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/METADATA +1 -1
- {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/RECORD +67 -61
- {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/WHEEL +1 -1
- hiddifypanel/panel/user/link_maker.py +0 -1089
- {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/LICENSE.md +0 -0
- {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-10.10.20.dist-info → hiddifypanel-10.11.1.dist-info}/top_level.txt +0 -0
@@ -1,1089 +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
|
-
# ignore httpupgrade for Streisand
|
306
|
-
if g.user_agent.get('is_streisand') and proxy.get('transport') == 'httpupgrade':
|
307
|
-
return {'msg': 'ignore httpupgrade for streisand'}
|
308
|
-
|
309
|
-
orig_name_link = (proxy['extra_info'] + " " + proxy["name"]).strip()
|
310
|
-
name_link = hutils.encode.url_encode(orig_name_link)
|
311
|
-
if proxy['proto'] == 'vmess':
|
312
|
-
# print(proxy)
|
313
|
-
vmess_type = None
|
314
|
-
if proxy["transport"] == 'tcp':
|
315
|
-
vmess_type = 'http'
|
316
|
-
if 'grpc_mode' in proxy:
|
317
|
-
vmess_type = proxy['grpc_mode']
|
318
|
-
vmess_data = {"v": "2",
|
319
|
-
"ps": orig_name_link,
|
320
|
-
"add": proxy['server'],
|
321
|
-
"port": proxy['port'],
|
322
|
-
"id": proxy["uuid"],
|
323
|
-
"aid": 0,
|
324
|
-
"scy": proxy['cipher'],
|
325
|
-
"net": proxy["transport"],
|
326
|
-
"type": vmess_type or "none",
|
327
|
-
"host": proxy.get("host", ""),
|
328
|
-
"alpn": proxy.get("alpn", "h2,http/1.1"),
|
329
|
-
"path": proxy["path"] if "path" in proxy else "",
|
330
|
-
"tls": "tls" if "tls" in proxy["l3"] else "",
|
331
|
-
"sni": proxy["sni"],
|
332
|
-
"fp": proxy["fingerprint"]
|
333
|
-
}
|
334
|
-
if 'reality' in proxy["l3"]:
|
335
|
-
vmess_data['tls'] = "reality"
|
336
|
-
vmess_data['pbk'] = proxy['reality_pbk']
|
337
|
-
vmess_data['sid'] = proxy['reality_short_id']
|
338
|
-
|
339
|
-
add_tls_tricks_to_dict(vmess_data, proxy)
|
340
|
-
add_mux_to_dict(vmess_data, proxy)
|
341
|
-
|
342
|
-
return "vmess://" + hutils.encode.do_base_64(f'{json.dumps(vmess_data,cls=CustomEncoder)}')
|
343
|
-
if proxy['proto'] == 'ssh':
|
344
|
-
baseurl = 'ssh://'
|
345
|
-
if g.user_agent.get('is_streisand'):
|
346
|
-
streisand_ssh = hutils.encode.do_base_64(f'{proxy["uuid"]}:0:{proxy["private_key"]}::@{proxy["server"]}:{proxy["port"]}')
|
347
|
-
baseurl += f'{streisand_ssh}#{name_link}'
|
348
|
-
else:
|
349
|
-
hk = ",".join(proxy["host_key"])
|
350
|
-
pk = proxy["private_key"].replace('\n', '')
|
351
|
-
baseurl += f'{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}/?file=ssh&pk={pk}&pp={pk}&hk={hk}#{name_link}'
|
352
|
-
|
353
|
-
return baseurl
|
354
|
-
if proxy['proto'] == "ssr":
|
355
|
-
baseurl = f'ssr://{proxy["cipher"]}:{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}'
|
356
|
-
return baseurl
|
357
|
-
if proxy['proto'] in ['ss', 'v2ray']:
|
358
|
-
baseurl = f'ss://{proxy["cipher"]}:{proxy["password"]}@{proxy["server"]}:{proxy["port"]}'
|
359
|
-
if proxy['mode'] == 'faketls':
|
360
|
-
return f'{baseurl}?plugin=obfs-local%3Bobfs%3Dtls%3Bobfs-host%3D{proxy["fakedomain"]}%3Budp-over-tcp=true#{name_link}'
|
361
|
-
# if proxy['mode'] == 'shadowtls':
|
362
|
-
# return f'{baseurl}?plugin=shadow-tls%3Bpassword%3D{proxy["proxy_path"]}%3Bhost%3D{proxy["fakedomain"]}%3Budp-over-tcp=true#{name_link}'
|
363
|
-
if proxy['proto'] == 'v2ray':
|
364
|
-
return f'{baseurl}?plugin=v2ray-plugin%3Bmode%3Dwebsocket%3Bpath%3D{proxy["path"]}%3Bhost%3D{proxy["host"]}%3Btls%3Budp-over-tcp=true#{name_link}'
|
365
|
-
if proxy['transport'] == 'shadowsocks':
|
366
|
-
return baseurl
|
367
|
-
if proxy['proto'] == 'tuic':
|
368
|
-
baseurl = f'tuic://{proxy["uuid"]}:{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}?congestion_control=cubic&udp_relay_mode=native&sni={proxy["sni"]}&alpn=h3'
|
369
|
-
if proxy['mode'] == 'Fake' or proxy['allow_insecure']:
|
370
|
-
baseurl += "&allow_insecure=1"
|
371
|
-
return f"{baseurl}#{name_link}"
|
372
|
-
if proxy['proto'] == 'hysteria2':
|
373
|
-
baseurl = f'hysteria2://{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}?hiddify=1&obfs=salamander&obfs-password={hconfig(ConfigEnum.proxy_path)}&sni={proxy["sni"]}'
|
374
|
-
if proxy['mode'] == 'Fake' or proxy['allow_insecure']:
|
375
|
-
baseurl += "&insecure=1"
|
376
|
-
return f"{baseurl}#{name_link}"
|
377
|
-
if proxy['proto'] == ProxyProto.wireguard:
|
378
|
-
if g.user_agent.get('is_streisand'):
|
379
|
-
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}'
|
380
|
-
else:
|
381
|
-
# hiddify_format =
|
382
|
-
# 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}'
|
383
|
-
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}'
|
384
|
-
|
385
|
-
baseurl = f'{proxy["proto"]}://{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}?hiddify=1'
|
386
|
-
baseurl += f'&sni={proxy["sni"]}&type={proxy["transport"]}'
|
387
|
-
baseurl += f"&alpn={proxy['alpn']}"
|
388
|
-
|
389
|
-
# the ray2sing supports vless, vmess and trojan tls tricks and mux
|
390
|
-
# the vmess handled already
|
391
|
-
|
392
|
-
baseurl += add_mux_to_link(proxy)
|
393
|
-
baseurl += add_tls_tricks_to_link(proxy)
|
394
|
-
|
395
|
-
# infos+=f'&alpn={proxy["alpn"]}'
|
396
|
-
baseurl += f'&path={proxy["path"]}' if "path" in proxy else ""
|
397
|
-
baseurl += f'&host={proxy["host"]}' if "host" in proxy else ""
|
398
|
-
if "grpc" == proxy["transport"]:
|
399
|
-
baseurl += f'&serviceName={proxy["grpc_service_name"]}&mode={proxy["grpc_mode"]}'
|
400
|
-
# print(proxy['cdn'],proxy["transport"])
|
401
|
-
if request.args.get("fragment"):
|
402
|
-
baseurl += f'&fragment=' + request.args.get("fragment") # type: ignore
|
403
|
-
if "ws" == proxy["transport"] and proxy['cdn'] and request.args.get("fragment_v1"):
|
404
|
-
baseurl += f'&fragment_v1=' + request.args.get("fragment_v1") # type: ignore
|
405
|
-
if 'vless' == proxy['proto']:
|
406
|
-
baseurl += "&encryption=none"
|
407
|
-
if proxy.get('fingerprint', 'none') != 'none':
|
408
|
-
baseurl += "&fp=" + proxy['fingerprint']
|
409
|
-
if proxy['l3'] != 'quic':
|
410
|
-
if proxy.get('transport') == ProxyTransport.tcp and proxy['proto'] in [ProxyProto.vless, ProxyProto.vmess] and proxy.get('l3') != ProxyL3.reality:
|
411
|
-
baseurl += '&headerType=http'
|
412
|
-
else:
|
413
|
-
baseurl += '&headerType=None'
|
414
|
-
if proxy['mode'] == 'Fake' or proxy['allow_insecure']:
|
415
|
-
baseurl += "&allowInsecure=true"
|
416
|
-
if proxy.get('flow'):
|
417
|
-
baseurl += f'&flow={proxy["flow"]}'
|
418
|
-
|
419
|
-
infos = f'#{name_link}'
|
420
|
-
|
421
|
-
if 'reality' in proxy["l3"]:
|
422
|
-
return f"{baseurl}&security=reality&pbk={proxy['reality_pbk']}&sid={proxy['reality_short_id']}{infos}"
|
423
|
-
if 'tls' in proxy['l3']:
|
424
|
-
return f'{baseurl}&security=tls{infos}'
|
425
|
-
if proxy['l3'] == 'http':
|
426
|
-
return f'{baseurl}&security=none{infos}'
|
427
|
-
return proxy
|
428
|
-
|
429
|
-
# region tls tricks & mux
|
430
|
-
# notice: combining the functions into two function would make code less readable and difficult to maintain
|
431
|
-
|
432
|
-
|
433
|
-
def add_tls_tricks_to_link(proxy) -> str:
|
434
|
-
out = {}
|
435
|
-
add_tls_tricks_to_dict(out, proxy)
|
436
|
-
return convert_dict_to_url(out)
|
437
|
-
|
438
|
-
|
439
|
-
def add_tls_tricks_to_dict(d: dict, proxy):
|
440
|
-
if proxy.get('tls_fragment_enable'):
|
441
|
-
if g.user_agent.get('is_shadowrocket'):
|
442
|
-
d['fragment'] = f'1,{proxy["tls_fragment_size"]},{proxy["tls_fragment_sleep"]}'
|
443
|
-
else:
|
444
|
-
d['fragment'] = f'{proxy["tls_fragment_size"]},{proxy["tls_fragment_sleep"]},tlshello'
|
445
|
-
|
446
|
-
if proxy.get("tls_mixed_case"):
|
447
|
-
d['mc'] = 1
|
448
|
-
if proxy.get("tls_padding_enable"):
|
449
|
-
d['padsize'] = proxy["tls_padding_length"]
|
450
|
-
|
451
|
-
|
452
|
-
def convert_dict_to_url(dict):
|
453
|
-
return '&' + '&'.join([f'{k}={v}' for k, v in dict.items()]) if len(dict) else ''
|
454
|
-
|
455
|
-
|
456
|
-
def add_mux_to_link(proxy) -> str:
|
457
|
-
out = {}
|
458
|
-
add_mux_to_dict(out, proxy)
|
459
|
-
return convert_dict_to_url(out)
|
460
|
-
|
461
|
-
|
462
|
-
def add_mux_to_dict(d: dict, proxy):
|
463
|
-
if proxy.get('mux_enable'):
|
464
|
-
# d['mux'] = proxy["mux_protocol"]
|
465
|
-
# mux is equals to concurrency in clients
|
466
|
-
d['mux'] = proxy["mux_max_streams"]
|
467
|
-
d['mux_max'] = proxy["mux_max_connections"]
|
468
|
-
d['mux_pad'] = proxy["mux_padding_enable"]
|
469
|
-
# doesn't exist
|
470
|
-
# d['mux_min'] = proxy["mux_min_connections"]
|
471
|
-
|
472
|
-
if proxy.get('mux_brutal_enable'):
|
473
|
-
d['mux_up'] = proxy["mux_brutal_up_mbps"]
|
474
|
-
d['mux_down'] = proxy["mux_brutal_down_mbps"]
|
475
|
-
|
476
|
-
# endregion
|
477
|
-
|
478
|
-
|
479
|
-
# def to_clash_yml(proxy):
|
480
|
-
# return yaml.dump(to_clash(proxy,'normal'))
|
481
|
-
|
482
|
-
|
483
|
-
def to_clash(proxy, meta_or_normal):
|
484
|
-
|
485
|
-
name = proxy['name']
|
486
|
-
if proxy['l3'] == "kcp":
|
487
|
-
return {'name': name, 'msg': "clash does not support kcp", 'type': 'debug'}
|
488
|
-
if proxy['proto'] == "ssh":
|
489
|
-
return {'name': name, 'msg': "clash does not support ssh", 'type': 'debug'}
|
490
|
-
if meta_or_normal == "normal":
|
491
|
-
if proxy['proto'] in ["vless", 'tuic', 'hysteria2']:
|
492
|
-
return {'name': name, 'msg': f"{proxy['proto']} not supported in clash", 'type': 'debug'}
|
493
|
-
if proxy.get('flow'):
|
494
|
-
return {'name': name, 'msg': "xtls not supported in clash", 'type': 'debug'}
|
495
|
-
if proxy['transport'] == "shadowtls":
|
496
|
-
return {'name': name, 'msg': "shadowtls not supported in clash", 'type': 'debug'}
|
497
|
-
if proxy['l3'] == ProxyL3.tls_h2 and proxy['proto'] in [ProxyProto.vmess, ProxyProto.vless] and proxy['dbe'].cdn == ProxyCDN.direct:
|
498
|
-
return {'name': name, 'msg': "bug tls_h2 vmess and vless in clash meta", 'type': 'warning'}
|
499
|
-
base = {}
|
500
|
-
# vmess ws
|
501
|
-
base["name"] = f"""{proxy['extra_info']} {proxy["name"]} § {proxy['port']} {proxy["dbdomain"].id}"""
|
502
|
-
base["type"] = str(proxy["proto"])
|
503
|
-
base["server"] = proxy["server"]
|
504
|
-
base["port"] = proxy["port"]
|
505
|
-
base['alpn'] = proxy['alpn'].split(',')
|
506
|
-
if proxy["proto"] == "ssr":
|
507
|
-
base["cipher"] = proxy["cipher"]
|
508
|
-
base["password"] = proxy["uuid"]
|
509
|
-
base["udp"] = True
|
510
|
-
base["obfs"] = proxy["ssr-obfs"]
|
511
|
-
base["protocol"] = proxy["ssr-protocol"]
|
512
|
-
base["obfs-param"] = proxy["fakedomain"]
|
513
|
-
return base
|
514
|
-
elif proxy["proto"] == "tuic":
|
515
|
-
base["uuid"] = proxy["uuid"]
|
516
|
-
base["password"] = proxy["uuid"]
|
517
|
-
base["disable-sni"] = proxy['allow_insecure']
|
518
|
-
base["reduce-rtt"] = True
|
519
|
-
base["request-timeout"] = 8000
|
520
|
-
base["udp-relay-mode"] = 'native'
|
521
|
-
base["congestion-controller"] = 'cubic'
|
522
|
-
base['sni'] = proxy['sni']
|
523
|
-
return base
|
524
|
-
elif proxy["proto"] in ["ss", "v2ray"]:
|
525
|
-
base["cipher"] = proxy["cipher"]
|
526
|
-
base["password"] = proxy["password"]
|
527
|
-
base["udp_over_tcp"] = True
|
528
|
-
if proxy["transport"] == "faketls":
|
529
|
-
base["plugin"] = "obfs"
|
530
|
-
base["plugin-opts"] = {
|
531
|
-
"mode": 'tls',
|
532
|
-
"host": proxy["fakedomain"]
|
533
|
-
}
|
534
|
-
elif proxy["transport"] == "shadowtls":
|
535
|
-
base["plugin"] = "shadow-tls"
|
536
|
-
base["plugin-opts"] = {
|
537
|
-
"host": proxy["fakedomain"],
|
538
|
-
"password": proxy["proxy_path"],
|
539
|
-
"version": 3 # support 1/2/3
|
540
|
-
|
541
|
-
}
|
542
|
-
|
543
|
-
elif proxy["proto"] == "v2ray":
|
544
|
-
base["plugin"] = "v2ray-plugin"
|
545
|
-
base["type"] = "ss"
|
546
|
-
base["plugin-opts"] = {
|
547
|
-
"mode": "websocket",
|
548
|
-
"tls": "tls" in proxy["l3"],
|
549
|
-
"skip-cert-verify": proxy["mode"] == "Fake" or proxy['allow_insecure'],
|
550
|
-
"host": proxy['sni'],
|
551
|
-
"path": proxy["path"]
|
552
|
-
}
|
553
|
-
return base
|
554
|
-
elif proxy["proto"] == "trojan":
|
555
|
-
base["password"] = proxy["uuid"]
|
556
|
-
base["sni"] = proxy["sni"]
|
557
|
-
|
558
|
-
else:
|
559
|
-
base["uuid"] = proxy["uuid"]
|
560
|
-
base["servername"] = proxy["sni"]
|
561
|
-
base["tls"] = "tls" in proxy["l3"] or "reality" in proxy["l3"]
|
562
|
-
if meta_or_normal == "meta":
|
563
|
-
base['client-fingerprint'] = proxy['fingerprint']
|
564
|
-
if proxy.get('flow'):
|
565
|
-
base["flow"] = proxy['flow']
|
566
|
-
# base["flow-show"] = True
|
567
|
-
|
568
|
-
if proxy["proto"] == "vmess":
|
569
|
-
base["alterId"] = 0
|
570
|
-
base["cipher"] = proxy["cipher"]
|
571
|
-
base["udp"] = True
|
572
|
-
|
573
|
-
base["skip-cert-verify"] = proxy["mode"] == "Fake"
|
574
|
-
|
575
|
-
base["network"] = proxy["transport"]
|
576
|
-
|
577
|
-
if base["network"] == "ws":
|
578
|
-
base["ws-opts"] = {
|
579
|
-
"path": proxy["path"]
|
580
|
-
}
|
581
|
-
if "host" in proxy:
|
582
|
-
base["ws-opts"]["headers"] = {"Host": proxy["host"]}
|
583
|
-
|
584
|
-
if base["network"] == "tcp" and proxy['alpn'] != 'h2':
|
585
|
-
if proxy['transport'] != ProxyTransport.XTLS:
|
586
|
-
base["network"] = "http"
|
587
|
-
|
588
|
-
if "path" in proxy:
|
589
|
-
base["http-opts"] = {
|
590
|
-
"path": [proxy["path"]]
|
591
|
-
}
|
592
|
-
if 'host' in proxy:
|
593
|
-
base["http-opts"]["host"] = [proxy["host"]]
|
594
|
-
if base["network"] == "tcp" and proxy['alpn'] == 'h2':
|
595
|
-
base["network"] = "h2"
|
596
|
-
|
597
|
-
if "path" in proxy:
|
598
|
-
base["h2-opts"] = {
|
599
|
-
"path": proxy["path"]
|
600
|
-
}
|
601
|
-
if 'host' in proxy:
|
602
|
-
base["h2-opts"]["host"] = [proxy["host"]]
|
603
|
-
if base["network"] == "grpc":
|
604
|
-
base["grpc-opts"] = {
|
605
|
-
"grpc-service-name": proxy["grpc_service_name"]
|
606
|
-
}
|
607
|
-
if proxy['l3'] == ProxyL3.reality:
|
608
|
-
base["reality-opts"] = {
|
609
|
-
"public-key": proxy['reality_pbk'],
|
610
|
-
"short-id": proxy['reality_short_id'],
|
611
|
-
}
|
612
|
-
if proxy["transport"] != 'grpc':
|
613
|
-
base["network"] = 'tcp'
|
614
|
-
|
615
|
-
return base
|
616
|
-
|
617
|
-
|
618
|
-
def get_clash_config_names(meta_or_normal, domains):
|
619
|
-
allp = []
|
620
|
-
for pinfo in get_all_validated_proxies(domains):
|
621
|
-
clash = to_clash(pinfo, meta_or_normal)
|
622
|
-
if 'msg' not in clash:
|
623
|
-
allp.append(clash['name'])
|
624
|
-
|
625
|
-
return yaml.dump(allp, sort_keys=False)
|
626
|
-
|
627
|
-
|
628
|
-
def get_all_clash_configs(meta_or_normal, domains):
|
629
|
-
allp = []
|
630
|
-
for pinfo in get_all_validated_proxies(domains):
|
631
|
-
clash = to_clash(pinfo, meta_or_normal)
|
632
|
-
if 'msg' not in clash:
|
633
|
-
allp.append(clash)
|
634
|
-
|
635
|
-
return yaml.dump({"proxies": allp}, sort_keys=False)
|
636
|
-
|
637
|
-
|
638
|
-
def to_singbox(proxy):
|
639
|
-
name = proxy['name']
|
640
|
-
|
641
|
-
all_base = []
|
642
|
-
if proxy['l3'] == "kcp":
|
643
|
-
return {'name': name, 'msg': "clash does not support kcp", 'type': 'debug'}
|
644
|
-
|
645
|
-
base = {}
|
646
|
-
all_base.append(base)
|
647
|
-
# vmess ws
|
648
|
-
base["tag"] = f"""{proxy['extra_info']} {proxy["name"]} § {proxy['port']} {proxy["dbdomain"].id}"""
|
649
|
-
base["type"] = str(proxy["proto"])
|
650
|
-
base["server"] = proxy["server"]
|
651
|
-
base["server_port"] = int(proxy["port"])
|
652
|
-
# base['alpn'] = proxy['alpn'].split(',')
|
653
|
-
if proxy["proto"] == "ssr":
|
654
|
-
add_singbox_ssr(base, proxy)
|
655
|
-
return all_base
|
656
|
-
if proxy["proto"] == ProxyProto.wireguard:
|
657
|
-
add_singbox_wireguard(base, proxy)
|
658
|
-
return all_base
|
659
|
-
|
660
|
-
if proxy["proto"] in ["ss", "v2ray"]:
|
661
|
-
add_singbox_shadowsocks_base(all_base, proxy)
|
662
|
-
return all_base
|
663
|
-
if proxy["proto"] == "ssh":
|
664
|
-
add_singbox_ssh(all_base, proxy)
|
665
|
-
return all_base
|
666
|
-
|
667
|
-
if proxy["proto"] == "trojan":
|
668
|
-
base["password"] = proxy["uuid"]
|
669
|
-
|
670
|
-
if proxy['proto'] in ['vmess', 'vless']:
|
671
|
-
base["uuid"] = proxy["uuid"]
|
672
|
-
|
673
|
-
if proxy['proto'] in ['vmess', 'vless', 'trojan']:
|
674
|
-
add_singbox_multiplex(base)
|
675
|
-
|
676
|
-
add_singbox_tls(base, proxy)
|
677
|
-
|
678
|
-
if g.user_agent.get('is_hiddify'):
|
679
|
-
add_singbox_tls_tricks(base, proxy)
|
680
|
-
|
681
|
-
if proxy.get('flow'):
|
682
|
-
base["flow"] = proxy['flow']
|
683
|
-
# base["flow-show"] = True
|
684
|
-
|
685
|
-
if proxy["proto"] == "vmess":
|
686
|
-
base["alter_id"] = 0
|
687
|
-
base["security"] = proxy["cipher"]
|
688
|
-
|
689
|
-
# base["udp"] = True
|
690
|
-
if proxy["proto"] in ["vmess", "vless"]:
|
691
|
-
base["packet_encoding"] = "xudp" # udp packet encoding
|
692
|
-
|
693
|
-
if proxy["proto"] == "tuic":
|
694
|
-
add_tuic(base, proxy)
|
695
|
-
elif proxy["proto"] == "hysteria2":
|
696
|
-
add_hysteria(base, proxy)
|
697
|
-
else:
|
698
|
-
add_singbox_transport(base, proxy)
|
699
|
-
|
700
|
-
return all_base
|
701
|
-
|
702
|
-
|
703
|
-
def add_tuic(base, proxy):
|
704
|
-
base['congestion_control'] = "cubic"
|
705
|
-
base['udp_relay_mode'] = 'native'
|
706
|
-
base['zero_rtt_handshake'] = True
|
707
|
-
base['heartbeat'] = "10s"
|
708
|
-
base['password'] = proxy['uuid']
|
709
|
-
base['uuid'] = proxy['uuid']
|
710
|
-
|
711
|
-
|
712
|
-
def add_hysteria(base, proxy):
|
713
|
-
base['up_mbps'] = int(hconfig(ConfigEnum.hysteria_up_mbps))
|
714
|
-
base['down_mbps'] = int(hconfig(ConfigEnum.hysteria_down_mbps))
|
715
|
-
# TODO: check the obfs should be empty or not exists at all
|
716
|
-
if hconfig(ConfigEnum.hysteria_obfs_enable):
|
717
|
-
base['obfs'] = {
|
718
|
-
"type": "salamander",
|
719
|
-
"password": hconfig(ConfigEnum.proxy_path)
|
720
|
-
}
|
721
|
-
base['password'] = proxy['uuid']
|
722
|
-
|
723
|
-
|
724
|
-
def add_singbox_multiplex(base):
|
725
|
-
if not hconfig(ConfigEnum.mux_enable):
|
726
|
-
return
|
727
|
-
base['multiplex'] = {
|
728
|
-
"enabled": True,
|
729
|
-
"protocol": hconfig(ConfigEnum.mux_protocol),
|
730
|
-
"padding": hconfig(ConfigEnum.mux_padding_enable)
|
731
|
-
}
|
732
|
-
# Conflicts: max_streams with max_connections and min_streams
|
733
|
-
mux_max_streams = int(hconfig(ConfigEnum.mux_max_streams))
|
734
|
-
if mux_max_streams and mux_max_streams != 0:
|
735
|
-
base['multiplex']['max_streams'] = mux_max_streams
|
736
|
-
else:
|
737
|
-
base['multiplex']['max_connections'] = int(hconfig(ConfigEnum.mux_max_connections))
|
738
|
-
base['multiplex']['min_streams'] = int(hconfig(ConfigEnum.mux_min_streams))
|
739
|
-
|
740
|
-
add_singbox_tcp_brutal(base)
|
741
|
-
|
742
|
-
|
743
|
-
def add_singbox_tcp_brutal(base):
|
744
|
-
if 'multiplex' in base:
|
745
|
-
base['multiplex']['brutal'] = {
|
746
|
-
"enabled": hconfig(ConfigEnum.mux_brutal_enable),
|
747
|
-
"up_mbps": int(hconfig(ConfigEnum.mux_brutal_up_mbps)),
|
748
|
-
"down_mbps": int(hconfig(ConfigEnum.mux_brutal_down_mbps))
|
749
|
-
}
|
750
|
-
|
751
|
-
|
752
|
-
def add_singbox_udp_over_tcp(base):
|
753
|
-
base['udp_over_tcp'] = {
|
754
|
-
"enabled": True,
|
755
|
-
"version": 2
|
756
|
-
}
|
757
|
-
|
758
|
-
|
759
|
-
def add_singbox_tls(base, proxy):
|
760
|
-
if not ("tls" in proxy["l3"] or "reality" in proxy["l3"]):
|
761
|
-
return
|
762
|
-
base["tls"] = {
|
763
|
-
"enabled": True,
|
764
|
-
"server_name": proxy["sni"]
|
765
|
-
}
|
766
|
-
if proxy['proto'] not in ["tuic", "hysteria2"]:
|
767
|
-
base["tls"]["utls"] = {
|
768
|
-
"enabled": True,
|
769
|
-
"fingerprint": proxy.get('fingerprint', 'none')
|
770
|
-
}
|
771
|
-
|
772
|
-
if "reality" in proxy["l3"]:
|
773
|
-
base["tls"]["reality"] = {
|
774
|
-
"enabled": True,
|
775
|
-
"public_key": proxy['reality_pbk'],
|
776
|
-
"short_id": proxy['reality_short_id']
|
777
|
-
}
|
778
|
-
base["tls"]['insecure'] = proxy['allow_insecure'] or (proxy["mode"] == "Fake")
|
779
|
-
base["tls"]["alpn"] = proxy['alpn'].split(',')
|
780
|
-
# base['ech'] = {
|
781
|
-
# "enabled": True,
|
782
|
-
# }
|
783
|
-
|
784
|
-
|
785
|
-
def add_singbox_tls_tricks(base, proxy):
|
786
|
-
if proxy.get('tls_fragment_enable'):
|
787
|
-
base['tls_fragment'] = {
|
788
|
-
'enabled': True,
|
789
|
-
'size': proxy["tls_fragment_size"],
|
790
|
-
'sleep': proxy["tls_fragment_sleep"]
|
791
|
-
}
|
792
|
-
|
793
|
-
if 'tls' in base:
|
794
|
-
if proxy.get("tls_padding_enable") or proxy.get("tls_mixed_case"):
|
795
|
-
base['tls']['tls_tricks'] = {}
|
796
|
-
if proxy.get("tls_padding_enable"):
|
797
|
-
base['tls']['tls_tricks']['padding_size'] = proxy["tls_padding_length"]
|
798
|
-
|
799
|
-
if proxy.get("tls_mixed_case"):
|
800
|
-
base['tls']['tls_tricks']['mixedcase_sni'] = True
|
801
|
-
|
802
|
-
|
803
|
-
def add_singbox_transport(base, proxy):
|
804
|
-
if proxy['l3'] == 'reality' and proxy['transport'] not in ["grpc"]:
|
805
|
-
return
|
806
|
-
base["transport"] = {}
|
807
|
-
if proxy['transport'] in ["ws", "WS"]:
|
808
|
-
base["transport"] = {
|
809
|
-
"type": "ws",
|
810
|
-
"path": proxy["path"],
|
811
|
-
"early_data_header_name": "Sec-WebSocket-Protocol"
|
812
|
-
}
|
813
|
-
if "host" in proxy:
|
814
|
-
base["transport"]["headers"] = {"Host": proxy["host"]}
|
815
|
-
|
816
|
-
if proxy['transport'] in [ProxyTransport.httpupgrade]:
|
817
|
-
base["transport"] = {
|
818
|
-
"type": "httpupgrade",
|
819
|
-
"path": proxy["path"]
|
820
|
-
}
|
821
|
-
if "host" in proxy:
|
822
|
-
base["transport"]["headers"] = {"Host": proxy["host"]}
|
823
|
-
|
824
|
-
if proxy["transport"] in ["tcp", "h2"]:
|
825
|
-
base["transport"] = {
|
826
|
-
"type": "http",
|
827
|
-
"path": proxy.get("path", ""),
|
828
|
-
# "method": "",
|
829
|
-
# "headers": {},
|
830
|
-
"idle_timeout": "15s",
|
831
|
-
"ping_timeout": "15s"
|
832
|
-
}
|
833
|
-
|
834
|
-
if 'host' in proxy:
|
835
|
-
base["transport"]["host"] = [proxy["host"]]
|
836
|
-
|
837
|
-
if proxy["transport"] == "grpc":
|
838
|
-
base["transport"] = {
|
839
|
-
"type": "grpc",
|
840
|
-
"service_name": proxy["grpc_service_name"],
|
841
|
-
"idle_timeout": "115s",
|
842
|
-
"ping_timeout": "15s",
|
843
|
-
# "permit_without_stream": false
|
844
|
-
}
|
845
|
-
|
846
|
-
|
847
|
-
def add_singbox_ssr(base, proxy):
|
848
|
-
|
849
|
-
base["method"] = proxy["cipher"]
|
850
|
-
base["password"] = proxy["uuid"]
|
851
|
-
# base["udp"] = True
|
852
|
-
base["obfs"] = proxy["ssr-obfs"]
|
853
|
-
base["protocol"] = proxy["ssr-protocol"]
|
854
|
-
base["protocol-param"] = proxy["fakedomain"]
|
855
|
-
|
856
|
-
|
857
|
-
def add_singbox_wireguard(base, proxy):
|
858
|
-
|
859
|
-
base["local_address"] = f'{proxy["wg_ipv4"]}/32'
|
860
|
-
base["private_key"] = proxy["wg_pk"]
|
861
|
-
base["peer_public_key"] = proxy["wg_server_pub"]
|
862
|
-
|
863
|
-
base["pre_shared_key"] = proxy["wg_psk"]
|
864
|
-
|
865
|
-
base["mtu"] = 1380
|
866
|
-
if g.user_agent.get('is_hiddify') and hiddify.is_hiddify_next_version(0, 15, 0):
|
867
|
-
base["fake_packets"] = proxy["wg_noise_trick"]
|
868
|
-
|
869
|
-
|
870
|
-
def add_singbox_shadowsocks_base(all_base, proxy):
|
871
|
-
base = all_base[0]
|
872
|
-
base["type"] = "shadowsocks"
|
873
|
-
base["method"] = proxy["cipher"]
|
874
|
-
base["password"] = proxy["password"]
|
875
|
-
add_singbox_udp_over_tcp(base)
|
876
|
-
add_singbox_multiplex(base)
|
877
|
-
if proxy["transport"] == "faketls":
|
878
|
-
base["plugin"] = "obfs-local"
|
879
|
-
base["plugin_opts"] = f'obfs=tls;obfs-host={proxy["fakedomain"]}'
|
880
|
-
if proxy['proto'] == 'v2ray':
|
881
|
-
base["plugin"] = "v2ray-plugin"
|
882
|
-
# "skip-cert-verify": proxy["mode"] == "Fake" or proxy['allow_insecure'],
|
883
|
-
base["plugin_opts"] = f'mode=websocket;path={proxy["path"]};host={proxy["host"]};tls'
|
884
|
-
|
885
|
-
if proxy["transport"] == "shadowtls":
|
886
|
-
base['detour'] = base['tag'] + "_shadowtls-out §hide§"
|
887
|
-
|
888
|
-
shadowtls_base = {
|
889
|
-
"type": "shadowtls",
|
890
|
-
"tag": base['detour'],
|
891
|
-
"server": base['server'],
|
892
|
-
"server_port": base['server_port'],
|
893
|
-
"version": 3,
|
894
|
-
"password": proxy["shared_secret"],
|
895
|
-
"tls": {
|
896
|
-
"enabled": True,
|
897
|
-
"server_name": proxy["fakedomain"],
|
898
|
-
"utls": {
|
899
|
-
"enabled": True,
|
900
|
-
"fingerprint": proxy.get('fingerprint', 'none')
|
901
|
-
},
|
902
|
-
# "alpn": proxy['alpn'].split(',')
|
903
|
-
}
|
904
|
-
}
|
905
|
-
# add_singbox_utls(shadowtls_base)
|
906
|
-
del base['server']
|
907
|
-
del base['server_port']
|
908
|
-
all_base.append(shadowtls_base)
|
909
|
-
|
910
|
-
|
911
|
-
def add_singbox_ssh(all_base, proxy):
|
912
|
-
base = all_base[0]
|
913
|
-
# base["client_version"]= "{{ssh_client_version}}"
|
914
|
-
base["user"] = proxy['uuid']
|
915
|
-
base["private_key"] = proxy['private_key'] # .replace('\n', '\\n')
|
916
|
-
|
917
|
-
base["host_key"] = proxy.get('host_key', [])
|
918
|
-
|
919
|
-
socks_front = {
|
920
|
-
"type": "socks",
|
921
|
-
"tag": base['tag'] + "+UDP",
|
922
|
-
"server": "127.0.0.1",
|
923
|
-
"server_port": 2000,
|
924
|
-
"version": "5",
|
925
|
-
"udp_over_tcp": True,
|
926
|
-
"network": "tcp",
|
927
|
-
"detour": base['tag']
|
928
|
-
}
|
929
|
-
all_base.append(socks_front)
|
930
|
-
|
931
|
-
|
932
|
-
def make_full_singbox_config(domains, **kwargs):
|
933
|
-
ua = hutils.flask.get_user_agent()
|
934
|
-
base_config = json.loads(render_template('base_singbox_config.json.j2'))
|
935
|
-
allphttp = [p for p in request.args.get("phttp", "").split(',') if p]
|
936
|
-
allptls = [p for p in request.args.get("ptls", "").split(',') if p]
|
937
|
-
|
938
|
-
allp = []
|
939
|
-
for d in domains:
|
940
|
-
base_config['dns']['rules'][0]['domain'].append(d.domain)
|
941
|
-
for pinfo in get_all_validated_proxies(domains):
|
942
|
-
sing = to_singbox(pinfo)
|
943
|
-
if 'msg' not in sing:
|
944
|
-
allp += sing
|
945
|
-
base_config['outbounds'] += allp
|
946
|
-
|
947
|
-
select = {
|
948
|
-
"type": "selector",
|
949
|
-
"tag": "Select",
|
950
|
-
"outbounds": [p['tag'] for p in allp if 'shadowtls-out' not in p['tag']],
|
951
|
-
"default": "Auto"
|
952
|
-
}
|
953
|
-
select['outbounds'].insert(0, "Auto")
|
954
|
-
base_config['outbounds'].insert(0, select)
|
955
|
-
smart = {
|
956
|
-
"type": "urltest",
|
957
|
-
"tag": "Auto",
|
958
|
-
"outbounds": [p['tag'] for p in allp if 'shadowtls-out' not in p],
|
959
|
-
"url": "https://www.gstatic.com/generate_204",
|
960
|
-
"interval": "10m",
|
961
|
-
"tolerance": 200
|
962
|
-
}
|
963
|
-
base_config['outbounds'].insert(1, smart)
|
964
|
-
res = json.dumps(base_config, indent=4, cls=CustomEncoder)
|
965
|
-
# if ua['is_hiddify']:
|
966
|
-
# res = res[:-1]+',"experimental": {}}'
|
967
|
-
return res
|
968
|
-
|
969
|
-
|
970
|
-
def make_v2ray_configs(user, user_activate, domains, expire_days, ip_debug, db_domain, has_auto_cdn, asn, profile_title, **kwargs):
|
971
|
-
res = []
|
972
|
-
|
973
|
-
ua = hutils.flask.get_user_agent()
|
974
|
-
if hconfig(ConfigEnum.show_usage_in_sublink):
|
975
|
-
|
976
|
-
if not ua['is_hiddify']:
|
977
|
-
|
978
|
-
fake_ip_for_sub_link = datetime.datetime.now().strftime(f"%H.%M--%Y.%m.%d.time:%H%M")
|
979
|
-
# if ua['app'] == "Fair1":
|
980
|
-
# 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')
|
981
|
-
# else:
|
982
|
-
|
983
|
-
# res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{hutils.encode.url_encode(profile_title)}')
|
984
|
-
|
985
|
-
name = '⏳' if user_activate else '✖'
|
986
|
-
if user.usage_limit_GB < 1000:
|
987
|
-
name += f'{round(user.current_usage_GB,3)}/{str(user.usage_limit_GB).replace(".0","")}GB'
|
988
|
-
elif user.usage_limit_GB < 100000:
|
989
|
-
name += f'{round(user.current_usage_GB/1000,3)}/{str(round(user.usage_limit_GB/1000,1)).replace(".0","")}TB'
|
990
|
-
else:
|
991
|
-
res.append("#No Usage Limit")
|
992
|
-
if expire_days < 1000:
|
993
|
-
name += " " + _(f'📅%(expire_days)s days', expire_days=expire_days)
|
994
|
-
else:
|
995
|
-
res.append("#No Time Limit")
|
996
|
-
|
997
|
-
name = name.strip()
|
998
|
-
if len(name) > 3:
|
999
|
-
res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{hutils.encode.url_encode(name)}')
|
1000
|
-
|
1001
|
-
if ua['is_browser']:
|
1002
|
-
res.append(f'#Hiddify auto ip: {ip_debug}')
|
1003
|
-
|
1004
|
-
if not user_activate:
|
1005
|
-
|
1006
|
-
if hconfig(ConfigEnum.lang) == 'fa':
|
1007
|
-
res.append('trojan://1@1.1.1.1#' + hutils.encode.url_encode('✖بسته شما به پایان رسید'))
|
1008
|
-
else:
|
1009
|
-
res.append('trojan://1@1.1.1.1#' + hutils.encode.url_encode('✖Package_Ended'))
|
1010
|
-
return "\n".join(res)
|
1011
|
-
|
1012
|
-
for pinfo in get_all_validated_proxies(domains):
|
1013
|
-
link = to_link(pinfo)
|
1014
|
-
if 'msg' not in link:
|
1015
|
-
res.append(link)
|
1016
|
-
return "\n".join(res)
|
1017
|
-
|
1018
|
-
|
1019
|
-
def get_all_validated_proxies(domains):
|
1020
|
-
allp = []
|
1021
|
-
allphttp = [p for p in request.args.get("phttp", "").split(',') if p]
|
1022
|
-
allptls = [p for p in request.args.get("ptls", "").split(',') if p]
|
1023
|
-
added_ip = {}
|
1024
|
-
configsmap = {}
|
1025
|
-
proxeismap = {}
|
1026
|
-
for d in domains:
|
1027
|
-
if d.child_id not in configsmap:
|
1028
|
-
configsmap[d.child_id] = get_hconfigs(d.child_id)
|
1029
|
-
proxeismap[d.child_id] = all_proxies(d.child_id)
|
1030
|
-
hconfigs = configsmap[d.child_id]
|
1031
|
-
|
1032
|
-
ip = hutils.network.get_domain_ip(d.domain, version=4)
|
1033
|
-
ip6 = hutils.network.get_domain_ip(d.domain, version=6)
|
1034
|
-
ips = [x for x in [ip, ip6] if x is not None]
|
1035
|
-
for type in proxeismap[d.child_id]:
|
1036
|
-
noDomainProxies = False
|
1037
|
-
if type.proto in [ProxyProto.ssh, ProxyProto.wireguard]:
|
1038
|
-
noDomainProxies = True
|
1039
|
-
if type.proto in [ProxyProto.ss] and type.transport not in [ProxyTransport.grpc, ProxyTransport.h2, ProxyTransport.WS, ProxyTransport.httpupgrade]:
|
1040
|
-
noDomainProxies = True
|
1041
|
-
options = []
|
1042
|
-
key = f'{type.proto}{type.transport}{type.cdn}{type.l3}'
|
1043
|
-
if key not in added_ip:
|
1044
|
-
added_ip[key] = {}
|
1045
|
-
if type.proto in [ProxyProto.ssh, ProxyProto.tuic, ProxyProto.hysteria2, ProxyProto.wireguard, ProxyProto.ss]:
|
1046
|
-
if noDomainProxies and all([x in added_ip[key] for x in ips]):
|
1047
|
-
continue
|
1048
|
-
|
1049
|
-
for x in ips:
|
1050
|
-
added_ip[key][x] = 1
|
1051
|
-
|
1052
|
-
if type.proto in [ProxyProto.ssh, ProxyProto.wireguard, ProxyProto.ss]:
|
1053
|
-
if d.mode == 'fake':
|
1054
|
-
continue
|
1055
|
-
if type.proto in [ProxyProto.ssh]:
|
1056
|
-
options = [{'pport': hconfigs[ConfigEnum.ssh_server_port]}]
|
1057
|
-
elif type.proto in [ProxyProto.wireguard]:
|
1058
|
-
options = [{'pport': hconfigs[ConfigEnum.wireguard_port]}]
|
1059
|
-
elif type.transport in [ProxyTransport.shadowsocks]:
|
1060
|
-
options = [{'pport': hconfigs[ConfigEnum.shadowsocks2022_port]}]
|
1061
|
-
elif type.proto in [ProxyProto.ss]:
|
1062
|
-
options = [{'pport': 443}]
|
1063
|
-
elif type.proto == ProxyProto.tuic:
|
1064
|
-
options = [{'pport': hconfigs[ConfigEnum.tuic_port]}]
|
1065
|
-
elif type.proto == ProxyProto.hysteria2:
|
1066
|
-
options = [{'pport': hconfigs[ConfigEnum.hysteria_port]}]
|
1067
|
-
else:
|
1068
|
-
for t in (['http', 'tls'] if hconfigs[ConfigEnum.http_proxy_enable] else ['tls']):
|
1069
|
-
for port in hconfigs[ConfigEnum.http_ports if t == 'http' else ConfigEnum.tls_ports].split(','):
|
1070
|
-
phttp = port if t == 'http' else None
|
1071
|
-
ptls = port if t == 'tls' else None
|
1072
|
-
if phttp and len(allphttp) and phttp not in allphttp:
|
1073
|
-
continue
|
1074
|
-
if ptls and len(allptls) and ptls not in allptls:
|
1075
|
-
continue
|
1076
|
-
options.append({'phttp': phttp, 'ptls': ptls})
|
1077
|
-
|
1078
|
-
for opt in options:
|
1079
|
-
pinfo = make_proxy(hconfigs, type, d, **opt)
|
1080
|
-
if 'msg' not in pinfo:
|
1081
|
-
allp.append(pinfo)
|
1082
|
-
return allp
|
1083
|
-
|
1084
|
-
|
1085
|
-
class CustomEncoder(json.JSONEncoder):
|
1086
|
-
def default(self, obj):
|
1087
|
-
if isinstance(obj, IPv4Address) or isinstance(obj, IPv6Address):
|
1088
|
-
return str(obj)
|
1089
|
-
return super().default(obj)
|