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
@@ -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
 
@@ -213,7 +213,8 @@ def get_config_form():
213
213
  "config.telegram_lib.description"), default=hconfig(ConfigEnum.telegram_lib))
214
214
  elif c.key == ConfigEnum.mux_protocol:
215
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"))
216
+ field = wtf.fields.SelectField(_(f"config.{c.key}.label"), choices=choices, description=_(f"config.{c.key}.description"), default=hconfig(c.key))
217
+
217
218
  elif c.key == ConfigEnum.warp_sites:
218
219
  validators = [wtf.validators.Length(max=2048)]
219
220
  render_kw = {'class': "ltr", 'maxlength': 2048}
@@ -274,7 +275,8 @@ def get_config_form():
274
275
  if c.key in [ConfigEnum.tls_fragment_size, ConfigEnum.tls_fragment_sleep, ConfigEnum.tls_padding_length]:
275
276
  validators.append(wtf.validators.Regexp("^\d+-\d+$", re.IGNORECASE, _("config.Invalid! The pattern is number-number")+f' {c.key}'))
276
277
  # mux and hysteria validations
277
- if c.key in [ConfigEnum.hysteria_up_mbps, ConfigEnum.hysteria_down_mbps, ConfigEnum.mux_max_connections, ConfigEnum.mux_min_streams, ConfigEnum.mux_max_streams, ConfigEnum.mux_brutal_down_mbps, ConfigEnum.mux_brutal_up_mbps]:
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]:
278
280
  validators.append(wtf.validators.Regexp("^\d+$", re.IGNORECASE, _("config.Invalid! it should be a number only")+f' {c.key}'))
279
281
  for val in validators:
280
282
  if hasattr(val, "regex"):
@@ -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
 
@@ -121,7 +122,7 @@ class UserAdmin(AdminLTEModelView):
121
122
  # print("model.telegram_id",model.telegram_id)
122
123
  extra = ""
123
124
  if hconfig(ConfigEnum.telegram_bot_token):
124
- if model.telegram_id and model.telegram_id != '0':
125
+ if model.telegram_id:
125
126
  extra = f'<button class="btn hbtn bg-h-blue btn-xs " onclick="show_send_message({model.id})" ><i class="fa-solid fa-paper-plane"></i></button> '
126
127
  else:
127
128
  extra = f'<button class="btn hbtn bg-h-grey btn-xs disabled"><i class="fa-solid fa-paper-plane"></i></button> '
@@ -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,7 +247,7 @@ 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
  if form.reset_usage.data:
@@ -276,7 +277,7 @@ class UserAdmin(AdminLTEModelView):
276
277
  # xray_api.add_client(model.uuid)
277
278
  # else:
278
279
  # xray_api.remove_client(model.uuid)
279
- # hiddify.flash_config_success()
280
+ # hutils.flask.flash_config_success()
280
281
 
281
282
  def after_model_change(self, form, model, is_created):
282
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,18 +172,18 @@ 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)
@@ -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:
@@ -13,6 +13,7 @@ import hiddifypanel.panel.auth as auth
13
13
 
14
14
  class ProxyDetailsAdmin(AdminLTEModelView):
15
15
  column_hide_backrefs = True
16
+ can_create = False
16
17
  form_excluded_columns = ['child']
17
18
  column_exclude_list = ['child']
18
19
  # list_template = 'model/domain_list.html'
@@ -46,7 +46,7 @@ class SendMsgResource(Resource):
46
46
  query = User.query.filter(User.added_by.in_(g.account.recursive_sub_admins_ids()))
47
47
  query = query.filter(User.telegram_id != None, User.telegram_id != 0)
48
48
 
49
- if hutils.utils.is_int(identifier):
49
+ if hutils.convert.is_int(identifier):
50
50
  return [query.filter(User.id == int(identifier)).first() or abort(404, 'The user not found')] # type: ignore
51
51
  elif identifier == 'all':
52
52
  return query.all()
@@ -11,7 +11,8 @@ import user_agents
11
11
  from strenum import StrEnum
12
12
  from enum import auto
13
13
  from hiddifypanel.panel.user.user import get_common_data
14
- from hiddifypanel.hutils.utils import get_latest_release_url, do_base_64
14
+ from hiddifypanel.hutils.utils import get_latest_release_url
15
+ from hiddifypanel import hutils
15
16
  from hiddifypanel.models.role import Role
16
17
  from hiddifypanel.panel.auth import login_required
17
18
 
@@ -76,7 +77,7 @@ class AppAPI(MethodView):
76
77
  self.user_panel_encoded_url = quote_plus(self.user_panel_url)
77
78
  c = get_common_data(g.account.uuid, 'new')
78
79
  self.subscription_link_url = f"{self.user_panel_url}all.txt?name={c['db_domain'].alias or c['db_domain'].domain}-{c['asn']}&asn={c['asn']}&mode={c['mode']}"
79
- self.subscription_link_encoded_url = do_base_64(self.subscription_link_url)
80
+ self.subscription_link_encoded_url = hutils.encode.do_base_64(self.subscription_link_url)
80
81
  domain = c['db_domain'].alias or c['db_domain'].domain
81
82
  self.profile_title = c['profile_title']
82
83
  # self.clash_all_sites = f"https://{domain}/{g.proxy_path}/clash/all.yml?mode={c['mode']}&asn={c['asn']}&name={c['asn']}_all_{domain}-{c['mode']}"
@@ -277,7 +278,7 @@ class AppAPI(MethodView):
277
278
  dto.description = _('app.foxray.description')
278
279
  dto.icon_url = self.__get_app_icon_url(_('app.foxray.title'))
279
280
  dto.guide_url = ''
280
- dto.deeplink = f'https://yiguo.dev/sub/add/?url={do_base_64(self.subscription_link_encoded_url)}#{self.profile_title}'
281
+ dto.deeplink = f'https://yiguo.dev/sub/add/?url={hutils.encode.do_base_64(self.subscription_link_encoded_url)}#{self.profile_title}'
281
282
 
282
283
  ins_url = 'https://apps.apple.com/us/app/foxray/id6448898396'
283
284
  dto.install = [self.__get_app_install_dto(AppInstallType.app_store, ins_url),]
@@ -289,7 +290,7 @@ class AppAPI(MethodView):
289
290
  dto.description = _('app.shadowrocket.description')
290
291
  dto.icon_url = self.__get_app_icon_url(_('app.shadowrocket.title'))
291
292
  dto.guide_url = 'https://www.youtube.com/watch?v=F2bC_mtbYmQ'
292
- dto.deeplink = f'sub://{do_base_64(self.user_panel_url)}'
293
+ dto.deeplink = f'sub://{hutils.encode.do_base_64(self.user_panel_url)}'
293
294
 
294
295
  ins_url = 'https://apps.apple.com/us/app/shadowrocket/id932747118'
295
296
  dto.install = [self.__get_app_install_dto(AppInstallType.app_store, ins_url),]