hiddifypanel 10.12.1__py3-none-any.whl → 10.15.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.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +2 -2
- hiddifypanel/auth.py +15 -4
- hiddifypanel/base.py +58 -50
- hiddifypanel/cache.py +43 -25
- hiddifypanel/database.py +9 -0
- hiddifypanel/drivers/abstract_driver.py +2 -0
- hiddifypanel/drivers/singbox_api.py +17 -15
- hiddifypanel/drivers/ssh_liberty_bridge_api.py +2 -0
- hiddifypanel/drivers/user_driver.py +12 -6
- hiddifypanel/drivers/wireguard_api.py +2 -0
- hiddifypanel/drivers/xray_api.py +14 -9
- hiddifypanel/hutils/__init__.py +1 -0
- hiddifypanel/hutils/convert.py +13 -2
- hiddifypanel/hutils/crypto.py +21 -2
- hiddifypanel/hutils/flask.py +19 -5
- hiddifypanel/hutils/importer/xui.py +5 -2
- hiddifypanel/hutils/node/__init__.py +3 -0
- hiddifypanel/hutils/node/api_client.py +76 -0
- hiddifypanel/hutils/node/child.py +147 -0
- hiddifypanel/hutils/node/parent.py +100 -0
- hiddifypanel/hutils/node/shared.py +65 -0
- hiddifypanel/hutils/proxy/shared.py +15 -3
- hiddifypanel/models/__init__.py +2 -2
- hiddifypanel/models/admin.py +14 -2
- hiddifypanel/models/base_account.py +3 -3
- hiddifypanel/models/child.py +30 -16
- hiddifypanel/models/config.py +39 -15
- hiddifypanel/models/config_enum.py +55 -8
- hiddifypanel/models/domain.py +28 -20
- hiddifypanel/models/parent_domain.py +2 -2
- hiddifypanel/models/proxy.py +13 -4
- hiddifypanel/models/report.py +2 -3
- hiddifypanel/models/usage.py +2 -2
- hiddifypanel/models/user.py +18 -9
- hiddifypanel/panel/admin/Actions.py +4 -6
- hiddifypanel/panel/admin/AdminstratorAdmin.py +13 -2
- hiddifypanel/panel/admin/Dashboard.py +5 -10
- hiddifypanel/panel/admin/DomainAdmin.py +12 -11
- hiddifypanel/panel/admin/NodeAdmin.py +6 -2
- hiddifypanel/panel/admin/ProxyAdmin.py +4 -3
- hiddifypanel/panel/admin/SettingAdmin.py +60 -21
- hiddifypanel/panel/admin/UserAdmin.py +10 -2
- hiddifypanel/panel/admin/templates/index.html +1 -1
- hiddifypanel/panel/admin/templates/parent_dash.html +2 -4
- hiddifypanel/panel/cli.py +16 -16
- hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +10 -5
- hiddifypanel/panel/commercial/__init__.py +7 -5
- hiddifypanel/panel/commercial/restapi/v2/admin/__init__.py +0 -5
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_info_api.py +2 -2
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_log_api.py +4 -5
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_user_api.py +8 -35
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_users_api.py +4 -4
- hiddifypanel/panel/commercial/restapi/v2/admin/schema.py +157 -0
- hiddifypanel/panel/commercial/restapi/v2/admin/server_status_api.py +3 -3
- hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +9 -73
- hiddifypanel/panel/commercial/restapi/v2/admin/users_api.py +1 -1
- hiddifypanel/panel/commercial/restapi/v2/child/__init__.py +18 -0
- hiddifypanel/panel/commercial/restapi/v2/child/actions.py +63 -0
- hiddifypanel/panel/commercial/restapi/v2/child/register_parent_api.py +34 -0
- hiddifypanel/panel/commercial/restapi/v2/child/schema.py +7 -0
- hiddifypanel/panel/commercial/restapi/v2/child/sync_parent_api.py +21 -0
- hiddifypanel/panel/commercial/restapi/v2/panel/__init__.py +13 -0
- hiddifypanel/panel/commercial/restapi/v2/panel/info.py +18 -0
- hiddifypanel/panel/commercial/restapi/v2/panel/ping_pong.py +23 -0
- hiddifypanel/panel/commercial/restapi/v2/panel/schema.py +7 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/__init__.py +16 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/register_api.py +65 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/schema.py +115 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/status_api.py +26 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/sync_api.py +53 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/usage_api.py +57 -0
- hiddifypanel/panel/commercial/telegrambot/admin.py +1 -2
- hiddifypanel/panel/common.py +21 -6
- hiddifypanel/panel/hiddify.py +9 -80
- hiddifypanel/panel/init_db.py +84 -38
- hiddifypanel/panel/usage.py +33 -18
- hiddifypanel/panel/user/templates/home/usage.html +1 -1
- hiddifypanel/panel/user/templates/new.html +2 -2
- hiddifypanel/static/css/custom.css +13 -0
- hiddifypanel/static/images/hiddify.png +0 -0
- hiddifypanel/static/images/hiddify2.png +0 -0
- hiddifypanel/static/new/assets/hiddify-logo-7617d937.png +0 -0
- hiddifypanel/static/new/assets/{index-4510b616.js → index-ccb9873c.js} +2 -2
- hiddifypanel/static/new/assets/index-fa00de9a.css +1 -0
- hiddifypanel/static/new/i18n/en.json +6 -6
- hiddifypanel/static/new/i18n/fa.json +1 -1
- hiddifypanel/templates/admin-layout.html +24 -40
- hiddifypanel/templates/fake.html +22 -0
- hiddifypanel/templates/master.html +24 -42
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +95 -5
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +96 -4
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +98 -6
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +91 -1
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +92 -2
- hiddifypanel/translations.i18n/en.json +61 -5
- hiddifypanel/translations.i18n/fa.json +60 -4
- hiddifypanel/translations.i18n/pt.json +63 -7
- hiddifypanel/translations.i18n/ru.json +57 -1
- hiddifypanel/translations.i18n/zh.json +58 -2
- {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/METADATA +47 -47
- {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/RECORD +112 -94
- hiddifypanel/panel/commercial/restapi/v2/DTO.py +0 -9
- hiddifypanel/panel/commercial/restapi/v2/hello/__init__.py +0 -16
- hiddifypanel/panel/commercial/restapi/v2/hello/hello.py +0 -32
- hiddifypanel/static/new/assets/hiddify-logo-7617d937_old.png +0 -0
- hiddifypanel/static/new/assets/index-669b32c8.css +0 -1
- /hiddifypanel/static/images/{hiddify1.png → hiddify-old.png} +0 -0
- {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/LICENSE.md +0 -0
- {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/WHEEL +0 -0
- {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/top_level.txt +0 -0
hiddifypanel/models/config.py
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
-
from
|
1
|
+
from typing import Optional
|
2
|
+
from hiddifypanel.models.config_enum import ConfigEnum, LogLevel, PanelMode, Lang
|
2
3
|
from flask import g
|
3
|
-
|
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
|
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
|
-
|
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
|
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,14 +83,18 @@ 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
|
66
|
-
if
|
67
|
-
|
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)
|
91
|
+
|
68
92
|
return value
|
69
93
|
|
70
94
|
|
71
95
|
def set_hconfig(key: ConfigEnum, value: str | int | bool, child_id: int | None = None, commit: bool = True):
|
72
96
|
if child_id is None:
|
73
|
-
child_id = Child.current.id
|
97
|
+
child_id = Child.current().id
|
74
98
|
|
75
99
|
print(f"chainging .... {key}---{value}---{child_id}---{commit}")
|
76
100
|
if key.type == int and value != None:
|
@@ -81,7 +105,7 @@ def set_hconfig(key: ConfigEnum, value: str | int | bool, child_id: int | None =
|
|
81
105
|
hconfig.invalidate(key, child_id)
|
82
106
|
hconfig.invalidate(key, child_id=child_id)
|
83
107
|
hconfig.invalidate(key=key, child_id=child_id)
|
84
|
-
if child_id == Child.current.id:
|
108
|
+
if child_id == Child.current().id:
|
85
109
|
hconfig.invalidate(key)
|
86
110
|
# hconfig.invalidate_all()
|
87
111
|
get_hconfigs.invalidate_all()
|
@@ -115,7 +139,7 @@ def set_hconfig(key: ConfigEnum, value: str | int | bool, child_id: int | None =
|
|
115
139
|
@cache.cache(ttl=500,)
|
116
140
|
def get_hconfigs(child_id: int | None = None, json=False) -> dict:
|
117
141
|
if child_id is None:
|
118
|
-
child_id = Child.current.id
|
142
|
+
child_id = Child.current().id
|
119
143
|
|
120
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},
|
121
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},
|
@@ -131,9 +155,9 @@ def get_hconfigs_childs(child_ids: list[int], json=False):
|
|
131
155
|
return {c: get_hconfigs(c, json) for c in child_ids}
|
132
156
|
|
133
157
|
|
134
|
-
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):
|
135
159
|
if child_id is None:
|
136
|
-
child_id = Child.current.id
|
160
|
+
child_id = Child.current().id
|
137
161
|
c = config['key']
|
138
162
|
ckey = ConfigEnum(c)
|
139
163
|
if c == ConfigEnum.unique_id and not override_unique_id:
|
@@ -145,13 +169,13 @@ def add_or_update_config(commit: bool = True, child_id: int = None, override_uni
|
|
145
169
|
set_hconfig(ckey, v, child_id, commit=commit)
|
146
170
|
|
147
171
|
|
148
|
-
def bulk_register_configs(hconfigs, commit: bool = True,
|
172
|
+
def bulk_register_configs(hconfigs, commit: bool = True, froce_child_unique_id: str | None = None, override_unique_id: bool = True):
|
149
173
|
from hiddifypanel.panel import hiddify
|
150
174
|
for conf in hconfigs:
|
151
175
|
# print(conf)
|
152
176
|
if conf['key'] == ConfigEnum.unique_id and not override_unique_id:
|
153
177
|
continue
|
154
|
-
child_id = hiddify.get_child(unique_id=
|
178
|
+
child_id = hiddify.get_child(unique_id=froce_child_unique_id)
|
155
179
|
# print(conf, child_id, conf.get('child_unique_id', None), override_child_unique_id)
|
156
180
|
add_or_update_config(commit=False, child_id=child_id, **conf)
|
157
181
|
if commit:
|
@@ -5,7 +5,13 @@ from strenum import StrEnum
|
|
5
5
|
from fast_enum import FastEnum
|
6
6
|
|
7
7
|
|
8
|
-
class
|
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()
|
@@ -59,11 +81,15 @@ def _IntConfigDscr(category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.n
|
|
59
81
|
return category, apply_mode, int, show_in_parent
|
60
82
|
|
61
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
|
+
|
62
88
|
class ConfigEnum(metaclass=FastEnum):
|
63
89
|
# category: ConfigCategory
|
64
|
-
__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')
|
65
91
|
|
66
|
-
def __init__(self, category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.apply, ctype=
|
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):
|
67
93
|
self.value = name
|
68
94
|
self.name = name
|
69
95
|
self.category = category
|
@@ -110,13 +136,27 @@ class ConfigEnum(metaclass=FastEnum):
|
|
110
136
|
package_mode = _StrConfigDscr(ConfigCategory.advanced, hide_in_virtual_child=True)
|
111
137
|
utls = _StrConfigDscr(ConfigCategory.advanced)
|
112
138
|
telegram_bot_token = _StrConfigDscr(ConfigCategory.telegram, ApplyMode.apply, hide_in_virtual_child=True)
|
139
|
+
|
140
|
+
# region child-parent
|
141
|
+
# deprecated
|
113
142
|
is_parent = _BoolConfigDscr(ConfigCategory.hidden)
|
114
|
-
|
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
|
+
|
115
155
|
unique_id = _StrConfigDscr(ConfigCategory.hidden)
|
116
156
|
last_hash = _StrConfigDscr(ConfigCategory.hidden)
|
117
157
|
cdn_forced_host = _StrConfigDscr(ConfigCategory.hidden) # removed
|
118
|
-
lang =
|
119
|
-
admin_lang =
|
158
|
+
lang = _TypedConfigDscr(Lang, ConfigCategory.branding)
|
159
|
+
admin_lang = _TypedConfigDscr(Lang, ConfigCategory.admin)
|
120
160
|
admin_secret = _StrConfigDscr(ConfigCategory.hidden) # removed
|
121
161
|
|
122
162
|
# tls
|
@@ -199,6 +239,13 @@ class ConfigEnum(metaclass=FastEnum):
|
|
199
239
|
ws_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
|
200
240
|
grpc_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
|
201
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)
|
202
249
|
|
203
250
|
db_version = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
|
204
251
|
|
@@ -234,7 +281,7 @@ class ConfigEnum(metaclass=FastEnum):
|
|
234
281
|
return not self.__eq__(other)
|
235
282
|
|
236
283
|
def endswith(self, other):
|
237
|
-
return self.name.endswith(other)
|
284
|
+
return self.name.endswith(other) # type: ignore
|
238
285
|
|
239
286
|
def startswith(self, other):
|
240
|
-
return self.name.startswith(other)
|
287
|
+
return self.name.startswith(other) # type: ignore
|
hiddifypanel/models/domain.py
CHANGED
@@ -4,7 +4,7 @@ from typing import List
|
|
4
4
|
from urllib.parse import urlparse
|
5
5
|
|
6
6
|
from flask import request
|
7
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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=
|
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
|
-
#
|
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
|
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)
|
hiddifypanel/models/proxy.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
from strenum import StrEnum
|
3
3
|
from enum import auto
|
4
4
|
from sqlalchemy import Column, String, Integer, Boolean, Enum, ForeignKey
|
@@ -57,7 +57,7 @@ class ProxyL3(StrEnum):
|
|
57
57
|
custom = auto()
|
58
58
|
|
59
59
|
|
60
|
-
class Proxy(db.Model
|
60
|
+
class Proxy(db.Model): # type: ignore
|
61
61
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
62
62
|
child_id = Column(Integer, ForeignKey('child.id'), default=0)
|
63
63
|
name = Column(String(200), nullable=False, unique=False)
|
@@ -102,10 +102,19 @@ class Proxy(db.Model, SerializerMixin): # type: ignore
|
|
102
102
|
db.session.commit() # type: ignore
|
103
103
|
|
104
104
|
@staticmethod
|
105
|
-
def
|
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):
|
106
115
|
from hiddifypanel.panel import hiddify
|
107
116
|
for proxy in proxies:
|
108
|
-
child_id = hiddify.get_child(unique_id=
|
117
|
+
child_id = hiddify.get_child(unique_id=force_child_unique_id)
|
109
118
|
Proxy.add_or_update(commit=False, child_id=child_id, **proxy)
|
110
119
|
if commit:
|
111
120
|
db.session.commit() # type: ignore
|
hiddifypanel/models/report.py
CHANGED
@@ -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
|
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
|
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)
|
hiddifypanel/models/usage.py
CHANGED
@@ -3,12 +3,12 @@ from datetime import timedelta, date
|
|
3
3
|
|
4
4
|
from flask import g
|
5
5
|
from sqlalchemy import func
|
6
|
-
|
6
|
+
|
7
7
|
|
8
8
|
from hiddifypanel.database import db
|
9
9
|
|
10
10
|
|
11
|
-
class DailyUsage(db.Model
|
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)
|
hiddifypanel/models/user.py
CHANGED
@@ -2,7 +2,7 @@ import datetime
|
|
2
2
|
from enum import auto
|
3
3
|
from hiddifypanel.models.role import Role
|
4
4
|
from dateutil import relativedelta
|
5
|
-
|
5
|
+
|
6
6
|
from strenum import StrEnum
|
7
7
|
from sqlalchemy import event
|
8
8
|
|
@@ -35,13 +35,13 @@ package_mode_dic = {
|
|
35
35
|
}
|
36
36
|
|
37
37
|
|
38
|
-
class UserDetail(db.Model
|
38
|
+
class UserDetail(db.Model):
|
39
39
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
40
40
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), default=0, nullable=False)
|
41
41
|
child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0, nullable=False)
|
42
42
|
last_online = db.Column(db.DateTime, nullable=False, default=datetime.datetime.min)
|
43
43
|
current_usage = db.Column(db.BigInteger, default=0, nullable=False)
|
44
|
-
|
44
|
+
connected_devices = db.Column(db.String(512), default='', nullable=False)
|
45
45
|
|
46
46
|
@property
|
47
47
|
def current_usage_GB(self):
|
@@ -52,8 +52,8 @@ class UserDetail(db.Model, SerializerMixin):
|
|
52
52
|
self.current_usage = (value or 0) * ONE_GIG
|
53
53
|
|
54
54
|
@property
|
55
|
-
def
|
56
|
-
return [] if not self.
|
55
|
+
def devices(self):
|
56
|
+
return [] if not self.connected_devices else self.connected_devices.split(",")
|
57
57
|
|
58
58
|
|
59
59
|
class User(BaseAccount):
|
@@ -121,16 +121,16 @@ class User(BaseAccount):
|
|
121
121
|
is_active = False
|
122
122
|
elif self.remaining_days < 0:
|
123
123
|
is_active = False
|
124
|
-
elif len(self.
|
124
|
+
elif len(self.devices) > max(3, self.max_ips):
|
125
125
|
is_active = False
|
126
126
|
return is_active
|
127
127
|
|
128
128
|
@property
|
129
|
-
def
|
129
|
+
def devices(self):
|
130
130
|
res = {}
|
131
131
|
for detail in UserDetail.query.filter(UserDetail.user_id == self.id):
|
132
|
-
for
|
133
|
-
res[
|
132
|
+
for device in detail.devices:
|
133
|
+
res[device] = 1
|
134
134
|
return list(res.keys())
|
135
135
|
|
136
136
|
def user_should_reset(self) -> bool:
|
@@ -256,6 +256,15 @@ class User(BaseAccount):
|
|
256
256
|
db.session.commit()
|
257
257
|
return dbuser
|
258
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
|
+
|
259
268
|
def to_dict(self, convert_date=True, dump_id=False) -> dict:
|
260
269
|
base = super().to_dict()
|
261
270
|
from hiddifypanel import hutils
|
@@ -61,11 +61,9 @@ class Actions(FlaskView):
|
|
61
61
|
def reinstall2(self, complete_install=True, domain_changed=False):
|
62
62
|
if int(hconfig(ConfigEnum.db_version)) < 9:
|
63
63
|
return ("Please update your panel before this action.")
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# except e as Exception:
|
68
|
-
# hutils.flask.flash(_('can not sync child with parent panel')+" "+e)
|
64
|
+
if hutils.node.is_child():
|
65
|
+
if not hutils.node.child.sync_with_parent():
|
66
|
+
hutils.flask.flash(_('child.sync-failed'), 'danger') # type: ignore
|
69
67
|
|
70
68
|
domain_changed = request.args.get("domain_changed", str(domain_changed)).lower() == "true"
|
71
69
|
complete_install = request.args.get("complete_install", str(complete_install)).lower() == "true"
|
@@ -110,7 +108,7 @@ class Actions(FlaskView):
|
|
110
108
|
|
111
109
|
@login_required(roles={Role.super_admin})
|
112
110
|
def change_reality_keys(self):
|
113
|
-
key =
|
111
|
+
key = hutils.crypto.generate_x25519_keys()
|
114
112
|
set_hconfig(ConfigEnum.reality_private_key, key['private_key'])
|
115
113
|
set_hconfig(ConfigEnum.reality_public_key, key['public_key'])
|
116
114
|
hutils.flask.flash_config_success(restart_mode=ApplyMode.restart, domain_changed=False)
|
@@ -7,7 +7,9 @@ from .adminlte import AdminLTEModelView
|
|
7
7
|
from flask_babel import lazy_gettext as _
|
8
8
|
from wtforms.validators import Regexp
|
9
9
|
from flask_babel import gettext as __
|
10
|
-
from flask import
|
10
|
+
from flask import request # type: ignore
|
11
|
+
from markupsafe import Markup
|
12
|
+
|
11
13
|
from flask import g
|
12
14
|
import datetime
|
13
15
|
from wtforms import SelectField
|
@@ -37,7 +39,7 @@ class SubAdminsField(SelectField):
|
|
37
39
|
|
38
40
|
class AdminstratorAdmin(AdminLTEModelView):
|
39
41
|
column_hide_backrefs = False
|
40
|
-
column_list = ["name", 'UserLinks', 'mode', 'can_add_admin', 'max_active_users', 'max_users', 'online_users', 'comment']
|
42
|
+
column_list = ["name", 'UserLinks', 'mode', 'can_add_admin', 'max_active_users', 'max_users', 'online_users', 'comment',]
|
41
43
|
form_columns = ["name", 'mode', 'can_add_admin', 'max_active_users', 'max_users', 'comment', "uuid"]
|
42
44
|
list_template = 'model/admin_list.html'
|
43
45
|
# column_editable_list = ['name']
|
@@ -215,6 +217,7 @@ class AdminstratorAdmin(AdminLTEModelView):
|
|
215
217
|
model.remove()
|
216
218
|
|
217
219
|
def get_query_for_parent_admin(self):
|
220
|
+
# WHAT IS THIS?
|
218
221
|
admin_user_id = self.get_pk_value()
|
219
222
|
sub_admins_ids = set(recursive_sub_admins_ids(AdminUser.query.get(admin_user_id)))
|
220
223
|
return AdminUser.query.filter(AdminUser.id.in_(sub_admins_ids)).with_entities(AdminUser.id, AdminUser.name)
|
@@ -236,3 +239,11 @@ class AdminstratorAdmin(AdminLTEModelView):
|
|
236
239
|
del form.max_users
|
237
240
|
del form.max_active_users
|
238
241
|
del form.can_add_admin
|
242
|
+
|
243
|
+
def after_model_change(self, form, model, is_created):
|
244
|
+
if hutils.node.is_parent():
|
245
|
+
hutils.node.parent.send_sync_req_to_childs()
|
246
|
+
|
247
|
+
def after_model_delete(self, model):
|
248
|
+
if hutils.node.is_parent():
|
249
|
+
hutils.node.parent.send_sync_req_to_childs()
|
@@ -18,9 +18,9 @@ class Dashboard(FlaskView):
|
|
18
18
|
|
19
19
|
@login_required(roles={Role.super_admin, Role.admin, Role.agent})
|
20
20
|
def index(self):
|
21
|
-
|
22
21
|
if hconfig(ConfigEnum.first_setup):
|
23
22
|
return redirect(hurl_for("admin.QuickSetup:index"))
|
23
|
+
|
24
24
|
if hiddifypanel.__release_date__ + datetime.timedelta(days=20) < datetime.datetime.now():
|
25
25
|
hutils.flask.flash(_('This version of hiddify panel is outdated. Please update it from admin area.'), "danger") # type: ignore
|
26
26
|
bot = None
|
@@ -34,20 +34,15 @@ class Dashboard(FlaskView):
|
|
34
34
|
user_query = User.query
|
35
35
|
if admin_id:
|
36
36
|
user_query = user_query.filter(User.added_by == admin_id)
|
37
|
-
if
|
37
|
+
if hutils.node.is_parent():
|
38
38
|
childs = Child.query.filter(Child.id != 0).all()
|
39
39
|
for c in childs:
|
40
40
|
c.is_active = False
|
41
41
|
for d in c.domains:
|
42
|
-
|
43
|
-
continue
|
44
|
-
remote = hiddify.get_account_panel_link(g.account, d.domain, child_id=c.id)
|
45
|
-
d.is_active = hutils.network.check_connection_to_remote(remote)
|
42
|
+
d.is_active = hutils.node.parent.is_child_domain_active(c, d)
|
46
43
|
if d.is_active:
|
47
44
|
c.is_active = True
|
48
45
|
|
49
|
-
# return render_template('parent_dash.html',childs=childs,bot=bot)
|
50
|
-
# try:
|
51
46
|
def_user = None if len(User.query.all()) > 1 else User.query.filter(User.name == 'default').first()
|
52
47
|
domains = get_panel_domains()
|
53
48
|
sslip_domains = [d.domain for d in domains if "sslip.io" in d.domain]
|
@@ -56,13 +51,13 @@ class Dashboard(FlaskView):
|
|
56
51
|
quick_setup = hurl_for("admin.QuickSetup:index")
|
57
52
|
hutils.flask.flash((_('It seems that you have not setup the system completely. <a class="btn btn-success" href="%(quick_setup)s">Click here</a> to complete setup.',
|
58
53
|
quick_setup=quick_setup)), 'warning') # type: ignore
|
59
|
-
if
|
54
|
+
if hutils.node.is_parent():
|
60
55
|
hutils.flask.flash(
|
61
56
|
_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
|
62
57
|
elif len(sslip_domains):
|
63
58
|
hutils.flask.flash((_('It seems that you are using default domain (%(domain)s) which is not recommended.',
|
64
59
|
domain=sslip_domains[0])), 'warning') # type: ignore
|
65
|
-
if
|
60
|
+
if hutils.node.is_parent():
|
66
61
|
hutils.flask.flash(
|
67
62
|
_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
|
68
63
|
elif def_user:
|