hiddifypanel 9.0.0.dev60__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 (63) 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 -169
  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/domain.py +2 -2
  18. hiddifypanel/models/parent_domain.py +1 -0
  19. hiddifypanel/models/user.py +105 -33
  20. hiddifypanel/models/utils.py +3 -3
  21. hiddifypanel/panel/admin/Actions.py +5 -6
  22. hiddifypanel/panel/admin/Backup.py +5 -5
  23. hiddifypanel/panel/admin/ChildAdmin.py +3 -3
  24. hiddifypanel/panel/admin/Dashboard.py +12 -10
  25. hiddifypanel/panel/admin/DomainAdmin.py +10 -9
  26. hiddifypanel/panel/admin/ProxyAdmin.py +4 -6
  27. hiddifypanel/panel/admin/QuickSetup.py +11 -13
  28. hiddifypanel/panel/admin/SettingAdmin.py +13 -11
  29. hiddifypanel/panel/admin/UserAdmin.py +13 -12
  30. hiddifypanel/panel/auth.py +42 -9
  31. hiddifypanel/panel/auth_back2.py +5 -5
  32. hiddifypanel/panel/cli.py +1 -0
  33. hiddifypanel/panel/commercial/ParentDomainAdmin.py +3 -3
  34. hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +1 -0
  35. hiddifypanel/panel/commercial/restapi/v1/tgmsg.py +1 -1
  36. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +5 -4
  37. hiddifypanel/panel/commercial/restapi/v2/user/info_api.py +7 -11
  38. hiddifypanel/panel/commercial/telegrambot/admin.py +1 -0
  39. hiddifypanel/panel/common.py +10 -86
  40. hiddifypanel/panel/common_bp/login.py +9 -8
  41. hiddifypanel/panel/database.py +22 -21
  42. hiddifypanel/panel/hiddify.py +25 -28
  43. hiddifypanel/panel/importer/xui.py +2 -2
  44. hiddifypanel/panel/init_db.py +20 -13
  45. hiddifypanel/panel/usage.py +2 -1
  46. hiddifypanel/panel/user/link_maker.py +118 -15
  47. hiddifypanel/panel/user/user.py +25 -19
  48. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  49. hiddifypanel/translations/en/LC_MESSAGES/messages.po +252 -234
  50. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  51. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +280 -228
  52. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  53. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +240 -207
  54. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  55. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +240 -207
  56. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  57. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +779 -2740
  58. {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/METADATA +2 -1
  59. {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/RECORD +63 -57
  60. {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/LICENSE.md +0 -0
  61. {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/WHEEL +0 -0
  62. {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/entry_points.txt +0 -0
  63. {hiddifypanel-9.0.0.dev60.dist-info → hiddifypanel-9.0.0.dev61.dist-info}/top_level.txt +0 -0
@@ -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):
@@ -1,19 +1,22 @@
1
+ import user_agents
2
+ import datetime
3
+ import random
4
+ import re
1
5
 
2
- from flask import redirect, render_template, request, Response, g, url_for, jsonify, flash
6
+ from flask import render_template, request, Response, g
3
7
  from apiflask import abort
4
- from hiddifypanel.hutils import auto_ip_selector
5
- import datetime
6
- from hiddifypanel.models import *
7
- from hiddifypanel.panel.database import db
8
- from hiddifypanel.panel import hiddify
9
8
  from . import link_maker
10
9
  from flask_classful import FlaskView, route
11
- import random
12
10
  from urllib.parse import urlparse
13
- import user_agents
14
11
  from flask_babelex import gettext as _
15
- import re
12
+
13
+
16
14
  from hiddifypanel.panel.auth import login_required
15
+ from hiddifypanel.hutils import auto_ip_selector
16
+ from hiddifypanel.panel.database import db
17
+ from hiddifypanel.panel import hiddify
18
+ from hiddifypanel.models import *
19
+ from hiddifypanel import hutils
17
20
 
18
21
 
19
22
  class UserView(FlaskView):
@@ -129,6 +132,9 @@ class UserView(FlaskView):
129
132
  @ route('/report', methods=["POST"])
130
133
  @login_required(roles={Role.user})
131
134
  def report(self):
135
+
136
+ # THE REPORT MODEL IS NOT COMPLETED YET.
137
+
132
138
  data = request.get_json()
133
139
  user_ip = auto_ip_selector.get_real_user_ip()
134
140
  report = Report()
@@ -217,11 +223,11 @@ class UserView(FlaskView):
217
223
  if request.method == 'HEAD':
218
224
  resp = ""
219
225
  else:
220
- # render_template('all_configs.txt', **c, base64=do_base_64)
226
+ # render_template('all_configs.txt', **c, base64=hutils.encode.do_base_64)
221
227
  resp = link_maker.make_v2ray_configs(**c)
222
228
 
223
229
  if base64:
224
- resp = do_base_64(resp)
230
+ resp = hutils.encode.do_base_64(resp)
225
231
  return add_headers(resp, c)
226
232
 
227
233
  @ route("/offline.html")
@@ -236,10 +242,10 @@ class UserView(FlaskView):
236
242
  return ""
237
243
 
238
244
 
239
- def do_base_64(str):
240
- import base64
241
- resp = base64.b64encode(f'{str}'.encode("utf-8"))
242
- return resp.decode()
245
+ # def do_base_64(str):
246
+ # import base64
247
+ # resp = base64.b64encode(f'{str}'.encode("utf-8"))
248
+ # return resp.decode()
243
249
 
244
250
 
245
251
  def get_common_data(user_uuid, mode, no_domain=False, filter_domain=None):
@@ -263,7 +269,7 @@ def get_common_data(user_uuid, mode, no_domain=False, filter_domain=None):
263
269
 
264
270
  if not db_domain:
265
271
  db_domain = DB(domain=domain, show_domains=[])
266
- flash(_("This domain does not exist in the panel!" + domain))
272
+ hutils.flask.flash(_("This domain does not exist in the panel!" + domain))
267
273
 
268
274
  if mode == 'multi':
269
275
  domains = Domain.query.all()
@@ -301,7 +307,7 @@ def get_common_data(user_uuid, mode, no_domain=False, filter_domain=None):
301
307
  d.cdn_ip, d.mode == DomainType.auto_cdn_ip, default_asn)
302
308
  # print("autocdn ip mode ", d.cdn_ip)
303
309
  if "*" in d.domain:
304
- d.domain = d.domain.replace("*", hiddify.get_random_string(5, 15))
310
+ d.domain = d.domain.replace("*", hutils.random.get_random_string(5, 15))
305
311
 
306
312
  package_mode_dic = {
307
313
  UserMode.daily: 1,
@@ -354,7 +360,7 @@ def get_common_data(user_uuid, mode, no_domain=False, filter_domain=None):
354
360
  "asn": asn,
355
361
  "country": auto_ip_selector.get_country(user_ip),
356
362
  'has_auto_cdn': has_auto_cdn,
357
- 'profile_url': hiddify.get_account_panel_link(g.account if g.get('account') else user, domain)
363
+ 'profile_url': hiddify.get_account_panel_link(user, domain)
358
364
  }
359
365
 
360
366
 
@@ -369,6 +375,6 @@ def add_headers(res, c):
369
375
  resp.headers['profile-update-interval'] = 1
370
376
  # resp.headers['content-disposition']=f'attachment; filename="{c["db_domain"].alias or c["db_domain"].domain} {c["user"].name}"'
371
377
 
372
- resp.headers['profile-title'] = 'base64:'+do_base_64(c['profile_title'])
378
+ resp.headers['profile-title'] = 'base64:'+hutils.encode.do_base_64(c['profile_title'])
373
379
 
374
380
  return resp