hiddifypanel 10.80.0.dev13__py3-none-any.whl → 10.80.0.dev14__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 +1 -1
- hiddifypanel/hutils/proxy/clash.py +2 -2
- hiddifypanel/hutils/proxy/shared.py +6 -6
- hiddifypanel/hutils/proxy/singbox.py +1 -1
- hiddifypanel/hutils/proxy/xray.py +2 -2
- hiddifypanel/hutils/proxy/xrayjson.py +4 -4
- hiddifypanel/models/config_enum.py +2 -2
- hiddifypanel/models/proxy.py +1 -1
- hiddifypanel/panel/admin/AdminstratorAdmin.py +7 -8
- hiddifypanel/panel/admin/DomainAdmin.py +131 -98
- hiddifypanel/panel/admin/QuickSetup.py +7 -7
- hiddifypanel/panel/admin/UserAdmin.py +58 -33
- hiddifypanel/panel/admin/templates/index.html +6 -4
- hiddifypanel/panel/admin/templates/model/user_list.html +11 -3
- hiddifypanel/panel/commercial/restapi/v1/tgbot.py +19 -1
- hiddifypanel/panel/init_db.py +19 -16
- hiddifypanel/translations.i18n/fr.json +2 -2
- hiddifypanel/translations.i18n/my.json +2 -2
- {hiddifypanel-10.80.0.dev13.dist-info → hiddifypanel-10.80.0.dev14.dist-info}/METADATA +1 -1
- {hiddifypanel-10.80.0.dev13.dist-info → hiddifypanel-10.80.0.dev14.dist-info}/RECORD +24 -24
- {hiddifypanel-10.80.0.dev13.dist-info → hiddifypanel-10.80.0.dev14.dist-info}/LICENSE.md +0 -0
- {hiddifypanel-10.80.0.dev13.dist-info → hiddifypanel-10.80.0.dev14.dist-info}/WHEEL +0 -0
- {hiddifypanel-10.80.0.dev13.dist-info → hiddifypanel-10.80.0.dev14.dist-info}/entry_points.txt +0 -0
hiddifypanel/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
10.80.0.
|
1
|
+
10.80.0.dev14
|
hiddifypanel/VERSION.py
CHANGED
@@ -2,5 +2,5 @@ import importlib.metadata
|
|
2
2
|
from datetime import datetime
|
3
3
|
|
4
4
|
__version__ = importlib.metadata.version(__package__ or __name__)
|
5
|
-
__release_time__= datetime.strptime('2024-11-
|
5
|
+
__release_time__= datetime.strptime('2024-11-18T03:24:43','%Y-%m-%dT%H:%M:%S')
|
6
6
|
is_released_version=True
|
@@ -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'}
|
@@ -134,8 +134,8 @@ def get_proxies(child_id: int = 0, only_enabled=False) -> list['Proxy']:
|
|
134
134
|
proxies = [c for c in proxies if 'trojan' not in c.proto]
|
135
135
|
if not hconfig(ConfigEnum.httpupgrade_enable, child_id):
|
136
136
|
proxies = [c for c in proxies if ProxyTransport.httpupgrade not in c.transport]
|
137
|
-
if not hconfig(ConfigEnum.
|
138
|
-
proxies = [c for c in proxies if ProxyTransport.
|
137
|
+
if not hconfig(ConfigEnum.xhttp_enable, child_id):
|
138
|
+
proxies = [c for c in proxies if ProxyTransport.xhttp not in c.transport]
|
139
139
|
if not hconfig(ConfigEnum.ws_enable, child_id):
|
140
140
|
proxies = [c for c in proxies if ProxyTransport.WS not in c.transport]
|
141
141
|
# if not hconfig(ConfigEnum.xtls_enable, child_id):
|
@@ -189,7 +189,7 @@ def get_valid_proxies(domains: list[Domain]) -> list[dict]:
|
|
189
189
|
noDomainProxies = False
|
190
190
|
if proxy.proto in [ProxyProto.ssh, ProxyProto.wireguard]:
|
191
191
|
noDomainProxies = True
|
192
|
-
if proxy.proto in [ProxyProto.ss] and proxy.transport not in [ProxyTransport.grpc, ProxyTransport.h2, ProxyTransport.WS, ProxyTransport.httpupgrade, ProxyTransport.
|
192
|
+
if proxy.proto in [ProxyProto.ss] and proxy.transport not in [ProxyTransport.grpc, ProxyTransport.h2, ProxyTransport.WS, ProxyTransport.httpupgrade, ProxyTransport.xhttp]:
|
193
193
|
noDomainProxies = True
|
194
194
|
options = []
|
195
195
|
key = f'{proxy.proto}{proxy.transport}{proxy.cdn}{proxy.l3}'
|
@@ -413,9 +413,9 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
413
413
|
base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_httpupgrade]}'
|
414
414
|
base["host"] = domain
|
415
415
|
return base
|
416
|
-
if proxy.transport in [ProxyTransport.
|
417
|
-
base['transport'] = '
|
418
|
-
base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.
|
416
|
+
if proxy.transport in [ProxyTransport.xhttp]:
|
417
|
+
base['transport'] = 'xhttp'
|
418
|
+
base['path'] = f'/{path[base["proto"]]}{hconfigs[ConfigEnum.path_xhttp]}'
|
419
419
|
# if 0 and 'h2' in base['alpn'] or 'h3' in base['alpn']:
|
420
420
|
# base['path'] += "2"
|
421
421
|
# else:
|
@@ -47,7 +47,7 @@ def configs_as_json(domains: list[Domain], **kwargs) -> str:
|
|
47
47
|
def is_xray_proxy(proxy: dict):
|
48
48
|
if g.user_agent.get('is_hiddify_prefere_xray'):
|
49
49
|
return True
|
50
|
-
if proxy['transport'] == ProxyTransport.
|
50
|
+
if proxy['transport'] == ProxyTransport.xhttp:
|
51
51
|
return True
|
52
52
|
return False
|
53
53
|
|
@@ -126,10 +126,10 @@ def to_link(proxy: dict) -> str | dict:
|
|
126
126
|
baseurl += "&encryption=none"
|
127
127
|
if proxy.get('fingerprint', 'none') != 'none':
|
128
128
|
baseurl += "&fp=" + proxy['fingerprint']
|
129
|
-
if proxy.get('transport') in {ProxyTransport.
|
129
|
+
if proxy.get('transport') in {ProxyTransport.xhttp}:
|
130
130
|
baseurl += "&core=xray"
|
131
131
|
if proxy['l3'] != 'quic':
|
132
|
-
if proxy.get('l3') != ProxyL3.reality and (proxy.get('transport') in {ProxyTransport.tcp, ProxyTransport.httpupgrade, ProxyTransport.
|
132
|
+
if proxy.get('l3') != ProxyL3.reality and (proxy.get('transport') in {ProxyTransport.tcp, ProxyTransport.httpupgrade, ProxyTransport.xhttp}) and proxy['proto'] in [ProxyProto.vless, ProxyProto.trojan]:
|
133
133
|
baseurl += '&headerType=http'
|
134
134
|
else:
|
135
135
|
baseurl += '&headerType=None'
|
@@ -262,9 +262,9 @@ def add_stream_settings(base: dict, proxy: dict):
|
|
262
262
|
if proxy['transport'] == ProxyTransport.httpupgrade:
|
263
263
|
ss['network'] = proxy['transport']
|
264
264
|
add_httpupgrade_stream(ss, proxy)
|
265
|
-
if proxy['transport'] == ProxyTransport.
|
265
|
+
if proxy['transport'] == ProxyTransport.xhttp:
|
266
266
|
ss['network'] = proxy['transport']
|
267
|
-
|
267
|
+
add_xhttp_stream(ss, proxy)
|
268
268
|
if proxy['transport'] == 'ws':
|
269
269
|
ss['network'] = proxy['transport']
|
270
270
|
add_ws_stream(ss, proxy)
|
@@ -338,8 +338,8 @@ def add_httpupgrade_stream(ss: dict, proxy: dict):
|
|
338
338
|
}
|
339
339
|
|
340
340
|
|
341
|
-
def
|
342
|
-
ss['
|
341
|
+
def add_xhttp_stream(ss: dict, proxy: dict):
|
342
|
+
ss['xhttpSettings'] = {
|
343
343
|
'path': proxy['path'],
|
344
344
|
'host': proxy['host'],
|
345
345
|
"headers": {
|
@@ -239,7 +239,7 @@ class ConfigEnum(metaclass=FastEnum):
|
|
239
239
|
ws_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply_config)
|
240
240
|
grpc_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply_config)
|
241
241
|
httpupgrade_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply_config)
|
242
|
-
|
242
|
+
xhttp_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply_config)
|
243
243
|
|
244
244
|
vless_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply_config)
|
245
245
|
trojan_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply_config)
|
@@ -262,7 +262,7 @@ class ConfigEnum(metaclass=FastEnum):
|
|
262
262
|
path_v2ray = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply_config, hide_in_virtual_child=True) # deprecated
|
263
263
|
path_ss = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply_config, hide_in_virtual_child=True)
|
264
264
|
|
265
|
-
|
265
|
+
path_xhttp = _StrConfigDscr(ConfigCategory.too_advanced, ApplyMode.apply_config, hide_in_virtual_child=True)
|
266
266
|
path_httpupgrade = _StrConfigDscr(ConfigCategory.too_advanced, ApplyMode.apply_config, hide_in_virtual_child=True)
|
267
267
|
path_ws = _StrConfigDscr(ConfigCategory.too_advanced, ApplyMode.apply_config, hide_in_virtual_child=True)
|
268
268
|
path_tcp = _StrConfigDscr(ConfigCategory.too_advanced, ApplyMode.apply_config, hide_in_virtual_child=True)
|
hiddifypanel/models/proxy.py
CHANGED
@@ -143,19 +143,18 @@ class AdminstratorAdmin(AdminLTEModelView):
|
|
143
143
|
""")
|
144
144
|
|
145
145
|
def _max_active_users_formatter(view, context, model, name):
|
146
|
-
|
147
|
-
|
148
|
-
u = len(actives)
|
146
|
+
"""Optimized user count formatter using database queries"""
|
147
|
+
active_count = model.recursive_users_query().filter(User.is_active == True).count()
|
149
148
|
if model.mode == AdminMode.super_admin:
|
150
|
-
return f"{
|
149
|
+
return f"{active_count} / ∞"
|
151
150
|
t = model.max_active_users
|
152
|
-
rate = round(
|
153
|
-
|
154
|
-
|
151
|
+
rate = round(active_count * 100 / (t + 0.000001))
|
152
|
+
color = "#ff7e7e" if active_count >= t else ('#ffc107' if rate > 80 else '#9ee150')
|
153
|
+
|
155
154
|
return Markup(f"""
|
156
155
|
<div class="progress progress-lg position-relative" style="min-width: 100px;">
|
157
156
|
<div class="progress-bar progress-bar-striped" role="progressbar" style="width: {rate}%;background-color: {color};" aria-valuenow="{rate}" aria-valuemin="0" aria-valuemax="100"></div>
|
158
|
-
<span class='badge position-absolute' style="left:auto;right:auto;width: 100%;font-size:1em">{
|
157
|
+
<span class='badge position-absolute' style="left:auto;right:auto;width: 100%;font-size:1em">{active_count} {_('user.home.usage.from')} {t}</span>
|
159
158
|
|
160
159
|
</div>
|
161
160
|
""")
|
@@ -16,6 +16,7 @@ from hiddifypanel.panel import hiddify, custom_widgets
|
|
16
16
|
from .adminlte import AdminLTEModelView
|
17
17
|
from hiddifypanel import hutils
|
18
18
|
|
19
|
+
from loguru import logger
|
19
20
|
from flask import current_app
|
20
21
|
# Define a custom field type for the related domains
|
21
22
|
|
@@ -152,132 +153,164 @@ class DomainAdmin(AdminLTEModelView):
|
|
152
153
|
|
153
154
|
# TODO: refactor this function
|
154
155
|
def on_model_change(self, form, model, is_created):
|
155
|
-
|
156
|
+
# Sanitize domain input
|
157
|
+
model.domain = (model.domain or '').lower().strip()
|
158
|
+
|
159
|
+
# Basic validation
|
156
160
|
if model.domain == '' and model.mode != DomainType.fake:
|
157
161
|
raise ValidationError(_("domain.empty.allowed_for_fake_only"))
|
158
|
-
configs = get_hconfigs()
|
159
|
-
for c in configs:
|
160
|
-
if "domain" in c and c not in [ConfigEnum.decoy_domain, ConfigEnum.reality_fallback_domain] and c.category != 'hidden':
|
161
|
-
if model.domain == configs[c]:
|
162
|
-
raise ValidationError(_("You have used this domain in: ") + _(f"config.{c}.label"))
|
163
|
-
|
164
|
-
for td in Domain.query.filter(Domain.mode == DomainType.reality, Domain.domain != model.domain).all():
|
165
|
-
# print(td)
|
166
|
-
if td.servernames and (model.domain in td.servernames.split(",")):
|
167
|
-
raise ValidationError(_("You have used this domain in: ") + _(f"config.reality_server_names.label") + td.domain)
|
168
|
-
|
169
|
-
if is_created and Domain.query.filter(Domain.domain == model.domain, Domain.child_id == model.child_id).count() > 1:
|
170
|
-
raise ValidationError(_("You have used this domain in: "))
|
171
162
|
|
163
|
+
self._validate_not_used_before(model,is_created)
|
172
164
|
ipv4_list = hutils.network.get_ips(4)
|
173
165
|
ipv6_list = hutils.network.get_ips(6)
|
166
|
+
server_ips = [*ipv4_list, *ipv6_list]
|
174
167
|
|
175
|
-
if not
|
168
|
+
if not server_ips:
|
176
169
|
raise ValidationError(_("Couldn't find your ip addresses"))
|
177
170
|
|
171
|
+
# Validate domain based on mode
|
178
172
|
if "*" in model.domain and model.mode not in [DomainType.cdn, DomainType.auto_cdn_ip]:
|
179
173
|
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain"))
|
180
174
|
|
181
|
-
|
175
|
+
cloudflare_updated=self._update_cloudflare(model, ipv4_list,ipv6_list)
|
176
|
+
|
177
|
+
if not (cloudflare_updated or "*" in model.domain or model.domain == ""):
|
178
|
+
self._validate_domain_ips(model, server_ips)
|
179
|
+
|
180
|
+
# Handle CDN IP settings
|
181
|
+
if model.mode == DomainType.direct and model.cdn_ip:
|
182
|
+
model.cdn_ip = ""
|
183
|
+
raise ValidationError(_("Specifying CDN IP is only valid for CDN mode"))
|
184
|
+
|
185
|
+
if model.mode == DomainType.fake and not model.cdn_ip:
|
186
|
+
model.cdn_ip = str(server_ips[0])
|
187
|
+
|
188
|
+
if model.cdn_ip:
|
189
|
+
try:
|
190
|
+
hutils.network.auto_ip_selector.get_clean_ip(str(model.cdn_ip))
|
191
|
+
except Exception:
|
192
|
+
raise ValidationError(_("Error in auto cdn format"))
|
193
|
+
|
194
|
+
# Update show domains
|
195
|
+
if len(model.show_domains) == Domain.query.count():
|
196
|
+
model.show_domains = []
|
197
|
+
|
198
|
+
# Handle mode-specific settings
|
199
|
+
if model.mode == DomainType.old_xtls_direct and not hconfig(ConfigEnum.xtls_enable):
|
200
|
+
set_hconfig(ConfigEnum.xtls_enable, True)
|
201
|
+
hutils.proxy.get_proxies().invalidate_all()
|
202
|
+
elif model.mode == DomainType.reality:
|
203
|
+
self._validate_reality_settings(model, server_ips)
|
204
|
+
|
205
|
+
# Signal config update if needed
|
206
|
+
old_db_domain = Domain.by_domain(model.domain)
|
207
|
+
if is_created or not old_db_domain or old_db_domain.mode != model.mode:
|
208
|
+
# return hiddify.reinstall_action(complete_install=False, domain_changed=True)
|
209
|
+
hutils.flask.flash_config_success(restart_mode=ApplyMode.apply_config, domain_changed=True)
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
def _update_cloudflare(self, model, ipv4_list,ipv6_list):
|
182
214
|
if hconfig(ConfigEnum.cloudflare) and model.mode not in [DomainType.fake, DomainType.relay, DomainType.reality]:
|
183
215
|
try:
|
184
216
|
proxied = model.mode in [DomainType.cdn, DomainType.auto_cdn_ip]
|
185
|
-
|
217
|
+
if ipv4_list:
|
218
|
+
hutils.network.cf_api.add_or_update_dns_record(model.domain, str(ipv4_list[0]), "A", proxied=proxied)
|
186
219
|
if ipv6_list:
|
187
220
|
hutils.network.cf_api.add_or_update_dns_record(model.domain, str(ipv6_list[0]), "AAAA", proxied=proxied)
|
188
|
-
|
189
|
-
skip_check = True
|
221
|
+
return True
|
190
222
|
except Exception as e:
|
191
223
|
raise ValidationError(__("cloudflare.error") + f' {e}')
|
192
|
-
|
193
|
-
# if model.alias and not model.alias.replace("_", "").isalnum():
|
194
|
-
# hutils.flask.flash(__("Using alias with special charachters may cause problem in some clients like FairVPN."), 'warning')
|
195
|
-
# raise ValidationError(_("You have to add your cloudflare api key to use this feature: "))
|
224
|
+
return False
|
196
225
|
|
197
|
-
|
198
|
-
|
199
|
-
if
|
200
|
-
|
201
|
-
|
202
|
-
elif not skip_check:
|
203
|
-
if not dips:
|
204
|
-
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain")) # type: ignore
|
205
|
-
|
206
|
-
domain_ip_is_same_as_panel = False
|
207
|
-
|
208
|
-
for mip in server_ips:
|
209
|
-
domain_ip_is_same_as_panel |= mip in dips
|
210
|
-
server_ips_str = ', '.join(list(map(str, server_ips)))
|
211
|
-
dips_str = ', '.join(list(map(str, dips)))
|
212
|
-
|
213
|
-
if model.mode == DomainType.direct and not domain_ip_is_same_as_panel:
|
214
|
-
# hutils.flask.flash(__(f"Domain IP={dip} is not matched with your ip={', '.join(list(map(str, ipv4_list)))} which is required in direct mode"),category='error')
|
215
|
-
raise ValidationError(
|
216
|
-
__("Domain IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode", server_ip=server_ips_str, domain_ip=dips_str)) # type: ignore
|
217
|
-
|
218
|
-
if domain_ip_is_same_as_panel and model.mode in [DomainType.cdn, DomainType.relay, DomainType.fake, DomainType.auto_cdn_ip]:
|
219
|
-
# # hutils.flask.flash(__(f"In CDN mode, Domain IP={dip} should be different to your ip={', '.join(list(map(str, ipv4_list)))}"), 'warning')
|
220
|
-
raise ValidationError(__("In CDN mode, Domain IP=%(domain_ip)s should be different to your ip=%(server_ip)s",
|
221
|
-
server_ip=server_ips_str, domain_ip=dips_str)) # type: ignore
|
222
|
-
|
223
|
-
# if model.mode in [DomainType.ss_faketls, DomainType.telegram_faketls]:
|
224
|
-
# if len(Domain.query.filter(Domain.mode==model.mode and Domain.id!=model.id).all())>0:
|
225
|
-
# ValidationError(f"another {model.mode} is exist")
|
226
|
-
|
227
|
-
model.domain = model.domain.lower()
|
228
|
-
if model.mode == DomainType.direct and model.cdn_ip:
|
229
|
-
model.cdn_ip = ""
|
230
|
-
raise ValidationError(f"Specifying CDN IP is only valid for CDN mode")
|
226
|
+
def _validate_reality_settings(self, model, server_ips):
|
227
|
+
"""Validate REALITY protocol settings with proper error handling"""
|
228
|
+
if not hconfig(ConfigEnum.reality_enable):
|
229
|
+
set_hconfig(ConfigEnum.reality_enable, True)
|
230
|
+
hutils.proxy.get_proxies().invalidate_all()
|
231
231
|
|
232
|
-
|
233
|
-
|
232
|
+
model.servernames = (model.servernames or model.domain).lower().strip()
|
233
|
+
domains_to_check = set()
|
234
|
+
for v in [model.domain, model.servernames]:
|
235
|
+
domains_to_check.update(d.strip() for d in v.split(",") if d.strip())
|
234
236
|
|
235
|
-
|
236
|
-
|
237
|
+
for d in domains_to_check:
|
238
|
+
# Check REALITY compatibility
|
239
|
+
if not hutils.network.is_domain_reality_friendly(d):
|
240
|
+
raise ValidationError(_("Domain is not REALITY friendly!") + f' {d}')
|
237
241
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
set_hconfig(ConfigEnum.xtls_enable, True)
|
244
|
-
hutils.proxy.get_proxies().invalidate_all()
|
245
|
-
elif model.mode == DomainType.reality:
|
246
|
-
if not hconfig(ConfigEnum.reality_enable):
|
247
|
-
set_hconfig(ConfigEnum.reality_enable, True)
|
248
|
-
hutils.proxy.get_proxies().invalidate_all()
|
249
|
-
model.servernames = (model.servernames or model.domain).lower()
|
250
|
-
for v in set([model.domain, model.servernames]):
|
251
|
-
for d in v.split(","):
|
252
|
-
if not d:
|
253
|
-
continue
|
254
|
-
if not hutils.network.is_domain_reality_friendly(d): # the minimum requirement for the REALITY protocol is to have tls1.3 and h2
|
255
|
-
raise ValidationError(_("Domain is not REALITY friendly!") + f' {d}')
|
256
|
-
|
257
|
-
if not hutils.network.is_in_same_asn(d, server_ips[0]):
|
258
|
-
dip = next(iter(dips))
|
242
|
+
try:
|
243
|
+
if not hutils.network.is_in_same_asn(d, server_ips[0]):
|
244
|
+
domain_ips = hutils.network.get_domain_ips(d)
|
245
|
+
if domain_ips:
|
246
|
+
dip = next(iter(domain_ips))
|
259
247
|
server_asn = hutils.network.get_ip_asn(server_ips[0])
|
260
|
-
domain_asn = hutils.network.get_ip_asn(dip)
|
261
|
-
msg = _("domain.reality.asn_issue")
|
262
|
-
|
248
|
+
domain_asn = hutils.network.get_ip_asn(dip)
|
249
|
+
msg = _("domain.reality.asn_issue")
|
250
|
+
if server_asn or domain_asn:
|
251
|
+
msg += f"<br> Server ASN={server_asn}<br>{d}_ASN={domain_asn}"
|
263
252
|
hutils.flask.flash(msg, 'warning')
|
253
|
+
except Exception as e:
|
254
|
+
logger.warning(f"ASN check failed for domain {d}: {str(e)}")
|
264
255
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
256
|
+
# Check fallback compatibility
|
257
|
+
for d in model.servernames.split(","):
|
258
|
+
if d.strip() and not hutils.network.fallback_domain_compatible_with_servernames(model.domain, d):
|
259
|
+
msg = _("REALITY Fallback domain is not compatible with server names!") + f' {d} != {model.domain}'
|
260
|
+
hutils.flask.flash(msg, 'warning')
|
269
261
|
|
270
|
-
if (model.cdn_ip):
|
271
|
-
try:
|
272
|
-
hutils.network.auto_ip_selector.get_clean_ip(str(model.cdn_ip))
|
273
|
-
except BaseException:
|
274
|
-
raise ValidationError(_("Error in auto cdn format"))
|
275
262
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
263
|
+
def _validate_not_used_before(self, model,is_created):
|
264
|
+
configs = get_hconfigs()
|
265
|
+
for c in configs:
|
266
|
+
if "domain" in c and c not in [ConfigEnum.decoy_domain, ConfigEnum.reality_fallback_domain] and c.category != 'hidden':
|
267
|
+
if model.domain == configs[c]:
|
268
|
+
raise ValidationError(_("You have used this domain in: ") + _(f"config.{c}.label"))
|
269
|
+
|
270
|
+
for td in Domain.query.filter(Domain.mode == DomainType.reality, Domain.domain != model.domain).all():
|
271
|
+
# print(td)
|
272
|
+
if td.servernames and (model.domain in td.servernames.split(",")):
|
273
|
+
raise ValidationError(_("You have used this domain in: ") + _(f"config.reality_server_names.label") + td.domain)
|
280
274
|
|
275
|
+
if is_created and Domain.query.filter(Domain.domain == model.domain, Domain.child_id == model.child_id).count() > 1:
|
276
|
+
raise ValidationError(_("You have used this domain in: "))
|
277
|
+
|
278
|
+
def _validate_domain_ips(self, model, server_ips):
|
279
|
+
"""Validate domain IP resolution and matching"""
|
280
|
+
|
281
|
+
# Skip validation for wildcard or empty domains
|
282
|
+
if model.domain.startswith('*') or not model.domain:
|
283
|
+
return True
|
284
|
+
|
285
|
+
# Resolve domain IPs with timeout
|
286
|
+
try:
|
287
|
+
dips = hutils.network.get_domain_ips(model.domain, timeout=10)
|
288
|
+
except Exception as e:
|
289
|
+
logger.error(f"Error resolving domain {model.domain}: {str(e)}")
|
290
|
+
raise ValidationError(_("Domain cannot be resolved! Please check DNS settings"))
|
291
|
+
|
292
|
+
# Validate resolution success
|
293
|
+
if not dips:
|
294
|
+
raise ValidationError(_("Domain cannot be resolved! Please check DNS settings"))
|
295
|
+
|
296
|
+
# Check IP matching based on mode
|
297
|
+
domain_ip_matches_server = any(ip in dips for ip in server_ips)
|
298
|
+
server_ips_str = ', '.join(map(str, server_ips))
|
299
|
+
dips_str = ', '.join(map(str, dips))
|
300
|
+
|
301
|
+
if not domain_ip_matches_server and model.mode in [DomainType.direct]:
|
302
|
+
raise ValidationError(
|
303
|
+
__("Domain IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode",
|
304
|
+
server_ip=server_ips_str, domain_ip=dips_str))
|
305
|
+
|
306
|
+
if domain_ip_matches_server and model.mode in [DomainType.cdn, DomainType.relay, DomainType.fake, DomainType.auto_cdn_ip]:
|
307
|
+
raise ValidationError(
|
308
|
+
__("In CDN mode, Domain IP=%(domain_ip)s should be different to your ip=%(server_ip)s",
|
309
|
+
server_ip=server_ips_str, domain_ip=dips_str))
|
310
|
+
|
311
|
+
return True
|
312
|
+
|
313
|
+
|
281
314
|
# def after_model_change(self,form, model, is_created):
|
282
315
|
# if model.show_domains.count==0:
|
283
316
|
# db.session.bulk_save_objects(ShowDomain(model.id,model.id))
|
@@ -251,11 +251,11 @@ def validate_domain(form, field):
|
|
251
251
|
if dip is None:
|
252
252
|
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain"))
|
253
253
|
|
254
|
-
|
255
|
-
|
256
|
-
if dip
|
254
|
+
myips = hutils.network.get_ips()
|
255
|
+
# Fixed: Changed from get_ip(4) to get_ip(6)
|
256
|
+
if dip not in myips:
|
257
257
|
raise ValidationError(_("Domain (%(domain)s)-> IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode",
|
258
|
-
server_ip=
|
258
|
+
server_ip=myips, domain_ip=dip, domain=domain))
|
259
259
|
|
260
260
|
|
261
261
|
def validate_domain_cdn(form, field):
|
@@ -266,10 +266,10 @@ def validate_domain_cdn(form, field):
|
|
266
266
|
if dip is None:
|
267
267
|
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain"))
|
268
268
|
|
269
|
-
|
270
|
-
if
|
269
|
+
myips = hutils.network.get_ips()
|
270
|
+
if dip in myips:
|
271
271
|
raise ValidationError(_("In CDN mode, Domain IP=%(domain_ip)s should be different to your ip=%(server_ip)s",
|
272
|
-
server_ip=
|
272
|
+
server_ip=myips, domain_ip=dip, domain=domain))
|
273
273
|
|
274
274
|
|
275
275
|
def admin_link():
|
@@ -27,7 +27,7 @@ from hiddifypanel import hutils
|
|
27
27
|
class UserAdmin(AdminLTEModelView):
|
28
28
|
column_default_sort = ('id', False) # Sort by username in ascending order
|
29
29
|
|
30
|
-
column_sortable_list = ["is_active", "name", "current_usage", 'mode', "remaining_days","max_ips", "comment", 'last_online', "uuid"
|
30
|
+
column_sortable_list = ["is_active", "name", "current_usage", 'mode', "remaining_days", "max_ips", "comment", 'last_online', "uuid"]
|
31
31
|
column_searchable_list = ["uuid", "name"]
|
32
32
|
column_list = ["is_active", "name", "UserLinks", "current_usage", "remaining_days", "comment", 'last_online', 'mode', 'admin', "uuid"]
|
33
33
|
column_editable_list = ["comment", "name", "uuid"]
|
@@ -131,7 +131,7 @@ class UserAdmin(AdminLTEModelView):
|
|
131
131
|
if model.is_active:
|
132
132
|
link = '<i class="fa-solid fa-circle-check text-success"></i> '
|
133
133
|
elif len(model.devices):
|
134
|
-
link = '<i class="fa-solid fa-users-slash text-danger" title="{_("Too many Connected IPs")}"></i>'
|
134
|
+
link = f'<i class="fa-solid fa-users-slash text-danger" title="{_("Too many Connected IPs")}"></i>'
|
135
135
|
else:
|
136
136
|
link = '<i class="fa-solid fa-circle-xmark text-danger"></i> '
|
137
137
|
|
@@ -161,8 +161,8 @@ class UserAdmin(AdminLTEModelView):
|
|
161
161
|
|
162
162
|
def _usage_formatter(view, context, model, name):
|
163
163
|
u = round(model.current_usage_GB, 3)
|
164
|
-
t = round(model.usage_limit_GB, 3)
|
165
|
-
rate = round(u * 100 /
|
164
|
+
t = max(round(model.usage_limit_GB, 3), 0.001) # Prevent division by zero
|
165
|
+
rate = min(round(u * 100 / t), 100) # Cap at 100%
|
166
166
|
state = "danger" if u >= t else ('warning' if rate > 80 else 'success')
|
167
167
|
color = "#ff7e7e" if u >= t else ('#ffc107' if rate > 80 else '#9ee150')
|
168
168
|
return Markup(f"""
|
@@ -225,38 +225,45 @@ class UserAdmin(AdminLTEModelView):
|
|
225
225
|
|
226
226
|
def on_form_prefill(self, form, id=None):
|
227
227
|
# print("================",form._obj.start_date)
|
228
|
-
if
|
228
|
+
if form._obj is None:
|
229
|
+
return
|
230
|
+
|
231
|
+
if id is None or form._obj.start_date is None or form._obj.current_usage==0:
|
229
232
|
msg = _("Package not started yet.")
|
230
233
|
# form.reset['class']="d-none"
|
231
|
-
|
234
|
+
if form._obj.start_date is None:
|
235
|
+
if hasattr(form, 'reset_days'):
|
232
236
|
delattr(form, 'reset_days')
|
233
|
-
if form._obj.current_usage==0:
|
234
|
-
delattr(form, 'reset_usage')
|
235
|
-
# delattr(form,'disable_user')
|
236
237
|
else:
|
237
|
-
remaining = form._obj.remaining_days
|
238
|
+
remaining = form._obj.remaining_days
|
238
239
|
relative_remaining = hutils.convert.format_timedelta(datetime.timedelta(days=remaining))
|
239
240
|
msg = _("Remaining about %(relative)s, exactly %(days)s days", relative=relative_remaining, days=remaining)
|
240
241
|
form.reset_days.label.text += f" ({msg})"
|
241
|
-
usr_usage = f" ({_('user.home.usage.title')} {round(form._obj.current_usage_GB,3)}GB)"
|
242
|
-
form.reset_usage.label.text += usr_usage
|
243
|
-
form.reset_usage.data = False
|
244
242
|
form.reset_days.data = False
|
245
243
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
form.
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
244
|
+
# Handle reset_usage field
|
245
|
+
if form._obj.current_usage == 0:
|
246
|
+
if hasattr(form, 'reset_usage'):
|
247
|
+
delattr(form, 'reset_usage')
|
248
|
+
else:
|
249
|
+
usr_usage = f" ({_('user.home.usage.title')} {round(form._obj.current_usage_GB,3)}GB)"
|
250
|
+
if hasattr(form, 'reset_usage'):
|
251
|
+
form.reset_usage.label.text += usr_usage
|
252
|
+
form.reset_usage.data = False
|
253
|
+
|
254
|
+
if hasattr(form, 'usage_limit'):
|
255
|
+
form.usage_limit.label.text += usr_usage
|
256
|
+
|
257
|
+
# Handle package days info
|
258
|
+
if form._obj.start_date and hasattr(form, 'package_days'):
|
259
|
+
started = form._obj.start_date - datetime.date.today()
|
260
|
+
msg = _("Started from %(relative)s", relative=hutils.convert.format_timedelta(started))
|
261
|
+
form.package_days.label.text += f" ({msg})"
|
262
|
+
if started.days <= 0:
|
263
|
+
exact_start = _("Started %(days)s days ago", days=-started.days)
|
264
|
+
else:
|
265
|
+
exact_start = _("Will Start in %(days)s days", days=started.days)
|
266
|
+
form.package_days.description += f" ({exact_start})"
|
260
267
|
|
261
268
|
def get_edit_form(self):
|
262
269
|
form = super().get_edit_form()
|
@@ -267,26 +274,44 @@ class UserAdmin(AdminLTEModelView):
|
|
267
274
|
return form
|
268
275
|
|
269
276
|
def on_model_change(self, form, model, is_created):
|
270
|
-
|
277
|
+
# Validate max_ips
|
278
|
+
try:
|
279
|
+
model.max_ips = max(3, min(int(model.max_ips or 10000), 10000))
|
280
|
+
except (ValueError, TypeError):
|
281
|
+
model.max_ips = 1000
|
282
|
+
|
283
|
+
# Show donation message
|
271
284
|
if len(User.query.all()) % 4 == 0:
|
272
285
|
hutils.flask.flash(('<div id="show-modal-donation"></div>'), ' d-none')
|
286
|
+
|
287
|
+
# Validate UUID
|
273
288
|
if not re.match("^[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}$", model.uuid):
|
274
289
|
raise ValidationError('Invalid UUID e.g.,' + str(uuid.uuid4()))
|
290
|
+
|
291
|
+
# Handle reset flags
|
275
292
|
if hasattr(form, 'reset_usage') and form.reset_usage.data:
|
276
293
|
model.current_usage_GB = 0
|
277
|
-
|
278
|
-
# raise ValidationError('Invalid Telegram ID')
|
279
|
-
# if form.disable_user.data:
|
280
|
-
# model.mode=UserMode.disable
|
294
|
+
|
281
295
|
if hasattr(form, 'reset_days') and form.reset_days.data:
|
282
296
|
model.start_date = None
|
283
|
-
|
297
|
+
|
298
|
+
# Validate package days
|
299
|
+
try:
|
300
|
+
model.package_days = min(int(model.package_days), 10000)
|
301
|
+
except (ValueError, TypeError):
|
302
|
+
model.package_days = 10000
|
303
|
+
|
304
|
+
# Handle user ownership
|
284
305
|
old_user = User.by_id(model.id)
|
285
306
|
if not model.added_by or model.added_by == 1:
|
286
307
|
model.added_by = g.account.id
|
308
|
+
|
309
|
+
# Validate user limits
|
287
310
|
if not g.account.can_have_more_users():
|
288
311
|
raise ValidationError(_('You have too much users! You can have only %(active)s active users and %(total)s users',
|
289
312
|
active=g.account.max_active_users, total=g.account.max_users))
|
313
|
+
|
314
|
+
# Handle UUID changes
|
290
315
|
if old_user and old_user.uuid != model.uuid:
|
291
316
|
user_driver.remove_client(old_user)
|
292
317
|
|
@@ -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');
|
@@ -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())
|
hiddifypanel/panel/init_db.py
CHANGED
@@ -77,7 +77,7 @@ def _v94(child_id):
|
|
77
77
|
|
78
78
|
def _v93(child_id):
|
79
79
|
set_hconfig(ConfigEnum.quic_enable, True)
|
80
|
-
set_hconfig(ConfigEnum.
|
80
|
+
set_hconfig(ConfigEnum.xhttp_enable, True)
|
81
81
|
|
82
82
|
|
83
83
|
def _v92(child_id):
|
@@ -85,9 +85,9 @@ def _v92(child_id):
|
|
85
85
|
|
86
86
|
|
87
87
|
def _v89(child_id):
|
88
|
-
set_hconfig(ConfigEnum.
|
88
|
+
set_hconfig(ConfigEnum.path_xhttp,
|
89
89
|
hutils.random.get_random_string(7, 15))
|
90
|
-
set_hconfig(ConfigEnum.
|
90
|
+
set_hconfig(ConfigEnum.xhttp_enable, False)
|
91
91
|
pass
|
92
92
|
|
93
93
|
|
@@ -218,7 +218,7 @@ def _v65():
|
|
218
218
|
add_config_if_not_exist(ConfigEnum.mux_min_streams, '4')
|
219
219
|
add_config_if_not_exist(ConfigEnum.mux_max_streams, '0')
|
220
220
|
add_config_if_not_exist(ConfigEnum.mux_padding_enable, False)
|
221
|
-
add_config_if_not_exist(ConfigEnum.mux_brutal_enable,
|
221
|
+
add_config_if_not_exist(ConfigEnum.mux_brutal_enable, False)
|
222
222
|
add_config_if_not_exist(ConfigEnum.mux_brutal_up_mbps, '100')
|
223
223
|
add_config_if_not_exist(ConfigEnum.mux_brutal_down_mbps, '100')
|
224
224
|
|
@@ -571,9 +571,9 @@ def get_proxy_rows_v1():
|
|
571
571
|
"httpupgrade direct vless",
|
572
572
|
# "httpupgrade direct trojan",
|
573
573
|
"httpupgrade direct vmess",
|
574
|
-
"
|
575
|
-
"
|
576
|
-
"
|
574
|
+
"xhttp direct vless",
|
575
|
+
"xhttp direct trojan",
|
576
|
+
"xhttp direct vmess",
|
577
577
|
"tcp direct vless",
|
578
578
|
"tcp direct trojan",
|
579
579
|
"tcp direct vmess",
|
@@ -591,9 +591,9 @@ def get_proxy_rows_v1():
|
|
591
591
|
# "httpupgrade relay trojan",
|
592
592
|
"httpupgrade relay vmess",
|
593
593
|
|
594
|
-
"
|
595
|
-
"
|
596
|
-
"
|
594
|
+
"xhttp relay vless",
|
595
|
+
"xhttp relay trojan",
|
596
|
+
"xhttp relay vmess",
|
597
597
|
|
598
598
|
"tcp relay vless",
|
599
599
|
"tcp relay trojan",
|
@@ -615,9 +615,9 @@ def get_proxy_rows_v1():
|
|
615
615
|
# "httpupgrade CDN trojan",
|
616
616
|
"httpupgrade CDN vmess",
|
617
617
|
|
618
|
-
"
|
619
|
-
"
|
620
|
-
"
|
618
|
+
"xhttp CDN vless",
|
619
|
+
"xhttp CDN trojan",
|
620
|
+
"xhttp CDN vmess",
|
621
621
|
|
622
622
|
"grpc CDN vless",
|
623
623
|
"grpc CDN trojan",
|
@@ -663,7 +663,7 @@ def make_proxy_rows(cfgs):
|
|
663
663
|
for l3 in [ProxyL3.h3_quic, "tls_h2", "tls", "http", "reality"]:
|
664
664
|
for c in cfgs:
|
665
665
|
transport, cdn, proto = c.split(" ")
|
666
|
-
if transport != ProxyTransport.
|
666
|
+
if transport != ProxyTransport.xhttp and l3 == ProxyL3.h3_quic:
|
667
667
|
continue
|
668
668
|
if l3 in ["kcp", 'reality'] and cdn != "direct":
|
669
669
|
continue
|
@@ -750,8 +750,11 @@ def add_new_enum_values():
|
|
750
750
|
continue
|
751
751
|
|
752
752
|
# Add the new value to the enum column in the database
|
753
|
-
enumstr = ','.join([f"'{a}'" for a in [*existing_values, *old_values]])
|
754
|
-
|
753
|
+
# enumstr = ','.join([f"'{a}'" for a in [*existing_values, *old_values]])
|
754
|
+
enumstr = ','.join([f"'{a}'" for a in [*existing_values]])
|
755
|
+
expired_enumstr = ','.join([f"'{a}'" for a in [*old_values]])
|
756
|
+
db_execute(
|
757
|
+
f"delete from {table_name} where `{column_name}` in ({expired_enumstr});", commit=True)
|
755
758
|
db_execute(
|
756
759
|
f"ALTER TABLE {table_name} MODIFY COLUMN `{column_name}` ENUM({enumstr});", commit=True)
|
757
760
|
|
@@ -642,7 +642,7 @@
|
|
642
642
|
"description": "ça devrait être aléatoire",
|
643
643
|
"label": "ℹ️ Chemin de mise à niveau HTTP"
|
644
644
|
},
|
645
|
-
"
|
645
|
+
"path_xhttp": {
|
646
646
|
"description": "Cette option définit le chemin pour Split HTTP",
|
647
647
|
"label": "Chemin pour le HTTP fractionné"
|
648
648
|
},
|
@@ -778,7 +778,7 @@
|
|
778
778
|
"description": "Autorisez vos utilisateurs à effectuer des tests de vitesse. Cela les aide à identifier la qualité du lien",
|
779
779
|
"label": "🚀 Test de vitesse"
|
780
780
|
},
|
781
|
-
"
|
781
|
+
"xhttp_enable": {
|
782
782
|
"description": "Ce protocole envoie et reçoit des informations dans des canaux individuels ",
|
783
783
|
"label": "🈁 Split HTTP"
|
784
784
|
},
|
@@ -642,7 +642,7 @@
|
|
642
642
|
"description": "ကျပန်းဖြစ်သင့်သည်",
|
643
643
|
"label": "ℹ️ HTTP အဆင့်မြှင့်တင်မှု လမ်းကြောင်း"
|
644
644
|
},
|
645
|
-
"
|
645
|
+
"path_xhttp": {
|
646
646
|
"description": "ဤရွေးချယ်မှုသည် Split HTTP အတွက် လမ်းကြောင်းကို သတ်မှတ်သည်။",
|
647
647
|
"label": "ℹ️ Split HTTP အတွက် လမ်းကြောင်း"
|
648
648
|
},
|
@@ -778,7 +778,7 @@
|
|
778
778
|
"description": "သင့်အသုံးပြုသူများကို အမြန်နှုန်းစမ်းသပ်မှု ပြုလုပ်ခွင့်ပြုရန်။ ၎င်းသည် ၎င်းတို့အား လင့်ခ်အရည်အသွေးကို ခွဲခြားသတ်မှတ်ရန် ကူညီပေးသည်။",
|
779
779
|
"label": "🚀 အမြန်နှုန်း စမ်းသပ်"
|
780
780
|
},
|
781
|
-
"
|
781
|
+
"xhttp_enable": {
|
782
782
|
"description": "ဤပရိုတိုကောသည် ချန်နယ်တစ်ခုချင်းစီတွင် အချက်အလက်များကို ပေးပို့လက်ခံသည်",
|
783
783
|
"label": "🈁 Split HTTP"
|
784
784
|
},
|
@@ -1,6 +1,6 @@
|
|
1
1
|
hiddifypanel/Events.py,sha256=AlnRdjVul0jP-NCT4-zoaQgowoOo-JhdQB4ytetAFKA,723
|
2
|
-
hiddifypanel/VERSION,sha256=
|
3
|
-
hiddifypanel/VERSION.py,sha256=
|
2
|
+
hiddifypanel/VERSION,sha256=xBTCiBOLHDQLmnkIj8kG6LekkaQVA9EDbrLn_tKtU78,14
|
3
|
+
hiddifypanel/VERSION.py,sha256=zzfFvEjn3EVsQaXeZlJR3pKOPBTBKtsIquwH3ds11-8,227
|
4
4
|
hiddifypanel/__init__.py,sha256=kigwDO8d9jXyPZLvJAWd6zo-GX3pG_xWf-q2aStz80Y,377
|
5
5
|
hiddifypanel/__main__.py,sha256=IVchnXpK6bm8T3N--mN17HBQNLMeLAjyP7iwzULexB4,218
|
6
6
|
hiddifypanel/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -39,11 +39,11 @@ hiddifypanel/hutils/node/child.py,sha256=oAyKlEHHn9FHcpZ9jBi3nYH-GHs8H7Gi2hzkmtO
|
|
39
39
|
hiddifypanel/hutils/node/parent.py,sha256=UbyfvfP4fTSn6HN9oZDjYsKYIejiqW6eApKIfP0Mz5U,3749
|
40
40
|
hiddifypanel/hutils/node/shared.py,sha256=FDSj3e-i3pb3mEv5vcUeX0Km1nxYg1CeAruIq7RwFmU,2540
|
41
41
|
hiddifypanel/hutils/proxy/__init__.py,sha256=xXBa83kjYT_b-BNseEykfQYyJBQHTq1ZosfR8ZrQHkI,106
|
42
|
-
hiddifypanel/hutils/proxy/clash.py,sha256=
|
43
|
-
hiddifypanel/hutils/proxy/shared.py,sha256=
|
44
|
-
hiddifypanel/hutils/proxy/singbox.py,sha256=
|
45
|
-
hiddifypanel/hutils/proxy/xray.py,sha256=
|
46
|
-
hiddifypanel/hutils/proxy/xrayjson.py,sha256=
|
42
|
+
hiddifypanel/hutils/proxy/clash.py,sha256=V9Y2UIw-CYTXD_Q73Oeq3WLw6chsPrMIiNxYnlWyNbg,7065
|
43
|
+
hiddifypanel/hutils/proxy/shared.py,sha256=Zg4qMqp-fzWXHMqZsE1stluVDgT71AlFVlJAxQwMtfQ,22203
|
44
|
+
hiddifypanel/hutils/proxy/singbox.py,sha256=Fmmzoake-gpnRB5yfTyQvd1dB-10WKwhJt4vhiKzJZQ,11722
|
45
|
+
hiddifypanel/hutils/proxy/xray.py,sha256=0vEHL9yq5Si7W_fgI8tn9zwNAWhwBE7djun05cAUDF8,10808
|
46
|
+
hiddifypanel/hutils/proxy/xrayjson.py,sha256=iEfMlLZfzYzp5eCj8AuL9nXmuPJavKZaoAjtASEIhNY,14990
|
47
47
|
hiddifypanel/hutils/random.py,sha256=KrsarmRNL05PYzwMxDaDyv-_QcKS0YsZR2z7BnllAqI,1789
|
48
48
|
hiddifypanel/hutils/system.py,sha256=nX7ZvmXKfHu6_cFVOGZRG-7ch2glqgzQL2iWraQc4S0,4350
|
49
49
|
hiddifypanel/hutils/utils.py,sha256=qOvyBFQxBFAV9HYtZn8XVgIauNbVIE2A6WGSpf-NyQM,2349
|
@@ -52,27 +52,27 @@ hiddifypanel/models/admin.py,sha256=Ocvb9x1LG2rG36euoSoVvxUXf1LPBLieEPTghcXjOBk,
|
|
52
52
|
hiddifypanel/models/base_account.py,sha256=RkdGy6KmbX1E-VDNtVNE2RYxhvPuWg18Grm5H9Dv1-k,3561
|
53
53
|
hiddifypanel/models/child.py,sha256=ZFJaH-GWTKAGD0BGMH0iKEMipi37_cAk59OeJKt2IKA,3039
|
54
54
|
hiddifypanel/models/config.py,sha256=goWQugd1yelIP3z1nkTkh4Uvh4Ak1rEXS33Ru_kTpsg,6373
|
55
|
-
hiddifypanel/models/config_enum.py,sha256=
|
55
|
+
hiddifypanel/models/config_enum.py,sha256=ZhO9K7IAfa3J-eNmAzToduz0h37lh40dP37tr1kPqnE,16705
|
56
56
|
hiddifypanel/models/domain.py,sha256=0tAPHR6XukN35CoyOxR3zXDNjXR-w_Ezd89jxk2H-xc,8308
|
57
57
|
hiddifypanel/models/parent_domain.py,sha256=bs5F1neOAQu9XHEk3QQTBM4p2iuebM4cnAQqwfNjCtg,2291
|
58
|
-
hiddifypanel/models/proxy.py,sha256=
|
58
|
+
hiddifypanel/models/proxy.py,sha256=Ha_gz7RHrPVeP7wDjkOaWeRN99XlITMklDTSzBXGlY8,3323
|
59
59
|
hiddifypanel/models/report.py,sha256=33h9k12SAEWkwZsc3-jUdIIpFL66cEOTHQqVXd07NWY,1001
|
60
60
|
hiddifypanel/models/role.py,sha256=V93_AhOcgbIiAaRYUaNIWKsKZ704ANl0hq-uAJFQCUo,269
|
61
61
|
hiddifypanel/models/usage.py,sha256=BCZtYhmgru-bF8O2dGwJgcN7qtZ29a3arQEK9EVPdtE,4362
|
62
62
|
hiddifypanel/models/user.py,sha256=GXVcxP1kgAIqb0OLC_6vhu4kKMTkS5OBT7oPrfD59hg,14802
|
63
63
|
hiddifypanel/panel/__init__.py,sha256=q7y-nJntWhWX7dwDm3q-QWT5ZNytT3y6IJsdGtH2B6c,196
|
64
64
|
hiddifypanel/panel/admin/Actions.py,sha256=o_ENbphriVrbRJkx9nvrkpaliuMIfp34sscMkZJ3P5s,8578
|
65
|
-
hiddifypanel/panel/admin/AdminstratorAdmin.py,sha256=
|
65
|
+
hiddifypanel/panel/admin/AdminstratorAdmin.py,sha256=X8MI3DtW62vJqFRp97M_CxSdB-NFNMlZOSDsd5hn8HA,10482
|
66
66
|
hiddifypanel/panel/admin/Backup.py,sha256=BKSoAZgw1j16P1Jh9vMqGj7ZfB2m-WafDK0C5vil5FY,3634
|
67
67
|
hiddifypanel/panel/admin/ConfigAdmin.py,sha256=0hnLY-8BxrpVnrAcQaedWjHnRUq1X_Styi_ZCZ2ivds,2876
|
68
68
|
hiddifypanel/panel/admin/Dashboard.py,sha256=JOqZLHxPOYKQYQVJ7AtHAkilH-anJZQyK1rQrgCJUeA,3798
|
69
|
-
hiddifypanel/panel/admin/DomainAdmin.py,sha256=
|
69
|
+
hiddifypanel/panel/admin/DomainAdmin.py,sha256=PQv1U_Ro0VMRjX4dPXUewiHJuZdi1ocvA1jw4mgOSdo,16152
|
70
70
|
hiddifypanel/panel/admin/NodeAdmin.py,sha256=QAHQjF7e7F4KqsWNWpMt7SoLANlFEborVtWQV9OXJ2E,3102
|
71
71
|
hiddifypanel/panel/admin/ProxyAdmin.py,sha256=HtuYHkZ8LCrYtjF2xO2i7lyw_KtOTBYCPu0bNWR4fOs,5364
|
72
|
-
hiddifypanel/panel/admin/QuickSetup.py,sha256=
|
72
|
+
hiddifypanel/panel/admin/QuickSetup.py,sha256=wma8Ctka4PM80B0UJY2JXzl0cJnaBkcyAh1__pfUffo,12645
|
73
73
|
hiddifypanel/panel/admin/SettingAdmin.py,sha256=SCzhsZh9QrmYNPPhutQfMRuB_q6RNCXv9hy-uLjlrd0,19893
|
74
74
|
hiddifypanel/panel/admin/Terminal.py,sha256=rzZWRjMhjVnAvC65rfE3HJT3boUDznI6fl-htzKp7sI,1712
|
75
|
-
hiddifypanel/panel/admin/UserAdmin.py,sha256=
|
75
|
+
hiddifypanel/panel/admin/UserAdmin.py,sha256=i1-B0iBtFA-D18V920hFlYJIzPdiuYUKtLP860D0sbY,18601
|
76
76
|
hiddifypanel/panel/admin/__init__.py,sha256=hb0A2HuK_nBZRCNPumwahXX-25FMxODKYlNbk2ItF08,3015
|
77
77
|
hiddifypanel/panel/admin/adminlte.py,sha256=TrUUu6WYUM-rpgvW2C2KBq3bXkvKe3Pa3cEPjpWCJuk,758
|
78
78
|
hiddifypanel/panel/admin/commercial_info.py,sha256=_fBJcR6zTlMs5Wx4NQJYxq5LvMHY8qfoh73-eCNJyb8,278
|
@@ -109,12 +109,12 @@ hiddifypanel/panel/admin/templates/fake_for_translation/Flask-AdminLTE3/template
|
|
109
109
|
hiddifypanel/panel/admin/templates/fake_for_translation/Flask-AdminLTE3/templates/flask-admin/rediscli/console.html,sha256=m0lQD8cwGUMfzRjiPeGFlV3cdKqtArxhSzPXOBd7myM,909
|
110
110
|
hiddifypanel/panel/admin/templates/fake_for_translation/Flask-AdminLTE3/templates/flask-admin/rediscli/response.html,sha256=FekGe9v4RIMoGZlnk9TwqOFjSUVaRweLeZf-oFCVOck,965
|
111
111
|
hiddifypanel/panel/admin/templates/fake_for_translation/Flask-AdminLTE3/templates/flask-admin/static.html,sha256=S-_WCUQPTU4zWO7C2fJ8uxf47Q7QroSrKkIHstBDfTU,94
|
112
|
-
hiddifypanel/panel/admin/templates/index.html,sha256=
|
112
|
+
hiddifypanel/panel/admin/templates/index.html,sha256=aFNSYWav3qI4kLhdTuk_yTPJc5RLY-9H-3NtM8k_HV0,13898
|
113
113
|
hiddifypanel/panel/admin/templates/ltemaster.html,sha256=KE_HsUOIR__BG1fW8DZ05rhgckQ8ls0a-ho6dWtmuX4,1080
|
114
114
|
hiddifypanel/panel/admin/templates/model/admin_list.html,sha256=lpjiAl7kR5xb0fLpI5-kmf9uA6CVSAFuNE-2WZ152yQ,690
|
115
115
|
hiddifypanel/panel/admin/templates/model/domain_list.html,sha256=gl-LnCQCPve5OHH0ber0bwV9vAguZB_PXv0qgpx0qaE,288
|
116
116
|
hiddifypanel/panel/admin/templates/model/proxydetail_list.html,sha256=5VVFPZkcGhfKVq842CWggv1Wte6CQodrbGxO4AJ9Bo0,206
|
117
|
-
hiddifypanel/panel/admin/templates/model/user_list.html,sha256=
|
117
|
+
hiddifypanel/panel/admin/templates/model/user_list.html,sha256=XwrcElWgJhLViOGlowSNLPW-SX6wk9Jd5_Uy6n11d6Q,6158
|
118
118
|
hiddifypanel/panel/admin/templates/parent_dash.html,sha256=kAVBwv287oaQFfNmvTxBqgaZOaAf1Nz6jPXfEZMfTXQ,1814
|
119
119
|
hiddifypanel/panel/admin/templates/proxy.html,sha256=Q-Flp_O1LuuJnwWbodte2yr96MGzDoqgU50kB4dcsf0,1777
|
120
120
|
hiddifypanel/panel/admin/templates/quick_setup.html,sha256=tYZnRBH682eThl6lQcnLNKIdCQDTWRZWccIZSiNxSlA,2101
|
@@ -133,7 +133,7 @@ hiddifypanel/panel/commercial/__init__.py,sha256=oanPV36n6MXiVhiq_NYL6K9ENhQXZGQ
|
|
133
133
|
hiddifypanel/panel/commercial/restapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
134
134
|
hiddifypanel/panel/commercial/restapi/v1/__init__.py,sha256=p7KxjATIX71uT1JQJrg9LKn5RgYJS2k6urX4MlOCb7E,1229
|
135
135
|
hiddifypanel/panel/commercial/restapi/v1/resources.py,sha256=D7HTLAW-KA_Ikm9VArN2FSARfyCPKHxr3WEs_y4_HTM,4691
|
136
|
-
hiddifypanel/panel/commercial/restapi/v1/tgbot.py,sha256=
|
136
|
+
hiddifypanel/panel/commercial/restapi/v1/tgbot.py,sha256=nBj-BZ-BTocLPFY7VK2R1Cae_xCSJZUah0TDhEzF0n0,3132
|
137
137
|
hiddifypanel/panel/commercial/restapi/v1/tgmsg.py,sha256=bUERY88cNvcDQ-SxoL4oNn6fiIKj8souyS1kSYnQmuU,3033
|
138
138
|
hiddifypanel/panel/commercial/restapi/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
139
139
|
hiddifypanel/panel/commercial/restapi/v2/admin/__init__.py,sha256=Q0nvBCzTIHb0BNTBUjbVN2_j4e6MJhDWHE6_RNBleso,1871
|
@@ -181,7 +181,7 @@ hiddifypanel/panel/common_bp/templates/login.html,sha256=jDl9-Nh2qMuCsLQmXm7e5jv
|
|
181
181
|
hiddifypanel/panel/custom_widgets.py,sha256=_zA0WZRZOCyh6Z1gW62aRQLMAOM_m85B2oZoIOU59Ys,2637
|
182
182
|
hiddifypanel/panel/hiddify.py,sha256=-GBmkEXnGsIhZtjRomYJsqmnEToZwSXzd8ltS6Slgrc,15615
|
183
183
|
hiddifypanel/panel/hlogger.py,sha256=1L2T1fwuozPoNfkcKF-wP2TH2pd7lGRr9htWqwR1c2M,1157
|
184
|
-
hiddifypanel/panel/init_db.py,sha256=
|
184
|
+
hiddifypanel/panel/init_db.py,sha256=fgKZ27xFb1p1m3vqph3EUv6Gh7_fqFCaTmbWFNWAJY0,37305
|
185
185
|
hiddifypanel/panel/node/__init__.py,sha256=gGwtD5XczIpB1OP7Fb3JLxb8kGxn5zNgeHQ-MgGg01g,189
|
186
186
|
hiddifypanel/panel/node/a.py,sha256=KTzfA-RYRGNGtjFlXcYgH7N1gJRqrdneksXr0XmivvU,330
|
187
187
|
hiddifypanel/panel/node/hello.py,sha256=P6htWmqwk7uixDrl0bSgRocV_zlatSBNAx_RnivN0aQ,519
|
@@ -850,13 +850,13 @@ hiddifypanel/translations/zh/LC_MESSAGES/messages.mo,sha256=WDVuh5nD9Lqzocm43KAU
|
|
850
850
|
hiddifypanel/translations/zh/LC_MESSAGES/messages.po,sha256=r9ekUU5AcPRWMYHkEyiBQWoBWw5KWGDrfU4IXhd50CE,62592
|
851
851
|
hiddifypanel/translations.i18n/en.json,sha256=jNo3qUHuEZ_Q5CXuP3K6DRM7Nih0DSdMcjoEenDFAJQ,56637
|
852
852
|
hiddifypanel/translations.i18n/fa.json,sha256=MoLFtZq9JhlV3mT1GIL0NtIrVlnu4iR_cMyW6C0dvAw,78581
|
853
|
-
hiddifypanel/translations.i18n/fr.json,sha256=
|
854
|
-
hiddifypanel/translations.i18n/my.json,sha256=
|
853
|
+
hiddifypanel/translations.i18n/fr.json,sha256=3D_JxOMxuQrdDCTTvsah5VXxvYcPcZFzBzeHqQZwRuI,80842
|
854
|
+
hiddifypanel/translations.i18n/my.json,sha256=UHXP_EuyX9f5mEAtcxp_40TgGykXs_ap9yp7QcsVQ88,136285
|
855
855
|
hiddifypanel/translations.i18n/pt.json,sha256=utRxsg-gt8TZAsjszZmr-2cy0gH0LQ5CavIyQqqgzy0,59165
|
856
856
|
hiddifypanel/translations.i18n/ru.json,sha256=J77yrIPYj0DKzqwvcyOlDfmr8mJsm2Phu9UtveBdw5Q,82933
|
857
857
|
hiddifypanel/translations.i18n/zh.json,sha256=f8T19F92fa0FyexbgSLdRItPZcKIqBXnzzXLW77s3eE,54843
|
858
|
-
hiddifypanel-10.80.0.
|
859
|
-
hiddifypanel-10.80.0.
|
860
|
-
hiddifypanel-10.80.0.
|
861
|
-
hiddifypanel-10.80.0.
|
862
|
-
hiddifypanel-10.80.0.
|
858
|
+
hiddifypanel-10.80.0.dev14.dist-info/LICENSE.md,sha256=oDrt-cUsyiDGnRPjEJh-3dH2ddAuK_bIVBD8ntkOtZw,19807
|
859
|
+
hiddifypanel-10.80.0.dev14.dist-info/METADATA,sha256=ls5SsP-LsOn6leZ7zqi52nfOX6HBLYMGVIHjvavyC7w,3963
|
860
|
+
hiddifypanel-10.80.0.dev14.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
861
|
+
hiddifypanel-10.80.0.dev14.dist-info/entry_points.txt,sha256=fiVgmdZ7nff9Ow1XnyMFrn1y4akk9gwnDkxpN8P3Xrw,59
|
862
|
+
hiddifypanel-10.80.0.dev14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{hiddifypanel-10.80.0.dev13.dist-info → hiddifypanel-10.80.0.dev14.dist-info}/entry_points.txt
RENAMED
File without changes
|