hiddifypanel 10.70.8__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.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +5 -2
- hiddifypanel/__init__.py +5 -1
- hiddifypanel/apps/__init__.py +0 -0
- hiddifypanel/apps/asgi_app.py +7 -0
- hiddifypanel/apps/celery_app.py +3 -0
- hiddifypanel/apps/wsgi_app.py +5 -0
- hiddifypanel/auth.py +8 -3
- hiddifypanel/base.py +43 -126
- hiddifypanel/base_setup.py +82 -0
- hiddifypanel/cache.py +3 -2
- hiddifypanel/celery.py +45 -0
- hiddifypanel/database.py +7 -0
- hiddifypanel/drivers/ssh_liberty_bridge_api.py +2 -1
- hiddifypanel/drivers/wireguard_api.py +1 -1
- hiddifypanel/hutils/crypto.py +27 -0
- hiddifypanel/hutils/flask.py +5 -3
- hiddifypanel/hutils/network/cf_api.py +5 -5
- hiddifypanel/hutils/proxy/__init__.py +1 -0
- hiddifypanel/hutils/proxy/clash.py +3 -3
- hiddifypanel/hutils/proxy/shared.py +14 -18
- hiddifypanel/hutils/proxy/singbox.py +4 -2
- hiddifypanel/hutils/proxy/wireguard.py +34 -0
- hiddifypanel/hutils/proxy/xray.py +3 -3
- hiddifypanel/hutils/proxy/xrayjson.py +10 -7
- hiddifypanel/models/admin.py +1 -1
- hiddifypanel/models/base_account.py +3 -0
- hiddifypanel/models/config.py +5 -2
- hiddifypanel/models/config_enum.py +15 -2
- hiddifypanel/models/proxy.py +1 -1
- hiddifypanel/models/user.py +2 -2
- hiddifypanel/panel/__init__.py +8 -8
- hiddifypanel/panel/admin/AdminstratorAdmin.py +16 -10
- hiddifypanel/panel/admin/DomainAdmin.py +132 -98
- hiddifypanel/panel/admin/ProxyAdmin.py +4 -0
- hiddifypanel/panel/admin/QuickSetup.py +48 -17
- hiddifypanel/panel/admin/SettingAdmin.py +6 -0
- hiddifypanel/panel/admin/UserAdmin.py +63 -36
- hiddifypanel/panel/admin/adminlte.py +1 -1
- hiddifypanel/panel/admin/templates/index.html +6 -4
- hiddifypanel/panel/admin/templates/model/user_list.html +11 -3
- hiddifypanel/panel/cli.py +14 -3
- hiddifypanel/panel/commercial/restapi/v1/tgbot.py +19 -1
- hiddifypanel/panel/commercial/restapi/v2/admin/system_actions.py +5 -1
- hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +2 -1
- hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +76 -6
- hiddifypanel/panel/common.py +5 -2
- hiddifypanel/panel/common_bp/login.py +14 -8
- hiddifypanel/panel/hlogger.py +32 -0
- hiddifypanel/panel/init_db.py +157 -77
- hiddifypanel/panel/node/__init__.py +9 -0
- hiddifypanel/panel/node/a.py +14 -0
- hiddifypanel/panel/node/hello.py +14 -0
- hiddifypanel/panel/node/test.proto +13 -0
- hiddifypanel/panel/node/test_grpc.py +40 -0
- hiddifypanel/panel/node/test_pb2.py +40 -0
- hiddifypanel/panel/node/test_pb2.pyi +17 -0
- hiddifypanel/panel/node/test_pb2_grpc.py +97 -0
- hiddifypanel/panel/usage.py +13 -3
- hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +16 -0
- hiddifypanel/panel/user/templates/home/home.html +1 -2
- hiddifypanel/panel/user/templates/home/multi.html +1 -2
- hiddifypanel/panel/user/user.py +13 -19
- hiddifypanel/static/apps-icon/singbox.ico +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +125 -30
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +123 -32
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +114 -22
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +129 -32
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +107 -18
- hiddifypanel/translations.i18n/en.json +73 -14
- hiddifypanel/translations.i18n/fa.json +72 -13
- hiddifypanel/translations.i18n/fr.json +28 -10
- hiddifypanel/translations.i18n/my.json +1266 -0
- hiddifypanel/translations.i18n/pt.json +68 -9
- hiddifypanel/translations.i18n/ru.json +75 -16
- hiddifypanel/translations.i18n/zh.json +67 -8
- hiddifypanel-10.80.0.dist-info/METADATA +137 -0
- {hiddifypanel-10.70.8.dist-info → hiddifypanel-10.80.0.dist-info}/RECORD +136 -119
- {hiddifypanel-10.70.8.dist-info → hiddifypanel-10.80.0.dist-info}/WHEEL +1 -2
- hiddifypanel-10.80.0.dist-info/entry_points.txt +3 -0
- hiddifypanel-10.70.8.dist-info/METADATA +0 -144
- hiddifypanel-10.70.8.dist-info/entry_points.txt +0 -2
- hiddifypanel-10.70.8.dist-info/top_level.txt +0 -1
- {hiddifypanel-10.70.8.dist-info → hiddifypanel-10.80.0.dist-info}/LICENSE.md +0 -0
hiddifypanel/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
10.
|
1
|
+
10.80.0
|
hiddifypanel/VERSION.py
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
-
|
1
|
+
import importlib.metadata
|
2
2
|
from datetime import datetime
|
3
|
-
|
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__,
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|
-
|
125
|
-
app.config
|
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
|
-
|
159
|
-
|
160
|
-
# #
|
161
|
-
# #
|
162
|
-
# #
|
163
|
-
# #
|
164
|
-
#
|
165
|
-
|
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(
|
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(
|
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(
|
16
|
+
self.redis_client = redis.from_url(os.environ.get("REDIS_URI_SSH",""))
|
17
17
|
|
18
18
|
return self.redis_client
|
19
19
|
|
hiddifypanel/hutils/crypto.py
CHANGED
@@ -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
|
hiddifypanel/hutils/flask.py
CHANGED
@@ -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) <
|
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'] =
|
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
|
1
|
+
import cloudflare
|
2
2
|
from hiddifypanel.models import hconfig, ConfigEnum
|
3
3
|
|
4
|
-
__cf:
|
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,
|
10
|
+
if __cf and isinstance(__cf, cloudflare.Cloudflare):
|
11
11
|
return True
|
12
12
|
|
13
13
|
if hconfig(ConfigEnum.cloudflare):
|
14
|
-
__cf =
|
15
|
-
if __cf and isinstance(__cf,
|
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
|
|
@@ -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.
|
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", "
|
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('
|
60
|
+
base["host-key"] = proxy.get('host_keys', [])
|
61
61
|
return base
|
62
62
|
base["udp"] = True
|
63
63
|
if proxy["proto"] == ProxyProto.wireguard:
|