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.
Files changed (38) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/cache.py +2 -2
  4. hiddifypanel/database.py +13 -6
  5. hiddifypanel/hutils/flask.py +5 -3
  6. hiddifypanel/hutils/importer/xui.py +2 -3
  7. hiddifypanel/hutils/proxy/shared.py +9 -4
  8. hiddifypanel/hutils/proxy/xrayjson.py +11 -3
  9. hiddifypanel/models/admin.py +3 -2
  10. hiddifypanel/models/base_account.py +2 -1
  11. hiddifypanel/models/child.py +4 -3
  12. hiddifypanel/models/config.py +3 -2
  13. hiddifypanel/models/config_enum.py +4 -4
  14. hiddifypanel/models/domain.py +2 -1
  15. hiddifypanel/models/proxy.py +2 -1
  16. hiddifypanel/models/report.py +3 -2
  17. hiddifypanel/models/usage.py +2 -1
  18. hiddifypanel/models/user.py +3 -2
  19. hiddifypanel/panel/admin/SettingAdmin.py +9 -5
  20. hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +2 -7
  21. hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +14 -7
  22. hiddifypanel/panel/init_db.py +14 -7
  23. hiddifypanel/panel/user/user.py +3 -1
  24. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  25. hiddifypanel/translations/en/LC_MESSAGES/messages.po +29 -21
  26. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  27. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +31 -26
  28. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  29. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  30. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  31. hiddifypanel/translations.i18n/en.json +18 -18
  32. hiddifypanel/translations.i18n/fa.json +18 -18
  33. {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/METADATA +2 -2
  34. {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/RECORD +38 -38
  35. {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/LICENSE.md +0 -0
  36. {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/WHEEL +0 -0
  37. {hiddifypanel-10.16.0.dev1.dist-info → hiddifypanel-10.20.0.dist-info}/entry_points.txt +0 -0
  38. {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.16.0.dev1
1
+ 10.20.0
hiddifypanel/VERSION.py CHANGED
@@ -1,3 +1,3 @@
1
- __version__='10.16.0.dev1'
1
+ __version__='10.20.0'
2
2
  from datetime import datetime
3
- __release_date__= datetime.strptime('2024-04-07','%Y-%m-%d')
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.info("Invalidating all cached functions")
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.success("Successfully invalidated all cached functions")
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
- with db.engine.connect() as connection:
19
- res = connection.execute(text(query), params)
20
- connection.commit()
21
- return res
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
@@ -17,7 +17,8 @@ from hiddifypanel import hutils
17
17
 
18
18
 
19
19
  def flash(message: str, category: str = "message"):
20
- # if isinstance(message, LazyString)
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) < 5:
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'] = 5
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, args: Tuple = ()) -> List[Dict[str, Any]]:
14
+ def __query_fetch_json(db, query: str, **kwargs) -> List[Dict[str, Any]]:
15
15
  try:
16
16
 
17
- db_execute(query, args)
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
- # if not hconfig(ConfigEnum.tuic_enable, child_id):
111
- # proxies = [c for c in proxies if c.proto != ProxyProto.tuic]
112
- # if not hconfig(ConfigEnum.hysteria_enable, child_id):
113
- # proxies = [c for c in proxies if c.proto != ProxyProto.hysteria2]
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, request, g
3
+ from flask import render_template, g
5
4
  from hiddifypanel import hutils
6
- from hiddifypanel.models import Proxy, ProxyTransport, ProxyL3, ProxyCDN, ProxyProto, Domain, ConfigEnum, DomainType
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)
@@ -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='')
@@ -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
- print("child-=======", child)
81
+
81
82
  return child
82
83
 
83
84
  @classmethod
@@ -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.hidden, ApplyMode.apply)
212
- tuic_port = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply, hide_in_virtual_child=True)
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.hidden, ApplyMode.apply)
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.shadowsocks, ApplyMode.apply)
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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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
- elif c.key == ConfigEnum.shadowsocks2022_method:
217
- field = wtf.SelectField(
218
- _(f"config.{c.key}.label"),
219
- choices=[("2022-blake3-aes-256-gcm", "2022-blake3-aes-256-gcm"), ("2022-blake3-chacha20-poly1305", "2022-blake3-chacha20-poly1305"),],
220
- description=_(f"config.{c.key}.description"), default=hconfig(c.key))
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", "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", "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", "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", "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", "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", "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
  )
@@ -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 = db_execute(f"SHOW COLUMNS FROM {table_name} LIKE '{column_name}';")
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
- hconfig.invalidate_all()
652
- get_hconfigs.invalidate_all()
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()
@@ -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