hiddifypanel 10.80.12.dev1__py3-none-any.whl → 10.85.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.
Files changed (74) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +3 -3
  3. hiddifypanel/apps/asgi_app.py +1 -1
  4. hiddifypanel/apps/celery_app.py +2 -2
  5. hiddifypanel/apps/celery_app_flask.py +3 -0
  6. hiddifypanel/apps/wsgi_app.py +1 -1
  7. hiddifypanel/base.py +5 -5
  8. hiddifypanel/celery.py +68 -1
  9. hiddifypanel/database.py +62 -5
  10. hiddifypanel/drivers/singbox_api.py +2 -1
  11. hiddifypanel/drivers/user_driver.py +4 -1
  12. hiddifypanel/hutils/__init__.py +46 -14
  13. hiddifypanel/hutils/crypto.py +2 -1
  14. hiddifypanel/hutils/encode.py +1 -2
  15. hiddifypanel/hutils/flask.py +1 -1
  16. hiddifypanel/hutils/network/auto_ip_selector.py +15 -12
  17. hiddifypanel/hutils/network/cf_api.py +7 -2
  18. hiddifypanel/hutils/proxy/xrayjson.py +1 -0
  19. hiddifypanel/hutils/system.py +9 -8
  20. hiddifypanel/hutils/utils.py +2 -1
  21. hiddifypanel/models/admin.py +7 -5
  22. hiddifypanel/models/base_account.py +3 -3
  23. hiddifypanel/models/child.py +4 -4
  24. hiddifypanel/models/config.py +5 -5
  25. hiddifypanel/models/config_enum.py +3 -1
  26. hiddifypanel/models/domain.py +5 -5
  27. hiddifypanel/models/proxy.py +4 -2
  28. hiddifypanel/models/report.py +3 -3
  29. hiddifypanel/models/usage.py +2 -2
  30. hiddifypanel/models/user.py +3 -3
  31. hiddifypanel/panel/admin/templates/index.html +6 -6
  32. hiddifypanel/panel/cli.py +1 -1
  33. hiddifypanel/panel/commercial/restapi/v1/tgbot.py +2 -3
  34. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +76 -6
  35. hiddifypanel/panel/common.py +5 -1
  36. hiddifypanel/panel/common_bp/login.py +3 -2
  37. hiddifypanel/panel/hiddify.py +9 -9
  38. hiddifypanel/panel/hlogger.py +3 -1
  39. hiddifypanel/panel/init_db.py +71 -87
  40. hiddifypanel/panel/run_commander.py +3 -4
  41. hiddifypanel/panel/usage.py +10 -9
  42. hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +19 -34
  43. hiddifypanel/panel/user/templates/base_xray_config.json.j2 +4 -2
  44. hiddifypanel/panel/user/templates/clash_config.yml +33 -3
  45. hiddifypanel/static/apps-icon/clash_verge_rev.ico +0 -0
  46. hiddifypanel/static/apps-icon/cmfa.ico +0 -0
  47. hiddifypanel/templates/master.html +1 -1
  48. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  49. hiddifypanel/translations/en/LC_MESSAGES/messages.po +13 -1
  50. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  51. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +13 -1
  52. hiddifypanel/translations/my/LC_MESSAGES/messages.mo +0 -0
  53. hiddifypanel/translations/my/LC_MESSAGES/messages.po +0 -2
  54. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  55. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +13 -1
  56. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  57. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +13 -1
  58. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  59. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +13 -1
  60. hiddifypanel/translations.i18n/en.json +9 -1
  61. hiddifypanel/translations.i18n/fa.json +9 -1
  62. hiddifypanel/translations.i18n/fr.json +1 -0
  63. hiddifypanel/translations.i18n/my.json +4 -0
  64. hiddifypanel/translations.i18n/pt.json +9 -1
  65. hiddifypanel/translations.i18n/ru.json +9 -1
  66. hiddifypanel/translations.i18n/zh.json +9 -1
  67. hiddifypanel-10.85.0b1.dist-info/METADATA +331 -0
  68. {hiddifypanel-10.80.12.dev1.dist-info → hiddifypanel-10.85.0b1.dist-info}/RECORD +120 -116
  69. {hiddifypanel-10.80.12.dev1.dist-info → hiddifypanel-10.85.0b1.dist-info}/WHEEL +2 -1
  70. hiddifypanel-10.85.0b1.dist-info/entry_points.txt +2 -0
  71. hiddifypanel-10.85.0b1.dist-info/top_level.txt +1 -0
  72. hiddifypanel-10.80.12.dev1.dist-info/METADATA +0 -137
  73. hiddifypanel-10.80.12.dev1.dist-info/entry_points.txt +0 -3
  74. {hiddifypanel-10.80.12.dev1.dist-info → hiddifypanel-10.85.0b1.dist-info/licenses}/LICENSE.md +0 -0
@@ -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
- from hiddifypanel.panel import hiddify
12
+
13
13
  from hiddifypanel.database import db, db_execute
14
- from flask import g
15
- from sqlalchemy import func, text
14
+
15
+
16
16
  from loguru import logger
17
- MAX_DB_VERSION = 100
17
+ MAX_DB_VERSION = 120
18
18
 
19
19
 
20
- def _v98(child_id):
21
- add_config_if_not_exist(ConfigEnum.path_xhttp,hutils.random.get_random_string(7, 15))
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
- result = (
45
- db.session.query(
46
- 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
- )
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
- DailyUsage.child_id == r.child_id,
62
- DailyUsage.admin_id == r.admin_id,
63
- DailyUsage.date == r.date
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
- child_id=r.child_id,
69
- admin_id=r.admin_id,
70
- date=r.date,
71
- online=r.online,
72
- usage=r.usage
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
- ConfigEnum.reality_private_key, key_pair['private_key'])
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=True),
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
- f"delete from {table_name} where `{column_name}` in ({expired_enumstr});", commit=True)
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
- 'ALTER TABLE user RENAME COLUMN monthly_usage_limit_GB TO usage_limit_GB')
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
- current_app.config['HIDDIFY_CONFIG_PATH'], 'common/commander.py')
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(current_app.config['HIDDIFY_CONFIG_PATH']), start_new_session=True)
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(current_app.config['HIDDIFY_CONFIG_PATH'])).decode()
84
+ return subprocess.check_output(base_cmd, cwd=str(os.environ['HIDDIFY_CONFIG_PATH'])).decode()
@@ -1,4 +1,4 @@
1
- from flask_babel import lazy_gettext as _
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
- return {"msg": "last update task is not finished yet."}
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 = User.query.filter(User.uuid.in_(uuids))
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 User.query.filter(User.mode != UserMode.no_reset).all():
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 AdminUser.query.all():
80
- daily_usage[adm.id] = DailyUsage.query.filter(DailyUsage.date == today, DailyUsage.admin_id == adm.id, DailyUsage.child_id == child_id).first()
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 = User.query.filter(User.added_by == adm.id).filter(func.DATE(User.last_online) == today).count()
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 = User.query.filter(User.uuid == uuid).first()
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)=='cn' %}"Select" {%else%}"bypass"{%endif%}
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)=='cn' %}"Select" {%else%}"bypass"{%endif%}
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)=="ir"%}
38
+ {%if hconfig(ConfigEnum.country) in ["ir","zh","ru"]%}
38
39
  {
39
- "tag": "geosite-ir",
40
+ "tag": "geosite-{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}",
40
41
  "type": "remote",
41
42
  "format": "binary",
42
- "url": "https:\/\/raw.githubusercontent.com\/Chocolate4U\/Iran-sing-box-rules\/rule-set\/geosite-ir.srs",
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-ir",
47
+ "tag": "geoip-{{hconfig(ConfigEnum.country)|replace('zh', 'cn')}}",
47
48
  "type": "remote",
48
49
  "format": "binary",
49
- "url": "https:\/\/raw.githubusercontent.com\/Chocolate4U\/Iran-sing-box-rules\/rule-set\/geoip-ir.srs",
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) in ["ir","cn","ru"]%}
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","cn","ru"]%}
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","cn","ru"]%}
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
- - GEOIP,IR,{{OnIranSites}}
179
- - DOMAIN-SUFFIX,.ir,{{OnIranSites}}
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