hiddifypanel 10.70.9__py3-none-any.whl → 10.80.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 (89) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +5 -2
  3. hiddifypanel/__init__.py +5 -1
  4. hiddifypanel/apps/__init__.py +0 -0
  5. hiddifypanel/apps/asgi_app.py +7 -0
  6. hiddifypanel/apps/celery_app.py +3 -0
  7. hiddifypanel/apps/wsgi_app.py +5 -0
  8. hiddifypanel/auth.py +8 -3
  9. hiddifypanel/base.py +43 -126
  10. hiddifypanel/base_setup.py +82 -0
  11. hiddifypanel/cache.py +3 -2
  12. hiddifypanel/celery.py +45 -0
  13. hiddifypanel/database.py +7 -0
  14. hiddifypanel/drivers/ssh_liberty_bridge_api.py +2 -1
  15. hiddifypanel/drivers/wireguard_api.py +1 -1
  16. hiddifypanel/hutils/crypto.py +27 -0
  17. hiddifypanel/hutils/flask.py +5 -3
  18. hiddifypanel/hutils/network/cf_api.py +5 -5
  19. hiddifypanel/hutils/proxy/__init__.py +1 -0
  20. hiddifypanel/hutils/proxy/clash.py +3 -3
  21. hiddifypanel/hutils/proxy/shared.py +14 -18
  22. hiddifypanel/hutils/proxy/singbox.py +4 -2
  23. hiddifypanel/hutils/proxy/wireguard.py +34 -0
  24. hiddifypanel/hutils/proxy/xray.py +3 -3
  25. hiddifypanel/hutils/proxy/xrayjson.py +10 -7
  26. hiddifypanel/models/admin.py +1 -1
  27. hiddifypanel/models/base_account.py +3 -0
  28. hiddifypanel/models/config.py +5 -2
  29. hiddifypanel/models/config_enum.py +15 -2
  30. hiddifypanel/models/proxy.py +1 -1
  31. hiddifypanel/models/user.py +2 -2
  32. hiddifypanel/panel/__init__.py +8 -8
  33. hiddifypanel/panel/admin/AdminstratorAdmin.py +16 -10
  34. hiddifypanel/panel/admin/DomainAdmin.py +132 -98
  35. hiddifypanel/panel/admin/ProxyAdmin.py +4 -0
  36. hiddifypanel/panel/admin/QuickSetup.py +48 -17
  37. hiddifypanel/panel/admin/SettingAdmin.py +6 -0
  38. hiddifypanel/panel/admin/UserAdmin.py +63 -36
  39. hiddifypanel/panel/admin/adminlte.py +1 -1
  40. hiddifypanel/panel/admin/templates/index.html +6 -4
  41. hiddifypanel/panel/admin/templates/model/user_list.html +11 -3
  42. hiddifypanel/panel/cli.py +14 -3
  43. hiddifypanel/panel/commercial/restapi/v1/tgbot.py +19 -1
  44. hiddifypanel/panel/commercial/restapi/v2/admin/system_actions.py +5 -1
  45. hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +2 -1
  46. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +76 -6
  47. hiddifypanel/panel/common.py +5 -2
  48. hiddifypanel/panel/common_bp/login.py +14 -8
  49. hiddifypanel/panel/hlogger.py +32 -0
  50. hiddifypanel/panel/init_db.py +157 -77
  51. hiddifypanel/panel/node/__init__.py +9 -0
  52. hiddifypanel/panel/node/a.py +14 -0
  53. hiddifypanel/panel/node/hello.py +14 -0
  54. hiddifypanel/panel/node/test.proto +13 -0
  55. hiddifypanel/panel/node/test_grpc.py +40 -0
  56. hiddifypanel/panel/node/test_pb2.py +40 -0
  57. hiddifypanel/panel/node/test_pb2.pyi +17 -0
  58. hiddifypanel/panel/node/test_pb2_grpc.py +97 -0
  59. hiddifypanel/panel/usage.py +13 -3
  60. hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +16 -0
  61. hiddifypanel/panel/user/templates/home/home.html +1 -2
  62. hiddifypanel/panel/user/templates/home/multi.html +1 -2
  63. hiddifypanel/panel/user/user.py +13 -19
  64. hiddifypanel/static/apps-icon/singbox.ico +0 -0
  65. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  66. hiddifypanel/translations/en/LC_MESSAGES/messages.po +125 -30
  67. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  68. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +123 -32
  69. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  70. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +114 -22
  71. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  72. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +129 -32
  73. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  74. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +107 -18
  75. hiddifypanel/translations.i18n/en.json +73 -14
  76. hiddifypanel/translations.i18n/fa.json +72 -13
  77. hiddifypanel/translations.i18n/fr.json +28 -10
  78. hiddifypanel/translations.i18n/my.json +1266 -0
  79. hiddifypanel/translations.i18n/pt.json +68 -9
  80. hiddifypanel/translations.i18n/ru.json +75 -16
  81. hiddifypanel/translations.i18n/zh.json +67 -8
  82. hiddifypanel-10.80.0.dist-info/METADATA +137 -0
  83. {hiddifypanel-10.70.9.dist-info → hiddifypanel-10.80.0.dist-info}/RECORD +136 -119
  84. {hiddifypanel-10.70.9.dist-info → hiddifypanel-10.80.0.dist-info}/WHEEL +1 -2
  85. hiddifypanel-10.80.0.dist-info/entry_points.txt +3 -0
  86. hiddifypanel-10.70.9.dist-info/METADATA +0 -144
  87. hiddifypanel-10.70.9.dist-info/entry_points.txt +0 -2
  88. hiddifypanel-10.70.9.dist-info/top_level.txt +0 -1
  89. {hiddifypanel-10.70.9.dist-info → hiddifypanel-10.80.0.dist-info}/LICENSE.md +0 -0
hiddifypanel/VERSION CHANGED
@@ -1 +1 @@
1
- 10.70.9
1
+ 10.80.0
hiddifypanel/VERSION.py CHANGED
@@ -1,3 +1,6 @@
1
- __version__='10.70.9'
1
+ import importlib.metadata
2
2
  from datetime import datetime
3
- __release_date__= datetime.strptime('2024-11-18','%Y-%m-%d')
3
+
4
+ __version__ = importlib.metadata.version(__package__ or __name__)
5
+ __release_time__= datetime.strptime('2024-12-15T04:01:06','%Y-%m-%dT%H:%M:%S')
6
+ is_released_version=True
hiddifypanel/__init__.py CHANGED
@@ -1,4 +1,8 @@
1
- from .VERSION import __version__, __release_date__
1
+ from .VERSION import __version__, __release_time__,is_released_version
2
+
3
+ from dotenv import load_dotenv
4
+ load_dotenv("/opt/hiddify-manager/hiddify-panel/app.cfg")
5
+
2
6
  # from . import cache
3
7
  from . import Events
4
8
  from .base import create_app, create_app_wsgi
File without changes
@@ -0,0 +1,7 @@
1
+ #!/opt/hiddify-manager/.venv/bin/python
2
+
3
+ from hiddifypanel import create_app_wsgi
4
+ from asgiref.wsgi import WsgiToAsgi
5
+
6
+ app = create_app_wsgi() # noqa
7
+ asgi_app = WsgiToAsgi(app)
@@ -0,0 +1,3 @@
1
+ from hiddifypanel.base import create_celery_app
2
+
3
+ celery_app=create_celery_app()
@@ -0,0 +1,5 @@
1
+ #!/opt/hiddify-manager/.venv/bin/python
2
+
3
+ from hiddifypanel import create_app_wsgi
4
+
5
+ app = create_app_wsgi() # noqa
hiddifypanel/auth.py CHANGED
@@ -142,14 +142,19 @@ def get_account_by_uuid(uuid, is_admin):
142
142
  return AdminUser.by_uuid(f'{uuid}') if is_admin else User.by_uuid(f'{uuid}')
143
143
 
144
144
 
145
- def login_by_uuid(uuid, is_admin: bool):
145
+ def login_by_uuid(uuid,password:str, is_admin: bool)->bool:
146
146
  account = get_account_by_uuid(uuid, is_admin)
147
147
  if not account:
148
148
  return False
149
+ if account.password!=password:
150
+ return False
149
151
  return login_user(account, force=True)
150
152
 
151
153
 
152
154
  def auth_before_request():
155
+ if ".webmanifest" in request.path:
156
+ return
157
+
153
158
  # print("before_request")
154
159
  account = None
155
160
 
@@ -160,7 +165,7 @@ def auth_before_request():
160
165
  # print("uuid", g.uuid, is_admin_path)
161
166
  account = get_account_by_uuid(g.uuid, is_admin_path)
162
167
  # print(account)
163
- if not account:
168
+ if not account or account.password!="":
164
169
  return logout_redirect()
165
170
  if is_admin_path:
166
171
  next_url = request.url
@@ -230,7 +235,7 @@ def redirect_to_login():
230
235
  json_abort(403, 'Unathorized')
231
236
  # if g.user_agent['is_browser']:
232
237
  # return redirect(hurl_for('common_bp.LoginView:basic_0', force=1, next=request.path))
233
- return redirect(hurl_for('common_bp.LoginView:index', force=1, next=request.path))
238
+ return redirect(hurl_for('common_bp.LoginView:index', force=1, next=request.path.replace(f'{g.uuid}/',''),user=g.uuid))
234
239
 
235
240
  # else:
236
241
  # abort(401, "Unauthorized")
hiddifypanel/base.py CHANGED
@@ -1,11 +1,7 @@
1
1
  from flask import request, g
2
2
  # from hiddifypanel.cache import cache
3
- from hiddifypanel.models import *
4
3
 
5
- import flask_bootstrap
6
- import hiddifypanel
7
- from flask_babel import Babel
8
- from flask_session import Session
4
+
9
5
 
10
6
  import datetime
11
7
 
@@ -13,135 +9,54 @@ from dotenv import dotenv_values
13
9
  import os
14
10
  import sys
15
11
  from apiflask import APIFlask
16
- from werkzeug.middleware.proxy_fix import ProxyFix
17
12
  from loguru import logger
18
- from hiddifypanel.panel.init_db import init_db
19
-
20
-
21
- def logger_dynamic_formatter(record) -> str:
22
- fmt = '<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>'
23
- if record['extra']:
24
- fmt += ' | <level>{extra}</level>'
25
- return fmt + '\n'
26
13
 
27
14
 
28
- def init_logger(app, cli):
29
- # configure logger
30
- logger.remove()
31
- logger.add(sys.stderr if cli else sys.stdout, format=logger_dynamic_formatter, level=app.config['STDOUT_LOG_LEVEL'],
32
- colorize=True, catch=True, enqueue=True, diagnose=False, backtrace=True)
33
- logger.trace('Logger initiated :)')
34
-
35
-
36
- # TODO: refactor this function
15
+ from dynaconf import FlaskDynaconf
37
16
 
38
17
  def create_app(*args, cli=False, **config):
39
18
 
40
19
  app = APIFlask(__name__, static_url_path="/<proxy_path>/static/", instance_relative_config=True, version='2.2.0', title="Hiddify API",
41
20
  openapi_blueprint_url_prefix="/<proxy_path>/api", docs_ui='elements', json_errors=False, enable_openapi=not cli)
42
21
  # app = Flask(__name__, static_url_path="/<proxy_path>/static/", instance_relative_config=True)
43
-
44
- if not cli:
45
- from hiddifypanel.cache import redis_client
46
- from hiddifypanel import auth
47
- app.config["PREFERRED_URL_SCHEME"] = "https"
48
- app.wsgi_app = ProxyFix(
49
- app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1,
50
- )
51
- app.servers = {
52
- 'name': 'current',
53
- 'url': '',
54
- } # type: ignore
55
- app.info = {
56
- 'description': 'Hiddify is a free and open source software. It is as it is.',
57
- 'termsOfService': 'https://hiddify.com',
58
- 'contact': {
59
- 'name': 'API Support',
60
- 'url': 'https://www.hiddify.com/support',
61
- 'email': 'panel@hiddify.com'
62
- },
63
- 'license': {
64
- 'name': 'Creative Commons Zero v1.0 Universal',
65
- 'url': 'https://github.com/hiddify/Hiddify-Manager/blob/main/LICENSE'
66
- }
67
- }
68
- # setup flask server-side session
69
- # app.config['APPLICATION_ROOT'] = './'
70
- # app.config['SESSION_COOKIE_DOMAIN'] = '/'
71
- app.config['SESSION_TYPE'] = 'redis'
72
- app.config['SESSION_REDIS'] = redis_client
73
- app.config['SESSION_PERMANENT'] = True
74
- app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=10)
75
- app.security_schemes = { # equals to use config SECURITY_SCHEMES
76
- 'Hiddify-API-Key': {
77
- 'type': 'apiKey',
78
- 'in': 'header',
79
- 'name': 'Hiddify-API-Key',
80
- }
81
- }
82
- Session(app)
83
-
84
- app.jinja_env.line_statement_prefix = '%'
85
- from hiddifypanel import hutils
86
- app.jinja_env.filters['b64encode'] = hutils.encode.do_base_64
87
- app.view_functions['admin.static'] = {} # fix bug in apiflask
88
- flask_bootstrap.Bootstrap4(app)
89
-
22
+ # app.asgi_app = WsgiToAsgi(app)
23
+
90
24
  for c, v in dotenv_values(os.environ.get("HIDDIFY_CFG_PATH", 'app.cfg')).items():
91
25
  if v.isdecimal():
92
26
  v = int(v)
93
27
  else:
94
28
  v = True if v.lower() == "true" else (False if v.lower() == "false" else v)
95
-
96
29
  app.config[c] = v
97
- init_logger(app, cli)
98
- hiddifypanel.database.init_app(app)
99
- with app.app_context():
100
- init_db()
101
- logger.add(app.config['HIDDIFY_CONFIG_PATH'] + "/log/system/panel.log", format=logger_dynamic_formatter, level=hconfig(ConfigEnum.log_level),
102
- colorize=True, catch=True, enqueue=True, diagnose=False, backtrace=True)
103
-
104
- def get_locale():
105
- # Put your logic here. Application can store locale in
106
- # user profile, cookie, session, etc.
107
- if "admin" in request.base_url:
108
- g.locale = hconfig(ConfigEnum.admin_lang) or 'en'
109
- else:
110
- g.locale = auth.current_account.lang or hconfig(ConfigEnum.lang) or 'en'
111
- return g.locale
112
- app.jinja_env.globals['get_locale'] = get_locale
113
- babel = Babel(app, locale_selector=get_locale)
114
- if not cli:
115
- hiddifypanel.panel.common.init_app(app)
116
- hiddifypanel.panel.common_bp.init_app(app)
117
-
118
- from hiddifypanel.panel import user, commercial, admin
119
- admin.init_app(app)
120
- user.init_app(app)
121
- commercial.init_app(app)
30
+ dyn=FlaskDynaconf(app,settings_files=[os.environ.get("HIDDIFY_CFG_PATH", 'app.cfg')])
31
+
32
+ if cli:
33
+ app.config['EXTENSIONS']=[
34
+ # "hiddifypanel.cache:init_app",
35
+ "hiddifypanel.database:init_app",
36
+ "hiddifypanel.panel.hlogger:init_cli",
37
+ "hiddifypanel.panel.cli:init_app",
38
+ "hiddifypanel.celery:init_app",
39
+ ]
40
+ else:
41
+ app.config['EXTENSIONS']=[
42
+ # "hiddifypanel.cache:init_app",
43
+ "hiddifypanel.database:init_app",
44
+ "hiddifypanel.panel.hlogger:init_app",
45
+ "hiddifypanel.base_setup:init_app",
46
+ "hiddifypanel.panel.common:init_app",
47
+ "hiddifypanel.panel.common_bp:init_app",
48
+ "hiddifypanel.panel.admin:init_app",
49
+ "hiddifypanel.panel.user:init_app",
50
+ "hiddifypanel.panel.commercial:init_app",
51
+ "hiddifypanel.panel.node:init_app",
52
+ "hiddifypanel.celery:init_app",
53
+ ]
54
+
55
+
122
56
 
123
57
  app.config.update(config) # Override with passed config
124
- # app.config['WTF_CSRF_CHECK_DEFAULT'] = False
125
- app.config['WTF_CSRF_ENABLED'] = False
126
- # app.config['BABEL_TRANSLATION_DIRECTORIES'] = '/workspace/Hiddify-Server/hiddify-panel/src/translations.i18n'
127
-
128
- # from flask_wtf.csrf import CSRFProtect
129
-
130
- # csrf = CSRFProtect(app)
131
-
132
- # @app.before_request
133
- # def check_csrf():
134
- # if "/admin/user/" in request.base_url:
135
- # return
136
- # if "/admin/domain/" in request.base_url:
137
- # return
138
- # if "/admin/actions/" in request.base_url:
139
- # return
140
- # if "/api/" in request.base_url:
141
- # return
142
- # csrf.protect()
143
-
144
- hiddifypanel.panel.cli.init_app(app)
58
+
59
+ app.config.load_extensions("EXTENSIONS")
145
60
  return app
146
61
 
147
62
 
@@ -150,16 +65,18 @@ def create_app_wsgi(*args, **kwargs):
150
65
  # that doesn't allow **config
151
66
  # to be passed to create_app
152
67
  # https://github.com/pallets/flask/issues/4170
153
- cli = ("hiddifypanel" in sys.argv[0]) or (sys.argv[1] in ["update-usage", "all-configs", "admin_links", "admin_path"])
68
+ cli = ("hiddifypanel" in sys.argv[0] ) or (sys.argv[1] in ["update-usage", "all-configs", "admin_links", "admin_path"])
69
+
154
70
  app = create_app(cli=cli)
155
71
  return app
156
72
 
157
73
 
158
- # def create_cli_app(*args, **kwargs):
159
- # # # workaround for Flask issue
160
- # # # that doesn't allow **config
161
- # # # to be passed to create_app
162
- # # # https://github.com/pallets/flask/issues/4170
163
- # # print(kwargs)
164
- # app = create_app(*args, cli=True, **kwargs)
165
- # return app
74
+
75
+ def create_celery_app():
76
+ # # workaround for Flask issue
77
+ # # that doesn't allow **config
78
+ # # to be passed to create_app
79
+ # # https://github.com/pallets/flask/issues/4170
80
+ # print(kwargs)
81
+ app = create_app(cli=True)
82
+ return app.extensions["celery"]
@@ -0,0 +1,82 @@
1
+ from flask import request, g
2
+ import redis
3
+ # from hiddifypanel.cache import cache
4
+ from hiddifypanel.models import *
5
+
6
+ import flask_bootstrap
7
+ from flask_babel import Babel
8
+ from flask_session import Session
9
+
10
+ import datetime
11
+
12
+ from dotenv import dotenv_values
13
+ import os
14
+ import sys
15
+ from werkzeug.middleware.proxy_fix import ProxyFix
16
+ from loguru import logger
17
+ from sonora.wsgi import grpcWSGI
18
+
19
+
20
+
21
+ def init_app(app):
22
+ from hiddifypanel import auth
23
+ app.config["PREFERRED_URL_SCHEME"] = "https"
24
+ app.wsgi_app = ProxyFix(
25
+ app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1,
26
+ )
27
+
28
+
29
+ app.secret_key="asdsad"
30
+ app.servers = {
31
+ 'name': 'current',
32
+ 'url': '',
33
+ } # type: ignore
34
+ app.info = {
35
+ 'description': 'Hiddify is a free and open source software. It is as it is.',
36
+ 'termsOfService': 'https://hiddify.com',
37
+ 'contact': {
38
+ 'name': 'API Support',
39
+ 'url': 'https://www.hiddify.com/support',
40
+ 'email': 'panel@hiddify.com'
41
+ },
42
+ 'license': {
43
+ 'name': 'Creative Commons Zero v1.0 Universal',
44
+ 'url': 'https://github.com/hiddify/Hiddify-Manager/blob/main/LICENSE'
45
+ }
46
+ }
47
+ # setup flask server-side session
48
+ # app.config['APPLICATION_ROOT'] = './'
49
+ # app.config['SESSION_COOKIE_DOMAIN'] = '/'
50
+
51
+
52
+ app.jinja_env.line_statement_prefix = '%'
53
+ from hiddifypanel import hutils
54
+ app.jinja_env.filters['b64encode'] = hutils.encode.do_base_64
55
+ app.view_functions['admin.static'] = {} # fix bug in apiflask
56
+ flask_bootstrap.Bootstrap4(app)
57
+
58
+ def get_locale():
59
+ # Put your logic here. Application can store locale in
60
+ # user profile, cookie, session, etc.
61
+ if "admin" in request.base_url:
62
+ g.locale = hconfig(ConfigEnum.admin_lang) or 'en'
63
+ else:
64
+ g.locale = auth.current_account.lang or hconfig(ConfigEnum.lang) or 'en'
65
+ return g.locale
66
+ app.jinja_env.globals['get_locale'] = get_locale
67
+ babel = Babel(app, locale_selector=get_locale)
68
+
69
+ app.config['SESSION_TYPE'] = 'redis'
70
+
71
+ app.config['SESSION_REDIS'] = redis.from_url(os.environ['REDIS_URI_MAIN'])
72
+ app.config['SESSION_PERMANENT'] = True
73
+ app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=10)
74
+ app.security_schemes = { # equals to use config SECURITY_SCHEMES
75
+ 'Hiddify-API-Key': {
76
+ 'type': 'apiKey',
77
+ 'in': 'header',
78
+ 'name': 'Hiddify-API-Key',
79
+ }
80
+ }
81
+ Session(app)
82
+ app.wsgi_app = grpcWSGI(app.wsgi_app)
hiddifypanel/cache.py CHANGED
@@ -1,10 +1,11 @@
1
+ import os
1
2
  from redis_cache import RedisCache, chunks, compact_dump
2
3
  import redis
3
4
  from pickle import dumps, loads
4
5
  from loguru import logger
5
6
 
6
- redis_client = redis.from_url('unix:///opt/hiddify-manager/other/redis/run.sock?db=0')
7
-
7
+ redis_client = redis.from_url(os.environ["REDIS_URI_MAIN"])
8
+ # print(os.environ["REDIS_URI_MAIN"])
8
9
 
9
10
  class CustomRedisCache(RedisCache):
10
11
  def __init__(self, redis_client, prefix="rc", serializer=compact_dump, deserializer=loads, key_serializer=None, support_cluster=True, exception_handler=None):
hiddifypanel/celery.py ADDED
@@ -0,0 +1,45 @@
1
+ from celery import Celery, Task
2
+ from celery.schedules import crontab
3
+
4
+ def init_app(app):
5
+ class FlaskTask(Task):
6
+ def __call__(self, *args: object, **kwargs: object) -> object:
7
+ with app.app_context():
8
+ return self.run(*args, **kwargs)
9
+
10
+ celery_app = Celery(app.name, task_cls=FlaskTask)
11
+
12
+ celery_app.config_from_object(dict(
13
+ broker_url=app.config['REDIS_URI_MAIN'],
14
+ result_backend=app.config['REDIS_URI_MAIN'],
15
+ # task_ignore_result=True,
16
+ ))
17
+ app.extensions["celery"] = celery_app
18
+
19
+
20
+ # Calls test('hello') every 10 seconds.
21
+ from hiddifypanel.panel import usage
22
+ celery_app.add_periodic_task(60.0, usage.update_local_usage.s(), name='update usage')
23
+ # celery_app.conf.beat_schedule = {
24
+ # 'update_usage': {
25
+ # 'task': 'hiddifypanel.panel.usage.update_local_usage',
26
+ # 'schedule': 30.0,
27
+
28
+ # },
29
+ # }
30
+ from hiddifypanel.panel.cli import backup_task
31
+ celery_app.autodiscover_tasks()
32
+ # celery_app.add_periodic_task(30.0, backup_task.s(), name='backup task')
33
+ # celery_app.add_periodic_task(
34
+ # crontab(hour="*/6", minute=30),
35
+ # backup_task.delay(),
36
+ # )
37
+
38
+ celery_app.add_periodic_task(
39
+ crontab(hour="*/6", minute="0"),
40
+ backup_task.s(),
41
+ name="backup_task "
42
+ )
43
+
44
+ celery_app.set_default()
45
+ return celery_app
hiddifypanel/database.py CHANGED
@@ -6,6 +6,9 @@ import os
6
6
  from sqlalchemy import Row, text, Sequence
7
7
 
8
8
 
9
+
10
+
11
+
9
12
  db: SQLAlchemy = SQLAlchemy()
10
13
  db.UUID = UUIDType # type: ignore
11
14
 
@@ -13,6 +16,10 @@ db.UUID = UUIDType # type: ignore
13
16
  def init_app(app):
14
17
  app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
15
18
  db.init_app(app)
19
+ with app.app_context():
20
+ from hiddifypanel.panel.init_db import init_db
21
+ init_db()
22
+
16
23
 
17
24
 
18
25
  def db_execute(query: str, return_val: bool = False, commit: bool = False, **params: dict):
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from .abstract_driver import DriverABS
2
3
  from hiddifypanel.models import *
3
4
  import redis
@@ -13,7 +14,7 @@ class SSHLibertyBridgeApi(DriverABS):
13
14
 
14
15
  def get_ssh_redis_client(self):
15
16
  if not hasattr(self, 'redis_client'):
16
- self.redis_client = redis.from_url('unix:///opt/hiddify-manager/other/redis/run.sock?db=1', decode_responses=True)
17
+ self.redis_client = redis.from_url(os.environ.get("REDIS_URI_SSH",""), decode_responses=True)
17
18
 
18
19
  return self.redis_client
19
20
 
@@ -13,7 +13,7 @@ USERS_USAGE = "wg:users-usage"
13
13
  class WireguardApi(DriverABS):
14
14
  def get_redis_client(self):
15
15
  if not hasattr(self, 'redis_client'):
16
- self.redis_client = redis.from_url('unix:///opt/hiddify-manager/other/redis/run.sock?db=1')
16
+ self.redis_client = redis.from_url(os.environ.get("REDIS_URI_SSH",""))
17
17
 
18
18
  return self.redis_client
19
19
 
@@ -1,3 +1,4 @@
1
+ import os
1
2
  import subprocess
2
3
  from cryptography.hazmat.primitives import serialization
3
4
  from cryptography.hazmat.primitives.asymmetric import x25519, ed25519
@@ -46,3 +47,29 @@ def generate_x25519_keys():
46
47
  priv_str = base64.urlsafe_b64encode(priv_bytes).decode()[:-1]
47
48
 
48
49
  return {'private_key': priv_str, 'public_key': pub_str}
50
+
51
+
52
+
53
+ def generate_ssh_host_keys():
54
+ key_types = ["dsa", "ecdsa", "ed25519", "rsa"]
55
+ keys_dict = {}
56
+
57
+ # Generate and read keys
58
+ for key_type in key_types:
59
+ key_file = f"ssh_host_{key_type}_key"
60
+
61
+ subprocess.run([
62
+ "ssh-keygen", "-t", key_type,
63
+ "-f", key_file,
64
+ "-N", ""
65
+ ], check=True)
66
+
67
+ keys_dict[key_type]={}
68
+ with open(key_file, "r") as f:
69
+ keys_dict[key_type]['pk'] = f.read()
70
+ with open(f"{key_file}.pub", "r") as f:
71
+ keys_dict[key_type]['pub'] = f.read()
72
+
73
+ os.remove(key_file)
74
+ os.remove(f"{key_file}.pub") # Remove the public key if not needed
75
+ return keys_dict
@@ -51,7 +51,7 @@ def hurl_for(endpoint, **values):
51
51
  def get_user_agent() -> dict:
52
52
  ua = __parse_user_agent(request.user_agent.string)
53
53
 
54
- if ua.get('v', 1) < 7:
54
+ if ua.get('v', 1) < 9:
55
55
  __parse_user_agent.invalidate_all() # type:ignore
56
56
  ua = __parse_user_agent(request.user_agent.string)
57
57
  return ua
@@ -65,13 +65,14 @@ def __parse_user_agent(ua: str) -> dict:
65
65
  # Example: SFA/1.8.0 (239; sing-box 1.8.0)
66
66
  # Example: SFA/1.7.0 (239; sing-box 1.7.0)
67
67
  # Example: HiddifyNext/0.13.6 (android) like ClashMeta v2ray sing-box
68
-
68
+ if ua=="v2rayNG/1.8.23": #temporary fix for xray sub in hiddifynext
69
+ ua="HiddifyNextX/3.0.0 (android) like ClashMeta v2ray sing-box"
69
70
  uaa = user_agents.parse(ua)
70
71
 
71
72
  match = re.search(ua_version_pattern, ua)
72
73
  generic_version = list(map(int, match.group(1).split('.'))) if match else [0, 0, 0]
73
74
  res = {}
74
- res['v'] = 7
75
+ res['v'] = 9
75
76
  res["is_bot"] = uaa.is_bot
76
77
  res["is_browser"] = re.match('^Mozilla', ua, re.IGNORECASE) and True
77
78
  res['os'] = uaa.os.family
@@ -80,6 +81,7 @@ def __parse_user_agent(ua: str) -> dict:
80
81
  res['is_clash_meta'] = re.match('^(Clash-verge|Clash-?Meta|Stash|NekoBox|NekoRay|Pharos|hiddify-desktop)', ua, re.IGNORECASE) and True
81
82
  res['is_singbox'] = re.match('^(HiddifyNext|Dart|SFI|SFA)', ua, re.IGNORECASE) and True
82
83
  res['is_hiddify'] = re.match('^(HiddifyNext)', ua, re.IGNORECASE) and True
84
+ res['is_hiddify_prefere_xray'] = re.match('^(HiddifyNextX)', ua, re.IGNORECASE) and True
83
85
  res['is_streisand'] = re.match('^(Streisand)', ua, re.IGNORECASE) and True
84
86
  res['is_shadowrocket'] = re.match('^(Shadowrocket)', ua, re.IGNORECASE) and True
85
87
  res['is_v2rayng'] = re.match('^(v2rayNG)', ua, re.IGNORECASE) and True
@@ -1,18 +1,18 @@
1
- import CloudFlare
1
+ import cloudflare
2
2
  from hiddifypanel.models import hconfig, ConfigEnum
3
3
 
4
- __cf: CloudFlare.CloudFlare = '' # type: ignore
4
+ __cf: cloudflare.Cloudflare # type: ignore
5
5
 
6
6
 
7
7
  def __prepare_cf_api_client() -> bool:
8
8
  '''Prepares cloudflare client if it's not already'''
9
9
  global __cf
10
- if __cf and isinstance(__cf, CloudFlare.CloudFlare):
10
+ if __cf and isinstance(__cf, cloudflare.Cloudflare):
11
11
  return True
12
12
 
13
13
  if hconfig(ConfigEnum.cloudflare):
14
- __cf = CloudFlare.CloudFlare(token=hconfig(ConfigEnum.cloudflare))
15
- if __cf and isinstance(__cf, CloudFlare.CloudFlare):
14
+ __cf = cloudflare.Cloudflare(token=hconfig(ConfigEnum.cloudflare))
15
+ if __cf and isinstance(__cf, cloudflare.Cloudflare):
16
16
  return True
17
17
  return False
18
18
 
@@ -3,3 +3,4 @@ from . import xray
3
3
  from . import xrayjson
4
4
  from . import singbox
5
5
  from . import clash
6
+ from . import wireguard
@@ -33,7 +33,7 @@ def to_clash(proxy, meta_or_normal):
33
33
 
34
34
  if proxy['l3'] in ["kcp", ProxyL3.h3_quic]:
35
35
  return {'name': name, 'msg': f"clash does not support {proxy['l3']}", 'type': 'debug'}
36
- if proxy['transport'] in [ProxyTransport.splithttp, ProxyTransport.httpupgrade]:
36
+ if proxy['transport'] in [ProxyTransport.xhttp, ProxyTransport.httpupgrade]:
37
37
  return {'name': name, 'msg': f"clash does not support {proxy['transport']}", 'type': 'debug'}
38
38
  # if proxy['proto'] in [Proxy.shado]:
39
39
 
@@ -44,7 +44,7 @@ def to_clash(proxy, meta_or_normal):
44
44
  return {'name': name, 'msg': f"clash does not support {proxy['proto']}", 'type': 'debug'}
45
45
  if proxy['proto'] in ["vless", 'tuic', 'hysteria2']:
46
46
  return {'name': name, 'msg': f"{proxy['proto']} not supported in clash", 'type': 'debug'}
47
- if proxy['transport'] in ["shadowtls", "splithttp"]:
47
+ if proxy['transport'] in ["shadowtls", "xhttp"]:
48
48
  return {'name': name, 'msg': f"{proxy['transport']} not supported in clash", 'type': 'debug'}
49
49
  if proxy['l3'] == ProxyL3.tls_h2 and proxy['proto'] in [ProxyProto.vmess, ProxyProto.vless] and proxy['dbe'].cdn == ProxyCDN.direct:
50
50
  return {'name': name, 'msg': "bug tls_h2 vmess and vless in clash meta", 'type': 'warning'}
@@ -57,7 +57,7 @@ def to_clash(proxy, meta_or_normal):
57
57
  if proxy["proto"] == "ssh":
58
58
  base["username"] = proxy["uuid"]
59
59
  base["private-key"] = proxy['private_key']
60
- base["host-key"] = proxy.get('host_key', [])
60
+ base["host-key"] = proxy.get('host_keys', [])
61
61
  return base
62
62
  base["udp"] = True
63
63
  if proxy["proto"] == ProxyProto.wireguard: