hiddifypanel 10.20.3__py3-none-any.whl → 10.30.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +2 -2
- hiddifypanel/base.py +17 -8
- hiddifypanel/cache.py +2 -51
- hiddifypanel/drivers/wireguard_api.py +24 -5
- hiddifypanel/hutils/convert.py +1 -1
- hiddifypanel/hutils/flask.py +28 -2
- hiddifypanel/hutils/importer/xui.py +6 -7
- hiddifypanel/hutils/network/__init__.py +1 -0
- hiddifypanel/hutils/network/cf_api.py +84 -0
- hiddifypanel/hutils/network/net.py +26 -49
- hiddifypanel/hutils/node/child.py +25 -7
- hiddifypanel/hutils/node/parent.py +7 -7
- hiddifypanel/hutils/node/shared.py +19 -6
- hiddifypanel/hutils/proxy/clash.py +1 -1
- hiddifypanel/hutils/proxy/shared.py +1 -1
- hiddifypanel/hutils/proxy/singbox.py +2 -3
- hiddifypanel/hutils/proxy/xray.py +12 -10
- hiddifypanel/hutils/proxy/xrayjson.py +26 -49
- hiddifypanel/hutils/utils.py +47 -3
- hiddifypanel/models/__init__.py +1 -1
- hiddifypanel/models/admin.py +9 -2
- hiddifypanel/models/base_account.py +3 -1
- hiddifypanel/models/config.py +5 -7
- hiddifypanel/models/config_enum.py +18 -6
- hiddifypanel/models/domain.py +82 -118
- hiddifypanel/models/user.py +44 -24
- hiddifypanel/panel/admin/Actions.py +6 -11
- hiddifypanel/panel/admin/AdminstratorAdmin.py +3 -9
- hiddifypanel/panel/admin/Backup.py +5 -8
- hiddifypanel/panel/admin/Dashboard.py +3 -4
- hiddifypanel/panel/admin/DomainAdmin.py +20 -15
- hiddifypanel/panel/admin/ProxyAdmin.py +3 -10
- hiddifypanel/panel/admin/QuickSetup.py +1 -1
- hiddifypanel/panel/admin/SettingAdmin.py +7 -5
- hiddifypanel/panel/admin/Terminal.py +0 -1
- hiddifypanel/panel/admin/UserAdmin.py +4 -3
- hiddifypanel/panel/cli.py +36 -23
- hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +2 -4
- hiddifypanel/panel/commercial/restapi/v1/tgbot.py +7 -4
- hiddifypanel/panel/commercial/restapi/v2/admin/__init__.py +17 -13
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_info_api.py +4 -3
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_user_api.py +28 -10
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_users_api.py +2 -19
- hiddifypanel/panel/commercial/restapi/v2/admin/schema.py +27 -4
- hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +28 -9
- hiddifypanel/panel/commercial/restapi/v2/admin/users_api.py +1 -21
- hiddifypanel/panel/commercial/restapi/v2/parent/register_api.py +1 -1
- hiddifypanel/panel/commercial/restapi/v2/parent/schema.py +8 -4
- hiddifypanel/panel/commercial/restapi/v2/parent/sync_api.py +19 -3
- hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +48 -42
- hiddifypanel/panel/commercial/telegrambot/Usage.py +1 -1
- hiddifypanel/panel/commercial/telegrambot/admin.py +1 -1
- hiddifypanel/panel/commercial/telegrambot/information.py +1 -1
- hiddifypanel/panel/common.py +5 -11
- hiddifypanel/panel/hiddify.py +9 -20
- hiddifypanel/panel/init_db.py +31 -13
- hiddifypanel/panel/usage.py +38 -9
- hiddifypanel/panel/user/user.py +52 -32
- hiddifypanel/templates/admin-layout.html +2 -2
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +80 -25
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +74 -20
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +60 -6
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +158 -78
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +60 -6
- hiddifypanel/translations.i18n/en.json +62 -22
- hiddifypanel/translations.i18n/fa.json +57 -17
- hiddifypanel/translations.i18n/pt.json +43 -3
- hiddifypanel/translations.i18n/ru.json +112 -72
- hiddifypanel/translations.i18n/zh.json +43 -3
- {hiddifypanel-10.20.3.dist-info → hiddifypanel-10.30.0.dev0.dist-info}/METADATA +2 -1
- {hiddifypanel-10.20.3.dist-info → hiddifypanel-10.30.0.dev0.dist-info}/RECORD +81 -81
- {hiddifypanel-10.20.3.dist-info → hiddifypanel-10.30.0.dev0.dist-info}/WHEEL +1 -1
- hiddifypanel/panel/cf_api.py +0 -37
- {hiddifypanel-10.20.3.dist-info → hiddifypanel-10.30.0.dev0.dist-info}/LICENSE.md +0 -0
- {hiddifypanel-10.20.3.dist-info → hiddifypanel-10.30.0.dev0.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-10.20.3.dist-info → hiddifypanel-10.30.0.dev0.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,6 @@ import json
|
|
3
3
|
|
4
4
|
from hiddifypanel import hutils
|
5
5
|
from hiddifypanel.models import ProxyProto, ProxyTransport, Domain, ConfigEnum
|
6
|
-
from hiddifypanel.panel.hiddify import is_hiddify_next_version
|
7
6
|
|
8
7
|
|
9
8
|
def configs_as_json(domains: list[Domain], **kwargs) -> str:
|
@@ -125,7 +124,7 @@ def add_multiplex(base: dict, proxy: dict):
|
|
125
124
|
base['multiplex']['max_connections'] = proxy.get('mux_max_connections', 0)
|
126
125
|
base['multiplex']['min_streams'] = proxy.get('mux_min_streams', 0)
|
127
126
|
|
128
|
-
add_tcp_brutal(base,proxy)
|
127
|
+
add_tcp_brutal(base, proxy)
|
129
128
|
|
130
129
|
|
131
130
|
def add_tcp_brutal(base: dict, proxy: dict):
|
@@ -252,7 +251,7 @@ def add_wireguard(base: dict, proxy: dict):
|
|
252
251
|
base["pre_shared_key"] = proxy["wg_psk"]
|
253
252
|
|
254
253
|
base["mtu"] = 1380
|
255
|
-
if g.user_agent.get('is_hiddify') and
|
254
|
+
if g.user_agent.get('is_hiddify') and hutils.flask.is_client_version(hutils.flask.ClientVersion.hiddify_next, 0, 15, 0):
|
256
255
|
base["fake_packets"] = proxy["wg_noise_trick"]
|
257
256
|
|
258
257
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import datetime
|
2
2
|
import json
|
3
|
-
import
|
4
|
-
from flask import render_template, request, g
|
3
|
+
from flask import request, g
|
5
4
|
from hiddifypanel import hutils
|
6
5
|
from hiddifypanel.models import ProxyTransport, ProxyL3, ProxyProto, Domain, User, ConfigEnum, hconfig
|
7
6
|
from flask_babel import gettext as _
|
@@ -73,15 +72,18 @@ def to_link(proxy: dict) -> str | dict:
|
|
73
72
|
baseurl = f'ssr://{proxy["cipher"]}:{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}'
|
74
73
|
return baseurl
|
75
74
|
if proxy['proto'] in ['ss', 'v2ray']:
|
76
|
-
baseurl = f'ss://{proxy["cipher"]
|
77
|
-
|
78
|
-
return f'{baseurl}?plugin=obfs-local%3Bobfs%3Dtls%3Bobfs-host%3D{proxy["fakedomain"]}%3Budp-over-tcp=true#{name_link}'
|
79
|
-
# if proxy['mode'] == 'shadowtls':
|
80
|
-
# return f'{baseurl}?plugin=shadow-tls%3Bpassword%3D{proxy["proxy_path"]}%3Bhost%3D{proxy["fakedomain"]}%3Budp-over-tcp=true#{name_link}'
|
81
|
-
if proxy['proto'] == 'v2ray':
|
82
|
-
return f'{baseurl}?plugin=v2ray-plugin%3Bmode%3Dwebsocket%3Bpath%3D{proxy["path"]}%3Bhost%3D{proxy["host"]}%3Btls%3Budp-over-tcp=true#{name_link}'
|
75
|
+
baseurl = f'ss://{hutils.encode.do_base_64(proxy["cipher"] + ":" + proxy["password"])}@{proxy["server"]}:{proxy["port"]}'
|
76
|
+
|
83
77
|
if proxy['transport'] == 'shadowsocks':
|
84
|
-
return baseurl
|
78
|
+
return f'{baseurl}#{name_link}'
|
79
|
+
if proxy['transport'] == 'faketls':
|
80
|
+
return f'{baseurl}?plugin=obfs-local&obfs-host={proxy["fakedomain"]}&obfs=http&udp-over-tcp=true#{name_link}'
|
81
|
+
if proxy['transport'] == 'shadowtls':
|
82
|
+
return "ShadowTLS is Not Supported for this platform"
|
83
|
+
# return f'{baseurl}?plugin=v2ray-plugin&path={proxy["proxy_path"]}&host={proxy["fakedomain"]}&udp-over-tcp=true#{name_link}'
|
84
|
+
if proxy['proto'] == 'v2ray':
|
85
|
+
return f'{baseurl}?plugin=v2ray-plugin&mode=websocket&path={proxy["proxy_path"]}&host={proxy["fakedomain"]}&tls&udp-over-tcp=true#{name_link}'
|
86
|
+
|
85
87
|
if proxy['proto'] == 'tuic':
|
86
88
|
baseurl = f'tuic://{proxy["uuid"]}:{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}?congestion_control=cubic&udp_relay_mode=native&sni={proxy["sni"]}&alpn=h3'
|
87
89
|
if proxy['mode'] == 'Fake' or proxy['allow_insecure']:
|
@@ -5,14 +5,14 @@ from hiddifypanel import hutils
|
|
5
5
|
from hiddifypanel.models import ProxyTransport, ProxyL3, ProxyProto, Domain, User
|
6
6
|
from flask_babel import gettext as _
|
7
7
|
from hiddifypanel.models import hconfig, ConfigEnum
|
8
|
-
from .xray import is_muxable_agent
|
9
|
-
OUTBOUND_LEVEL = 8
|
8
|
+
from .xray import is_muxable_agent, OUTBOUND_LEVEL
|
10
9
|
|
11
10
|
|
12
11
|
def configs_as_json(domains: list[Domain], user: User, expire_days: int, remarks: str) -> str:
|
13
12
|
'''Returns xray configs as json'''
|
14
|
-
|
15
13
|
all_configs = []
|
14
|
+
|
15
|
+
# region show usage
|
16
16
|
if hconfig(ConfigEnum.show_usage_in_sublink) and not g.user_agent.get('is_hiddify'):
|
17
17
|
# determine usages
|
18
18
|
tag = '⏳ ' if user.is_active else '✖ '
|
@@ -33,7 +33,9 @@ def configs_as_json(domains: list[Domain], user: User, expire_days: int, remark
|
|
33
33
|
all_configs.append(
|
34
34
|
null_config(tag)
|
35
35
|
)
|
36
|
+
# endregion
|
36
37
|
|
38
|
+
# region show status (active/disable)
|
37
39
|
active = True
|
38
40
|
if not user.is_active:
|
39
41
|
tag = '✖ ' + (hutils.encode.url_encode('بسته شما به پایان رسید') if hconfig(ConfigEnum.lang) == 'fa' else 'Package Ended')
|
@@ -42,13 +44,18 @@ def configs_as_json(domains: list[Domain], user: User, expire_days: int, remark
|
|
42
44
|
null_config(tag)
|
43
45
|
)
|
44
46
|
active = False
|
47
|
+
# endregion
|
45
48
|
|
46
49
|
if active:
|
50
|
+
# TODO: seperate codes to small functions
|
47
51
|
# TODO: check what are unsupported protocols in other apps
|
48
|
-
unsupported_protos =
|
52
|
+
unsupported_protos = []
|
53
|
+
unsupported_transport = []
|
49
54
|
if g.user_agent.get('is_v2rayng'):
|
50
55
|
# TODO: ensure which protocols are not supported in v2rayng
|
51
|
-
unsupported_protos =
|
56
|
+
unsupported_protos = [ProxyProto.wireguard, ProxyProto.hysteria, ProxyProto.hysteria2, ProxyProto.tuic, ProxyProto.ss, ProxyProto.ssr, ProxyProto.ssh]
|
57
|
+
if not hutils.flask.is_client_version(hutils.flask.ClientVersion.v2ryang, 1, 8, 18):
|
58
|
+
unsupported_transport = [ProxyTransport.httpupgrade]
|
52
59
|
|
53
60
|
# multiple outbounds needs multiple whole base config not just one with multiple outbounds (at least for v2rayng)
|
54
61
|
# https://github.com/2dust/v2rayNG/pull/2827#issue-2127534078
|
@@ -56,6 +63,8 @@ def configs_as_json(domains: list[Domain], user: User, expire_days: int, remark
|
|
56
63
|
for proxy in hutils.proxy.get_valid_proxies(domains):
|
57
64
|
if unsupported_protos and proxy['proto'] in unsupported_protos:
|
58
65
|
continue
|
66
|
+
if unsupported_transport and proxy['transport'] in unsupported_transport:
|
67
|
+
continue
|
59
68
|
outbound = to_xray(proxy)
|
60
69
|
if 'msg' not in outbound:
|
61
70
|
outbounds.append(outbound)
|
@@ -76,6 +85,7 @@ def configs_as_json(domains: list[Domain], user: User, expire_days: int, remark
|
|
76
85
|
|
77
86
|
if not all_configs:
|
78
87
|
return ''
|
88
|
+
|
79
89
|
json_configs = json.dumps(all_configs, indent=2, cls=hutils.proxy.ProxyJsonEncoder)
|
80
90
|
return json_configs
|
81
91
|
|
@@ -91,6 +101,7 @@ def to_xray(proxy: dict) -> dict:
|
|
91
101
|
'concurrency': -1
|
92
102
|
}
|
93
103
|
}
|
104
|
+
outbound['protocol'] = 'shadowsocks' if outbound['protocol'] == 'ss' else outbound['protocol']
|
94
105
|
# add multiplex to outbound
|
95
106
|
add_multiplex(outbound, proxy)
|
96
107
|
|
@@ -211,7 +222,11 @@ def add_stream_settings(base: dict, proxy: dict):
|
|
211
222
|
ss['security'] = 'tls'
|
212
223
|
|
213
224
|
# network and transport settings
|
214
|
-
|
225
|
+
# THE CURRENT CODE WORKS BUT THE CORRECT CONDITINO SHOULD BE THIS:
|
226
|
+
# ss['security'] == 'tls' or 'xtls' -----> ss['security'] in ['tls','xtls']
|
227
|
+
# TODO: FIX THE CONDITION AND TEST CONFIGS ON THE CLIENT SIDE
|
228
|
+
|
229
|
+
if ss['security'] == 'tls' or 'xtls' and proxy['proto'] != ProxyProto.ss:
|
215
230
|
ss['tlsSettings'] = {
|
216
231
|
'serverName': proxy['sni'],
|
217
232
|
'allowInsecure': proxy['allow_insecure'],
|
@@ -236,7 +251,7 @@ def add_stream_settings(base: dict, proxy: dict):
|
|
236
251
|
if proxy['l3'] == ProxyL3.h3_quic:
|
237
252
|
add_quic_stream(ss, proxy)
|
238
253
|
|
239
|
-
if proxy['transport'] == 'tcp' or ss['security'] == 'reality' or (ss['security'] == 'none' and proxy['transport'] not in [ProxyTransport.httpupgrade, ProxyTransport.WS]):
|
254
|
+
if proxy['transport'] == 'tcp' or ss['security'] == 'reality' or (ss['security'] == 'none' and proxy['transport'] not in [ProxyTransport.httpupgrade, ProxyTransport.WS] and proxy['proto'] != ProxyProto.ss):
|
240
255
|
ss['network'] = proxy['transport']
|
241
256
|
add_tcp_stream(ss, proxy)
|
242
257
|
if proxy['transport'] == ProxyTransport.h2 and ss['security'] == 'none' and ss['security'] != 'reality':
|
@@ -252,6 +267,9 @@ def add_stream_settings(base: dict, proxy: dict):
|
|
252
267
|
ss['network'] = proxy['transport']
|
253
268
|
add_ws_stream(ss, proxy)
|
254
269
|
|
270
|
+
if proxy['proto'] == ProxyProto.ss:
|
271
|
+
ss['network'] = 'tcp'
|
272
|
+
|
255
273
|
# tls fragmentaion
|
256
274
|
add_tls_fragmentation_stream_settings(base, proxy)
|
257
275
|
|
@@ -379,7 +397,7 @@ def add_tls_fragmentation_stream_settings(base: dict, proxy: dict):
|
|
379
397
|
|
380
398
|
|
381
399
|
def add_multiplex(base: dict, proxy: dict):
|
382
|
-
if proxy.get('mux_enable') != "xray":
|
400
|
+
if proxy.get('mux_enable') != "xray" or not is_muxable_agent(proxy):
|
383
401
|
return
|
384
402
|
|
385
403
|
concurrency = proxy['mux_max_connections']
|
@@ -390,47 +408,6 @@ def add_multiplex(base: dict, proxy: dict):
|
|
390
408
|
base['mux']['xudpProxyUDP443'] = 'reject'
|
391
409
|
|
392
410
|
|
393
|
-
def add_tls_tricks_to_dict(d: dict, proxy: dict):
|
394
|
-
if proxy.get('tls_fragment_enable'):
|
395
|
-
if g.user_agent.get('is_shadowrocket'):
|
396
|
-
d['fragment'] = f'1,{proxy["tls_fragment_size"]},{proxy["tls_fragment_sleep"]}'
|
397
|
-
else:
|
398
|
-
d['fragment'] = f'{proxy["tls_fragment_size"]},{proxy["tls_fragment_sleep"]},tlshello'
|
399
|
-
|
400
|
-
if proxy.get("tls_mixed_case"):
|
401
|
-
d['mc'] = 1
|
402
|
-
if proxy.get("tls_padding_enable"):
|
403
|
-
d['padsize'] = proxy["tls_padding_length"]
|
404
|
-
|
405
|
-
|
406
|
-
def add_mux_to_dict(d: dict, proxy):
|
407
|
-
if not is_muxable_agent(proxy):
|
408
|
-
return
|
409
|
-
|
410
|
-
# according to github.com/hiddify/ray2sing/
|
411
|
-
d['muxtype'] = proxy["mux_protocol"]
|
412
|
-
d['muxmaxc'] = proxy["mux_max_connections"]
|
413
|
-
d['mux'] = proxy['mux_min_streams']
|
414
|
-
d['muxsmax'] = proxy["mux_max_streams"]
|
415
|
-
d['muxpad'] = proxy["mux_padding_enable"]
|
416
|
-
|
417
|
-
if proxy.get('mux_brutal_enable'):
|
418
|
-
d['muxup'] = proxy["mux_brutal_up_mbps"]
|
419
|
-
d['muxdown'] = proxy["mux_brutal_down_mbps"]
|
420
|
-
|
421
|
-
|
422
|
-
def add_tls_tricks_to_link(proxy: dict) -> str:
|
423
|
-
out = {}
|
424
|
-
add_tls_tricks_to_dict(out, proxy)
|
425
|
-
return hutils.encode.convert_dict_to_url(out)
|
426
|
-
|
427
|
-
|
428
|
-
def add_mux_to_link(proxy: dict) -> str:
|
429
|
-
out = {}
|
430
|
-
add_mux_to_dict(out, proxy)
|
431
|
-
return hutils.encode.convert_dict_to_url(out)
|
432
|
-
|
433
|
-
|
434
411
|
def null_config(tag: str) -> dict:
|
435
412
|
base_config = json.loads(render_template('base_xray_config.json.j2', remarks=tag))
|
436
413
|
return base_config
|
hiddifypanel/hutils/utils.py
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
from flask_babel import lazy_gettext as _
|
2
2
|
import requests
|
3
|
-
|
3
|
+
from packaging.version import Version
|
4
4
|
import re
|
5
5
|
import sys
|
6
6
|
|
7
|
+
from hiddifypanel.models.config import hconfig, ConfigEnum
|
8
|
+
from hiddifypanel import __version__ as current_version
|
7
9
|
from hiddifypanel.cache import cache
|
8
10
|
|
9
11
|
|
@@ -35,7 +37,49 @@ def get_latest_release_version(repo_name):
|
|
35
37
|
if ver == "latest":
|
36
38
|
return get_latest_release_version(repo_name.replace("-", ""))
|
37
39
|
return ver
|
38
|
-
except Exception
|
39
|
-
return
|
40
|
+
except Exception:
|
41
|
+
return None
|
40
42
|
|
41
43
|
return None
|
44
|
+
|
45
|
+
|
46
|
+
def is_panel_outdated() -> bool:
|
47
|
+
# TODO: handle beta and develop version too
|
48
|
+
pm = hconfig(ConfigEnum.package_mode)
|
49
|
+
try:
|
50
|
+
if pm == 'release':
|
51
|
+
if latest_v := get_latest_release_version('hiddifypanel'):
|
52
|
+
if compare_versions(latest_v, current_version) == 1:
|
53
|
+
return True
|
54
|
+
except:
|
55
|
+
pass
|
56
|
+
return False
|
57
|
+
|
58
|
+
|
59
|
+
def compare_versions(version_1: str, version_2: str) -> int:
|
60
|
+
"""
|
61
|
+
Compare two version strings and return an integer based on their relative order.
|
62
|
+
Returns:
|
63
|
+
int:
|
64
|
+
|
65
|
+
- 1 if version_1 is greater than version_2.
|
66
|
+
- 0 if version_1 is equal to version_2.
|
67
|
+
- -1 if version_1 is less than version_2.
|
68
|
+
|
69
|
+
Examples:
|
70
|
+
>>> compare_versions("10.20.4", "10.20.4")
|
71
|
+
0
|
72
|
+
>>> compare_versions("10.20.4", "10.20.2")
|
73
|
+
1
|
74
|
+
>>> compare_versions("10.20.2", "10.20.4")
|
75
|
+
-1
|
76
|
+
"""
|
77
|
+
v1 = Version(version_1)
|
78
|
+
v2 = Version(version_2)
|
79
|
+
|
80
|
+
if v1 > v2:
|
81
|
+
return 1 # version_1 is greater
|
82
|
+
elif v2 > v1:
|
83
|
+
return -1 # version_2 is greater
|
84
|
+
else:
|
85
|
+
return 0 # versions are equal
|
hiddifypanel/models/__init__.py
CHANGED
@@ -4,7 +4,7 @@ from .config_enum import ConfigCategory, ConfigEnum, Lang, ApplyMode, PanelMode,
|
|
4
4
|
from .config import StrConfig, BoolConfig, get_hconfigs, hconfig, set_hconfig, add_or_update_config, bulk_register_configs, get_hconfigs_childs
|
5
5
|
|
6
6
|
# from .parent_domain import ParentDomain
|
7
|
-
from .domain import Domain, DomainType, ShowDomain
|
7
|
+
from .domain import Domain, DomainType, ShowDomain
|
8
8
|
from .proxy import Proxy, ProxyL3, ProxyCDN, ProxyProto, ProxyTransport
|
9
9
|
from .user import User, UserMode, UserDetail, ONE_GIG
|
10
10
|
from .admin import AdminUser, AdminMode
|
hiddifypanel/models/admin.py
CHANGED
@@ -67,16 +67,21 @@ class AdminUser(BaseAccount, SerializerMixin):
|
|
67
67
|
base = super().to_dict()
|
68
68
|
if dump_id:
|
69
69
|
base['id'] = self.id
|
70
|
-
|
70
|
+
if not base.get('lang'):
|
71
|
+
from hiddifypanel.models import hconfig, ConfigEnum
|
72
|
+
base['lang'] = hconfig(ConfigEnum.admin_lang)
|
71
73
|
return {**base,
|
72
74
|
'mode': self.mode,
|
73
75
|
'can_add_admin': self.can_add_admin,
|
74
76
|
'parent_admin_uuid': self.parent_admin.uuid if self.parent_admin else None,
|
75
|
-
'
|
77
|
+
'max_users': self.max_users,
|
78
|
+
'max_active_users': self.max_active_users,
|
76
79
|
}
|
77
80
|
|
78
81
|
@classmethod
|
79
82
|
def by_uuid(cls, uuid: str, create: bool = False) -> BaseAccount | None:
|
83
|
+
if not isinstance(uuid, str):
|
84
|
+
uuid = str(uuid)
|
80
85
|
account = AdminUser.query.filter(AdminUser.uuid == uuid).first()
|
81
86
|
if not account and create:
|
82
87
|
dbuser = AdminUser(uuid=uuid, name="unknown", parent_admin_id=AdminUser.current_admin_or_owner().id)
|
@@ -101,6 +106,8 @@ class AdminUser(BaseAccount, SerializerMixin):
|
|
101
106
|
|
102
107
|
dbuser.mode = data.get('mode', AdminMode.agent)
|
103
108
|
dbuser.can_add_admin = data.get('can_add_admin') or False
|
109
|
+
dbuser.max_users = data.get('max_users', 100)
|
110
|
+
dbuser.max_active_users = data.get('max_active_users', 100)
|
104
111
|
if commit:
|
105
112
|
db.session.commit()
|
106
113
|
return dbuser
|
@@ -49,6 +49,8 @@ class BaseAccount(db.Model, SerializerMixin, FlaskLoginUserMixin): # type: igno
|
|
49
49
|
|
50
50
|
@classmethod
|
51
51
|
def by_uuid(cls, uuid: str, create: bool = False):
|
52
|
+
if not isinstance(uuid, str):
|
53
|
+
uuid = str(uuid)
|
52
54
|
account = cls.query.filter(cls.uuid == uuid).first()
|
53
55
|
if not account and create:
|
54
56
|
raise NotImplementedError
|
@@ -60,10 +62,10 @@ class BaseAccount(db.Model, SerializerMixin, FlaskLoginUserMixin): # type: igno
|
|
60
62
|
|
61
63
|
@classmethod
|
62
64
|
def add_or_update(cls, commit: bool = True, **data):
|
63
|
-
from hiddifypanel import hutils
|
64
65
|
db_account = cls.by_uuid(data['uuid'], create=True)
|
65
66
|
db_account.name = data.get('name', '')
|
66
67
|
db_account.comment = data.get('comment', '')
|
68
|
+
from hiddifypanel import hutils
|
67
69
|
db_account.telegram_id = hutils.convert.to_int(data.get('telegram_id'))
|
68
70
|
db_account.lang = data.get('lang')
|
69
71
|
if commit:
|
hiddifypanel/models/config.py
CHANGED
@@ -45,11 +45,11 @@ class StrConfig(db.Model, SerializerMixin):
|
|
45
45
|
key = Column(Enum(ConfigEnum), primary_key=True, default=ConfigEnum.admin_secret)
|
46
46
|
value = Column(String(2048))
|
47
47
|
|
48
|
-
def to_dict(
|
48
|
+
def to_dict(self: "StrConfig"):
|
49
49
|
return {
|
50
|
-
'key': str(
|
51
|
-
'value':
|
52
|
-
'child_unique_id':
|
50
|
+
'key': str(self.key),
|
51
|
+
'value': self.value,
|
52
|
+
'child_unique_id': self.child.unique_id if self.child else ''
|
53
53
|
}
|
54
54
|
|
55
55
|
@staticmethod
|
@@ -119,6 +119,7 @@ def set_hconfig(key: ConfigEnum, value: str | int | bool, child_id: int | None =
|
|
119
119
|
else:
|
120
120
|
old_v = dbconf.value
|
121
121
|
else:
|
122
|
+
value = str(value)
|
122
123
|
dbconf = StrConfig.query.filter(StrConfig.key == key, StrConfig.child_id == child_id).first()
|
123
124
|
if not dbconf:
|
124
125
|
dbconf = StrConfig(key=key, value=value, child_id=child_id)
|
@@ -144,9 +145,6 @@ def get_hconfigs(child_id: int | None = None, json=False) -> dict:
|
|
144
145
|
|
145
146
|
return {**{f'{u.key}' if json else u.key: u.value for u in BoolConfig.query.filter(BoolConfig.child_id == child_id).all() if u.key.type == bool},
|
146
147
|
**{f'{u.key}' if json else u.key: int(u.value) if u.key.type == int and u.value != None else u.value for u in StrConfig.query.filter(StrConfig.child_id == child_id).all() if u.key.type != bool},
|
147
|
-
# ConfigEnum.telegram_fakedomain:hdomain(DomainType.telegram_faketls),
|
148
|
-
# ConfigEnum.ssfaketls_fakedomain:hdomain(DomainType.ss_faketls),
|
149
|
-
# ConfigEnum.fake_cdn_domain:hdomain(DomainType.fake_cdn)
|
150
148
|
}
|
151
149
|
|
152
150
|
|
@@ -69,19 +69,19 @@ class ApplyMode(StrEnum):
|
|
69
69
|
nothing = auto()
|
70
70
|
|
71
71
|
|
72
|
-
def _BoolConfigDscr(category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False):
|
72
|
+
def _BoolConfigDscr(category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False) -> "ConfigEnum":
|
73
73
|
return category, apply_mode, bool, show_in_parent
|
74
74
|
|
75
75
|
|
76
|
-
def _StrConfigDscr(category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False):
|
76
|
+
def _StrConfigDscr(category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False) -> "ConfigEnum":
|
77
77
|
return category, apply_mode, str, show_in_parent
|
78
78
|
|
79
79
|
|
80
|
-
def _IntConfigDscr(category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False):
|
80
|
+
def _IntConfigDscr(category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False) -> "ConfigEnum":
|
81
81
|
return category, apply_mode, int, show_in_parent
|
82
82
|
|
83
83
|
|
84
|
-
def _TypedConfigDscr(ctype: type, category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False):
|
84
|
+
def _TypedConfigDscr(ctype: type, category: ConfigCategory, apply_mode: ApplyMode = ApplyMode.nothing, show_in_parent: bool = True, hide_in_virtual_child=False) -> "ConfigEnum":
|
85
85
|
return category, apply_mode, ctype, show_in_parent
|
86
86
|
|
87
87
|
|
@@ -116,7 +116,7 @@ class ConfigEnum(metaclass=FastEnum):
|
|
116
116
|
first_setup = _BoolConfigDscr(ConfigCategory.hidden)
|
117
117
|
core_type = _StrConfigDscr(ConfigCategory.advanced, ApplyMode.apply, hide_in_virtual_child=True)
|
118
118
|
warp_enable = _BoolConfigDscr(ConfigCategory.hidden, ApplyMode.restart, hide_in_virtual_child=True)
|
119
|
-
warp_mode = _StrConfigDscr(ConfigCategory.warp, ApplyMode.
|
119
|
+
warp_mode = _StrConfigDscr(ConfigCategory.warp, ApplyMode.restart, hide_in_virtual_child=True)
|
120
120
|
warp_plus_code = _StrConfigDscr(ConfigCategory.warp, ApplyMode.apply, hide_in_virtual_child=True)
|
121
121
|
warp_sites = _StrConfigDscr(ConfigCategory.warp, ApplyMode.apply, hide_in_virtual_child=True)
|
122
122
|
dns_server = _StrConfigDscr(ConfigCategory.general, ApplyMode.apply, hide_in_virtual_child=True)
|
@@ -222,7 +222,7 @@ class ConfigEnum(metaclass=FastEnum):
|
|
222
222
|
shadowsocks2022_enable = _BoolConfigDscr(ConfigCategory.shadowsocks, ApplyMode.apply)
|
223
223
|
shadowsocks2022_method = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
|
224
224
|
shadowsocks2022_port = _StrConfigDscr(ConfigCategory.shadowsocks, ApplyMode.apply)
|
225
|
-
ssfaketls_enable = _BoolConfigDscr(ConfigCategory.shadowsocks, ApplyMode.
|
225
|
+
ssfaketls_enable = _BoolConfigDscr(ConfigCategory.shadowsocks, ApplyMode.restart)
|
226
226
|
ssfaketls_fakedomain = _StrConfigDscr(ConfigCategory.shadowsocks, ApplyMode.apply, hide_in_virtual_child=True)
|
227
227
|
shadowtls_enable = _BoolConfigDscr(ConfigCategory.shadowsocks, ApplyMode.apply)
|
228
228
|
shadowtls_fakedomain = _StrConfigDscr(ConfigCategory.shadowsocks, ApplyMode.apply, hide_in_virtual_child=True)
|
@@ -248,6 +248,7 @@ class ConfigEnum(metaclass=FastEnum):
|
|
248
248
|
h2_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
|
249
249
|
|
250
250
|
db_version = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
|
251
|
+
last_priodic_usage_check = _IntConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
|
251
252
|
|
252
253
|
branding_title = _StrConfigDscr(ConfigCategory.branding)
|
253
254
|
branding_site = _StrConfigDscr(ConfigCategory.branding)
|
@@ -264,6 +265,17 @@ class ConfigEnum(metaclass=FastEnum):
|
|
264
265
|
path_tcp = _StrConfigDscr(ConfigCategory.too_advanced, hide_in_virtual_child=True)
|
265
266
|
path_grpc = _StrConfigDscr(ConfigCategory.too_advanced, hide_in_virtual_child=True)
|
266
267
|
|
268
|
+
# subs
|
269
|
+
sub_full_singbox_enable = _BoolConfigDscr(ConfigCategory.hidden)
|
270
|
+
sub_singbox_ssh_enable = _BoolConfigDscr(ConfigCategory.hidden)
|
271
|
+
sub_full_xray_json_enable = _BoolConfigDscr(ConfigCategory.proxies)
|
272
|
+
sub_full_links_enable = _BoolConfigDscr(ConfigCategory.hidden)
|
273
|
+
sub_full_links_b64_enable = _BoolConfigDscr(ConfigCategory.hidden)
|
274
|
+
sub_full_clash_enable = _BoolConfigDscr(ConfigCategory.hidden)
|
275
|
+
sub_full_clash_meta_enable = _BoolConfigDscr(ConfigCategory.hidden)
|
276
|
+
|
277
|
+
hiddifycli_enable = _BoolConfigDscr(ConfigCategory.hidden, ApplyMode.restart)
|
278
|
+
|
267
279
|
@classmethod
|
268
280
|
def __missing__(cls, value):
|
269
281
|
return ConfigEnum.not_found
|