hiddifypanel 10.85.0b21__py3-none-any.whl → 10.86.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +2 -2
- hiddifypanel/hutils/network/auto_ip_selector.py +19 -10
- hiddifypanel/hutils/network/net.py +25 -5
- hiddifypanel/hutils/proxy/clash.py +1 -1
- hiddifypanel/hutils/proxy/shared.py +118 -56
- hiddifypanel/hutils/proxy/xray.py +55 -40
- hiddifypanel/hutils/proxy/xrayjson.py +48 -28
- hiddifypanel/models/config.py +1 -1
- hiddifypanel/models/config_enum.py +4 -0
- hiddifypanel/models/domain.py +33 -8
- hiddifypanel/models/proxy.py +6 -2
- hiddifypanel/panel/admin/DomainAdmin.py +22 -25
- hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +13 -4
- hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +1 -1
- hiddifypanel/panel/custom_widgets.py +45 -0
- hiddifypanel/panel/init_db.py +102 -184
- hiddifypanel/panel/user/user.py +12 -12
- hiddifypanel/static/js/custom-rtl.js +1 -1
- hiddifypanel/templates/fake.html +11 -2
- hiddifypanel/templates/flaskadmin-layout.html +11 -9
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations/my/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +33 -0
- hiddifypanel/translations.i18n/en.json +19 -0
- hiddifypanel/translations.i18n/fa.json +19 -0
- hiddifypanel/translations.i18n/pt.json +19 -0
- hiddifypanel/translations.i18n/ru.json +19 -0
- hiddifypanel/translations.i18n/zh.json +19 -0
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b1.dist-info}/METADATA +1 -1
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b1.dist-info}/RECORD +43 -43
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b1.dist-info}/WHEEL +0 -0
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b1.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b1.dist-info}/licenses/LICENSE.md +0 -0
- {hiddifypanel-10.85.0b21.dist-info → hiddifypanel-10.86.0b1.dist-info}/top_level.txt +0 -0
hiddifypanel/panel/init_db.py
CHANGED
@@ -16,6 +16,13 @@ from hiddifypanel.database import db, db_execute
|
|
16
16
|
from loguru import logger
|
17
17
|
MAX_DB_VERSION = 120
|
18
18
|
|
19
|
+
def _v104(child_id):
|
20
|
+
set_hconfig(ConfigEnum.special_port,hconfig(ConfigEnum.reality_port))
|
21
|
+
set_hconfig(ConfigEnum.default_useragent_string,hutils.network.get_random_user_agent())
|
22
|
+
for d in Domain.query.filter(Domain.mode==DomainType.reality,Domain.child_id == child_id).all():
|
23
|
+
d.mode=DomainType.special_reality_tcp
|
24
|
+
set_hconfig(ConfigEnum.h2_enable,False)
|
25
|
+
db.session.bulk_save_objects(get_proxy_rows_v1())
|
19
26
|
|
20
27
|
def _v103(child_id):
|
21
28
|
|
@@ -33,12 +40,8 @@ BEGIN
|
|
33
40
|
|
34
41
|
DECLARE cur CURSOR FOR
|
35
42
|
SELECT jt.uuid, jt.usage FROM JSON_TABLE(
|
36
|
-
usage_data,
|
37
|
-
|
38
|
-
uuid CHAR(36) PATH '$.uuid',
|
39
|
-
`usage` BIGINT PATH '$.usage'
|
40
|
-
)
|
41
|
-
) AS jt;
|
43
|
+
usage_data, '$[*]' COLUMNS (
|
44
|
+
uuid CHAR(36) PATH '$.uuid', `usage` BIGINT PATH '$.usage')) AS jt;
|
42
45
|
|
43
46
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
44
47
|
SET cur_date = DATE(cur_time);
|
@@ -52,9 +55,7 @@ BEGIN
|
|
52
55
|
|
53
56
|
|
54
57
|
UPDATE `user`
|
55
|
-
SET current_usage = current_usage + u_usage,
|
56
|
-
last_online = cur_time,
|
57
|
-
start_date = CASE WHEN start_date IS NULL THEN cur_date ELSE start_date END
|
58
|
+
SET current_usage = current_usage + u_usage, last_online = cur_time, start_date = CASE WHEN start_date IS NULL THEN cur_date ELSE start_date END
|
58
59
|
WHERE uuid = u_uuid;
|
59
60
|
|
60
61
|
|
@@ -72,7 +73,7 @@ END
|
|
72
73
|
def _v101(child_id):
|
73
74
|
add_config_if_not_exist(ConfigEnum.path_xhttp, hutils.random.get_random_string(7, 15))
|
74
75
|
add_config_if_not_exist(ConfigEnum.xhttp_enable, False)
|
75
|
-
|
76
|
+
|
76
77
|
|
77
78
|
|
78
79
|
def _v97(child_id):
|
@@ -94,32 +95,17 @@ def _v97(child_id):
|
|
94
95
|
|
95
96
|
def _v96(child_id):
|
96
97
|
from sqlalchemy import func
|
97
|
-
result = (db.session.query(DailyUsage.child_id,
|
98
|
-
DailyUsage.admin_id,
|
99
|
-
DailyUsage.date,
|
100
|
-
func.max(DailyUsage.online).label('online'),
|
101
|
-
func.sum(DailyUsage.usage).label('usage'),
|
102
|
-
func.count(DailyUsage.usage).label('count'),
|
103
|
-
)
|
98
|
+
result = (db.session.query(DailyUsage.child_id, DailyUsage.admin_id, DailyUsage.date, func.max(DailyUsage.online).label('online'), func.sum(DailyUsage.usage).label('usage'), func.count(DailyUsage.usage).label('count'), )
|
104
99
|
.group_by(DailyUsage.child_id, DailyUsage.admin_id, DailyUsage.date)
|
105
|
-
.all()
|
106
|
-
)
|
100
|
+
.all())
|
107
101
|
|
108
102
|
for r in result:
|
109
103
|
if r.count > 1:
|
110
104
|
# Delete existing records for this group
|
111
|
-
db.session.query(DailyUsage).filter(DailyUsage.child_id == r.child_id,
|
112
|
-
DailyUsage.admin_id == r.admin_id,
|
113
|
-
DailyUsage.date == r.date
|
114
|
-
).delete()
|
105
|
+
db.session.query(DailyUsage).filter(DailyUsage.child_id == r.child_id, DailyUsage.admin_id == r.admin_id, DailyUsage.date == r.date).delete()
|
115
106
|
|
116
107
|
# Add the aggregated record
|
117
|
-
new_record = DailyUsage(child_id=r.child_id,
|
118
|
-
admin_id=r.admin_id,
|
119
|
-
date=r.date,
|
120
|
-
online=r.online,
|
121
|
-
usage=r.usage
|
122
|
-
)
|
108
|
+
new_record = DailyUsage(child_id=r.child_id, admin_id=r.admin_id, date=r.date, online=r.online, usage=r.usage)
|
123
109
|
db.session.add(new_record)
|
124
110
|
|
125
111
|
# Commit the changes to the database
|
@@ -140,8 +126,7 @@ def _v92(child_id):
|
|
140
126
|
|
141
127
|
|
142
128
|
def _v89(child_id):
|
143
|
-
set_hconfig(ConfigEnum.path_xhttp,
|
144
|
-
hutils.random.get_random_string(7, 15))
|
129
|
+
set_hconfig(ConfigEnum.path_xhttp, hutils.random.get_random_string(7, 15))
|
145
130
|
set_hconfig(ConfigEnum.xhttp_enable, False)
|
146
131
|
pass
|
147
132
|
|
@@ -163,8 +148,7 @@ def _v85(child_id):
|
|
163
148
|
def _v84(child_id):
|
164
149
|
# the 2022-blake3-chacha20-poly1305 encryption method doesn't support multiuser config
|
165
150
|
if hconfig(ConfigEnum.shadowsocks2022_method) == '2022-blake3-chacha20-poly1305':
|
166
|
-
set_hconfig(ConfigEnum.shadowsocks2022_method,
|
167
|
-
'2022-blake3-aes-256-gcm')
|
151
|
+
set_hconfig(ConfigEnum.shadowsocks2022_method, '2022-blake3-aes-256-gcm')
|
168
152
|
|
169
153
|
|
170
154
|
def _v83(child_id):
|
@@ -209,12 +193,10 @@ def _v74(child_id):
|
|
209
193
|
set_hconfig(ConfigEnum.ws_enable, False)
|
210
194
|
set_hconfig(ConfigEnum.grpc_enable, True)
|
211
195
|
set_hconfig(ConfigEnum.httpupgrade_enable, True)
|
212
|
-
set_hconfig(ConfigEnum.shadowsocks2022_port,
|
213
|
-
hutils.random.get_random_unused_port())
|
196
|
+
set_hconfig(ConfigEnum.shadowsocks2022_port, hutils.random.get_random_unused_port())
|
214
197
|
set_hconfig(ConfigEnum.shadowsocks2022_method, "2022-blake3-aes-256-gcm")
|
215
198
|
set_hconfig(ConfigEnum.shadowsocks2022_enable, False)
|
216
|
-
set_hconfig(ConfigEnum.path_httpupgrade,
|
217
|
-
hutils.random.get_random_string(7, 15))
|
199
|
+
set_hconfig(ConfigEnum.path_httpupgrade, hutils.random.get_random_string(7, 15))
|
218
200
|
db.session.bulk_save_objects(get_proxy_rows_v1())
|
219
201
|
|
220
202
|
for i in range(1, 10):
|
@@ -226,14 +208,10 @@ def _v74(child_id):
|
|
226
208
|
|
227
209
|
|
228
210
|
def _v71(child_id):
|
229
|
-
add_config_if_not_exist(ConfigEnum.tuic_port,
|
230
|
-
|
231
|
-
add_config_if_not_exist(ConfigEnum.
|
232
|
-
|
233
|
-
add_config_if_not_exist(ConfigEnum.ssh_server_port,
|
234
|
-
hutils.random.get_random_unused_port())
|
235
|
-
add_config_if_not_exist(ConfigEnum.wireguard_port,
|
236
|
-
hutils.random.get_random_unused_port())
|
211
|
+
add_config_if_not_exist(ConfigEnum.tuic_port, hutils.random.get_random_unused_port())
|
212
|
+
add_config_if_not_exist(ConfigEnum.hysteria_port, hutils.random.get_random_unused_port())
|
213
|
+
add_config_if_not_exist(ConfigEnum.ssh_server_port, hutils.random.get_random_unused_port())
|
214
|
+
add_config_if_not_exist(ConfigEnum.wireguard_port, hutils.random.get_random_unused_port())
|
237
215
|
|
238
216
|
|
239
217
|
def _v70(child_id):
|
@@ -254,8 +232,7 @@ def _v70(child_id):
|
|
254
232
|
def _v69():
|
255
233
|
db.session.bulk_save_objects(get_proxy_rows_v1())
|
256
234
|
add_config_if_not_exist(ConfigEnum.wireguard_enable, True)
|
257
|
-
add_config_if_not_exist(ConfigEnum.wireguard_port,
|
258
|
-
hutils.random.get_random_unused_port())
|
235
|
+
add_config_if_not_exist(ConfigEnum.wireguard_port, hutils.random.get_random_unused_port())
|
259
236
|
add_config_if_not_exist(ConfigEnum.wireguard_ipv4, "10.90.0.1")
|
260
237
|
add_config_if_not_exist(ConfigEnum.wireguard_ipv6, "fd42:42:90::1")
|
261
238
|
wg_pk, wg_pub, _ = hutils.crypto.get_wg_private_public_psk_pair()
|
@@ -279,8 +256,7 @@ def _v65():
|
|
279
256
|
|
280
257
|
def _v63():
|
281
258
|
add_config_if_not_exist(ConfigEnum.hysteria_enable, True)
|
282
|
-
add_config_if_not_exist(ConfigEnum.hysteria_port,
|
283
|
-
hutils.random.get_random_unused_port())
|
259
|
+
add_config_if_not_exist(ConfigEnum.hysteria_port, hutils.random.get_random_unused_port())
|
284
260
|
add_config_if_not_exist(ConfigEnum.hysteria_obfs_enable, True)
|
285
261
|
add_config_if_not_exist(ConfigEnum.hysteria_up_mbps, "150")
|
286
262
|
add_config_if_not_exist(ConfigEnum.hysteria_down_mbps, "300")
|
@@ -301,10 +277,8 @@ def _v61():
|
|
301
277
|
|
302
278
|
|
303
279
|
def _v60():
|
304
|
-
add_config_if_not_exist(ConfigEnum.proxy_path_admin,
|
305
|
-
|
306
|
-
add_config_if_not_exist(ConfigEnum.proxy_path_client,
|
307
|
-
hutils.random.get_random_string())
|
280
|
+
add_config_if_not_exist(ConfigEnum.proxy_path_admin, hutils.random.get_random_string())
|
281
|
+
add_config_if_not_exist(ConfigEnum.proxy_path_client, hutils.random.get_random_string())
|
308
282
|
|
309
283
|
|
310
284
|
def _v59():
|
@@ -324,8 +298,7 @@ def _v57():
|
|
324
298
|
|
325
299
|
|
326
300
|
def _v56():
|
327
|
-
set_hconfig(ConfigEnum.reality_port,
|
328
|
-
hutils.random.get_random_unused_port())
|
301
|
+
set_hconfig(ConfigEnum.reality_port, hutils.random.get_random_unused_port())
|
329
302
|
|
330
303
|
|
331
304
|
def _v55():
|
@@ -336,10 +309,8 @@ def _v55():
|
|
336
309
|
set_hconfig(ConfigEnum.tuic_enable, True)
|
337
310
|
set_hconfig(ConfigEnum.hysteria_enable, True)
|
338
311
|
Proxy.query.filter(Proxy.proto.in_(["tuic", "hysteria2", "hysteria"])).delete()
|
339
|
-
db.session.add(Proxy(l3='tls', transport='custom',
|
340
|
-
|
341
|
-
db.session.add(Proxy(l3='tls', transport='custom', cdn='direct',
|
342
|
-
proto='hysteria2', enable=True, name="Hysteria2"))
|
312
|
+
db.session.add(Proxy(l3='tls', transport='custom', cdn='direct', proto='tuic', enable=True, name="TUIC"))
|
313
|
+
db.session.add(Proxy(l3='tls', transport='custom', cdn='direct', proto='hysteria2', enable=True, name="Hysteria2"))
|
343
314
|
|
344
315
|
|
345
316
|
def _v52():
|
@@ -374,11 +345,9 @@ def _v47():
|
|
374
345
|
def _v45():
|
375
346
|
|
376
347
|
if not Proxy.query.filter(Proxy.name == "SSH").first():
|
377
|
-
db.session.add(Proxy(l3='ssh', transport='ssh',
|
378
|
-
cdn='direct', proto='ssh', enable=True, name="SSH"))
|
348
|
+
db.session.add(Proxy(l3='ssh', transport='ssh', cdn='direct', proto='ssh', enable=True, name="SSH"))
|
379
349
|
|
380
|
-
add_config_if_not_exist(ConfigEnum.ssh_server_port,
|
381
|
-
hutils.random.get_random_unused_port())
|
350
|
+
add_config_if_not_exist(ConfigEnum.ssh_server_port, hutils.random.get_random_unused_port())
|
382
351
|
add_config_if_not_exist(ConfigEnum.ssh_server_enable, False)
|
383
352
|
# def _v43():
|
384
353
|
# if not (Domain.query.filter(Domain.domain==hconfig(ConfigEnum.domain_fronting_domain)).first()):
|
@@ -398,8 +367,7 @@ def _v42():
|
|
398
367
|
def _v41():
|
399
368
|
add_config_if_not_exist(ConfigEnum.core_type, "xray")
|
400
369
|
if not (Domain.query.filter(Domain.domain == hconfig(ConfigEnum.reality_fallback_domain)).first()):
|
401
|
-
db.session.add(Domain(domain=hconfig(ConfigEnum.reality_fallback_domain),
|
402
|
-
servernames=hconfig(ConfigEnum.reality_server_names), mode=DomainType.reality))
|
370
|
+
db.session.add(Domain(domain=hconfig(ConfigEnum.reality_fallback_domain), servernames=hconfig(ConfigEnum.reality_server_names), mode=DomainType.reality))
|
403
371
|
|
404
372
|
|
405
373
|
def _v38():
|
@@ -418,8 +386,7 @@ def _v33():
|
|
418
386
|
|
419
387
|
|
420
388
|
def _v31():
|
421
|
-
add_config_if_not_exist(ConfigEnum.reality_short_ids,
|
422
|
-
uuid.uuid4().hex[0:random.randint(1, 8) * 2])
|
389
|
+
add_config_if_not_exist(ConfigEnum.reality_short_ids, uuid.uuid4().hex[0:random.randint(1, 8) * 2])
|
423
390
|
key_pair = hutils.crypto.generate_x25519_keys()
|
424
391
|
add_config_if_not_exist(ConfigEnum.reality_private_key, key_pair['private_key'])
|
425
392
|
add_config_if_not_exist(ConfigEnum.reality_public_key, key_pair['public_key'])
|
@@ -505,55 +472,11 @@ def _v1():
|
|
505
472
|
rnd_domains = hutils.network.get_random_domains(5)
|
506
473
|
|
507
474
|
data = [
|
508
|
-
StrConfig(key=ConfigEnum.db_version, value=1),
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
StrConfig(key=ConfigEnum.http_ports, value="80"),
|
514
|
-
StrConfig(key=ConfigEnum.tls_ports, value="443"),
|
515
|
-
BoolConfig(key=ConfigEnum.first_setup, value=True),
|
516
|
-
StrConfig(key=ConfigEnum.decoy_domain,
|
517
|
-
value=hutils.network.get_random_decoy_domain()),
|
518
|
-
StrConfig(key=ConfigEnum.proxy_path,
|
519
|
-
value=hutils.random.get_random_string()),
|
520
|
-
BoolConfig(key=ConfigEnum.firewall, value=False),
|
521
|
-
BoolConfig(key=ConfigEnum.netdata, value=True),
|
522
|
-
StrConfig(key=ConfigEnum.lang, value='en'),
|
523
|
-
BoolConfig(key=ConfigEnum.block_iran_sites, value=True),
|
524
|
-
BoolConfig(key=ConfigEnum.allow_invalid_sni, value=True),
|
525
|
-
BoolConfig(key=ConfigEnum.kcp_enable, value=False),
|
526
|
-
StrConfig(key=ConfigEnum.kcp_ports, value="88"),
|
527
|
-
BoolConfig(key=ConfigEnum.auto_update, value=os.environ.get('HIDDIFY_DISABLE_UPDATE',"").lower() not in {'1','true'}),
|
528
|
-
BoolConfig(key=ConfigEnum.speed_test, value=True),
|
529
|
-
BoolConfig(key=ConfigEnum.only_ipv4, value=False),
|
530
|
-
BoolConfig(key=ConfigEnum.vmess_enable, value=True),
|
531
|
-
BoolConfig(key=ConfigEnum.http_proxy_enable, value=True),
|
532
|
-
StrConfig(key=ConfigEnum.shared_secret, value=str(uuid.uuid4())),
|
533
|
-
BoolConfig(key=ConfigEnum.telegram_enable, value=False),
|
534
|
-
# StrConfig(key=ConfigEnum.telegram_secret,value=uuid.uuid4().hex),
|
535
|
-
StrConfig(key=ConfigEnum.telegram_adtag, value=""),
|
536
|
-
StrConfig(key=ConfigEnum.telegram_fakedomain, value=rnd_domains[1]),
|
537
|
-
BoolConfig(key=ConfigEnum.ssfaketls_enable, value=False),
|
538
|
-
# StrConfig(key=ConfigEnum.ssfaketls_secret,value=str(uuid.uuid4())),
|
539
|
-
StrConfig(key=ConfigEnum.ssfaketls_fakedomain, value=rnd_domains[2]),
|
540
|
-
BoolConfig(key=ConfigEnum.shadowtls_enable, value=False),
|
541
|
-
# StrConfig(key=ConfigEnum.shadowtls_secret,value=str(uuid.uuid4())),
|
542
|
-
StrConfig(key=ConfigEnum.shadowtls_fakedomain, value=rnd_domains[3]),
|
543
|
-
|
544
|
-
BoolConfig(key=ConfigEnum.ssr_enable, value=False),
|
545
|
-
# StrConfig(key=ConfigEnum.ssr_secret,value=str(uuid.uuid4())),
|
546
|
-
StrConfig(key=ConfigEnum.ssr_fakedomain, value=rnd_domains[4]),
|
547
|
-
|
548
|
-
# BoolConfig(key=ConfigEnum.tuic_enable, value=False),
|
549
|
-
# StrConfig(key=ConfigEnum.tuic_port, value=3048),
|
550
|
-
|
551
|
-
BoolConfig(key=ConfigEnum.domain_fronting_tls_enable, value=False),
|
552
|
-
BoolConfig(key=ConfigEnum.domain_fronting_http_enable, value=False),
|
553
|
-
StrConfig(key=ConfigEnum.domain_fronting_domain, value=""),
|
554
|
-
|
555
|
-
# BoolConfig(key=ConfigEnum.torrent_block,value=False),
|
556
|
-
|
475
|
+
StrConfig(key=ConfigEnum.db_version, value=1), User(name="default", usage_limit_GB=3000, package_days=3650, mode=UserMode.weekly), Domain(domain=external_ip + ".sslip.io", mode=DomainType.direct), StrConfig(key=ConfigEnum.admin_secret, value=uuid.uuid4()), StrConfig(key=ConfigEnum.http_ports, value="80"), StrConfig(key=ConfigEnum.tls_ports, value="443"), BoolConfig(key=ConfigEnum.first_setup, value=True), StrConfig(key=ConfigEnum.decoy_domain, value=hutils.network.get_random_decoy_domain()), StrConfig(key=ConfigEnum.proxy_path, value=hutils.random.get_random_string()), BoolConfig(key=ConfigEnum.firewall, value=False), BoolConfig(key=ConfigEnum.netdata, value=True), StrConfig(key=ConfigEnum.lang, value='en'), BoolConfig(key=ConfigEnum.block_iran_sites, value=True), BoolConfig(key=ConfigEnum.allow_invalid_sni, value=True), BoolConfig(key=ConfigEnum.kcp_enable, value=False), StrConfig(key=ConfigEnum.kcp_ports, value="88"), BoolConfig(key=ConfigEnum.auto_update, value=os.environ.get('HIDDIFY_DISABLE_UPDATE',"").lower() not in {'1','true'}), BoolConfig(key=ConfigEnum.speed_test, value=True), BoolConfig(key=ConfigEnum.only_ipv4, value=False), BoolConfig(key=ConfigEnum.vmess_enable, value=True), BoolConfig(key=ConfigEnum.http_proxy_enable, value=True), StrConfig(key=ConfigEnum.shared_secret, value=str(uuid.uuid4())), BoolConfig(key=ConfigEnum.telegram_enable, value=False), # StrConfig(key=ConfigEnum.telegram_secret,value=uuid.uuid4().hex), StrConfig(key=ConfigEnum.telegram_adtag, value=""), StrConfig(key=ConfigEnum.telegram_fakedomain, value=rnd_domains[1]), BoolConfig(key=ConfigEnum.ssfaketls_enable, value=False), # StrConfig(key=ConfigEnum.ssfaketls_secret,value=str(uuid.uuid4())), StrConfig(key=ConfigEnum.ssfaketls_fakedomain, value=rnd_domains[2]), BoolConfig(key=ConfigEnum.shadowtls_enable, value=False), # StrConfig(key=ConfigEnum.shadowtls_secret,value=str(uuid.uuid4())), StrConfig(key=ConfigEnum.shadowtls_fakedomain, value=rnd_domains[3]),
|
476
|
+
BoolConfig(key=ConfigEnum.ssr_enable, value=False), # StrConfig(key=ConfigEnum.ssr_secret,value=str(uuid.uuid4())), StrConfig(key=ConfigEnum.ssr_fakedomain, value=rnd_domains[4]),
|
477
|
+
# BoolConfig(key=ConfigEnum.tuic_enable, value=False), # StrConfig(key=ConfigEnum.tuic_port, value=3048),
|
478
|
+
BoolConfig(key=ConfigEnum.domain_fronting_tls_enable, value=False), BoolConfig(key=ConfigEnum.domain_fronting_http_enable, value=False), StrConfig(key=ConfigEnum.domain_fronting_domain, value=""),
|
479
|
+
# BoolConfig(key=ConfigEnum.torrent_block,value=False),
|
557
480
|
*get_proxy_rows_v1()
|
558
481
|
]
|
559
482
|
# fake_domains=['speedtest.net']
|
@@ -607,17 +530,17 @@ def _v10():
|
|
607
530
|
|
608
531
|
def get_proxy_rows_v1():
|
609
532
|
rows = list(make_proxy_rows([
|
610
|
-
"h2 direct vless",
|
611
|
-
"XTLS direct vless",
|
612
|
-
"WS direct vless",
|
613
|
-
"WS direct trojan",
|
614
|
-
"WS direct vmess",
|
615
|
-
"httpupgrade direct vless",
|
616
|
-
# "httpupgrade direct trojan",
|
617
|
-
"httpupgrade direct vmess",
|
618
|
-
"xhttp direct vless",
|
619
|
-
"xhttp direct trojan",
|
620
|
-
"xhttp direct vmess",
|
533
|
+
"h2 direct vless",
|
534
|
+
# "XTLS direct vless",
|
535
|
+
"WS direct vless",
|
536
|
+
"WS direct trojan",
|
537
|
+
"WS direct vmess",
|
538
|
+
"httpupgrade direct vless",
|
539
|
+
# "httpupgrade direct trojan",
|
540
|
+
"httpupgrade direct vmess",
|
541
|
+
"xhttp direct vless",
|
542
|
+
# "xhttp direct trojan",
|
543
|
+
"xhttp direct vmess",
|
621
544
|
"tcp direct vless",
|
622
545
|
"tcp direct trojan",
|
623
546
|
"tcp direct vmess",
|
@@ -627,18 +550,18 @@ def get_proxy_rows_v1():
|
|
627
550
|
"faketls direct ss",
|
628
551
|
"WS direct v2ray",
|
629
552
|
"h2 relay vless",
|
630
|
-
"XTLS relay vless",
|
553
|
+
# "XTLS relay vless",
|
631
554
|
"WS relay vless",
|
632
555
|
"WS relay trojan",
|
633
556
|
"WS relay vmess",
|
634
557
|
"httpupgrade relay vless",
|
635
558
|
# "httpupgrade relay trojan",
|
636
559
|
"httpupgrade relay vmess",
|
637
|
-
|
560
|
+
|
638
561
|
"xhttp relay vless",
|
639
|
-
"xhttp relay trojan",
|
562
|
+
# "xhttp relay trojan",
|
640
563
|
"xhttp relay vmess",
|
641
|
-
|
564
|
+
|
642
565
|
"tcp relay vless",
|
643
566
|
"tcp relay trojan",
|
644
567
|
"tcp relay vmess",
|
@@ -647,7 +570,7 @@ def get_proxy_rows_v1():
|
|
647
570
|
"grpc relay vmess",
|
648
571
|
"faketls relay ss",
|
649
572
|
"WS relay v2ray",
|
650
|
-
|
573
|
+
|
651
574
|
# "restls1_2 direct ss",
|
652
575
|
# "restls1_3 direct ss",
|
653
576
|
# "tcp direct ssr",
|
@@ -658,43 +581,31 @@ def get_proxy_rows_v1():
|
|
658
581
|
"httpupgrade CDN vless",
|
659
582
|
# "httpupgrade CDN trojan",
|
660
583
|
"httpupgrade CDN vmess",
|
661
|
-
|
584
|
+
|
662
585
|
"xhttp CDN vless",
|
663
|
-
"xhttp CDN trojan",
|
586
|
+
# "xhttp CDN trojan",
|
664
587
|
"xhttp CDN vmess",
|
665
|
-
|
588
|
+
|
589
|
+
|
666
590
|
"grpc CDN vless",
|
667
591
|
"grpc CDN trojan",
|
668
592
|
"grpc CDN vmess",
|
669
|
-
|
670
|
-
]
|
671
|
-
))
|
672
|
-
rows.append(Proxy(l3=ProxyL3.custom, transport=ProxyTransport.shadowsocks,
|
673
|
-
|
674
|
-
rows.append(Proxy(l3=ProxyL3.
|
675
|
-
|
676
|
-
|
677
|
-
rows.append(Proxy(l3=
|
678
|
-
|
679
|
-
rows.append(Proxy(l3=
|
680
|
-
|
681
|
-
rows.append(Proxy(l3='
|
682
|
-
|
683
|
-
rows.append(Proxy(l3=
|
684
|
-
|
685
|
-
|
686
|
-
rows.append(Proxy(l3='tls', transport='custom', cdn='direct',
|
687
|
-
proto='tuic', enable=True, name="TUIC"))
|
688
|
-
rows.append(Proxy(l3='tls', transport='custom', cdn='relay',
|
689
|
-
proto='tuic', enable=True, name="TUIC Relay"))
|
690
|
-
rows.append(Proxy(l3='tls', transport='custom', cdn='direct',
|
691
|
-
proto='hysteria2', enable=True, name="Hysteria2"))
|
692
|
-
rows.append(Proxy(l3='tls', transport='custom', cdn='relay',
|
693
|
-
proto='hysteria2', enable=True, name="Hysteria2 Relay"))
|
694
|
-
rows.append(Proxy(l3=ProxyL3.udp, transport=ProxyTransport.custom,
|
695
|
-
cdn=ProxyCDN.direct, proto=ProxyProto.wireguard, enable=True, name="WireGuard"))
|
696
|
-
rows.append(Proxy(l3=ProxyL3.udp, transport=ProxyTransport.custom, cdn=ProxyCDN.relay,
|
697
|
-
proto=ProxyProto.wireguard, enable=True, name="WireGuard Relay"))
|
593
|
+
|
594
|
+
]))
|
595
|
+
rows.append(Proxy(l3=ProxyL3.custom, transport=ProxyTransport.shadowsocks, cdn='direct', proto='ss', enable=True, name="ShadowSocks2022"))
|
596
|
+
rows.append(Proxy(l3=ProxyL3.custom, transport=ProxyTransport.shadowsocks, cdn='relay', proto='ss', enable=True, name="ShadowSocks2022 Relay"))
|
597
|
+
|
598
|
+
rows.append(Proxy(l3=ProxyL3.tls, transport=ProxyTransport.shadowtls, cdn='direct', proto='ss', enable=True, name="ShadowTLS"))
|
599
|
+
rows.append(Proxy(l3=ProxyL3.tls, transport=ProxyTransport.shadowtls, cdn='relay', proto='ss', enable=True, name="ShadowTLS Relay"))
|
600
|
+
rows.append(Proxy(l3='ssh', transport='ssh', cdn='direct', proto='ssh', enable=True, name="SSH"))
|
601
|
+
rows.append(Proxy(l3='ssh', transport=ProxyTransport.ssh, cdn=ProxyCDN.relay, proto=ProxyProto.ssh, enable=True, name="SSH Relay"))
|
602
|
+
|
603
|
+
rows.append(Proxy(l3='tls', transport='custom', cdn='direct', proto='tuic', enable=True, name="TUIC"))
|
604
|
+
rows.append(Proxy(l3='tls', transport='custom', cdn='relay', proto='tuic', enable=True, name="TUIC Relay"))
|
605
|
+
rows.append(Proxy(l3='tls', transport='custom', cdn='direct', proto='hysteria2', enable=True, name="Hysteria2"))
|
606
|
+
rows.append(Proxy(l3='tls', transport='custom', cdn='relay', proto='hysteria2', enable=True, name="Hysteria2 Relay"))
|
607
|
+
rows.append(Proxy(l3=ProxyL3.udp, transport=ProxyTransport.custom, cdn=ProxyCDN.direct, proto=ProxyProto.wireguard, enable=True, name="WireGuard"))
|
608
|
+
rows.append(Proxy(l3=ProxyL3.udp, transport=ProxyTransport.custom, cdn=ProxyCDN.relay, proto=ProxyProto.wireguard, enable=True, name="WireGuard Relay"))
|
698
609
|
for p in rows:
|
699
610
|
is_exist = Proxy.query.filter(Proxy.name == p.name).first() or Proxy.query.filter(
|
700
611
|
Proxy.l3 == p.l3, Proxy.transport == p.transport, Proxy.cdn == p.cdn, Proxy.proto == p.proto).first()
|
@@ -703,7 +614,7 @@ def get_proxy_rows_v1():
|
|
703
614
|
|
704
615
|
|
705
616
|
def make_proxy_rows(cfgs):
|
706
|
-
# "h3_quic",
|
617
|
+
# "h3_quic",
|
707
618
|
for l3 in [ProxyL3.h3_quic, "tls_h2", "tls", "http", "reality"]:
|
708
619
|
for c in cfgs:
|
709
620
|
transport, cdn, proto = c.split(" ")
|
@@ -731,7 +642,26 @@ def make_proxy_rows(cfgs):
|
|
731
642
|
name = f'{l3} {c}'
|
732
643
|
# is_exist = Proxy.query.filter(Proxy.name == name).first() or Proxy.query.filter( # Proxy.l3 == l3, Proxy.transport == transport, Proxy.cdn == cdn, Proxy.proto == proto).first()
|
733
644
|
# if not is_exist:
|
734
|
-
|
645
|
+
params_list=[('',{})]
|
646
|
+
|
647
|
+
if transport=="xhttp" and l3 != "reality":
|
648
|
+
params_list=[]
|
649
|
+
# for up in ['http/1.1"','h2','h3']:
|
650
|
+
if l3=="http":
|
651
|
+
alpn=['http/1.1']
|
652
|
+
else:
|
653
|
+
alpns=['http/1.1','h2','h3']
|
654
|
+
for dl in alpns:
|
655
|
+
name_postfix=f' dl={dl}'.replace("http/1.1",'h1')
|
656
|
+
params={
|
657
|
+
'download':{
|
658
|
+
'alpn':f'{dl}'
|
659
|
+
}
|
660
|
+
}
|
661
|
+
params_list.append((name_postfix,params))
|
662
|
+
|
663
|
+
for name_postfix,params in params_list:
|
664
|
+
yield Proxy(l3=l3, transport=transport, cdn=cdn, proto=proto, enable=enable, name=name+name_postfix, params=params)
|
735
665
|
|
736
666
|
|
737
667
|
def add_config_if_not_exist(key: "ConfigEnum", val: str | int, child_id: int | None = None):
|
@@ -762,8 +692,7 @@ def execute(query: str):
|
|
762
692
|
|
763
693
|
def add_new_enum_values():
|
764
694
|
columns = [
|
765
|
-
Proxy.l3, Proxy.proto, Proxy.cdn, Proxy.transport,
|
766
|
-
User.mode, Domain.mode, BoolConfig.key, StrConfig.key
|
695
|
+
Proxy.l3, Proxy.proto, Proxy.cdn, Proxy.transport, User.mode, Domain.mode, BoolConfig.key, StrConfig.key
|
767
696
|
]
|
768
697
|
from sqlalchemy import text
|
769
698
|
for col in columns:
|
@@ -798,7 +727,8 @@ def add_new_enum_values():
|
|
798
727
|
# enumstr = ','.join([f"'{a}'" for a in [*existing_values, *old_values]])
|
799
728
|
enumstr = ','.join([f"'{a}'" for a in [*existing_values]])
|
800
729
|
expired_enumstr = ','.join([f"'{a}'" for a in [*old_values]])
|
801
|
-
|
730
|
+
if expired_enumstr:
|
731
|
+
db_execute(f"delete from {table_name} where `{column_name}` in ({expired_enumstr});", commit=True)
|
802
732
|
db_execute(f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});", commit=True)
|
803
733
|
|
804
734
|
|
@@ -839,18 +769,7 @@ def upgrade_database():
|
|
839
769
|
logger.info(f"importing configs from {newest_file}")
|
840
770
|
json_data = json.load(f)
|
841
771
|
from hiddifypanel.panel import hiddify
|
842
|
-
hiddify.set_db_from_json(json_data,
|
843
|
-
set_users=True,
|
844
|
-
set_domains=True,
|
845
|
-
remove_domains=True,
|
846
|
-
remove_users=True,
|
847
|
-
set_settings=True,
|
848
|
-
override_unique_id=True,
|
849
|
-
set_admins=True,
|
850
|
-
override_root_admin=True,
|
851
|
-
override_child_unique_id=0,
|
852
|
-
replace_owner_admin=True
|
853
|
-
)
|
772
|
+
hiddify.set_db_from_json(json_data, set_users=True, set_domains=True, remove_domains=True, remove_users=True, set_settings=True, override_unique_id=True, set_admins=True, override_root_admin=True, override_child_unique_id=0, replace_owner_admin=True)
|
854
773
|
db_version = int([d['value'] for d in json_data['hconfigs'] if d['key'] == "db_version"][0])
|
855
774
|
os.rename(sqlite_db, sqlite_db + ".old")
|
856
775
|
set_hconfig(ConfigEnum.db_version, db_version, commit=True)
|
@@ -860,7 +779,7 @@ def upgrade_database():
|
|
860
779
|
|
861
780
|
def init_db():
|
862
781
|
# set_hconfig(ConfigEnum.db_version, 71)
|
863
|
-
# set_hconfig(ConfigEnum.db_version,
|
782
|
+
# set_hconfig(ConfigEnum.db_version,103)
|
864
783
|
db_version = current_db_version()
|
865
784
|
if db_version == latest_db_version():
|
866
785
|
return
|
@@ -915,8 +834,7 @@ def init_db():
|
|
915
834
|
|
916
835
|
db_version = ver
|
917
836
|
db.session.commit()
|
918
|
-
set_hconfig(ConfigEnum.db_version, db_version,
|
919
|
-
child_id=child.id, commit=False)
|
837
|
+
set_hconfig(ConfigEnum.db_version, db_version, child_id=child.id, commit=False)
|
920
838
|
|
921
839
|
db.session.commit()
|
922
840
|
g.child = Child.by_id(0)
|
hiddifypanel/panel/user/user.py
CHANGED
@@ -332,22 +332,22 @@ def get_domain_information(no_domain=False, filter_domain=None, alternative=None
|
|
332
332
|
domains = db_domain.show_domains or Domain.query.filter(Domain.sub_link_only != True).all()
|
333
333
|
|
334
334
|
has_auto_cdn = False
|
335
|
-
for d in domains:
|
336
|
-
db.session.expunge(d)
|
337
|
-
d.has_auto_ip = False
|
338
|
-
if d.mode == DomainType.auto_cdn_ip or d.cdn_ip:
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
335
|
+
# for d in domains:
|
336
|
+
# db.session.expunge(d)
|
337
|
+
# d.has_auto_ip = False
|
338
|
+
# if d.mode == DomainType.auto_cdn_ip or d.cdn_ip:
|
339
|
+
# has_auto_cdn = True
|
340
|
+
# d.has_auto_ip = d.mode == DomainType.auto_cdn_ip or (
|
341
|
+
# d.cdn_ip and "MTN" in d.cdn_ip)
|
342
|
+
# d.cdn_ip = hutils.network.auto_ip_selector.get_clean_ip(
|
343
|
+
# d.cdn_ip, d.mode == DomainType.auto_cdn_ip, default_asn)
|
344
344
|
# print("autocdn ip mode ", d.cdn_ip)
|
345
|
-
if "*" in d.domain:
|
346
|
-
|
345
|
+
# if "*" in d.domain:
|
346
|
+
# d.domain = d.domain.replace("*", hutils.random.get_random_string(5, 15))
|
347
347
|
|
348
348
|
if len(domains) == 0:
|
349
349
|
domains = [Domain(id=0, domain=alternative, mode=DomainType.direct, cdn_ip='', show_domains=[], child_id=0)]
|
350
|
-
domains[0].has_auto_ip = True
|
350
|
+
# domains[0].has_auto_ip = True
|
351
351
|
|
352
352
|
return domains, db_domain, has_auto_cdn
|
353
353
|
|
@@ -13,7 +13,7 @@ function ConvertNumberToPersion(elemnt) {
|
|
13
13
|
|
14
14
|
function traverse(el) {
|
15
15
|
// console.log(el.tagName)
|
16
|
-
if (el.tagName == "PRE" || el.tagName == "STYLE" || el.tagName == "SCRIPT" || el.tagName == "INPUT" || el.tagName == "TEXTAREA") return
|
16
|
+
if (el==undefined||el.tagName == "PRE" || el.tagName == "STYLE" || el.tagName == "SCRIPT" || el.tagName == "INPUT" || el.tagName == "TEXTAREA") return
|
17
17
|
if (el.nodeType == 3 && el.data != undefined) {
|
18
18
|
for (const key in replace) {
|
19
19
|
el.data = el.data.replace(key, replace[key])
|
hiddifypanel/templates/fake.html
CHANGED
@@ -48,6 +48,8 @@
|
|
48
48
|
{{_("config.reality_public_key.description")}}
|
49
49
|
{{_("config.reality_port.label")}}
|
50
50
|
{{_("config.reality_port.description")}}
|
51
|
+
{{_("config.special_port.label")}}
|
52
|
+
{{_("config.special_port.description")}}
|
51
53
|
{{_("config.restls1_2_domain.label")}}
|
52
54
|
{{_("config.restls1_2_domain.description")}}
|
53
55
|
{{_("config.restls1_3_domain.label")}}
|
@@ -90,6 +92,10 @@
|
|
90
92
|
{{_("config.admin_lang.description")}}
|
91
93
|
{{_("config.admin_secret.label")}}
|
92
94
|
{{_("config.admin_secret.description")}}
|
95
|
+
{{_("config.default_useragent_string.label")}}
|
96
|
+
{{_("config.default_useragent_string.description")}}
|
97
|
+
{{_("config.use_ip_in_config.label")}}
|
98
|
+
{{_("config.use_ip_in_config.description")}}
|
93
99
|
{{_("config.tls_ports.label")}}
|
94
100
|
{{_("config.tls_ports.description")}}
|
95
101
|
{{_("config.tls_fragment_enable.label")}}
|
@@ -324,10 +330,13 @@
|
|
324
330
|
{{_("cdn")}}
|
325
331
|
{{_("auto_cdn_ip")}}
|
326
332
|
{{_("relay")}}
|
327
|
-
{{_("reality")}}
|
328
|
-
{{_("old_xtls_direct")}}
|
329
333
|
{{_("worker")}}
|
330
334
|
{{_("fake")}}
|
335
|
+
{{_("reality")}}
|
336
|
+
{{_("special_reality_tcp")}}
|
337
|
+
{{_("special_reality_xhttp")}}
|
338
|
+
{{_("special_reality_grpc")}}
|
339
|
+
{{_("old_xtls_direct")}}
|
331
340
|
|
332
341
|
{{_("no_reset")}}
|
333
342
|
{{_("monthly")}}
|
@@ -37,12 +37,12 @@
|
|
37
37
|
{% endfor %}
|
38
38
|
{% endif %}
|
39
39
|
<!-- Include the default stylesheet -->
|
40
|
-
<link rel="stylesheet" href="https://unpkg.com/multiple-select@1.
|
40
|
+
<link rel="stylesheet" href="https://unpkg.com/multiple-select@2.1.1/dist/multiple-select.min.css">
|
41
41
|
|
42
42
|
<!-- Latest compiled and minified JavaScript -->
|
43
|
-
<script src="https://unpkg.com/multiple-select@1.
|
44
|
-
<link href="https://unpkg.com/multiple-select@1.
|
45
|
-
|
43
|
+
<script src="https://unpkg.com/multiple-select@2.1.1/dist/multiple-select.min.js"></script>
|
44
|
+
<link href="https://unpkg.com/multiple-select@2.1.1/dist/themes/bootstrap.min.css" rel="stylesheet">
|
45
|
+
<!-- <link href="https://cdn.jsdelivr.net/npm/select2@4.0.0/dist/css/select2.min.css" rel="stylesheet" /> -->
|
46
46
|
<!-- <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /> -->
|
47
47
|
<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ttskch/select2-bootstrap4-theme@x.x.x/dist/select2-bootstrap4.min.css">
|
48
48
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script> -->
|
@@ -54,7 +54,9 @@
|
|
54
54
|
|
55
55
|
function update_hiddify_ui() {
|
56
56
|
|
57
|
-
$("#show_domains").multipleSelect({ width: '100%' });
|
57
|
+
$("#show_domains").multipleSelect({ width: '100%', filter: true });
|
58
|
+
// $("#download_domain").select2()
|
59
|
+
$("#download_domain").multipleSelect({ width: '100%', filter: true });
|
58
60
|
|
59
61
|
if ($("#domain").length > 0) {
|
60
62
|
var selectElement = document.getElementById("mode");
|
@@ -62,7 +64,7 @@
|
|
62
64
|
{ label: `{{_("Direct")}}`, options: ["direct", "old_xtls_direct"] },
|
63
65
|
{ label: `{{_("Panel Link")}}`, options: ["sub_link_only"] },
|
64
66
|
{ label: `{{_("Bridge Servers")}}`, options: ["cdn", "auto_cdn_ip", "worker", "relay"] },
|
65
|
-
{ label: `{{_("Fake")}}`, options: ["
|
67
|
+
{ label: `{{_("Fake")}}`, options: ["special_reality_xhttp","special_reality_tcp","special_reality_grpc", "fake"] }
|
66
68
|
];
|
67
69
|
|
68
70
|
var options = Array.from($("#mode option"));
|
@@ -106,7 +108,7 @@
|
|
106
108
|
$("#domain").parent().find(".control-label").html(`{{_('domain.domain')}}`)
|
107
109
|
$("#domain").parent().find(".help-block").html(`{{_('domain.description')}}`)
|
108
110
|
|
109
|
-
|
111
|
+
|
110
112
|
} else {
|
111
113
|
$("#cdn_ip").parent().show();
|
112
114
|
//$("#mode").parent().show();
|
@@ -119,14 +121,14 @@
|
|
119
121
|
$("#cdn_ip").parent().show();
|
120
122
|
}
|
121
123
|
{% autoescape false %}
|
122
|
-
if ($("#mode").val()
|
124
|
+
if (($("#mode").val()?? "").indexOf('reality')>=0) {
|
123
125
|
|
124
126
|
//$("#servernames").parent().hide();
|
125
127
|
$("#servernames").parent().show();
|
126
128
|
$("#servernames").parent().find(".control-label").html(`{{_('config.reality_server_names.label')}}`)
|
127
129
|
$("#servernames").parent().find(".help-block").html(`{{_('config.reality_server_names.description')}}`)
|
128
130
|
|
129
|
-
$("#grpc").parent().parent().show()
|
131
|
+
// $("#grpc").parent().parent().show()
|
130
132
|
$("#domain").parent().find(".control-label").html(`{{_('config.reality_fallback_domain.label')}}`)
|
131
133
|
$("#domain").parent().find(".help-block").html(`{{_('config.reality_fallback_domain.description')+("<a target='_blank' href='" +hurl_for('admin.Actions:get_some_random_reality_friendly_domain',test_domain=domain)+"'>"+_('Example Domains')+"</a>")}}`)
|
132
134
|
} else {
|
Binary file
|