hiddifypanel 9.0.0.dev90__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 +60 -52
  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 -1840
  133. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  134. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +2036 -1881
  135. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  136. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +1857 -1720
  137. hiddifypanel/translations.i18n/en.json +992 -933
  138. hiddifypanel/translations.i18n/fa.json +994 -935
  139. hiddifypanel/translations.i18n/pt.json +994 -935
  140. hiddifypanel/translations.i18n/ru.json +994 -935
  141. hiddifypanel/translations.i18n/zh.json +971 -912
  142. {hiddifypanel-9.0.0.dev90.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/METADATA +47 -47
  143. {hiddifypanel-9.0.0.dev90.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/RECORD +147 -120
  144. {hiddifypanel-9.0.0.dev90.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.dev90.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/LICENSE.md +0 -0
  151. {hiddifypanel-9.0.0.dev90.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/entry_points.txt +0 -0
  152. {hiddifypanel-9.0.0.dev90.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,13 @@
1
- from hiddifypanel.models.config_enum import ConfigEnum
1
+ from typing import Optional
2
+ from hiddifypanel.models.config_enum import ConfigEnum, LogLevel, PanelMode, Lang
2
3
  from flask import g
3
- from sqlalchemy_serializer import SerializerMixin
4
+
4
5
  from hiddifypanel import Events
5
6
  from hiddifypanel.database import db
6
7
  from hiddifypanel.cache import cache
7
8
  from hiddifypanel.models.child import Child, ChildMode
8
9
  from sqlalchemy import Column, String, Boolean, Enum, ForeignKey, Integer
10
+ from strenum import StrEnum
9
11
 
10
12
 
11
13
  def error(st):
@@ -13,7 +15,7 @@ def error(st):
13
15
  err(st)
14
16
 
15
17
 
16
- class BoolConfig(db.Model, SerializerMixin):
18
+ class BoolConfig(db.Model):
17
19
  child_id = Column(Integer, ForeignKey('child.id'), primary_key=True, default=0)
18
20
  # category = db.Column(db.String(128), primary_key=True)
19
21
  key = Column(Enum(ConfigEnum), primary_key=True)
@@ -26,8 +28,17 @@ class BoolConfig(db.Model, SerializerMixin):
26
28
  'child_unique_id': d.child.unique_id if d.child else ''
27
29
  }
28
30
 
31
+ @staticmethod
32
+ def from_schema(schema):
33
+ return schema.dump(BoolConfig())
34
+
35
+ def to_schema(self):
36
+ conf_dict = self.to_dict()
37
+ from hiddifypanel.panel.commercial.restapi.v2.parent.schema import HConfigSchema
38
+ return HConfigSchema().load(conf_dict)
29
39
 
30
- class StrConfig(db.Model, SerializerMixin):
40
+
41
+ class StrConfig(db.Model):
31
42
  child_id = Column(Integer, ForeignKey('child.id'), primary_key=True, default=0)
32
43
  # category = db.Column(db.String(128), primary_key=True)
33
44
  key = Column(Enum(ConfigEnum), primary_key=True, default=ConfigEnum.admin_secret)
@@ -40,11 +51,20 @@ class StrConfig(db.Model, SerializerMixin):
40
51
  'child_unique_id': d.child.unique_id if d.child else ''
41
52
  }
42
53
 
54
+ @staticmethod
55
+ def from_schema(schema):
56
+ return schema.dump(StrConfig())
57
+
58
+ def to_schema(self):
59
+ conf_dict = self.to_dict()
60
+ from hiddifypanel.panel.commercial.restapi.v2.parent.schema import HConfigSchema
61
+ return HConfigSchema().load(conf_dict)
62
+
43
63
 
44
64
  @cache.cache(ttl=500)
45
- def hconfig(key: ConfigEnum, child_id: int | None = None) -> str | int | None:
65
+ def hconfig(key: ConfigEnum, child_id: Optional[int] = None): # -> str | int | StrEnum | None:
46
66
  if child_id is None:
47
- child_id = Child.current.id
67
+ child_id = Child.current().id
48
68
 
49
69
  value = None
50
70
  try:
@@ -63,20 +83,29 @@ def hconfig(key: ConfigEnum, child_id: int | None = None) -> str | int | None:
63
83
  except BaseException:
64
84
  error(f'{key} error!')
65
85
  raise
86
+ if value != None:
87
+ if key.type == int:
88
+ return int(value)
89
+ elif hasattr(key.type, 'from_str'):
90
+ return key.type.from_str(value)
66
91
 
67
92
  return value
68
93
 
69
94
 
70
- def set_hconfig(key: ConfigEnum, value: str | int | bool, child_id: int = None, commit: bool = True):
95
+ def set_hconfig(key: ConfigEnum, value: str | int | bool, child_id: int | None = None, commit: bool = True):
71
96
  if child_id is None:
72
- child_id = Child.current.id
97
+ child_id = Child.current().id
98
+
73
99
  print(f"chainging .... {key}---{value}---{child_id}---{commit}")
100
+ if key.type == int and value != None:
101
+ int(value) # for testing int
102
+
74
103
  # hconfig.invalidate(key, child_id)
75
104
  # get_hconfigs.invalidate(child_id)
76
105
  hconfig.invalidate(key, child_id)
77
106
  hconfig.invalidate(key, child_id=child_id)
78
107
  hconfig.invalidate(key=key, child_id=child_id)
79
- if child_id == Child.current.id:
108
+ if child_id == Child.current().id:
80
109
  hconfig.invalidate(key)
81
110
  # hconfig.invalidate_all()
82
111
  get_hconfigs.invalidate_all()
@@ -108,12 +137,12 @@ def set_hconfig(key: ConfigEnum, value: str | int | bool, child_id: int = None,
108
137
 
109
138
 
110
139
  @cache.cache(ttl=500,)
111
- def get_hconfigs(child_id: int | None = None, json=False):
140
+ def get_hconfigs(child_id: int | None = None, json=False) -> dict:
112
141
  if child_id is None:
113
- child_id = Child.current.id
142
+ child_id = Child.current().id
114
143
 
115
144
  return {**{f'{u.key}' if json else u.key: u.value for u in BoolConfig.query.filter(BoolConfig.child_id == child_id).all() if u.key.type == bool},
116
- **{f'{u.key}' if json else u.key: u.value for u in StrConfig.query.filter(StrConfig.child_id == child_id).all() if u.key.type != bool},
145
+ **{f'{u.key}' if json else u.key: int(u.value) if u.key.type == int and u.value != None else u.value for u in StrConfig.query.filter(StrConfig.child_id == child_id).all() if u.key.type != bool},
117
146
  # ConfigEnum.telegram_fakedomain:hdomain(DomainType.telegram_faketls),
118
147
  # ConfigEnum.ssfaketls_fakedomain:hdomain(DomainType.ss_faketls),
119
148
  # ConfigEnum.fake_cdn_domain:hdomain(DomainType.fake_cdn)
@@ -126,9 +155,9 @@ def get_hconfigs_childs(child_ids: list[int], json=False):
126
155
  return {c: get_hconfigs(c, json) for c in child_ids}
127
156
 
128
157
 
129
- def add_or_update_config(commit: bool = True, child_id: int = None, override_unique_id: bool = True, **config):
158
+ def add_or_update_config(commit: bool = True, child_id: int | None = None, override_unique_id: bool = True, **config):
130
159
  if child_id is None:
131
- child_id = Child.current.id
160
+ child_id = Child.current().id
132
161
  c = config['key']
133
162
  ckey = ConfigEnum(c)
134
163
  if c == ConfigEnum.unique_id and not override_unique_id:
@@ -140,13 +169,13 @@ def add_or_update_config(commit: bool = True, child_id: int = None, override_uni
140
169
  set_hconfig(ckey, v, child_id, commit=commit)
141
170
 
142
171
 
143
- def bulk_register_configs(hconfigs, commit: bool = True, override_child_unique_id: int | None = None, override_unique_id: bool = True):
172
+ def bulk_register_configs(hconfigs, commit: bool = True, froce_child_unique_id: str | None = None, override_unique_id: bool = True):
144
173
  from hiddifypanel.panel import hiddify
145
174
  for conf in hconfigs:
146
175
  # print(conf)
147
176
  if conf['key'] == ConfigEnum.unique_id and not override_unique_id:
148
177
  continue
149
- child_id = hiddify.get_child(unique_id=None)
178
+ child_id = hiddify.get_child(unique_id=froce_child_unique_id)
150
179
  # print(conf, child_id, conf.get('child_unique_id', None), override_child_unique_id)
151
180
  add_or_update_config(commit=False, child_id=child_id, **conf)
152
181
  if commit:
@@ -5,7 +5,13 @@ from strenum import StrEnum
5
5
  from fast_enum import FastEnum
6
6
 
7
7
 
8
- class Lang(StrEnum):
8
+ class HEnum(StrEnum):
9
+ @classmethod
10
+ def from_str(cls, key: str) -> 'HEnum':
11
+ return cls[key]
12
+
13
+
14
+ class Lang(HEnum):
9
15
  en = auto()
10
16
  fa = auto()
11
17
  ru = auto()
@@ -13,6 +19,22 @@ class Lang(StrEnum):
13
19
  zh = auto()
14
20
 
15
21
 
22
+ class PanelMode(HEnum):
23
+ standalone = auto()
24
+ parent = auto()
25
+ child = auto()
26
+
27
+
28
+ class LogLevel(HEnum):
29
+ TRACE = auto()
30
+ DEBUG = auto()
31
+ INFO = auto()
32
+ SUCCESS = auto()
33
+ WARNING = auto()
34
+ ERROR = auto()
35
+ CRITICAL = auto()
36
+
37
+
16
38
  class ConfigCategory(StrEnum):
17
39
  admin = auto()
18
40
  branding = auto()
@@ -55,11 +77,19 @@ def _StrConfigDscr(category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.n
55
77
  return category, apply_mode, str, show_in_parent
56
78
 
57
79
 
80
+ def _IntConfigDscr(category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False):
81
+ return category, apply_mode, int, show_in_parent
82
+
83
+
84
+ def _TypedConfigDscr(ctype: type, category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False):
85
+ return category, apply_mode, ctype, show_in_parent
86
+
87
+
58
88
  class ConfigEnum(metaclass=FastEnum):
59
89
  # category: ConfigCategory
60
- __slots__ = ('category', 'apply_mode', 'type', 'show_in_parent', 'hide_in_virtual_child')
90
+ __slots__ = ('name', 'value', 'category', 'apply_mode', 'type', 'show_in_parent', 'hide_in_virtual_child')
61
91
 
62
- def __init__(self, category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.apply, ctype=str, show_in_parent: bool = True, hide_in_virtual_child=False, name=auto):
92
+ def __init__(self, category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.apply, ctype=type, show_in_parent: bool = True, hide_in_virtual_child=False, name=auto):
63
93
  self.value = name
64
94
  self.name = name
65
95
  self.category = category
@@ -106,13 +136,27 @@ class ConfigEnum(metaclass=FastEnum):
106
136
  package_mode = _StrConfigDscr(ConfigCategory.advanced, hide_in_virtual_child=True)
107
137
  utls = _StrConfigDscr(ConfigCategory.advanced)
108
138
  telegram_bot_token = _StrConfigDscr(ConfigCategory.telegram, ApplyMode.apply, hide_in_virtual_child=True)
139
+
140
+ # region child-parent
141
+ # deprecated
109
142
  is_parent = _BoolConfigDscr(ConfigCategory.hidden)
110
- parent_panel = _StrConfigDscr(ConfigCategory.hidden)
143
+ # parent panel domain
144
+ parent_panel = _StrConfigDscr(ConfigCategory.hidden) # should be able to change by user
145
+ parent_domain = _StrConfigDscr(ConfigCategory.hidden)
146
+ parent_admin_proxy_path = _StrConfigDscr(ConfigCategory.hidden)
147
+
148
+ # the panel mode could be one of these: "parent", "child", "standalone"
149
+ # this config value would be 'standalone' by default. and would be set by panel itself
150
+ panel_mode = _TypedConfigDscr(PanelMode, ConfigCategory.hidden, ApplyMode.nothing, hide_in_virtual_child=True)
151
+ # endregion
152
+
153
+ log_level = _TypedConfigDscr(LogLevel, ConfigCategory.hidden, ApplyMode.restart, hide_in_virtual_child=True)
154
+
111
155
  unique_id = _StrConfigDscr(ConfigCategory.hidden)
112
156
  last_hash = _StrConfigDscr(ConfigCategory.hidden)
113
157
  cdn_forced_host = _StrConfigDscr(ConfigCategory.hidden) # removed
114
- lang = _StrConfigDscr(ConfigCategory.branding)
115
- admin_lang = _StrConfigDscr(ConfigCategory.admin)
158
+ lang = _TypedConfigDscr(Lang, ConfigCategory.branding)
159
+ admin_lang = _TypedConfigDscr(Lang, ConfigCategory.admin)
116
160
  admin_secret = _StrConfigDscr(ConfigCategory.hidden) # removed
117
161
 
118
162
  # tls
@@ -128,13 +172,13 @@ class ConfigEnum(metaclass=FastEnum):
128
172
  # mux
129
173
  mux_enable = _BoolConfigDscr(ConfigCategory.mux, ApplyMode.apply)
130
174
  mux_protocol = _StrConfigDscr(ConfigCategory.mux, ApplyMode.apply)
131
- mux_max_connections = _StrConfigDscr(ConfigCategory.mux, ApplyMode.apply)
132
- mux_min_streams = _StrConfigDscr(ConfigCategory.mux, ApplyMode.apply)
133
- mux_max_streams = _StrConfigDscr(ConfigCategory.mux, ApplyMode.apply)
175
+ mux_max_connections = _IntConfigDscr(ConfigCategory.mux, ApplyMode.apply)
176
+ mux_min_streams = _IntConfigDscr(ConfigCategory.mux, ApplyMode.apply)
177
+ mux_max_streams = _IntConfigDscr(ConfigCategory.mux, ApplyMode.apply)
134
178
  mux_padding_enable = _BoolConfigDscr(ConfigCategory.mux, ApplyMode.apply)
135
179
  mux_brutal_enable = _BoolConfigDscr(ConfigCategory.mux, ApplyMode.apply)
136
- mux_brutal_up_mbps = _StrConfigDscr(ConfigCategory.mux, ApplyMode.apply)
137
- mux_brutal_down_mbps = _StrConfigDscr(ConfigCategory.mux, ApplyMode.apply)
180
+ mux_brutal_up_mbps = _IntConfigDscr(ConfigCategory.mux, ApplyMode.apply)
181
+ mux_brutal_down_mbps = _IntConfigDscr(ConfigCategory.mux, ApplyMode.apply)
138
182
 
139
183
  http_ports = _StrConfigDscr(ConfigCategory.http, ApplyMode.apply)
140
184
  kcp_ports = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
@@ -155,11 +199,11 @@ class ConfigEnum(metaclass=FastEnum):
155
199
 
156
200
  shared_secret = _StrConfigDscr(ConfigCategory.proxies, ApplyMode.apply, hide_in_virtual_child=True)
157
201
 
158
- telegram_enable = _BoolConfigDscr(ConfigCategory.telegram, ApplyMode.apply)
202
+ telegram_enable = _BoolConfigDscr(ConfigCategory.telegram, ApplyMode.restart)
159
203
  # telegram_secret=auto()
160
- telegram_adtag = _StrConfigDscr(ConfigCategory.telegram, ApplyMode.apply, hide_in_virtual_child=True)
161
- telegram_lib = _StrConfigDscr(ConfigCategory.telegram, ApplyMode.apply, hide_in_virtual_child=True)
162
- telegram_fakedomain = _StrConfigDscr(ConfigCategory.telegram, ApplyMode.apply, hide_in_virtual_child=True)
204
+ telegram_adtag = _StrConfigDscr(ConfigCategory.telegram, ApplyMode.restart, hide_in_virtual_child=True)
205
+ telegram_lib = _StrConfigDscr(ConfigCategory.telegram, ApplyMode.restart, hide_in_virtual_child=True)
206
+ telegram_fakedomain = _StrConfigDscr(ConfigCategory.telegram, ApplyMode.restart, hide_in_virtual_child=True)
163
207
 
164
208
  v2ray_enable = _BoolConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
165
209
  torrent_block = _BoolConfigDscr(ConfigCategory.general, ApplyMode.apply)
@@ -195,6 +239,13 @@ class ConfigEnum(metaclass=FastEnum):
195
239
  ws_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
196
240
  grpc_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
197
241
  httpupgrade_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
242
+ vless_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
243
+ trojan_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
244
+ reality_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
245
+ tcp_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
246
+ quic_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
247
+ xtls_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
248
+ h2_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
198
249
 
199
250
  db_version = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
200
251
 
@@ -230,7 +281,7 @@ class ConfigEnum(metaclass=FastEnum):
230
281
  return not self.__eq__(other)
231
282
 
232
283
  def endswith(self, other):
233
- return self.name.endswith(other)
284
+ return self.name.endswith(other) # type: ignore
234
285
 
235
286
  def startswith(self, other):
236
- return self.name.startswith(other)
287
+ return self.name.startswith(other) # type: ignore
@@ -4,7 +4,7 @@ from typing import List
4
4
  from urllib.parse import urlparse
5
5
 
6
6
  from flask import request
7
- from sqlalchemy_serializer import SerializerMixin
7
+
8
8
  from flask_babel import lazy_gettext as _
9
9
  from sqlalchemy.orm import backref
10
10
  from urllib.parse import urlparse
@@ -40,7 +40,7 @@ ShowDomain = db.Table('show_domain',
40
40
  )
41
41
 
42
42
 
43
- class Domain(db.Model, SerializerMixin):
43
+ class Domain(db.Model):
44
44
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
45
45
  child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0)
46
46
  domain = db.Column(db.String(200), nullable=False, unique=False)
@@ -67,7 +67,7 @@ class Domain(db.Model, SerializerMixin):
67
67
  'domain': self.domain.lower(),
68
68
  'mode': self.mode,
69
69
  'alias': self.alias,
70
- # 'sub_link_only':d.sub_link_only,
70
+ 'sub_link_only': self.sub_link_only,
71
71
  'child_unique_id': self.child.unique_id if self.child else '',
72
72
  'cdn_ip': self.cdn_ip,
73
73
  'servernames': self.servernames,
@@ -84,6 +84,15 @@ class Domain(db.Model, SerializerMixin):
84
84
 
85
85
  return data
86
86
 
87
+ @staticmethod
88
+ def from_schema(schema):
89
+ return schema.dump(Domain())
90
+
91
+ def to_schema(self):
92
+ domain_dict = self.to_dict()
93
+ from hiddifypanel.panel.commercial.restapi.v2.parent.schema import DomainSchema
94
+ return DomainSchema().load(domain_dict)
95
+
87
96
  @property
88
97
  def need_valid_ssl(self):
89
98
  return self.mode in [DomainType.direct, DomainType.cdn, DomainType.worker, DomainType.relay, DomainType.auto_cdn_ip, DomainType.old_xtls_direct, DomainType.sub_link_only]
@@ -137,14 +146,22 @@ def get_domain(domain):
137
146
  return Domain.query.filter(Domain.domain == domain).first()
138
147
 
139
148
 
149
+ def get_panel_link(child_id: int | None = None) -> Domain | None:
150
+ if child_id is None:
151
+ child_id = Child.current().id
152
+ domains = Domain.query.filter(Domain.mode.in_(
153
+ [DomainType.direct, DomainType.cdn, DomainType.worker, DomainType.relay, DomainType.auto_cdn_ip, DomainType.old_xtls_direct, DomainType.sub_link_only]),
154
+ Domain.child_id == child_id
155
+ ).all()
156
+ if not domains:
157
+ return None
158
+ return domains[0]
159
+
160
+
140
161
  def get_panel_domains(always_add_ip=False, always_add_all_domains=False) -> List[Domain]:
141
162
  from hiddifypanel import hutils
142
163
  domains = []
143
- # if hconfig(ConfigEnum.is_parent):
144
- # from .parent_domain import ParentDomain
145
- # domains = ParentDomain.query.all()
146
- # else:
147
- domains = Domain.query.filter(Domain.mode == DomainType.sub_link_only, Domain.child_id == Child.current.id).all()
164
+ domains = Domain.query.filter(Domain.mode == DomainType.sub_link_only, Domain.child_id == Child.current().id).all()
148
165
  if not len(domains) or always_add_all_domains:
149
166
  domains = Domain.query.filter(Domain.mode.notin_([DomainType.fake, DomainType.reality])).all()
150
167
 
@@ -156,11 +173,7 @@ def get_panel_domains(always_add_ip=False, always_add_all_domains=False) -> List
156
173
 
157
174
 
158
175
  def get_proxy_domains(domain):
159
- # if hconfig(ConfigEnum.is_parent):
160
- # from hiddifypanel.models.parent_domain import ParentDomain
161
- # db_domain = ParentDomain.query.filter(ParentDomain.domain == domain).first() or ParentDomain(domain=domain, show_domains=[])
162
- # else:
163
- db_domain = Domain.query.filter(Domain.domain == domain, Domain.child_id == Child.current.id).first()
176
+ db_domain = Domain.query.filter(Domain.domain == domain, Domain.child_id == Child.current().id).first()
164
177
  if not db_domain:
165
178
  db_domain = Domain(domain=domain, mode=DomainType.direct, cdn_ip='', show_domains=[])
166
179
  return get_proxy_domains_db(db_domain)
@@ -202,11 +215,11 @@ def add_or_update_domain(commit=True, child_id=0, **domain):
202
215
  db.session.commit()
203
216
 
204
217
 
205
- def bulk_register_domains(domains, commit=True, remove=False, override_child_unique_id=None):
218
+ def bulk_register_domains(domains, commit=True, remove=False, force_child_unique_id: str | None = None):
206
219
  from hiddifypanel.panel import hiddify
207
220
  child_ids = {}
208
221
  for domain in domains:
209
- child_id = hiddify.get_child(unique_id=None)
222
+ child_id = hiddify.get_child(unique_id=force_child_unique_id)
210
223
  child_ids[child_id] = 1
211
224
  add_or_update_domain(commit=False, child_id=child_id, **domain)
212
225
  if remove and len(child_ids):
@@ -215,10 +228,5 @@ def bulk_register_domains(domains, commit=True, remove=False, override_child_uni
215
228
  if d.domain not in dd:
216
229
  db.session.delete(d)
217
230
 
218
- # if commit:
219
- db.session.commit()
220
- for domain in domains:
221
- child_id = hiddify.get_child(unique_id=None)
222
- add_or_update_domain(commit=False, child_id=child_id, **domain)
223
231
  if commit:
224
232
  db.session.commit()
@@ -1,6 +1,6 @@
1
1
  # from hiddifypanel.models.domain import Domain
2
2
  # from sqlalchemy.orm import backref
3
- # from sqlalchemy_serializer import SerializerMixin
3
+ #
4
4
 
5
5
  # from hiddifypanel.database import db
6
6
 
@@ -10,7 +10,7 @@
10
10
  # )
11
11
 
12
12
 
13
- # class ParentDomain(db.Model, SerializerMixin):
13
+ # class ParentDomain(db.Model):
14
14
  # id = db.Column(db.Integer, primary_key=True, autoincrement=True)
15
15
  # domain = db.Column(db.String(200), nullable=False, unique=True)
16
16
  # alias = db.Column(db.String(200), nullable=False, unique=False)
@@ -1,7 +1,7 @@
1
- from enum import auto
2
1
 
3
- from sqlalchemy_serializer import SerializerMixin
4
2
  from strenum import StrEnum
3
+ from enum import auto
4
+ from sqlalchemy import Column, String, Integer, Boolean, Enum, ForeignKey
5
5
 
6
6
  from hiddifypanel.database import db
7
7
 
@@ -39,7 +39,7 @@ class ProxyProto(StrEnum):
39
39
  ssr = auto()
40
40
  ssh = auto()
41
41
  tuic = auto()
42
- # hysteria = auto()
42
+ hysteria = auto()
43
43
  hysteria2 = auto()
44
44
  wireguard = auto()
45
45
 
@@ -57,15 +57,15 @@ class ProxyL3(StrEnum):
57
57
  custom = auto()
58
58
 
59
59
 
60
- class Proxy(db.Model, SerializerMixin):
61
- id = db.Column(db.Integer, primary_key=True, autoincrement=True)
62
- child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0)
63
- name = db.Column(db.String(200), nullable=False, unique=False)
64
- enable = db.Column(db.Boolean, nullable=False)
65
- proto = db.Column(db.Enum(ProxyProto), nullable=False)
66
- l3 = db.Column(db.Enum(ProxyL3), nullable=False)
67
- transport = db.Column(db.Enum(ProxyTransport), nullable=False)
68
- cdn = db.Column(db.Enum(ProxyCDN), nullable=False)
60
+ class Proxy(db.Model): # type: ignore
61
+ id = Column(Integer, primary_key=True, autoincrement=True)
62
+ child_id = Column(Integer, ForeignKey('child.id'), default=0)
63
+ name = Column(String(200), nullable=False, unique=False)
64
+ enable = Column(Boolean, nullable=False)
65
+ proto = Column(Enum(ProxyProto), nullable=False)
66
+ l3 = Column(Enum(ProxyL3), nullable=False)
67
+ transport = Column(Enum(ProxyTransport), nullable=False)
68
+ cdn = Column(Enum(ProxyCDN), nullable=False)
69
69
 
70
70
  @property
71
71
  def enabled(self):
@@ -82,12 +82,15 @@ class Proxy(db.Model, SerializerMixin):
82
82
  'child_unique_id': self.child.unique_id if self.child else ''
83
83
  }
84
84
 
85
+ def __str__(self):
86
+ return str(self.to_dict())
87
+
85
88
  @staticmethod
86
89
  def add_or_update(commit=True, child_id=0, **proxy):
87
90
  dbproxy = Proxy.query.filter(Proxy.name == proxy['name']).first()
88
91
  if not dbproxy:
89
92
  dbproxy = Proxy()
90
- db.session.add(dbproxy)
93
+ db.session.add(dbproxy) # type: ignore
91
94
  dbproxy.enable = proxy['enable']
92
95
  dbproxy.name = proxy['name']
93
96
  dbproxy.proto = proxy['proto']
@@ -96,16 +99,22 @@ class Proxy(db.Model, SerializerMixin):
96
99
  dbproxy.l3 = proxy['l3']
97
100
  dbproxy.child_id = child_id
98
101
  if commit:
99
- db.session.commit()
102
+ db.session.commit() # type: ignore
100
103
 
101
104
  @staticmethod
102
- def bulk_register(proxies, commit=True, override_child_unique_id=None):
105
+ def from_schema(schema):
106
+ return schema.dump(Proxy())
107
+
108
+ def to_schema(self):
109
+ proxy_dict = self.to_dict()
110
+ from hiddifypanel.panel.commercial.restapi.v2.parent.schema import ProxySchema
111
+ return ProxySchema().load(proxy_dict)
112
+
113
+ @staticmethod
114
+ def bulk_register(proxies, commit=True, force_child_unique_id: str | None = None):
103
115
  from hiddifypanel.panel import hiddify
104
116
  for proxy in proxies:
105
- child_id = hiddify.get_child(unique_id=None)
117
+ child_id = hiddify.get_child(unique_id=force_child_unique_id)
106
118
  Proxy.add_or_update(commit=False, child_id=child_id, **proxy)
107
119
  if commit:
108
- db.session.commit()
109
-
110
- def __str__(self):
111
- return str(self.to_dict())
120
+ db.session.commit() # type: ignore
@@ -1,11 +1,10 @@
1
1
  import datetime
2
2
 
3
- from sqlalchemy_serializer import SerializerMixin
4
3
 
5
4
  from hiddifypanel.database import db
6
5
 
7
6
 
8
- class Report(db.Model, SerializerMixin):
7
+ class Report(db.Model):
9
8
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
10
9
  user_id = db.Column(db.Integer, db.ForeignKey('user.id'), default=0, nullable=False)
11
10
  asn_id = db.Column(db.String(200), nullable=False, unique=False)
@@ -19,7 +18,7 @@ class Report(db.Model, SerializerMixin):
19
18
  details = db.relationship('ReportDetail', cascade="all,delete", backref='report', lazy='dynamic',)
20
19
 
21
20
 
22
- class ReportDetail(db.Model, SerializerMixin):
21
+ class ReportDetail(db.Model):
23
22
  report_id = db.Column(db.Integer, db.ForeignKey('report.id'), primary_key=True, )
24
23
  proxy_id = db.Column(db.Integer, db.ForeignKey('proxy.id'), primary_key=True, )
25
24
  ping = db.Column(db.Integer, default=-1)
@@ -3,12 +3,12 @@ from datetime import timedelta, date
3
3
 
4
4
  from flask import g
5
5
  from sqlalchemy import func
6
- from sqlalchemy_serializer import SerializerMixin
6
+
7
7
 
8
8
  from hiddifypanel.database import db
9
9
 
10
10
 
11
- class DailyUsage(db.Model, SerializerMixin):
11
+ class DailyUsage(db.Model):
12
12
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
13
13
  date = db.Column(db.Date, default=datetime.date.today(), index=True)
14
14
  usage = db.Column(db.BigInteger, default=0, nullable=False)
@@ -2,13 +2,12 @@ import datetime
2
2
  from enum import auto
3
3
  from hiddifypanel.models.role import Role
4
4
  from dateutil import relativedelta
5
- from sqlalchemy_serializer import SerializerMixin
5
+
6
6
  from strenum import StrEnum
7
7
  from sqlalchemy import event
8
8
 
9
9
  from hiddifypanel.database import db
10
10
  from hiddifypanel.models import Lang
11
- from hiddifypanel.models.utils import fill_password, fill_username
12
11
  from hiddifypanel.models.base_account import BaseAccount
13
12
  from hiddifypanel.models.admin import AdminUser
14
13
 
@@ -36,13 +35,13 @@ package_mode_dic = {
36
35
  }
37
36
 
38
37
 
39
- class UserDetail(db.Model, SerializerMixin):
38
+ class UserDetail(db.Model):
40
39
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
41
40
  user_id = db.Column(db.Integer, db.ForeignKey('user.id'), default=0, nullable=False)
42
41
  child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0, nullable=False)
43
42
  last_online = db.Column(db.DateTime, nullable=False, default=datetime.datetime.min)
44
43
  current_usage = db.Column(db.BigInteger, default=0, nullable=False)
45
- connected_ips = db.Column(db.String(512), default='', nullable=False)
44
+ connected_devices = db.Column(db.String(512), default='', nullable=False)
46
45
 
47
46
  @property
48
47
  def current_usage_GB(self):
@@ -53,8 +52,8 @@ class UserDetail(db.Model, SerializerMixin):
53
52
  self.current_usage = (value or 0) * ONE_GIG
54
53
 
55
54
  @property
56
- def ips(self):
57
- return [] if not self.connected_ips else self.connected_ips.split(",")
55
+ def devices(self):
56
+ return [] if not self.connected_devices else self.connected_devices.split(",")
58
57
 
59
58
 
60
59
  class User(BaseAccount):
@@ -122,16 +121,16 @@ class User(BaseAccount):
122
121
  is_active = False
123
122
  elif self.remaining_days < 0:
124
123
  is_active = False
125
- elif len(self.ips) > max(3, self.max_ips):
124
+ elif len(self.devices) > max(3, self.max_ips):
126
125
  is_active = False
127
126
  return is_active
128
127
 
129
128
  @property
130
- def ips(self):
129
+ def devices(self):
131
130
  res = {}
132
131
  for detail in UserDetail.query.filter(UserDetail.user_id == self.id):
133
- for ip in detail.ips:
134
- res[ip] = 1
132
+ for device in detail.devices:
133
+ res[device] = 1
135
134
  return list(res.keys())
136
135
 
137
136
  def user_should_reset(self) -> bool:
@@ -208,7 +207,7 @@ class User(BaseAccount):
208
207
  from hiddifypanel import hutils
209
208
  dbuser = super().add_or_update(commit=commit, **data)
210
209
  if data.get('added_by_uuid'):
211
- admin = AdminUser.by_uuid(data.get('added_by_uuid'), create=True) or AdminUser.current_admin_or_owner()
210
+ admin = AdminUser.by_uuid(data.get('added_by_uuid'), create=True) or AdminUser.current_admin_or_owner() # type: ignore
212
211
  dbuser.added_by = admin.id
213
212
  else:
214
213
  dbuser.added_by = 1
@@ -233,17 +232,17 @@ class User(BaseAccount):
233
232
  if data.get('ed25519_private_key', ''):
234
233
  dbuser.ed25519_private_key = data.get('ed25519_private_key', '')
235
234
  dbuser.ed25519_public_key = data.get('ed25519_public_key', '')
236
- if not dbuser.ed25519_private_key:
237
- from hiddifypanel.panel import hiddify
238
- priv, publ = hiddify.get_ed25519_private_public_pair()
239
- dbuser.ed25519_private_key = priv
240
- dbuser.ed25519_public_key = publ
235
+ # if not dbuser.ed25519_private_key:
236
+ # priv, publ = hutils.crypto.get_ed25519_private_public_pair()
237
+ # dbuser.ed25519_private_key = priv
238
+ # dbuser.ed25519_public_key = publ
239
+
241
240
  dbuser.wg_pk = data.get('wg_pk', dbuser.wg_pk)
242
241
  dbuser.wg_pub = data.get('wg_pub', dbuser.wg_pub)
243
242
  dbuser.wg_psk = data.get('wg_psk', dbuser.wg_psk)
244
- if not dbuser.wg_pk:
245
- from hiddifypanel.panel import hiddify
246
- dbuser.wg_pk, dbuser.wg_pub, dbuser.wg_psk = hiddify.get_wg_private_public_psk_pair()
243
+
244
+ # if not dbuser.wg_pk:
245
+ # dbuser.wg_pk, dbuser.wg_pub, dbuser.wg_psk = hutils.crypto.get_wg_private_public_psk_pair()
247
246
 
248
247
  mode = data.get('mode', UserMode.no_reset)
249
248
  if mode == 'disable':
@@ -257,6 +256,15 @@ class User(BaseAccount):
257
256
  db.session.commit()
258
257
  return dbuser
259
258
 
259
+ @staticmethod
260
+ def form_schema(schema):
261
+ return schema.dump(User())
262
+
263
+ def to_schema(self):
264
+ user_dict = self.to_dict()
265
+ from hiddifypanel.panel.commercial.restapi.v2.admin.user_api import UserSchema
266
+ return UserSchema().load(user_dict)
267
+
260
268
  def to_dict(self, convert_date=True, dump_id=False) -> dict:
261
269
  base = super().to_dict()
262
270
  from hiddifypanel import hutils
@@ -270,7 +278,7 @@ class User(BaseAccount):
270
278
  'start_date': hutils.convert.date_to_json(self.start_date)if convert_date else self.start_date,
271
279
  'current_usage_GB': self.current_usage_GB,
272
280
  'last_reset_time': hutils.convert.date_to_json(self.last_reset_time) if convert_date else self.last_reset_time,
273
- 'added_by_uuid': self.admin.uuid,
281
+ 'added_by_uuid': self.admin.uuid if self.admin else None,
274
282
  'ed25519_private_key': self.ed25519_private_key,
275
283
  'ed25519_public_key': self.ed25519_public_key,
276
284
  'wg_pk': self.wg_pk,
@@ -302,5 +310,8 @@ class User(BaseAccount):
302
310
 
303
311
  @event.listens_for(User, 'before_insert')
304
312
  def on_user_insert(mapper, connection, target):
305
- fill_username(target)
306
- fill_password(target)
313
+ from hiddifypanel import hutils
314
+ hutils.model.gen_username(target)
315
+ hutils.model.gen_password(target)
316
+ hutils.model.gen_ed25519_keys(target)
317
+ hutils.model.gen_wg_keys(target)