hiddifypanel 9.0.0.dev54__py3-none-any.whl → 9.0.0.dev61__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/base.py +5 -4
- hiddifypanel/hutils/__init__.py +8 -1
- hiddifypanel/hutils/auth.py +94 -0
- hiddifypanel/hutils/auto_ip_selector.py +1 -1
- hiddifypanel/hutils/convert.py +14 -0
- hiddifypanel/hutils/encode.py +11 -0
- hiddifypanel/hutils/flask.py +24 -0
- hiddifypanel/{panel/github_issue_generator.py → hutils/github_issue.py} +104 -14
- hiddifypanel/hutils/json.py +24 -0
- hiddifypanel/hutils/random.py +19 -0
- hiddifypanel/hutils/utils.py +0 -161
- hiddifypanel/models/__init__.py +1 -0
- hiddifypanel/models/admin.py +53 -8
- hiddifypanel/models/base_account.py +31 -169
- hiddifypanel/models/config_enum.py +23 -1
- hiddifypanel/models/domain.py +2 -2
- hiddifypanel/models/parent_domain.py +1 -0
- hiddifypanel/models/user.py +105 -33
- hiddifypanel/models/utils.py +3 -3
- hiddifypanel/panel/admin/Actions.py +5 -6
- hiddifypanel/panel/admin/AdminstratorAdmin.py +1 -1
- hiddifypanel/panel/admin/Backup.py +5 -5
- hiddifypanel/panel/admin/ChildAdmin.py +3 -3
- hiddifypanel/panel/admin/Dashboard.py +12 -10
- hiddifypanel/panel/admin/DomainAdmin.py +10 -9
- hiddifypanel/panel/admin/ProxyAdmin.py +4 -6
- hiddifypanel/panel/admin/QuickSetup.py +11 -13
- hiddifypanel/panel/admin/SettingAdmin.py +20 -10
- hiddifypanel/panel/admin/UserAdmin.py +14 -12
- hiddifypanel/panel/auth.py +43 -10
- hiddifypanel/panel/auth_back2.py +5 -5
- hiddifypanel/panel/cli.py +1 -0
- hiddifypanel/panel/commercial/ParentDomainAdmin.py +3 -3
- hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +1 -0
- hiddifypanel/panel/commercial/restapi/v1/tgbot.py +1 -2
- hiddifypanel/panel/commercial/restapi/v1/tgmsg.py +37 -29
- hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +5 -4
- hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +15 -7
- hiddifypanel/panel/commercial/restapi/v2/user/info_api.py +7 -11
- hiddifypanel/panel/commercial/telegrambot/Usage.py +2 -1
- hiddifypanel/panel/commercial/telegrambot/admin.py +1 -0
- hiddifypanel/panel/common.py +12 -89
- hiddifypanel/panel/common_bp/login.py +12 -12
- hiddifypanel/panel/database.py +22 -21
- hiddifypanel/panel/hiddify.py +27 -29
- hiddifypanel/panel/importer/xui.py +2 -2
- hiddifypanel/panel/init_db.py +32 -13
- hiddifypanel/panel/usage.py +2 -1
- hiddifypanel/panel/user/link_maker.py +118 -15
- hiddifypanel/panel/user/templates/new.html +4 -2
- hiddifypanel/panel/user/user.py +83 -38
- hiddifypanel/static/new/assets/{index-bd9ba5e9.js → index-2cd90979.js} +1 -1
- hiddifypanel/templates/fake.html +2 -2
- hiddifypanel/templates/master.html +1 -1
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +317 -189
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +346 -206
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +315 -195
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +315 -195
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +866 -2739
- {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/METADATA +2 -1
- {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/RECORD +72 -66
- {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/LICENSE.md +0 -0
- {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/WHEEL +0 -0
- {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/top_level.txt +0 -0
hiddifypanel/models/admin.py
CHANGED
@@ -7,7 +7,7 @@ from strenum import StrEnum
|
|
7
7
|
from apiflask import abort
|
8
8
|
from flask_babelex import gettext as __
|
9
9
|
from flask_babelex import lazy_gettext as _
|
10
|
-
|
10
|
+
from hiddifypanel.models.role import Role
|
11
11
|
from hiddifypanel.panel.database import db
|
12
12
|
from .base_account import BaseAccount
|
13
13
|
|
@@ -38,13 +38,58 @@ class AdminUser(BaseAccount):
|
|
38
38
|
usages = db.relationship('DailyUsage', backref='admin')
|
39
39
|
parent_admin_id = db.Column(db.Integer, db.ForeignKey('admin_user.id'), default=1)
|
40
40
|
parent_admin = db.relationship('AdminUser', remote_side=[id], backref='sub_admins')
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
|
42
|
+
@property
|
43
|
+
def role(self) -> Role | None:
|
44
|
+
match self.mode:
|
45
|
+
case AdminMode.super_admin:
|
46
|
+
return Role.super_admin
|
47
|
+
case AdminMode.admin:
|
48
|
+
return Role.admin
|
49
|
+
case AdminMode.agent:
|
50
|
+
return Role.agent
|
51
|
+
return None
|
52
|
+
|
53
|
+
def get_id(self) -> str | None:
|
54
|
+
return f'admin_{self.id}'
|
55
|
+
|
56
|
+
def to_dict(self, convert_date=True) -> dict:
|
57
|
+
base = super().to_dict()
|
58
|
+
return {**base,
|
59
|
+
'mode': self.mode,
|
60
|
+
'can_add_admin': self.can_add_admin,
|
61
|
+
'parent_admin_uuid': self.parent_admin.uuid if self.parent_admin else None,
|
62
|
+
}
|
63
|
+
|
64
|
+
@classmethod
|
65
|
+
def by_uuid(cls, uuid: str, create: bool = False):
|
66
|
+
account = AdminUser.query.filter(AdminUser.uuid == uuid).first()
|
67
|
+
if not account and create:
|
68
|
+
dbuser = AdminUser(uuid=uuid, name="unknown", parent_admin_id=AdminUser.current_admin_or_owner().id)
|
69
|
+
db.session.add(dbuser)
|
70
|
+
db.session.commit()
|
71
|
+
account = AdminUser.by_uuid(uuid, False)
|
72
|
+
|
73
|
+
return account
|
74
|
+
|
75
|
+
@classmethod
|
76
|
+
def add_or_update(cls, commit: bool = True, **data):
|
77
|
+
|
78
|
+
dbuser = super().add_or_update(commit=commit, **data)
|
79
|
+
|
80
|
+
if dbuser.id != 1:
|
81
|
+
parent = data.get('parent_admin_uuid')
|
82
|
+
if parent == data['uuid'] or not parent:
|
83
|
+
parent_admin = cls.current_admin_or_owner()
|
84
|
+
else:
|
85
|
+
parent_admin = cls.by_uuid(parent, create=True)
|
86
|
+
dbuser.parent_admin_id = parent_admin.id # type: ignore
|
87
|
+
|
88
|
+
dbuser.mode = data.get('mode', AdminMode.agent)
|
89
|
+
dbuser.can_add_admin = data.get('can_add_admin') == True
|
90
|
+
if commit:
|
91
|
+
db.session.commit()
|
92
|
+
return dbuser
|
48
93
|
|
49
94
|
def recursive_users_query(self):
|
50
95
|
from .user import User
|
@@ -2,10 +2,10 @@ import datetime
|
|
2
2
|
import uuid as uuid_mod
|
3
3
|
from hiddifypanel import hutils
|
4
4
|
from hiddifypanel.models.role import Role
|
5
|
-
from sqlalchemy import Column, String
|
5
|
+
from sqlalchemy import Column, String, BigInteger, Integer
|
6
6
|
from sqlalchemy_serializer import SerializerMixin
|
7
7
|
from flask_login import UserMixin as FlaskLoginUserMixin
|
8
|
-
|
8
|
+
from hiddifypanel.models import Lang
|
9
9
|
from hiddifypanel.panel.database import db
|
10
10
|
|
11
11
|
|
@@ -16,77 +16,31 @@ class BaseAccount(db.Model, SerializerMixin, FlaskLoginUserMixin): # type: igno
|
|
16
16
|
username = Column(String(100), nullable=True, default='')
|
17
17
|
password = Column(String(100), nullable=True, default='')
|
18
18
|
comment = Column(String(512), nullable=True, default='')
|
19
|
-
telegram_id = Column(
|
19
|
+
telegram_id = Column(BigInteger, nullable=True, default='')
|
20
|
+
lang = db.Column(db.Enum(Lang), default=None)
|
20
21
|
|
21
22
|
@property
|
22
23
|
def role(self) -> Role | None:
|
23
|
-
|
24
|
-
from hiddifypanel.models.admin import AdminUser, AdminMode
|
25
|
-
if isinstance(self, AdminUser):
|
26
|
-
match self.mode:
|
27
|
-
case AdminMode.super_admin:
|
28
|
-
return Role.super_admin
|
29
|
-
case AdminMode.admin:
|
30
|
-
return Role.admin
|
31
|
-
case AdminMode.agent:
|
32
|
-
return Role.agent
|
33
|
-
if isinstance(self, User):
|
34
|
-
return Role.user
|
24
|
+
return None
|
35
25
|
|
36
26
|
def get_id(self) -> str | None:
|
37
|
-
"""
|
38
|
-
Get the ID of the account. (*only for flask_login)
|
39
|
-
"""
|
40
|
-
from hiddifypanel.models.user import User
|
41
|
-
from hiddifypanel.models.admin import AdminUser
|
42
|
-
if isinstance(self, AdminUser):
|
43
|
-
return f'admin_{self.id}'
|
44
|
-
if isinstance(self, User):
|
45
|
-
return f'user_{self.id}'
|
27
|
+
return '{self.__class__.name}_{self.id if self.hasattr("id") else "-"}'
|
46
28
|
|
47
29
|
def is_username_unique(self) -> bool:
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
model = None
|
52
|
-
if isinstance(self, AdminUser):
|
53
|
-
model = AdminUser.query.filter(AdminUser.username == self.username).first()
|
54
|
-
else:
|
55
|
-
model = User.query.filter(User.username == self.username).first()
|
56
|
-
|
57
|
-
if model and model.id != self.id:
|
30
|
+
cls = self.__class__()
|
31
|
+
model = cls.query.filter(cls.username == self.username, cls.id != self.id).first()
|
32
|
+
if model:
|
58
33
|
return False
|
59
34
|
return True
|
60
35
|
|
61
36
|
def to_dict(self, convert_date=True) -> dict:
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
'can_add_admin': self.can_add_admin,
|
70
|
-
'parent_admin_uuid': self.parent_admin.uuid if self.parent_admin else None,
|
71
|
-
'telegram_id': hutils.utils.convert_to_int(self.telegram_id),
|
72
|
-
}
|
73
|
-
else:
|
74
|
-
return {
|
75
|
-
'uuid': self.uuid,
|
76
|
-
'name': self.name,
|
77
|
-
'last_online': hutils.utils.time_to_json(self.last_online) if convert_date else self.last_online,
|
78
|
-
'usage_limit_GB': self.usage_limit_GB,
|
79
|
-
'package_days': self.package_days,
|
80
|
-
'mode': self.mode,
|
81
|
-
'start_date': hutils.utils.date_to_json(self.start_date)if convert_date else self.start_date,
|
82
|
-
'current_usage_GB': self.current_usage_GB,
|
83
|
-
'last_reset_time': hutils.utils.date_to_json(self.last_reset_time) if convert_date else self.last_reset_time,
|
84
|
-
'comment': self.comment,
|
85
|
-
'added_by_uuid': self.admin.uuid,
|
86
|
-
'telegram_id': hutils.utils.convert_to_int(self.telegram_id),
|
87
|
-
'ed25519_private_key': self.ed25519_private_key,
|
88
|
-
'ed25519_public_key': self.ed25519_public_key
|
89
|
-
}
|
37
|
+
return {
|
38
|
+
'name': self.name,
|
39
|
+
'comment': self.comment,
|
40
|
+
'uuid': self.uuid,
|
41
|
+
'telegram_id': self.telegram_id,
|
42
|
+
'lang': self.lang
|
43
|
+
}
|
90
44
|
|
91
45
|
@classmethod
|
92
46
|
def by_id(cls, id: int):
|
@@ -94,24 +48,9 @@ class BaseAccount(db.Model, SerializerMixin, FlaskLoginUserMixin): # type: igno
|
|
94
48
|
|
95
49
|
@classmethod
|
96
50
|
def by_uuid(cls, uuid: str, create: bool = False):
|
97
|
-
|
98
|
-
from hiddifypanel.models.admin import AdminUser
|
99
|
-
account = None
|
100
|
-
if cls.__subclasscheck__(User) or cls.__subclasscheck__(AdminUser):
|
101
|
-
account = cls.query.filter(cls.uuid == uuid).first()
|
102
|
-
|
51
|
+
account = cls.query.filter(cls.uuid == uuid).first()
|
103
52
|
if not account and create:
|
104
|
-
|
105
|
-
dbuser = User(uuid=uuid, name="unknown", added_by=AdminUser.current_admin_or_owner().id)
|
106
|
-
db.session.add(dbuser)
|
107
|
-
db.session.commit()
|
108
|
-
account = cls.by_uuid(uuid)
|
109
|
-
elif cls.__subclasscheck__(AdminUser):
|
110
|
-
dbuser = AdminUser(uuid=uuid, name="unknown", parent_admin_id=cls.current_admin_or_owner().id)
|
111
|
-
db.session.add(dbuser)
|
112
|
-
db.session.commit()
|
113
|
-
account = cls.by_uuid(uuid) # AdminUser.query.filter(AdminUser.uuid == uuid).first()
|
114
|
-
|
53
|
+
raise NotImplementedError
|
115
54
|
return account
|
116
55
|
|
117
56
|
@classmethod
|
@@ -120,100 +59,23 @@ class BaseAccount(db.Model, SerializerMixin, FlaskLoginUserMixin): # type: igno
|
|
120
59
|
|
121
60
|
@classmethod
|
122
61
|
def add_or_update(cls, commit: bool = True, **data):
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
dbuser = User.by_uuid(data['uuid'], create=True)
|
129
|
-
|
130
|
-
if data.get('added_by_uuid'):
|
131
|
-
admin = AdminUser.by_uuid(data.get('added_by_uuid'), create=True) # type: ignore
|
132
|
-
dbuser.added_by = admin.id # type: ignore
|
133
|
-
else:
|
134
|
-
dbuser.added_by = 1
|
135
|
-
|
136
|
-
if data.get('expiry_time', ''):
|
137
|
-
last_reset_time = hutils.utils.json_to_date(data.get('last_reset_time', '')) or datetime.date.today()
|
138
|
-
|
139
|
-
expiry_time = hutils.utils.json_to_date(data['expiry_time'])
|
140
|
-
dbuser.start_date = last_reset_time
|
141
|
-
dbuser.package_days = (expiry_time-last_reset_time).days # type: ignore
|
142
|
-
|
143
|
-
elif 'package_days' in data:
|
144
|
-
dbuser.package_days = data['package_days']
|
145
|
-
if data.get('start_date', ''):
|
146
|
-
dbuser.start_date = hutils.utils.json_to_date(data['start_date'])
|
147
|
-
else:
|
148
|
-
dbuser.start_date = None
|
149
|
-
dbuser.current_usage_GB = data['current_usage_GB']
|
150
|
-
|
151
|
-
dbuser.usage_limit_GB = data['usage_limit_GB']
|
152
|
-
dbuser.name = data.get('name') or ''
|
153
|
-
dbuser.comment = data.get('comment', '')
|
154
|
-
dbuser.enable = data.get('enable', True)
|
155
|
-
if data.get('ed25519_private_key', ''):
|
156
|
-
dbuser.ed25519_private_key = data.get('ed25519_private_key', '')
|
157
|
-
dbuser.ed25519_public_key = data.get('ed25519_public_key', '')
|
158
|
-
if not dbuser.ed25519_private_key:
|
159
|
-
from hiddifypanel.panel import hiddify
|
160
|
-
priv, publ = hiddify.get_ed25519_private_public_pair()
|
161
|
-
dbuser.ed25519_private_key = priv
|
162
|
-
dbuser.ed25519_public_key = publ
|
163
|
-
|
164
|
-
mode = data.get('mode', UserMode.no_reset)
|
165
|
-
if mode == 'disable':
|
166
|
-
mode = UserMode.no_reset
|
167
|
-
dbuser.enable = False
|
168
|
-
|
169
|
-
dbuser.mode = mode
|
170
|
-
|
171
|
-
dbuser.telegram_id = data.get('telegram_id') or 0
|
172
|
-
|
173
|
-
dbuser.last_online = hutils.utils.json_to_time(data.get('last_online')) or datetime.datetime.min
|
174
|
-
elif cls.__subclasscheck__(AdminUser):
|
175
|
-
# if not is_valid():return
|
176
|
-
dbuser = cls.by_uuid(data['uuid']) # type: ignore
|
177
|
-
|
178
|
-
if not dbuser:
|
179
|
-
dbuser = AdminUser(uuid=data['uuid'])
|
180
|
-
# if not is_valid():
|
181
|
-
# return
|
182
|
-
db.session.add(dbuser)
|
183
|
-
dbuser.name = data['name']
|
184
|
-
if dbuser.id != 1:
|
185
|
-
parent = data.get('parent_admin_uuid')
|
186
|
-
if parent == data['uuid'] or not parent:
|
187
|
-
parent_admin = cls.current_admin_or_owner()
|
188
|
-
else:
|
189
|
-
parent_admin = cls.by_uuid(parent, create=True)
|
190
|
-
dbuser.parent_admin_id = parent_admin.id # type: ignore
|
191
|
-
|
192
|
-
dbuser.comment = data.get('comment', '')
|
193
|
-
dbuser.mode = data.get('mode', AdminMode.agent)
|
194
|
-
dbuser.telegram_id = data.get('telegram_id')
|
195
|
-
dbuser.can_add_admin = data.get('can_add_admin') == True
|
196
|
-
|
197
|
-
# dbuser.last_online=user.get('last_online','')
|
198
|
-
|
62
|
+
db_account = cls.by_uuid(data['uuid'], create=True)
|
63
|
+
db_account.name = data.get('name') or ''
|
64
|
+
db_account.comment = data.get('comment', '')
|
65
|
+
db_account.telegram_id = hutils.convert.to_int(data.get('telegram_id'))
|
66
|
+
db_account.lang = data.get('lang')
|
199
67
|
if commit:
|
200
68
|
db.session.commit()
|
201
|
-
return
|
69
|
+
return db_account
|
202
70
|
|
203
71
|
@classmethod
|
204
72
|
def bulk_register(cls, accounts: list = [], commit: bool = True, remove: bool = False):
|
205
|
-
|
206
|
-
|
207
|
-
if
|
208
|
-
for u in accounts
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
for d in cls.query.all():
|
213
|
-
if d.uuid not in dd:
|
214
|
-
db.session.delete(d)
|
215
|
-
elif cls.__subclasscheck__(AdminUser):
|
216
|
-
for u in accounts:
|
217
|
-
cls.add_or_update(commit=False, **u)
|
73
|
+
for u in accounts:
|
74
|
+
cls.add_or_update(commit=False, **u)
|
75
|
+
if remove:
|
76
|
+
dd = {u['uuid']: 1 for u in accounts}
|
77
|
+
for d in cls.query.all():
|
78
|
+
if d.uuid not in dd:
|
79
|
+
db.session.delete(d)
|
218
80
|
if commit:
|
219
81
|
db.session.commit()
|
@@ -20,6 +20,7 @@ class ConfigCategory(StrEnum):
|
|
20
20
|
telegram = auto()
|
21
21
|
http = auto()
|
22
22
|
tls = auto()
|
23
|
+
mux = auto()
|
23
24
|
tls_trick = auto()
|
24
25
|
ssh = auto()
|
25
26
|
ssfaketls = auto()
|
@@ -81,6 +82,17 @@ class ConfigEnum(StrEnum):
|
|
81
82
|
tls_padding_enable = auto()
|
82
83
|
tls_padding_length = auto()
|
83
84
|
|
85
|
+
# mux
|
86
|
+
mux_enable = auto()
|
87
|
+
mux_protocol = auto()
|
88
|
+
mux_max_connections = auto()
|
89
|
+
mux_min_streams = auto()
|
90
|
+
mux_max_streams = auto()
|
91
|
+
mux_padding_enable = auto()
|
92
|
+
mux_brutal_enable = auto()
|
93
|
+
mux_brutal_up_mbps = auto()
|
94
|
+
mux_brutal_down_mbps = auto()
|
95
|
+
|
84
96
|
http_ports = auto()
|
85
97
|
kcp_ports = auto()
|
86
98
|
kcp_enable = auto()
|
@@ -219,6 +231,16 @@ class ConfigEnum(StrEnum):
|
|
219
231
|
self.tls_padding_enable: {'category': ConfigCategory.tls_trick, 'apply_mode': 'apply', 'type': bool},
|
220
232
|
self.tls_padding_length: {'category': ConfigCategory.tls_trick, 'apply_mode': 'apply'},
|
221
233
|
|
234
|
+
# mux
|
235
|
+
self.mux_enable: {'category': ConfigCategory.mux, 'apply_mode': 'apply', 'type': bool},
|
236
|
+
self.mux_protocol: {'category': ConfigCategory.mux, 'apply_mode': 'apply'},
|
237
|
+
self.mux_max_connections: {'category': ConfigCategory.mux, 'apply_mode': 'apply'},
|
238
|
+
self.mux_min_streams: {'category': ConfigCategory.mux, 'apply_mode': 'apply'},
|
239
|
+
self.mux_max_streams: {'category': ConfigCategory.mux, 'apply_mode': 'apply'},
|
240
|
+
self.mux_padding_enable: {'category': ConfigCategory.mux, 'apply_mode': 'apply', 'type': bool},
|
241
|
+
self.mux_brutal_enable: {'category': ConfigCategory.mux, 'apply_mode': 'apply', 'type': bool},
|
242
|
+
self.mux_brutal_up_mbps: {'category': ConfigCategory.mux, 'apply_mode': 'apply'},
|
243
|
+
self.mux_brutal_down_mbps: {'category': ConfigCategory.mux, 'apply_mode': 'apply'},
|
222
244
|
|
223
245
|
self.http_ports: {'category': ConfigCategory.http, 'apply_mode': 'apply'}, # http
|
224
246
|
self.kcp_ports: {'category': ConfigCategory.hidden, 'apply_mode': 'apply'},
|
@@ -257,7 +279,7 @@ class ConfigEnum(StrEnum):
|
|
257
279
|
self.tuic_port: {'category': ConfigCategory.hidden, 'apply_mode': 'apply'},
|
258
280
|
|
259
281
|
self.hysteria_enable: {'category': ConfigCategory.hidden, 'type': bool, 'apply_mode': 'apply'},
|
260
|
-
self.hysteria_port: {'category': ConfigCategory.
|
282
|
+
self.hysteria_port: {'category': ConfigCategory.hidden, 'apply_mode': 'apply'},
|
261
283
|
self.hysteria_obfs_enable: {'category': ConfigCategory.hysteria, 'type': bool, 'apply_mode': 'apply'},
|
262
284
|
self.hysteria_up_mbps: {'category': ConfigCategory.hysteria, 'apply_mode': 'apply'},
|
263
285
|
self.hysteria_down_mbps: {'category': ConfigCategory.hysteria, 'apply_mode': 'apply'},
|
hiddifypanel/models/domain.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from enum import auto
|
2
2
|
from urllib.parse import urlparse
|
3
3
|
|
4
|
-
from flask import
|
4
|
+
from flask import request
|
5
5
|
from sqlalchemy_serializer import SerializerMixin
|
6
6
|
from strenum import StrEnum
|
7
7
|
|
@@ -162,7 +162,7 @@ def get_proxy_domains_db(db_domain):
|
|
162
162
|
domain = urlparse(request.base_url).hostname
|
163
163
|
db_domain = Domain(domain=domain, mode=DomainType.direct, show_domains=[])
|
164
164
|
# print("no domain")
|
165
|
-
flash(_("This domain does not exist in the panel!" + domain))
|
165
|
+
hutils.flask.flash(_("This domain does not exist in the panel!" + domain)) #type: ignore
|
166
166
|
|
167
167
|
return db_domain.show_domains or Domain.query.all()
|
168
168
|
|
hiddifypanel/models/user.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import datetime
|
2
2
|
from enum import auto
|
3
|
-
|
3
|
+
from hiddifypanel.models.role import Role
|
4
4
|
from dateutil import relativedelta
|
5
5
|
from sqlalchemy_serializer import SerializerMixin
|
6
6
|
from strenum import StrEnum
|
@@ -10,7 +10,8 @@ from hiddifypanel.panel.database import db
|
|
10
10
|
from hiddifypanel.models import Lang
|
11
11
|
from hiddifypanel.models.utils import fill_password, fill_username
|
12
12
|
from .base_account import BaseAccount
|
13
|
-
|
13
|
+
from .admin import AdminUser
|
14
|
+
from hiddifypanel import hutils
|
14
15
|
ONE_GIG = 1024*1024*1024
|
15
16
|
|
16
17
|
|
@@ -26,6 +27,7 @@ class UserMode(StrEnum):
|
|
26
27
|
weekly = auto()
|
27
28
|
daily = auto()
|
28
29
|
|
30
|
+
|
29
31
|
# disable = auto()
|
30
32
|
package_mode_dic = {
|
31
33
|
UserMode.daily: 1,
|
@@ -75,16 +77,15 @@ class User(BaseAccount):
|
|
75
77
|
max_ips = db.Column(db.Integer, default=1000, nullable=False)
|
76
78
|
details = db.relationship('UserDetail', cascade="all,delete", backref='user', lazy='dynamic',)
|
77
79
|
enable = db.Column(db.Boolean, default=True, nullable=False)
|
78
|
-
lang = db.Column(db.Enum(Lang), default=None)
|
79
80
|
ed25519_private_key = db.Column(db.String(500))
|
80
81
|
ed25519_public_key = db.Column(db.String(100))
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
82
|
+
|
83
|
+
@property
|
84
|
+
def role(self) -> Role | None:
|
85
|
+
return Role.user
|
86
|
+
|
87
|
+
def get_id(self) -> str | None:
|
88
|
+
return f'user_{self.id}'
|
88
89
|
|
89
90
|
@property
|
90
91
|
def current_usage_GB(self):
|
@@ -176,26 +177,99 @@ class User(BaseAccount):
|
|
176
177
|
res = self.package_days
|
177
178
|
return min(res, 10000)
|
178
179
|
|
179
|
-
@
|
180
|
-
def
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
180
|
+
@classmethod
|
181
|
+
def by_uuid(cls, uuid: str, create: bool = False):
|
182
|
+
account = User.query.filter(User.uuid == uuid).first()
|
183
|
+
if not account and create:
|
184
|
+
dbuser = User(uuid=uuid, name="unknown", added_by=AdminUser.current_admin_or_owner().id)
|
185
|
+
db.session.add(dbuser)
|
186
|
+
db.session.commit()
|
187
|
+
account = User.by_uuid(uuid, False)
|
188
|
+
return account
|
189
|
+
|
190
|
+
@classmethod
|
191
|
+
def add_or_update(cls, commit: bool = True, **data):
|
192
|
+
|
193
|
+
dbuser = super().add_or_update(commit=commit, **data)
|
194
|
+
if data.get('added_by_uuid'):
|
195
|
+
admin = AdminUser.by_uuid(data.get('added_by_uuid'), create=True) or AdminUser.current_admin_or_owner()
|
196
|
+
dbuser.added_by = admin.id
|
197
|
+
else:
|
198
|
+
dbuser.added_by = 1
|
199
|
+
|
200
|
+
if data.get('expiry_time', ''):
|
201
|
+
last_reset_time = hutils.json.json_to_date(data.get('last_reset_time', '')) or datetime.date.today()
|
202
|
+
|
203
|
+
expiry_time = hutils.json.json_to_date(data['expiry_time'])
|
204
|
+
dbuser.start_date = last_reset_time
|
205
|
+
dbuser.package_days = (expiry_time-last_reset_time).days # type: ignore
|
206
|
+
|
207
|
+
elif 'package_days' in data:
|
208
|
+
dbuser.package_days = data['package_days']
|
209
|
+
if data.get('start_date', ''):
|
210
|
+
dbuser.start_date = hutils.json.json_to_date(data['start_date'])
|
211
|
+
else:
|
212
|
+
dbuser.start_date = None
|
213
|
+
dbuser.current_usage_GB = data['current_usage_GB']
|
214
|
+
|
215
|
+
dbuser.usage_limit_GB = data['usage_limit_GB']
|
216
|
+
dbuser.enable = data.get('enable', True)
|
217
|
+
if data.get('ed25519_private_key', ''):
|
218
|
+
dbuser.ed25519_private_key = data.get('ed25519_private_key', '')
|
219
|
+
dbuser.ed25519_public_key = data.get('ed25519_public_key', '')
|
220
|
+
if not dbuser.ed25519_private_key:
|
221
|
+
from hiddifypanel.panel import hiddify
|
222
|
+
priv, publ = hiddify.get_ed25519_private_public_pair()
|
223
|
+
dbuser.ed25519_private_key = priv
|
224
|
+
dbuser.ed25519_public_key = publ
|
225
|
+
|
226
|
+
mode = data.get('mode', UserMode.no_reset)
|
227
|
+
if mode == 'disable':
|
228
|
+
mode = UserMode.no_reset
|
229
|
+
dbuser.enable = False
|
230
|
+
|
231
|
+
dbuser.mode = mode
|
232
|
+
|
233
|
+
dbuser.last_online = hutils.json.json_to_time(data.get('last_online')) or datetime.datetime.min
|
234
|
+
if commit:
|
235
|
+
db.session.commit()
|
236
|
+
return dbuser
|
237
|
+
|
238
|
+
def to_dict(self, convert_date=True) -> dict:
|
239
|
+
base = super().to_dict()
|
240
|
+
return {**base,
|
241
|
+
'last_online': hutils.json.time_to_json(self.last_online) if convert_date else self.last_online,
|
242
|
+
'usage_limit_GB': self.usage_limit_GB,
|
243
|
+
'package_days': self.package_days,
|
244
|
+
'mode': self.mode,
|
245
|
+
'start_date': hutils.json.date_to_json(self.start_date)if convert_date else self.start_date,
|
246
|
+
'current_usage_GB': self.current_usage_GB,
|
247
|
+
'last_reset_time': hutils.json.date_to_json(self.last_reset_time) if convert_date else self.last_reset_time,
|
248
|
+
'added_by_uuid': self.admin.uuid,
|
249
|
+
'ed25519_private_key': self.ed25519_private_key,
|
250
|
+
'ed25519_public_key': self.ed25519_public_key
|
251
|
+
}
|
252
|
+
|
253
|
+
# @staticmethod
|
254
|
+
# def from_dict(data):
|
255
|
+
# """
|
256
|
+
# Returns a new User object created from a dictionary.
|
257
|
+
# """
|
258
|
+
|
259
|
+
# return User(
|
260
|
+
# name=data.get('name', ''),
|
261
|
+
# expiry_time=data.get('expiry_time', datetime.date.today() + relativedelta.relativedelta(months=6)),
|
262
|
+
# usage_limit_GB=data.get('usage_limit_GB', 1000),
|
263
|
+
# package_days=data.get('package_days', 90),
|
264
|
+
# mode=UserMode[data.get('mode', 'no_reset')],
|
265
|
+
# monthly=data.get('monthly', False),
|
266
|
+
# start_date=data.get('start_date', None),
|
267
|
+
# current_usage_GB=data.get('current_usage_GB', 0),
|
268
|
+
# last_reset_time=data.get('last_reset_time', datetime.date.today()),
|
269
|
+
# comment=data.get('comment', None),
|
270
|
+
# telegram_id=data.get('telegram_id', None),
|
271
|
+
# added_by=data.get('added_by', 1)
|
272
|
+
# )
|
199
273
|
|
200
274
|
|
201
275
|
# TODO: refactor this function too
|
@@ -211,9 +285,7 @@ def remove(user: User, commit=True) -> None:
|
|
211
285
|
|
212
286
|
def remove_user(uuid: str, commit=True):
|
213
287
|
dbuser = User.by_uuid(uuid)
|
214
|
-
|
215
|
-
if commit:
|
216
|
-
db.session.commit()
|
288
|
+
remove(dbuser, commit)
|
217
289
|
|
218
290
|
|
219
291
|
@event.listens_for(User, 'before_insert')
|
hiddifypanel/models/utils.py
CHANGED
@@ -9,18 +9,18 @@ def fill_username(model) -> None:
|
|
9
9
|
minimum_username_length = 10
|
10
10
|
|
11
11
|
if len(base_username) < minimum_username_length:
|
12
|
-
base_username += hutils.
|
12
|
+
base_username += hutils.random.get_random_string(minimum_username_length-len(base_username), minimum_username_length)
|
13
13
|
|
14
14
|
if len(base_username) > 100:
|
15
15
|
base_username = base_username[0:100]
|
16
16
|
model.username = base_username
|
17
17
|
|
18
18
|
while not model.is_username_unique():
|
19
|
-
rand_str = hutils.
|
19
|
+
rand_str = hutils.random.get_random_string(2, 4)
|
20
20
|
model.username += rand_str
|
21
21
|
|
22
22
|
|
23
23
|
def fill_password(model) -> None:
|
24
24
|
# TODO: hash the password
|
25
25
|
if not model.password or len(model.password) < 16:
|
26
|
-
model.password=hutils.
|
26
|
+
model.password = hutils.random.get_random_password(length=16)
|
@@ -13,7 +13,6 @@ from hiddifypanel import hutils
|
|
13
13
|
from hiddifypanel.models import *
|
14
14
|
from hiddifypanel.panel import hiddify, usage
|
15
15
|
from hiddifypanel.panel.run_commander import commander, Command
|
16
|
-
from hiddifypanel.panel.hiddify import flash
|
17
16
|
|
18
17
|
|
19
18
|
class Actions(FlaskView):
|
@@ -99,13 +98,13 @@ class Actions(FlaskView):
|
|
99
98
|
# try:
|
100
99
|
# hiddify_api.sync_child_to_parent()
|
101
100
|
# except e as Exception:
|
102
|
-
# flash(_('can not sync child with parent panel')+" "+e)
|
101
|
+
# hutils.flask.flash(_('can not sync child with parent panel')+" "+e)
|
103
102
|
|
104
103
|
domain_changed = request.args.get("domain_changed", str(domain_changed)).lower() == "true"
|
105
104
|
complete_install = request.args.get("complete_install", str(complete_install)).lower() == "true"
|
106
105
|
if domain_changed:
|
107
|
-
flash((_('Your domains changed. Please do not forget to copy admin links, otherwise you can not access to the panel anymore.')), 'info')
|
108
|
-
# flash(f'complete_install={complete_install} domain_changed={domain_changed} ', 'info')
|
106
|
+
hutils.flask.flash((_('Your domains changed. Please do not forget to copy admin links, otherwise you can not access to the panel anymore.')), 'info')
|
107
|
+
# hutils.flask.flash(f'complete_install={complete_install} domain_changed={domain_changed} ', 'info')
|
109
108
|
# return render_template("result.html")
|
110
109
|
# hiddify.add_temporary_access()
|
111
110
|
file = "install.sh" if complete_install else "apply_configs.sh"
|
@@ -147,7 +146,7 @@ class Actions(FlaskView):
|
|
147
146
|
key = hiddify.generate_x25519_keys()
|
148
147
|
set_hconfig(ConfigEnum.reality_private_key, key['private_key'])
|
149
148
|
set_hconfig(ConfigEnum.reality_public_key, key['public_key'])
|
150
|
-
|
149
|
+
hutils.flask.flash_config_success(restart_mode='apply', domain_changed=False)
|
151
150
|
return redirect(url_for('admin.SettingAdmin:index'))
|
152
151
|
|
153
152
|
@login_required(roles={Role.super_admin})
|
@@ -232,4 +231,4 @@ def get_log_api_url():
|
|
232
231
|
|
233
232
|
|
234
233
|
def get_domains():
|
235
|
-
return [str(d.domain).replace("*",
|
234
|
+
return [str(d.domain).replace("*", hutils.random.get_random_string(3, 6)) for d in get_panel_domains(always_add_all_domains=True, always_add_ip=True)]
|
@@ -168,7 +168,7 @@ class AdminstratorAdmin(AdminLTEModelView):
|
|
168
168
|
|
169
169
|
# @login_required(roles={Role.super_admin, Role.admin})
|
170
170
|
def is_accessible(self):
|
171
|
-
if login_required(roles={Role.super_admin, Role.admin})(lambda: True)() != True:
|
171
|
+
if login_required(roles={Role.super_admin, Role.admin, Role.agent})(lambda: True)() != True:
|
172
172
|
return False
|
173
173
|
return True
|
174
174
|
|