hiddifypanel 9.0.0.dev54__py3-none-any.whl → 9.0.0.dev61__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 (72) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/base.py +5 -4
  4. hiddifypanel/hutils/__init__.py +8 -1
  5. hiddifypanel/hutils/auth.py +94 -0
  6. hiddifypanel/hutils/auto_ip_selector.py +1 -1
  7. hiddifypanel/hutils/convert.py +14 -0
  8. hiddifypanel/hutils/encode.py +11 -0
  9. hiddifypanel/hutils/flask.py +24 -0
  10. hiddifypanel/{panel/github_issue_generator.py → hutils/github_issue.py} +104 -14
  11. hiddifypanel/hutils/json.py +24 -0
  12. hiddifypanel/hutils/random.py +19 -0
  13. hiddifypanel/hutils/utils.py +0 -161
  14. hiddifypanel/models/__init__.py +1 -0
  15. hiddifypanel/models/admin.py +53 -8
  16. hiddifypanel/models/base_account.py +31 -169
  17. hiddifypanel/models/config_enum.py +23 -1
  18. hiddifypanel/models/domain.py +2 -2
  19. hiddifypanel/models/parent_domain.py +1 -0
  20. hiddifypanel/models/user.py +105 -33
  21. hiddifypanel/models/utils.py +3 -3
  22. hiddifypanel/panel/admin/Actions.py +5 -6
  23. hiddifypanel/panel/admin/AdminstratorAdmin.py +1 -1
  24. hiddifypanel/panel/admin/Backup.py +5 -5
  25. hiddifypanel/panel/admin/ChildAdmin.py +3 -3
  26. hiddifypanel/panel/admin/Dashboard.py +12 -10
  27. hiddifypanel/panel/admin/DomainAdmin.py +10 -9
  28. hiddifypanel/panel/admin/ProxyAdmin.py +4 -6
  29. hiddifypanel/panel/admin/QuickSetup.py +11 -13
  30. hiddifypanel/panel/admin/SettingAdmin.py +20 -10
  31. hiddifypanel/panel/admin/UserAdmin.py +14 -12
  32. hiddifypanel/panel/auth.py +43 -10
  33. hiddifypanel/panel/auth_back2.py +5 -5
  34. hiddifypanel/panel/cli.py +1 -0
  35. hiddifypanel/panel/commercial/ParentDomainAdmin.py +3 -3
  36. hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +1 -0
  37. hiddifypanel/panel/commercial/restapi/v1/tgbot.py +1 -2
  38. hiddifypanel/panel/commercial/restapi/v1/tgmsg.py +37 -29
  39. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +5 -4
  40. hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +15 -7
  41. hiddifypanel/panel/commercial/restapi/v2/user/info_api.py +7 -11
  42. hiddifypanel/panel/commercial/telegrambot/Usage.py +2 -1
  43. hiddifypanel/panel/commercial/telegrambot/admin.py +1 -0
  44. hiddifypanel/panel/common.py +12 -89
  45. hiddifypanel/panel/common_bp/login.py +12 -12
  46. hiddifypanel/panel/database.py +22 -21
  47. hiddifypanel/panel/hiddify.py +27 -29
  48. hiddifypanel/panel/importer/xui.py +2 -2
  49. hiddifypanel/panel/init_db.py +32 -13
  50. hiddifypanel/panel/usage.py +2 -1
  51. hiddifypanel/panel/user/link_maker.py +118 -15
  52. hiddifypanel/panel/user/templates/new.html +4 -2
  53. hiddifypanel/panel/user/user.py +83 -38
  54. hiddifypanel/static/new/assets/{index-bd9ba5e9.js → index-2cd90979.js} +1 -1
  55. hiddifypanel/templates/fake.html +2 -2
  56. hiddifypanel/templates/master.html +1 -1
  57. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  58. hiddifypanel/translations/en/LC_MESSAGES/messages.po +317 -189
  59. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  60. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +346 -206
  61. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  62. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +315 -195
  63. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  64. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +315 -195
  65. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  66. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +866 -2739
  67. {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/METADATA +2 -1
  68. {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/RECORD +72 -66
  69. {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/LICENSE.md +0 -0
  70. {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/WHEEL +0 -0
  71. {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/entry_points.txt +0 -0
  72. {hiddifypanel-9.0.0.dev54.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,22 @@
1
1
  import glob
2
+ import random
3
+ import socket
4
+ import ssl
5
+ import time
6
+ import uuid
2
7
  import user_agents
3
8
  import json
4
9
  import subprocess
5
10
  import psutil
11
+ from datetime import datetime
6
12
  from typing import Tuple
7
13
  from cryptography.hazmat.primitives import serialization
8
14
  from cryptography.hazmat.primitives.asymmetric import x25519
9
- from flask import current_app, g, jsonify, request
15
+ from flask import current_app, g, request, Markup # type: ignore
10
16
  from flask_babelex import gettext as __
11
17
  from flask_babelex import lazy_gettext as _
12
18
  from wtforms.validators import ValidationError
13
19
  from apiflask import abort as apiflask_abort
14
- from apiflask import abort
15
20
 
16
21
  from datetime import timedelta
17
22
  from babel.dates import format_timedelta as babel_format_timedelta
@@ -56,7 +61,7 @@ def add_short_link_imp(link: str, period_min: int = 5) -> Tuple[str, datetime]:
56
61
  if link in line:
57
62
  return re.search(pattern, line).group(1), datetime.now() + timedelta(minutes=period_min)
58
63
 
59
- short_code = get_random_string(6, 10).lower()
64
+ short_code = hutils.random.get_random_string(6, 10).lower()
60
65
  # exec_command(
61
66
  # f'sudo /opt/hiddify-manager/nginx/add2shortlink.sh {link} {short_code} {period_min} &')
62
67
 
@@ -171,6 +176,8 @@ def is_login_call() -> bool:
171
176
 
172
177
 
173
178
  def is_admin_role(role: Role):
179
+ if not role:
180
+ return False
174
181
  if role in {Role.super_admin, Role.admin, Role.agent}:
175
182
  return True
176
183
  return False
@@ -201,18 +208,18 @@ def proxy_path_validator(proxy_path):
201
208
  return
202
209
 
203
210
  if proxy_path not in [admin_proxy_path, deprecated_path, client_proxy_path]:
204
- abort(400, 'invalid request')
211
+ apiflask_abort(400, 'invalid request')
205
212
 
206
213
  if is_admin_panel_call() and proxy_path != admin_proxy_path:
207
- abort(400, 'invalid request')
214
+ apiflask_abort(400, 'invalid request')
208
215
  if is_user_panel_call() and proxy_path != client_proxy_path:
209
- abort(400, 'invalid request')
216
+ apiflask_abort(400, 'invalid request')
210
217
 
211
218
  if is_api_call(request.path):
212
219
  if is_admin_api_call() and proxy_path != admin_proxy_path:
213
- return apiflask_abort(400, Markup(f"Invalid Proxy Path <a href=/{admin_proxy_path}/admin>Admin Panel</a>")) if dbg_mode else abort(400, 'invalid request')
220
+ return apiflask_abort(400, Markup(f"Invalid Proxy Path <a href=/{admin_proxy_path}/admin>Admin Panel</a>")) if dbg_mode else apiflask_abort(400, 'invalid request')
214
221
  if is_user_api_call() and proxy_path != client_proxy_path:
215
- return apiflask_abort(400, Markup(f"Invalid Proxy Path <a href=/{client_proxy_path}/admin>User Panel</a>")) if dbg_mode else abort(400, 'invalid request')
222
+ return apiflask_abort(400, Markup(f"Invalid Proxy Path <a href=/{client_proxy_path}/admin>User Panel</a>")) if dbg_mode else apiflask_abort(400, 'invalid request')
216
223
 
217
224
 
218
225
  def asset_url(path) -> str:
@@ -270,17 +277,6 @@ def quick_apply_users():
270
277
  return {"status": 'success'}
271
278
 
272
279
 
273
- def flash_config_success(restart_mode='', domain_changed=True):
274
- if restart_mode:
275
- url = url_for('admin.Actions:reinstall', complete_install=restart_mode ==
276
- 'reinstall', domain_changed=domain_changed)
277
- apply_btn = f"<a href='{url}' class='btn btn-primary form_post'>" + \
278
- _("admin.config.apply_configs")+"</a>"
279
- flash((_('config.validation-success', link=apply_btn)), 'success')
280
- else:
281
- flash((_('config.validation-success-no-reset')), 'success')
282
-
283
-
284
280
  # Importing socket library
285
281
 
286
282
  # Function to display hostname and
@@ -332,7 +328,7 @@ def get_html_user_link(model: BaseAccount, domain: Domain):
332
328
  res = ""
333
329
  d = domain.domain
334
330
  if "*" in d:
335
- d = d.replace("*", get_random_string(5, 15))
331
+ d = d.replace("*", hutils.random.get_random_string(5, 15))
336
332
 
337
333
  link = get_account_panel_link(model, d)+f"#{model.name}"
338
334
 
@@ -379,7 +375,7 @@ def check_need_reset(old_configs, do=False):
379
375
  if old_configs[ConfigEnum.package_mode] != hconfig(ConfigEnum.package_mode):
380
376
  return reinstall_action(do_update=True)
381
377
  if not (do and restart_mode == 'reinstall'):
382
- return flash_config_success(restart_mode=restart_mode, domain_changed=False)
378
+ return hutils.flask.flash_config_success(restart_mode=restart_mode, domain_changed=False)
383
379
 
384
380
  return reinstall_action(complete_install=True, domain_changed=domain_changed)
385
381
 
@@ -648,9 +644,12 @@ def get_random_domains(count=1, retry=3):
648
644
  return random.sample(defdomains, count)
649
645
  return get_random_domains(count, retry-1)
650
646
 
647
+ # not used
648
+
651
649
 
652
650
  def is_domain_support_tls_13(domain):
653
651
  context = ssl.create_default_context()
652
+ port = 433
654
653
  with socket.create_connection((domain, port)) as sock:
655
654
  with context.wrap_socket(sock, server_hostname=domain) as ssock:
656
655
  return ssock.version() == "TLSv1.3"
@@ -693,8 +692,8 @@ def debug_flash_if_not_in_the_same_asn(domain):
693
692
  # country_ipv4= ipcountry.get(ipv4)
694
693
  # country_dip= ipcountry.get(dip)
695
694
  if asn_ipv4.get('autonomous_system_organization') != asn_dip.get('autonomous_system_organization'):
696
- flash(_("selected domain for REALITY is not in the same ASN. To better use of the protocol, it is better to find a domain in the same ASN.") +
697
- f"<br> Server ASN={asn_ipv4.get('autonomous_system_organization','unknown')}<br>{domain}_ASN={asn_dip.get('autonomous_system_organization','unknown')}", "warning")
695
+ hutils.flask.flash(_("selected domain for REALITY is not in the same ASN. To better use of the protocol, it is better to find a domain in the same ASN.") +
696
+ f"<br> Server ASN={asn_ipv4.get('autonomous_system_organization','unknown')}<br>{domain}_ASN={asn_dip.get('autonomous_system_organization','unknown')}", "warning")
698
697
  except:
699
698
  pass
700
699
 
@@ -788,10 +787,10 @@ def get_ed25519_private_public_pair():
788
787
  return priv_bytes.decode(), pub_bytes.decode()
789
788
 
790
789
 
791
- def do_base_64(str):
792
- import base64
793
- resp = base64.b64encode(f'{str}'.encode("utf-8"))
794
- return resp.decode()
790
+ # def do_base_64(str):
791
+ # import base64
792
+ # resp = base64.b64encode(f'{str}'.encode("utf-8"))
793
+ # return resp.decode()
795
794
 
796
795
 
797
796
  def get_user_agent():
@@ -854,7 +853,6 @@ def __parse_user_agent(ua):
854
853
 
855
854
  def is_ssh_password_authentication_enabled():
856
855
  if os.path.isfile('/etc/ssh/sshd_config'):
857
- content = ''
858
856
  with open('/etc/ssh/sshd_config', 'r') as f:
859
857
  for line in f.readlines():
860
858
  line = line.strip()
@@ -876,7 +874,7 @@ def get_direct_host_or_ip(prefer_version: int):
876
874
  else:
877
875
  direct = hutils.ip.get_ip(prefer_version)
878
876
  if not direct:
879
- direct = hutils.ip.get_ip(socket.AF_INET if prefer_version == socket.AF_INET6 else socket.AF_INET6)
877
+ direct = hutils.ip.get_ip(4 if prefer_version == 6 else 6)
880
878
  return direct
881
879
 
882
880
 
@@ -4,7 +4,7 @@ from typing import Any, Dict, List, Tuple
4
4
  import uuid as uuid_mod
5
5
  from datetime import datetime
6
6
  from dateutil.relativedelta import relativedelta
7
- import hiddifypanel.hutils.utils as utils
7
+ from hiddifypanel import hutils
8
8
  from hiddifypanel.models.admin import AdminUser
9
9
  from hiddifypanel.models.user import User, UserMode
10
10
  from hiddifypanel.models.domain import Domain, DomainType
@@ -63,7 +63,7 @@ def __get_users(db, x_ui_inbounds):
63
63
  def __create_hiddify_user_from_xui_values(id: str, values: Dict[str, Any]) -> User:
64
64
  user = User()
65
65
  user.name = values['name']
66
- user.uuid = id if utils.is_uuid_valid(id, 4) else uuid_mod.uuid4()
66
+ user.uuid = id if hutils.auth.is_uuid_valid(id, 4) else uuid_mod.uuid4()
67
67
 
68
68
  if str(values['expiry_time']) == '0':
69
69
  user.expiry_time = datetime.now() + relativedelta(years=10)
@@ -12,7 +12,7 @@ from hiddifypanel import Events, hutils
12
12
  from hiddifypanel.models import *
13
13
  from hiddifypanel.panel import hiddify
14
14
  from hiddifypanel.panel.database import db
15
- from hiddifypanel.panel.hiddify import get_random_domains, get_random_string
15
+ from hiddifypanel.panel.hiddify import get_random_domains
16
16
  import hiddifypanel.models.utils as model_utils
17
17
 
18
18
  MAX_DB_VERSION = 70
@@ -26,7 +26,12 @@ def init_db():
26
26
  hconfig.invalidate_all()
27
27
  get_hconfigs.invalidate_all()
28
28
  db_version = int(hconfig(ConfigEnum.db_version) or 0)
29
+ if db_version == latest_db_version():
30
+ return
31
+ execute("alter table user alter column telegram_id int;")
32
+ execute("alter table admin_user alter column telegram_id int;")
29
33
  add_column(User.lang)
34
+ add_column(AdminUser.lang)
30
35
  add_column(User.username)
31
36
  add_column(User.password)
32
37
  add_column(AdminUser.username)
@@ -34,8 +39,6 @@ def init_db():
34
39
 
35
40
  add_column(Domain.extra_params)
36
41
 
37
- if db_version == latest_db_version():
38
- return
39
42
  Events.db_prehook.notify()
40
43
  if db_version < 52:
41
44
  execute(f'update domain set mode="sub_link_only", sub_link_only=false where sub_link_only = true or mode=1 or mode="1"')
@@ -148,6 +151,22 @@ def init_db():
148
151
  # add_config_if_not_exist(ConfigEnum.hysteria_enable, True)
149
152
  # add_config_if_not_exist(ConfigEnum.hysteria_port, random.randint(5000, 20000))
150
153
 
154
+ def _v67():
155
+ pass
156
+
157
+
158
+ def _v65():
159
+ add_config_if_not_exist(ConfigEnum.mux_enable, False)
160
+ add_config_if_not_exist(ConfigEnum.mux_protocol, 'smux')
161
+ add_config_if_not_exist(ConfigEnum.mux_max_connections, '4')
162
+ add_config_if_not_exist(ConfigEnum.mux_min_streams, '4')
163
+ add_config_if_not_exist(ConfigEnum.mux_max_streams, '0')
164
+ add_config_if_not_exist(ConfigEnum.mux_padding_enable, False)
165
+ add_config_if_not_exist(ConfigEnum.mux_brutal_enable, True)
166
+ add_config_if_not_exist(ConfigEnum.mux_brutal_up_mbps, '100')
167
+ add_config_if_not_exist(ConfigEnum.mux_brutal_down_mbps, '100')
168
+
169
+
151
170
  def _v64():
152
171
  set_hconfig(ConfigEnum.ssh_server_redis_url, "unix:///opt/hiddify-manager/other/redis/run.sock?db=1")
153
172
 
@@ -175,8 +194,8 @@ def _v61():
175
194
 
176
195
 
177
196
  def _v60():
178
- add_config_if_not_exist(ConfigEnum.proxy_path_admin, get_random_string())
179
- add_config_if_not_exist(ConfigEnum.proxy_path_client, get_random_string())
197
+ add_config_if_not_exist(ConfigEnum.proxy_path_admin, hutils.random.get_random_string())
198
+ add_config_if_not_exist(ConfigEnum.proxy_path_client, hutils.random.get_random_string())
180
199
 
181
200
 
182
201
  def _v59():
@@ -342,13 +361,13 @@ def _v20():
342
361
 
343
362
 
344
363
  def _v19():
345
- set_hconfig(ConfigEnum.path_trojan, get_random_string(7, 15))
346
- set_hconfig(ConfigEnum.path_vless, get_random_string(7, 15))
347
- set_hconfig(ConfigEnum.path_vmess, get_random_string(7, 15))
348
- set_hconfig(ConfigEnum.path_ss, get_random_string(7, 15))
349
- set_hconfig(ConfigEnum.path_grpc, get_random_string(7, 15))
350
- set_hconfig(ConfigEnum.path_tcp, get_random_string(7, 15))
351
- set_hconfig(ConfigEnum.path_ws, get_random_string(7, 15))
364
+ set_hconfig(ConfigEnum.path_trojan, hutils.random.get_random_string(7, 15))
365
+ set_hconfig(ConfigEnum.path_vless, hutils.random.get_random_string(7, 15))
366
+ set_hconfig(ConfigEnum.path_vmess, hutils.random.get_random_string(7, 15))
367
+ set_hconfig(ConfigEnum.path_ss, hutils.random.get_random_string(7, 15))
368
+ set_hconfig(ConfigEnum.path_grpc, hutils.random.get_random_string(7, 15))
369
+ set_hconfig(ConfigEnum.path_tcp, hutils.random.get_random_string(7, 15))
370
+ set_hconfig(ConfigEnum.path_ws, hutils.random.get_random_string(7, 15))
352
371
  add_config_if_not_exist(ConfigEnum.tuic_enable, False)
353
372
  add_config_if_not_exist(ConfigEnum.shadowtls_enable, False)
354
373
  add_config_if_not_exist(ConfigEnum.shadowtls_fakedomain, "en.wikipedia.org")
@@ -383,7 +402,7 @@ def _v1():
383
402
  StrConfig(key=ConfigEnum.tls_ports, value="443"),
384
403
  BoolConfig(key=ConfigEnum.first_setup, value=True),
385
404
  StrConfig(key=ConfigEnum.decoy_domain, value=hiddify.get_random_decoy_domain()),
386
- StrConfig(key=ConfigEnum.proxy_path, value=get_random_string()),
405
+ StrConfig(key=ConfigEnum.proxy_path, value=hutils.random.get_random_string()),
387
406
  BoolConfig(key=ConfigEnum.firewall, value=False),
388
407
  BoolConfig(key=ConfigEnum.netdata, value=True),
389
408
  StrConfig(key=ConfigEnum.lang, value='en'),
@@ -19,6 +19,7 @@ def update_local_usage():
19
19
 
20
20
 
21
21
  def add_users_usage_uuid(uuids_bytes, child_id):
22
+ # WHAT IS THE "keys" function WHY ?????
22
23
  users = User.query.filter(User.uuid.in_(keys(uuids_bytes)))
23
24
  dbusers_bytes = {u: uuids_bytes.get(u.uuid, 0) for u in users}
24
25
  add_users_usage(dbusers_bytes, child_id)
@@ -100,6 +101,6 @@ def send_bot_message(user):
100
101
  try:
101
102
  msg = Usage.get_usage_msg(user.uuid)
102
103
  msg = _("User activated!") if user.is_active else _("Package ended!")+"\n"+msg
103
- bot.send_message(user.telegram_id, msg, reply_markup=Usage.user_keyboard(uuid))
104
+ bot.send_message(user.telegram_id, msg, reply_markup=Usage.user_keyboard(user.uuid))
104
105
  except:
105
106
  pass
@@ -1,5 +1,5 @@
1
1
  from flask import g, request, render_template
2
- from ipaddress import IPv4Address, IPv4Address
2
+ from ipaddress import IPv4Address, IPv6Address
3
3
  import enum
4
4
  from hiddifypanel import hutils
5
5
  from hiddifypanel.models import *
@@ -235,7 +235,7 @@ def to_link(proxy):
235
235
  if 'error' in proxy:
236
236
  return proxy
237
237
  orig_name_link = (proxy['extra_info'] + " " + proxy["name"]).strip()
238
- name_link = hiddify.url_encode(orig_name_link)
238
+ name_link = hutils.encode.url_encode(orig_name_link)
239
239
  if proxy['proto'] == 'vmess':
240
240
  # print(proxy)
241
241
  vmess_type = None
@@ -264,12 +264,18 @@ def to_link(proxy):
264
264
  vmess_data['pbk'] = proxy['reality_pbk']
265
265
  vmess_data['sid'] = proxy['reality_short_id']
266
266
 
267
- return "vmess://" + hiddify.do_base_64(f'{json.dumps(vmess_data,cls=CustomEncoder)}')
267
+ if proxy['cdn'] and g.user_agent.get('is_hiddify'):
268
+ add_tls_tricks_to_dict(vmess_data)
269
+ add_mux_to_dict(vmess_data)
270
+
271
+ return "vmess://" + hutils.encode.do_base_64(f'{json.dumps(vmess_data,cls=CustomEncoder)}')
268
272
  # return pbase64(f'vmess://{json.dumps(vmess_data)}')
269
273
  if proxy['proto'] == 'ssh':
270
- strenssh = hiddify.do_base_64(f'{proxy["uuid"]}:0:{proxy["private_key"]}::@{proxy["server"]}:{proxy["port"]}')
274
+ strenssh = hutils.encode.do_base_64(f'{proxy["uuid"]}:0:{proxy["private_key"]}::@{proxy["server"]}:{proxy["port"]}')
271
275
  baseurl = f'ssh://{strenssh}#{name_link}'
272
- baseurl += f'\nssh://{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}/?pk='+hiddify.do_base_64(proxy["private_key"])+f"&hk={hiddify.get_hostkeys(True)}#{name_link}"
276
+ hk = hutils.encode.do_base_64(",".join(proxy["host_key"]))
277
+ pk = hutils.encode.do_base_64(proxy["private_key"])
278
+ baseurl += f'\nssh://{proxy["uuid"]}@{proxy["server"]}:{proxy["port"]}/?pk={pk}&hk={hk}#{name_link}'
273
279
 
274
280
  return baseurl
275
281
  if proxy['proto'] == "ssr":
@@ -298,6 +304,14 @@ def to_link(proxy):
298
304
  baseurl += f'&sni={proxy["sni"]}&type={proxy["transport"]}'
299
305
  baseurl += f"&alpn={proxy['alpn']}"
300
306
 
307
+ # the ray2sing supports vless, vmess and trojan tls tricks and mux
308
+ # the vmess handled already
309
+
310
+ if proxy['proto'] in {'vless', 'trojan'}:
311
+ baseurl = add_mux_to_link(baseurl)
312
+ if proxy['cdn'] and g.user_agent.get('is_hiddify'):
313
+ baseurl = add_tls_tricks_to_link(baseurl)
314
+
301
315
  # infos+=f'&alpn={proxy["alpn"]}'
302
316
  baseurl += f'&path={proxy["path"]}' if "path" in proxy else ""
303
317
  baseurl += f'&host={proxy["host"]}' if "host" in proxy else ""
@@ -329,6 +343,54 @@ def to_link(proxy):
329
343
  return f'{baseurl}&security=none{infos}'
330
344
  return proxy
331
345
 
346
+ # region tls tricks & mux
347
+ # notice: combining the functions into two function would make code less readable and difficult to maintain
348
+
349
+
350
+ def add_tls_tricks_to_link(link: str) -> str:
351
+ if hconfig(ConfigEnum.tls_fragment_enable):
352
+ link += f'&fgsize={hconfig(ConfigEnum.tls_fragment_size)}&fgsleep={hconfig(ConfigEnum.tls_fragment_sleep)}'
353
+ if hconfig(ConfigEnum.tls_mixed_case):
354
+ link += '&mc=1'
355
+ if hconfig(ConfigEnum.tls_padding_enable):
356
+ link += f'&padsize={hconfig(ConfigEnum.tls_padding_length)}'
357
+ return link
358
+
359
+
360
+ def add_mux_to_link(link: str) -> str:
361
+ if hconfig(ConfigEnum.mux_enable):
362
+ link += f'&mux={hconfig(ConfigEnum.mux_protocol)}&mux_max={hconfig(ConfigEnum.mux_max_connections)}&mux_min={hconfig(ConfigEnum.mux_min_streams)}&mux_pad={hconfig(ConfigEnum.mux_padding_enable)}'
363
+ if hconfig(ConfigEnum.mux_brutal_enable):
364
+ link += f'&mux_up={hconfig(ConfigEnum.mux_brutal_up_mbps)}&mux_down={hconfig(ConfigEnum.mux_brutal_down_mbps)}'
365
+ return link
366
+
367
+
368
+ def add_tls_tricks_to_dict(d: dict):
369
+ if hconfig(ConfigEnum.tls_fragment_enable):
370
+ d['fgsize'] = hconfig(ConfigEnum.tls_fragment_size)
371
+ d['fgsleep'] = hconfig(ConfigEnum.tls_fragment_sleep)
372
+ if hconfig(ConfigEnum.tls_mixed_case):
373
+ d['mc'] = 1
374
+ if hconfig(ConfigEnum.tls_padding_enable):
375
+ d['padsize'] = hconfig(ConfigEnum.tls_padding_length)
376
+
377
+
378
+ def add_mux_to_dict(d: dict):
379
+ if hconfig(ConfigEnum.mux_enable):
380
+ d['mux'] = hconfig(ConfigEnum.mux_protocol)
381
+ d['mux_max'] = hconfig(ConfigEnum.mux_max_connections)
382
+ d['mux_min'] = hconfig(ConfigEnum.mux_min_streams)
383
+ d['mux_pad'] = hconfig(ConfigEnum.mux_padding_enable)
384
+ # the hiddify next client doesn't support mux max streams
385
+ # vmess_data['mux_max_streams'] = hconfig(ConfigEnum.mux_max_streams)
386
+
387
+ # handle brutal tcp
388
+ if hconfig(ConfigEnum.mux_brutal_enable):
389
+ d['mux_up'] = hconfig(ConfigEnum.mux_brutal_up_mbps)
390
+ d['mux_down'] = hconfig(ConfigEnum.mux_brutal_down_mbps)
391
+
392
+ # endregion
393
+
332
394
 
333
395
  def to_clash_yml(proxy):
334
396
  return yaml.dump(to_clash(proxy))
@@ -523,6 +585,9 @@ def to_singbox(proxy):
523
585
 
524
586
  add_singbox_tls(base, proxy)
525
587
 
588
+ if proxy['cdn'] and g.user_agent.get('is_hiddify') and proxy["proto"] in ['vmess', 'vless', 'trojan']:
589
+ add_singbox_tls_tricks(base)
590
+
526
591
  if proxy.get('flow'):
527
592
  base["flow"] = proxy['flow']
528
593
  # base["flow-show"] = True
@@ -567,15 +632,31 @@ def add_hysteria(base, proxy):
567
632
 
568
633
 
569
634
  def add_singbox_multiplex(base):
570
- return
635
+ if not hconfig(ConfigEnum.mux_enable):
636
+ return
571
637
  base['multiplex'] = {
572
638
  "enabled": True,
573
- "protocol": "h2mux",
574
- "max_connections": 4,
575
- "min_streams": 4,
576
- "max_streams": 0,
577
- "padding": false
639
+ "protocol": hconfig(ConfigEnum.mux_protocol),
640
+ "padding": hconfig(ConfigEnum.mux_padding_enable)
578
641
  }
642
+ # Conflicts: max_streams with max_connections and min_streams
643
+ mux_max_streams = int(hconfig(ConfigEnum.mux_max_streams))
644
+ if mux_max_streams and mux_max_streams != 0:
645
+ base['multiplex']['max_streams'] = mux_max_streams
646
+ else:
647
+ base['multiplex']['max_connections'] = int(hconfig(ConfigEnum.mux_max_connections))
648
+ base['multiplex']['min_streams'] = int(hconfig(ConfigEnum.mux_min_streams))
649
+
650
+ add_singbox_tcp_brutal(base)
651
+
652
+
653
+ def add_singbox_tcp_brutal(base):
654
+ if 'multiplex' in base:
655
+ base['multiplex']['brutal'] = {
656
+ "enabled": hconfig(ConfigEnum.mux_brutal_enable),
657
+ "up_mbps": int(hconfig(ConfigEnum.mux_brutal_up_mbps)),
658
+ "down_mbps": int(hconfig(ConfigEnum.mux_brutal_down_mbps))
659
+ }
579
660
 
580
661
 
581
662
  def add_singbox_udp_over_tcp(base):
@@ -611,6 +692,28 @@ def add_singbox_tls(base, proxy):
611
692
  # }
612
693
 
613
694
 
695
+ def add_singbox_tls_tricks(base):
696
+ if hconfig(ConfigEnum.tls_fragment_enable):
697
+ base['tls_fragment'] = {
698
+ # 'enable': True,
699
+ 'size': hconfig(ConfigEnum.tls_fragment_size),
700
+ 'sleep': hconfig(ConfigEnum.tls_fragment_sleep)
701
+ }
702
+
703
+ tls_padding_enable = hconfig(ConfigEnum.tls_padding_enable)
704
+ tls_mixed_case = hconfig(ConfigEnum.tls_mixed_case)
705
+ if (tls_padding_enable or tls_mixed_case) and 'tls' not in base:
706
+ base['tls'] = {
707
+ 'tls_tricks': {}
708
+ }
709
+ if hconfig(ConfigEnum.tls_padding_enable):
710
+ base['tls']['tls_tricks'] = {
711
+ 'padding_size': hconfig(ConfigEnum.tls_padding_length)
712
+ }
713
+ if hconfig(ConfigEnum.tls_mixed_case):
714
+ base['tls']['tls_tricks']['mixedcase_sni'] = True
715
+
716
+
614
717
  def add_singbox_transport(base, proxy):
615
718
  if proxy['l3'] == 'reality' and proxy['transport'] not in ["grpc"]:
616
719
  return
@@ -769,7 +872,7 @@ def make_v2ray_configs(user, user_activate, domains, expire_days, ip_debug, db_d
769
872
  # res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{round(user.current_usage_GB,3)}/{user.usage_limit_GB}GB_Remain:{expire_days}days')
770
873
  # else:
771
874
 
772
- # res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{hiddify.url_encode(profile_title)}')
875
+ # res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{hutils.encode.url_encode(profile_title)}')
773
876
 
774
877
  name = '⏳' if user_activate else '✖'
775
878
  if user.usage_limit_GB < 1000:
@@ -785,7 +888,7 @@ def make_v2ray_configs(user, user_activate, domains, expire_days, ip_debug, db_d
785
888
 
786
889
  name = name.strip()
787
890
  if len(name) > 3:
788
- res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{hiddify.url_encode(name)}')
891
+ res.append(f'trojan://1@{fake_ip_for_sub_link}?sni=fake_ip_for_sub_link&security=tls#{hutils.encode.url_encode(name)}')
789
892
 
790
893
  if ua['is_browser']:
791
894
  res.append(f'#Hiddify auto ip: {ip_debug}')
@@ -793,9 +896,9 @@ def make_v2ray_configs(user, user_activate, domains, expire_days, ip_debug, db_d
793
896
  if not user_activate:
794
897
 
795
898
  if hconfig(ConfigEnum.lang) == 'fa':
796
- res.append('trojan://1@1.1.1.1#'+hiddify.url_encode('✖بسته شما به پایان رسید'))
899
+ res.append('trojan://1@1.1.1.1#'+hutils.encode.url_encode('✖بسته شما به پایان رسید'))
797
900
  else:
798
- res.append('trojan://1@1.1.1.1#'+hiddify.url_encode('✖Package_Ended'))
901
+ res.append('trojan://1@1.1.1.1#'+hutils.encode.url_encode('✖Package_Ended'))
799
902
  return "\n".join(res)
800
903
 
801
904
  for pinfo in get_all_validated_proxies(domains):
@@ -9,9 +9,11 @@
9
9
  <link rel="stylesheet" href="node_modules/smartbanner.js/dist/smartbanner.min.css">
10
10
  <link href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css" rel="stylesheet" type="text/css" />
11
11
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
12
-
12
+ <link rel="icon" type="image/x-icon" href="{{ static_url_for( filename='images/favicon.ico')}}">
13
+ <link rel="manifest" href="{{ url_for('common_bp.LoginView:create_pwa_manifest',secret_uuid=g.account.uuid or '')}}">
14
+
13
15
  <title>Hiddify | Panel</title>
14
- <script type="module" crossorigin src="../static/new/assets/index-bd9ba5e9.js"></script>
16
+ <script type="module" crossorigin src="../static/new/assets/index-2cd90979.js"></script>
15
17
  <link rel="stylesheet" href="../static/new/assets/index-d9bbf489.css">
16
18
  </head>
17
19
  <body>