hiddifypanel 9.0.0.dev92__py3-none-any.whl → 10.5.0.dev0__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.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +2 -2
- hiddifypanel/auth.py +30 -9
- hiddifypanel/base.py +58 -50
- hiddifypanel/cache.py +43 -25
- hiddifypanel/database.py +9 -0
- hiddifypanel/drivers/abstract_driver.py +2 -0
- hiddifypanel/drivers/singbox_api.py +17 -15
- hiddifypanel/drivers/ssh_liberty_bridge_api.py +3 -1
- hiddifypanel/drivers/user_driver.py +12 -6
- hiddifypanel/drivers/wireguard_api.py +7 -2
- hiddifypanel/drivers/xray_api.py +14 -9
- hiddifypanel/hutils/__init__.py +4 -0
- hiddifypanel/hutils/convert.py +13 -2
- hiddifypanel/hutils/crypto.py +48 -0
- hiddifypanel/hutils/encode.py +4 -1
- hiddifypanel/hutils/flask.py +38 -5
- hiddifypanel/hutils/github_issue.py +1 -1
- hiddifypanel/hutils/importer/xui.py +5 -2
- hiddifypanel/{models/utils.py → hutils/model.py} +14 -4
- hiddifypanel/hutils/network/auto_ip_selector.py +2 -0
- hiddifypanel/hutils/network/net.py +46 -2
- hiddifypanel/hutils/node/__init__.py +3 -0
- hiddifypanel/hutils/node/api_client.py +76 -0
- hiddifypanel/hutils/node/child.py +147 -0
- hiddifypanel/hutils/node/parent.py +100 -0
- hiddifypanel/hutils/node/shared.py +65 -0
- hiddifypanel/hutils/proxy/__init__.py +5 -0
- hiddifypanel/hutils/proxy/clash.py +161 -0
- hiddifypanel/hutils/proxy/shared.py +434 -0
- hiddifypanel/hutils/proxy/singbox.py +339 -0
- hiddifypanel/hutils/proxy/xray.py +235 -0
- hiddifypanel/hutils/proxy/xrayjson.py +391 -0
- hiddifypanel/hutils/random.py +4 -0
- hiddifypanel/hutils/utils.py +4 -1
- hiddifypanel/models/__init__.py +2 -2
- hiddifypanel/models/admin.py +31 -17
- hiddifypanel/models/base_account.py +7 -7
- hiddifypanel/models/child.py +30 -16
- hiddifypanel/models/config.py +45 -16
- hiddifypanel/models/config_enum.py +68 -17
- hiddifypanel/models/domain.py +28 -20
- hiddifypanel/models/parent_domain.py +2 -2
- hiddifypanel/models/proxy.py +29 -20
- hiddifypanel/models/report.py +2 -3
- hiddifypanel/models/usage.py +2 -2
- hiddifypanel/models/user.py +33 -22
- hiddifypanel/panel/admin/Actions.py +13 -19
- hiddifypanel/panel/admin/AdminstratorAdmin.py +14 -3
- hiddifypanel/panel/admin/Dashboard.py +5 -10
- hiddifypanel/panel/admin/DomainAdmin.py +35 -48
- hiddifypanel/panel/admin/NodeAdmin.py +6 -2
- hiddifypanel/panel/admin/ProxyAdmin.py +6 -5
- hiddifypanel/panel/admin/QuickSetup.py +21 -20
- hiddifypanel/panel/admin/SettingAdmin.py +107 -62
- hiddifypanel/panel/admin/UserAdmin.py +22 -21
- hiddifypanel/panel/admin/templates/index.html +1 -1
- hiddifypanel/panel/admin/templates/model/user_list.html +44 -20
- hiddifypanel/panel/admin/templates/parent_dash.html +2 -4
- hiddifypanel/panel/admin/templates/result.html +2 -3
- hiddifypanel/panel/cf_api.py +1 -2
- hiddifypanel/panel/cli.py +16 -16
- hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +16 -12
- hiddifypanel/panel/commercial/__init__.py +7 -5
- hiddifypanel/panel/commercial/restapi/v1/__init__.py +1 -1
- hiddifypanel/panel/commercial/restapi/v1/tgbot.py +1 -1
- hiddifypanel/panel/commercial/restapi/v1/tgmsg.py +14 -10
- hiddifypanel/panel/commercial/restapi/v2/admin/__init__.py +0 -5
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_info_api.py +2 -2
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_log_api.py +4 -5
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_user_api.py +8 -25
- hiddifypanel/panel/commercial/restapi/v2/admin/admin_users_api.py +4 -4
- hiddifypanel/panel/commercial/restapi/v2/admin/schema.py +157 -0
- hiddifypanel/panel/commercial/restapi/v2/admin/server_status_api.py +3 -3
- hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +9 -66
- hiddifypanel/panel/commercial/restapi/v2/admin/users_api.py +1 -1
- hiddifypanel/panel/commercial/restapi/v2/child/__init__.py +18 -0
- hiddifypanel/panel/commercial/restapi/v2/child/actions.py +63 -0
- hiddifypanel/panel/commercial/restapi/v2/child/register_parent_api.py +34 -0
- hiddifypanel/panel/commercial/restapi/v2/child/schema.py +7 -0
- hiddifypanel/panel/commercial/restapi/v2/child/sync_parent_api.py +21 -0
- hiddifypanel/panel/commercial/restapi/v2/panel/__init__.py +13 -0
- hiddifypanel/panel/commercial/restapi/v2/panel/info.py +18 -0
- hiddifypanel/panel/commercial/restapi/v2/panel/ping_pong.py +23 -0
- hiddifypanel/panel/commercial/restapi/v2/panel/schema.py +7 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/__init__.py +16 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/register_api.py +65 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/schema.py +115 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/status_api.py +26 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/sync_api.py +53 -0
- hiddifypanel/panel/commercial/restapi/v2/parent/usage_api.py +57 -0
- hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +17 -23
- hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +23 -26
- hiddifypanel/panel/commercial/telegrambot/admin.py +1 -2
- hiddifypanel/panel/common.py +25 -8
- hiddifypanel/panel/common_bp/login.py +2 -2
- hiddifypanel/panel/hiddify.py +22 -185
- hiddifypanel/panel/init_db.py +102 -55
- hiddifypanel/panel/usage.py +33 -18
- hiddifypanel/panel/user/__init__.py +0 -1
- hiddifypanel/panel/user/templates/all_configs copy.txt +2 -2
- hiddifypanel/panel/user/templates/all_configs.txt +2 -2
- hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +2 -1
- hiddifypanel/panel/user/templates/base_xray_config.json.j2 +125 -0
- hiddifypanel/panel/user/templates/clash_config copy.yml +1 -1
- hiddifypanel/panel/user/templates/clash_config.yml +4 -4
- hiddifypanel/panel/user/templates/clash_proxies.yml +1 -1
- hiddifypanel/panel/user/templates/home/all-configs.html +2 -2
- hiddifypanel/panel/user/templates/home/all-configs_old.html +1 -1
- hiddifypanel/panel/user/templates/home/ios copy.html +2 -2
- hiddifypanel/panel/user/templates/home/usage.html +1 -1
- hiddifypanel/panel/user/templates/new.html +2 -2
- hiddifypanel/panel/user/user.py +56 -50
- hiddifypanel/static/css/custom.css +31 -0
- hiddifypanel/static/images/favicon.ico +0 -0
- hiddifypanel/static/images/hiddify-old.png +0 -0
- hiddifypanel/static/images/hiddify.png +0 -0
- hiddifypanel/static/images/hiddify2.png +0 -0
- hiddifypanel/static/new/assets/{index-1b891a7c.js → index-ccb9873c.js} +56 -56
- hiddifypanel/static/new/assets/index-fa00de9a.css +1 -0
- hiddifypanel/static/new/i18n/en.json +6 -6
- hiddifypanel/static/new/i18n/fa.json +2 -2
- hiddifypanel/templates/admin-layout.html +30 -43
- hiddifypanel/templates/fake.html +0 -4
- hiddifypanel/templates/flaskadmin-layout.html +7 -3
- hiddifypanel/templates/master.html +11 -6
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +2082 -1977
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +2035 -1924
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +1911 -1848
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +2019 -1874
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +1873 -1742
- hiddifypanel/translations.i18n/en.json +992 -933
- hiddifypanel/translations.i18n/fa.json +994 -935
- hiddifypanel/translations.i18n/pt.json +1031 -972
- hiddifypanel/translations.i18n/ru.json +994 -935
- hiddifypanel/translations.i18n/zh.json +971 -912
- {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/METADATA +47 -47
- {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/RECORD +147 -120
- {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/WHEEL +1 -1
- hiddifypanel/panel/commercial/restapi/v2/DTO.py +0 -9
- hiddifypanel/panel/commercial/restapi/v2/hello/__init__.py +0 -16
- hiddifypanel/panel/commercial/restapi/v2/hello/hello.py +0 -32
- hiddifypanel/panel/user/link_maker.py +0 -1083
- hiddifypanel/static/new/assets/index-669b32c8.css +0 -1
- {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/LICENSE.md +0 -0
- {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-9.0.0.dev92.dist-info → hiddifypanel-10.5.0.dev0.dist-info}/top_level.txt +0 -0
@@ -39,22 +39,18 @@ class Actions(FlaskView):
|
|
39
39
|
|
40
40
|
@login_required(roles={Role.super_admin})
|
41
41
|
def reset2(self):
|
42
|
-
|
42
|
+
res = render_template("result.html",
|
43
|
+
out_type="info",
|
44
|
+
out_msg="",
|
45
|
+
log_file_url=get_log_api_url(),
|
46
|
+
log_file='restart.log',
|
47
|
+
show_success=True,
|
48
|
+
domains=get_domains())
|
43
49
|
|
44
50
|
# run restart.sh
|
45
51
|
commander(Command.restart_services)
|
46
52
|
|
47
|
-
|
48
|
-
# import time
|
49
|
-
# time.sleep(1)
|
50
|
-
|
51
|
-
return render_template("result.html",
|
52
|
-
out_type="info",
|
53
|
-
out_msg="",
|
54
|
-
log_file_url=get_log_api_url(),
|
55
|
-
log_file='restart.log',
|
56
|
-
show_success=True,
|
57
|
-
domains=get_domains())
|
53
|
+
return res
|
58
54
|
|
59
55
|
@login_required(roles={Role.super_admin})
|
60
56
|
@route('reinstall', methods=['POST'])
|
@@ -65,11 +61,9 @@ class Actions(FlaskView):
|
|
65
61
|
def reinstall2(self, complete_install=True, domain_changed=False):
|
66
62
|
if int(hconfig(ConfigEnum.db_version)) < 9:
|
67
63
|
return ("Please update your panel before this action.")
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
# except e as Exception:
|
72
|
-
# hutils.flask.flash(_('can not sync child with parent panel')+" "+e)
|
64
|
+
if hutils.node.is_child():
|
65
|
+
if not hutils.node.child.sync_with_parent():
|
66
|
+
hutils.flask.flash(_('child.sync-failed'), 'danger') # type: ignore
|
73
67
|
|
74
68
|
domain_changed = request.args.get("domain_changed", str(domain_changed)).lower() == "true"
|
75
69
|
complete_install = request.args.get("complete_install", str(complete_install)).lower() == "true"
|
@@ -114,7 +108,7 @@ class Actions(FlaskView):
|
|
114
108
|
|
115
109
|
@login_required(roles={Role.super_admin})
|
116
110
|
def change_reality_keys(self):
|
117
|
-
key =
|
111
|
+
key = hutils.crypto.generate_x25519_keys()
|
118
112
|
set_hconfig(ConfigEnum.reality_private_key, key['private_key'])
|
119
113
|
set_hconfig(ConfigEnum.reality_public_key, key['public_key'])
|
120
114
|
hutils.flask.flash_config_success(restart_mode=ApplyMode.restart, domain_changed=False)
|
@@ -170,7 +164,7 @@ class Actions(FlaskView):
|
|
170
164
|
|
171
165
|
tcp_ping = hutils.network.is_domain_reality_friendly(d)
|
172
166
|
if tcp_ping:
|
173
|
-
dip = hutils.network.get_domain_ip(d)
|
167
|
+
dip = str(hutils.network.get_domain_ip(d))
|
174
168
|
dip_country = (IPCOUNTRY.get(dip) or {}).get('country', {}).get('iso_code', 'unknown')
|
175
169
|
if dip_country == "IR":
|
176
170
|
continue
|
@@ -7,7 +7,9 @@ from .adminlte import AdminLTEModelView
|
|
7
7
|
from flask_babel import lazy_gettext as _
|
8
8
|
from wtforms.validators import Regexp
|
9
9
|
from flask_babel import gettext as __
|
10
|
-
from flask import
|
10
|
+
from flask import request # type: ignore
|
11
|
+
from markupsafe import Markup
|
12
|
+
|
11
13
|
from flask import g
|
12
14
|
import datetime
|
13
15
|
from wtforms import SelectField
|
@@ -37,7 +39,7 @@ class SubAdminsField(SelectField):
|
|
37
39
|
|
38
40
|
class AdminstratorAdmin(AdminLTEModelView):
|
39
41
|
column_hide_backrefs = False
|
40
|
-
column_list = ["name", 'UserLinks', 'mode', 'can_add_admin', 'max_active_users', 'max_users', 'online_users', 'comment']
|
42
|
+
column_list = ["name", 'UserLinks', 'mode', 'can_add_admin', 'max_active_users', 'max_users', 'online_users', 'comment',]
|
41
43
|
form_columns = ["name", 'mode', 'can_add_admin', 'max_active_users', 'max_users', 'comment', "uuid"]
|
42
44
|
list_template = 'model/admin_list.html'
|
43
45
|
# column_editable_list = ['name']
|
@@ -208,13 +210,14 @@ class AdminstratorAdmin(AdminLTEModelView):
|
|
208
210
|
|
209
211
|
if g.account.mode != AdminMode.super_admin and model.mode == AdminMode.super_admin:
|
210
212
|
raise ValidationError("Sub-Admin can not have more power!!!!")
|
211
|
-
if
|
213
|
+
if g.account.mode == AdminMode.agent and model.mode != AdminMode.agent:
|
212
214
|
raise ValidationError("Sub-Admin can not have more power!!!!")
|
213
215
|
|
214
216
|
def on_model_delete(self, model):
|
215
217
|
model.remove()
|
216
218
|
|
217
219
|
def get_query_for_parent_admin(self):
|
220
|
+
# WHAT IS THIS?
|
218
221
|
admin_user_id = self.get_pk_value()
|
219
222
|
sub_admins_ids = set(recursive_sub_admins_ids(AdminUser.query.get(admin_user_id)))
|
220
223
|
return AdminUser.query.filter(AdminUser.id.in_(sub_admins_ids)).with_entities(AdminUser.id, AdminUser.name)
|
@@ -236,3 +239,11 @@ class AdminstratorAdmin(AdminLTEModelView):
|
|
236
239
|
del form.max_users
|
237
240
|
del form.max_active_users
|
238
241
|
del form.can_add_admin
|
242
|
+
|
243
|
+
def after_model_change(self, form, model, is_created):
|
244
|
+
if hutils.node.is_parent():
|
245
|
+
hutils.node.parent.send_sync_req_to_childs()
|
246
|
+
|
247
|
+
def after_model_delete(self, model):
|
248
|
+
if hutils.node.is_parent():
|
249
|
+
hutils.node.parent.send_sync_req_to_childs()
|
@@ -18,9 +18,9 @@ class Dashboard(FlaskView):
|
|
18
18
|
|
19
19
|
@login_required(roles={Role.super_admin, Role.admin, Role.agent})
|
20
20
|
def index(self):
|
21
|
-
|
22
21
|
if hconfig(ConfigEnum.first_setup):
|
23
22
|
return redirect(hurl_for("admin.QuickSetup:index"))
|
23
|
+
|
24
24
|
if hiddifypanel.__release_date__ + datetime.timedelta(days=20) < datetime.datetime.now():
|
25
25
|
hutils.flask.flash(_('This version of hiddify panel is outdated. Please update it from admin area.'), "danger") # type: ignore
|
26
26
|
bot = None
|
@@ -34,20 +34,15 @@ class Dashboard(FlaskView):
|
|
34
34
|
user_query = User.query
|
35
35
|
if admin_id:
|
36
36
|
user_query = user_query.filter(User.added_by == admin_id)
|
37
|
-
if
|
37
|
+
if hutils.node.is_parent():
|
38
38
|
childs = Child.query.filter(Child.id != 0).all()
|
39
39
|
for c in childs:
|
40
40
|
c.is_active = False
|
41
41
|
for d in c.domains:
|
42
|
-
|
43
|
-
continue
|
44
|
-
remote = hiddify.get_account_panel_link(g.account, d.domain, child_id=c.id)
|
45
|
-
d.is_active = hutils.network.check_connection_to_remote(remote)
|
42
|
+
d.is_active = hutils.node.parent.is_child_domain_active(c, d)
|
46
43
|
if d.is_active:
|
47
44
|
c.is_active = True
|
48
45
|
|
49
|
-
# return render_template('parent_dash.html',childs=childs,bot=bot)
|
50
|
-
# try:
|
51
46
|
def_user = None if len(User.query.all()) > 1 else User.query.filter(User.name == 'default').first()
|
52
47
|
domains = get_panel_domains()
|
53
48
|
sslip_domains = [d.domain for d in domains if "sslip.io" in d.domain]
|
@@ -56,13 +51,13 @@ class Dashboard(FlaskView):
|
|
56
51
|
quick_setup = hurl_for("admin.QuickSetup:index")
|
57
52
|
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.',
|
58
53
|
quick_setup=quick_setup)), 'warning') # type: ignore
|
59
|
-
if
|
54
|
+
if hutils.node.is_parent():
|
60
55
|
hutils.flask.flash(
|
61
56
|
_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
|
62
57
|
elif len(sslip_domains):
|
63
58
|
hutils.flask.flash((_('It seems that you are using default domain (%(domain)s) which is not recommended.',
|
64
59
|
domain=sslip_domains[0])), 'warning') # type: ignore
|
65
|
-
if
|
60
|
+
if hutils.node.is_parent():
|
66
61
|
hutils.flask.flash(
|
67
62
|
_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
|
68
63
|
elif def_user:
|
@@ -3,7 +3,9 @@ from hiddifypanel.auth import login_required, current_account
|
|
3
3
|
|
4
4
|
from hiddifypanel.models import *
|
5
5
|
import re
|
6
|
-
from flask import
|
6
|
+
from flask import g # type: ignore
|
7
|
+
from markupsafe import Markup
|
8
|
+
|
7
9
|
from flask_babel import gettext as __
|
8
10
|
from flask_babel import lazy_gettext as _
|
9
11
|
from hiddifypanel.panel.run_commander import Command, commander
|
@@ -169,26 +171,25 @@ class DomainAdmin(AdminLTEModelView):
|
|
169
171
|
if hconfig(ConfigEnum.cloudflare) and model.mode != DomainType.fake:
|
170
172
|
try:
|
171
173
|
proxied = model.mode in [DomainType.cdn, DomainType.auto_cdn_ip]
|
172
|
-
cf_api.add_or_update_domain(model.domain, ipv4_list[0], "A", proxied=proxied)
|
174
|
+
cf_api.add_or_update_domain(model.domain, str(ipv4_list[0]), "A", proxied=proxied)
|
173
175
|
if ipv6_list:
|
174
|
-
cf_api.add_or_update_domain(model.domain, ipv6_list[0], "AAAA", proxied=proxied)
|
176
|
+
cf_api.add_or_update_domain(model.domain, str(ipv6_list[0]), "AAAA", proxied=proxied)
|
175
177
|
|
176
178
|
skip_check = True
|
177
179
|
except Exception as e:
|
178
|
-
# raise e
|
179
180
|
raise ValidationError(__("Can not connect to Cloudflare.") + f' {e}')
|
180
181
|
# elif model.mode==DomainType.auto_cdn_ip:
|
181
|
-
if model.alias and not model.alias.replace("_", "").isalnum():
|
182
|
-
|
183
|
-
|
182
|
+
# if model.alias and not model.alias.replace("_", "").isalnum():
|
183
|
+
# hutils.flask.flash(__("Using alias with special charachters may cause problem in some clients like FairVPN."), 'warning')
|
184
|
+
# raise ValidationError(_("You have to add your cloudflare api key to use this feature: "))
|
184
185
|
|
185
186
|
dip = hutils.network.get_domain_ip(model.domain)
|
186
187
|
if model.sub_link_only:
|
187
188
|
if dip is None:
|
188
|
-
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain"))
|
189
|
+
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain")) # type: ignore
|
189
190
|
elif not skip_check:
|
190
191
|
if dip is None:
|
191
|
-
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain"))
|
192
|
+
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain")) # type: ignore
|
192
193
|
|
193
194
|
domain_ip_is_same_as_panel = False
|
194
195
|
domain_ip_is_same_as_panel |= dip in ipv4_list
|
@@ -196,65 +197,52 @@ class DomainAdmin(AdminLTEModelView):
|
|
196
197
|
domain_ip_is_same_as_panel |= ipaddress.ip_address(dip) == ipaddress.ip_address(ipv6)
|
197
198
|
|
198
199
|
if model.mode == DomainType.direct and not domain_ip_is_same_as_panel:
|
199
|
-
hutils.flask.flash(
|
200
|
-
|
201
|
-
|
202
|
-
# 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))
|
200
|
+
# hutils.flask.flash(__(f"Domain IP={dip} is not matched with your ip={', '.join(list(map(str, ipv4_list)))} which is required in direct mode"),category='error')
|
201
|
+
raise ValidationError(
|
202
|
+
__("Domain IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode", server_ip=', '.join(list(map(str, ipv4_list))), domain_ip=dip)) # type: ignore
|
203
203
|
|
204
204
|
if domain_ip_is_same_as_panel and model.mode in [DomainType.cdn, DomainType.relay, DomainType.fake, DomainType.auto_cdn_ip]:
|
205
|
-
hutils.flask.flash(__(f"In CDN mode, Domain IP={dip} should be different to your ip={', '.join(list(map(str, ipv4_list)))}"), 'warning')
|
206
|
-
|
205
|
+
# # hutils.flask.flash(__(f"In CDN mode, Domain IP={dip} should be different to your ip={', '.join(list(map(str, ipv4_list)))}"), 'warning')
|
206
|
+
raise ValidationError(__("In CDN mode, Domain IP=%(domain_ip)s should be different to your ip=%(server_ip)s",
|
207
|
+
server_ip=', '.join(list(map(str, ipv4_list))), domain_ip=dip)) # type: ignore
|
207
208
|
|
208
209
|
# if model.mode in [DomainType.ss_faketls, DomainType.telegram_faketls]:
|
209
210
|
# if len(Domain.query.filter(Domain.mode==model.mode and Domain.id!=model.id).all())>0:
|
210
211
|
# ValidationError(f"another {model.mode} is exist")
|
212
|
+
|
211
213
|
model.domain = model.domain.lower()
|
212
214
|
if model.mode == DomainType.direct and model.cdn_ip:
|
213
215
|
raise ValidationError(f"Specifying CDN IP is only valid for CDN mode")
|
214
216
|
|
215
217
|
if model.mode == DomainType.fake and not model.cdn_ip:
|
216
|
-
model.cdn_ip = ipv4_list[0]
|
218
|
+
model.cdn_ip = str(ipv4_list[0])
|
217
219
|
|
218
220
|
# if model.mode==DomainType.fake and model.cdn_ip!=myip:
|
219
221
|
# raise ValidationError(f"Specifying CDN IP is only valid for CDN mode")
|
220
222
|
|
221
|
-
# work_with_ids = form.work_with.data
|
222
|
-
# print(work_with_ids)
|
223
223
|
# # Update the many-to-many relationship
|
224
224
|
if len(model.show_domains) == Domain.query.count():
|
225
225
|
model.show_domains = []
|
226
|
-
# if model.alias and not g.is_commercial:
|
227
|
-
# model.alias= "@hiddify "+model.alias
|
228
|
-
# model.work_with = self.session.query(Domain).filter(
|
229
|
-
# Domain.id.in_(work_with_ids)).all()
|
230
226
|
|
231
227
|
if model.mode == DomainType.reality:
|
232
|
-
model.servernames = (model.domain).lower()
|
233
|
-
if not hutils.network.is_domain_reality_friendly(model.domain):
|
234
|
-
# hutils.flask.flash(_("Domain is not REALITY friendly!")+" "+d,'error')
|
235
|
-
# return render_template('config.html', form=form)
|
236
|
-
raise ValidationError(_("Domain is not REALITY friendly!") + " " + model.domain)
|
237
|
-
|
238
|
-
hiddify.debug_flash_if_not_in_the_same_asn(model.domain)
|
239
|
-
if False:
|
240
228
|
model.servernames = (model.servernames or model.domain).lower()
|
241
|
-
|
242
|
-
for v in [model.domain, model.servernames]:
|
243
|
-
|
229
|
+
for v in set([model.domain, model.servernames]):
|
244
230
|
for d in v.split(","):
|
245
231
|
if not d:
|
246
232
|
continue
|
247
|
-
|
248
233
|
if not hutils.network.is_domain_reality_friendly(d):
|
249
|
-
|
250
|
-
# return render_template('config.html', form=form)
|
251
|
-
raise ValidationError(_("Domain is not REALITY friendly!") + " " + d)
|
234
|
+
raise ValidationError(_("Domain is not REALITY friendly!") + f' {d}')
|
252
235
|
|
253
|
-
|
236
|
+
if not hutils.network.is_in_same_asn(d, ipv4_list[0]):
|
237
|
+
server_asn = hutils.network.get_ip_asn_name(ipv4_list[0])
|
238
|
+
domain_asn = hutils.network.get_ip_asn_name(dip) # type: ignore
|
239
|
+
msg = _("selected domain for REALITY is not in the same ASN. To better use of the protocol, it is better to find a domain in the same ASN.") + \
|
240
|
+
(f"<br> Server ASN={server_asn}<br>{d}_ASN={domain_asn}" if server_asn or domain_asn else "")
|
241
|
+
hutils.flask.flash(msg, 'warning')
|
254
242
|
|
255
243
|
for d in model.servernames.split(","):
|
256
|
-
if not
|
257
|
-
raise ValidationError(_("REALITY Fallback domain is not compaitble with server names!") +
|
244
|
+
if not hutils.network.fallback_domain_compatible_with_servernames(model.domain, d):
|
245
|
+
raise ValidationError(_("REALITY Fallback domain is not compaitble with server names!") + f' {d} != {model.domain}')
|
258
246
|
|
259
247
|
if (model.cdn_ip):
|
260
248
|
try:
|
@@ -280,19 +268,18 @@ class DomainAdmin(AdminLTEModelView):
|
|
280
268
|
hutils.flask.flash_config_success(restart_mode=ApplyMode.apply, domain_changed=True)
|
281
269
|
|
282
270
|
def after_model_delete(self, model):
|
283
|
-
|
284
|
-
|
285
|
-
|
271
|
+
if hutils.node.is_child():
|
272
|
+
if not hutils.node.child.sync_with_parent():
|
273
|
+
hutils.flask.flash(_('child.sync-failed'), 'danger') # type: ignore
|
286
274
|
|
287
275
|
def after_model_change(self, form, model, is_created):
|
288
276
|
if hconfig(ConfigEnum.first_setup):
|
289
277
|
set_hconfig(ConfigEnum.first_setup, False)
|
290
|
-
# if hconfig(ConfigEnum.parent_panel):
|
291
|
-
# hiddify_api.sync_child_to_parent()
|
292
278
|
if model.need_valid_ssl:
|
293
|
-
# hiddify.exec_command(f"sudo /opt/hiddify-manager/acme.sh/get_cert.sh {model.domain}")
|
294
|
-
# run get_cert.sh
|
295
279
|
commander(Command.get_cert, domain=model.domain)
|
280
|
+
if hutils.node.is_child():
|
281
|
+
if not hutils.node.child.sync_with_parent():
|
282
|
+
hutils.flask.flash(_('child.sync-failed'), 'danger') # type: ignore
|
296
283
|
|
297
284
|
def is_accessible(self):
|
298
285
|
if login_required(roles={Role.super_admin, Role.admin})(lambda: True)() != True:
|
@@ -310,4 +297,4 @@ class DomainAdmin(AdminLTEModelView):
|
|
310
297
|
|
311
298
|
def get_query(self):
|
312
299
|
query = super().get_query()
|
313
|
-
return query.filter(Domain.child_id == Child.current.id)
|
300
|
+
return query.filter(Domain.child_id == Child.current().id)
|
@@ -4,7 +4,9 @@ from wtforms.validators import Regexp, ValidationError
|
|
4
4
|
from flask_babel import lazy_gettext as _
|
5
5
|
from .adminlte import AdminLTEModelView
|
6
6
|
from flask_babel import gettext as __
|
7
|
-
from flask import
|
7
|
+
from flask import g, request
|
8
|
+
from markupsafe import Markup
|
9
|
+
|
8
10
|
|
9
11
|
from hiddifypanel.auth import login_required
|
10
12
|
from hiddifypanel.panel import hiddify
|
@@ -40,7 +42,7 @@ class NodeAdmin(AdminLTEModelView):
|
|
40
42
|
def is_accessible(self):
|
41
43
|
if login_required(roles={Role.super_admin})(lambda: True)() != True:
|
42
44
|
return False
|
43
|
-
if Child.current.id != 0:
|
45
|
+
if Child.current().id != 0:
|
44
46
|
return False
|
45
47
|
return True
|
46
48
|
|
@@ -49,7 +51,9 @@ class NodeAdmin(AdminLTEModelView):
|
|
49
51
|
raise ValidationError(_("Remote nodes are not supported yet!"))
|
50
52
|
|
51
53
|
def after_model_change(self, form, model, is_created):
|
54
|
+
# deprecated
|
52
55
|
set_hconfig(ConfigEnum.is_parent, True)
|
56
|
+
set_hconfig(ConfigEnum.panel_mode, PanelMode.parent)
|
53
57
|
if is_created and model.mode == ChildMode.virtual:
|
54
58
|
# for k, v in get_hconfigs().items():
|
55
59
|
# set_hconfig(k, v, model.id)
|
@@ -35,7 +35,7 @@ class ProxyAdmin(FlaskView):
|
|
35
35
|
|
36
36
|
db.session.commit()
|
37
37
|
# print(cat,vs)
|
38
|
-
|
38
|
+
hutils.proxy.get_proxies.invalidate_all()
|
39
39
|
hiddify.check_need_reset(old_configs)
|
40
40
|
all_proxy_form = get_all_proxy_form(True)
|
41
41
|
|
@@ -55,10 +55,11 @@ class ProxyAdmin(FlaskView):
|
|
55
55
|
|
56
56
|
# print(cat,vs)
|
57
57
|
db.session.commit()
|
58
|
-
|
58
|
+
hutils.proxy.get_proxies.invalidate_all()
|
59
|
+
if hutils.node.is_child():
|
60
|
+
if not hutils.node.child.sync_with_parent():
|
61
|
+
hutils.flask.flash(_('child.sync-failed'), 'danger') # type: ignore
|
59
62
|
hutils.flask.flash_config_success(restart_mode=ApplyMode.apply, domain_changed=False)
|
60
|
-
# if hconfig(ConfigEnum.parent_panel):
|
61
|
-
# hiddify_api.sync_child_to_parent()
|
62
63
|
global_config_form = get_global_config_form(True)
|
63
64
|
else:
|
64
65
|
hutils.flask.flash((_('config.validation-error')), 'danger')
|
@@ -94,7 +95,7 @@ def get_global_config_form(empty=False):
|
|
94
95
|
|
95
96
|
|
96
97
|
def get_all_proxy_form(empty=False):
|
97
|
-
proxies =
|
98
|
+
proxies = hutils.proxy.get_proxies(Child.current().id)
|
98
99
|
categories1 = sorted([c for c in {c.cdn: 1 for c in proxies}])
|
99
100
|
|
100
101
|
class DynamicForm(FlaskForm):
|
@@ -8,7 +8,6 @@ import wtforms as wtf
|
|
8
8
|
from flask_wtf import FlaskForm
|
9
9
|
from flask_bootstrap import SwitchField
|
10
10
|
from hiddifypanel.panel import hiddify
|
11
|
-
from wtforms.fields import *
|
12
11
|
from flask_classful import FlaskView
|
13
12
|
from wtforms.validators import ValidationError
|
14
13
|
# from gettext import gettext as _
|
@@ -61,7 +60,7 @@ class QuickSetup(FlaskView):
|
|
61
60
|
Domain.query.filter(Domain.domain == f'{hutils.network.get_ip_str(4)}.sslip.io').delete()
|
62
61
|
db.session.add(Domain(domain=quick_form.domain.data.lower(), mode=DomainType.direct))
|
63
62
|
set_hconfig(ConfigEnum.block_iran_sites, quick_form.block_iran_sites.data)
|
64
|
-
set_hconfig(ConfigEnum.decoy_domain,quick_form.decoy_domain.data)
|
63
|
+
set_hconfig(ConfigEnum.decoy_domain, quick_form.decoy_domain.data)
|
65
64
|
# hiddify.bulk_register_configs([
|
66
65
|
# # {"key": ConfigEnum.telegram_enable, "value": quick_form.enable_telegram.data == True},
|
67
66
|
# # {"key": ConfigEnum.vmess_enable, "value": quick_form.enable_vmess.data == True},
|
@@ -84,12 +83,16 @@ class QuickSetup(FlaskView):
|
|
84
83
|
|
85
84
|
def get_lang_form(empty=False):
|
86
85
|
class LangForm(FlaskForm):
|
87
|
-
admin_lang = wtf.
|
88
|
-
"lang.
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
86
|
+
admin_lang = wtf.SelectField(
|
87
|
+
_("config.admin_lang.label"), choices=[("en", _("lang.en")), ("fa", _("lang.fa")), ("pt", _("lang.pt")), ("zh", _("lang.zh")), ("ru", _("lang.ru"))],
|
88
|
+
description=_("config.admin_lang.description"),
|
89
|
+
default=hconfig(ConfigEnum.admin_lang))
|
90
|
+
# lang=wtf.SelectField(_("config.lang.label"),choices=[("en",_("lang.en")),("fa",_("lang.fa"))],description=_("config.lang.description"),default=hconfig(ConfigEnum.lang))
|
91
|
+
country = wtf.SelectField(
|
92
|
+
_("config.country.label"), choices=[("ir", _("Iran")), ("zh", _("China")), ("other", "Others")],
|
93
|
+
description=_("config.country.description"),
|
94
|
+
default=hconfig(ConfigEnum.country))
|
95
|
+
lang_submit = wtf.SubmitField(_('Submit'))
|
93
96
|
|
94
97
|
return LangForm(None)if empty else LangForm()
|
95
98
|
|
@@ -108,13 +111,12 @@ def get_quick_setup_form(empty=False):
|
|
108
111
|
class QuickSetupForm(FlaskForm):
|
109
112
|
domain_regex = "^([A-Za-z0-9\\-\\.]+\\.[a-zA-Z]{2,})$"
|
110
113
|
|
111
|
-
domain_validators = [
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
domain = wtf.fields.StringField(
|
114
|
+
domain_validators = [
|
115
|
+
wtf.validators.Regexp(domain_regex, re.IGNORECASE, _("config.Invalid domain")),
|
116
|
+
validate_domain,
|
117
|
+
wtf.validators.NoneOf([d.domain.lower() for d in Domain.query.all()], _("config.Domain already used")),
|
118
|
+
wtf.validators.NoneOf([c.value.lower() for c in StrConfig.query.all() if "fakedomain" in c.key and c.key != ConfigEnum.decoy_domain], _("config.Domain already used"))]
|
119
|
+
domain = wtf.StringField(
|
118
120
|
_("domain.domain"),
|
119
121
|
domain_validators,
|
120
122
|
description=_("domain.description"),
|
@@ -129,9 +131,9 @@ def get_quick_setup_form(empty=False):
|
|
129
131
|
block_iran_sites = SwitchField(_("config.block_iran_sites.label"), description=_(
|
130
132
|
"config.block_iran_sites.description"), default=hconfig(ConfigEnum.block_iran_sites))
|
131
133
|
# enable_vmess = SwitchField(_("config.vmess_enable.label"), description=_("config.vmess_enable.description"), default=hconfig(ConfigEnum.vmess_enable))
|
132
|
-
decoy_domain = wtf.
|
133
|
-
ConfigEnum.decoy_domain), validators=[wtf.validators.Regexp(domain_regex, re.IGNORECASE, _("config.Invalid domain")),
|
134
|
-
submit = wtf.
|
134
|
+
decoy_domain = wtf.StringField(_("config.decoy_domain.label"), description=_("config.decoy_domain.description"), default=hconfig(
|
135
|
+
ConfigEnum.decoy_domain), validators=[wtf.validators.Regexp(domain_regex, re.IGNORECASE, _("config.Invalid domain")), hutils.flask.validate_domain_exist])
|
136
|
+
submit = wtf.SubmitField(_('Submit'))
|
135
137
|
|
136
138
|
return QuickSetupForm(None) if empty else QuickSetupForm()
|
137
139
|
|
@@ -144,8 +146,7 @@ def validate_domain(form, field):
|
|
144
146
|
|
145
147
|
myip = hutils.network.get_ip(4)
|
146
148
|
if dip and myip != dip:
|
147
|
-
raise ValidationError(_("Domain (%(domain)s)-> IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode",
|
148
|
-
server_ip=myip, domain_ip=dip, domain=domain))
|
149
|
+
raise ValidationError(_("Domain (%(domain)s)-> 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, domain=domain))
|
149
150
|
|
150
151
|
|
151
152
|
def admin_link():
|