hiddifypanel 9.0.0.dev92__py3-none-any.whl → 10.5.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/auth.py +30 -9
  4. hiddifypanel/base.py +58 -50
  5. hiddifypanel/cache.py +43 -25
  6. hiddifypanel/database.py +9 -0
  7. hiddifypanel/drivers/abstract_driver.py +2 -0
  8. hiddifypanel/drivers/singbox_api.py +17 -15
  9. hiddifypanel/drivers/ssh_liberty_bridge_api.py +3 -1
  10. hiddifypanel/drivers/user_driver.py +12 -6
  11. hiddifypanel/drivers/wireguard_api.py +7 -2
  12. hiddifypanel/drivers/xray_api.py +14 -9
  13. hiddifypanel/hutils/__init__.py +4 -0
  14. hiddifypanel/hutils/convert.py +13 -2
  15. hiddifypanel/hutils/crypto.py +48 -0
  16. hiddifypanel/hutils/encode.py +4 -1
  17. hiddifypanel/hutils/flask.py +38 -5
  18. hiddifypanel/hutils/github_issue.py +1 -1
  19. hiddifypanel/hutils/importer/xui.py +5 -2
  20. hiddifypanel/{models/utils.py → hutils/model.py} +14 -4
  21. hiddifypanel/hutils/network/auto_ip_selector.py +2 -0
  22. hiddifypanel/hutils/network/net.py +46 -2
  23. hiddifypanel/hutils/node/__init__.py +3 -0
  24. hiddifypanel/hutils/node/api_client.py +76 -0
  25. hiddifypanel/hutils/node/child.py +147 -0
  26. hiddifypanel/hutils/node/parent.py +100 -0
  27. hiddifypanel/hutils/node/shared.py +65 -0
  28. hiddifypanel/hutils/proxy/__init__.py +5 -0
  29. hiddifypanel/hutils/proxy/clash.py +161 -0
  30. hiddifypanel/hutils/proxy/shared.py +434 -0
  31. hiddifypanel/hutils/proxy/singbox.py +339 -0
  32. hiddifypanel/hutils/proxy/xray.py +235 -0
  33. hiddifypanel/hutils/proxy/xrayjson.py +391 -0
  34. hiddifypanel/hutils/random.py +4 -0
  35. hiddifypanel/hutils/utils.py +4 -1
  36. hiddifypanel/models/__init__.py +2 -2
  37. hiddifypanel/models/admin.py +31 -17
  38. hiddifypanel/models/base_account.py +7 -7
  39. hiddifypanel/models/child.py +30 -16
  40. hiddifypanel/models/config.py +45 -16
  41. hiddifypanel/models/config_enum.py +68 -17
  42. hiddifypanel/models/domain.py +28 -20
  43. hiddifypanel/models/parent_domain.py +2 -2
  44. hiddifypanel/models/proxy.py +29 -20
  45. hiddifypanel/models/report.py +2 -3
  46. hiddifypanel/models/usage.py +2 -2
  47. hiddifypanel/models/user.py +33 -22
  48. hiddifypanel/panel/admin/Actions.py +13 -19
  49. hiddifypanel/panel/admin/AdminstratorAdmin.py +14 -3
  50. hiddifypanel/panel/admin/Dashboard.py +5 -10
  51. hiddifypanel/panel/admin/DomainAdmin.py +35 -48
  52. hiddifypanel/panel/admin/NodeAdmin.py +6 -2
  53. hiddifypanel/panel/admin/ProxyAdmin.py +6 -5
  54. hiddifypanel/panel/admin/QuickSetup.py +21 -20
  55. hiddifypanel/panel/admin/SettingAdmin.py +107 -62
  56. hiddifypanel/panel/admin/UserAdmin.py +22 -21
  57. hiddifypanel/panel/admin/templates/index.html +1 -1
  58. hiddifypanel/panel/admin/templates/model/user_list.html +44 -20
  59. hiddifypanel/panel/admin/templates/parent_dash.html +2 -4
  60. hiddifypanel/panel/admin/templates/result.html +2 -3
  61. hiddifypanel/panel/cf_api.py +1 -2
  62. hiddifypanel/panel/cli.py +16 -16
  63. hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +16 -12
  64. hiddifypanel/panel/commercial/__init__.py +7 -5
  65. hiddifypanel/panel/commercial/restapi/v1/__init__.py +1 -1
  66. hiddifypanel/panel/commercial/restapi/v1/tgbot.py +1 -1
  67. hiddifypanel/panel/commercial/restapi/v1/tgmsg.py +14 -10
  68. hiddifypanel/panel/commercial/restapi/v2/admin/__init__.py +0 -5
  69. hiddifypanel/panel/commercial/restapi/v2/admin/admin_info_api.py +2 -2
  70. hiddifypanel/panel/commercial/restapi/v2/admin/admin_log_api.py +4 -5
  71. hiddifypanel/panel/commercial/restapi/v2/admin/admin_user_api.py +8 -25
  72. hiddifypanel/panel/commercial/restapi/v2/admin/admin_users_api.py +4 -4
  73. hiddifypanel/panel/commercial/restapi/v2/admin/schema.py +157 -0
  74. hiddifypanel/panel/commercial/restapi/v2/admin/server_status_api.py +3 -3
  75. hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +9 -66
  76. hiddifypanel/panel/commercial/restapi/v2/admin/users_api.py +1 -1
  77. hiddifypanel/panel/commercial/restapi/v2/child/__init__.py +18 -0
  78. hiddifypanel/panel/commercial/restapi/v2/child/actions.py +63 -0
  79. hiddifypanel/panel/commercial/restapi/v2/child/register_parent_api.py +34 -0
  80. hiddifypanel/panel/commercial/restapi/v2/child/schema.py +7 -0
  81. hiddifypanel/panel/commercial/restapi/v2/child/sync_parent_api.py +21 -0
  82. hiddifypanel/panel/commercial/restapi/v2/panel/__init__.py +13 -0
  83. hiddifypanel/panel/commercial/restapi/v2/panel/info.py +18 -0
  84. hiddifypanel/panel/commercial/restapi/v2/panel/ping_pong.py +23 -0
  85. hiddifypanel/panel/commercial/restapi/v2/panel/schema.py +7 -0
  86. hiddifypanel/panel/commercial/restapi/v2/parent/__init__.py +16 -0
  87. hiddifypanel/panel/commercial/restapi/v2/parent/register_api.py +65 -0
  88. hiddifypanel/panel/commercial/restapi/v2/parent/schema.py +115 -0
  89. hiddifypanel/panel/commercial/restapi/v2/parent/status_api.py +26 -0
  90. hiddifypanel/panel/commercial/restapi/v2/parent/sync_api.py +53 -0
  91. hiddifypanel/panel/commercial/restapi/v2/parent/usage_api.py +57 -0
  92. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +17 -23
  93. hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +23 -26
  94. hiddifypanel/panel/commercial/telegrambot/admin.py +1 -2
  95. hiddifypanel/panel/common.py +25 -8
  96. hiddifypanel/panel/common_bp/login.py +2 -2
  97. hiddifypanel/panel/hiddify.py +22 -185
  98. hiddifypanel/panel/init_db.py +102 -55
  99. hiddifypanel/panel/usage.py +33 -18
  100. hiddifypanel/panel/user/__init__.py +0 -1
  101. hiddifypanel/panel/user/templates/all_configs copy.txt +2 -2
  102. hiddifypanel/panel/user/templates/all_configs.txt +2 -2
  103. hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +2 -1
  104. hiddifypanel/panel/user/templates/base_xray_config.json.j2 +125 -0
  105. hiddifypanel/panel/user/templates/clash_config copy.yml +1 -1
  106. hiddifypanel/panel/user/templates/clash_config.yml +4 -4
  107. hiddifypanel/panel/user/templates/clash_proxies.yml +1 -1
  108. hiddifypanel/panel/user/templates/home/all-configs.html +2 -2
  109. hiddifypanel/panel/user/templates/home/all-configs_old.html +1 -1
  110. hiddifypanel/panel/user/templates/home/ios copy.html +2 -2
  111. hiddifypanel/panel/user/templates/home/usage.html +1 -1
  112. hiddifypanel/panel/user/templates/new.html +2 -2
  113. hiddifypanel/panel/user/user.py +56 -50
  114. hiddifypanel/static/css/custom.css +31 -0
  115. hiddifypanel/static/images/favicon.ico +0 -0
  116. hiddifypanel/static/images/hiddify-old.png +0 -0
  117. hiddifypanel/static/images/hiddify.png +0 -0
  118. hiddifypanel/static/images/hiddify2.png +0 -0
  119. hiddifypanel/static/new/assets/{index-1b891a7c.js → index-ccb9873c.js} +56 -56
  120. hiddifypanel/static/new/assets/index-fa00de9a.css +1 -0
  121. hiddifypanel/static/new/i18n/en.json +6 -6
  122. hiddifypanel/static/new/i18n/fa.json +2 -2
  123. hiddifypanel/templates/admin-layout.html +30 -43
  124. hiddifypanel/templates/fake.html +0 -4
  125. hiddifypanel/templates/flaskadmin-layout.html +7 -3
  126. hiddifypanel/templates/master.html +11 -6
  127. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  128. hiddifypanel/translations/en/LC_MESSAGES/messages.po +2082 -1977
  129. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  130. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +2035 -1924
  131. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  132. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +1911 -1848
  133. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  134. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +2019 -1874
  135. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  136. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +1873 -1742
  137. hiddifypanel/translations.i18n/en.json +992 -933
  138. hiddifypanel/translations.i18n/fa.json +994 -935
  139. hiddifypanel/translations.i18n/pt.json +1031 -972
  140. hiddifypanel/translations.i18n/ru.json +994 -935
  141. hiddifypanel/translations.i18n/zh.json +971 -912
  142. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/METADATA +47 -47
  143. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/RECORD +147 -120
  144. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/WHEEL +1 -1
  145. hiddifypanel/panel/commercial/restapi/v2/DTO.py +0 -9
  146. hiddifypanel/panel/commercial/restapi/v2/hello/__init__.py +0 -16
  147. hiddifypanel/panel/commercial/restapi/v2/hello/hello.py +0 -32
  148. hiddifypanel/panel/user/link_maker.py +0 -1083
  149. hiddifypanel/static/new/assets/index-669b32c8.css +0 -1
  150. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/LICENSE.md +0 -0
  151. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/entry_points.txt +0 -0
  152. {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/top_level.txt +0 -0
@@ -2,28 +2,63 @@ import datetime
2
2
  import json
3
3
  import os
4
4
  import random
5
- import string
6
5
  import sys
7
6
  import uuid
8
7
 
9
- from dateutil import relativedelta
10
8
 
11
9
  from hiddifypanel import Events, hutils
12
10
  from hiddifypanel.models import *
13
- from hiddifypanel.models import ConfigEnum, User, set_hconfig, ChildMode
14
11
  from hiddifypanel.panel import hiddify
15
- from hiddifypanel.database import db
16
- import hiddifypanel.models.utils as model_utils
17
-
12
+ from hiddifypanel.database import db, db_execute
13
+ from hiddifypanel import hutils
14
+ from sqlalchemy import text
18
15
  from flask import g
19
16
 
20
- MAX_DB_VERSION = 80
17
+ MAX_DB_VERSION = 90
18
+
19
+
20
+ def _v83(child_id):
21
+ set_hconfig(ConfigEnum.log_level, LogLevel.CRITICAL)
22
+
23
+
24
+ def _v82(child_id):
25
+ set_hconfig(ConfigEnum.vless_enable, True)
26
+ set_hconfig(ConfigEnum.trojan_enable, True)
27
+ set_hconfig(ConfigEnum.reality_enable, True)
28
+ set_hconfig(ConfigEnum.tcp_enable, True)
29
+ set_hconfig(ConfigEnum.quic_enable, True)
30
+ set_hconfig(ConfigEnum.xtls_enable, True)
31
+ set_hconfig(ConfigEnum.h2_enable, True)
32
+
33
+
34
+ def _v80(child_id):
35
+ set_hconfig(ConfigEnum.parent_domain, '')
36
+ set_hconfig(ConfigEnum.parent_admin_proxy_path, '')
37
+
38
+
39
+ def _v79(child_id):
40
+ set_hconfig(ConfigEnum.panel_mode, PanelMode.standalone)
41
+
42
+
43
+ def _v78(child_id):
44
+ # equalize panel unique id and root child unique id
45
+ root_child_unique_id = Child.query.filter(Child.name == "Root").first().unique_id
46
+ set_hconfig(ConfigEnum.unique_id, root_child_unique_id)
47
+
48
+
49
+ def _v77(child_id):
50
+ pass
51
+
52
+
53
+ def _v75(child_id):
54
+ for u in User.query.all():
55
+ hutils.model.gen_wg_keys(u)
21
56
 
22
57
 
23
58
  def _v74(child_id):
24
59
  set_hconfig(ConfigEnum.ws_enable, True)
25
60
  set_hconfig(ConfigEnum.grpc_enable, True)
26
- set_hconfig(ConfigEnum.httpupgrade_enable, False)
61
+ set_hconfig(ConfigEnum.httpupgrade_enable, True)
27
62
  set_hconfig(ConfigEnum.shadowsocks2022_port, hutils.random.get_random_unused_port())
28
63
  set_hconfig(ConfigEnum.shadowsocks2022_method, "2022-blake3-aes-256-gcm")
29
64
  set_hconfig(ConfigEnum.shadowsocks2022_enable, False)
@@ -66,12 +101,12 @@ def _v69():
66
101
  add_config_if_not_exist(ConfigEnum.wireguard_port, hutils.random.get_random_unused_port())
67
102
  add_config_if_not_exist(ConfigEnum.wireguard_ipv4, "10.90.0.1")
68
103
  add_config_if_not_exist(ConfigEnum.wireguard_ipv6, "fd42:42:90::1")
69
- wg_pk, wg_pub, _ = hiddify.get_wg_private_public_psk_pair()
104
+ wg_pk, wg_pub, _ = hutils.crypto.get_wg_private_public_psk_pair()
70
105
  add_config_if_not_exist(ConfigEnum.wireguard_private_key, wg_pk)
71
106
  add_config_if_not_exist(ConfigEnum.wireguard_public_key, wg_pub)
72
107
  add_config_if_not_exist(ConfigEnum.wireguard_noise_trick, "5-10")
73
108
  for u in User.query.all():
74
- u.wg_pk, u.wg_pub, u.wg_psk = hiddify.get_wg_private_public_psk_pair()
109
+ u.wg_pk, u.wg_pub, u.wg_psk = hutils.crypto.get_wg_private_public_psk_pair()
75
110
 
76
111
 
77
112
  def _v65():
@@ -86,10 +121,6 @@ def _v65():
86
121
  add_config_if_not_exist(ConfigEnum.mux_brutal_down_mbps, '100')
87
122
 
88
123
 
89
- def _v64():
90
- set_hconfig(ConfigEnum.ssh_server_redis_url, "unix:///opt/hiddify-manager/other/redis/run.sock?db=1")
91
-
92
-
93
124
  def _v63():
94
125
  add_config_if_not_exist(ConfigEnum.hysteria_enable, True)
95
126
  add_config_if_not_exist(ConfigEnum.hysteria_port, hutils.random.get_random_unused_port())
@@ -120,13 +151,13 @@ def _v60():
120
151
  def _v59():
121
152
  # set user model username and password
122
153
  for u in User.query.all():
123
- model_utils.fill_username(u)
124
- model_utils.fill_password(u)
154
+ hutils.model.gen_username(u)
155
+ hutils.model.gen_password(u)
125
156
 
126
157
  # set admin model username and password
127
158
  for a in AdminUser.query.all():
128
- model_utils.fill_username(a)
129
- model_utils.fill_password(a)
159
+ hutils.model.gen_username(a)
160
+ hutils.model.gen_password(a)
130
161
 
131
162
 
132
163
  def _v57():
@@ -164,7 +195,7 @@ def _v50():
164
195
  def _v49():
165
196
 
166
197
  for u in User.query.all():
167
- priv, publ = hiddify.get_ed25519_private_public_pair()
198
+ priv, publ = hutils.crypto.get_ed25519_private_public_pair()
168
199
  u.ed25519_private_key = priv
169
200
  u.ed25519_public_key = publ
170
201
 
@@ -182,7 +213,7 @@ def _v45():
182
213
 
183
214
  if not Proxy.query.filter(Proxy.name == "SSH").first():
184
215
  db.session.add(Proxy(l3='ssh', transport='ssh', cdn='direct', proto='ssh', enable=True, name="SSH"))
185
- add_config_if_not_exist(ConfigEnum.ssh_server_redis_url, "unix:///opt/hiddify-manager/other/redis/run.sock?db=1")
216
+
186
217
  add_config_if_not_exist(ConfigEnum.ssh_server_port, hutils.random.get_random_unused_port())
187
218
  add_config_if_not_exist(ConfigEnum.ssh_server_enable, False)
188
219
  # def _v43():
@@ -224,7 +255,7 @@ def _v33():
224
255
 
225
256
  def _v31():
226
257
  add_config_if_not_exist(ConfigEnum.reality_short_ids, uuid.uuid4().hex[0:random.randint(1, 8) * 2])
227
- key_pair = hiddify.generate_x25519_keys()
258
+ key_pair = hutils.crypto.generate_x25519_keys()
228
259
  add_config_if_not_exist(ConfigEnum.reality_private_key, key_pair['private_key'])
229
260
  add_config_if_not_exist(ConfigEnum.reality_public_key, key_pair['public_key'])
230
261
  db.session.bulk_save_objects(get_proxy_rows_v1())
@@ -370,7 +401,7 @@ def _v7():
370
401
  Proxy.query.filter(Proxy.name == 'tls XTLSVision direct trojan').delete()
371
402
  except BaseException:
372
403
  pass
373
- add_config_if_not_exist(ConfigEnum.telegram_lib, "python")
404
+ add_config_if_not_exist(ConfigEnum.telegram_lib, "erlang")
374
405
  add_config_if_not_exist(ConfigEnum.admin_lang, hconfig(ConfigEnum.lang))
375
406
  add_config_if_not_exist(ConfigEnum.branding_title, "")
376
407
  add_config_if_not_exist(ConfigEnum.branding_site, "")
@@ -506,7 +537,7 @@ def make_proxy_rows(cfgs):
506
537
 
507
538
  def add_config_if_not_exist(key: ConfigEnum, val: str | int, child_id: int | None = None):
508
539
  if child_id is None:
509
- child_id = Child.current.id
540
+ child_id = Child.current().id
510
541
 
511
542
  old_val = hconfig(key, child_id)
512
543
  print(key, val, child_id, old_val)
@@ -517,15 +548,18 @@ def add_config_if_not_exist(key: ConfigEnum, val: str | int, child_id: int | Non
517
548
  def add_column(column):
518
549
  try:
519
550
  column_type = column.type.compile(db.engine.dialect)
520
- db.engine.execute(f'ALTER TABLE {column.table.name} ADD COLUMN {column.name} {column_type}')
551
+
552
+ db_execute(f'ALTER TABLE {column.table.name} ADD COLUMN {column.name} {column_type}')
521
553
  except BaseException:
522
554
  pass
523
555
 
524
556
 
525
- def execute(query):
557
+ def execute(query: str):
526
558
  try:
527
- db.engine.execute(query)
528
- except BaseException:
559
+
560
+ db_execute(query)
561
+ except BaseException as e:
562
+ print(e)
529
563
  pass
530
564
 
531
565
 
@@ -545,7 +579,8 @@ def add_new_enum_values():
545
579
  # Get the values in the enum column in the database
546
580
  # result = db.engine.execute(f"SELECT DISTINCT `{column_name}` FROM {table_name}")
547
581
  # db_values = {row[0] for row in result}
548
- result = db.engine.execute(f"SHOW COLUMNS FROM {table_name} LIKE '{column_name}';")
582
+
583
+ result = db_execute(f"SHOW COLUMNS FROM {table_name} LIKE '{column_name}';")
549
584
  db_values = []
550
585
 
551
586
  for row in result:
@@ -564,7 +599,7 @@ def add_new_enum_values():
564
599
  # Add the new value to the enum column in the database
565
600
  enumstr = ','.join([f"'{a}'" for a in [*existing_values, *old_values]])
566
601
 
567
- db.engine.execute(f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});")
602
+ db_execute(text(f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});"))
568
603
 
569
604
  db.session.commit()
570
605
 
@@ -618,8 +653,8 @@ def init_db():
618
653
  get_hconfigs.invalidate_all()
619
654
  # set_hconfig(ConfigEnum.db_version, 71)
620
655
  # temporary fix
621
- # add_column(Child.mode)
622
- # add_column(Child.name)
656
+ add_column(Child.mode)
657
+ add_column(Child.name)
623
658
  db_version = int(hconfig(ConfigEnum.db_version) or 0)
624
659
  if db_version == latest_db_version():
625
660
  return
@@ -664,32 +699,44 @@ def init_db():
664
699
 
665
700
 
666
701
  def migrate(db_version):
667
- execute('CREATE INDEX date ON daily_usage (date);')
668
- execute('CREATE INDEX username ON user (username);')
669
- execute('CREATE INDEX username ON admin_user (username);')
670
- execute('CREATE INDEX telegram_id ON user (telegram_id);')
671
- execute('CREATE INDEX telegram_id ON admin_user (telegram_id);')
672
-
673
- execute('ALTER TABLE proxy DROP INDEX `name`;')
674
-
675
- execute("alter table user alter column telegram_id bigint;")
676
- execute("alter table admin_user alter column telegram_id bigint;")
702
+ for table_name, table_obj in db.metadata.tables.items():
703
+ for column in table_obj.columns:
704
+ add_column(column)
705
+ Events.db_prehook.notify()
706
+ if db_version < 82:
707
+ execute('ALTER TABLE child DROP INDEX `name`;')
708
+ if db_version < 77:
709
+ execute('ALTER TABLE user_detail DROP COLUMN connected_ips;')
710
+ execute('update user_detail set connected_devices="" where connected_devices IS NULL')
711
+
712
+ if db_version < 70:
713
+ execute('CREATE INDEX date ON daily_usage (date);')
714
+ execute('CREATE INDEX username ON user (username);')
715
+ execute('CREATE INDEX username ON admin_user (username);')
716
+ execute('CREATE INDEX telegram_id ON user (telegram_id);')
717
+ execute('CREATE INDEX telegram_id ON admin_user (telegram_id);')
718
+
719
+ execute('ALTER TABLE proxy DROP INDEX `name`;')
720
+
721
+ execute("ALTER TABLE user MODIFY COLUMN telegram_id BIGINT;")
722
+ execute("ALTER TABLE admin_user MODIFY COLUMN telegram_id BIGINT;")
723
+
724
+ # aaa
725
+ # # add_column(UserDetail.connected_devices)
726
+ # add_column(Child.mode)
727
+ # add_column(Child.name)
728
+ # add_column(User.lang)
729
+ # add_column(AdminUser.lang)
730
+ # add_column(User.username)
731
+ # add_column(User.password)
732
+ # add_column(AdminUser.username)
733
+ # add_column(AdminUser.password)
734
+ # add_column(User.wg_pk)
735
+ # add_column(User.wg_pub)
736
+ # add_column(User.wg_psk)
677
737
 
678
- add_column(Child.mode)
679
- add_column(Child.name)
680
- add_column(User.lang)
681
- add_column(AdminUser.lang)
682
- add_column(User.username)
683
- add_column(User.password)
684
- add_column(AdminUser.username)
685
- add_column(AdminUser.password)
686
- add_column(User.wg_pk)
687
- add_column(User.wg_pub)
688
- add_column(User.wg_psk)
689
-
690
- add_column(Domain.extra_params)
738
+ # add_column(Domain.extra_params)
691
739
 
692
- Events.db_prehook.notify()
693
740
  if db_version < 52:
694
741
  execute(f'update domain set mode="sub_link_only", sub_link_only=false where sub_link_only = true or mode=1 or mode="1"')
695
742
  execute(f'update domain set mode="direct", sub_link_only=false where mode=0 or mode="0"')
@@ -1,34 +1,36 @@
1
1
  from flask_babel import lazy_gettext as _
2
2
  from sqlalchemy import func
3
+ from typing import Dict
3
4
  import datetime
4
5
 
5
6
  from hiddifypanel.drivers import user_driver
6
7
  from hiddifypanel.models import *
7
8
  from hiddifypanel.panel import hiddify
8
9
  from hiddifypanel.database import db
10
+ from hiddifypanel import hutils
9
11
 
10
12
  to_gig_d = 1024**3
11
13
 
12
14
 
13
15
  def update_local_usage():
14
16
  res = user_driver.get_users_usage(reset=True)
15
- return add_users_usage(res, child_id=0)
17
+ return _add_users_usage(res, child_id=0)
16
18
 
17
19
  # return {"status": 'success', "comments":res}
18
20
 
19
21
 
20
- def add_users_usage_uuid(uuids_bytes, child_id):
21
- users = User.query.filter(User.uuid.in_(keys(uuids_bytes)))
22
+ def add_users_usage_uuid(uuids_bytes: Dict[str, Dict], child_id, sync=False):
23
+ uuids_bytes = {u: v for u, v in uuids_bytes.items() if v}
24
+ uuids = uuids_bytes.keys()
25
+ users = User.query.filter(User.uuid.in_(uuids))
22
26
  dbusers_bytes = {u: uuids_bytes.get(u.uuid, 0) for u in users}
23
- add_users_usage(dbusers_bytes, child_id)
27
+ _add_users_usage(dbusers_bytes, child_id, sync) # type: ignore
24
28
 
25
29
 
26
- def add_users_usage(dbusers_bytes, child_id):
27
- print(dbusers_bytes)
28
- if not hconfig(ConfigEnum.is_parent) and hconfig(ConfigEnum.parent_panel):
29
- from hiddifypanel.panel import hiddify_api
30
- hiddify_api.add_user_usage_to_parent(dbusers_bytes)
31
-
30
+ def _add_users_usage(users_usage_data: Dict[User, Dict], child_id, sync=False):
31
+ '''
32
+ sync: when enabled, it means we have received usages from the parent panel
33
+ '''
32
34
  res = {}
33
35
  have_change = False
34
36
  before_enabled_users = user_driver.get_enabled_users()
@@ -42,16 +44,16 @@ def add_users_usage(dbusers_bytes, child_id):
42
44
  daily_usage[adm.id].online = User.query.filter(User.added_by == adm.id).filter(func.DATE(User.last_online) == today).count()
43
45
  # db.session.commit()
44
46
  userDetails = {p.user_id: p for p in UserDetail.query.filter(UserDetail.child_id == child_id).all()}
45
- for user, uinfo in dbusers_bytes.items():
47
+ for user, uinfo in users_usage_data.items():
46
48
  usage_bytes = uinfo['usage']
47
- ips = uinfo['ips']
49
+ devices = uinfo['devices']
48
50
  # user_active_before=user.is_active
49
51
  detail = userDetails.get(user.id)
50
52
  if not detail:
51
53
  detail = UserDetail(user_id=user.id, child_id=child_id)
52
54
  detail.current_usage_GB = detail.current_usage_GB or 0
53
55
  db.session.add(detail)
54
- detail.connected_ips = ips
56
+ detail.connected_devices = devices
55
57
  detail.current_usage_GB = detail.current_usage_GB or 0
56
58
  if not user.last_reset_time or user.user_should_reset():
57
59
  user.last_reset_time = datetime.date.today()
@@ -66,11 +68,20 @@ def add_users_usage(dbusers_bytes, child_id):
66
68
  if not isinstance(usage_bytes, int) or usage_bytes == 0:
67
69
  res[user.uuid] = "No usage"
68
70
  else:
69
- daily_usage.get(user.added_by, daily_usage[1]).usage += usage_bytes
71
+ if sync:
72
+ if daily_usage.get(user.added_by, daily_usage[1]).usage != usage_bytes:
73
+ daily_usage.get(user.added_by, daily_usage[1]).usage = usage_bytes
74
+ else:
75
+ daily_usage.get(user.added_by, daily_usage[1]).usage += usage_bytes
70
76
  in_gig = (usage_bytes) / to_gig_d
71
77
  res[user.uuid] = in_gig
72
- user.current_usage_GB += in_gig
73
- detail.current_usage_GB += in_gig
78
+ if sync:
79
+ if user.current_usage_GB != in_gig:
80
+ user.current_usage_GB = in_gig
81
+ # detail.current_usage_GB = in_gig
82
+ else:
83
+ user.current_usage_GB += in_gig
84
+ detail.current_usage_GB += in_gig
74
85
  user.last_online = datetime.datetime.now()
75
86
  detail.last_online = datetime.datetime.now()
76
87
 
@@ -83,15 +94,19 @@ def add_users_usage(dbusers_bytes, child_id):
83
94
  have_change = True
84
95
  res[user.uuid] = f"{res[user.uuid]} !OUT of USAGE! Client Removed"
85
96
 
86
- db.session.commit()
97
+ db.session.commit() # type: ignore
87
98
  if have_change:
88
99
  hiddify.quick_apply_users()
89
100
 
101
+ # sync with the parent
102
+ if not sync:
103
+ if hutils.node.is_child():
104
+ hutils.node.child.sync_users_usage_with_parent()
90
105
  return {"status": 'success', "comments": res}
91
106
 
92
107
 
93
108
  def send_bot_message(user):
94
- if not (hconfig(ConfigEnum.telegram_bot_token) and not hconfig(ConfigEnum.parent_panel)):
109
+ if not (hconfig(ConfigEnum.telegram_bot_token) or not hutils.node.is_parent()):
95
110
  return
96
111
  if not user.telegram_id:
97
112
  return
@@ -1,6 +1,5 @@
1
1
  from .user import UserView
2
2
  from flask import send_from_directory
3
- from . import link_maker
4
3
  from flask import Blueprint
5
4
  from hiddifypanel.database import db
6
5
 
@@ -1,4 +1,4 @@
1
- {% for type in link_maker.all_proxies(d.child_id) %}
1
+ {% for type in link_maker.get_all_proxies(d.child_id,only_enabled=True) %}
2
2
  {% set pinfo=link_maker.proxy_info(type) %}
3
3
  # {{type}} {{domain}}
4
4
  {{pinfo['url']}}
@@ -16,7 +16,7 @@
16
16
  # HTTP Not Secure
17
17
  # HTTP Not Secure
18
18
 
19
- {% for type in link_maker.all_proxies(d.child_id) %}
19
+ {% for type in link_maker.get_all_proxies(d.child_id,only_enabled=True) %}
20
20
  {% set pinfo=link_maker.proxy_info(type,port=80,security="http") %}
21
21
  {% if pinfo!=None %}
22
22
  # HTTP {{type}} {{domain}}
@@ -14,10 +14,10 @@ trojan://1@{{fake_ip_for_sub_link}}?sni=fake_ip_for_sub_link&security=tls#{{user
14
14
  ####################################
15
15
  ## {% if d.has_auto_ip %}Auto {%endif%} {{d.mode}} {{d.alias or d.domain}} {{t}}:{{port}}
16
16
  ####################################
17
- {% for type in link_maker.all_proxies(d.child_id) %}
17
+ {% for type in link_maker.get_all_proxies(d.child_id, only_enabled=True) %}
18
18
  {% set pinfo=link_maker.make_proxy(type,d,phttp=phttp,ptls=ptls) %}
19
19
  {% if 'msg' not in pinfo %}
20
- {% set link=link_maker.to_link(pinfo) %}
20
+ {% set link=link_maker.xray.to_link(pinfo) %}
21
21
  {% if 'msg' not in link %}
22
22
  {{''}}
23
23
  # {{pinfo["name"]}} {{d.alias or d.domain}}
@@ -170,6 +170,7 @@
170
170
  "domain": [
171
171
  "github.com",
172
172
  "githubusercontent.com",
173
+ "raw.githubusercontent.com",
173
174
  "1.1.1.1"
174
175
  ],
175
176
  "server": "dns-local"
@@ -225,4 +226,4 @@
225
226
  "type": "mixed"
226
227
  }
227
228
  ]
228
- }
229
+ }
@@ -0,0 +1,125 @@
1
+ {
2
+ "remarks": "{{remarks}}",
3
+ "log": {
4
+ "access": "",
5
+ "error": "",
6
+ "loglevel": "warning"
7
+ },
8
+ "inbounds": [
9
+ {
10
+ "tag": "socks",
11
+ "port": 10808,
12
+ "listen": "127.0.0.1",
13
+ "protocol": "socks",
14
+ "sniffing": {
15
+ "enabled": true,
16
+ "destOverride": [
17
+ "http",
18
+ "tls"
19
+ ],
20
+ "routeOnly": false
21
+ },
22
+ "settings": {
23
+ "auth": "noauth",
24
+ "udp": true,
25
+ "allowTransparent": false
26
+ }
27
+ },
28
+ {
29
+ "tag": "http",
30
+ "port": 10809,
31
+ "listen": "127.0.0.1",
32
+ "protocol": "http",
33
+ "sniffing": {
34
+ "enabled": true,
35
+ "destOverride": [
36
+ "http",
37
+ "tls"
38
+ ],
39
+ "routeOnly": false
40
+ },
41
+ "settings": {
42
+ "auth": "noauth",
43
+ "udp": true,
44
+ "allowTransparent": false
45
+ }
46
+ }
47
+ ],
48
+ "outbounds": [
49
+ {
50
+ "tag": "fragment",
51
+ "protocol": "freedom",
52
+ "settings": {
53
+ "domainStrategy": "AsIs"
54
+ {% if hconfig(ConfigEnum.tls_fragment_enable) %}
55
+ ,"fragment": {
56
+ "packets": "tlshello",
57
+ "length": "{{ hconfig(ConfigEnum.tls_fragment_size) }}",
58
+ "interval": "{{ hconfig(ConfigEnum.tls_fragment_sleep) }}"
59
+ }
60
+ {% endif %}
61
+ },
62
+ "streamSettings": {
63
+ "sockopt": {
64
+ "tcpNoDelay": true,
65
+ "tcpKeepAliveIdle": 100
66
+ }
67
+ }
68
+ },
69
+ {
70
+ "tag": "direct",
71
+ "protocol": "freedom",
72
+ "settings": {}
73
+ },
74
+ {
75
+ "tag": "block",
76
+ "protocol": "blackhole",
77
+ "settings": {
78
+ "response": {
79
+ "type": "http"
80
+ }
81
+ }
82
+ }
83
+ ],
84
+ "routing": {
85
+ "domainStrategy": "AsIs",
86
+ "rules": [
87
+ {
88
+ "type": "field",
89
+ "inboundTag": [
90
+ "api"
91
+ ],
92
+ "outboundTag": "api",
93
+ "enabled": true
94
+ },
95
+ {
96
+ "id": "5465425548310166497",
97
+ "type": "field",
98
+ "outboundTag": "direct",
99
+ "domain": [
100
+ "domain:ir",
101
+ "geosite:cn"
102
+ ],
103
+ "enabled": true
104
+ },
105
+ {
106
+ "id": "5425034033205580637",
107
+ "type": "field",
108
+ "outboundTag": "direct",
109
+ "ip": [
110
+ "geoip:private",
111
+ "geoip:cn",
112
+ "geoip:ir"
113
+ ],
114
+ "enabled": true
115
+ },
116
+ {
117
+ "id": "5627785659655799759",
118
+ "type": "field",
119
+ "port": "0-65535",
120
+ "outboundTag": "proxy",
121
+ "enabled": true
122
+ }
123
+ ]
124
+ }
125
+ }
@@ -180,7 +180,7 @@ proxy-groups:
180
180
 
181
181
 
182
182
 
183
- {#link_maker.get_all_clash_configs(meta_or_normal,domains)#}
183
+ {#link_maker.clash.get_all_clash_configs(meta_or_normal,domains)#}
184
184
 
185
185
  proxy-providers:
186
186
  all_proxies:
@@ -51,7 +51,7 @@ proxy-groups:
51
51
  proxies:
52
52
  - automatic
53
53
  - sequential
54
- {{link_maker.get_clash_config_names(meta_or_normal,domains)|indent(6)}}
54
+ {{link_maker.clash.get_clash_config_names(meta_or_normal,domains)|indent(6)}}
55
55
 
56
56
  # use:
57
57
  # %for phttp in hconfigs[ConfigEnum.http_ports].split(',')
@@ -88,7 +88,7 @@ proxy-groups:
88
88
  url: "http://cp.cloudflare.com"
89
89
  interval: 300
90
90
  proxies:
91
- {{link_maker.get_clash_config_names(meta_or_normal,domains)|indent(6)}}
91
+ {{link_maker.clash.get_clash_config_names(meta_or_normal,domains)|indent(6)}}
92
92
  # use:
93
93
  # %for phttp in hconfigs[ConfigEnum.http_ports].split(',')
94
94
  # - all_proxies_{{phttp}}
@@ -99,7 +99,7 @@ proxy-groups:
99
99
 
100
100
  - name: auto
101
101
  proxies:
102
- {{link_maker.get_clash_config_names(meta_or_normal,domains)|indent(6)}}
102
+ {{link_maker.clash.get_clash_config_names(meta_or_normal,domains)|indent(6)}}
103
103
  # use:
104
104
  # %for phttp in hconfigs[ConfigEnum.http_ports].split(',')
105
105
  # - all_proxies_{{phttp}}
@@ -116,7 +116,7 @@ proxy-groups:
116
116
 
117
117
 
118
118
 
119
- {{link_maker.get_all_clash_configs(meta_or_normal,domains)}}
119
+ {{link_maker.clash.get_all_clash_configs(meta_or_normal,domains)}}
120
120
 
121
121
  # proxy-providers:
122
122
  # %for t in (['http','tls'] if hconfigs[ConfigEnum.http_proxy_enable] else ['tls'])
@@ -1,5 +1,5 @@
1
1
 
2
- {{link_maker.get_all_clash_configs(meta_or_normal,domains)}}
2
+ {{link_maker.clash.get_all_clash_configs(meta_or_normal,domains)}}
3
3
 
4
4
 
5
5
  {% if False %}
@@ -108,10 +108,10 @@
108
108
  <td><span class="badge badge-success">{{_('all')}}</span></td>
109
109
  </tr>
110
110
 
111
- {% for pinfo in link_maker.get_all_validated_proxies(domains) %}
111
+ {% for pinfo in link_maker.get_valid_proxies(domains) %}
112
112
  <tr>
113
113
  <td>
114
- <div class="btn-group"><a href='{{link_maker.to_link(pinfo)}}' class="btn btn-light orig-link">{{pinfo["name"].replace("_", " ")}}</a></div>
114
+ <div class="btn-group"><a href='{{link_maker.xray.to_link(pinfo)}}' class="btn btn-light orig-link">{{pinfo["name"].replace("_", " ")}}</a></div>
115
115
  </td>
116
116
  <td><span class="badge badge-danger"> {% if pinfo['dbdomain'].has_auto_ip %}Auto {%endif%}{{pinfo["mode"]}}</span></td>
117
117
  <td><span class="badge ltr">{{pinfo['server']}}</span></td>
@@ -48,7 +48,7 @@
48
48
  <td><span class="badge badge-success">{{_('all')}}</span></td>
49
49
  </tr>
50
50
 
51
- {% for type in link_maker.all_proxies() %}
51
+ {% for type in link_maker.get_all_proxies(only_enabled=True) %}
52
52
  {% for mode in ["tls","http"] %}
53
53
  {% set pinfo=link_maker.proxy_info(type,mode=mode) %}
54
54
  {% if pinfo!=None %}
@@ -51,7 +51,7 @@
51
51
  سپس کانفیگ مورد نظر را انتخاب و اجرا نمایید.
52
52
  <br>
53
53
 
54
- {% for type in link_maker.all_proxies() %}
54
+ {% for type in link_maker.get_all_proxies(only_enabled=True) %}
55
55
  {% set pinfo=link_maker.proxy_info(type) %}
56
56
  {% if pinfo!=None %}
57
57
  <div class="btn-group"><a href='{{pinfo["url"]}}' class="btn btn-primary orig-link">{{type}}</a></div>
@@ -107,7 +107,7 @@
107
107
  <br />
108
108
  سپس کانفیگ مورد نظر خود را اعمال کنید:
109
109
  <br />
110
- {% for type in link_maker.all_proxies() %}
110
+ {% for type in link_maker.get_all_proxies(only_enabled=True) %}
111
111
  {% set pinfo=link_maker.proxy_info(type) %}
112
112
  {% if pinfo!=None %}
113
113
  <div class="btn-group"><a href='{{pinfo["url"]}}' class="btn btn-primary orig-link">{{type}}</a></div>
@@ -23,7 +23,7 @@
23
23
  {% endif %}
24
24
  {% if not user.is_active %}
25
25
  {{_("User is inactive")}}
26
- {% if (user.ips|length)>user.max_ips: %}
26
+ {% if (user.devices|length)>user.max_ips: %}
27
27
  <br>
28
28
  <i class="fa-solid fa-users-slash text-danger"></i> {{_("Too many Connected IPs")}}
29
29
  {% endif %}