hiddifypanel 10.80.12.dev1__py3-none-any.whl → 10.85.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +3 -3
- hiddifypanel/apps/asgi_app.py +1 -1
- hiddifypanel/apps/celery_app.py +2 -2
- hiddifypanel/apps/celery_app_flask.py +3 -0
- hiddifypanel/apps/wsgi_app.py +1 -1
- hiddifypanel/base.py +5 -5
- hiddifypanel/celery.py +68 -1
- hiddifypanel/database.py +62 -5
- hiddifypanel/drivers/singbox_api.py +2 -1
- hiddifypanel/drivers/user_driver.py +4 -1
- hiddifypanel/hutils/__init__.py +46 -14
- hiddifypanel/hutils/crypto.py +2 -1
- hiddifypanel/hutils/encode.py +1 -2
- hiddifypanel/hutils/flask.py +1 -1
- hiddifypanel/hutils/network/auto_ip_selector.py +15 -12
- hiddifypanel/hutils/network/cf_api.py +7 -2
- hiddifypanel/hutils/proxy/xrayjson.py +1 -0
- hiddifypanel/hutils/system.py +9 -8
- hiddifypanel/hutils/utils.py +2 -1
- hiddifypanel/models/admin.py +7 -5
- hiddifypanel/models/base_account.py +3 -3
- hiddifypanel/models/child.py +4 -4
- hiddifypanel/models/config.py +5 -5
- hiddifypanel/models/config_enum.py +3 -1
- hiddifypanel/models/domain.py +5 -5
- hiddifypanel/models/proxy.py +4 -2
- hiddifypanel/models/report.py +3 -3
- hiddifypanel/models/usage.py +2 -2
- hiddifypanel/models/user.py +3 -3
- hiddifypanel/panel/admin/templates/index.html +6 -6
- hiddifypanel/panel/cli.py +1 -1
- hiddifypanel/panel/commercial/restapi/v1/tgbot.py +2 -3
- hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +76 -6
- hiddifypanel/panel/common.py +5 -1
- hiddifypanel/panel/common_bp/login.py +3 -2
- hiddifypanel/panel/hiddify.py +9 -9
- hiddifypanel/panel/hlogger.py +3 -1
- hiddifypanel/panel/init_db.py +71 -87
- hiddifypanel/panel/run_commander.py +3 -4
- hiddifypanel/panel/usage.py +10 -9
- hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +19 -34
- hiddifypanel/panel/user/templates/base_xray_config.json.j2 +4 -2
- hiddifypanel/panel/user/templates/clash_config.yml +33 -3
- hiddifypanel/static/apps-icon/clash_verge_rev.ico +0 -0
- hiddifypanel/static/apps-icon/cmfa.ico +0 -0
- hiddifypanel/templates/master.html +1 -1
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +37 -1
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +37 -1
- hiddifypanel/translations/my/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/my/LC_MESSAGES/messages.po +0 -2
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +37 -1
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +37 -1
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +37 -1
- hiddifypanel/translations.i18n/en.json +17 -1
- hiddifypanel/translations.i18n/fa.json +17 -1
- hiddifypanel/translations.i18n/fr.json +1 -0
- hiddifypanel/translations.i18n/my.json +4 -0
- hiddifypanel/translations.i18n/pt.json +17 -1
- hiddifypanel/translations.i18n/ru.json +17 -1
- hiddifypanel/translations.i18n/zh.json +17 -1
- hiddifypanel-10.85.0b2.dist-info/METADATA +331 -0
- {hiddifypanel-10.80.12.dev1.dist-info → hiddifypanel-10.85.0b2.dist-info}/RECORD +120 -116
- {hiddifypanel-10.80.12.dev1.dist-info → hiddifypanel-10.85.0b2.dist-info}/WHEEL +2 -1
- hiddifypanel-10.85.0b2.dist-info/entry_points.txt +2 -0
- hiddifypanel-10.85.0b2.dist-info/top_level.txt +1 -0
- hiddifypanel-10.80.12.dev1.dist-info/METADATA +0 -137
- hiddifypanel-10.80.12.dev1.dist-info/entry_points.txt +0 -3
- {hiddifypanel-10.80.12.dev1.dist-info → hiddifypanel-10.85.0b2.dist-info/licenses}/LICENSE.md +0 -0
hiddifypanel/panel/init_db.py
CHANGED
@@ -9,19 +9,20 @@ import uuid
|
|
9
9
|
from hiddifypanel import Events, hutils
|
10
10
|
from hiddifypanel.cache import cache
|
11
11
|
from hiddifypanel.models import *
|
12
|
-
|
12
|
+
|
13
13
|
from hiddifypanel.database import db, db_execute
|
14
|
-
|
15
|
-
|
14
|
+
|
15
|
+
|
16
16
|
from loguru import logger
|
17
|
-
MAX_DB_VERSION =
|
17
|
+
MAX_DB_VERSION = 120
|
18
18
|
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
|
21
|
+
def _v101(child_id):
|
22
|
+
add_config_if_not_exist(ConfigEnum.path_xhttp, hutils.random.get_random_string(7, 15))
|
22
23
|
add_config_if_not_exist(ConfigEnum.xhttp_enable, False)
|
23
24
|
db.session.bulk_save_objects(get_proxy_rows_v1())
|
24
|
-
|
25
|
+
|
25
26
|
|
26
27
|
def _v97(child_id):
|
27
28
|
keys = hutils.crypto.generate_ssh_host_keys()
|
@@ -41,36 +42,33 @@ def _v97(child_id):
|
|
41
42
|
|
42
43
|
|
43
44
|
def _v96(child_id):
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
)
|
45
|
+
from sqlalchemy import func
|
46
|
+
result = (db.session.query(DailyUsage.child_id,
|
47
|
+
DailyUsage.admin_id,
|
48
|
+
DailyUsage.date,
|
49
|
+
func.max(DailyUsage.online).label('online'),
|
50
|
+
func.sum(DailyUsage.usage).label('usage'),
|
51
|
+
func.count(DailyUsage.usage).label('count'),
|
52
|
+
)
|
53
|
+
.group_by(DailyUsage.child_id, DailyUsage.admin_id, DailyUsage.date)
|
54
|
+
.all()
|
55
|
+
)
|
56
56
|
|
57
57
|
for r in result:
|
58
58
|
if r.count > 1:
|
59
59
|
# Delete existing records for this group
|
60
|
-
db.session.query(DailyUsage).filter(
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
).delete()
|
60
|
+
db.session.query(DailyUsage).filter(DailyUsage.child_id == r.child_id,
|
61
|
+
DailyUsage.admin_id == r.admin_id,
|
62
|
+
DailyUsage.date == r.date
|
63
|
+
).delete()
|
65
64
|
|
66
65
|
# Add the aggregated record
|
67
|
-
new_record = DailyUsage(
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
)
|
66
|
+
new_record = DailyUsage(child_id=r.child_id,
|
67
|
+
admin_id=r.admin_id,
|
68
|
+
date=r.date,
|
69
|
+
online=r.online,
|
70
|
+
usage=r.usage
|
71
|
+
)
|
74
72
|
db.session.add(new_record)
|
75
73
|
|
76
74
|
# Commit the changes to the database
|
@@ -143,8 +141,7 @@ def _v79(child_id):
|
|
143
141
|
|
144
142
|
def _v78(child_id):
|
145
143
|
# equalize panel unique id and root child unique id
|
146
|
-
root_child_unique_id = Child.query.filter(
|
147
|
-
Child.name == "Root").first().unique_id
|
144
|
+
root_child_unique_id = Child.query.filter(Child.name == "Root").first().unique_id
|
148
145
|
set_hconfig(ConfigEnum.unique_id, root_child_unique_id)
|
149
146
|
|
150
147
|
|
@@ -287,8 +284,7 @@ def _v55():
|
|
287
284
|
set_hconfig(ConfigEnum.hysteria_port, hystria_port)
|
288
285
|
set_hconfig(ConfigEnum.tuic_enable, True)
|
289
286
|
set_hconfig(ConfigEnum.hysteria_enable, True)
|
290
|
-
Proxy.query.filter(Proxy.proto.in_(
|
291
|
-
["tuic", "hysteria2", "hysteria"])).delete()
|
287
|
+
Proxy.query.filter(Proxy.proto.in_(["tuic", "hysteria2", "hysteria"])).delete()
|
292
288
|
db.session.add(Proxy(l3='tls', transport='custom',
|
293
289
|
cdn='direct', proto='tuic', enable=True, name="TUIC"))
|
294
290
|
db.session.add(Proxy(l3='tls', transport='custom', cdn='direct',
|
@@ -321,8 +317,7 @@ def _v48():
|
|
321
317
|
|
322
318
|
|
323
319
|
def _v47():
|
324
|
-
StrConfig.query.filter(
|
325
|
-
StrConfig.key == ConfigEnum.ssh_server_enable).delete()
|
320
|
+
StrConfig.query.filter(StrConfig.key == ConfigEnum.ssh_server_enable).delete()
|
326
321
|
|
327
322
|
|
328
323
|
def _v45():
|
@@ -358,8 +353,7 @@ def _v41():
|
|
358
353
|
|
359
354
|
def _v38():
|
360
355
|
add_config_if_not_exist(ConfigEnum.dns_server, "1.1.1.1")
|
361
|
-
add_config_if_not_exist(ConfigEnum.warp_mode, "all" if hconfig(
|
362
|
-
ConfigEnum.warp_enable) else "disable")
|
356
|
+
add_config_if_not_exist(ConfigEnum.warp_mode, "all" if hconfig(ConfigEnum.warp_enable) else "disable")
|
363
357
|
add_config_if_not_exist(ConfigEnum.warp_plus_code, '')
|
364
358
|
|
365
359
|
|
@@ -376,14 +370,11 @@ def _v31():
|
|
376
370
|
add_config_if_not_exist(ConfigEnum.reality_short_ids,
|
377
371
|
uuid.uuid4().hex[0:random.randint(1, 8) * 2])
|
378
372
|
key_pair = hutils.crypto.generate_x25519_keys()
|
379
|
-
add_config_if_not_exist(
|
380
|
-
|
381
|
-
add_config_if_not_exist(
|
382
|
-
ConfigEnum.reality_public_key, key_pair['public_key'])
|
373
|
+
add_config_if_not_exist(ConfigEnum.reality_private_key, key_pair['private_key'])
|
374
|
+
add_config_if_not_exist(ConfigEnum.reality_public_key, key_pair['public_key'])
|
383
375
|
db.session.bulk_save_objects(get_proxy_rows_v1())
|
384
376
|
if not (AdminUser.query.filter(AdminUser.id == 1).first()):
|
385
|
-
db.session.add(AdminUser(id=1, uuid=hconfig(
|
386
|
-
ConfigEnum.admin_secret), name="Owner", mode=AdminMode.super_admin, comment=""))
|
377
|
+
db.session.add(AdminUser(id=1, uuid=hconfig(ConfigEnum.admin_secret), name="Owner", mode=AdminMode.super_admin, comment=""))
|
387
378
|
execute("update admin_user set id=1 where name='owner'")
|
388
379
|
for i in range(1, 10):
|
389
380
|
for d in hutils.network.get_random_domains(50):
|
@@ -418,8 +409,7 @@ def _v20():
|
|
418
409
|
if hconfig(ConfigEnum.domain_fronting_domain):
|
419
410
|
fake_domains = [hconfig(ConfigEnum.domain_fronting_domain)]
|
420
411
|
|
421
|
-
direct_domain = Domain.query.filter(
|
422
|
-
Domain.mode in [DomainType.direct, DomainType.relay]).first()
|
412
|
+
direct_domain = Domain.query.filter(Domain.mode in [DomainType.direct, DomainType.relay]).first()
|
423
413
|
if direct_domain:
|
424
414
|
direct_host = direct_domain.domain
|
425
415
|
else:
|
@@ -427,8 +417,7 @@ def _v20():
|
|
427
417
|
|
428
418
|
for fd in fake_domains:
|
429
419
|
if not Domain.query.filter(Domain.domain == fd).first():
|
430
|
-
db.session.add(Domain(
|
431
|
-
domain=fd, mode='fake', alias='moved from domain fronting', cdn_ip=direct_host))
|
420
|
+
db.session.add(Domain(domain=fd, mode='fake', alias='moved from domain fronting', cdn_ip=direct_host))
|
432
421
|
|
433
422
|
|
434
423
|
def _v19():
|
@@ -441,8 +430,7 @@ def _v19():
|
|
441
430
|
set_hconfig(ConfigEnum.path_ws, hutils.random.get_random_string(7, 15))
|
442
431
|
add_config_if_not_exist(ConfigEnum.tuic_enable, False)
|
443
432
|
add_config_if_not_exist(ConfigEnum.shadowtls_enable, False)
|
444
|
-
add_config_if_not_exist(
|
445
|
-
ConfigEnum.shadowtls_fakedomain, "en.wikipedia.org")
|
433
|
+
add_config_if_not_exist(ConfigEnum.shadowtls_fakedomain, "en.wikipedia.org")
|
446
434
|
add_config_if_not_exist(ConfigEnum.utls, "chrome")
|
447
435
|
add_config_if_not_exist(ConfigEnum.telegram_bot_token, "")
|
448
436
|
add_config_if_not_exist(ConfigEnum.package_mode, "release")
|
@@ -485,7 +473,7 @@ def _v1():
|
|
485
473
|
BoolConfig(key=ConfigEnum.allow_invalid_sni, value=True),
|
486
474
|
BoolConfig(key=ConfigEnum.kcp_enable, value=False),
|
487
475
|
StrConfig(key=ConfigEnum.kcp_ports, value="88"),
|
488
|
-
BoolConfig(key=ConfigEnum.auto_update, value=
|
476
|
+
BoolConfig(key=ConfigEnum.auto_update, value=os.environ.get('HIDDIFY_DISABLE_UPDATE',"").lower() not in {'1','true'}),
|
489
477
|
BoolConfig(key=ConfigEnum.speed_test, value=True),
|
490
478
|
BoolConfig(key=ConfigEnum.only_ipv4, value=False),
|
491
479
|
BoolConfig(key=ConfigEnum.vmess_enable, value=True),
|
@@ -527,8 +515,7 @@ def _v1():
|
|
527
515
|
def _v7():
|
528
516
|
try:
|
529
517
|
Proxy.query.filter(Proxy.name == 'tls XTLS direct trojan').delete()
|
530
|
-
Proxy.query.filter(
|
531
|
-
Proxy.name == 'tls XTLSVision direct trojan').delete()
|
518
|
+
Proxy.query.filter(Proxy.name == 'tls XTLSVision direct trojan').delete()
|
532
519
|
except BaseException:
|
533
520
|
pass
|
534
521
|
add_config_if_not_exist(ConfigEnum.telegram_lib, "erlang")
|
@@ -686,13 +673,12 @@ def make_proxy_rows(cfgs):
|
|
686
673
|
enable = l3 != "http" or proto == "vmess"
|
687
674
|
enable = enable and transport != 'tcp'
|
688
675
|
name = f'{l3} {c}'
|
689
|
-
# is_exist = Proxy.query.filter(Proxy.name == name).first() or Proxy.query.filter(
|
690
|
-
# Proxy.l3 == l3, Proxy.transport == transport, Proxy.cdn == cdn, Proxy.proto == proto).first()
|
676
|
+
# 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()
|
691
677
|
# if not is_exist:
|
692
678
|
yield Proxy(l3=l3, transport=transport, cdn=cdn, proto=proto, enable=enable, name=name)
|
693
679
|
|
694
680
|
|
695
|
-
def add_config_if_not_exist(key: ConfigEnum, val: str | int, child_id: int | None = None):
|
681
|
+
def add_config_if_not_exist(key: "ConfigEnum", val: str | int, child_id: int | None = None):
|
696
682
|
if child_id is None:
|
697
683
|
child_id = Child.current().id
|
698
684
|
|
@@ -705,8 +691,7 @@ def add_column(column):
|
|
705
691
|
try:
|
706
692
|
column_type = column.type.compile(db.engine.dialect)
|
707
693
|
|
708
|
-
db_execute(
|
709
|
-
f'ALTER TABLE {column.table.name} ADD COLUMN {column.name} {column_type}', commit=True)
|
694
|
+
db_execute(f'ALTER TABLE {column.table.name} ADD COLUMN {column.name} {column_type}', commit=True)
|
710
695
|
except BaseException:
|
711
696
|
pass
|
712
697
|
|
@@ -716,7 +701,7 @@ def execute(query: str):
|
|
716
701
|
|
717
702
|
db_execute(query)
|
718
703
|
except BaseException as e:
|
719
|
-
logger.debug(e)
|
704
|
+
logger.debug(f'migrating_db: {e}')
|
720
705
|
pass
|
721
706
|
|
722
707
|
|
@@ -725,21 +710,20 @@ def add_new_enum_values():
|
|
725
710
|
Proxy.l3, Proxy.proto, Proxy.cdn, Proxy.transport,
|
726
711
|
User.mode, Domain.mode, BoolConfig.key, StrConfig.key
|
727
712
|
]
|
713
|
+
from sqlalchemy import text
|
728
714
|
for col in columns:
|
729
715
|
enum_class = col.type.enum_class
|
730
716
|
column_name = col.name
|
731
717
|
table_name = col.table
|
732
718
|
|
733
719
|
# Get the existing values in the enum
|
734
|
-
existing_values = [f'{e}' if isinstance(
|
735
|
-
e, ConfigEnum) else e.value for e in enum_class]
|
720
|
+
existing_values = [f'{e}' if isinstance(e, ConfigEnum) else e.value for e in enum_class]
|
736
721
|
|
737
722
|
# Get the values in the enum column in the database
|
738
723
|
# result = db.engine.execute(f"SELECT DISTINCT `{column_name}` FROM {table_name}")
|
739
724
|
# db_values = {row[0] for row in result}
|
740
725
|
|
741
|
-
result = db.session.execute(
|
742
|
-
text(f"SHOW COLUMNS FROM {table_name} LIKE '{column_name}';")).fetchall()
|
726
|
+
result = db.session.execute(text(f"SHOW COLUMNS FROM {table_name} LIKE '{column_name}';")).fetchall()
|
743
727
|
db_values = []
|
744
728
|
|
745
729
|
for row in result:
|
@@ -759,12 +743,13 @@ def add_new_enum_values():
|
|
759
743
|
# enumstr = ','.join([f"'{a}'" for a in [*existing_values, *old_values]])
|
760
744
|
enumstr = ','.join([f"'{a}'" for a in [*existing_values]])
|
761
745
|
expired_enumstr = ','.join([f"'{a}'" for a in [*old_values]])
|
762
|
-
db_execute(
|
763
|
-
|
764
|
-
db_execute(
|
765
|
-
f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});", commit=True)
|
746
|
+
db_execute(f"delete from {table_name} where `{column_name}` in ({expired_enumstr});", commit=True)
|
747
|
+
db_execute(f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});", commit=True)
|
766
748
|
|
767
749
|
|
750
|
+
def is_db_latest():
|
751
|
+
return str(hconfig(ConfigEnum.db_version))==str(latest_db_version())
|
752
|
+
|
768
753
|
def latest_db_version():
|
769
754
|
for ver in range(MAX_DB_VERSION, 1, -1):
|
770
755
|
db_action = sys.modules[__name__].__dict__.get(f'_v{ver}', None)
|
@@ -784,13 +769,13 @@ def upgrade_database():
|
|
784
769
|
logger.info("no backup found...")
|
785
770
|
return
|
786
771
|
if os.path.isfile(sqlite_db):
|
787
|
-
logger.info(
|
788
|
-
"Finding Old Version Database... importing configs from latest backup")
|
772
|
+
logger.info("Finding Old Version Database... importing configs from latest backup")
|
789
773
|
newest_file = max([(f, os.path.getmtime(os.path.join(backup_root, f)))
|
790
774
|
for f in os.listdir(backup_root) if os.path.isfile(os.path.join(backup_root, f))], key=lambda x: x[1])[0]
|
791
775
|
with open(f'{backup_root}{newest_file}', 'r') as f:
|
792
776
|
logger.info(f"importing configs from {newest_file}")
|
793
777
|
json_data = json.load(f)
|
778
|
+
from hiddifypanel.panel import hiddify
|
794
779
|
hiddify.set_db_from_json(json_data,
|
795
780
|
set_users=True,
|
796
781
|
set_domains=True,
|
@@ -803,8 +788,7 @@ def upgrade_database():
|
|
803
788
|
override_child_unique_id=0,
|
804
789
|
replace_owner_admin=True
|
805
790
|
)
|
806
|
-
db_version = int(
|
807
|
-
[d['value'] for d in json_data['hconfigs'] if d['key'] == "db_version"][0])
|
791
|
+
db_version = int([d['value'] for d in json_data['hconfigs'] if d['key'] == "db_version"][0])
|
808
792
|
os.rename(sqlite_db, sqlite_db + ".old")
|
809
793
|
set_hconfig(ConfigEnum.db_version, db_version, commit=True)
|
810
794
|
|
@@ -813,14 +797,17 @@ def upgrade_database():
|
|
813
797
|
|
814
798
|
def init_db():
|
815
799
|
db.create_all()
|
816
|
-
|
800
|
+
|
817
801
|
# set_hconfig(ConfigEnum.db_version, 71)
|
818
802
|
# temporary fix
|
819
803
|
add_column(Child.mode)
|
820
804
|
add_column(Child.name)
|
805
|
+
|
821
806
|
db_version = int(hconfig(ConfigEnum.db_version) or 0)
|
807
|
+
|
822
808
|
if db_version == latest_db_version():
|
823
809
|
return
|
810
|
+
from flask import g
|
824
811
|
cache.invalidate_all_cached_functions()
|
825
812
|
migrate(db_version)
|
826
813
|
Child.query.filter(Child.id == 0).first().mode = ChildMode.virtual
|
@@ -841,8 +828,7 @@ def init_db():
|
|
841
828
|
if not db_action or (start_version == 0 and ver == 10):
|
842
829
|
continue
|
843
830
|
|
844
|
-
logger.info(
|
845
|
-
f"Updating db from version {db_version} for node {child.id}")
|
831
|
+
logger.info(f"Updating db from version {db_version} for node {child.id}")
|
846
832
|
|
847
833
|
if ver < 70:
|
848
834
|
if child.id != 0:
|
@@ -852,8 +838,7 @@ def init_db():
|
|
852
838
|
db_action(child.id)
|
853
839
|
|
854
840
|
Events.db_init_event.notify(db_version=db_version)
|
855
|
-
logger.info(
|
856
|
-
f"Updated successfuly db from version {db_version} to {ver}")
|
841
|
+
logger.info(f"Updated successfuly db from version {db_version} to {ver}")
|
857
842
|
|
858
843
|
db_version = ver
|
859
844
|
db.session.commit()
|
@@ -870,14 +855,17 @@ def migrate(db_version):
|
|
870
855
|
for column in table_obj.columns:
|
871
856
|
add_column(column)
|
872
857
|
Events.db_prehook.notify()
|
858
|
+
if db_version < 100:
|
859
|
+
execute('update str_config set `key`="xhttp_enable" where `key`="splithttp_enable";')
|
860
|
+
execute('update str_config set `key`="path_xhttp" where `key`="path_splithttp";')
|
861
|
+
execute("UPDATE proxy SET transport = 'xhttp' WHERE transport = 'splithttp';")
|
873
862
|
if db_version < 97:
|
874
863
|
execute('ALTER TABLE str_config MODIFY value VARCHAR(3072);')
|
875
864
|
if db_version < 82:
|
876
865
|
execute('ALTER TABLE child DROP INDEX `name`;')
|
877
866
|
if db_version < 77:
|
878
867
|
execute('ALTER TABLE user_detail DROP COLUMN connected_ips;')
|
879
|
-
execute(
|
880
|
-
'update user_detail set connected_devices="" where connected_devices IS NULL')
|
868
|
+
execute('update user_detail set connected_devices="" where connected_devices IS NULL')
|
881
869
|
|
882
870
|
if db_version < 70:
|
883
871
|
execute('CREATE INDEX date ON daily_usage (date);')
|
@@ -909,8 +897,7 @@ def migrate(db_version):
|
|
909
897
|
|
910
898
|
if db_version < 52:
|
911
899
|
execute(f'update domain set mode="sub_link_only", sub_link_only=false where sub_link_only = true or mode=1 or mode="1"')
|
912
|
-
execute(
|
913
|
-
f'update domain set mode="direct", sub_link_only=false where mode=0 or mode="0"')
|
900
|
+
execute(f'update domain set mode="direct", sub_link_only=false where mode=0 or mode="0"')
|
914
901
|
execute(f'update proxy set transport="WS" where transport = "ws"')
|
915
902
|
execute(f'update admin_user set mode="agent" where mode = "slave"')
|
916
903
|
execute(f'update admin_user set mode="super_admin" where id=1')
|
@@ -950,12 +937,9 @@ def migrate(db_version):
|
|
950
937
|
execute(f'DROP TABLE str_config')
|
951
938
|
execute(f'ALTER TABLE str_config_old RENAME TO str_config')
|
952
939
|
|
953
|
-
execute(
|
954
|
-
|
955
|
-
execute(
|
956
|
-
f'update admin_user set parent_admin_id=1 where parent_admin_id is NULL and 1!=id')
|
957
|
-
execute(
|
958
|
-
f'update admin_user set max_users=100,max_active_users=100 where max_users is NULL')
|
940
|
+
execute('ALTER TABLE user RENAME COLUMN monthly_usage_limit_GB TO usage_limit_GB')
|
941
|
+
execute(f'update admin_user set parent_admin_id=1 where parent_admin_id is NULL and 1!=id')
|
942
|
+
execute(f'update admin_user set max_users=100,max_active_users=100 where max_users is NULL')
|
959
943
|
execute(f'update dailyusage set child_id=0 where child_id is NULL')
|
960
944
|
execute(f'update dailyusage set admin_id=1 where admin_id is NULL')
|
961
945
|
execute(f'update dailyusage set admin_id=1 where admin_id = 0')
|
@@ -1,6 +1,5 @@
|
|
1
1
|
from typing import List
|
2
2
|
from strenum import StrEnum
|
3
|
-
from flask import current_app
|
4
3
|
import subprocess
|
5
4
|
import os
|
6
5
|
|
@@ -34,7 +33,7 @@ def commander(command: Command, run_in_background=True, **kwargs: str | int) ->
|
|
34
33
|
base_cmd: List[str] = [
|
35
34
|
'sudo',
|
36
35
|
os.path.join(
|
37
|
-
|
36
|
+
os.environ['HIDDIFY_CONFIG_PATH'], 'common/commander.py')
|
38
37
|
]
|
39
38
|
|
40
39
|
if command == Command.apply:
|
@@ -80,6 +79,6 @@ def commander(command: Command, run_in_background=True, **kwargs: str | int) ->
|
|
80
79
|
else:
|
81
80
|
raise Exception('WTF is happening!')
|
82
81
|
if run_in_background:
|
83
|
-
subprocess.Popen(base_cmd, cwd=str(
|
82
|
+
subprocess.Popen(base_cmd, cwd=str(os.environ['HIDDIFY_CONFIG_PATH']), start_new_session=True)
|
84
83
|
else:
|
85
|
-
return subprocess.check_output(base_cmd, cwd=str(
|
84
|
+
return subprocess.check_output(base_cmd, cwd=str(os.environ['HIDDIFY_CONFIG_PATH'])).decode()
|
hiddifypanel/panel/usage.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
from sqlalchemy import func
|
3
3
|
from typing import Dict
|
4
4
|
import datetime
|
@@ -16,8 +16,8 @@ from celery import shared_task
|
|
16
16
|
@shared_task(ignore_result=False)
|
17
17
|
def update_local_usage():
|
18
18
|
lock_key = "lock-update-local-usage"
|
19
|
-
if not cache.redis_client.set(lock_key, "locked", nx=True, ex=600):
|
20
|
-
|
19
|
+
# if not cache.redis_client.set(lock_key, "locked", nx=True, ex=600):
|
20
|
+
# return {"msg": "last update task is not finished yet."}
|
21
21
|
try:
|
22
22
|
res=update_local_usage_not_lock()
|
23
23
|
cache.redis_client.set(lock_key, "locked", nx=False, ex=60)
|
@@ -43,7 +43,7 @@ def update_local_usage_not_lock():
|
|
43
43
|
def add_users_usage_uuid(uuids_bytes: Dict[str, Dict], child_id, sync=False):
|
44
44
|
uuids_bytes = {u: v for u, v in uuids_bytes.items() if v}
|
45
45
|
uuids = uuids_bytes.keys()
|
46
|
-
users =
|
46
|
+
users = db.session.query(User).filter(User.uuid.in_(uuids))
|
47
47
|
dbusers_bytes = {u: uuids_bytes.get(u.uuid, 0) for u in users}
|
48
48
|
_add_users_usage(dbusers_bytes, child_id, sync) # type: ignore
|
49
49
|
|
@@ -58,7 +58,7 @@ def _reset_priodic_usage():
|
|
58
58
|
if datetime.datetime.now().hour > 5 and current_time - last_usage_check < 60 * 60 * 24:
|
59
59
|
return
|
60
60
|
logger.debug("reseting user usage if needed")
|
61
|
-
for user in
|
61
|
+
for user in db.session.query(User).filter(User.mode != UserMode.no_reset).all():
|
62
62
|
if user.user_should_reset():
|
63
63
|
logger.info(f"reseting user usage for {user.uuid}")
|
64
64
|
user.reset_usage(commit=False)
|
@@ -76,14 +76,14 @@ def _add_users_usage(users_usage_data: Dict[User, Dict], child_id, sync=False):
|
|
76
76
|
daily_usage = {}
|
77
77
|
today = datetime.date.today()
|
78
78
|
changes = False
|
79
|
-
for adm in
|
80
|
-
daily_usage[adm.id] =
|
79
|
+
for adm in db.session.query(AdminUser).all():
|
80
|
+
daily_usage[adm.id] = db.session.query(DailyUsage).filter(DailyUsage.date == today, DailyUsage.admin_id == adm.id, DailyUsage.child_id == child_id).first()
|
81
81
|
if daily_usage[adm.id] is None:
|
82
82
|
logger.info(f"creating a new daily usage {today} admin={adm.id} child={child_id}")
|
83
83
|
daily_usage[adm.id] = DailyUsage(date=today, admin_id=adm.id, child_id=child_id)
|
84
84
|
db.session.add(daily_usage[adm.id])
|
85
85
|
changes = True
|
86
|
-
daily_usage[adm.id].online =
|
86
|
+
daily_usage[adm.id].online = db.session.query(User).filter(User.added_by == adm.id).filter(func.DATE(User.last_online) == today).count()
|
87
87
|
if changes:
|
88
88
|
db.session.commit()
|
89
89
|
_reset_priodic_usage()
|
@@ -155,7 +155,7 @@ def _add_users_usage(users_usage_data: Dict[User, Dict], child_id, sync=False):
|
|
155
155
|
if uuid in res:
|
156
156
|
continue
|
157
157
|
|
158
|
-
user =
|
158
|
+
user = db.session.query(User).filter(User.uuid == uuid).first()
|
159
159
|
if not user:
|
160
160
|
user_driver.remove_client(User(uuid=uuid))
|
161
161
|
elif not user.is_active:
|
@@ -178,6 +178,7 @@ def send_bot_message(user):
|
|
178
178
|
return
|
179
179
|
if not user.telegram_id:
|
180
180
|
return
|
181
|
+
from flask_babel import lazy_gettext as _
|
181
182
|
from hiddifypanel.panel.commercial.telegrambot import bot, Usage
|
182
183
|
try:
|
183
184
|
msg = Usage.get_usage_msg(user.uuid)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
{% set V1_7= g.user_agent['is_singbox'] and g.user_agent['singbox_version'][0]==1 and g.user_agent['singbox_version'][1]<8 %}
|
2
2
|
{% set V1_9= g.user_agent['is_singbox'] and g.user_agent['singbox_version'][0]==1 and g.user_agent['singbox_version'][1]<10 %}
|
3
|
+
|
3
4
|
{
|
4
5
|
"outbounds": [
|
5
6
|
{
|
@@ -26,46 +27,30 @@
|
|
26
27
|
{% if V1_7 %}
|
27
28
|
"geoip": {
|
28
29
|
"download_url": "https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db",
|
29
|
-
"download_detour": {% if hconfig(ConfigEnum.country)=='
|
30
|
+
"download_detour": {% if hconfig(ConfigEnum.country)=='zh' %}"Select" {%else%}"bypass"{%endif%}
|
30
31
|
},
|
31
32
|
"geosite": {
|
32
33
|
"download_url": "https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db",
|
33
|
-
"download_detour": {% if hconfig(ConfigEnum.country)=='
|
34
|
+
"download_detour": {% if hconfig(ConfigEnum.country)=='zh' %}"Select" {%else%}"bypass"{%endif%}
|
34
35
|
},
|
35
36
|
{%else%}
|
36
37
|
"rule_set": [
|
37
|
-
{%if hconfig(ConfigEnum.country)
|
38
|
+
{%if hconfig(ConfigEnum.country) in ["ir","zh","ru"]%}
|
38
39
|
{
|
39
|
-
"tag": "geosite-
|
40
|
+
"tag": "geosite-{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}",
|
40
41
|
"type": "remote",
|
41
42
|
"format": "binary",
|
42
|
-
"url": "https:\/\/
|
43
|
-
"download_detour": "bypass"
|
43
|
+
"url": "https:\/\/github.com\/hiddify\/hiddify-geo\/raw\/rule-set\/country\/geosite-{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}.srs",
|
44
|
+
"download_detour": {% if hconfig(ConfigEnum.country)=='zh' %}"Select" {%else%}"bypass"{%endif%}
|
44
45
|
},
|
45
46
|
{
|
46
|
-
"tag": "geoip-
|
47
|
+
"tag": "geoip-{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}",
|
47
48
|
"type": "remote",
|
48
49
|
"format": "binary",
|
49
|
-
"url": "https:\/\/
|
50
|
-
"download_detour": "bypass"
|
50
|
+
"url": "https:\/\/github.com\/hiddify\/hiddify-geo\/raw\/rule-set\/country\/geoip-{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}.srs",
|
51
|
+
"download_detour": {% if hconfig(ConfigEnum.country)=='zh' %}"Select" {%else%}"bypass"{%endif%}
|
51
52
|
}
|
52
|
-
{%endif%}
|
53
|
-
{%if hconfig(ConfigEnum.country)=="ru"%}
|
54
|
-
{
|
55
|
-
"tag": "geosite-ru",
|
56
|
-
"type": "remote",
|
57
|
-
"format": "binary",
|
58
|
-
"url": "https:\/\/github.com\/SagerNet\/sing-geosite\/raw\/rule-set\/geosite-category-ru.srs",
|
59
|
-
"download_detour": "bypass"
|
60
|
-
},
|
61
|
-
{
|
62
|
-
"tag": "geoip-ru",
|
63
|
-
"type": "remote",
|
64
|
-
"format": "binary",
|
65
|
-
"url": "https:\/\/github.com\/SagerNet\/sing-geoip\/raw\/rule-set\/geoip-ru.srs",
|
66
|
-
"download_detour": "bypass"
|
67
|
-
}
|
68
|
-
{%endif%}
|
53
|
+
{%endif%}
|
69
54
|
{# {
|
70
55
|
"tag": "geosite-category-ads-all",
|
71
56
|
"type": "remote",
|
@@ -88,10 +73,10 @@
|
|
88
73
|
],
|
89
74
|
"outbound": "dns-out"
|
90
75
|
},
|
91
|
-
{%if hconfig(ConfigEnum.country)
|
76
|
+
{%if hconfig(ConfigEnum.country)in ["ir","zh","ru"]%}
|
92
77
|
{
|
93
78
|
"domain_suffix": [
|
94
|
-
"{{hconfig(ConfigEnum.country)}}"
|
79
|
+
"{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}"
|
95
80
|
],
|
96
81
|
"outbound": "bypass"
|
97
82
|
},
|
@@ -105,19 +90,19 @@
|
|
105
90
|
{%endif%}
|
106
91
|
"outbound": "block"
|
107
92
|
}, #}
|
108
|
-
{%if hconfig(ConfigEnum.country) in ["ir","
|
93
|
+
{%if hconfig(ConfigEnum.country) in ["ir","zh","ru"]%}
|
109
94
|
{% if V1_7 %}
|
110
95
|
{
|
111
|
-
"geoip": ["{{hconfig(ConfigEnum.country)}}"],
|
96
|
+
"geoip": ["{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}"],
|
112
97
|
"outbound": "bypass"
|
113
98
|
},
|
114
99
|
{%else%}
|
115
100
|
{
|
116
|
-
"rule_set": "geoip-{{hconfig(ConfigEnum.country)}}",
|
101
|
+
"rule_set": "geoip-{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}",
|
117
102
|
"outbound": "bypass"
|
118
103
|
},
|
119
104
|
{
|
120
|
-
"rule_set": "geosite-{{hconfig(ConfigEnum.country)}}",
|
105
|
+
"rule_set": "geosite-{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}",
|
121
106
|
"outbound": "bypass"
|
122
107
|
},
|
123
108
|
{%endif%}
|
@@ -192,10 +177,10 @@
|
|
192
177
|
],
|
193
178
|
"server": "dns-local"
|
194
179
|
},
|
195
|
-
{%if hconfig(ConfigEnum.country)in ["ir","
|
180
|
+
{%if hconfig(ConfigEnum.country)in ["ir","zh","ru"]%}
|
196
181
|
{
|
197
182
|
"domain_suffix": [
|
198
|
-
"{{hconfig(ConfigEnum.country)}}"
|
183
|
+
"{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}"
|
199
184
|
],
|
200
185
|
"server": "dns-local"
|
201
186
|
},
|
@@ -98,7 +98,8 @@
|
|
98
98
|
"outboundTag": "direct",
|
99
99
|
"domain": [
|
100
100
|
"domain:ir",
|
101
|
-
"geosite:cn"
|
101
|
+
"geosite:cn",
|
102
|
+
"geosite:category-ru"
|
102
103
|
],
|
103
104
|
"enabled": true
|
104
105
|
},
|
@@ -109,7 +110,8 @@
|
|
109
110
|
"ip": [
|
110
111
|
"geoip:private",
|
111
112
|
"geoip:cn",
|
112
|
-
"geoip:ir"
|
113
|
+
"geoip:ir",
|
114
|
+
"geoip:ru"
|
113
115
|
],
|
114
116
|
"enabled": true
|
115
117
|
},
|
@@ -135,7 +135,33 @@ proxy-groups:
|
|
135
135
|
# %endfor
|
136
136
|
# %endfor
|
137
137
|
rule-providers:
|
138
|
-
|
138
|
+
{% if hconfig(ConfigEnum.country) in ["ir","zh","ru"] %}
|
139
|
+
geoip_{{hconfig(ConfigEnum.country)}}:
|
140
|
+
type: http
|
141
|
+
behavior: classical
|
142
|
+
url: "https://github.com/MetaCubeX/meta-rules-dat/raw/meta/geo/geoip/classical/{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}.yaml"
|
143
|
+
path: ./geoip/{{hconfig(ConfigEnum.country)}}.yaml
|
144
|
+
interval: 432000
|
145
|
+
|
146
|
+
{% endif %}
|
147
|
+
{% if hconfig(ConfigEnum.country)=="zh" %}
|
148
|
+
geosite_cn:
|
149
|
+
type: http
|
150
|
+
behavior: classical
|
151
|
+
url: "https://github.com/MetaCubeX/meta-rules-dat/raw/meta/geo-lite/geosite/classical/cn.yaml"
|
152
|
+
path: ./geosite/zh.yaml
|
153
|
+
interval: 86400
|
154
|
+
|
155
|
+
{% endif %}
|
156
|
+
{% if hconfig(ConfigEnum.country) in ["ir","ru"] %}
|
157
|
+
geosite_{{hconfig(ConfigEnum.country)}}:
|
158
|
+
type: http
|
159
|
+
behavior: classical
|
160
|
+
url: "https://github.com/MetaCubeX/meta-rules-dat/raw/meta/geo/geosite/classical/category-{{hconfig(ConfigEnum.country)}}.yaml"
|
161
|
+
path: ./geosite/{{hconfig(ConfigEnum.country)}}.yaml
|
162
|
+
interval: 86400
|
163
|
+
|
164
|
+
{% endif %}
|
139
165
|
blocked:
|
140
166
|
type: http
|
141
167
|
behavior: classical
|
@@ -175,9 +201,13 @@ rules:
|
|
175
201
|
# - IP-CIDR,10.10.34.0/24,{{OnProxyIssue}}
|
176
202
|
# - RULE-SET,tmpblocked,{{OnProxyIssue}}
|
177
203
|
# - RULE-SET,blocked,{{OnProxyIssue}}
|
178
|
-
|
179
|
-
-
|
204
|
+
{% if hconfig(ConfigEnum.country) in ["ir","zh","ru"] %}
|
205
|
+
- RULE-SET,geoip_{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}},DIRECT
|
206
|
+
- RULE-SET,geosite_{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}},DIRECT
|
207
|
+
{% endif %}
|
208
|
+
{% if hconfig(ConfigEnum.country)=="ir" %}
|
180
209
|
- RULE-SET,open,{{OnIranSites}}
|
210
|
+
{% endif %}
|
181
211
|
# - RULE-SET,ads,REJECT
|
182
212
|
- MATCH,{{OnNotFilteredSites}}
|
183
213
|
|
Binary file
|
Binary file
|