hiddifypanel 9.0.0.dev60__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 -169
- hiddifypanel/models/__init__.py +1 -0
- hiddifypanel/models/admin.py +53 -8
- hiddifypanel/models/base_account.py +31 -169
- 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/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 +13 -11
- hiddifypanel/panel/admin/UserAdmin.py +13 -12
- hiddifypanel/panel/auth.py +42 -9
- 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/tgmsg.py +1 -1
- hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +5 -4
- hiddifypanel/panel/commercial/restapi/v2/user/info_api.py +7 -11
- hiddifypanel/panel/commercial/telegrambot/admin.py +1 -0
- hiddifypanel/panel/common.py +10 -86
- hiddifypanel/panel/common_bp/login.py +9 -8
- hiddifypanel/panel/database.py +22 -21
- hiddifypanel/panel/hiddify.py +25 -28
- hiddifypanel/panel/importer/xui.py +2 -2
- hiddifypanel/panel/init_db.py +20 -13
- hiddifypanel/panel/usage.py +2 -1
- hiddifypanel/panel/user/link_maker.py +118 -15
- hiddifypanel/panel/user/user.py +25 -19
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +252 -234
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +280 -228
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +240 -207
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +240 -207
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +779 -2740
- {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/METADATA +2 -1
- {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/RECORD +63 -57
- {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/LICENSE.md +0 -0
- {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/WHEEL +0 -0
- {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-9.0.0.dev60.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()
|
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)]
|
@@ -2,6 +2,7 @@
|
|
2
2
|
from urllib.parse import urlparse
|
3
3
|
from flask_babelex import gettext as _
|
4
4
|
from flask_bootstrap import SwitchField
|
5
|
+
from hiddifypanel import hutils
|
5
6
|
# from flask_babelex import gettext as _
|
6
7
|
import wtforms as wtf
|
7
8
|
from flask_wtf import FlaskForm
|
@@ -10,7 +11,6 @@ import json
|
|
10
11
|
import json
|
11
12
|
from flask import render_template, request, jsonify, redirect, g
|
12
13
|
from hiddifypanel.panel.auth import login_required
|
13
|
-
from hiddifypanel.panel.hiddify import flash
|
14
14
|
from flask_wtf.file import FileField, FileRequired
|
15
15
|
from flask_classful import FlaskView
|
16
16
|
|
@@ -58,13 +58,13 @@ class Backup(FlaskView):
|
|
58
58
|
|
59
59
|
from flask_babel import refresh
|
60
60
|
refresh()
|
61
|
-
return redirect(url_for("admin.Actions:reinstall2"))
|
61
|
+
return redirect(hutils.flask.url_for("admin.Actions:reinstall2"))
|
62
62
|
# from . import Actions
|
63
63
|
# action = Actions()
|
64
64
|
# return action.reinstall(complete_install=True, domain_changed=True)
|
65
|
-
# #
|
65
|
+
# # hutils.flask.flash_config_success(full_install=True)
|
66
66
|
else:
|
67
|
-
flash(_('Config file is incorrect'), category='error')
|
67
|
+
hutils.flask.flash(_('Config file is incorrect'), category='error')
|
68
68
|
return render_template('backup.html', restore_form=restore_form)
|
69
69
|
|
70
70
|
|
@@ -74,7 +74,7 @@ def get_restore_form(empty=False):
|
|
74
74
|
enable_config_restore = SwitchField(_("Restore Settings"), description=_("Restore Settings description"), default=False)
|
75
75
|
enable_user_restore = SwitchField(_("Restore Users"), description=_("Restore Users description"), default=False)
|
76
76
|
enable_domain_restore = SwitchField(_("Restore Domain"), description=_("Restore Domain description"), default=False)
|
77
|
-
override_root_admin = SwitchField(_("Override Root Admin"), description=_("It will override the root admin to the current user"), default=
|
77
|
+
override_root_admin = SwitchField(_("Override Root Admin"), description=_("It will override the root admin to the current user"), default=False)
|
78
78
|
submit = wtf.fields.SubmitField(_('Submit'))
|
79
79
|
|
80
80
|
return RestoreForm(None) if empty else RestoreForm()
|
@@ -3,7 +3,7 @@ from hiddifypanel.models import *
|
|
3
3
|
from .adminlte import AdminLTEModelView
|
4
4
|
from flask_babelex import gettext as __
|
5
5
|
from flask_babelex import lazy_gettext as _
|
6
|
-
from flask import Markup
|
6
|
+
from flask import Markup, g
|
7
7
|
|
8
8
|
from hiddifypanel.panel.auth import login_required
|
9
9
|
from hiddifypanel.panel import hiddify
|
@@ -103,12 +103,12 @@ class ChildAdmin(AdminLTEModelView):
|
|
103
103
|
if len(model.show_domains) == Domain.query.count():
|
104
104
|
model.show_domains = []
|
105
105
|
|
106
|
-
|
106
|
+
hutils.flask.flash_config_success(restart_mode='apply', domain_changed=True)
|
107
107
|
|
108
108
|
def on_model_delete(self, model):
|
109
109
|
if len(ParentDomain.query.all()) <= 1:
|
110
110
|
raise ValidationError(f"at least one domain should exist")
|
111
|
-
|
111
|
+
hutils.flask.flash_config_success(restart_mode='apply', domain_changed=True)
|
112
112
|
|
113
113
|
def is_accessible(self):
|
114
114
|
if login_required(roles={Role.super_admin})(lambda: True)() != True:
|