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
@@ -2,6 +2,7 @@
2
2
  from urllib.parse import urlparse
3
3
  from flask_babelex import gettext as _
4
4
  from flask_bootstrap import SwitchField
5
+ from hiddifypanel import hutils
5
6
  # from flask_babelex import gettext as _
6
7
  import wtforms as wtf
7
8
  from flask_wtf import FlaskForm
@@ -10,7 +11,6 @@ import json
10
11
  import json
11
12
  from flask import render_template, request, jsonify, redirect, g
12
13
  from hiddifypanel.panel.auth import login_required
13
- from hiddifypanel.panel.hiddify import flash
14
14
  from flask_wtf.file import FileField, FileRequired
15
15
  from flask_classful import FlaskView
16
16
 
@@ -58,13 +58,13 @@ class Backup(FlaskView):
58
58
 
59
59
  from flask_babel import refresh
60
60
  refresh()
61
- return redirect(url_for("admin.Actions:reinstall2"))
61
+ return redirect(hutils.flask.url_for("admin.Actions:reinstall2"))
62
62
  # from . import Actions
63
63
  # action = Actions()
64
64
  # return action.reinstall(complete_install=True, domain_changed=True)
65
- # # hiddify.flash_config_success(full_install=True)
65
+ # # hutils.flask.flash_config_success(full_install=True)
66
66
  else:
67
- flash(_('Config file is incorrect'), category='error')
67
+ hutils.flask.flash(_('Config file is incorrect'), category='error')
68
68
  return render_template('backup.html', restore_form=restore_form)
69
69
 
70
70
 
@@ -74,7 +74,7 @@ def get_restore_form(empty=False):
74
74
  enable_config_restore = SwitchField(_("Restore Settings"), description=_("Restore Settings description"), default=False)
75
75
  enable_user_restore = SwitchField(_("Restore Users"), description=_("Restore Users description"), default=False)
76
76
  enable_domain_restore = SwitchField(_("Restore Domain"), description=_("Restore Domain description"), default=False)
77
- override_root_admin = SwitchField(_("Override Root Admin"), description=_("It will override the root admin to the current user"), default=True)
77
+ override_root_admin = SwitchField(_("Override Root Admin"), description=_("It will override the root admin to the current user"), default=False)
78
78
  submit = wtf.fields.SubmitField(_('Submit'))
79
79
 
80
80
  return RestoreForm(None) if empty else RestoreForm()
@@ -3,7 +3,7 @@ from hiddifypanel.models import *
3
3
  from .adminlte import AdminLTEModelView
4
4
  from flask_babelex import gettext as __
5
5
  from flask_babelex import lazy_gettext as _
6
- from flask import Markup
6
+ from flask import Markup, g
7
7
 
8
8
  from hiddifypanel.panel.auth import login_required
9
9
  from hiddifypanel.panel import hiddify
@@ -103,12 +103,12 @@ class ChildAdmin(AdminLTEModelView):
103
103
  if len(model.show_domains) == Domain.query.count():
104
104
  model.show_domains = []
105
105
 
106
- hiddify.flash_config_success(restart_mode='apply', domain_changed=True)
106
+ hutils.flask.flash_config_success(restart_mode='apply', domain_changed=True)
107
107
 
108
108
  def on_model_delete(self, model):
109
109
  if len(ParentDomain.query.all()) <= 1:
110
110
  raise ValidationError(f"at least one domain should exist")
111
- hiddify.flash_config_success(restart_mode='apply', domain_changed=True)
111
+ hutils.flask.flash_config_success(restart_mode='apply', domain_changed=True)
112
112
 
113
113
  def is_accessible(self):
114
114
  if login_required(roles={Role.super_admin})(lambda: True)() != True:
@@ -11,7 +11,7 @@ import hiddifypanel
11
11
  from hiddifypanel.models import *
12
12
  from hiddifypanel.panel import hiddify
13
13
  from hiddifypanel.panel.database import db
14
- from hiddifypanel.panel.hiddify import flash
14
+ from hiddifypanel import hutils
15
15
 
16
16
 
17
17
  class Dashboard(FlaskView):
@@ -33,7 +33,7 @@ class Dashboard(FlaskView):
33
33
  if hconfig(ConfigEnum.first_setup):
34
34
  return redirect(url_for("admin.QuickSetup:index"))
35
35
  if hiddifypanel.__release_date__ + datetime.timedelta(days=20) < datetime.datetime.now():
36
- flash(_('This version of hiddify panel is outdated. Please update it from admin area.'), "danger")
36
+ hutils.flask.flash(_('This version of hiddify panel is outdated. Please update it from admin area.'), "danger") # type: ignore
37
37
  bot = None
38
38
  # if hconfig(ConfigEnum.license):
39
39
  childs = None
@@ -65,21 +65,23 @@ class Dashboard(FlaskView):
65
65
 
66
66
  if def_user and sslip_domains:
67
67
  quick_setup = url_for("admin.QuickSetup:index")
68
- flash((_('It seems that you have not setup the system completely. <a class="btn btn-success" href="%(quick_setup)s">Click here</a> to complete setup.', quick_setup=quick_setup)), 'warning')
68
+ hutils.flask.flash((_('It seems that you have not setup the system completely. <a class="btn btn-success" href="%(quick_setup)s">Click here</a> to complete setup.',
69
+ quick_setup=quick_setup)), 'warning') # type: ignore
69
70
  if hconfig(ConfigEnum.is_parent):
70
- flash(_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger")
71
+ hutils.flask.flash(_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
71
72
  elif len(sslip_domains):
72
- flash((_('It seems that you are using default domain (%(domain)s) which is not recommended.', domain=sslip_domains[0])), 'warning')
73
+ hutils.flask.flash((_('It seems that you are using default domain (%(domain)s) which is not recommended.', domain=sslip_domains[0])), 'warning') # type: ignore
73
74
  if hconfig(ConfigEnum.is_parent):
74
- flash(_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger")
75
+ hutils.flask.flash(_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
75
76
  elif def_user:
76
77
  d = domains[0]
77
- flash((_('It seems that you have not created any users yet. Default user link: %(default_link)s', default_link=hiddify.get_html_user_link(def_user, d))), 'secondary')
78
+ hutils.flask.flash((_('It seems that you have not created any users yet. Default user link: %(default_link)s',
79
+ default_link=hiddify.get_html_user_link(def_user, d))), 'secondary') # type: ignore
78
80
  if hiddify.is_ssh_password_authentication_enabled():
79
- flash(_('ssh.password-login.warning.'), "warning")
81
+ hutils.flask.flash(_('ssh.password-login.warning.'), "warning") # type: ignore
80
82
 
81
83
  # except:
82
- # flash((_('Error!!!')),'info')
84
+ # hutils.flask.flash((_('Error!!!')),'info')
83
85
 
84
86
  stats = {'system': hiddify.system_stats(), 'top5': hiddify.top_processes()}
85
87
  return render_template('index.html', stats=stats, usage_history=DailyUsage.get_daily_usage_stats(admin_id, child_id), childs=childs)
@@ -91,5 +93,5 @@ class Dashboard(FlaskView):
91
93
  child = Child.query.filter(Child.id == child_id).first()
92
94
  db.session.delete(child)
93
95
  db.session.commit()
94
- flash(_("child has been removed!"), "success")
96
+ hutils.flask.flash(_("child has been removed!"), "success") # type: ignore
95
97
  return self.index()
@@ -4,7 +4,6 @@ import hiddifypanel.panel.auth as auth
4
4
  from hiddifypanel.models import *
5
5
  import re
6
6
  from flask import Markup, g
7
- from flask import flash
8
7
  from flask_babelex import gettext as __
9
8
  from flask_babelex import lazy_gettext as _
10
9
  from hiddifypanel.panel.run_commander import Command, commander
@@ -91,7 +90,7 @@ class DomainAdmin(AdminLTEModelView):
91
90
  return Markup(f"<span class='badge'>{model.domain}</span>")
92
91
  d = model.domain
93
92
  if "*" in d:
94
- d = d.replace("*", hiddify.get_random_string(5, 15))
93
+ d = d.replace("*", hutils.random.get_random_string(5, 15))
95
94
  admin_link = hiddify.get_account_panel_link(g.account, d)
96
95
  return Markup(
97
96
  f'<div class="btn-group"><a href="{admin_link}" class="btn btn-xs btn-secondary">' + _("admin link") +
@@ -170,7 +169,7 @@ class DomainAdmin(AdminLTEModelView):
170
169
  raise ValidationError(__("Can not connect to Cloudflare.")+f' {e}')
171
170
  # elif model.mode==DomainType.auto_cdn_ip:
172
171
  if model.alias and not model.alias.replace("_", "").isalnum():
173
- flash(__("Using alias with special charachters may cause problem in some clients like FairVPN."), 'warning')
172
+ hutils.flask.flash(__("Using alias with special charachters may cause problem in some clients like FairVPN."), 'warning')
174
173
  # raise ValidationError(_("You have to add your cloudflare api key to use this feature: "))
175
174
 
176
175
  dip = hutils.ip.get_domain_ip(model.domain)
@@ -187,11 +186,13 @@ class DomainAdmin(AdminLTEModelView):
187
186
  domain_ip_is_same_as_panel |= ipaddress.ip_address(dip) == ipaddress.ip_address(ipv6)
188
187
 
189
188
  if model.mode == DomainType.direct and not domain_ip_is_same_as_panel:
190
- flash(__(message=f"Domain IP={dip} is not matched with your ip={', '.join(list(map(str, ipv4_list)))} which is required in direct mode"), category='warning')
189
+ hutils.flask.flash(
190
+ __(message=f"Domain IP={dip} is not matched with your ip={', '.join(list(map(str, ipv4_list)))} which is required in direct mode"),
191
+ category='warning')
191
192
  # raise ValidationError(_("Domain IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode", server_ip=myip, domain_ip=dip))
192
193
 
193
194
  if domain_ip_is_same_as_panel and model.mode in [DomainType.cdn, DomainType.relay, DomainType.fake, DomainType.auto_cdn_ip]:
194
- flash(__(f"In CDN mode, Domain IP={dip} should be different to your ip={', '.join(list(map(str, ipv4_list)))}"), 'warning')
195
+ hutils.flask.flash(__(f"In CDN mode, Domain IP={dip} should be different to your ip={', '.join(list(map(str, ipv4_list)))}"), 'warning')
195
196
  # raise ValidationError(_("In CDN mode, Domain IP=%(domain_ip)s should be different to your ip=%(server_ip)s", server_ip=myip, domain_ip=dip))
196
197
 
197
198
  # if model.mode in [DomainType.ss_faketls, DomainType.telegram_faketls]:
@@ -220,7 +221,7 @@ class DomainAdmin(AdminLTEModelView):
220
221
  if model.mode == DomainType.reality:
221
222
  model.servernames = (model.domain).lower()
222
223
  if not hiddify.is_domain_reality_friendly(model.domain):
223
- # flash(_("Domain is not REALITY friendly!")+" "+d,'error')
224
+ # hutils.flask.flash(_("Domain is not REALITY friendly!")+" "+d,'error')
224
225
  # return render_template('config.html', form=form)
225
226
  raise ValidationError(_("Domain is not REALITY friendly!")+" "+model.domain)
226
227
 
@@ -235,7 +236,7 @@ class DomainAdmin(AdminLTEModelView):
235
236
  continue
236
237
 
237
238
  if not hiddify.is_domain_reality_friendly(d):
238
- # flash(_("Domain is not REALITY friendly!")+" "+d,'error')
239
+ # hutils.flask.flash(_("Domain is not REALITY friendly!")+" "+d,'error')
239
240
  # return render_template('config.html', form=form)
240
241
  raise ValidationError(_("Domain is not REALITY friendly!")+" "+d)
241
242
 
@@ -255,7 +256,7 @@ class DomainAdmin(AdminLTEModelView):
255
256
  old_db_domain = get_domain(model.domain)
256
257
  if is_created or not old_db_domain or old_db_domain.mode != model.mode:
257
258
  # return hiddify.reinstall_action(complete_install=False, domain_changed=True)
258
- hiddify.flash_config_success(restart_mode='apply', domain_changed=True)
259
+ hutils.flask.flash_config_success(restart_mode='apply', domain_changed=True)
259
260
 
260
261
  # def after_model_change(self,form, model, is_created):
261
262
  # if model.show_domains.count==0:
@@ -267,7 +268,7 @@ class DomainAdmin(AdminLTEModelView):
267
268
  # ShowDomain.query.filter_by(related_id == model.id).delete()
268
269
  model.showed_by_domains = []
269
270
  # db.session.commit()
270
- hiddify.flash_config_success(restart_mode='apply', domain_changed=True)
271
+ hutils.flask.flash_config_success(restart_mode='apply', domain_changed=True)
271
272
 
272
273
  def after_model_delete(self, model):
273
274
  # if hconfig(ConfigEnum.parent_panel):
@@ -1,4 +1,5 @@
1
1
  from flask_babelex import gettext as _
2
+ from hiddifypanel import hutils
2
3
  from hiddifypanel.models.role import Role
3
4
  import wtforms as wtf
4
5
  from flask_wtf import FlaskForm
@@ -7,13 +8,10 @@ from flask import render_template
7
8
 
8
9
 
9
10
  from hiddifypanel.models import ConfigEnum, get_hconfigs, BoolConfig, ConfigEnum, hconfig, Proxy
10
- from hiddifypanel.panel.hiddify import flash
11
11
  from hiddifypanel.panel.database import db
12
12
  from wtforms.fields import *
13
13
  from hiddifypanel.panel import hiddify
14
14
  from flask_classful import FlaskView
15
- from hiddifypanel.panel.hiddify import flash
16
- from hiddifypanel.panel import hiddify
17
15
  from hiddifypanel.panel.auth import login_required
18
16
 
19
17
 
@@ -33,7 +31,7 @@ class ProxyAdmin(FlaskView):
33
31
  if k in [c for c in ConfigEnum]:
34
32
  BoolConfig.query.filter(BoolConfig.key == k).first().value = vs
35
33
  if vs and k in [ConfigEnum.domain_fronting_http_enable, ConfigEnum.domain_fronting_tls_enable] and hconfig(ConfigEnum.domain_fronting_domain) == "":
36
- flash((_('config.domain-fronting-notsetup-error')), 'danger')
34
+ hutils.flask.flash((_('config.domain-fronting-notsetup-error')), 'danger')
37
35
 
38
36
  # print(cat,vs)
39
37
  hiddify.get_available_proxies.invalidate_all()
@@ -58,12 +56,12 @@ class ProxyAdmin(FlaskView):
58
56
  # print(cat,vs)
59
57
  db.session.commit()
60
58
  hiddify.get_available_proxies.invalidate_all()
61
- hiddify.flash_config_success(restart_mode='apply', domain_changed=False)
59
+ hutils.flask.flash_config_success(restart_mode='apply', domain_changed=False)
62
60
  # if hconfig(ConfigEnum.parent_panel):
63
61
  # hiddify_api.sync_child_to_parent()
64
62
  global_config_form = get_global_config_form(True)
65
63
  else:
66
- flash((_('config.validation-error')), 'danger')
64
+ hutils.flask.flash((_('config.validation-error')), 'danger')
67
65
 
68
66
  return render_template('proxy.html', global_config_form=global_config_form, detailed_config_form=all_proxy_form)
69
67
 
@@ -1,26 +1,24 @@
1
- from hiddifypanel.panel.auth import login_required
2
- from hiddifypanel import hutils
3
- from hiddifypanel.models import *
1
+ import re
4
2
  import flask_babel
5
3
  import flask_babelex
6
4
 
7
5
  # from flask_babelex import lazy_gettext as _
6
+ from flask import render_template, g
8
7
  from flask_babelex import gettext as _
9
8
  import wtforms as wtf
10
9
  from flask_wtf import FlaskForm
11
10
  from flask_bootstrap import SwitchField
12
11
  from hiddifypanel.panel import hiddify
13
- # from gettext import gettext as _
12
+ from wtforms.fields import *
13
+ from flask_classful import FlaskView
14
14
  from wtforms.validators import ValidationError
15
+ # from gettext import gettext as _
15
16
 
16
- import re
17
- from flask import render_template, g
18
17
  from hiddifypanel.models import Domain, DomainType, StrConfig, ConfigEnum, get_hconfigs
19
18
  from hiddifypanel.panel.database import db
20
- from wtforms.fields import *
21
-
22
- from hiddifypanel.panel.hiddify import flash
23
- from flask_classful import FlaskView
19
+ from hiddifypanel.panel.auth import login_required
20
+ from hiddifypanel import hutils
21
+ from hiddifypanel.models import *
24
22
 
25
23
 
26
24
  class QuickSetup(FlaskView):
@@ -51,9 +49,9 @@ class QuickSetup(FlaskView):
51
49
  # with flask_babel.force_locale(lang_form.admin_lang.data):
52
50
  # flask_babel.refresh()
53
51
  # flask_babelex.refresh()
54
- flash((_('quicksetup.setlang.success')), 'success')
52
+ hutils.flask.flash((_('quicksetup.setlang.success')), 'success')
55
53
  else:
56
- flash((_('quicksetup.setlang.error')), 'danger')
54
+ hutils.flask.flash((_('quicksetup.setlang.error')), 'danger')
57
55
 
58
56
  return render_template(
59
57
  'quick_setup.html', form=get_quick_setup_form(True),
@@ -80,7 +78,7 @@ class QuickSetup(FlaskView):
80
78
  action = Actions.Actions()
81
79
  return action.reinstall(domain_changed=True)
82
80
  else:
83
- flash(_('config.validation-error'), 'danger')
81
+ hutils.flask.flash(_('config.validation-error'), 'danger')
84
82
  return render_template(
85
83
  'quick_setup.html', form=quick_form, lang_form=get_lang_form(True),
86
84
  ipv4=hutils.ip.get_ip(4),
@@ -1,9 +1,11 @@
1
+ import re
1
2
  import flask_babel
2
3
  import flask_babelex
3
4
  from flask_babelex import lazy_gettext as _
4
5
  # from flask_babelex import gettext as _
5
6
  from flask import render_template, Markup, url_for, g
6
7
  from flask import current_app as app
8
+ from hiddifypanel import hutils
7
9
  from hiddifypanel.panel.auth import login_required
8
10
  import wtforms as wtf
9
11
  from flask_bootstrap import SwitchField
@@ -13,12 +15,10 @@ from flask_classful import FlaskView
13
15
  from wtforms.fields import *
14
16
  from flask_wtf import FlaskForm
15
17
 
16
- import re
17
18
 
18
19
  from hiddifypanel.models import BoolConfig, StrConfig, ConfigEnum, hconfig, ConfigCategory
19
20
  from hiddifypanel.models import *
20
21
  from hiddifypanel.panel.database import db
21
- from hiddifypanel.panel.hiddify import flash
22
22
  from hiddifypanel.panel.hiddify import get_random_domains
23
23
  from hiddifypanel.panel import hiddify, custom_widgets
24
24
 
@@ -57,7 +57,7 @@ class SettingAdmin(FlaskView):
57
57
  for p in v.split(","):
58
58
  for k2, v2 in vs.items():
59
59
  if "port" in k2 and k != k2 and p in v2:
60
- flash(_("Port is already used! in")+f" {k2} {k}", 'error')
60
+ hutils.flask.flash(_("Port is already used! in")+f" {k2} {k}", 'error')
61
61
  return render_template('config.html', form=form)
62
62
  if k == ConfigEnum.parent_panel and v != '':
63
63
  # v=(v+"/").replace("/admin",'')
@@ -65,10 +65,10 @@ class SettingAdmin(FlaskView):
65
65
 
66
66
  # try:
67
67
  # # if hiddify_api.sync_child_to_parent(v)['status'] != 200:
68
- # # flash(_("Can not connect to parent panel!"), 'error')
68
+ # # hutils.flask.flash(_("Can not connect to parent panel!"), 'error')
69
69
  # # return render_template('config.html', form=form)
70
70
  # except:
71
- # flash(_("Can not connect to parent panel!"), 'error')
71
+ # hutils.flask.flash(_("Can not connect to parent panel!"), 'error')
72
72
  # return render_template('config.html', form=form)
73
73
  StrConfig.query.filter(StrConfig.key == k, StrConfig.child_id == 0).first().value = v
74
74
  if old_configs[k] != v:
@@ -78,20 +78,20 @@ class SettingAdmin(FlaskView):
78
78
 
79
79
  merged_configs = {**old_configs, **changed_configs}
80
80
  if len(set([merged_configs[ConfigEnum.proxy_path], merged_configs[ConfigEnum.proxy_path_client], merged_configs[ConfigEnum.proxy_path_admin]])) != 3:
81
- flash(_("ProxyPath is already used! use different proxy path"), 'error')
81
+ hutils.flask.flash(_("ProxyPath is already used! use different proxy path"), 'error')#type: ignore
82
82
  return render_template('config.html', form=form)
83
83
  # for k in [ConfigEnum.reality_server_names,ConfigEnum.reality_fallback_domain]:
84
84
  # v=merged_configs[k]
85
85
  # for d in v.split(","):
86
86
  # if not d:continue
87
87
  # if not hiddify.is_domain_reality_friendly(d):
88
- # flash(_("Domain is not REALITY friendly!")+" "+d,'error')
88
+ # hutils.flask.flash(_("Domain is not REALITY friendly!")+" "+d,'error')
89
89
  # return render_template('config.html', form=form)
90
90
  # hiddify.debug_flash_if_not_in_the_same_asn(d)
91
91
  # fallback=merged_configs[ConfigEnum.reality_fallback_domain]
92
92
  # for d in merged_configs[ConfigEnum.reality_server_names].split(","):
93
93
  # if not hiddify.fallback_domain_compatible_with_servernames(fallback, d):
94
- # flash(_("REALITY Fallback domain is not compaitble with server names!")+" "+d+" != "+fallback,'error')
94
+ # hutils.flask.flash(_("REALITY Fallback domain is not compaitble with server names!")+" "+d+" != "+fallback,'error')
95
95
  # return render_template('config.html', form=form)
96
96
  for k, v in changed_configs.items():
97
97
  set_hconfig(k, v, 0, False)
@@ -110,7 +110,7 @@ class SettingAdmin(FlaskView):
110
110
  if old_configs[ConfigEnum.admin_lang] != hconfig(ConfigEnum.admin_lang):
111
111
  form = get_config_form()
112
112
  else:
113
- flash(_('config.validation-error'), 'danger')
113
+ hutils.flask.flash(_('config.validation-error'), 'danger')#type: ignore
114
114
 
115
115
  return reset_action or render_template('config.html', form=form)
116
116
 
@@ -211,6 +211,10 @@ def get_config_form():
211
211
  libs = [("python", _("lib.telegram.python")), ("tgo", _("lib.telegram.go")), ("orig", _("lib.telegram.orignal")), ("erlang", _("lib.telegram.erlang"))]
212
212
  field = wtf.fields.SelectField(_("config.telegram_lib.label"), choices=libs, description=_(
213
213
  "config.telegram_lib.description"), default=hconfig(ConfigEnum.telegram_lib))
214
+ elif c.key == ConfigEnum.mux_protocol:
215
+ choices = [("smux", 'smux'), ("yamux", "yamux"), ("h2mux", "h2mux")]
216
+ field = wtf.fields.SelectField(_(f"config.{c.key}.label"), choices=choices, description=_(f"config.{c.key}.description"), default=hconfig(c.key))
217
+
214
218
  elif c.key == ConfigEnum.warp_sites:
215
219
  validators = [wtf.validators.Length(max=2048)]
216
220
  render_kw = {'class': "ltr", 'maxlength': 2048}
@@ -265,9 +269,15 @@ def get_config_form():
265
269
  render_kw['required'] = ""
266
270
  else:
267
271
  validators.append(wtf.validators.Regexp("^(\d+)(,\d+)*$|^$", re.IGNORECASE, _("config.Invalid port")))
268
-
269
272
  # validators.append(wtf.validators.Regexp("^(\d+)(,\d+)*$",re.IGNORECASE,_("config.port is required")))
270
273
 
274
+ # tls tricks validations
275
+ if c.key in [ConfigEnum.tls_fragment_size, ConfigEnum.tls_fragment_sleep, ConfigEnum.tls_padding_length]:
276
+ validators.append(wtf.validators.Regexp("^\d+-\d+$", re.IGNORECASE, _("config.Invalid! The pattern is number-number")+f' {c.key}'))
277
+ # mux and hysteria validations
278
+ if c.key in [ConfigEnum.hysteria_up_mbps, ConfigEnum.hysteria_down_mbps, ConfigEnum.mux_max_connections, ConfigEnum.mux_min_streams, ConfigEnum.mux_max_streams,
279
+ ConfigEnum.mux_brutal_down_mbps, ConfigEnum.mux_brutal_up_mbps]:
280
+ validators.append(wtf.validators.Regexp("^\d+$", re.IGNORECASE, _("config.Invalid! it should be a number only")+f' {c.key}'))
271
281
  for val in validators:
272
282
  if hasattr(val, "regex"):
273
283
  render_kw['pattern'] = val.regex.pattern
@@ -1,9 +1,8 @@
1
- from hiddifypanel.models import *
2
- from flask_bootstrap import SwitchField
3
- from hiddifypanel.drivers import user_driver
4
- from hiddifypanel.panel.hiddify import flash
5
- from hiddifypanel.panel import hiddify, custom_widgets
1
+ import re
2
+ import datetime
3
+ import uuid
6
4
  from apiflask import abort
5
+ from flask_bootstrap import SwitchField
7
6
  from flask_babelex import gettext as __
8
7
  from .adminlte import AdminLTEModelView
9
8
  from wtforms.validators import NumberRange
@@ -11,10 +10,12 @@ from flask_babelex import lazy_gettext as _
11
10
  from flask import Markup, g, request, url_for
12
11
  from wtforms.validators import Regexp, ValidationError
13
12
  from flask import current_app
14
- import datetime
15
- import uuid
16
- import re
13
+
14
+ from hiddifypanel.models import *
15
+ from hiddifypanel.drivers import user_driver
16
+ from hiddifypanel.panel import hiddify, custom_widgets
17
17
  from hiddifypanel.panel.auth import login_required
18
+ from hiddifypanel import hutils
18
19
  import hiddifypanel.panel.auth as auth
19
20
 
20
21
 
@@ -204,7 +205,7 @@ class UserAdmin(AdminLTEModelView):
204
205
  if len(User.query.all()) <= 1:
205
206
  raise ValidationError(f"at least one user should exist")
206
207
  user_driver.remove_client(model)
207
- # hiddify.flash_config_success()
208
+ # hutils.flask.flash_config_success()
208
209
 
209
210
  def is_accessible(self):
210
211
  if login_required(roles={Role.super_admin, Role.admin, Role.agent})(lambda: True)() != True:
@@ -246,12 +247,13 @@ class UserAdmin(AdminLTEModelView):
246
247
  def on_model_change(self, form, model, is_created):
247
248
  model.max_ips = max(3, model.max_ips or 10000)
248
249
  if len(User.query.all()) % 4 == 0:
249
- flash(('<div id="show-modal-donation"></div>'), ' d-none')
250
+ hutils.flask.flash(('<div id="show-modal-donation"></div>'), ' d-none')
250
251
  if not re.match("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", model.uuid):
251
252
  raise ValidationError('Invalid UUID e.g.,' + str(uuid.uuid4()))
252
-
253
253
  if form.reset_usage.data:
254
254
  model.current_usage_GB = 0
255
+ # if model.telegram_id and model.telegram_id != '0' and not re.match(r"^[1-9]\d*$", model.telegram_id):
256
+ # raise ValidationError('Invalid Telegram ID')
255
257
  # if form.disable_user.data:
256
258
  # model.mode=UserMode.disable
257
259
  if form.reset_days.data:
@@ -275,7 +277,7 @@ class UserAdmin(AdminLTEModelView):
275
277
  # xray_api.add_client(model.uuid)
276
278
  # else:
277
279
  # xray_api.remove_client(model.uuid)
278
- # hiddify.flash_config_success()
280
+ # hutils.flask.flash_config_success()
279
281
 
280
282
  def after_model_change(self, form, model, is_created):
281
283
  if hconfig(ConfigEnum.first_setup):
@@ -10,13 +10,46 @@ import hiddifypanel.panel.hiddify as hiddify
10
10
  from hiddifypanel import hutils
11
11
 
12
12
  from werkzeug.local import LocalProxy
13
+
13
14
  current_account = LocalProxy(lambda: _get_user())
14
15
 
15
16
 
17
+ class AnonymousAccount(BaseAccount):
18
+ __abstract__ = True
19
+
20
+ @property
21
+ def uuid(self):
22
+ return None
23
+
24
+ @property
25
+ def lang(self) -> Lang:
26
+ return None
27
+
28
+ @property
29
+ def role(self) -> Role | None:
30
+ return None
31
+
32
+ def get_id(self) -> str | None:
33
+ return "-1"
34
+
35
+ def __bool__(self):
36
+ return False
37
+
38
+ def __eq__(self, other):
39
+ if other == None:
40
+ return True
41
+ if isinstance(other, AnonymousAccount):
42
+ return True
43
+ return False
44
+
45
+ def __ne__(self, other):
46
+ return not self.__eq__(other)
47
+
48
+
16
49
  def _get_user():
17
- if not hasattr(g, "account"):
18
- g.account = None
19
- return g.account
50
+ if not hasattr(g, "__account_store"):
51
+ g.__account_store = AnonymousAccount()
52
+ return g.__account_store
20
53
 
21
54
 
22
55
  def admin_session_is_exist():
@@ -24,7 +57,7 @@ def admin_session_is_exist():
24
57
 
25
58
 
26
59
  def logout_user():
27
- g.account = None
60
+ g.__account_store = None
28
61
  if '_user_id' in session:
29
62
  session.pop('_user_id')
30
63
  if '_admin_id' in session:
@@ -33,7 +66,7 @@ def logout_user():
33
66
 
34
67
  def login_user(user: AdminUser | User, remember=False, duration=None, force=False, fresh=True):
35
68
  # abort(400, f'logining user: {user} {user.is_active}')
36
- g.account = user
69
+ g.__account_store = user
37
70
  # if not user.is_active:
38
71
  # return False
39
72
 
@@ -122,7 +155,7 @@ def init_app(app):
122
155
 
123
156
  elif auth_header := request.headers.get("Hiddify_API_KEY"):
124
157
  # print("auth_header", auth_header)
125
- apikey = hutils.utils.get_apikey_from_auth_header(auth_header)
158
+ apikey = hutils.auth.get_apikey_from_auth_header(auth_header)
126
159
  account = get_account_by_api_key(apikey, is_admin_path)
127
160
  if not account:
128
161
  return logout_redirect()
@@ -139,23 +172,23 @@ def init_app(app):
139
172
  return logout_redirect()
140
173
 
141
174
  elif (session_user := session.get('_user_id')) and not is_admin_path:
142
- print('session_user', session_user)
175
+ # print('session_user', session_user)
143
176
  account = User.by_id(int(session_user.split("_")[1])) # type: ignore
144
177
  if not account:
145
178
  return logout_redirect()
146
179
  elif (session_admin := session.get('_admin_id')) and is_admin_path:
147
- print('session_admin', session_admin)
180
+ # print('session_admin', session_admin)
148
181
  account = AdminUser.by_id(int(session_admin.split("_")[1])) # type: ignore
149
182
  if not account:
150
183
  return logout_redirect()
151
184
 
152
185
  if account:
153
- g.account = account
186
+ g.__account_store = account
154
187
  # g.account_uuid = account.uuid
155
188
  g.is_admin = hiddify.is_admin_role(account.role) # type: ignore
156
189
  login_user(account, force=True)
157
190
  # print("loggining in")
158
- if next_url is not None and g.user_agent['is_browser']:
191
+ if next_url is not None and g.user_agent['is_browser'] and ".webmanifest" not in request.path:
159
192
  return redirect(next_url)
160
193
 
161
194
  @app.url_value_preprocessor
@@ -77,7 +77,7 @@ class CustumLoginManager(LoginManager):
77
77
  is_api_call = False
78
78
 
79
79
  if hiddify.is_api_call(request.path):
80
- if apikey := hutils.utils.get_apikey_from_auth_header(auth_header):
80
+ if apikey := hutils.auth.get_apikey_from_auth_header(auth_header):
81
81
  account = User.by_uuid(apikey) or AdminUser.by_uuid(apikey)
82
82
  is_api_call = True
83
83
  else:
@@ -149,7 +149,7 @@ def get_account_by_api_key(api_key, is_admin):
149
149
 
150
150
 
151
151
  def get_account_by_uuid(uuid, is_admin):
152
- return AdminUser.by_uuid(api_key) if is_admin else User.by_uuid(api_key)
152
+ return AdminUser.by_uuid(uuid) if is_admin else User.by_uuid(uuid)
153
153
 
154
154
 
155
155
  def init_app(app):
@@ -165,12 +165,12 @@ def init_app(app):
165
165
  next_url = None
166
166
  print("--------1")
167
167
  if auth_header := request.headers.get("Authorization"):
168
- apikey = hutils.utils.get_apikey_from_auth_header(auth_header)
168
+ apikey = hutils.auth.get_apikey_from_auth_header(auth_header)
169
169
  account = get_account_by_api_key(apikey, is_admin_path)
170
170
  if not account:
171
171
  logout_user()
172
172
 
173
- if not account and (uuid := hutils.utils.get_uuid_from_url_path(request.path)):
173
+ if not account and (uuid := hutils.auth.get_uuid_from_url_path(request.path)):
174
174
  account = get_account_by_uuid(uuid, is_admin_path)
175
175
  if not account:
176
176
  logout_user()
@@ -208,7 +208,7 @@ def init_app(app):
208
208
  # return header_auth(request)
209
209
 
210
210
  # parse id
211
- acc_type, id = hutils.utils.parse_login_id(id) # type: ignore
211
+ acc_type, id = hutils.auth.parse_login_id(id) # type: ignore
212
212
  if not acc_type or not id:
213
213
  return
214
214
 
hiddifypanel/panel/cli.py CHANGED
@@ -105,6 +105,7 @@ def admin_links():
105
105
 
106
106
  def admin_path():
107
107
  admin = AdminUser.get_super_admin()
108
+ # WTF is the owner and server_id?
108
109
  print(hiddify.get_account_panel_link(owner, server_ip, prefere_path_only=True))
109
110
 
110
111
 
@@ -64,7 +64,7 @@ class ParentDomainAdmin(AdminLTEModelView):
64
64
  form_columns = ['domain', "alias", 'show_domains']
65
65
 
66
66
  def _domain_admin_link(view, context, model, name):
67
- admin_link = hiddify.get_account_panel_link(g.account,model.domain)
67
+ admin_link = hiddify.get_account_panel_link(g.account, model.domain)
68
68
  return Markup(f'<div class="btn-group"><a href="{admin_link}" class="btn btn-xs btn-secondary">' + _("admin link") +
69
69
  f'</a><a href="{admin_link}" class="btn btn-xs btn-info ltr" target="_blank">{model.domain}</a></div>')
70
70
 
@@ -116,12 +116,12 @@ class ParentDomainAdmin(AdminLTEModelView):
116
116
  if len(model.show_domains) == Domain.query.count():
117
117
  model.show_domains = []
118
118
 
119
- hiddify.flash_config_success(restart_mode='apply', domain_changed=True)
119
+ hutils.flask.flash_config_success(restart_mode='apply', domain_changed=True)
120
120
 
121
121
  def on_model_delete(self, model):
122
122
  if len(ParentDomain.query.all()) <= 1:
123
123
  raise ValidationError(f"at least one domain should exist")
124
- hiddify.flash_config_success(restart_mode='apply', domain_changed=True)
124
+ hutils.flask.flash_config_success(restart_mode='apply', domain_changed=True)
125
125
 
126
126
  def is_accessible(self):
127
127
  if login_required(roles={Role.super_admin, Role.admin})(lambda: True)() != True: