hiddifypanel 10.16.0.dev1__py3-none-any.whl → 10.20.0__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/cache.py +2 -2
- hiddifypanel/database.py +13 -6
- hiddifypanel/hutils/flask.py +5 -3
- hiddifypanel/hutils/importer/xui.py +2 -3
- hiddifypanel/hutils/proxy/shared.py +9 -4
- hiddifypanel/hutils/proxy/xrayjson.py +11 -3
- hiddifypanel/models/admin.py +3 -2
- hiddifypanel/models/base_account.py +2 -1
- hiddifypanel/models/child.py +4 -3
- hiddifypanel/models/config.py +3 -2
- hiddifypanel/models/config_enum.py +4 -4
- hiddifypanel/models/domain.py +2 -1
- hiddifypanel/models/proxy.py +2 -1
- hiddifypanel/models/report.py +3 -2
- hiddifypanel/models/usage.py +2 -1
- hiddifypanel/models/user.py +3 -2
- hiddifypanel/panel/admin/SettingAdmin.py +9 -5
- hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +2 -7
- hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +14 -7
- hiddifypanel/panel/init_db.py +14 -7
- hiddifypanel/panel/user/user.py +3 -1
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +29 -21
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +31 -26
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations.i18n/en.json +18 -18
- hiddifypanel/translations.i18n/fa.json +18 -18
- {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/METADATA +2 -2
- {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/RECORD +38 -38
- {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/LICENSE.md +0 -0
- {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/WHEEL +0 -0
- {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/top_level.txt +0 -0
hiddifypanel/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
10.
|
1
|
+
10.20.0
|
hiddifypanel/VERSION.py
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
__version__='10.
|
1
|
+
__version__='10.20.0'
|
2
2
|
from datetime import datetime
|
3
|
-
__release_date__= datetime.strptime('2024-04-
|
3
|
+
__release_date__= datetime.strptime('2024-04-12','%Y-%m-%d')
|
hiddifypanel/cache.py
CHANGED
@@ -11,11 +11,11 @@ class CustomRedisCache(RedisCache):
|
|
11
11
|
|
12
12
|
def invalidate_all_cached_functions(self):
|
13
13
|
try:
|
14
|
-
logger.
|
14
|
+
logger.trace("Invalidating all cached functions")
|
15
15
|
chunks_gen = chunks(f'{self.prefix}*', 500)
|
16
16
|
for keys in chunks_gen:
|
17
17
|
self.client.delete(*keys)
|
18
|
-
logger.
|
18
|
+
logger.trace("Successfully invalidated all cached functions")
|
19
19
|
return True
|
20
20
|
except Exception as err:
|
21
21
|
with logger.contextualize(error=err):
|
hiddifypanel/database.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
from typing import Optional
|
1
2
|
from flask_sqlalchemy import SQLAlchemy
|
2
3
|
from sqlalchemy_utils import UUIDType
|
3
4
|
import re
|
4
5
|
import os
|
5
|
-
from sqlalchemy import text
|
6
|
+
from sqlalchemy import Row, text, Sequence
|
6
7
|
|
7
8
|
|
8
9
|
db: SQLAlchemy = SQLAlchemy()
|
@@ -14,8 +15,14 @@ def init_app(app):
|
|
14
15
|
db.init_app(app)
|
15
16
|
|
16
17
|
|
17
|
-
def db_execute(query: str, **params: dict):
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
def db_execute(query: str, return_val: bool = False, commit: bool = False, **params: dict):
|
19
|
+
q = db.session.execute(text(query), params)
|
20
|
+
if commit:
|
21
|
+
db.session.commit()
|
22
|
+
if return_val:
|
23
|
+
return q.fetchall()
|
24
|
+
|
25
|
+
# with db.engine.connect() as connection:
|
26
|
+
# res = connection.execute(text(query), params)
|
27
|
+
# connection.commit()s
|
28
|
+
# return res
|
hiddifypanel/hutils/flask.py
CHANGED
@@ -17,7 +17,8 @@ from hiddifypanel import hutils
|
|
17
17
|
|
18
18
|
|
19
19
|
def flash(message: str, category: str = "message"):
|
20
|
-
|
20
|
+
if not isinstance(message,str):
|
21
|
+
message = str(message)
|
21
22
|
return flask_flash(message, category)
|
22
23
|
|
23
24
|
|
@@ -48,7 +49,7 @@ def hurl_for(endpoint, **values):
|
|
48
49
|
def get_user_agent() -> dict:
|
49
50
|
ua = __parse_user_agent(request.user_agent.string)
|
50
51
|
|
51
|
-
if ua.get('v', 1) <
|
52
|
+
if ua.get('v', 1) < 6:
|
52
53
|
__parse_user_agent.invalidate_all() # type:ignore
|
53
54
|
ua = __parse_user_agent(request.user_agent.string)
|
54
55
|
return ua
|
@@ -68,7 +69,7 @@ def __parse_user_agent(ua: str) -> dict:
|
|
68
69
|
match = re.search(ua_version_pattern, request.user_agent.string)
|
69
70
|
generic_version = list(map(int, match.group(1).split('.'))) if match else [0, 0, 0]
|
70
71
|
res = {}
|
71
|
-
res['v'] =
|
72
|
+
res['v'] = 6
|
72
73
|
res["is_bot"] = uaa.is_bot
|
73
74
|
res["is_browser"] = re.match('^Mozilla', ua, re.IGNORECASE) and True
|
74
75
|
res['os'] = uaa.os.family
|
@@ -79,6 +80,7 @@ def __parse_user_agent(ua: str) -> dict:
|
|
79
80
|
res['is_hiddify'] = re.match('^(HiddifyNext)', ua, re.IGNORECASE) and True
|
80
81
|
res['is_streisand'] = re.match('^(Streisand)', ua, re.IGNORECASE) and True
|
81
82
|
res['is_shadowrocket'] = re.match('^(Shadowrocket)', ua, re.IGNORECASE) and True
|
83
|
+
res['is_v2rayng'] = re.match('^(v2rayNG)', ua, re.IGNORECASE) and True
|
82
84
|
|
83
85
|
if res['is_singbox']:
|
84
86
|
res['singbox_version'] = generic_version
|
@@ -11,13 +11,12 @@ import os
|
|
11
11
|
from sqlalchemy import text
|
12
12
|
|
13
13
|
|
14
|
-
def __query_fetch_json(db, query: str,
|
14
|
+
def __query_fetch_json(db, query: str, **kwargs) -> List[Dict[str, Any]]:
|
15
15
|
try:
|
16
16
|
|
17
|
-
db_execute(query,
|
17
|
+
db_execute(query, commit=True, return_val=False, **kwargs)
|
18
18
|
r = [dict((db.description[i][0], value)
|
19
19
|
for i, value in enumerate(row)) for row in db.fetchall()]
|
20
|
-
connection.close()
|
21
20
|
return r
|
22
21
|
except Exception as err:
|
23
22
|
raise err
|
@@ -107,10 +107,15 @@ def is_tls(l3) -> bool:
|
|
107
107
|
def get_proxies(child_id: int = 0, only_enabled=False) -> list['Proxy']:
|
108
108
|
proxies = Proxy.query.filter(Proxy.child_id == child_id).all()
|
109
109
|
proxies = [c for c in proxies if 'restls' not in c.transport]
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
110
|
+
|
111
|
+
if not hconfig(ConfigEnum.tuic_enable, child_id):
|
112
|
+
proxies = [c for c in proxies if c.proto != ProxyProto.tuic]
|
113
|
+
if not hconfig(ConfigEnum.wireguard_enable, child_id):
|
114
|
+
proxies = [c for c in proxies if c.proto != ProxyProto.wireguard]
|
115
|
+
if not hconfig(ConfigEnum.ssh_server_enable, child_id):
|
116
|
+
proxies = [c for c in proxies if c.proto != ProxyProto.ssh]
|
117
|
+
if not hconfig(ConfigEnum.hysteria_enable, child_id):
|
118
|
+
proxies = [c for c in proxies if c.proto != ProxyProto.hysteria2]
|
114
119
|
if not hconfig(ConfigEnum.shadowsocks2022_enable, child_id):
|
115
120
|
proxies = [c for c in proxies if 'shadowsocks' != c.transport]
|
116
121
|
|
@@ -1,9 +1,8 @@
|
|
1
|
-
import datetime
|
2
1
|
import json
|
3
2
|
import copy
|
4
|
-
from flask import render_template,
|
3
|
+
from flask import render_template, g
|
5
4
|
from hiddifypanel import hutils
|
6
|
-
from hiddifypanel.models import
|
5
|
+
from hiddifypanel.models import ProxyTransport, ProxyL3, ProxyProto, Domain
|
7
6
|
from flask_babel import gettext as _
|
8
7
|
from .xray import is_muxable_agent
|
9
8
|
OUTBOUND_LEVEL = 8
|
@@ -12,7 +11,16 @@ OUTBOUND_LEVEL = 8
|
|
12
11
|
def configs_as_json(domains: list[Domain], remarks: str) -> str:
|
13
12
|
'''Returns xray configs as json'''
|
14
13
|
outbounds = []
|
14
|
+
|
15
|
+
# TODO: check what are unsupported protocols in other apps
|
16
|
+
unsupported_protos = {}
|
17
|
+
if g.user_agent.get('is_v2rayng'):
|
18
|
+
# TODO: ensure which protocols are not supported in v2rayng
|
19
|
+
unsupported_protos = {ProxyProto.wireguard, ProxyProto.hysteria, ProxyProto.hysteria2, ProxyProto.tuic, ProxyProto.ss, ProxyProto.ssr, ProxyProto.ssh}
|
20
|
+
|
15
21
|
for proxy in hutils.proxy.get_valid_proxies(domains):
|
22
|
+
if unsupported_protos and proxy['proto'] in unsupported_protos:
|
23
|
+
continue
|
16
24
|
outbound = to_xray(proxy)
|
17
25
|
if 'msg' not in outbound:
|
18
26
|
outbounds.append(outbound)
|
hiddifypanel/models/admin.py
CHANGED
@@ -10,6 +10,7 @@ from flask_babel import lazy_gettext as _
|
|
10
10
|
from hiddifypanel.database import db, db_execute
|
11
11
|
from hiddifypanel.models.role import Role
|
12
12
|
from hiddifypanel.models.base_account import BaseAccount
|
13
|
+
from sqlalchemy_serializer import SerializerMixin
|
13
14
|
|
14
15
|
|
15
16
|
class AdminMode(StrEnum):
|
@@ -24,7 +25,7 @@ class AdminMode(StrEnum):
|
|
24
25
|
agent = auto()
|
25
26
|
|
26
27
|
|
27
|
-
class AdminUser(BaseAccount):
|
28
|
+
class AdminUser(BaseAccount, SerializerMixin):
|
28
29
|
"""
|
29
30
|
This is a model class for a user in a database that includes columns for their ID, UUID, name, online status,
|
30
31
|
account expiration date, usage limit, package days, mode, start date, current usage, last reset time, and comment.
|
@@ -156,7 +157,7 @@ class AdminUser(BaseAccount):
|
|
156
157
|
db.session.add(AdminUser(id=1, uuid=str(uuid.uuid4()), name="Owner", mode=AdminMode.super_admin, comment=""))
|
157
158
|
db.session.commit()
|
158
159
|
|
159
|
-
db_execute("update admin_user set id=1 where name='Owner'")
|
160
|
+
db_execute("update admin_user set id=1 where name='Owner'", commit=True)
|
160
161
|
admin = AdminUser.by_id(1)
|
161
162
|
|
162
163
|
return admin
|
@@ -6,9 +6,10 @@ from sqlalchemy import Column, String, BigInteger, Enum
|
|
6
6
|
from flask_login import UserMixin as FlaskLoginUserMixin
|
7
7
|
from hiddifypanel.models import Lang
|
8
8
|
from hiddifypanel.database import db
|
9
|
+
from sqlalchemy_serializer import SerializerMixin
|
9
10
|
|
10
11
|
|
11
|
-
class BaseAccount(db.Model, FlaskLoginUserMixin): # type: ignore
|
12
|
+
class BaseAccount(db.Model, SerializerMixin, FlaskLoginUserMixin): # type: ignore
|
12
13
|
__abstract__ = True
|
13
14
|
uuid = Column(String(36), default=lambda: str(uuid.uuid4()), nullable=False, unique=True, index=True)
|
14
15
|
name = Column(String(512), nullable=False, default='')
|
hiddifypanel/models/child.py
CHANGED
@@ -8,6 +8,7 @@ from flask import g, has_app_context
|
|
8
8
|
|
9
9
|
|
10
10
|
from hiddifypanel.database import db, db_execute
|
11
|
+
from sqlalchemy_serializer import SerializerMixin
|
11
12
|
|
12
13
|
|
13
14
|
class ChildMode(StrEnum):
|
@@ -18,7 +19,7 @@ class ChildMode(StrEnum):
|
|
18
19
|
# the child model is node
|
19
20
|
|
20
21
|
|
21
|
-
class Child(db.Model): # type: ignore
|
22
|
+
class Child(db.Model, SerializerMixin): # type: ignore
|
22
23
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
23
24
|
name = Column(String(200), nullable=False, unique=False)
|
24
25
|
mode = Column(Enum(ChildMode), nullable=False, default=ChildMode.virtual)
|
@@ -75,9 +76,9 @@ class Child(db.Model): # type: ignore
|
|
75
76
|
tmp_uuid = str(uuid.uuid4())
|
76
77
|
db.session.add(Child(id=0, unique_id=tmp_uuid, name="Root"))
|
77
78
|
db.session.commit()
|
78
|
-
db_execute(f"update child set id=0 where unique_id='{tmp_uuid}'")
|
79
|
+
db_execute(f"update child set id=0 where unique_id='{tmp_uuid}'", commit=True)
|
79
80
|
child = Child.by_id(0)
|
80
|
-
|
81
|
+
|
81
82
|
return child
|
82
83
|
|
83
84
|
@classmethod
|
hiddifypanel/models/config.py
CHANGED
@@ -8,6 +8,7 @@ from hiddifypanel.cache import cache
|
|
8
8
|
from hiddifypanel.models.child import Child, ChildMode
|
9
9
|
from sqlalchemy import Column, String, Boolean, Enum, ForeignKey, Integer
|
10
10
|
from strenum import StrEnum
|
11
|
+
from sqlalchemy_serializer import SerializerMixin
|
11
12
|
|
12
13
|
|
13
14
|
def error(st):
|
@@ -15,7 +16,7 @@ def error(st):
|
|
15
16
|
err(st)
|
16
17
|
|
17
18
|
|
18
|
-
class BoolConfig(db.Model):
|
19
|
+
class BoolConfig(db.Model, SerializerMixin):
|
19
20
|
child_id = Column(Integer, ForeignKey('child.id'), primary_key=True, default=0)
|
20
21
|
# category = db.Column(db.String(128), primary_key=True)
|
21
22
|
key = Column(Enum(ConfigEnum), primary_key=True)
|
@@ -38,7 +39,7 @@ class BoolConfig(db.Model):
|
|
38
39
|
return HConfigSchema().load(conf_dict)
|
39
40
|
|
40
41
|
|
41
|
-
class StrConfig(db.Model):
|
42
|
+
class StrConfig(db.Model, SerializerMixin):
|
42
43
|
child_id = Column(Integer, ForeignKey('child.id'), primary_key=True, default=0)
|
43
44
|
# category = db.Column(db.String(128), primary_key=True)
|
44
45
|
key = Column(Enum(ConfigEnum), primary_key=True, default=ConfigEnum.admin_secret)
|
@@ -208,11 +208,11 @@ class ConfigEnum(metaclass=FastEnum):
|
|
208
208
|
v2ray_enable = _BoolConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
|
209
209
|
torrent_block = _BoolConfigDscr(ConfigCategory.general, ApplyMode.apply)
|
210
210
|
|
211
|
-
tuic_enable = _BoolConfigDscr(ConfigCategory.
|
212
|
-
tuic_port = _StrConfigDscr(ConfigCategory.
|
211
|
+
tuic_enable = _BoolConfigDscr(ConfigCategory.tuic, ApplyMode.apply)
|
212
|
+
tuic_port = _StrConfigDscr(ConfigCategory.tuic, ApplyMode.apply, hide_in_virtual_child=True)
|
213
213
|
|
214
214
|
# the hysteria is refereing to hysteria2
|
215
|
-
hysteria_enable = _BoolConfigDscr(ConfigCategory.
|
215
|
+
hysteria_enable = _BoolConfigDscr(ConfigCategory.hysteria, ApplyMode.apply)
|
216
216
|
hysteria_port = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply, hide_in_virtual_child=True)
|
217
217
|
# if be enable hysteria2 will be use salamander as obfs
|
218
218
|
hysteria_obfs_enable = _BoolConfigDscr(ConfigCategory.hysteria, ApplyMode.apply)
|
@@ -220,7 +220,7 @@ class ConfigEnum(metaclass=FastEnum):
|
|
220
220
|
hysteria_down_mbps = _StrConfigDscr(ConfigCategory.hysteria, ApplyMode.apply)
|
221
221
|
|
222
222
|
shadowsocks2022_enable = _BoolConfigDscr(ConfigCategory.shadowsocks, ApplyMode.apply)
|
223
|
-
shadowsocks2022_method = _StrConfigDscr(ConfigCategory.
|
223
|
+
shadowsocks2022_method = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
|
224
224
|
shadowsocks2022_port = _StrConfigDscr(ConfigCategory.shadowsocks, ApplyMode.apply)
|
225
225
|
ssfaketls_enable = _BoolConfigDscr(ConfigCategory.shadowsocks, ApplyMode.apply)
|
226
226
|
ssfaketls_fakedomain = _StrConfigDscr(ConfigCategory.shadowsocks, ApplyMode.apply, hide_in_virtual_child=True)
|
hiddifypanel/models/domain.py
CHANGED
@@ -16,6 +16,7 @@ from hiddifypanel.models.config import hconfig
|
|
16
16
|
from .child import Child
|
17
17
|
from hiddifypanel.models.config_enum import ConfigEnum
|
18
18
|
from sqlalchemy.orm import backref
|
19
|
+
from sqlalchemy_serializer import SerializerMixin
|
19
20
|
|
20
21
|
|
21
22
|
class DomainType(StrEnum):
|
@@ -40,7 +41,7 @@ ShowDomain = db.Table('show_domain',
|
|
40
41
|
)
|
41
42
|
|
42
43
|
|
43
|
-
class Domain(db.Model):
|
44
|
+
class Domain(db.Model, SerializerMixin):
|
44
45
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
45
46
|
child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0)
|
46
47
|
domain = db.Column(db.String(200), nullable=False, unique=False)
|
hiddifypanel/models/proxy.py
CHANGED
@@ -4,6 +4,7 @@ from enum import auto
|
|
4
4
|
from sqlalchemy import Column, String, Integer, Boolean, Enum, ForeignKey
|
5
5
|
|
6
6
|
from hiddifypanel.database import db
|
7
|
+
from sqlalchemy_serializer import SerializerMixin
|
7
8
|
|
8
9
|
|
9
10
|
class ProxyTransport(StrEnum):
|
@@ -57,7 +58,7 @@ class ProxyL3(StrEnum):
|
|
57
58
|
custom = auto()
|
58
59
|
|
59
60
|
|
60
|
-
class Proxy(db.Model): # type: ignore
|
61
|
+
class Proxy(db.Model, SerializerMixin): # type: ignore
|
61
62
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
62
63
|
child_id = Column(Integer, ForeignKey('child.id'), default=0)
|
63
64
|
name = Column(String(200), nullable=False, unique=False)
|
hiddifypanel/models/report.py
CHANGED
@@ -2,9 +2,10 @@ import datetime
|
|
2
2
|
|
3
3
|
|
4
4
|
from hiddifypanel.database import db
|
5
|
+
from sqlalchemy_serializer import SerializerMixin
|
5
6
|
|
6
7
|
|
7
|
-
class Report(db.Model):
|
8
|
+
class Report(db.Model, SerializerMixin):
|
8
9
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
9
10
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), default=0, nullable=False)
|
10
11
|
asn_id = db.Column(db.String(200), nullable=False, unique=False)
|
@@ -18,7 +19,7 @@ class Report(db.Model):
|
|
18
19
|
details = db.relationship('ReportDetail', cascade="all,delete", backref='report', lazy='dynamic',)
|
19
20
|
|
20
21
|
|
21
|
-
class ReportDetail(db.Model):
|
22
|
+
class ReportDetail(db.Model, SerializerMixin):
|
22
23
|
report_id = db.Column(db.Integer, db.ForeignKey('report.id'), primary_key=True, )
|
23
24
|
proxy_id = db.Column(db.Integer, db.ForeignKey('proxy.id'), primary_key=True, )
|
24
25
|
ping = db.Column(db.Integer, default=-1)
|
hiddifypanel/models/usage.py
CHANGED
@@ -6,9 +6,10 @@ from sqlalchemy import func
|
|
6
6
|
|
7
7
|
|
8
8
|
from hiddifypanel.database import db
|
9
|
+
from sqlalchemy_serializer import SerializerMixin
|
9
10
|
|
10
11
|
|
11
|
-
class DailyUsage(db.Model):
|
12
|
+
class DailyUsage(db.Model, SerializerMixin):
|
12
13
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
13
14
|
date = db.Column(db.Date, default=datetime.date.today(), index=True)
|
14
15
|
usage = db.Column(db.BigInteger, default=0, nullable=False)
|
hiddifypanel/models/user.py
CHANGED
@@ -10,6 +10,7 @@ from hiddifypanel.database import db
|
|
10
10
|
from hiddifypanel.models import Lang
|
11
11
|
from hiddifypanel.models.base_account import BaseAccount
|
12
12
|
from hiddifypanel.models.admin import AdminUser
|
13
|
+
from sqlalchemy_serializer import SerializerMixin
|
13
14
|
|
14
15
|
ONE_GIG = 1024 * 1024 * 1024
|
15
16
|
|
@@ -35,7 +36,7 @@ package_mode_dic = {
|
|
35
36
|
}
|
36
37
|
|
37
38
|
|
38
|
-
class UserDetail(db.Model):
|
39
|
+
class UserDetail(db.Model, SerializerMixin):
|
39
40
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
40
41
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), default=0, nullable=False)
|
41
42
|
child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0, nullable=False)
|
@@ -56,7 +57,7 @@ class UserDetail(db.Model):
|
|
56
57
|
return [] if not self.connected_devices else self.connected_devices.split(",")
|
57
58
|
|
58
59
|
|
59
|
-
class User(BaseAccount):
|
60
|
+
class User(BaseAccount, SerializerMixin):
|
60
61
|
"""
|
61
62
|
This is a model class for a user in a database that includes columns for their ID, UUID, name, online status,
|
62
63
|
account expiration date, usage limit, package days, mode, start date, current usage, last reset time, and comment.
|
@@ -213,11 +213,15 @@ def get_config_form():
|
|
213
213
|
package_modes.append(("develop", _("Develop")))
|
214
214
|
field = wtf.SelectField(_(f"config.{c.key}.label"), choices=package_modes, description=_(f"config.{c.key}.description"), default=hconfig(c.key))
|
215
215
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
216
|
+
# the shadowsocks2022_method is hidden now, because it only has one option to choose
|
217
|
+
# elif c.key == ConfigEnum.shadowsocks2022_method:
|
218
|
+
# field = wtf.SelectField(
|
219
|
+
# _(f"config.{c.key}.label"),
|
220
|
+
# choices=[
|
221
|
+
# ("2022-blake3-aes-256-gcm", "2022-blake3-aes-256-gcm"),
|
222
|
+
# # ("2022-blake3-chacha20-poly1305", "2022-blake3-chacha20-poly1305"),
|
223
|
+
# ],
|
224
|
+
# description=_(f"config.{c.key}.description"), default=hconfig(c.key))
|
221
225
|
|
222
226
|
elif c.key == ConfigEnum.utls:
|
223
227
|
field = wtf.SelectField(
|
@@ -1,18 +1,13 @@
|
|
1
1
|
from hiddifypanel.models import *
|
2
|
-
from hiddifypanel.panel import hiddify
|
3
2
|
from hiddifypanel.panel.admin.adminlte import AdminLTEModelView
|
4
3
|
from flask_babel import gettext as __
|
5
4
|
from flask_babel import lazy_gettext as _
|
6
5
|
from flask import g, redirect
|
7
6
|
from markupsafe import Markup
|
8
|
-
|
9
|
-
from hiddifypanel.hutils.flask import hurl_for, flash
|
10
7
|
from hiddifypanel.auth import login_required
|
11
|
-
from flask_admin.model.template import EndpointLinkRowAction
|
12
8
|
from flask_admin.actions import action
|
13
9
|
from flask_admin.contrib.sqla import form, filters as sqla_filters, tools
|
14
10
|
# Define a custom field type for the related domains
|
15
|
-
from flask import current_app
|
16
11
|
from hiddifypanel import hutils
|
17
12
|
|
18
13
|
|
@@ -31,7 +26,7 @@ class ProxyDetailsAdmin(AdminLTEModelView):
|
|
31
26
|
count = query.update({'enable': False})
|
32
27
|
|
33
28
|
self.session.commit()
|
34
|
-
flash(_('%(count)s records were successfully disabled.', count=count), 'success')
|
29
|
+
hutils.flask.flash(_('%(count)s records were successfully disabled.', count=count), 'success')
|
35
30
|
hutils.proxy.get_proxies.invalidate_all()
|
36
31
|
|
37
32
|
@action('enable', 'Enable', 'Are you sure you want to enable selected proxies?')
|
@@ -40,7 +35,7 @@ class ProxyDetailsAdmin(AdminLTEModelView):
|
|
40
35
|
count = query.update({'enable': True})
|
41
36
|
|
42
37
|
self.session.commit()
|
43
|
-
flash(_('%(count)s records were successfully enabled.', count=count), 'success')
|
38
|
+
hutils.flask.flash(_('%(count)s records were successfully enabled.', count=count), 'success')
|
44
39
|
hutils.proxy.get_proxies.invalidate_all()
|
45
40
|
|
46
41
|
# list_template = 'model/domain_list.html'
|
@@ -44,7 +44,7 @@ class AllConfigsAPI(MethodView):
|
|
44
44
|
# Add Auto
|
45
45
|
items.append(
|
46
46
|
create_item(
|
47
|
-
"Auto", "ALL", "
|
47
|
+
"Auto", "ALL", "", "", "", "",
|
48
48
|
# f"{base_url}sub/?asn={c['asn']}"
|
49
49
|
f"{base_url}auto/?asn={c['asn']}#{config_name}"
|
50
50
|
)
|
@@ -53,16 +53,24 @@ class AllConfigsAPI(MethodView):
|
|
53
53
|
# Add Full Singbox
|
54
54
|
items.append(
|
55
55
|
create_item(
|
56
|
-
"Full Singbox", "ALL", "
|
56
|
+
"Full Singbox", "ALL", "", "", "", "",
|
57
57
|
# f"{base_url}full-singbox.json?asn={c['asn']}"
|
58
58
|
f"{base_url}singbox/?asn={c['asn']}#{config_name}"
|
59
59
|
)
|
60
60
|
)
|
61
61
|
|
62
|
+
# Add Full Xray
|
63
|
+
items.append(
|
64
|
+
create_item(
|
65
|
+
"Full Xray", "ALL", "", "", "", "",
|
66
|
+
f"{base_url}xray/#{config_name}"
|
67
|
+
)
|
68
|
+
)
|
69
|
+
|
62
70
|
# Add Subscription link
|
63
71
|
items.append(
|
64
72
|
create_item(
|
65
|
-
"Subscription link", "ALL", "
|
73
|
+
"Subscription link", "ALL", "", "", "", "",
|
66
74
|
# f"{base_url}all.txt?name={c['db_domain'].alias or c['db_domain'].domain}-{c['asn']}&asn={c['asn']}&mode={c['mode']}"
|
67
75
|
f"{base_url}sub/?asn={c['asn']}#{config_name}"
|
68
76
|
)
|
@@ -71,16 +79,15 @@ class AllConfigsAPI(MethodView):
|
|
71
79
|
# Add Subscription link base64
|
72
80
|
items.append(
|
73
81
|
create_item(
|
74
|
-
"Subscription link b64", "ALL", "
|
82
|
+
"Subscription link b64", "ALL", "", "", "", "",
|
75
83
|
# f"{base_url}all.txt?name=new_link_{c['db_domain'].alias or c['db_domain'].domain}-{c['asn']}-{c['mode']}&asn={c['asn']}&mode={c['mode']}&base64=True"
|
76
84
|
f"{base_url}sub64/?asn={c['asn']}#{config_name}"
|
77
85
|
)
|
78
86
|
)
|
79
|
-
|
80
87
|
# Add Clash Meta
|
81
88
|
items.append(
|
82
89
|
create_item(
|
83
|
-
"Clash Meta", "ALL", "
|
90
|
+
"Clash Meta", "ALL", "", "", "", "",
|
84
91
|
# f"clashmeta://install-config?url={base_url}clash/meta/all.yml&name=mnormal_{c['db_domain'].alias or c['db_domain'].domain}-{c['asn']}-{c['mode']}&asn={c['asn']}&mode={c['mode']}"
|
85
92
|
f"clash://install-config?url={base_url}clashmeta/?asn={c['asn']}#{config_name}"
|
86
93
|
)
|
@@ -99,7 +106,7 @@ class AllConfigsAPI(MethodView):
|
|
99
106
|
if hconfig(ConfigEnum.ssh_server_enable):
|
100
107
|
items.append(
|
101
108
|
create_item(
|
102
|
-
"Singbox: SSH", "SSH", "
|
109
|
+
"Singbox: SSH", "SSH", "", "", "", "",
|
103
110
|
# f"{base_url}singbox.json?name={c['db_domain'].alias or c['db_domain'].domain}-{c['asn']}&asn={c['asn']}&mode={c['mode']}"
|
104
111
|
f"{base_url}singbox-ssh/?asn={c['asn']}#{config_name}"
|
105
112
|
)
|
hiddifypanel/panel/init_db.py
CHANGED
@@ -7,14 +7,22 @@ import uuid
|
|
7
7
|
|
8
8
|
|
9
9
|
from hiddifypanel import Events, hutils
|
10
|
+
from hiddifypanel.cache import cache
|
10
11
|
from hiddifypanel.models import *
|
11
12
|
from hiddifypanel.panel import hiddify
|
12
13
|
from hiddifypanel.database import db, db_execute
|
13
14
|
from flask import g
|
15
|
+
from sqlalchemy import text
|
14
16
|
|
15
17
|
MAX_DB_VERSION = 90
|
16
18
|
|
17
19
|
|
20
|
+
def _v84(child_id):
|
21
|
+
# the 2022-blake3-chacha20-poly1305 encryption method doesn't support multiuser config
|
22
|
+
if hconfig(ConfigEnum.shadowsocks2022_method) == '2022-blake3-chacha20-poly1305':
|
23
|
+
set_hconfig(ConfigEnum.shadowsocks2022_method, '2022-blake3-aes-256-gcm')
|
24
|
+
|
25
|
+
|
18
26
|
def _v83(child_id):
|
19
27
|
set_hconfig(ConfigEnum.log_level, LogLevel.CRITICAL)
|
20
28
|
|
@@ -547,7 +555,7 @@ def add_column(column):
|
|
547
555
|
try:
|
548
556
|
column_type = column.type.compile(db.engine.dialect)
|
549
557
|
|
550
|
-
db_execute(f'ALTER TABLE {column.table.name} ADD COLUMN {column.name} {column_type}')
|
558
|
+
db_execute(f'ALTER TABLE {column.table.name} ADD COLUMN {column.name} {column_type}', commit=True)
|
551
559
|
except BaseException:
|
552
560
|
pass
|
553
561
|
|
@@ -578,7 +586,7 @@ def add_new_enum_values():
|
|
578
586
|
# result = db.engine.execute(f"SELECT DISTINCT `{column_name}` FROM {table_name}")
|
579
587
|
# db_values = {row[0] for row in result}
|
580
588
|
|
581
|
-
result =
|
589
|
+
result = db.session.execute(text(f"SHOW COLUMNS FROM {table_name} LIKE '{column_name}';")).fetchall()
|
582
590
|
db_values = []
|
583
591
|
|
584
592
|
for row in result:
|
@@ -597,9 +605,7 @@ def add_new_enum_values():
|
|
597
605
|
# Add the new value to the enum column in the database
|
598
606
|
enumstr = ','.join([f"'{a}'" for a in [*existing_values, *old_values]])
|
599
607
|
|
600
|
-
db_execute(f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});")
|
601
|
-
|
602
|
-
db.session.commit()
|
608
|
+
db_execute(f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});", commit=True)
|
603
609
|
|
604
610
|
|
605
611
|
def latest_db_version():
|
@@ -648,8 +654,8 @@ def upgrade_database():
|
|
648
654
|
|
649
655
|
def init_db():
|
650
656
|
db.create_all()
|
651
|
-
|
652
|
-
|
657
|
+
cache.invalidate_all_cached_functions()
|
658
|
+
|
653
659
|
# set_hconfig(ConfigEnum.db_version, 71)
|
654
660
|
# temporary fix
|
655
661
|
add_column(Child.mode)
|
@@ -800,3 +806,4 @@ def migrate(db_version):
|
|
800
806
|
AdminUser.get_super_admin() # to create super admin if not exist
|
801
807
|
|
802
808
|
upgrade_database()
|
809
|
+
db.session.commit()
|
hiddifypanel/panel/user/user.py
CHANGED
@@ -6,7 +6,6 @@ import re
|
|
6
6
|
from flask import render_template, request, Response, g
|
7
7
|
from apiflask import abort
|
8
8
|
from flask_classful import FlaskView, route
|
9
|
-
from urllib.parse import urlparse
|
10
9
|
from flask_babel import gettext as _
|
11
10
|
|
12
11
|
|
@@ -112,6 +111,9 @@ class UserView(FlaskView):
|
|
112
111
|
if re.match('^(Clash|Stash)', ua, re.IGNORECASE):
|
113
112
|
return self.clash_config(meta_or_normal="normal")
|
114
113
|
|
114
|
+
if g.user_agent.get('is_v2rayng'):
|
115
|
+
return self.xray()
|
116
|
+
|
115
117
|
# if 'HiddifyNext' in ua or 'Dart' in ua:
|
116
118
|
# return self.clash_config(meta_or_normal="meta")
|
117
119
|
|
Binary file
|