hiddifypanel 10.30.9.dev0__py3-none-any.whl → 10.30.9.dev2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/cache.py +13 -3
  4. hiddifypanel/hutils/network/net.py +36 -7
  5. hiddifypanel/hutils/proxy/shared.py +1 -1
  6. hiddifypanel/hutils/proxy/xrayjson.py +6 -6
  7. hiddifypanel/models/config_enum.py +2 -2
  8. hiddifypanel/models/domain.py +1 -1
  9. hiddifypanel/panel/admin/DomainAdmin.py +45 -32
  10. hiddifypanel/panel/admin/ProxyAdmin.py +1 -1
  11. hiddifypanel/panel/admin/QuickSetup.py +138 -47
  12. hiddifypanel/panel/admin/SettingAdmin.py +11 -6
  13. hiddifypanel/panel/admin/templates/quick_setup.html +19 -13
  14. hiddifypanel/panel/init_db.py +6 -6
  15. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  16. hiddifypanel/translations/en/LC_MESSAGES/messages.po +16 -3
  17. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  18. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +16 -3
  19. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  20. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +11 -2
  21. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  22. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +11 -2
  23. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  24. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +11 -2
  25. hiddifypanel/translations.i18n/en.json +11 -2
  26. hiddifypanel/translations.i18n/fa.json +11 -2
  27. hiddifypanel/translations.i18n/pt.json +10 -1
  28. hiddifypanel/translations.i18n/ru.json +10 -1
  29. hiddifypanel/translations.i18n/zh.json +10 -1
  30. {hiddifypanel-10.30.9.dev0.dist-info → hiddifypanel-10.30.9.dev2.dist-info}/METADATA +1 -1
  31. {hiddifypanel-10.30.9.dev0.dist-info → hiddifypanel-10.30.9.dev2.dist-info}/RECORD +35 -35
  32. {hiddifypanel-10.30.9.dev0.dist-info → hiddifypanel-10.30.9.dev2.dist-info}/LICENSE.md +0 -0
  33. {hiddifypanel-10.30.9.dev0.dist-info → hiddifypanel-10.30.9.dev2.dist-info}/WHEEL +0 -0
  34. {hiddifypanel-10.30.9.dev0.dist-info → hiddifypanel-10.30.9.dev2.dist-info}/entry_points.txt +0 -0
  35. {hiddifypanel-10.30.9.dev0.dist-info → hiddifypanel-10.30.9.dev2.dist-info}/top_level.txt +0 -0
hiddifypanel/VERSION CHANGED
@@ -1 +1 @@
1
- 10.30.9.dev0
1
+ 10.30.9.dev2
hiddifypanel/VERSION.py CHANGED
@@ -1,3 +1,3 @@
1
- __version__='10.30.9.dev0'
1
+ __version__='10.30.9.dev2'
2
2
  from datetime import datetime
3
- __release_date__= datetime.strptime('2024-07-12','%Y-%m-%d')
3
+ __release_date__= datetime.strptime('2024-07-13','%Y-%m-%d')
hiddifypanel/cache.py CHANGED
@@ -1,4 +1,4 @@
1
- from redis_cache import RedisCache, chunks
1
+ from redis_cache import RedisCache, chunks, compact_dump
2
2
  import redis
3
3
  from pickle import dumps, loads
4
4
  from loguru import logger
@@ -7,11 +7,21 @@ redis_client = redis.from_url('unix:///opt/hiddify-manager/other/redis/run.sock?
7
7
 
8
8
 
9
9
  class CustomRedisCache(RedisCache):
10
+ def __init__(self, redis_client, prefix="rc", serializer=compact_dump, deserializer=loads, key_serializer=None, support_cluster=True, exception_handler=None):
11
+ super().__init__(redis_client, prefix, serializer, deserializer, key_serializer, support_cluster, exception_handler)
12
+ self.cached_functions = set()
13
+
14
+ def cache(self, ttl=0, limit=0, namespace=None, exception_handler=None):
15
+ res = super().cache(ttl, limit, namespace, exception_handler)
16
+ self.cached_functions.add(res)
17
+ return res
10
18
 
11
19
  def invalidate_all_cached_functions(self):
12
20
  try:
21
+ for f in self.cached_functions:
22
+ f.invalidate_all()
13
23
  logger.trace("Invalidating all cached functions")
14
- chunks_gen = chunks(f'{self.prefix}*', 500)
24
+ chunks_gen = chunks(f'{self.prefix}*', 5000)
15
25
  for keys in chunks_gen:
16
26
  self.client.delete(*keys)
17
27
  logger.trace("Successfully invalidated all cached functions")
@@ -22,4 +32,4 @@ class CustomRedisCache(RedisCache):
22
32
  return False
23
33
 
24
34
 
25
- cache = CustomRedisCache(redis_client=redis_client, prefix="h", serializer=dumps, deserializer=loads)
35
+ cache = CustomRedisCache(redis_client=redis_client, prefix="h", serializer=dumps, deserializer=loads)
@@ -1,4 +1,4 @@
1
- from typing import List, Literal, Union
1
+ from typing import List, Literal, Set, Union
2
2
  from urllib.parse import urlparse
3
3
  import urllib.request
4
4
  import ipaddress
@@ -33,17 +33,43 @@ def get_domain_ip(domain: str, retry: int = 3, version: Literal[4, 6] | None = N
33
33
 
34
34
  if not res and version != 4:
35
35
  try:
36
- res = f"[{socket.getaddrinfo(domain, None, socket.AF_INET6)[0][4][0]}]"
37
-
38
- res = res[1:-1]
36
+ res = f"{socket.getaddrinfo(domain, None, socket.AF_INET6)[0][4][0]}"
39
37
 
40
38
  except BaseException:
41
39
  pass
42
40
 
43
- if retry <= 0 or not res:
41
+ if retry <= 0:
44
42
  return None
43
+ if not res:
44
+ return get_domain_ip(domain, retry=retry - 1, version=version)
45
+
46
+ return ipaddress.ip_address(res)
47
+
48
+
49
+ def get_domain_ips(domain: str, retry: int = 3) -> Set[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
50
+ res = set()
51
+ if retry < 0:
52
+ return res
53
+ try:
54
+ _, _, ips = socket.gethostbyname_ex(domain)
55
+ for ip in ips:
56
+ res.add(ipaddress.ip_address(ip))
57
+ except Exception:
58
+ pass
59
+
60
+ try:
61
+ for ip in socket.getaddrinfo(domain, None, socket.AF_INET):
62
+ res.add(ipaddress.ip_address(ip[4][0]))
63
+ except BaseException:
64
+ pass
65
+
66
+ try:
67
+ for ip in socket.getaddrinfo(domain, None, socket.AF_INET6):
68
+ res.add(ipaddress.ip_address(ip[4][0]))
69
+ except BaseException:
70
+ pass
45
71
 
46
- return ipaddress.ip_address(res) or get_domain_ip(domain, retry=retry - 1) if res else None
72
+ return res or get_domain_ips(domain, retry=retry - 1)
47
73
 
48
74
 
49
75
  def get_socket_public_ip(version: Literal[4, 6]) -> Union[ipaddress.IPv4Address, ipaddress.IPv6Address, None]:
@@ -85,8 +111,11 @@ def get_interface_public_ip(version: Literal[4, 6]) -> List[Union[ipaddress.IPv4
85
111
 
86
112
 
87
113
  @cache.cache(ttl=600)
88
- def get_ips(version: Literal[4, 6]) -> List[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
114
+ def get_ips(version: Literal[4, 6] | None = None) -> List[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
115
+ if not version:
116
+ return [*get_ips(4), *get_ips(6)]
89
117
  addrs = []
118
+
90
119
  i_ips = get_interface_public_ip(version)
91
120
  if i_ips:
92
121
  addrs = i_ips
@@ -130,7 +130,7 @@ def get_proxies(child_id: int = 0, only_enabled=False) -> list['Proxy']:
130
130
  if not hconfig(ConfigEnum.vmess_enable, child_id):
131
131
  proxies = [c for c in proxies if 'vmess' not in c.proto]
132
132
  if not hconfig(ConfigEnum.vless_enable, child_id):
133
- proxies = [c for c in proxies if 'vless' not in c.proto]
133
+ proxies = [c for c in proxies if 'vless' not in c.proto or 'reality' in c.l3]
134
134
  if not hconfig(ConfigEnum.trojan_enable, child_id):
135
135
  proxies = [c for c in proxies if 'trojan' not in c.proto]
136
136
  if not hconfig(ConfigEnum.httpupgrade_enable, child_id):
@@ -223,8 +223,10 @@ def add_stream_settings(base: dict, proxy: dict):
223
223
  # THE CURRENT CODE WORKS BUT THE CORRECT CONDITINO SHOULD BE THIS:
224
224
  # ss['security'] == 'tls' or 'xtls' -----> ss['security'] in ['tls','xtls']
225
225
  # TODO: FIX THE CONDITION AND TEST CONFIGS ON THE CLIENT SIDE
226
-
227
- if ss['security'] == 'tls' or 'xtls' and proxy['proto'] != ProxyProto.ss:
226
+ if ss['security'] == 'reality':
227
+ ss['network'] = proxy['transport']
228
+ add_reality_stream(ss, proxy)
229
+ elif ss['security'] == 'tls' or 'xtls' and proxy['proto'] != ProxyProto.ss:
228
230
  ss['tlsSettings'] = {
229
231
  'serverName': proxy['sni'],
230
232
  'allowInsecure': proxy['allow_insecure'],
@@ -239,9 +241,7 @@ def add_stream_settings(base: dict, proxy: dict):
239
241
  # 'cipherSuites': '', # Go lang sets
240
242
  # 'rejectUnknownSni': '', # default is false
241
243
  }
242
- if ss['security'] == 'reality':
243
- ss['network'] = proxy['transport']
244
- add_reality_stream(ss, proxy)
244
+
245
245
  if proxy['l3'] == ProxyL3.kcp:
246
246
  ss['network'] = 'kcp'
247
247
  add_kcp_stream(ss, proxy)
@@ -249,7 +249,7 @@ def add_stream_settings(base: dict, proxy: dict):
249
249
  if proxy['l3'] == ProxyL3.h3_quic:
250
250
  add_quic_stream(ss, proxy)
251
251
 
252
- 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):
252
+ if (proxy['transport'] == 'tcp' and ss['security'] != 'reality') or (ss['security'] == 'none' and proxy['transport'] not in [ProxyTransport.httpupgrade, ProxyTransport.WS] and proxy['proto'] != ProxyProto.ss):
253
253
  ss['network'] = proxy['transport']
254
254
  add_tcp_stream(ss, proxy)
255
255
  if proxy['transport'] == ProxyTransport.h2 and ss['security'] == 'none' and ss['security'] != 'reality':
@@ -243,8 +243,8 @@ class ConfigEnum(metaclass=FastEnum):
243
243
  trojan_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
244
244
  reality_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
245
245
  tcp_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
246
- quic_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
247
- xtls_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
246
+ quic_enable = _BoolConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
247
+ xtls_enable = _BoolConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
248
248
  h2_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
249
249
 
250
250
  db_version = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
@@ -38,7 +38,7 @@ ShowDomain = db.Table('show_domain',
38
38
  class Domain(db.Model, SerializerMixin):
39
39
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
40
40
  child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0)
41
- domain = db.Column(db.String(200), nullable=False, unique=False)
41
+ domain = db.Column(db.String(200), nullable=True, unique=False)
42
42
  alias = db.Column(db.String(200))
43
43
  sub_link_only = db.Column(db.Boolean, nullable=False, default=False)
44
44
  mode = db.Column(db.Enum(DomainType), nullable=False, default=DomainType.direct)
@@ -65,7 +65,7 @@ class DomainAdmin(AdminLTEModelView):
65
65
  'domain': {
66
66
  'validators': [
67
67
  Regexp(
68
- r'^(\*\.)?([A-Za-z0-9\-\.]+\.[a-zA-Z]{2,})$',
68
+ r'^(\*\.)?([A-Za-z0-9\-\.]+\.[a-zA-Z]{2,})$|^$',
69
69
  message=__("Should be a valid domain"))]},
70
70
  "cdn_ip": {
71
71
  'validators': [
@@ -109,21 +109,24 @@ class DomainAdmin(AdminLTEModelView):
109
109
  f'</a><a href="{admin_link}" class="btn btn-xs btn-info ltr" target="_blank">{model.domain}</a></div>')
110
110
 
111
111
  def _domain_ip(view, context, model, name):
112
- dip = hutils.network.get_domain_ip(model.domain)
112
+ dips = hutils.network.get_domain_ips(model.domain)
113
113
  # The get_domain_ip function uses the socket library, which relies on the system DNS resolver. So it may sometimes use cached data, which is not desirable
114
- if not dip:
115
- dip = hutils.network.resolve_domain_with_api(model.domain)
116
- myip = hutils.network.get_ip(4)
117
- if myip == dip and model.mode in [DomainType.direct, DomainType.sub_link_only]:
118
- badge_type = ''
119
- elif dip and model.mode != DomainType.direct and myip != dip:
120
- badge_type = 'warning'
121
- else:
122
- badge_type = 'danger'
123
- res = f'<span class="badge badge-{badge_type}">{dip}</span>'
124
- if model.sub_link_only:
125
- res += f'<span class="badge badge-success">{_("SubLink")}</span>'
126
- return Markup(res)
114
+ # if not dips:
115
+ # dip = hutils.network.resolve_domain_with_api(model.domain)
116
+ myips = set(hutils.network.get_ips())
117
+ all_res = ""
118
+ for dip in dips:
119
+ if dip in myips and model.mode in [DomainType.direct, DomainType.sub_link_only]:
120
+ badge_type = ''
121
+ elif dip and dip not in myips and model.mode != DomainType.direct:
122
+ badge_type = 'warning'
123
+ else:
124
+ badge_type = 'danger'
125
+ res = f'<span class="badge badge-{badge_type}">{dip}</span>'
126
+ if model.sub_link_only:
127
+ res += f'<span class="badge badge-success">{_("SubLink")}</span>'
128
+ all_res += res
129
+ return Markup(all_res)
127
130
 
128
131
  def _show_domains_formater(view, context, model, name):
129
132
  if not len(model.show_domains):
@@ -149,8 +152,9 @@ class DomainAdmin(AdminLTEModelView):
149
152
 
150
153
  # TODO: refactor this function
151
154
  def on_model_change(self, form, model, is_created):
152
- model.domain = model.domain.lower()
153
-
155
+ model.domain = (model.domain or '').lower()
156
+ if model.domain == '' and model.mode != DomainType.fake:
157
+ raise ValidationError(_("domain.empty.allowed_for_fake_only"))
154
158
  configs = get_hconfigs()
155
159
  for c in configs:
156
160
  if "domain" in c and c not in [ConfigEnum.decoy_domain, ConfigEnum.reality_fallback_domain] and c.category != 'hidden':
@@ -174,7 +178,7 @@ class DomainAdmin(AdminLTEModelView):
174
178
  if "*" in model.domain and model.mode not in [DomainType.cdn, DomainType.auto_cdn_ip]:
175
179
  raise ValidationError(_("Domain can not be resolved! there is a problem in your domain"))
176
180
 
177
- skip_check = "*" in model.domain
181
+ skip_check = "*" in model.domain or model.domain == ""
178
182
  if hconfig(ConfigEnum.cloudflare) and model.mode not in [DomainType.fake, DomainType.relay, DomainType.reality]:
179
183
  try:
180
184
  proxied = model.mode in [DomainType.cdn, DomainType.auto_cdn_ip]
@@ -190,28 +194,30 @@ class DomainAdmin(AdminLTEModelView):
190
194
  # hutils.flask.flash(__("Using alias with special charachters may cause problem in some clients like FairVPN."), 'warning')
191
195
  # raise ValidationError(_("You have to add your cloudflare api key to use this feature: "))
192
196
 
193
- dip = hutils.network.get_domain_ip(model.domain)
197
+ dips = hutils.network.get_domain_ips(model.domain)
194
198
  if model.sub_link_only:
195
- if dip is None:
199
+ if not dips:
196
200
  raise ValidationError(_("Domain can not be resolved! there is a problem in your domain")) # type: ignore
197
201
  elif not skip_check:
198
- if dip is None:
202
+ if not dips:
199
203
  raise ValidationError(_("Domain can not be resolved! there is a problem in your domain")) # type: ignore
200
204
 
201
205
  domain_ip_is_same_as_panel = False
202
- domain_ip_is_same_as_panel |= dip in ipv4_list
203
- for ipv6 in ipv6_list:
204
- domain_ip_is_same_as_panel |= ipaddress.ip_address(dip) == ipaddress.ip_address(ipv6)
206
+ server_ips = [*ipv4_list, *ipv6_list]
207
+ for mip in server_ips:
208
+ domain_ip_is_same_as_panel |= mip in dips
209
+ server_ips_str = ', '.join(list(map(str, server_ips)))
210
+ dips_str = ', '.join(list(map(str, dips)))
205
211
 
206
212
  if model.mode == DomainType.direct and not domain_ip_is_same_as_panel:
207
213
  # 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')
208
214
  raise ValidationError(
209
- __("Domain IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode", server_ip=', '.join(list(map(str, ipv4_list))), domain_ip=dip)) # type: ignore
215
+ __("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
210
216
 
211
217
  if domain_ip_is_same_as_panel and model.mode in [DomainType.cdn, DomainType.relay, DomainType.fake, DomainType.auto_cdn_ip]:
212
218
  # # hutils.flask.flash(__(f"In CDN mode, Domain IP={dip} should be different to your ip={', '.join(list(map(str, ipv4_list)))}"), 'warning')
213
219
  raise ValidationError(__("In CDN mode, Domain IP=%(domain_ip)s should be different to your ip=%(server_ip)s",
214
- server_ip=', '.join(list(map(str, ipv4_list))), domain_ip=dip)) # type: ignore
220
+ server_ip=server_ips_str, domain_ip=dips_str)) # type: ignore
215
221
 
216
222
  # if model.mode in [DomainType.ss_faketls, DomainType.telegram_faketls]:
217
223
  # if len(Domain.query.filter(Domain.mode==model.mode and Domain.id!=model.id).all())>0:
@@ -219,10 +225,11 @@ class DomainAdmin(AdminLTEModelView):
219
225
 
220
226
  model.domain = model.domain.lower()
221
227
  if model.mode == DomainType.direct and model.cdn_ip:
228
+ model.cdn_ip = ""
222
229
  raise ValidationError(f"Specifying CDN IP is only valid for CDN mode")
223
230
 
224
231
  if model.mode == DomainType.fake and not model.cdn_ip:
225
- model.cdn_ip = str(ipv4_list[0])
232
+ model.cdn_ip = str(server_ips[0])
226
233
 
227
234
  # if model.mode==DomainType.fake and model.cdn_ip!=myip:
228
235
  # raise ValidationError(f"Specifying CDN IP is only valid for CDN mode")
@@ -230,8 +237,14 @@ class DomainAdmin(AdminLTEModelView):
230
237
  # # Update the many-to-many relationship
231
238
  if len(model.show_domains) == Domain.query.count():
232
239
  model.show_domains = []
233
-
234
- if model.mode == DomainType.reality:
240
+ if model.mode == DomainType.old_xtls_direct:
241
+ if not hconfig(ConfigEnum.xtls_enable):
242
+ set_hconfig(ConfigEnum.xtls_enable, True)
243
+ hutils.proxy.get_proxies().invalidate_all()
244
+ elif model.mode == DomainType.reality:
245
+ if not hconfig(ConfigEnum.reality_enable):
246
+ set_hconfig(ConfigEnum.reality_enable, True)
247
+ hutils.proxy.get_proxies().invalidate_all()
235
248
  model.servernames = (model.servernames or model.domain).lower()
236
249
  for v in set([model.domain, model.servernames]):
237
250
  for d in v.split(","):
@@ -240,9 +253,9 @@ class DomainAdmin(AdminLTEModelView):
240
253
  if not hutils.network.is_domain_reality_friendly(d): # the minimum requirement for the REALITY protocol is to have tls1.3 and h2
241
254
  raise ValidationError(_("Domain is not REALITY friendly!") + f' {d}')
242
255
 
243
- if not hutils.network.is_in_same_asn(d, ipv4_list[0]):
244
- server_asn = hutils.network.get_ip_asn(ipv4_list[0])
245
- domain_asn = hutils.network.get_ip_asn(dip) # type: ignore
256
+ if not hutils.network.is_in_same_asn(d, server_ips[0]):
257
+ server_asn = hutils.network.get_ip_asn(server_ips[0])
258
+ domain_asn = hutils.network.get_ip_asn(dips[0]) # type: ignore
246
259
  msg = _("domain.reality.asn_issue") + \
247
260
  (f"<br> Server ASN={server_asn}<br>{d}_ASN={domain_asn}" if server_asn or domain_asn else "")
248
261
  hutils.flask.flash(msg, 'warning')
@@ -69,7 +69,7 @@ class ProxyAdmin(FlaskView):
69
69
 
70
70
 
71
71
  def get_global_config_form(empty=False):
72
- boolconfigs = BoolConfig.query.all()
72
+ boolconfigs = BoolConfig.query.filter(BoolConfig.child_id == Child.current().id).all()
73
73
 
74
74
  class DynamicForm(FlaskForm):
75
75
  pass
@@ -4,6 +4,7 @@ import uuid
4
4
  # from flask_babelex import lazy_gettext as _
5
5
  from flask import render_template, g, request
6
6
  from flask_babel import gettext as _
7
+ from markupsafe import Markup
7
8
  import wtforms as wtf
8
9
  from flask_wtf import FlaskForm
9
10
  from flask_bootstrap import SwitchField
@@ -22,67 +23,46 @@ from hiddifypanel.models import *
22
23
  class QuickSetup(FlaskView):
23
24
  decorators = [login_required({Role.super_admin})]
24
25
 
26
+ def current_form(self, step=None, empty=False, next=False):
27
+ step = int(step or request.form.get("step") or request.args.get('step', "1"))
28
+ if next:
29
+ step = step + 1
30
+ form = {1: get_lang_form,
31
+ 2: get_quick_setup_form,
32
+ 3: get_proxy_form}
33
+
34
+ return form[step](empty=empty or next)
35
+
25
36
  def index(self):
26
37
  return render_template(
27
- 'quick_setup.html', lang_form=get_lang_form(),
28
- form=get_quick_setup_form(),
29
- ipv4=hutils.network.get_ip_str(4),
30
- ipv6=hutils.network.get_ip_str(6),
38
+ 'quick_setup.html',
39
+ form=self.current_form(),
40
+ # ipv4=hutils.network.get_ip_str(4),
41
+ # ipv6=hutils.network.get_ip_str(6),
31
42
  admin_link=admin_link(),
32
43
  show_domain_info=True)
33
44
 
34
45
  def post(self):
35
46
  if request.args.get('changepw') == "true":
36
47
  AdminUser.current_admin_or_owner().uuid = str(uuid.uuid4())
37
- set_hconfig(ConfigEnum.first_setup, False)
38
- quick_form = get_quick_setup_form()
39
- lang_form = get_lang_form()
40
- if lang_form.lang_submit.data:
41
- if lang_form.validate_on_submit():
42
- set_hconfig(ConfigEnum.lang, lang_form.admin_lang.data)
43
- set_hconfig(ConfigEnum.admin_lang, lang_form.admin_lang.data)
44
- set_hconfig(ConfigEnum.country, lang_form.country.data)
45
-
46
- flask_babel.refresh()
47
- hutils.flask.flash((_('quicksetup.setlang.success')), 'success')
48
- else:
49
- hutils.flask.flash((_('quicksetup.setlang.error')), 'danger')
48
+ db.session.commit()
50
49
 
50
+ set_hconfig(ConfigEnum.first_setup, False)
51
+ form = self.current_form()
52
+ if not form.validate_on_submit() or form.step.data not in ["1", "2", "3"]:
53
+ hutils.flask.flash(_('config.validation-error'), 'danger')
51
54
  return render_template(
52
- 'quick_setup.html', form=get_quick_setup_form(True),
53
- lang_form=get_lang_form(),
55
+ 'quick_setup.html', form=form,
54
56
  admin_link=admin_link(),
55
57
  ipv4=hutils.network.get_ip_str(4),
56
58
  ipv6=hutils.network.get_ip_str(6),
57
59
  show_domain_info=False)
58
-
59
- if quick_form.validate_on_submit():
60
- Domain.query.filter(Domain.domain == f'{hutils.network.get_ip_str(4)}.sslip.io').delete()
61
- db.session.add(Domain(domain=quick_form.domain.data.lower(), mode=DomainType.direct))
62
- set_hconfig(ConfigEnum.block_iran_sites, quick_form.block_iran_sites.data)
63
- set_hconfig(ConfigEnum.decoy_domain, quick_form.decoy_domain.data)
64
- # hiddify.bulk_register_configs([
65
- # # {"key": ConfigEnum.telegram_enable, "value": quick_form.enable_telegram.data == True},
66
- # # {"key": ConfigEnum.vmess_enable, "value": quick_form.enable_vmess.data == True},
67
- # # {"key": ConfigEnum.firewall, "value": quick_form.enable_firewall.data == True},
68
- # {"key": ConfigEnum.block_iran_sites, "value": quick_form.block_iran_sites.data == True},
69
- # # {"key":ConfigEnum.decoy_domain,"value":quick_form.decoy_domain.data}
70
- # ])
71
-
72
- from .Actions import Actions
73
- return Actions().reinstall(domain_changed=True)
74
- else:
75
- hutils.flask.flash(_('config.validation-error'), 'danger')
76
- return render_template(
77
- 'quick_setup.html', form=quick_form, lang_form=get_lang_form(True),
78
- ipv4=hutils.network.get_ip_str(4),
79
- ipv6=hutils.network.get_ip_str(6),
80
- admin_link=admin_link(),
81
- show_domain_info=False)
60
+ return form.post(self)
82
61
 
83
62
 
84
63
  def get_lang_form(empty=False):
85
64
  class LangForm(FlaskForm):
65
+ step = wtf.HiddenField(default="1")
86
66
  admin_lang = wtf.SelectField(
87
67
  _("config.admin_lang.label"), choices=[("en", _("lang.en")), ("fa", _("lang.fa")), ("pt", _("lang.pt")), ("zh", _("lang.zh")), ("ru", _("lang.ru"))],
88
68
  description=_("config.admin_lang.description"),
@@ -94,7 +74,61 @@ def get_lang_form(empty=False):
94
74
  default=hconfig(ConfigEnum.country))
95
75
  lang_submit = wtf.SubmitField(_('Submit'))
96
76
 
97
- return LangForm(None)if empty else LangForm()
77
+ def post(self, view):
78
+ set_hconfig(ConfigEnum.lang, self.admin_lang.data)
79
+ set_hconfig(ConfigEnum.admin_lang, self.admin_lang.data)
80
+ set_hconfig(ConfigEnum.country, self.country.data)
81
+
82
+ flask_babel.refresh()
83
+ hutils.flask.flash((_('quicksetup.setlang.success')), 'success')
84
+
85
+ return render_template(
86
+ 'quick_setup.html', form=view.current_form(next=True),
87
+ admin_link=admin_link(),
88
+ ipv4=hutils.network.get_ip_str(4),
89
+ ipv6=hutils.network.get_ip_str(6),
90
+ show_domain_info=False)
91
+
92
+ form = LangForm(None)if empty else LangForm()
93
+ form.step.data = "1"
94
+ return form
95
+
96
+
97
+ def get_proxy_form(empty=False):
98
+ class ProxyForm(FlaskForm):
99
+ step = wtf.HiddenField(default="3")
100
+ description_for_fieldset = wtf.TextAreaField("", description=_(f'quicksetup.proxy_cat.description'), render_kw={"class": "d-none"})
101
+
102
+ def post(self, view):
103
+
104
+ for k, vs in self.data.items():
105
+ ek = ConfigEnum[k]
106
+ if ek != ConfigEnum.not_found:
107
+ set_hconfig(ek, vs, commit=False)
108
+
109
+ db.session.commit()
110
+ # print(cat,vs)
111
+ hutils.proxy.get_proxies.invalidate_all()
112
+ if hutils.node.is_child():
113
+ hutils.node.run_node_op_in_bg(hutils.node.child.sync_with_parent, *[hutils.node.child.SyncFields.hconfigs])
114
+
115
+ from .Actions import Actions
116
+ return Actions().reinstall(domain_changed=True)
117
+ boolconfigs = BoolConfig.query.filter(BoolConfig.child_id == Child.current().id).all()
118
+
119
+ for cf in boolconfigs:
120
+ if cf.key.category == 'hidden':
121
+ continue
122
+ if cf.key.startswith("sub_") or cf.key.startswith("mux_"):
123
+ continue
124
+ if not cf.key.endswith("_enable") or cf.key in [ConfigEnum.hysteria_obfs_enable, ConfigEnum.tls_padding_enable]:
125
+ continue
126
+ field = SwitchField(_(f'config.{cf.key}.label'), default=cf.value, description=_(f'config.{cf.key}.description'))
127
+ setattr(ProxyForm, f'{cf.key}', field)
128
+ setattr(ProxyForm, "submit_global", wtf.fields.SubmitField(_('Submit')))
129
+ form = ProxyForm(None) if empty else ProxyForm()
130
+ form.step.data = "3"
131
+ return form
98
132
 
99
133
 
100
134
  def get_quick_setup_form(empty=False):
@@ -108,7 +142,9 @@ def get_quick_setup_form(empty=False):
108
142
  domains.append(d.domain)
109
143
  return domains
110
144
 
111
- class QuickSetupForm(FlaskForm):
145
+ class BasicConfigs(FlaskForm):
146
+ step = wtf.HiddenField(default="2")
147
+ description_for_fieldset = wtf.TextAreaField("", description=_(f'quicksetup.proxy_cat.description'), render_kw={"class": "d-none"})
112
148
  domain_regex = "^([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})$"
113
149
 
114
150
  domain_validators = [
@@ -116,6 +152,12 @@ def get_quick_setup_form(empty=False):
116
152
  validate_domain,
117
153
  wtf.validators.NoneOf([d.domain.lower() for d in Domain.query.all()], _("config.Domain_already_used")),
118
154
  wtf.validators.NoneOf([c.value.lower() for c in StrConfig.query.all() if "fakedomain" in c.key and c.key != ConfigEnum.decoy_domain], _("config.Domain_already_used"))]
155
+
156
+ cdn_domain_validators = [
157
+ wtf.validators.Regexp(f'({domain_regex})|(^$)', re.IGNORECASE, _("config.Invalid_domain")),
158
+ validate_domain_cdn,
159
+ wtf.validators.NoneOf([d.domain.lower() for d in Domain.query.all()], _("config.Domain_already_used")),
160
+ wtf.validators.NoneOf([c.value.lower() for c in StrConfig.query.all() if "fakedomain" in c.key and c.key != ConfigEnum.decoy_domain], _("config.Domain_already_used"))]
119
161
  domain = wtf.StringField(
120
162
  _("domain.domain"),
121
163
  domain_validators,
@@ -126,6 +168,16 @@ def get_quick_setup_form(empty=False):
126
168
  "title": domain_validators[0].message,
127
169
  "required": "",
128
170
  "placeholder": "sub.domain.com"})
171
+
172
+ cdn_domain = wtf.StringField(
173
+ _("quicksetup.cdn_domain.label"),
174
+ cdn_domain_validators,
175
+ description=_("quicksetup.cdn_domain.description"),
176
+ render_kw={
177
+ "class": "ltr",
178
+ "pattern": domain_validators[0].regex.pattern,
179
+ "title": domain_validators[0].message,
180
+ "placeholder": "sub.domain.com"})
129
181
  # enable_telegram = SwitchField(_("config.telegram_enable.label"), description=_("config.telegram_enable.description"), default=hconfig(ConfigEnum.telegram_enable))
130
182
  # enable_firewall = SwitchField(_("config.firewall.label"), description=_("config.firewall.description"), default=hconfig(ConfigEnum.firewall))
131
183
  block_iran_sites = SwitchField(_("config.block_iran_sites.label"), description=_(
@@ -135,7 +187,31 @@ def get_quick_setup_form(empty=False):
135
187
  ConfigEnum.decoy_domain), validators=[wtf.validators.Regexp(domain_regex, re.IGNORECASE, _("config.Invalid_domain")), hutils.flask.validate_domain_exist])
136
188
  submit = wtf.SubmitField(_('Submit'))
137
189
 
138
- return QuickSetupForm(None) if empty else QuickSetupForm()
190
+ def post(self, view):
191
+ Domain.query.filter(Domain.domain == f'{hutils.network.get_ip_str(4)}.sslip.io').delete()
192
+ db.session.add(Domain(domain=self.domain.data.lower(), mode=DomainType.direct))
193
+ if self.cdn_domain.data:
194
+ db.session.add(Domain(domain=self.cdn_domain.data.lower(), mode=DomainType.cdn))
195
+ set_hconfig(ConfigEnum.block_iran_sites, self.block_iran_sites.data)
196
+ set_hconfig(ConfigEnum.decoy_domain, self.decoy_domain.data)
197
+ # hiddify.bulk_register_configs([
198
+ # # {"key": ConfigEnum.telegram_enable, "value": quick_form.enable_telegram.data == True},
199
+ # # {"key": ConfigEnum.vmess_enable, "value": quick_form.enable_vmess.data == True},
200
+ # # {"key": ConfigEnum.firewall, "value": quick_form.enable_firewall.data == True},
201
+ # {"key": ConfigEnum.block_iran_sites, "value": quick_form.block_iran_sites.data == True},
202
+ # # {"key":ConfigEnum.decoy_domain,"value":quick_form.decoy_domain.data}
203
+ # ])
204
+
205
+ return render_template(
206
+ 'quick_setup.html', form=view.current_form(next=True),
207
+ # ipv4=hutils.network.get_ip_str(4),
208
+ # ipv6=hutils.network.get_ip_str(6),
209
+ admin_link=admin_link(),
210
+ show_domain_info=False)
211
+
212
+ form = BasicConfigs(None) if empty else BasicConfigs()
213
+ form.step.data = "2"
214
+ return form
139
215
 
140
216
 
141
217
  def validate_domain(form, field):
@@ -145,11 +221,26 @@ def validate_domain(form, field):
145
221
  raise ValidationError(_("Domain can not be resolved! there is a problem in your domain"))
146
222
 
147
223
  myip = hutils.network.get_ip(4)
148
- if dip and myip != dip:
224
+ myip6 = hutils.network.get_ip(4)
225
+ if dip and myip != dip and (not myip6 or myip6 != dip):
149
226
  raise ValidationError(_("Domain (%(domain)s)-> IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode",
150
227
  server_ip=myip, domain_ip=dip, domain=domain))
151
228
 
152
229
 
230
+ def validate_domain_cdn(form, field):
231
+ domain = field.data
232
+ if not domain:
233
+ return
234
+ dip = hutils.network.get_domain_ip(domain)
235
+ if dip is None:
236
+ raise ValidationError(_("Domain can not be resolved! there is a problem in your domain"))
237
+
238
+ myip = hutils.network.get_ip(4)
239
+ if myip == dip:
240
+ raise ValidationError(_("In CDN mode, Domain IP=%(domain_ip)s should be different to your ip=%(server_ip)s",
241
+ server_ip=myip, domain_ip=dip, domain=domain))
242
+
243
+
153
244
  def admin_link():
154
245
  domains = Domain.get_domains()
155
246
  return hiddify.get_account_panel_link(g.account, domains[0] if len(domains)else hutils.network.get_ip_str(4))
@@ -24,6 +24,7 @@ from hiddifypanel.models import *
24
24
  from hiddifypanel.database import db
25
25
  from hiddifypanel.panel import hiddify, custom_widgets
26
26
  from hiddifypanel import __version__
27
+ from hiddifypanel.cache import cache
27
28
 
28
29
 
29
30
  class SettingAdmin(FlaskView):
@@ -111,6 +112,8 @@ class SettingAdmin(FlaskView):
111
112
  if p_mode != PanelMode.standalone:
112
113
  set_hconfig(ConfigEnum.panel_mode, PanelMode.standalone)
113
114
 
115
+ cache.invalidate_all_cached_functions()
116
+ # hutils.proxy.get_proxies.invalidate_all()
114
117
  from hiddifypanel.panel.commercial.telegrambot import register_bot
115
118
  register_bot(set_hook=True)
116
119
 
@@ -194,13 +197,15 @@ def get_config_form():
194
197
  if c.key in bool_types:
195
198
  field = SwitchField(_(f'config.{c.key}.label'), default=c.value, description=_(f'config.{c.key}.description'))
196
199
  elif c.key == ConfigEnum.core_type:
197
- field = wtf.SelectField(_(f"config.{c.key}.label"), choices=[("xray", _("Xray")), ("singbox", _(
198
- "SingBox"))], description=_(f"config.{c.key}.description"), default=hconfig(c.key))
200
+ field = wtf.SelectField(_(f"config.{c.key}.label"),
201
+ choices=[("xray", _("Xray")), ("singbox", _("SingBox"))],
202
+ description=_(f"config.{c.key}.description"),
203
+ default=hconfig(c.key))
199
204
  elif c.key == ConfigEnum.warp_mode:
200
- field = wtf.SelectField(
201
- _(f"config.{c.key}.label"), choices=[("disable", _("Disable")), ("all", _("All")), ("custom", _("Only Blocked and Local websites"))],
202
- description=_(f"config.{c.key}.description"),
203
- default=hconfig(c.key))
205
+ field = wtf.SelectField(_(f"config.{c.key}.label"),
206
+ choices=[("disable", _("Disable")), ("all", _("All")), ("custom", _("Only Blocked and Local websites"))],
207
+ description=_(f"config.{c.key}.description"),
208
+ default=hconfig(c.key))
204
209
 
205
210
  elif c.key == ConfigEnum.lang or c.key == ConfigEnum.admin_lang:
206
211
  field = wtf.SelectField(
@@ -43,26 +43,17 @@
43
43
 
44
44
 
45
45
  <div class="row">
46
- <div class="card col-12">
47
- <div class="card-header">{{_("config.lang.label")}}</div>
48
- <div class="card-body">
49
46
 
50
- <div class="row">
51
- <div class="col-12">
52
47
 
53
- {{render_form(lang_form)}}
54
- </div>
55
- </div>
56
- </div>
57
- </div>
58
-
59
- <div class="card">
48
+ <div class="card col-12">
60
49
  <div class="card-header">{{_("admin.quicksetup.title")}}</div>
61
50
  <div class="card-body">
62
51
 
63
52
  <div class="row">
64
53
  <div class="card-columns">
54
+ {% if ipv4 or ipv6 %}
65
55
  {{_('admin.quicksetup_intro',ipv4=ip_btn(ipv4),ipv6=ip_btn(ipv6))}}
56
+ {%endif%}
66
57
  {{render_form(form,form_type="",extra_classes="card-columns1")}}
67
58
  </div>
68
59
  </div>
@@ -71,9 +62,24 @@
71
62
  </div>
72
63
 
73
64
  <style>
65
+ .form-group {
66
+ display: inline-block;
67
+ width: 100%;
68
+ }
69
+
70
+ fieldset {
71
+ margin: 20px 0;
72
+ }
73
+
74
+ legend {
75
+ background: transparent;
76
+ margin-bottom: 20px;
77
+
78
+ }
79
+
74
80
  @media (min-width: 576px) {
75
81
  .card-columns {
76
- column-count: 1;
82
+ column-count: 2;
77
83
  }
78
84
  }
79
85
 
@@ -14,7 +14,7 @@ from hiddifypanel.database import db, db_execute
14
14
  from flask import g
15
15
  from sqlalchemy import text
16
16
  from loguru import logger
17
- MAX_DB_VERSION = 90
17
+ MAX_DB_VERSION = 100
18
18
 
19
19
 
20
20
  def _v88(child_id):
@@ -47,11 +47,11 @@ def _v83(child_id):
47
47
 
48
48
  def _v82(child_id):
49
49
  set_hconfig(ConfigEnum.vless_enable, True)
50
- set_hconfig(ConfigEnum.trojan_enable, True)
51
- set_hconfig(ConfigEnum.reality_enable, True)
50
+ set_hconfig(ConfigEnum.trojan_enable, False)
51
+ set_hconfig(ConfigEnum.reality_enable, False)
52
52
  set_hconfig(ConfigEnum.tcp_enable, True)
53
- set_hconfig(ConfigEnum.quic_enable, True)
54
- set_hconfig(ConfigEnum.xtls_enable, True)
53
+ set_hconfig(ConfigEnum.quic_enable, False)
54
+ set_hconfig(ConfigEnum.xtls_enable, False)
55
55
  set_hconfig(ConfigEnum.h2_enable, True)
56
56
 
57
57
 
@@ -80,7 +80,7 @@ def _v75(child_id):
80
80
 
81
81
 
82
82
  def _v74(child_id):
83
- set_hconfig(ConfigEnum.ws_enable, True)
83
+ set_hconfig(ConfigEnum.ws_enable, False)
84
84
  set_hconfig(ConfigEnum.grpc_enable, True)
85
85
  set_hconfig(ConfigEnum.httpupgrade_enable, True)
86
86
  set_hconfig(ConfigEnum.shadowsocks2022_port, hutils.random.get_random_unused_port())
@@ -965,7 +965,7 @@ msgstr ""
965
965
  "%(default_link)s"
966
966
 
967
967
  msgid "admin.proxy.detailed_config"
968
- msgstr "⚙️ Detailed Configs"
968
+ msgstr "⚙️ Detailed Configs: Only enabled configs are shown."
969
969
 
970
970
  msgid "admin.proxy.global_config"
971
971
  msgstr "⚙️ Global Configs"
@@ -2340,6 +2340,9 @@ msgstr ""
2340
2340
  msgid "domain.domain_fronting.label"
2341
2341
  msgstr "🔒 TLS Domain Fronting"
2342
2342
 
2343
+ msgid "domain.empty.allowed_for_fake_only"
2344
+ msgstr "domain.empty.allowed_for_fake_only"
2345
+
2343
2346
  msgid "domain.intro"
2344
2347
  msgstr ""
2345
2348
  "1️⃣ In this section, you can add your Domain. \n"
@@ -2488,8 +2491,18 @@ msgstr "parent.sync-req-failed"
2488
2491
  msgid "previous"
2489
2492
  msgstr "Previous"
2490
2493
 
2491
- msgid "quicksetup.setlang.error"
2492
- msgstr "An error occurred while changing language."
2494
+ msgid "quicksetup.cdn_domain.description"
2495
+ msgstr ""
2496
+ "Setting CDN domain is optional. Only use it if you have already config a "
2497
+ "CDN."
2498
+
2499
+ msgid "quicksetup.cdn_domain.label"
2500
+ msgstr "CDN Domain"
2501
+
2502
+ msgid "quicksetup.proxy_cat.description"
2503
+ msgstr ""
2504
+ "Final Step: Please select the proxies you want. Please choose minimum as "
2505
+ "possible."
2493
2506
 
2494
2507
  msgid "quicksetup.setlang.success"
2495
2508
  msgstr "Changing the Language was Successful."
@@ -953,7 +953,7 @@ msgstr ""
953
953
  "%(default_link)s"
954
954
 
955
955
  msgid "admin.proxy.detailed_config"
956
- msgstr "⚙️ تنظیمات دقیق"
956
+ msgstr "⚙️ تنظیمات دقیق: فقط کانفیگ های فعال نمایش داده می‌شود."
957
957
 
958
958
  msgid "admin.proxy.global_config"
959
959
  msgstr "⚙️ تنظیمات عمومی"
@@ -2345,6 +2345,9 @@ msgstr ""
2345
2345
  msgid "domain.domain_fronting.label"
2346
2346
  msgstr "🔒 فعال کردن دامین فرانتینگ در اتصال TLS"
2347
2347
 
2348
+ msgid "domain.empty.allowed_for_fake_only"
2349
+ msgstr ""
2350
+
2348
2351
  msgid "domain.intro"
2349
2352
  msgstr ""
2350
2353
 
@@ -2486,8 +2489,18 @@ msgstr ""
2486
2489
  msgid "previous"
2487
2490
  msgstr "قبلی"
2488
2491
 
2489
- msgid "quicksetup.setlang.error"
2490
- msgstr "خطایی در تغییر زبان رخ داد"
2492
+ msgid "quicksetup.cdn_domain.description"
2493
+ msgstr ""
2494
+ "تنظیم دامنه CDN اختیاری است. فقط در صورتی از آن استفاده کنید که قبلاً یک CDN"
2495
+ " را پیکربندی کرده باشید."
2496
+
2497
+ msgid "quicksetup.cdn_domain.label"
2498
+ msgstr "دامنه CDN"
2499
+
2500
+ msgid "quicksetup.proxy_cat.description"
2501
+ msgstr ""
2502
+ "مرحله آخر: لطفا پراکسی های مورد نظر خود را انتخاب کنید. لطفا حداقل تا حد "
2503
+ "امکان را انتخاب کنید."
2491
2504
 
2492
2505
  msgid "quicksetup.setlang.success"
2493
2506
  msgstr "تغییر زبان با موفقیت انجام شد"
@@ -2251,6 +2251,9 @@ msgstr ""
2251
2251
  msgid "domain.domain_fronting.label"
2252
2252
  msgstr "🔒 Habilitar fronting de domínio TLS"
2253
2253
 
2254
+ msgid "domain.empty.allowed_for_fake_only"
2255
+ msgstr ""
2256
+
2254
2257
  msgid "domain.intro"
2255
2258
  msgstr ""
2256
2259
 
@@ -2394,8 +2397,14 @@ msgstr ""
2394
2397
  msgid "previous"
2395
2398
  msgstr "Anterior"
2396
2399
 
2397
- msgid "quicksetup.setlang.error"
2398
- msgstr "Ocorreu um erro ao alterar o idioma."
2400
+ msgid "quicksetup.cdn_domain.description"
2401
+ msgstr ""
2402
+
2403
+ msgid "quicksetup.cdn_domain.label"
2404
+ msgstr ""
2405
+
2406
+ msgid "quicksetup.proxy_cat.description"
2407
+ msgstr ""
2399
2408
 
2400
2409
  msgid "quicksetup.setlang.success"
2401
2410
  msgstr "A alteração do idioma foi bem-sucedida."
@@ -2358,6 +2358,9 @@ msgstr ""
2358
2358
  msgid "domain.domain_fronting.label"
2359
2359
  msgstr "🔒 Включить подключение к домену TLS"
2360
2360
 
2361
+ msgid "domain.empty.allowed_for_fake_only"
2362
+ msgstr ""
2363
+
2361
2364
  msgid "domain.intro"
2362
2365
  msgstr ""
2363
2366
 
@@ -2504,8 +2507,14 @@ msgstr ""
2504
2507
  msgid "previous"
2505
2508
  msgstr "Предыдущий"
2506
2509
 
2507
- msgid "quicksetup.setlang.error"
2508
- msgstr "Произошла ошибка при смене языка."
2510
+ msgid "quicksetup.cdn_domain.description"
2511
+ msgstr ""
2512
+
2513
+ msgid "quicksetup.cdn_domain.label"
2514
+ msgstr ""
2515
+
2516
+ msgid "quicksetup.proxy_cat.description"
2517
+ msgstr ""
2509
2518
 
2510
2519
  msgid "quicksetup.setlang.success"
2511
2520
  msgstr "Изменение языка прошло успешно."
@@ -2176,6 +2176,9 @@ msgstr ""
2176
2176
  msgid "domain.domain_fronting.label"
2177
2177
  msgstr "🔒 启用 TLS 域前置"
2178
2178
 
2179
+ msgid "domain.empty.allowed_for_fake_only"
2180
+ msgstr ""
2181
+
2179
2182
  msgid "domain.intro"
2180
2183
  msgstr ""
2181
2184
 
@@ -2314,8 +2317,14 @@ msgstr ""
2314
2317
  msgid "previous"
2315
2318
  msgstr "以前的"
2316
2319
 
2317
- msgid "quicksetup.setlang.error"
2318
- msgstr "更改语言时发生错误。"
2320
+ msgid "quicksetup.cdn_domain.description"
2321
+ msgstr ""
2322
+
2323
+ msgid "quicksetup.cdn_domain.label"
2324
+ msgstr ""
2325
+
2326
+ msgid "quicksetup.proxy_cat.description"
2327
+ msgstr ""
2319
2328
 
2320
2329
  msgid "quicksetup.setlang.success"
2321
2330
  msgstr "更改语言成功。"
@@ -260,7 +260,7 @@
260
260
  },
261
261
  "no_user_warning": "It seems that you have not created any users yet. default user link: %(default_link)s",
262
262
  "proxy": {
263
- "detailed_config": "⚙️ Detailed Configs",
263
+ "detailed_config": "⚙️ Detailed Configs: Only enabled configs are shown.",
264
264
  "global_config": "⚙️ Global Configs"
265
265
  },
266
266
  "quicksetup": {
@@ -1026,6 +1026,9 @@
1026
1026
  "description": "It is used to simulate another website instead of your website in SNI. therefore, GFW can not filter your Domain\n<a href='https://github.com/hiddify/hiddify-config/wiki/Guide-for-domain-fronting'>Guide</a>. ⚠️CloudFlare does not support Domain Fronting.",
1027
1027
  "label": "🔒 TLS Domain Fronting"
1028
1028
  },
1029
+ "empty": {
1030
+ "allowed_for_fake_only": "domain.empty.allowed_for_fake_only"
1031
+ },
1029
1032
  "intro": "1️⃣ In this section, you can add your Domain. \n<br>\n2️⃣ If you want to lessen the probability of having dirty IP, you can add Multiple Relay Server <a href='https://github.com/hiddify/hiddify-config/discussions/129'>Read More</a>.\n<br>\n3️⃣ If you have Multiple IPv4 or IPv6 in your Panel you have to add the domain pointed to them as Relay.",
1030
1033
  "ip": "IP",
1031
1034
  "mode": "Mode",
@@ -1099,8 +1102,14 @@
1099
1102
  },
1100
1103
  "previous": "Previous",
1101
1104
  "quicksetup": {
1105
+ "cdn_domain": {
1106
+ "description": "Setting CDN domain is optional. Only use it if you have already config a CDN.",
1107
+ "label": "CDN Domain"
1108
+ },
1109
+ "proxy_cat": {
1110
+ "description": "Final Step: Please select the proxies you want. Please choose minimum as possible."
1111
+ },
1102
1112
  "setlang": {
1103
- "error": "An error occurred while changing language.",
1104
1113
  "success": "Changing the Language was Successful."
1105
1114
  }
1106
1115
  },
@@ -260,7 +260,7 @@
260
260
  },
261
261
  "no_user_warning": "شما هنوز هیچ کاربری ایجاد نکرده اید. لینک صفحه کاربری پیشفرض: %(default_link)s",
262
262
  "proxy": {
263
- "detailed_config": "⚙️ تنظیمات دقیق",
263
+ "detailed_config": "⚙️ تنظیمات دقیق: فقط کانفیگ های فعال نمایش داده می‌شود.",
264
264
  "global_config": "⚙️ تنظیمات عمومی"
265
265
  },
266
266
  "quicksetup": {
@@ -1026,6 +1026,9 @@
1026
1026
  "description": "برای شبیه سازی وب سایت دیگری به جای وب سایت شما در SNI استفاده می شود. بنابراین، فیلترچی نمی تواند دامنه شما را فیلتر کند. \n<a href='https://github.com/hiddify/hiddify-config/wiki/استفاده-از-دامین-فرانتینگ'>آموزش ثبت </a>\n\n⚠️CloudFlare از دامین فرانتینگ پشتیبانی نمی کند.",
1027
1027
  "label": "🔒 فعال کردن دامین فرانتینگ در اتصال TLS"
1028
1028
  },
1029
+ "empty": {
1030
+ "allowed_for_fake_only": ""
1031
+ },
1029
1032
  "intro": "",
1030
1033
  "ip": "آی‌پی",
1031
1034
  "mode": "حالت",
@@ -1099,8 +1102,14 @@
1099
1102
  },
1100
1103
  "previous": "قبلی",
1101
1104
  "quicksetup": {
1105
+ "cdn_domain": {
1106
+ "description": "تنظیم دامنه CDN اختیاری است. فقط در صورتی از آن استفاده کنید که قبلاً یک CDN را پیکربندی کرده باشید.",
1107
+ "label": "دامنه CDN"
1108
+ },
1109
+ "proxy_cat": {
1110
+ "description": "مرحله آخر: لطفا پراکسی های مورد نظر خود را انتخاب کنید. لطفا حداقل تا حد امکان را انتخاب کنید."
1111
+ },
1102
1112
  "setlang": {
1103
- "error": "خطایی در تغییر زبان رخ داد",
1104
1113
  "success": "تغییر زبان با موفقیت انجام شد"
1105
1114
  }
1106
1115
  },
@@ -1026,6 +1026,9 @@
1026
1026
  "description": "É usado para simular outro site em vez do seu site no SNI. portanto, o GFW não pode filtrar seu domínio\n<a href='https://github.com/hiddify/hiddify-config/wiki/Guide-for-domain-fronting'>Guia</a>. ⚠️CloudFlare não suporta fronting de domínio.",
1027
1027
  "label": "🔒 Habilitar fronting de domínio TLS"
1028
1028
  },
1029
+ "empty": {
1030
+ "allowed_for_fake_only": ""
1031
+ },
1029
1032
  "intro": "",
1030
1033
  "ip": "IP",
1031
1034
  "mode": "Modo",
@@ -1099,8 +1102,14 @@
1099
1102
  },
1100
1103
  "previous": "Anterior",
1101
1104
  "quicksetup": {
1105
+ "cdn_domain": {
1106
+ "description": "",
1107
+ "label": ""
1108
+ },
1109
+ "proxy_cat": {
1110
+ "description": ""
1111
+ },
1102
1112
  "setlang": {
1103
- "error": "Ocorreu um erro ao alterar o idioma.",
1104
1113
  "success": "A alteração do idioma foi bem-sucedida."
1105
1114
  }
1106
1115
  },
@@ -1026,6 +1026,9 @@
1026
1026
  "description": "Он используется для имитации другого веб-сайта вместо вашего веб-сайта в SNI следовательно, GTW не может отфильтровать ваш домен\n<<a href='https://github.com/hibbity/hibbity-config/wiki/Guide-for-domain-fronting '>Руководство</a>. ⚠CloudFlare не поддерживает подключение к домену.",
1027
1027
  "label": "🔒 Включить подключение к домену TLS"
1028
1028
  },
1029
+ "empty": {
1030
+ "allowed_for_fake_only": ""
1031
+ },
1029
1032
  "intro": "",
1030
1033
  "ip": "IP",
1031
1034
  "mode": "Режим",
@@ -1099,8 +1102,14 @@
1099
1102
  },
1100
1103
  "previous": "Предыдущий",
1101
1104
  "quicksetup": {
1105
+ "cdn_domain": {
1106
+ "description": "",
1107
+ "label": ""
1108
+ },
1109
+ "proxy_cat": {
1110
+ "description": ""
1111
+ },
1102
1112
  "setlang": {
1103
- "error": "Произошла ошибка при смене языка.",
1104
1113
  "success": "Изменение языка прошло успешно."
1105
1114
  }
1106
1115
  },
@@ -1026,6 +1026,9 @@
1026
1026
  "description": "它用于在 SNI 中模拟另一个网站而不是您的网站。因此,GFW 无法过滤您的域名\n<a href='https://github.com/hiddify/hiddify-config/wiki/Guide-for-domain-fronting'>指南</a>。 ⚠️CloudFlare 不支持域前置。",
1027
1027
  "label": "🔒 启用 TLS 域前置"
1028
1028
  },
1029
+ "empty": {
1030
+ "allowed_for_fake_only": ""
1031
+ },
1029
1032
  "intro": "",
1030
1033
  "ip": "知识产权",
1031
1034
  "mode": "模式",
@@ -1099,8 +1102,14 @@
1099
1102
  },
1100
1103
  "previous": "以前的",
1101
1104
  "quicksetup": {
1105
+ "cdn_domain": {
1106
+ "description": "",
1107
+ "label": ""
1108
+ },
1109
+ "proxy_cat": {
1110
+ "description": ""
1111
+ },
1102
1112
  "setlang": {
1103
- "error": "更改语言时发生错误。",
1104
1113
  "success": "更改语言成功。"
1105
1114
  }
1106
1115
  },
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hiddifypanel
3
- Version: 10.30.9.dev0
3
+ Version: 10.30.9.dev2
4
4
  Summary: hiddifypanel multi proxy panel
5
5
  Home-page: https://github.com/hiddify/hiddify-manager/
6
6
  Author: hiddify
@@ -1,11 +1,11 @@
1
1
  hiddifypanel/Events.py,sha256=AlnRdjVul0jP-NCT4-zoaQgowoOo-JhdQB4ytetAFKA,723
2
- hiddifypanel/VERSION,sha256=AVxY-e9QofB7CHv6wUGPAAmVSSDZykdyCFq1B0yMIQA,13
3
- hiddifypanel/VERSION.py,sha256=yGAHE_66mKFbnR9QFfUAtfBVkXW_4SkkmEIbwQbJA9U,118
2
+ hiddifypanel/VERSION,sha256=Y6IENmPdjXKcyFlyeQEdpnopW1VkZD3KlHmAS1UFMyo,13
3
+ hiddifypanel/VERSION.py,sha256=PCPEWTyKxxkXM5tojvD0a2up6INqf7ZCIxDtdstpnc4,118
4
4
  hiddifypanel/__init__.py,sha256=aLukp3ORszdcH4G9J-MlxhjHN6yFlOuOE6mm-L3aG_g,266
5
5
  hiddifypanel/__main__.py,sha256=IVchnXpK6bm8T3N--mN17HBQNLMeLAjyP7iwzULexB4,218
6
6
  hiddifypanel/auth.py,sha256=Xq0UwiFTRFmQpxnOehQGwPDlJqoelwGhPQbYZ0Xn5c0,7850
7
7
  hiddifypanel/base.py,sha256=vnN0o7KFNZIQSix_TmYTRYVMRHioQ2TDCAV6LV20XWI,6079
8
- hiddifypanel/cache.py,sha256=6snErbx9rD6XSC2fO79XZy3EGMJoZB-yhnAMEWTPWAg,880
8
+ hiddifypanel/cache.py,sha256=H-QhHbQbz0Avh_ntjPntzhnFJOKdLTJyIaovtOYH1GE,1507
9
9
  hiddifypanel/database.py,sha256=14sfbGEG-NCqkfUtyLvcO2JbkQ3-Fzs-MezPNkNbvgk,717
10
10
  hiddifypanel/drivers/abstract_driver.py,sha256=HpWkgbWVWF8n3WhDe0BlxsIF1WTWO57AQEAEb2ZVCPM,223
11
11
  hiddifypanel/drivers/singbox_api.py,sha256=gdP_RM8b7qvDpN9RzUyJJ9i_MtMOpATx0LVDLEmDMjs,2270
@@ -29,7 +29,7 @@ hiddifypanel/hutils/importer/xui.py,sha256=TtmF4KJ263k3ByUvOeVKPlsGfj0tHLdlSdUQs
29
29
  hiddifypanel/hutils/network/__init__.py,sha256=wQ1atebA98SC0agNc_Tbe4ct1aIIKaXOniSEyTE2PKo,348
30
30
  hiddifypanel/hutils/network/auto_ip_selector.py,sha256=uSQjxnqI7NdJ6N_jCNtHAGLwjRjHagBG4GeR0lhD-HM,5667
31
31
  hiddifypanel/hutils/network/cf_api.py,sha256=RgOGhx936VcMq_WpDc_xCtMhanMkh9zKdeBpSij5rcM,2611
32
- hiddifypanel/hutils/network/net.py,sha256=qGU-1lGjGwqWZ6ycv1FBgZngjxDcB-sDJwfy3VW0tV4,11248
32
+ hiddifypanel/hutils/network/net.py,sha256=IaoLd8p4GNrMRkKtoiXFqRHWxdnwgPAOkAkr5CcwU9s,12043
33
33
  hiddifypanel/hutils/node/__init__.py,sha256=p9-nse5h2p3SX6XdU33GOqOX-8OfvmdkDRmIq3cWDWM,63
34
34
  hiddifypanel/hutils/node/api_client.py,sha256=Gr2532czQEE3YBh3sbeK036QI5gXDigUFlrMdJuO2sE,3684
35
35
  hiddifypanel/hutils/node/child.py,sha256=oAyKlEHHn9FHcpZ9jBi3nYH-GHs8H7Gi2hzkmtO5IA8,6714
@@ -37,17 +37,17 @@ hiddifypanel/hutils/node/parent.py,sha256=UbyfvfP4fTSn6HN9oZDjYsKYIejiqW6eApKIfP
37
37
  hiddifypanel/hutils/node/shared.py,sha256=FDSj3e-i3pb3mEv5vcUeX0Km1nxYg1CeAruIq7RwFmU,2540
38
38
  hiddifypanel/hutils/proxy/__init__.py,sha256=xXBa83kjYT_b-BNseEykfQYyJBQHTq1ZosfR8ZrQHkI,106
39
39
  hiddifypanel/hutils/proxy/clash.py,sha256=t57ywMo2TPpnAIuOn9v5gMD2os7zqS9b4NQtFX-Do5s,5813
40
- hiddifypanel/hutils/proxy/shared.py,sha256=kfjvqkweQGPpdic-f5Og9LSenp73Vjtu4qy5BkgSUOU,21811
40
+ hiddifypanel/hutils/proxy/shared.py,sha256=O7lVTUlNo-kbI0P2DMG9ZdmPypsrm8eoWUJeGIGEK3A,21832
41
41
  hiddifypanel/hutils/proxy/singbox.py,sha256=WBSsGF7QeNvDPg0SbfWitV2_CP6UQ0gcV5-Gpy4AlkY,10786
42
42
  hiddifypanel/hutils/proxy/xray.py,sha256=LFHjgQhebN4Kw1XzMDRk7F_K-2DSL93wkad12XijzBA,10694
43
- hiddifypanel/hutils/proxy/xrayjson.py,sha256=nBzVNpE9TCTk1y1WuZiFHBJZhY6Cq27QCWtOTww0z7g,14447
43
+ hiddifypanel/hutils/proxy/xrayjson.py,sha256=Ph1m_ZKINZ57XyWcnhp5mjASWL4ahj8ObVu3Kd7O8ZI,14452
44
44
  hiddifypanel/models/__init__.py,sha256=PngFjQL9WvQP4EioNHRz1tTeyIgLoNvZ7WpmAhwKHnU,677
45
45
  hiddifypanel/models/admin.py,sha256=qZ-BRJ_Gn6hJNWz35SQQSds1CoeDslU9B0MDBRhjPSM,7596
46
46
  hiddifypanel/models/base_account.py,sha256=TUGDGHt3q3GWqWBdWwqaZl75KXTt7bw6pxnzOWAbkjI,3454
47
47
  hiddifypanel/models/child.py,sha256=ZFJaH-GWTKAGD0BGMH0iKEMipi37_cAk59OeJKt2IKA,3039
48
48
  hiddifypanel/models/config.py,sha256=-KKYqMkSEn2DabRxqBogSyA6xOU4ons6sa5CxxHAlAk,6373
49
- hiddifypanel/models/config_enum.py,sha256=iqPuwirmyMcQi20UBI-EngTPpn82ryC9kpsYWvGpXR4,15366
50
- hiddifypanel/models/domain.py,sha256=kpiyN7-HeDgKSPXia6fMgox5Onefg5FDjxxRkmAil5A,8017
49
+ hiddifypanel/models/config_enum.py,sha256=KDDXdYfNKjY3SUvmmhAJqLQ5cshFAsQjtqgZ8jbrjo8,15364
50
+ hiddifypanel/models/domain.py,sha256=szrSdqGZBZ4lS_D_K-XO8OUjU4ojKrxnYzXy5MgU2QA,8016
51
51
  hiddifypanel/models/parent_domain.py,sha256=bs5F1neOAQu9XHEk3QQTBM4p2iuebM4cnAQqwfNjCtg,2291
52
52
  hiddifypanel/models/proxy.py,sha256=9cm5Q0ZUEPeRDWdm1lQGom0SM_Q32NCDFTNFh36OzaQ,3304
53
53
  hiddifypanel/models/report.py,sha256=33h9k12SAEWkwZsc3-jUdIIpFL66cEOTHQqVXd07NWY,1001
@@ -63,7 +63,7 @@ hiddifypanel/panel/cli.py,sha256=GNK-lqoedepG6hfpLHTPLxBaMsdjbQHZAw-qKjdRxnQ,859
63
63
  hiddifypanel/panel/common.py,sha256=3jMmdoMk-qvdT8mSmIXEBh9y54P81EsWUKmGeK9qQKg,7593
64
64
  hiddifypanel/panel/custom_widgets.py,sha256=9qI_fNX8NKqB1r8ljgcaisGZaDM89_PM_rOBZbGaTYs,2506
65
65
  hiddifypanel/panel/hiddify.py,sha256=Tj2WSjNrlRJ3yahFINCTQSn36ygBgFB3SQRr9MegLuE,15572
66
- hiddifypanel/panel/init_db.py,sha256=n6woa0_WORC8Gc3YS4YAIfgfAMj_2pAqlOnzykQX8ME,33391
66
+ hiddifypanel/panel/init_db.py,sha256=wewSjqu9LwvD9UiTtrAe4Y6BVl6EjzxwZ7ONUxwaWes,33397
67
67
  hiddifypanel/panel/run_commander.py,sha256=D9y-My0xSe2adHWXKV5UPYGl-9WwKURzniq55MRu6tE,3259
68
68
  hiddifypanel/panel/usage.py,sha256=LBmM5pKPbCxBxFozPjrXIypNVMlBn4ZyO46t5VBCNKg,6137
69
69
  hiddifypanel/panel/admin/Actions.py,sha256=yRMKuCZ7J8F8KLlIfFUTYhdL19zVC_tujzZUWmTmCOA,8573
@@ -71,11 +71,11 @@ hiddifypanel/panel/admin/AdminstratorAdmin.py,sha256=eUUe5b8bGPj2nZstKkwK3lhqBhM
71
71
  hiddifypanel/panel/admin/Backup.py,sha256=BKSoAZgw1j16P1Jh9vMqGj7ZfB2m-WafDK0C5vil5FY,3634
72
72
  hiddifypanel/panel/admin/ConfigAdmin.py,sha256=0hnLY-8BxrpVnrAcQaedWjHnRUq1X_Styi_ZCZ2ivds,2876
73
73
  hiddifypanel/panel/admin/Dashboard.py,sha256=JOqZLHxPOYKQYQVJ7AtHAkilH-anJZQyK1rQrgCJUeA,3798
74
- hiddifypanel/panel/admin/DomainAdmin.py,sha256=XD_PoXlqPeJPGhBE-wnXx6W--ZxlgZ1MCWCQcTuHrtg,14975
74
+ hiddifypanel/panel/admin/DomainAdmin.py,sha256=rAtLUgVHXarbqAsfskW-77oSpulWZ6bI4Gb0hHW79aU,15747
75
75
  hiddifypanel/panel/admin/NodeAdmin.py,sha256=QAHQjF7e7F4KqsWNWpMt7SoLANlFEborVtWQV9OXJ2E,3102
76
- hiddifypanel/panel/admin/ProxyAdmin.py,sha256=GzuRB9dcnjX_E1LxQoB8ZeD3ivRxbAY9Re7ykwijH9I,5193
77
- hiddifypanel/panel/admin/QuickSetup.py,sha256=ZFQd9qwOSZQvkqm3Hczpe5FYRuVRYN0mRjU69T4uE0E,7591
78
- hiddifypanel/panel/admin/SettingAdmin.py,sha256=Y9vM3pQSU_cgNeBTs7kf7uUuFfInWj7Uqf15WwzV2o8,19250
76
+ hiddifypanel/panel/admin/ProxyAdmin.py,sha256=jiay6e9Eyi_-VgWORBLgCAyzxLRYCAyJnlG7DtFaQIc,5243
77
+ hiddifypanel/panel/admin/QuickSetup.py,sha256=EDa_ombxF3vWDsj7JEmDnw8Kf0bKwdXU-IdISDi2hj0,11448
78
+ hiddifypanel/panel/admin/SettingAdmin.py,sha256=EMBAW4v4F4dFpz3ApfT2HiXMtqSnQA1DfaUj4oAMuwU,19553
79
79
  hiddifypanel/panel/admin/Terminal.py,sha256=rzZWRjMhjVnAvC65rfE3HJT3boUDznI6fl-htzKp7sI,1712
80
80
  hiddifypanel/panel/admin/UserAdmin.py,sha256=UPPg92NGxclBKE-inYas58Lz2bc06oFibSMdygQaC2M,18020
81
81
  hiddifypanel/panel/admin/__init__.py,sha256=hb0A2HuK_nBZRCNPumwahXX-25FMxODKYlNbk2ItF08,3015
@@ -93,7 +93,7 @@ hiddifypanel/panel/admin/templates/index.html,sha256=4QPq8ATHmzaEpMjLkxCRpTTaZZ1
93
93
  hiddifypanel/panel/admin/templates/ltemaster.html,sha256=KE_HsUOIR__BG1fW8DZ05rhgckQ8ls0a-ho6dWtmuX4,1080
94
94
  hiddifypanel/panel/admin/templates/parent_dash.html,sha256=kAVBwv287oaQFfNmvTxBqgaZOaAf1Nz6jPXfEZMfTXQ,1814
95
95
  hiddifypanel/panel/admin/templates/proxy.html,sha256=Q-Flp_O1LuuJnwWbodte2yr96MGzDoqgU50kB4dcsf0,1777
96
- hiddifypanel/panel/admin/templates/quick_setup.html,sha256=kv0kwHQLH9y8ayNaUGQVCkVRmK2wOSl2gqz-vBsQYzU,2127
96
+ hiddifypanel/panel/admin/templates/quick_setup.html,sha256=tYZnRBH682eThl6lQcnLNKIdCQDTWRZWccIZSiNxSlA,2101
97
97
  hiddifypanel/panel/admin/templates/redirect_to_admin.html,sha256=ivXFEUOv-3sKCJYPlJGjIrALxTaqq9SkjW5NLDKB3DI,139
98
98
  hiddifypanel/panel/admin/templates/result.html,sha256=q8mZDl0Wmzxy23TP9YZBOZ2Gsklvuzfewd1ce0FogFc,6786
99
99
  hiddifypanel/panel/admin/templates/view_logs.html,sha256=cemHWjYifbPVgaa9CuHf2nKOwTnYuBura9oZ7NKCBW0,771
@@ -822,24 +822,24 @@ hiddifypanel/templates/redirect.html,sha256=K9x_O4P96vEkqBhOXIhoGrWw1KIqd2bL0BjI
822
822
  hiddifypanel/templates/static.html,sha256=jp6q4wtx-k2A_cjqJoNiMS7Ee30arE45qI3ev4d5ky4,165
823
823
  hiddifypanel/templates/hiddify-flask-admin/actions.html,sha256=2NeITe2e-lPKCk_o511tCIqVtrPu8LYHE1wTCtrFUrI,1331
824
824
  hiddifypanel/templates/hiddify-flask-admin/list.html,sha256=MBGrTqZpzNLe4sZy0RozvXNr8seFUQc2C6v88BJtNWc,11095
825
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo,sha256=Y83ftCvxlGomDLWBO9WqTX6mEUhPmivFEInyVXiIoUc,75406
826
- hiddifypanel/translations/en/LC_MESSAGES/messages.po,sha256=kG0aufelFgV56J3oy53cscPAP_VLdktKKwiR1pMi2xk,78552
827
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo,sha256=J4uDA_wyALIRNGQIuKcdam4qKEaCwJZXahBYeAy6zvc,95609
828
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po,sha256=5sHqx3IUAabwa8ROuDsTpfvianoVxlkhYJOqnHZdbZ4,100916
829
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo,sha256=4TqaAjkcK9Z33NJbBRLhqjeuKz_0d5JCahSOFaGPjIY,58727
830
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po,sha256=-bl1ASJ9cdgrgvtyHvUTka0_nEzE50RfQP619y4ePiI,69275
831
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo,sha256=OWRHhfFoW0mnyOI1m3wMYa1VyCECI6nNCqpS0m3G_QI,97723
832
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po,sha256=EADJZxU2ey3IombHZFNkj7DZnCn9FDuIBHYM5BPqT_E,104523
833
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo,sha256=alHISYgjc6FngwOkFAx_4g4Qryyw0PxNQjMf2J6Z1EY,59038
834
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po,sha256=5CrTLK1cudiJSMkAHg7ftAciA28WfNwdyDyslLc9xDs,68497
835
- hiddifypanel/translations.i18n/en.json,sha256=Qc3vcvgOUkqAVqOW3y9J811U3J3mgJoE-DAhZUnPJjo,68212
836
- hiddifypanel/translations.i18n/fa.json,sha256=goX6-zlgFlyh9S_9JNauBrgC2veEGL-JV9iq3pRJLQk,90567
837
- hiddifypanel/translations.i18n/pt.json,sha256=U7l6vAZnE5LcuaCNrIOhJ2B0nDB3RQPA_nToH6FtIEM,59286
838
- hiddifypanel/translations.i18n/ru.json,sha256=5KJTiUs5G7829bnXLLSBj7WZH_X1A1U76XLWyLyxiYE,94135
839
- hiddifypanel/translations.i18n/zh.json,sha256=7SaS3GohMMU4EZcZEkMxDMdIETqjRZiuLyVAWqtUl5w,58748
840
- hiddifypanel-10.30.9.dev0.dist-info/LICENSE.md,sha256=oDrt-cUsyiDGnRPjEJh-3dH2ddAuK_bIVBD8ntkOtZw,19807
841
- hiddifypanel-10.30.9.dev0.dist-info/METADATA,sha256=Rniy0ilCX6TfmRgGhTXmWRcK2UP0yTJY1jwCBb9k0pc,4044
842
- hiddifypanel-10.30.9.dev0.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
843
- hiddifypanel-10.30.9.dev0.dist-info/entry_points.txt,sha256=Xzpqlh3nwBtZhoV9AANJykano056VJvYzaujxPztJaM,60
844
- hiddifypanel-10.30.9.dev0.dist-info/top_level.txt,sha256=rv-b3qFWUZQTBy0kyBfsr7L6tPpeO7AaQlLHXn-HI5M,13
845
- hiddifypanel-10.30.9.dev0.dist-info/RECORD,,
825
+ hiddifypanel/translations/en/LC_MESSAGES/messages.mo,sha256=iMDqnzl1z2iGaY_NJmCoRKOltuFXcklHm86Z7Kg9FC0,75756
826
+ hiddifypanel/translations/en/LC_MESSAGES/messages.po,sha256=96O8XWX3UEb8OCw0WL9cGTOkzyU51UupXSKt4dBMs14,78920
827
+ hiddifypanel/translations/fa/LC_MESSAGES/messages.mo,sha256=ak3v2PQgdDMyWF00RkKwGneDWdIxGj4M6_qb3msndN4,96092
828
+ hiddifypanel/translations/fa/LC_MESSAGES/messages.po,sha256=JdZQhrLwzFDngs0Wu3qDJaCxSoh7UJn09zwPTMKupyg,101469
829
+ hiddifypanel/translations/pt/LC_MESSAGES/messages.mo,sha256=n5yiUZy_2I8OwE1kq5m5gHquM6KGpYSHl1ltFktCXoM,58649
830
+ hiddifypanel/translations/pt/LC_MESSAGES/messages.po,sha256=tEWo_g0gJAm1wlmRWfV7rKjt1w87GglPwv504K7hPyI,69401
831
+ hiddifypanel/translations/ru/LC_MESSAGES/messages.mo,sha256=MFrKhsX-nKtqj8-cqL1FdpI47YpO2Z0FqbF8khpqVKU,97620
832
+ hiddifypanel/translations/ru/LC_MESSAGES/messages.po,sha256=7gdyumMtKwmL2KtbdE6aVSZ31N5VM51GuyHhS__41ds,104624
833
+ hiddifypanel/translations/zh/LC_MESSAGES/messages.mo,sha256=vlgjN9lFxAnZwVx9qJu4SE17oELs0oYiXr7aGcs0vWs,58966
834
+ hiddifypanel/translations/zh/LC_MESSAGES/messages.po,sha256=8aP7TqaDZjDEHwiL0t8_eu5yP5PH8OrgouOND9ExH88,68629
835
+ hiddifypanel/translations.i18n/en.json,sha256=IukyU5kkY_FRkFx_xT1APP7A5PASazjFOzMzDg5aZy0,68563
836
+ hiddifypanel/translations.i18n/fa.json,sha256=ebTs9S5L4F_rFYfQxuJ8pMr6fz2PG8i8fkl4Soyxhzc,91103
837
+ hiddifypanel/translations.i18n/pt.json,sha256=YQseQvgHDlCy3HHVJo-yAvepMl_y-zCU0qPLARybDmA,59407
838
+ hiddifypanel/translations.i18n/ru.json,sha256=dCp5BI_15WoiMpV2u9_6M6feS_yL_lf22gXeyMqJDB4,94231
839
+ hiddifypanel/translations.i18n/zh.json,sha256=8iFoOhmXeoPJHWop7Fa8FMs1Ix-5jvn09gq8N9w1iUs,58875
840
+ hiddifypanel-10.30.9.dev2.dist-info/LICENSE.md,sha256=oDrt-cUsyiDGnRPjEJh-3dH2ddAuK_bIVBD8ntkOtZw,19807
841
+ hiddifypanel-10.30.9.dev2.dist-info/METADATA,sha256=Z4jbG1XjsMbwtM5kF_qH05ZEyV2WngsuIy4aQv6D_Bo,4044
842
+ hiddifypanel-10.30.9.dev2.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
843
+ hiddifypanel-10.30.9.dev2.dist-info/entry_points.txt,sha256=Xzpqlh3nwBtZhoV9AANJykano056VJvYzaujxPztJaM,60
844
+ hiddifypanel-10.30.9.dev2.dist-info/top_level.txt,sha256=rv-b3qFWUZQTBy0kyBfsr7L6tPpeO7AaQlLHXn-HI5M,13
845
+ hiddifypanel-10.30.9.dev2.dist-info/RECORD,,