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.
- 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.9.dist-info → hiddifypanel-10.80.0.dist-info}/RECORD +136 -119
- {hiddifypanel-10.70.9.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.9.dist-info/METADATA +0 -144
- hiddifypanel-10.70.9.dist-info/entry_points.txt +0 -2
- hiddifypanel-10.70.9.dist-info/top_level.txt +0 -1
- {hiddifypanel-10.70.9.dist-info → hiddifypanel-10.80.0.dist-info}/LICENSE.md +0 -0
@@ -192,10 +192,12 @@
|
|
192
192
|
}
|
193
193
|
|
194
194
|
function update_from_json(data) {
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
195
|
+
// Use local variables instead of globals
|
196
|
+
const usage_history = data['usage_history'];
|
197
|
+
const onlines = usage_history['m5']['online'];
|
198
|
+
const total_users = usage_history['total']['users'];
|
199
|
+
const stats = data['stats'];
|
200
|
+
|
199
201
|
info_box("today", "fa-solid fa-calendar", "Today Usage",
|
200
202
|
((usage_history['today']['usage'] / Math.pow(1024, 3)).toFixed(1)) + " GB",
|
201
203
|
usage_history['today']['online'] / Math.max(1, total_users) * 100,
|
@@ -121,9 +121,17 @@
|
|
121
121
|
$(document).Toasts('create', {
|
122
122
|
class: 'bg-danger',
|
123
123
|
position: "{{'topRight' if get_locale()=='fa' else 'topLeft'}}",
|
124
|
-
title: status + " " + error,
|
125
|
-
body: JSON.stringify(jqx)
|
126
|
-
|
124
|
+
title: $('<div>').text(status + " " + error).html(),
|
125
|
+
body: $('<div>').text(JSON.stringify(jqx)).html(),
|
126
|
+
autohide: true,
|
127
|
+
delay: 5000
|
128
|
+
});
|
129
|
+
|
130
|
+
console.error('API Error:', {
|
131
|
+
status: status,
|
132
|
+
error: error,
|
133
|
+
details: jqx
|
134
|
+
});
|
127
135
|
},
|
128
136
|
success: function (data) {
|
129
137
|
// dialog.modal('hide');
|
hiddifypanel/panel/cli.py
CHANGED
@@ -13,6 +13,7 @@ from hiddifypanel.panel import hiddify, usage
|
|
13
13
|
from hiddifypanel.database import db
|
14
14
|
from hiddifypanel.panel.init_db import init_db
|
15
15
|
|
16
|
+
from loguru import logger
|
16
17
|
|
17
18
|
def drop_db():
|
18
19
|
"""Cleans database"""
|
@@ -29,7 +30,12 @@ def downgrade():
|
|
29
30
|
os.rename("/opt/hiddify-manager/hiddify-panel/hiddifypanel.db.old", "/opt/hiddify-manager/hiddify-panel/hiddifypanel.db")
|
30
31
|
|
31
32
|
|
33
|
+
from celery import shared_task
|
32
34
|
def backup():
|
35
|
+
backup_task()
|
36
|
+
|
37
|
+
@shared_task(ignore_result=False)
|
38
|
+
def backup_task():
|
33
39
|
dbdict = hiddify.dump_db_to_dict()
|
34
40
|
os.makedirs('backup', exist_ok=True)
|
35
41
|
dst = f'backup/{datetime.datetime.now().strftime("%Y_%m_%d__%H_%M_%S")}.json'
|
@@ -42,9 +48,12 @@ def backup():
|
|
42
48
|
register_bot(True)
|
43
49
|
|
44
50
|
with open(dst, 'rb') as document:
|
45
|
-
for admin in AdminUser.query.filter(AdminUser.mode == AdminMode.super_admin, AdminUser.telegram_id is not None).all():
|
51
|
+
for admin in AdminUser.query.filter(AdminUser.mode == AdminMode.super_admin, AdminUser.telegram_id is not None,AdminUser.telegram_id!=0).all():
|
46
52
|
caption = ("Backup \n" + admin_links())
|
47
|
-
|
53
|
+
try:
|
54
|
+
bot.send_document(admin.telegram_id, document, visible_file_name=dst.replace("backup/", ""), caption=caption[:1000])
|
55
|
+
except Exception as e:
|
56
|
+
logger.exception(e)
|
48
57
|
|
49
58
|
|
50
59
|
def all_configs():
|
@@ -131,7 +140,9 @@ def init_app(app):
|
|
131
140
|
hiddify.add_or_update_config(key=key, value=val)
|
132
141
|
|
133
142
|
return "success"
|
134
|
-
|
143
|
+
@app.cli.command()
|
144
|
+
def reset_owner_password():
|
145
|
+
AdminUser.get_super_admin().update_password("")
|
135
146
|
@ app.cli.command()
|
136
147
|
@ click.option("--config", "-c")
|
137
148
|
def import_config(config):
|
@@ -2,6 +2,7 @@ import telebot
|
|
2
2
|
from flask import request
|
3
3
|
from apiflask import abort
|
4
4
|
from flask_restful import Resource
|
5
|
+
import time
|
5
6
|
|
6
7
|
from hiddifypanel.models import *
|
7
8
|
from hiddifypanel import Events
|
@@ -11,7 +12,24 @@ logger = telebot.logger
|
|
11
12
|
|
12
13
|
class ExceptionHandler(telebot.ExceptionHandler):
|
13
14
|
def handle(self, exception):
|
14
|
-
|
15
|
+
"""Improved error handling for Telegram bot exceptions"""
|
16
|
+
error_msg = str(exception)
|
17
|
+
logger.error(f"Telegram bot error: {error_msg}")
|
18
|
+
|
19
|
+
try:
|
20
|
+
# Attempt recovery based on error type
|
21
|
+
if "webhook" in error_msg.lower():
|
22
|
+
if hasattr(bot, 'remove_webhook'):
|
23
|
+
bot.remove_webhook()
|
24
|
+
logger.info("Removed webhook due to error")
|
25
|
+
elif "connection" in error_msg.lower():
|
26
|
+
# Wait and retry for connection issues
|
27
|
+
time.sleep(5)
|
28
|
+
return True # Indicates retry
|
29
|
+
except Exception as e:
|
30
|
+
logger.error(f"Error during recovery attempt: {str(e)}")
|
31
|
+
|
32
|
+
return False # Don't retry for unknown errors
|
15
33
|
|
16
34
|
|
17
35
|
bot = telebot.TeleBot("1:2", parse_mode="HTML", threaded=False, exception_handler=ExceptionHandler())
|
@@ -1,3 +1,5 @@
|
|
1
|
+
import asyncio
|
2
|
+
import time
|
1
3
|
from flask import current_app as app, request
|
2
4
|
from flask import g
|
3
5
|
from flask.views import MethodView
|
@@ -16,7 +18,9 @@ class UpdateUserUsageApi(MethodView):
|
|
16
18
|
|
17
19
|
def get(self):
|
18
20
|
"""System: Update User Usage"""
|
19
|
-
|
21
|
+
# time.sleep(5)
|
22
|
+
|
23
|
+
return json.dumps(usage.update_local_usage_not_lock(), indent=2)
|
20
24
|
|
21
25
|
|
22
26
|
class AllConfigsApi(MethodView):
|
@@ -6,7 +6,8 @@ from hiddifypanel.auth import login_required
|
|
6
6
|
from hiddifypanel.models import *
|
7
7
|
from hiddifypanel.panel import hiddify
|
8
8
|
from hiddifypanel.drivers import user_driver
|
9
|
-
|
9
|
+
|
10
|
+
|
10
11
|
|
11
12
|
from . import has_permission
|
12
13
|
from .schema import UserSchema, PostUserSchema, PatchUserSchema, SuccessfulSchema
|
@@ -108,31 +108,35 @@ class AppAPI(MethodView):
|
|
108
108
|
apps_data = self.__get_all_apps_dto()
|
109
109
|
case Platform.android:
|
110
110
|
hiddify_next_dto = self.__get_hiddify_next_app_dto()
|
111
|
+
singbox_dto = self.__get_singbox_app_dto()
|
111
112
|
hiddifyng_dto = self.__get_hiddifyng_app_dto()
|
112
113
|
v2rayng_dto = self.__get_v2rayng_app_dto()
|
113
114
|
hiddify_clash_android_dto = self.__get_hiddify_clash_android_app_dto()
|
114
115
|
nekobox_dto = self.__get_nekobox_app_dto()
|
115
|
-
apps_data += ([hiddify_next_dto,
|
116
|
+
apps_data += ([hiddify_next_dto, singbox_dto, v2rayng_dto, nekobox_dto, hiddifyng_dto, hiddify_clash_android_dto])
|
116
117
|
case Platform.windows:
|
117
118
|
hiddify_next_dto = self.__get_hiddify_next_app_dto()
|
118
119
|
hiddify_clash_dto = self.__get_hiddify_clash_desktop_app_dto()
|
119
120
|
hiddifyn_dto = self.__get_hiddifyn_app_dto()
|
120
121
|
apps_data += ([hiddify_next_dto, hiddify_clash_dto, hiddifyn_dto])
|
121
122
|
case Platform.ios:
|
123
|
+
hiddify_next_dto = self.__get_hiddify_next_app_dto()
|
124
|
+
singbox_dto = self.__get_singbox_app_dto()
|
122
125
|
stash_dto = self.__get_stash_app_dto()
|
123
126
|
shadowrocket_dto = self.__get_shadowrocket_app_dto()
|
124
127
|
foxray_dto = self.__get_foxray_app_dto()
|
125
128
|
streisand_dto = self.__get_streisand_app_dto()
|
126
129
|
loon_dto = self.__get_loon_app_dto()
|
127
|
-
apps_data += ([streisand_dto, stash_dto, shadowrocket_dto, foxray_dto, loon_dto])
|
130
|
+
apps_data += ([hiddify_next_dto, singbox_dto, streisand_dto, stash_dto, shadowrocket_dto, foxray_dto, loon_dto])
|
128
131
|
case Platform.linux:
|
129
132
|
hiddify_next_dto = self.__get_hiddify_next_app_dto()
|
130
133
|
hiddify_clash_dto = self.__get_hiddify_clash_desktop_app_dto()
|
131
134
|
apps_data += ([hiddify_next_dto, hiddify_clash_dto,])
|
132
135
|
case Platform.mac:
|
136
|
+
singbox_dto = self.__get_singbox_app_dto()
|
133
137
|
hiddify_clash_dto = self.__get_hiddify_clash_desktop_app_dto()
|
134
138
|
hiddify_next_dto = self.__get_hiddify_next_app_dto()
|
135
|
-
apps_data += ([hiddify_next_dto, hiddify_clash_dto])
|
139
|
+
apps_data += ([hiddify_next_dto, singbox_dto, hiddify_clash_dto])
|
136
140
|
|
137
141
|
return apps_data
|
138
142
|
|
@@ -162,11 +166,12 @@ class AppAPI(MethodView):
|
|
162
166
|
loon_app_dto = self.__get_loon_app_dto()
|
163
167
|
stash_app_dto = self.__get_stash_app_dto()
|
164
168
|
hiddify_clash_app_dto = self.__get_hiddify_clash_desktop_app_dto()
|
169
|
+
singbox_app_dto = self.__get_singbox_app_dto()
|
165
170
|
hiddify_next_app_dto = self.__get_hiddify_next_app_dto()
|
166
171
|
return [
|
167
172
|
hiddifyn_app_dto, v2rayng_app_dto, hiddifyng_app_dto, hiddify_android_app_dto,
|
168
173
|
foxray_app_dto, shadowrocket_app_dto, streisand_app_dto,
|
169
|
-
loon_app_dto, stash_app_dto, hiddify_clash_app_dto, hiddify_next_app_dto
|
174
|
+
loon_app_dto, stash_app_dto, hiddify_clash_app_dto, singbox_app_dto, hiddify_next_app_dto
|
170
175
|
]
|
171
176
|
|
172
177
|
def __get_app_icon_url(self, app_name):
|
@@ -174,6 +179,8 @@ class AppAPI(MethodView):
|
|
174
179
|
url = ''
|
175
180
|
if app_name == _('app.hiddify.next.title'):
|
176
181
|
url = base + static_url_for(filename='apps-icon/hiddify_next.ico')
|
182
|
+
elif app_name == _('app.singbox.title'):
|
183
|
+
url = base + static_url_for(filename='apps-icon/singbox.ico')
|
177
184
|
elif app_name == _('app.hiddifyn.title'):
|
178
185
|
url = base + static_url_for(filename='apps-icon/hiddifyn.ico')
|
179
186
|
elif app_name == _('app.v2rayng.title'):
|
@@ -241,7 +248,7 @@ class AppAPI(MethodView):
|
|
241
248
|
|
242
249
|
# make v2rayng latest version url download
|
243
250
|
latest_url, version = get_latest_release_url(f'https://github.com/2dust/v2rayNG/')
|
244
|
-
github_ins_url = latest_url.split('releases/')[0] + f'releases/download/{version}/v2rayNG_{version}.apk'
|
251
|
+
github_ins_url = latest_url.split('releases/')[0] + f'releases/download/{version}/v2rayNG_{version}_universal.apk'
|
245
252
|
google_play_ins_url = 'https://play.google.com/store/apps/details?id=com.v2ray.ang'
|
246
253
|
dto.install = [self.__get_app_install_dto(AppInstallType.apk, github_ins_url), self.__get_app_install_dto(AppInstallType.google_play, google_play_ins_url)]
|
247
254
|
return dto
|
@@ -367,6 +374,65 @@ class AppAPI(MethodView):
|
|
367
374
|
|
368
375
|
return dto
|
369
376
|
|
377
|
+
def __get_singbox_app_dto(self):
|
378
|
+
dto = AppSchema()
|
379
|
+
dto.title = _('app.singbox.title')
|
380
|
+
dto.description = _('app.singbox.description')
|
381
|
+
dto.icon_url = self.__get_app_icon_url(_('app.singbox.title'))
|
382
|
+
dto.guide_url = ''
|
383
|
+
dto.deeplink = f'sing-box://import-remote-profile/?url={self.user_panel_url}'
|
384
|
+
|
385
|
+
# availabe installatoin types
|
386
|
+
installation_types = []
|
387
|
+
if self.platform == Platform.all:
|
388
|
+
installation_types = [AppInstallType.apk, AppInstallType.google_play, AppInstallType.dmg, AppInstallType.app_store]
|
389
|
+
else:
|
390
|
+
match self.platform:
|
391
|
+
case Platform.android:
|
392
|
+
installation_types = [AppInstallType.apk, AppInstallType.google_play]
|
393
|
+
case Platform.mac:
|
394
|
+
installation_types = [AppInstallType.dmg]
|
395
|
+
case Platform.ios:
|
396
|
+
installation_types = [AppInstallType.app_store]
|
397
|
+
|
398
|
+
install_dtos = []
|
399
|
+
for install_type in installation_types:
|
400
|
+
install_dto = AppInstall()
|
401
|
+
ins_url = ''
|
402
|
+
match install_type:
|
403
|
+
case AppInstallType.apk:
|
404
|
+
latest_url, version = get_latest_release_url(f'https://github.com/SagerNet/sing-box')
|
405
|
+
ins_url = latest_url.split('releases/')[0] + f'releases/download/{version}/SFA-{version}-universal.apk'
|
406
|
+
def remove_v_from_filename(url):
|
407
|
+
parts = url.split('/')
|
408
|
+
filename = parts[-1]
|
409
|
+
new_filename = filename.replace('SFA-v', 'SFA-')
|
410
|
+
parts[-1] = new_filename
|
411
|
+
new_url = '/'.join(parts)
|
412
|
+
return new_url
|
413
|
+
ins_url = remove_v_from_filename(ins_url)
|
414
|
+
case AppInstallType.google_play:
|
415
|
+
ins_url = 'https://play.google.com/store/apps/details?id=io.nekohasekai.sfa'
|
416
|
+
case AppInstallType.dmg:
|
417
|
+
latest_url, version = get_latest_release_url(f'https://github.com/SagerNet/sing-box')
|
418
|
+
ins_url = latest_url.split('releases/')[0] + f'releases/download/{version}/SFM-{version}-universal.dmg'
|
419
|
+
def remove_v_from_filename(url):
|
420
|
+
parts = url.split('/')
|
421
|
+
filename = parts[-1]
|
422
|
+
new_filename = filename.replace('SFM-v', 'SFM-')
|
423
|
+
parts[-1] = new_filename
|
424
|
+
new_url = '/'.join(parts)
|
425
|
+
return new_url
|
426
|
+
ins_url = remove_v_from_filename(ins_url)
|
427
|
+
case AppInstallType.app_store:
|
428
|
+
ins_url = 'https://apps.apple.com/us/app/sing-box-vt/id6673731168'
|
429
|
+
|
430
|
+
install_dto = self.__get_app_install_dto(install_type, ins_url)
|
431
|
+
install_dtos.append(install_dto)
|
432
|
+
|
433
|
+
dto.install = install_dtos
|
434
|
+
return dto
|
435
|
+
|
370
436
|
def __get_hiddify_next_app_dto(self):
|
371
437
|
dto = AppSchema()
|
372
438
|
dto.title = _('app.hiddify.next.title')
|
@@ -378,7 +444,7 @@ class AppAPI(MethodView):
|
|
378
444
|
# availabe installatoin types
|
379
445
|
installation_types = []
|
380
446
|
if self.platform == Platform.all:
|
381
|
-
installation_types = [AppInstallType.apk, AppInstallType.google_play, AppInstallType.setup, AppInstallType.portable, AppInstallType.appimage, AppInstallType.dmg]
|
447
|
+
installation_types = [AppInstallType.apk, AppInstallType.google_play, AppInstallType.setup, AppInstallType.portable, AppInstallType.appimage, AppInstallType.dmg, AppInstallType.app_store]
|
382
448
|
else:
|
383
449
|
match self.platform:
|
384
450
|
case Platform.android:
|
@@ -389,6 +455,8 @@ class AppAPI(MethodView):
|
|
389
455
|
installation_types = [AppInstallType.appimage]
|
390
456
|
case Platform.mac:
|
391
457
|
installation_types = [AppInstallType.dmg]
|
458
|
+
case Platform.ios:
|
459
|
+
installation_types = [AppInstallType.app_store]
|
392
460
|
|
393
461
|
install_dtos = []
|
394
462
|
for install_type in installation_types:
|
@@ -407,6 +475,8 @@ class AppAPI(MethodView):
|
|
407
475
|
ins_url = f'{self.hiddify_github_repo}/hiddify-next/releases/latest/download/Hiddify-Linux-x64.AppImage'
|
408
476
|
case AppInstallType.dmg:
|
409
477
|
ins_url = f'{self.hiddify_github_repo}/hiddify-next/releases/latest/download/Hiddify-MacOS.dmg'
|
478
|
+
case AppInstallType.app_store:
|
479
|
+
ins_url = 'https://apps.apple.com/us/app/hiddify-proxy-vpn/id6596777532'
|
410
480
|
|
411
481
|
install_dto = self.__get_app_install_dto(install_type, ins_url)
|
412
482
|
install_dtos.append(install_dto)
|
hiddifypanel/panel/common.py
CHANGED
@@ -22,6 +22,9 @@ def init_app(app: APIFlask):
|
|
22
22
|
app.jinja_env.globals['hutils'] = hutils
|
23
23
|
app.jinja_env.globals['hiddify'] = hiddify
|
24
24
|
app.jinja_env.globals['version'] = hiddifypanel.__version__
|
25
|
+
if not hiddifypanel.is_released_version:
|
26
|
+
app.jinja_env.globals['version']= "DEV"
|
27
|
+
|
25
28
|
app.jinja_env.globals['static_url_for'] = hutils.flask.static_url_for
|
26
29
|
app.jinja_env.globals['hurl_for'] = hutils.flask.hurl_for
|
27
30
|
app.jinja_env.globals['_gettext'] = lambda x: print("==========", x)
|
@@ -40,9 +43,9 @@ def init_app(app: APIFlask):
|
|
40
43
|
logger.exception(e)
|
41
44
|
if isinstance(e, Exception):
|
42
45
|
if hutils.flask.is_api_call(request.path):
|
43
|
-
return {
|
46
|
+
return jsonify({
|
44
47
|
'msg': str(e),
|
45
|
-
}, 500
|
48
|
+
}), 500
|
46
49
|
|
47
50
|
if hasattr(e, 'code') and e.code == 404:
|
48
51
|
return jsonify({
|
@@ -11,6 +11,7 @@ from hiddifypanel.models import *
|
|
11
11
|
|
12
12
|
from flask_wtf import FlaskForm
|
13
13
|
import wtforms as wtf
|
14
|
+
|
14
15
|
import re
|
15
16
|
|
16
17
|
|
@@ -22,7 +23,10 @@ class LoginForm(FlaskForm):
|
|
22
23
|
'pattern': "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
|
23
24
|
'message': _('config.invalid_uuid')
|
24
25
|
})
|
25
|
-
|
26
|
+
|
27
|
+
password_textbox = wtf.fields.PasswordField(_(f'login.password.label'), default='',
|
28
|
+
description=_(f'login.password.description'), render_kw={ })
|
29
|
+
submit = wtf.fields.SubmitField(_('login.button'))
|
26
30
|
|
27
31
|
|
28
32
|
class LoginView(FlaskView):
|
@@ -33,8 +37,9 @@ class LoginView(FlaskView):
|
|
33
37
|
redirect_arg = request.args.get('redirect')
|
34
38
|
username_arg = request.args.get('user') or ''
|
35
39
|
if not current_account:
|
36
|
-
|
37
|
-
|
40
|
+
form=LoginForm()
|
41
|
+
form.secret_textbox.data=form.secret_textbox.data or username_arg
|
42
|
+
return render_template('login.html', form=form)
|
38
43
|
|
39
44
|
# abort(401, "Unauthorized1")
|
40
45
|
|
@@ -52,9 +57,9 @@ class LoginView(FlaskView):
|
|
52
57
|
form = LoginForm()
|
53
58
|
if form.validate_on_submit():
|
54
59
|
uuid = form.secret_textbox.data.strip()
|
55
|
-
if login_by_uuid(uuid, hutils.flask.is_admin_proxy_path()):
|
60
|
+
if login_by_uuid(uuid,form.password_textbox.data, hutils.flask.is_admin_proxy_path()):
|
56
61
|
return redirect(f'/{g.proxy_path}/')
|
57
|
-
hutils.flask.flash(_('config.
|
62
|
+
hutils.flask.flash(_('config.invalid_uuid'), 'danger') # type: ignore
|
58
63
|
return render_template('login.html', form=LoginForm())
|
59
64
|
|
60
65
|
@ route("/l/<path:path>/")
|
@@ -68,7 +73,7 @@ class LoginView(FlaskView):
|
|
68
73
|
redirect_arg = request.args.get('next')
|
69
74
|
|
70
75
|
if not current_account or (not request.headers.get('Authorization')):
|
71
|
-
username = request.authorization.username if request.authorization else
|
76
|
+
username = request.authorization.username if request.authorization else g.uuid
|
72
77
|
|
73
78
|
loginurl = hurl_for('common_bp.LoginView:index', next=redirect_arg, user=username)
|
74
79
|
if g.user_agent['is_browser'] and request.headers.get('Authorization') or (current_account and len(username) > 0 and current_account.username != username):
|
@@ -128,7 +133,8 @@ class LoginView(FlaskView):
|
|
128
133
|
@ route('/<secret_uuid>/manifest.webmanifest')
|
129
134
|
def create_pwa_manifest(self):
|
130
135
|
domain = request.host
|
131
|
-
|
136
|
+
account=AdminUser.by_uuid(g.uuid)
|
137
|
+
name = (domain if hutils.flask.is_admin_panel_call() else account.name)
|
132
138
|
return jsonify({
|
133
139
|
"name": f"Hiddify {name}",
|
134
140
|
"short_name": f"{name}"[:12],
|
@@ -136,7 +142,7 @@ class LoginView(FlaskView):
|
|
136
142
|
"background_color": "#1a1b21",
|
137
143
|
"display": "standalone",
|
138
144
|
"scope": f"/",
|
139
|
-
"start_url": hiddify.get_account_panel_link(
|
145
|
+
"start_url": hiddify.get_account_panel_link(account, domain) + "?pwa=true",
|
140
146
|
"description": "Hiddify, for a free Internet",
|
141
147
|
"orientation": "any",
|
142
148
|
"icons": [
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import sys
|
2
|
+
from loguru import logger
|
3
|
+
|
4
|
+
def logger_dynamic_formatter(record) -> str:
|
5
|
+
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>'
|
6
|
+
if record['extra']:
|
7
|
+
fmt += ' | <level>{extra}</level>'
|
8
|
+
return fmt + '\n'
|
9
|
+
|
10
|
+
def init_app(app):
|
11
|
+
init_logger(app,False)
|
12
|
+
|
13
|
+
def init_cli(app):
|
14
|
+
init_logger(app,True)
|
15
|
+
|
16
|
+
|
17
|
+
def init_logger(app, cli):
|
18
|
+
# configure logger
|
19
|
+
|
20
|
+
logger.remove()
|
21
|
+
logger.add(sys.stderr if cli else sys.stdout, format=logger_dynamic_formatter, level=app.config['STDOUT_LOG_LEVEL'],
|
22
|
+
colorize=True, catch=True, enqueue=True, diagnose=False, backtrace=True)
|
23
|
+
logger.trace('Logger initiated :)')
|
24
|
+
|
25
|
+
with app.app_context():
|
26
|
+
from hiddifypanel.models.config import hconfig,ConfigEnum
|
27
|
+
set_level(app,hconfig(ConfigEnum.log_level))
|
28
|
+
|
29
|
+
|
30
|
+
def set_level(app, level):
|
31
|
+
logger.add(app.config['HIDDIFY_CONFIG_PATH'] + "/log/system/panel.log", format=logger_dynamic_formatter, level=level,
|
32
|
+
colorize=True, catch=True, enqueue=True, diagnose=False, backtrace=True)
|