hiddifypanel 10.70.9__py3-none-any.whl → 10.80.0.dev1__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 (62) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +5 -2
  3. hiddifypanel/__init__.py +5 -1
  4. hiddifypanel/auth.py +8 -3
  5. hiddifypanel/base.py +26 -23
  6. hiddifypanel/cache.py +2 -1
  7. hiddifypanel/drivers/ssh_liberty_bridge_api.py +2 -1
  8. hiddifypanel/drivers/wireguard_api.py +1 -1
  9. hiddifypanel/hutils/crypto.py +27 -0
  10. hiddifypanel/hutils/flask.py +5 -3
  11. hiddifypanel/hutils/network/cf_api.py +5 -5
  12. hiddifypanel/hutils/proxy/clash.py +1 -1
  13. hiddifypanel/hutils/proxy/shared.py +8 -12
  14. hiddifypanel/hutils/proxy/singbox.py +3 -1
  15. hiddifypanel/hutils/proxy/xray.py +1 -1
  16. hiddifypanel/models/admin.py +1 -1
  17. hiddifypanel/models/base_account.py +3 -0
  18. hiddifypanel/models/config.py +1 -1
  19. hiddifypanel/models/config_enum.py +13 -0
  20. hiddifypanel/models/user.py +2 -2
  21. hiddifypanel/panel/admin/AdminstratorAdmin.py +9 -2
  22. hiddifypanel/panel/admin/ProxyAdmin.py +4 -0
  23. hiddifypanel/panel/admin/QuickSetup.py +40 -9
  24. hiddifypanel/panel/admin/SettingAdmin.py +6 -0
  25. hiddifypanel/panel/admin/UserAdmin.py +10 -8
  26. hiddifypanel/panel/admin/adminlte.py +1 -1
  27. hiddifypanel/panel/cli.py +3 -1
  28. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +76 -6
  29. hiddifypanel/panel/common.py +6 -3
  30. hiddifypanel/panel/common_bp/login.py +14 -8
  31. hiddifypanel/panel/init_db.py +139 -62
  32. hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +16 -0
  33. hiddifypanel/panel/user/templates/home/home.html +1 -2
  34. hiddifypanel/panel/user/templates/home/multi.html +1 -2
  35. hiddifypanel/panel/user/user.py +1 -1
  36. hiddifypanel/static/apps-icon/singbox.ico +0 -0
  37. hiddifypanel/templates/fake.html +320 -0
  38. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  39. hiddifypanel/translations/en/LC_MESSAGES/messages.po +50 -24
  40. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  41. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +47 -25
  42. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  43. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +41 -18
  44. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  45. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +56 -29
  46. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  47. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +34 -14
  48. hiddifypanel/translations.i18n/en.json +27 -11
  49. hiddifypanel/translations.i18n/fa.json +26 -10
  50. hiddifypanel/translations.i18n/fr.json +26 -8
  51. hiddifypanel/translations.i18n/my.json +1266 -0
  52. hiddifypanel/translations.i18n/pt.json +21 -5
  53. hiddifypanel/translations.i18n/ru.json +29 -13
  54. hiddifypanel/translations.i18n/zh.json +20 -4
  55. hiddifypanel-10.80.0.dev1.dist-info/METADATA +130 -0
  56. {hiddifypanel-10.70.9.dist-info → hiddifypanel-10.80.0.dev1.dist-info}/RECORD +111 -110
  57. {hiddifypanel-10.70.9.dist-info → hiddifypanel-10.80.0.dev1.dist-info}/WHEEL +1 -2
  58. hiddifypanel-10.80.0.dev1.dist-info/entry_points.txt +3 -0
  59. hiddifypanel-10.70.9.dist-info/METADATA +0 -144
  60. hiddifypanel-10.70.9.dist-info/entry_points.txt +0 -2
  61. hiddifypanel-10.70.9.dist-info/top_level.txt +0 -1
  62. {hiddifypanel-10.70.9.dist-info → hiddifypanel-10.80.0.dev1.dist-info}/LICENSE.md +0 -0
@@ -27,7 +27,7 @@ from hiddifypanel import hutils
27
27
  class UserAdmin(AdminLTEModelView):
28
28
  column_default_sort = ('id', False) # Sort by username in ascending order
29
29
 
30
- column_sortable_list = ["is_active", "name", "current_usage", 'mode', "remaining_days", "comment", 'last_online', "uuid", 'remaining_days']
30
+ column_sortable_list = ["is_active", "name", "current_usage", 'mode', "remaining_days","max_ips", "comment", 'last_online', "uuid", 'remaining_days']
31
31
  column_searchable_list = ["uuid", "name"]
32
32
  column_list = ["is_active", "name", "UserLinks", "current_usage", "remaining_days", "comment", 'last_online', 'mode', 'admin', "uuid"]
33
33
  column_editable_list = ["comment", "name", "uuid"]
@@ -37,8 +37,8 @@ class UserAdmin(AdminLTEModelView):
37
37
  # 'disable_user': SwitchField(_("Disable User"))
38
38
  }
39
39
  list_template = 'model/user_list.html'
40
-
41
- form_columns = ["name", "comment", "usage_limit", "reset_usage", "package_days", "reset_days", "mode", "uuid", "enable",]
40
+ # "max_ips",
41
+ form_columns = ["name","comment", "usage_limit", "reset_usage", "package_days", "reset_days", "mode", "uuid", "enable"]
42
42
  # form_excluded_columns = ['current_usage', 'monthly', 'telegram_id', 'last_online', 'expiry_time', 'last_reset_time', 'current_usage_GB',
43
43
  # 'start_date', 'added_by', 'admin', 'details', 'max_ips', 'ed25519_private_key', 'ed25519_public_key', 'username', 'password']
44
44
  page_size = 50
@@ -48,7 +48,6 @@ class UserAdmin(AdminLTEModelView):
48
48
  # can_export = True
49
49
  # form_overrides = dict(monthly=SwitchField)
50
50
  form_overrides = {
51
-
52
51
  'start_date': custom_widgets.DaysLeftField,
53
52
  'mode': custom_widgets.EnumSelectField,
54
53
  'usage_limit': custom_widgets.UsageField
@@ -71,7 +70,8 @@ class UserAdmin(AdminLTEModelView):
71
70
  'validators': [Regexp(r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', message=__("Should be a valid uuid"))]
72
71
  # 'label': 'First Name',
73
72
  # 'validators': [required()]
74
- }
73
+ },
74
+
75
75
  # ,
76
76
  # 'expiry_time':{
77
77
  # "":'%Y-%m-%d'
@@ -225,11 +225,13 @@ class UserAdmin(AdminLTEModelView):
225
225
 
226
226
  def on_form_prefill(self, form, id=None):
227
227
  # print("================",form._obj.start_date)
228
- if id is None or form._obj is None or form._obj.start_date is None:
228
+ if id is None or form._obj is None or form._obj.start_date is None or form._obj.current_usage==0:
229
229
  msg = _("Package not started yet.")
230
230
  # form.reset['class']="d-none"
231
- delattr(form, 'reset_days')
232
- delattr(form, 'reset_usage')
231
+ if form._obj.start_date is None:
232
+ delattr(form, 'reset_days')
233
+ if form._obj.current_usage==0:
234
+ delattr(form, 'reset_usage')
233
235
  # delattr(form,'disable_user')
234
236
  else:
235
237
  remaining = form._obj.remaining_days # remaining_days(form._obj)
@@ -3,6 +3,7 @@ from hiddifypanel import auth
3
3
  from flask_admin.form import SecureForm
4
4
 
5
5
 
6
+
6
7
  class AdminLTEModelView(ModelView):
7
8
  form_base_class = SecureForm
8
9
  edit_modal = True
@@ -17,6 +18,5 @@ class AdminLTEModelView(ModelView):
17
18
  edit_modal_template = 'flask-admin/model/modals/edit.html'
18
19
  details_modal_template = 'flask-admin/model/modals/details.html'
19
20
 
20
- # form_base_class = SecureForm
21
21
  def inaccessible_callback(self, name, **kwargs):
22
22
  return auth.redirect_to_login() # type: ignore
hiddifypanel/panel/cli.py CHANGED
@@ -131,7 +131,9 @@ def init_app(app):
131
131
  hiddify.add_or_update_config(key=key, value=val)
132
132
 
133
133
  return "success"
134
-
134
+ @app.cli.command()
135
+ def reset_owner_password():
136
+ AdminUser.get_super_admin().update_password("")
135
137
  @ app.cli.command()
136
138
  @ click.option("--config", "-c")
137
139
  def import_config(config):
@@ -108,31 +108,35 @@ class AppAPI(MethodView):
108
108
  apps_data = self.__get_all_apps_dto()
109
109
  case Platform.android:
110
110
  hiddify_next_dto = self.__get_hiddify_next_app_dto()
111
+ singbox_dto = self.__get_singbox_app_dto()
111
112
  hiddifyng_dto = self.__get_hiddifyng_app_dto()
112
113
  v2rayng_dto = self.__get_v2rayng_app_dto()
113
114
  hiddify_clash_android_dto = self.__get_hiddify_clash_android_app_dto()
114
115
  nekobox_dto = self.__get_nekobox_app_dto()
115
- apps_data += ([hiddify_next_dto, hiddifyng_dto, v2rayng_dto, hiddify_clash_android_dto, nekobox_dto])
116
+ apps_data += ([hiddify_next_dto, singbox_dto, v2rayng_dto, nekobox_dto, hiddifyng_dto, hiddify_clash_android_dto])
116
117
  case Platform.windows:
117
118
  hiddify_next_dto = self.__get_hiddify_next_app_dto()
118
119
  hiddify_clash_dto = self.__get_hiddify_clash_desktop_app_dto()
119
120
  hiddifyn_dto = self.__get_hiddifyn_app_dto()
120
121
  apps_data += ([hiddify_next_dto, hiddify_clash_dto, hiddifyn_dto])
121
122
  case Platform.ios:
123
+ hiddify_next_dto = self.__get_hiddify_next_app_dto()
124
+ singbox_dto = self.__get_singbox_app_dto()
122
125
  stash_dto = self.__get_stash_app_dto()
123
126
  shadowrocket_dto = self.__get_shadowrocket_app_dto()
124
127
  foxray_dto = self.__get_foxray_app_dto()
125
128
  streisand_dto = self.__get_streisand_app_dto()
126
129
  loon_dto = self.__get_loon_app_dto()
127
- apps_data += ([streisand_dto, stash_dto, shadowrocket_dto, foxray_dto, loon_dto])
130
+ apps_data += ([hiddify_next_dto, singbox_dto, streisand_dto, stash_dto, shadowrocket_dto, foxray_dto, loon_dto])
128
131
  case Platform.linux:
129
132
  hiddify_next_dto = self.__get_hiddify_next_app_dto()
130
133
  hiddify_clash_dto = self.__get_hiddify_clash_desktop_app_dto()
131
134
  apps_data += ([hiddify_next_dto, hiddify_clash_dto,])
132
135
  case Platform.mac:
136
+ singbox_dto = self.__get_singbox_app_dto()
133
137
  hiddify_clash_dto = self.__get_hiddify_clash_desktop_app_dto()
134
138
  hiddify_next_dto = self.__get_hiddify_next_app_dto()
135
- apps_data += ([hiddify_next_dto, hiddify_clash_dto])
139
+ apps_data += ([hiddify_next_dto, singbox_dto, hiddify_clash_dto])
136
140
 
137
141
  return apps_data
138
142
 
@@ -162,11 +166,12 @@ class AppAPI(MethodView):
162
166
  loon_app_dto = self.__get_loon_app_dto()
163
167
  stash_app_dto = self.__get_stash_app_dto()
164
168
  hiddify_clash_app_dto = self.__get_hiddify_clash_desktop_app_dto()
169
+ singbox_app_dto = self.__get_singbox_app_dto()
165
170
  hiddify_next_app_dto = self.__get_hiddify_next_app_dto()
166
171
  return [
167
172
  hiddifyn_app_dto, v2rayng_app_dto, hiddifyng_app_dto, hiddify_android_app_dto,
168
173
  foxray_app_dto, shadowrocket_app_dto, streisand_app_dto,
169
- loon_app_dto, stash_app_dto, hiddify_clash_app_dto, hiddify_next_app_dto
174
+ loon_app_dto, stash_app_dto, hiddify_clash_app_dto, singbox_app_dto, hiddify_next_app_dto
170
175
  ]
171
176
 
172
177
  def __get_app_icon_url(self, app_name):
@@ -174,6 +179,8 @@ class AppAPI(MethodView):
174
179
  url = ''
175
180
  if app_name == _('app.hiddify.next.title'):
176
181
  url = base + static_url_for(filename='apps-icon/hiddify_next.ico')
182
+ elif app_name == _('app.singbox.title'):
183
+ url = base + static_url_for(filename='apps-icon/singbox.ico')
177
184
  elif app_name == _('app.hiddifyn.title'):
178
185
  url = base + static_url_for(filename='apps-icon/hiddifyn.ico')
179
186
  elif app_name == _('app.v2rayng.title'):
@@ -241,7 +248,7 @@ class AppAPI(MethodView):
241
248
 
242
249
  # make v2rayng latest version url download
243
250
  latest_url, version = get_latest_release_url(f'https://github.com/2dust/v2rayNG/')
244
- github_ins_url = latest_url.split('releases/')[0] + f'releases/download/{version}/v2rayNG_{version}.apk'
251
+ github_ins_url = latest_url.split('releases/')[0] + f'releases/download/{version}/v2rayNG_{version}_universal.apk'
245
252
  google_play_ins_url = 'https://play.google.com/store/apps/details?id=com.v2ray.ang'
246
253
  dto.install = [self.__get_app_install_dto(AppInstallType.apk, github_ins_url), self.__get_app_install_dto(AppInstallType.google_play, google_play_ins_url)]
247
254
  return dto
@@ -367,6 +374,65 @@ class AppAPI(MethodView):
367
374
 
368
375
  return dto
369
376
 
377
+ def __get_singbox_app_dto(self):
378
+ dto = AppSchema()
379
+ dto.title = _('app.singbox.title')
380
+ dto.description = _('app.singbox.description')
381
+ dto.icon_url = self.__get_app_icon_url(_('app.singbox.title'))
382
+ dto.guide_url = ''
383
+ dto.deeplink = f'sing-box://import-remote-profile/?url={self.user_panel_url}'
384
+
385
+ # availabe installatoin types
386
+ installation_types = []
387
+ if self.platform == Platform.all:
388
+ installation_types = [AppInstallType.apk, AppInstallType.google_play, AppInstallType.dmg, AppInstallType.app_store]
389
+ else:
390
+ match self.platform:
391
+ case Platform.android:
392
+ installation_types = [AppInstallType.apk, AppInstallType.google_play]
393
+ case Platform.mac:
394
+ installation_types = [AppInstallType.dmg]
395
+ case Platform.ios:
396
+ installation_types = [AppInstallType.app_store]
397
+
398
+ install_dtos = []
399
+ for install_type in installation_types:
400
+ install_dto = AppInstall()
401
+ ins_url = ''
402
+ match install_type:
403
+ case AppInstallType.apk:
404
+ latest_url, version = get_latest_release_url(f'https://github.com/SagerNet/sing-box')
405
+ ins_url = latest_url.split('releases/')[0] + f'releases/download/{version}/SFA-{version}-universal.apk'
406
+ def remove_v_from_filename(url):
407
+ parts = url.split('/')
408
+ filename = parts[-1]
409
+ new_filename = filename.replace('SFA-v', 'SFA-')
410
+ parts[-1] = new_filename
411
+ new_url = '/'.join(parts)
412
+ return new_url
413
+ ins_url = remove_v_from_filename(ins_url)
414
+ case AppInstallType.google_play:
415
+ ins_url = 'https://play.google.com/store/apps/details?id=io.nekohasekai.sfa'
416
+ case AppInstallType.dmg:
417
+ latest_url, version = get_latest_release_url(f'https://github.com/SagerNet/sing-box')
418
+ ins_url = latest_url.split('releases/')[0] + f'releases/download/{version}/SFM-{version}-universal.dmg'
419
+ def remove_v_from_filename(url):
420
+ parts = url.split('/')
421
+ filename = parts[-1]
422
+ new_filename = filename.replace('SFM-v', 'SFM-')
423
+ parts[-1] = new_filename
424
+ new_url = '/'.join(parts)
425
+ return new_url
426
+ ins_url = remove_v_from_filename(ins_url)
427
+ case AppInstallType.app_store:
428
+ ins_url = 'https://apps.apple.com/us/app/sing-box-vt/id6673731168'
429
+
430
+ install_dto = self.__get_app_install_dto(install_type, ins_url)
431
+ install_dtos.append(install_dto)
432
+
433
+ dto.install = install_dtos
434
+ return dto
435
+
370
436
  def __get_hiddify_next_app_dto(self):
371
437
  dto = AppSchema()
372
438
  dto.title = _('app.hiddify.next.title')
@@ -378,7 +444,7 @@ class AppAPI(MethodView):
378
444
  # availabe installatoin types
379
445
  installation_types = []
380
446
  if self.platform == Platform.all:
381
- installation_types = [AppInstallType.apk, AppInstallType.google_play, AppInstallType.setup, AppInstallType.portable, AppInstallType.appimage, AppInstallType.dmg]
447
+ installation_types = [AppInstallType.apk, AppInstallType.google_play, AppInstallType.setup, AppInstallType.portable, AppInstallType.appimage, AppInstallType.dmg, AppInstallType.app_store]
382
448
  else:
383
449
  match self.platform:
384
450
  case Platform.android:
@@ -389,6 +455,8 @@ class AppAPI(MethodView):
389
455
  installation_types = [AppInstallType.appimage]
390
456
  case Platform.mac:
391
457
  installation_types = [AppInstallType.dmg]
458
+ case Platform.ios:
459
+ installation_types = [AppInstallType.app_store]
392
460
 
393
461
  install_dtos = []
394
462
  for install_type in installation_types:
@@ -407,6 +475,8 @@ class AppAPI(MethodView):
407
475
  ins_url = f'{self.hiddify_github_repo}/hiddify-next/releases/latest/download/Hiddify-Linux-x64.AppImage'
408
476
  case AppInstallType.dmg:
409
477
  ins_url = f'{self.hiddify_github_repo}/hiddify-next/releases/latest/download/Hiddify-MacOS.dmg'
478
+ case AppInstallType.app_store:
479
+ ins_url = 'https://apps.apple.com/us/app/hiddify-proxy-vpn/id6596777532'
410
480
 
411
481
  install_dto = self.__get_app_install_dto(install_type, ins_url)
412
482
  install_dtos.append(install_dto)
@@ -22,6 +22,9 @@ def init_app(app: APIFlask):
22
22
  app.jinja_env.globals['hutils'] = hutils
23
23
  app.jinja_env.globals['hiddify'] = hiddify
24
24
  app.jinja_env.globals['version'] = hiddifypanel.__version__
25
+ if not hiddifypanel.is_released_version:
26
+ app.jinja_env.globals['version']= "DEV"
27
+
25
28
  app.jinja_env.globals['static_url_for'] = hutils.flask.static_url_for
26
29
  app.jinja_env.globals['hurl_for'] = hutils.flask.hurl_for
27
30
  app.jinja_env.globals['_gettext'] = lambda x: print("==========", x)
@@ -40,9 +43,9 @@ def init_app(app: APIFlask):
40
43
  logger.exception(e)
41
44
  if isinstance(e, Exception):
42
45
  if hutils.flask.is_api_call(request.path):
43
- return {
46
+ return jsonify({
44
47
  'msg': str(e),
45
- }, 500
48
+ }), 500
46
49
 
47
50
  if hasattr(e, 'code') and e.code == 404:
48
51
  return jsonify({
@@ -62,7 +65,7 @@ def init_app(app: APIFlask):
62
65
  'version': hiddifypanel.__version__,
63
66
  }), 500
64
67
 
65
- trace = traceback.format_exc()
68
+ trace = traceback.format_exc(e)
66
69
 
67
70
  # Create github issue link
68
71
  issue_link = hutils.github_issue.generate_github_issue_link_for_500_error(e, trace)
@@ -11,6 +11,7 @@ from hiddifypanel.models import *
11
11
 
12
12
  from flask_wtf import FlaskForm
13
13
  import wtforms as wtf
14
+
14
15
  import re
15
16
 
16
17
 
@@ -22,7 +23,10 @@ class LoginForm(FlaskForm):
22
23
  'pattern': "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
23
24
  'message': _('config.invalid_uuid')
24
25
  })
25
- submit = wtf.fields.SubmitField(_('Submit'))
26
+
27
+ password_textbox = wtf.fields.PasswordField(_(f'login.password.label'), default='',
28
+ description=_(f'login.password.description'), render_kw={ })
29
+ submit = wtf.fields.SubmitField(_('login.button'))
26
30
 
27
31
 
28
32
  class LoginView(FlaskView):
@@ -33,8 +37,9 @@ class LoginView(FlaskView):
33
37
  redirect_arg = request.args.get('redirect')
34
38
  username_arg = request.args.get('user') or ''
35
39
  if not current_account:
36
-
37
- return render_template('login.html', form=LoginForm())
40
+ form=LoginForm()
41
+ form.secret_textbox.data=form.secret_textbox.data or username_arg
42
+ return render_template('login.html', form=form)
38
43
 
39
44
  # abort(401, "Unauthorized1")
40
45
 
@@ -52,9 +57,9 @@ class LoginView(FlaskView):
52
57
  form = LoginForm()
53
58
  if form.validate_on_submit():
54
59
  uuid = form.secret_textbox.data.strip()
55
- if login_by_uuid(uuid, hutils.flask.is_admin_proxy_path()):
60
+ if login_by_uuid(uuid,form.password_textbox.data, hutils.flask.is_admin_proxy_path()):
56
61
  return redirect(f'/{g.proxy_path}/')
57
- hutils.flask.flash(_('config.validation-error'), 'danger') # type: ignore
62
+ hutils.flask.flash(_('config.invalid_uuid'), 'danger') # type: ignore
58
63
  return render_template('login.html', form=LoginForm())
59
64
 
60
65
  @ route("/l/<path:path>/")
@@ -68,7 +73,7 @@ class LoginView(FlaskView):
68
73
  redirect_arg = request.args.get('next')
69
74
 
70
75
  if not current_account or (not request.headers.get('Authorization')):
71
- username = request.authorization.username if request.authorization else ''
76
+ username = request.authorization.username if request.authorization else g.uuid
72
77
 
73
78
  loginurl = hurl_for('common_bp.LoginView:index', next=redirect_arg, user=username)
74
79
  if g.user_agent['is_browser'] and request.headers.get('Authorization') or (current_account and len(username) > 0 and current_account.username != username):
@@ -128,7 +133,8 @@ class LoginView(FlaskView):
128
133
  @ route('/<secret_uuid>/manifest.webmanifest')
129
134
  def create_pwa_manifest(self):
130
135
  domain = request.host
131
- name = (domain if hutils.flask.is_admin_panel_call() else g.account.name)
136
+ account=AdminUser.by_uuid(g.uuid)
137
+ name = (domain if hutils.flask.is_admin_panel_call() else account.name)
132
138
  return jsonify({
133
139
  "name": f"Hiddify {name}",
134
140
  "short_name": f"{name}"[:12],
@@ -136,7 +142,7 @@ class LoginView(FlaskView):
136
142
  "background_color": "#1a1b21",
137
143
  "display": "standalone",
138
144
  "scope": f"/",
139
- "start_url": hiddify.get_account_panel_link(g.account, domain) + "?pwa=true",
145
+ "start_url": hiddify.get_account_panel_link(account, domain) + "?pwa=true",
140
146
  "description": "Hiddify, for a free Internet",
141
147
  "orientation": "any",
142
148
  "icons": [