hiddifypanel 10.30.8.dev1__py3-none-any.whl → 10.30.9.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +2 -2
- hiddifypanel/cache.py +13 -3
- hiddifypanel/hutils/network/net.py +41 -10
- hiddifypanel/hutils/proxy/shared.py +1 -1
- hiddifypanel/hutils/proxy/xrayjson.py +6 -6
- hiddifypanel/models/config_enum.py +2 -2
- hiddifypanel/models/domain.py +1 -1
- hiddifypanel/models/user.py +3 -2
- hiddifypanel/panel/admin/Actions.py +2 -2
- hiddifypanel/panel/admin/AdminstratorAdmin.py +1 -1
- hiddifypanel/panel/admin/Dashboard.py +3 -4
- hiddifypanel/panel/admin/DomainAdmin.py +48 -35
- hiddifypanel/panel/admin/ProxyAdmin.py +1 -1
- hiddifypanel/panel/admin/QuickSetup.py +144 -52
- hiddifypanel/panel/admin/SettingAdmin.py +23 -18
- hiddifypanel/panel/admin/UserAdmin.py +7 -4
- hiddifypanel/panel/admin/templates/model/domain_list.html +13 -12
- hiddifypanel/panel/admin/templates/model/user_list.html +8 -5
- hiddifypanel/panel/admin/templates/quick_setup.html +20 -14
- hiddifypanel/panel/admin/templates/result.html +3 -2
- hiddifypanel/panel/commercial/ParentDomainAdmin.py +1 -1
- hiddifypanel/panel/commercial/restapi/v2/admin/schema.py +3 -0
- hiddifypanel/panel/commercial/telegrambot/Usage.py +1 -4
- hiddifypanel/panel/commercial/telegrambot/admin.py +3 -3
- hiddifypanel/panel/commercial/telegrambot/information.py +1 -3
- hiddifypanel/panel/common_bp/login.py +2 -2
- hiddifypanel/panel/init_db.py +6 -6
- hiddifypanel/panel/user/templates/home/home.html +30 -14
- hiddifypanel/panel/user/templates/home/index_old.html +2 -2
- hiddifypanel/panel/user/templates/home/multi.html +2 -2
- hiddifypanel/panel/user/templates/redirect_to_new_format.html +1 -1
- hiddifypanel/templates/500.html +1 -1
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/en/LC_MESSAGES/messages.po +128 -133
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.po +130 -136
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.po +115 -129
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.po +120 -134
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.po +104 -116
- hiddifypanel/translations.i18n/en.json +52 -73
- hiddifypanel/translations.i18n/fa.json +133 -75
- hiddifypanel/translations.i18n/pt.json +337 -70
- hiddifypanel/translations.i18n/ru.json +190 -75
- hiddifypanel/translations.i18n/zh.json +318 -70
- {hiddifypanel-10.30.8.dev1.dist-info → hiddifypanel-10.30.9.dev1.dist-info}/METADATA +1 -1
- {hiddifypanel-10.30.8.dev1.dist-info → hiddifypanel-10.30.9.dev1.dist-info}/RECORD +54 -54
- {hiddifypanel-10.30.8.dev1.dist-info → hiddifypanel-10.30.9.dev1.dist-info}/LICENSE.md +0 -0
- {hiddifypanel-10.30.8.dev1.dist-info → hiddifypanel-10.30.9.dev1.dist-info}/WHEEL +0 -0
- {hiddifypanel-10.30.8.dev1.dist-info → hiddifypanel-10.30.9.dev1.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-10.30.8.dev1.dist-info → hiddifypanel-10.30.9.dev1.dist-info}/top_level.txt +0 -0
hiddifypanel/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
10.30.
|
1
|
+
10.30.9.dev1
|
hiddifypanel/VERSION.py
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
__version__='10.30.
|
1
|
+
__version__='10.30.9.dev1'
|
2
2
|
from datetime import datetime
|
3
|
-
__release_date__= datetime.strptime('2024-07-
|
3
|
+
__release_date__= datetime.strptime('2024-07-13','%Y-%m-%d')
|
hiddifypanel/cache.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from redis_cache import RedisCache, chunks
|
1
|
+
from redis_cache import RedisCache, chunks, compact_dump
|
2
2
|
import redis
|
3
3
|
from pickle import dumps, loads
|
4
4
|
from loguru import logger
|
@@ -7,11 +7,21 @@ redis_client = redis.from_url('unix:///opt/hiddify-manager/other/redis/run.sock?
|
|
7
7
|
|
8
8
|
|
9
9
|
class CustomRedisCache(RedisCache):
|
10
|
+
def __init__(self, redis_client, prefix="rc", serializer=compact_dump, deserializer=loads, key_serializer=None, support_cluster=True, exception_handler=None):
|
11
|
+
super().__init__(redis_client, prefix, serializer, deserializer, key_serializer, support_cluster, exception_handler)
|
12
|
+
self.cached_functions = set()
|
13
|
+
|
14
|
+
def cache(self, ttl=0, limit=0, namespace=None, exception_handler=None):
|
15
|
+
res = super().cache(ttl, limit, namespace, exception_handler)
|
16
|
+
self.cached_functions.add(res)
|
17
|
+
return res
|
10
18
|
|
11
19
|
def invalidate_all_cached_functions(self):
|
12
20
|
try:
|
21
|
+
for f in self.cached_functions:
|
22
|
+
f.invalidate_all()
|
13
23
|
logger.trace("Invalidating all cached functions")
|
14
|
-
chunks_gen = chunks(f'{self.prefix}*',
|
24
|
+
chunks_gen = chunks(f'{self.prefix}*', 5000)
|
15
25
|
for keys in chunks_gen:
|
16
26
|
self.client.delete(*keys)
|
17
27
|
logger.trace("Successfully invalidated all cached functions")
|
@@ -22,4 +32,4 @@ class CustomRedisCache(RedisCache):
|
|
22
32
|
return False
|
23
33
|
|
24
34
|
|
25
|
-
cache = CustomRedisCache(redis_client=redis_client, prefix="h", serializer=dumps, deserializer=loads)
|
35
|
+
cache = CustomRedisCache(redis_client=redis_client, prefix="h", serializer=dumps, deserializer=loads)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import List, Literal, Union
|
1
|
+
from typing import List, Literal, Set, Union
|
2
2
|
from urllib.parse import urlparse
|
3
3
|
import urllib.request
|
4
4
|
import ipaddress
|
@@ -33,17 +33,43 @@ def get_domain_ip(domain: str, retry: int = 3, version: Literal[4, 6] | None = N
|
|
33
33
|
|
34
34
|
if not res and version != 4:
|
35
35
|
try:
|
36
|
-
res = f"
|
37
|
-
|
38
|
-
res = res[1:-1]
|
36
|
+
res = f"{socket.getaddrinfo(domain, None, socket.AF_INET6)[0][4][0]}"
|
39
37
|
|
40
38
|
except BaseException:
|
41
39
|
pass
|
42
40
|
|
43
|
-
if retry <= 0
|
41
|
+
if retry <= 0:
|
44
42
|
return None
|
43
|
+
if not res:
|
44
|
+
return get_domain_ip(domain, retry=retry - 1, version=version)
|
45
|
+
|
46
|
+
return ipaddress.ip_address(res)
|
47
|
+
|
48
|
+
|
49
|
+
def get_domain_ips(domain: str, retry: int = 3) -> Set[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
|
50
|
+
res = set()
|
51
|
+
if retry < 0:
|
52
|
+
return res
|
53
|
+
try:
|
54
|
+
_, _, ips = socket.gethostbyname_ex(domain)
|
55
|
+
for ip in ips:
|
56
|
+
res.add(ipaddress.ip_address(ip))
|
57
|
+
except Exception:
|
58
|
+
pass
|
59
|
+
|
60
|
+
try:
|
61
|
+
for ip in socket.getaddrinfo(domain, None, socket.AF_INET):
|
62
|
+
res.add(ipaddress.ip_address(ip[4][0]))
|
63
|
+
except BaseException:
|
64
|
+
pass
|
65
|
+
|
66
|
+
try:
|
67
|
+
for ip in socket.getaddrinfo(domain, None, socket.AF_INET6):
|
68
|
+
res.add(ipaddress.ip_address(ip[4][0]))
|
69
|
+
except BaseException:
|
70
|
+
pass
|
45
71
|
|
46
|
-
return
|
72
|
+
return res or get_domain_ips(domain, retry=retry - 1)
|
47
73
|
|
48
74
|
|
49
75
|
def get_socket_public_ip(version: Literal[4, 6]) -> Union[ipaddress.IPv4Address, ipaddress.IPv6Address, None]:
|
@@ -85,8 +111,11 @@ def get_interface_public_ip(version: Literal[4, 6]) -> List[Union[ipaddress.IPv4
|
|
85
111
|
|
86
112
|
|
87
113
|
@cache.cache(ttl=600)
|
88
|
-
def get_ips(version: Literal[4, 6]) -> List[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
|
114
|
+
def get_ips(version: Literal[4, 6] | None = None) -> List[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
|
115
|
+
if not version:
|
116
|
+
return [*get_ips(4), *get_ips(6)]
|
89
117
|
addrs = []
|
118
|
+
|
90
119
|
i_ips = get_interface_public_ip(version)
|
91
120
|
if i_ips:
|
92
121
|
addrs = i_ips
|
@@ -136,6 +165,7 @@ def get_ip(version: Literal[4, 6], retry: int = 5) -> ipaddress.IPv4Address | ip
|
|
136
165
|
ip = get_ip(version, retry=retry - 1)
|
137
166
|
return ip
|
138
167
|
|
168
|
+
|
139
169
|
def get_random_domains(count: int = 1, retry: int = 3) -> List[str]:
|
140
170
|
try:
|
141
171
|
irurl = "https://api.ooni.io/api/v1/measurements?probe_cc=IR&test_name=web_connectivity&anomaly=false&confirmed=false&failure=false&order_by=test_start_time&limit=1000"
|
@@ -310,7 +340,7 @@ def is_in_same_asn(domain_or_ip: str, domain_or_ip_target: str) -> bool:
|
|
310
340
|
print(f"An error occurred: {e}")
|
311
341
|
return False
|
312
342
|
|
313
|
-
# hutils.flask.flash(_("
|
343
|
+
# hutils.flask.flash(_("domain.reality.asn_issue") +
|
314
344
|
# f"<br> Server ASN={asn_ipv4.get('autonomous_system_organization','unknown')}<br>{domain}_ASN={asn_dip.get('autonomous_system_organization','unknown')}", "warning")
|
315
345
|
|
316
346
|
|
@@ -342,8 +372,9 @@ def is_ip(input: str):
|
|
342
372
|
except:
|
343
373
|
return False
|
344
374
|
|
345
|
-
|
375
|
+
|
376
|
+
def resolve_domain_with_api(domain: str) -> str:
|
346
377
|
if not domain:
|
347
378
|
return ''
|
348
379
|
endpoint = f'http://ip-api.com/json/{domain}?fields=query'
|
349
|
-
return str(requests.get(endpoint).json().get('query'))
|
380
|
+
return str(requests.get(endpoint).json().get('query'))
|
@@ -130,7 +130,7 @@ def get_proxies(child_id: int = 0, only_enabled=False) -> list['Proxy']:
|
|
130
130
|
if not hconfig(ConfigEnum.vmess_enable, child_id):
|
131
131
|
proxies = [c for c in proxies if 'vmess' not in c.proto]
|
132
132
|
if not hconfig(ConfigEnum.vless_enable, child_id):
|
133
|
-
proxies = [c for c in proxies if 'vless' not in c.proto]
|
133
|
+
proxies = [c for c in proxies if 'vless' not in c.proto or 'reality' in c.l3]
|
134
134
|
if not hconfig(ConfigEnum.trojan_enable, child_id):
|
135
135
|
proxies = [c for c in proxies if 'trojan' not in c.proto]
|
136
136
|
if not hconfig(ConfigEnum.httpupgrade_enable, child_id):
|
@@ -223,8 +223,10 @@ def add_stream_settings(base: dict, proxy: dict):
|
|
223
223
|
# THE CURRENT CODE WORKS BUT THE CORRECT CONDITINO SHOULD BE THIS:
|
224
224
|
# ss['security'] == 'tls' or 'xtls' -----> ss['security'] in ['tls','xtls']
|
225
225
|
# TODO: FIX THE CONDITION AND TEST CONFIGS ON THE CLIENT SIDE
|
226
|
-
|
227
|
-
|
226
|
+
if ss['security'] == 'reality':
|
227
|
+
ss['network'] = proxy['transport']
|
228
|
+
add_reality_stream(ss, proxy)
|
229
|
+
elif ss['security'] == 'tls' or 'xtls' and proxy['proto'] != ProxyProto.ss:
|
228
230
|
ss['tlsSettings'] = {
|
229
231
|
'serverName': proxy['sni'],
|
230
232
|
'allowInsecure': proxy['allow_insecure'],
|
@@ -239,9 +241,7 @@ def add_stream_settings(base: dict, proxy: dict):
|
|
239
241
|
# 'cipherSuites': '', # Go lang sets
|
240
242
|
# 'rejectUnknownSni': '', # default is false
|
241
243
|
}
|
242
|
-
|
243
|
-
ss['network'] = proxy['transport']
|
244
|
-
add_reality_stream(ss, proxy)
|
244
|
+
|
245
245
|
if proxy['l3'] == ProxyL3.kcp:
|
246
246
|
ss['network'] = 'kcp'
|
247
247
|
add_kcp_stream(ss, proxy)
|
@@ -249,7 +249,7 @@ def add_stream_settings(base: dict, proxy: dict):
|
|
249
249
|
if proxy['l3'] == ProxyL3.h3_quic:
|
250
250
|
add_quic_stream(ss, proxy)
|
251
251
|
|
252
|
-
if proxy['transport'] == 'tcp'
|
252
|
+
if (proxy['transport'] == 'tcp' and ss['security'] != 'reality') or (ss['security'] == 'none' and proxy['transport'] not in [ProxyTransport.httpupgrade, ProxyTransport.WS] and proxy['proto'] != ProxyProto.ss):
|
253
253
|
ss['network'] = proxy['transport']
|
254
254
|
add_tcp_stream(ss, proxy)
|
255
255
|
if proxy['transport'] == ProxyTransport.h2 and ss['security'] == 'none' and ss['security'] != 'reality':
|
@@ -243,8 +243,8 @@ class ConfigEnum(metaclass=FastEnum):
|
|
243
243
|
trojan_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
|
244
244
|
reality_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
|
245
245
|
tcp_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
|
246
|
-
quic_enable = _BoolConfigDscr(ConfigCategory.
|
247
|
-
xtls_enable = _BoolConfigDscr(ConfigCategory.
|
246
|
+
quic_enable = _BoolConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
|
247
|
+
xtls_enable = _BoolConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
|
248
248
|
h2_enable = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply)
|
249
249
|
|
250
250
|
db_version = _StrConfigDscr(ConfigCategory.hidden, ApplyMode.apply)
|
hiddifypanel/models/domain.py
CHANGED
@@ -38,7 +38,7 @@ ShowDomain = db.Table('show_domain',
|
|
38
38
|
class Domain(db.Model, SerializerMixin):
|
39
39
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
40
40
|
child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0)
|
41
|
-
domain = db.Column(db.String(200), nullable=
|
41
|
+
domain = db.Column(db.String(200), nullable=True, unique=False)
|
42
42
|
alias = db.Column(db.String(200))
|
43
43
|
sub_link_only = db.Column(db.Boolean, nullable=False, default=False)
|
44
44
|
mode = db.Column(db.Enum(DomainType), nullable=False, default=DomainType.direct)
|
hiddifypanel/models/user.py
CHANGED
@@ -290,7 +290,7 @@ class User(BaseAccount, SerializerMixin):
|
|
290
290
|
return schema.dump(User())
|
291
291
|
|
292
292
|
def to_schema(self):
|
293
|
-
user_dict = self.to_dict()
|
293
|
+
user_dict = self.to_dict(dump_id=True)
|
294
294
|
from hiddifypanel.panel.commercial.restapi.v2.admin.user_api import UserSchema
|
295
295
|
return UserSchema().load(user_dict)
|
296
296
|
|
@@ -317,7 +317,8 @@ class User(BaseAccount, SerializerMixin):
|
|
317
317
|
'wg_pk': self.wg_pk,
|
318
318
|
'wg_pub': self.wg_pub,
|
319
319
|
'wg_psk': self.wg_psk,
|
320
|
-
'is_active': self.is_active
|
320
|
+
'is_active': self.is_active,
|
321
|
+
'enable': self.enable
|
321
322
|
}
|
322
323
|
|
323
324
|
# @staticmethod
|
@@ -65,7 +65,7 @@ class Actions(FlaskView):
|
|
65
65
|
domain_changed = request.args.get("domain_changed", str(domain_changed)).lower() == "true"
|
66
66
|
complete_install = request.args.get("complete_install", str(complete_install)).lower() == "true"
|
67
67
|
if domain_changed:
|
68
|
-
hutils.flask.flash((_('
|
68
|
+
hutils.flask.flash((_('domain.changed_in_domain_warning')), 'info')
|
69
69
|
# hutils.flask.flash(f'complete_install={complete_install} domain_changed={domain_changed} ', 'info')
|
70
70
|
# return render_template("result.html")
|
71
71
|
# hiddify.add_temporary_access()
|
@@ -87,7 +87,7 @@ class Actions(FlaskView):
|
|
87
87
|
|
88
88
|
resp = render_template("result.html",
|
89
89
|
out_type="info",
|
90
|
-
out_msg=_("
|
90
|
+
out_msg=_("admin.waiting_for_update") +
|
91
91
|
admin_links,
|
92
92
|
log_file_url=get_log_api_url(),
|
93
93
|
log_file="0-install.log",
|
@@ -72,7 +72,7 @@ class AdminstratorAdmin(AdminLTEModelView):
|
|
72
72
|
|
73
73
|
column_descriptions = dict(
|
74
74
|
comment=_("Add some text that is only visible to super_admin."),
|
75
|
-
mode=_("
|
75
|
+
mode=_("admin.define_mode"),
|
76
76
|
)
|
77
77
|
# create_modal = True
|
78
78
|
can_export = False
|
@@ -22,7 +22,7 @@ class Dashboard(FlaskView):
|
|
22
22
|
return redirect(hurl_for("admin.QuickSetup:index"))
|
23
23
|
|
24
24
|
if hutils.utils.is_panel_outdated():
|
25
|
-
hutils.flask.flash(_('
|
25
|
+
hutils.flask.flash(_('outdated_panel'), "danger") # type: ignore
|
26
26
|
|
27
27
|
childs = None
|
28
28
|
admin_id = request.args.get("admin_id") or g.account.id
|
@@ -48,8 +48,7 @@ class Dashboard(FlaskView):
|
|
48
48
|
|
49
49
|
if def_user and sslip_domains:
|
50
50
|
quick_setup = hurl_for("admin.QuickSetup:index")
|
51
|
-
hutils.flask.flash((_('
|
52
|
-
quick_setup=quick_setup)), 'warning') # type: ignore
|
51
|
+
hutils.flask.flash((_('admin.incomplete_setup_warning', quick_setup=quick_setup)), 'warning') # type: ignore
|
53
52
|
if hutils.node.is_parent():
|
54
53
|
hutils.flask.flash(
|
55
54
|
_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
|
@@ -61,7 +60,7 @@ class Dashboard(FlaskView):
|
|
61
60
|
_("Please understand that parent panel is under test and the plan and the condition of use maybe change at anytime."), "danger") # type: ignore
|
62
61
|
elif def_user:
|
63
62
|
d = domains[0]
|
64
|
-
hutils.flask.flash((_(
|
63
|
+
hutils.flask.flash((_("admin.no_user_warning",
|
65
64
|
default_link=hiddify.get_html_user_link(def_user, d))), 'secondary') # type: ignore
|
66
65
|
if hutils.network.is_ssh_password_authentication_enabled():
|
67
66
|
hutils.flask.flash(_('serverssh.password-login.warning'), "warning") # type: ignore
|
@@ -46,11 +46,11 @@ class DomainAdmin(AdminLTEModelView):
|
|
46
46
|
mode=_("Direct mode means you want to use your server directly (for usual use), CDN means that you use your server on behind of a CDN provider."),
|
47
47
|
cdn_ip=_("config.cdn_forced_host.description"),
|
48
48
|
show_domains=_(
|
49
|
-
'
|
49
|
+
'domain.show_domains_description'),
|
50
50
|
alias=_('The name shown in the configs for this domain.'),
|
51
51
|
servernames=_('config.reality_server_names.description'),
|
52
52
|
sub_link_only=_('This can be used for giving your users a permanent non blockable links.'),
|
53
|
-
grpc=_('
|
53
|
+
grpc=_('grpc-proxy.description'))
|
54
54
|
|
55
55
|
# create_modal = True
|
56
56
|
can_export = False
|
@@ -65,7 +65,7 @@ class DomainAdmin(AdminLTEModelView):
|
|
65
65
|
'domain': {
|
66
66
|
'validators': [
|
67
67
|
Regexp(
|
68
|
-
r'^(\*\.)?([A-Za-z0-9\-\.]+\.[a-zA-Z]{2,})
|
68
|
+
r'^(\*\.)?([A-Za-z0-9\-\.]+\.[a-zA-Z]{2,})$|^$',
|
69
69
|
message=__("Should be a valid domain"))]},
|
70
70
|
"cdn_ip": {
|
71
71
|
'validators': [
|
@@ -109,21 +109,24 @@ class DomainAdmin(AdminLTEModelView):
|
|
109
109
|
f'</a><a href="{admin_link}" class="btn btn-xs btn-info ltr" target="_blank">{model.domain}</a></div>')
|
110
110
|
|
111
111
|
def _domain_ip(view, context, model, name):
|
112
|
-
|
112
|
+
dips = hutils.network.get_domain_ips(model.domain)
|
113
113
|
# The get_domain_ip function uses the socket library, which relies on the system DNS resolver. So it may sometimes use cached data, which is not desirable
|
114
|
-
if not
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
res
|
126
|
-
|
114
|
+
# if not dips:
|
115
|
+
# dip = hutils.network.resolve_domain_with_api(model.domain)
|
116
|
+
myips = set(hutils.network.get_ips())
|
117
|
+
all_res = ""
|
118
|
+
for dip in dips:
|
119
|
+
if dip in myips and model.mode in [DomainType.direct, DomainType.sub_link_only]:
|
120
|
+
badge_type = ''
|
121
|
+
elif dip and dip not in myips and model.mode != DomainType.direct:
|
122
|
+
badge_type = 'warning'
|
123
|
+
else:
|
124
|
+
badge_type = 'danger'
|
125
|
+
res = f'<span class="badge badge-{badge_type}">{dip}</span>'
|
126
|
+
if model.sub_link_only:
|
127
|
+
res += f'<span class="badge badge-success">{_("SubLink")}</span>'
|
128
|
+
all_res += res
|
129
|
+
return Markup(all_res)
|
127
130
|
|
128
131
|
def _show_domains_formater(view, context, model, name):
|
129
132
|
if not len(model.show_domains):
|
@@ -149,8 +152,9 @@ class DomainAdmin(AdminLTEModelView):
|
|
149
152
|
|
150
153
|
# TODO: refactor this function
|
151
154
|
def on_model_change(self, form, model, is_created):
|
152
|
-
model.domain = model.domain.lower()
|
153
|
-
|
155
|
+
model.domain = (model.domain or '').lower()
|
156
|
+
if model.domain == '' and model.mode != DomainType.fake:
|
157
|
+
raise ValidationError(_("domain.empty.allowed_for_fake_only"))
|
154
158
|
configs = get_hconfigs()
|
155
159
|
for c in configs:
|
156
160
|
if "domain" in c and c not in [ConfigEnum.decoy_domain, ConfigEnum.reality_fallback_domain] and c.category != 'hidden':
|
@@ -174,7 +178,7 @@ class DomainAdmin(AdminLTEModelView):
|
|
174
178
|
if "*" in model.domain and model.mode not in [DomainType.cdn, DomainType.auto_cdn_ip]:
|
175
179
|
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain"))
|
176
180
|
|
177
|
-
skip_check = "*" in model.domain
|
181
|
+
skip_check = "*" in model.domain or model.domain == ""
|
178
182
|
if hconfig(ConfigEnum.cloudflare) and model.mode not in [DomainType.fake, DomainType.relay, DomainType.reality]:
|
179
183
|
try:
|
180
184
|
proxied = model.mode in [DomainType.cdn, DomainType.auto_cdn_ip]
|
@@ -190,28 +194,30 @@ class DomainAdmin(AdminLTEModelView):
|
|
190
194
|
# hutils.flask.flash(__("Using alias with special charachters may cause problem in some clients like FairVPN."), 'warning')
|
191
195
|
# raise ValidationError(_("You have to add your cloudflare api key to use this feature: "))
|
192
196
|
|
193
|
-
|
197
|
+
dips = hutils.network.get_domain_ips(model.domain)
|
194
198
|
if model.sub_link_only:
|
195
|
-
if
|
199
|
+
if not dips:
|
196
200
|
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain")) # type: ignore
|
197
201
|
elif not skip_check:
|
198
|
-
if
|
202
|
+
if not dips:
|
199
203
|
raise ValidationError(_("Domain can not be resolved! there is a problem in your domain")) # type: ignore
|
200
204
|
|
201
205
|
domain_ip_is_same_as_panel = False
|
202
|
-
|
203
|
-
for
|
204
|
-
domain_ip_is_same_as_panel |=
|
206
|
+
server_ips = [*ipv4_list, *ipv6_list]
|
207
|
+
for mip in server_ips:
|
208
|
+
domain_ip_is_same_as_panel |= mip in dips
|
209
|
+
server_ips_str = ', '.join(list(map(str, server_ips)))
|
210
|
+
dips_str = ', '.join(list(map(str, dips)))
|
205
211
|
|
206
212
|
if model.mode == DomainType.direct and not domain_ip_is_same_as_panel:
|
207
213
|
# 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')
|
208
214
|
raise ValidationError(
|
209
|
-
__("Domain IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode", server_ip=
|
215
|
+
__("Domain IP=%(domain_ip)s is not matched with your ip=%(server_ip)s which is required in direct mode", server_ip=server_ips_str, domain_ip=dips_str)) # type: ignore
|
210
216
|
|
211
217
|
if domain_ip_is_same_as_panel and model.mode in [DomainType.cdn, DomainType.relay, DomainType.fake, DomainType.auto_cdn_ip]:
|
212
218
|
# # hutils.flask.flash(__(f"In CDN mode, Domain IP={dip} should be different to your ip={', '.join(list(map(str, ipv4_list)))}"), 'warning')
|
213
219
|
raise ValidationError(__("In CDN mode, Domain IP=%(domain_ip)s should be different to your ip=%(server_ip)s",
|
214
|
-
server_ip=
|
220
|
+
server_ip=server_ips_str, domain_ip=dips_str)) # type: ignore
|
215
221
|
|
216
222
|
# if model.mode in [DomainType.ss_faketls, DomainType.telegram_faketls]:
|
217
223
|
# if len(Domain.query.filter(Domain.mode==model.mode and Domain.id!=model.id).all())>0:
|
@@ -219,10 +225,11 @@ class DomainAdmin(AdminLTEModelView):
|
|
219
225
|
|
220
226
|
model.domain = model.domain.lower()
|
221
227
|
if model.mode == DomainType.direct and model.cdn_ip:
|
228
|
+
model.cdn_ip = ""
|
222
229
|
raise ValidationError(f"Specifying CDN IP is only valid for CDN mode")
|
223
230
|
|
224
231
|
if model.mode == DomainType.fake and not model.cdn_ip:
|
225
|
-
model.cdn_ip = str(
|
232
|
+
model.cdn_ip = str(server_ips[0])
|
226
233
|
|
227
234
|
# if model.mode==DomainType.fake and model.cdn_ip!=myip:
|
228
235
|
# raise ValidationError(f"Specifying CDN IP is only valid for CDN mode")
|
@@ -230,8 +237,14 @@ class DomainAdmin(AdminLTEModelView):
|
|
230
237
|
# # Update the many-to-many relationship
|
231
238
|
if len(model.show_domains) == Domain.query.count():
|
232
239
|
model.show_domains = []
|
233
|
-
|
234
|
-
|
240
|
+
if model.mode == DomainType.old_xtls_direct:
|
241
|
+
if not hconfig(ConfigEnum.xtls_enable):
|
242
|
+
set_hconfig(ConfigEnum.xtls_enable, True)
|
243
|
+
hutils.proxy.get_proxies().invalidate_all()
|
244
|
+
elif model.mode == DomainType.reality:
|
245
|
+
if not hconfig(ConfigEnum.reality_enable):
|
246
|
+
set_hconfig(ConfigEnum.reality_enable, True)
|
247
|
+
hutils.proxy.get_proxies().invalidate_all()
|
235
248
|
model.servernames = (model.servernames or model.domain).lower()
|
236
249
|
for v in set([model.domain, model.servernames]):
|
237
250
|
for d in v.split(","):
|
@@ -240,10 +253,10 @@ class DomainAdmin(AdminLTEModelView):
|
|
240
253
|
if not hutils.network.is_domain_reality_friendly(d): # the minimum requirement for the REALITY protocol is to have tls1.3 and h2
|
241
254
|
raise ValidationError(_("Domain is not REALITY friendly!") + f' {d}')
|
242
255
|
|
243
|
-
if not hutils.network.is_in_same_asn(d,
|
244
|
-
server_asn = hutils.network.get_ip_asn(
|
245
|
-
domain_asn = hutils.network.get_ip_asn(
|
246
|
-
msg = _("
|
256
|
+
if not hutils.network.is_in_same_asn(d, server_ips[0]):
|
257
|
+
server_asn = hutils.network.get_ip_asn(server_ips[0])
|
258
|
+
domain_asn = hutils.network.get_ip_asn(dips[0]) # type: ignore
|
259
|
+
msg = _("domain.reality.asn_issue") + \
|
247
260
|
(f"<br> Server ASN={server_asn}<br>{d}_ASN={domain_asn}" if server_asn or domain_asn else "")
|
248
261
|
hutils.flask.flash(msg, 'warning')
|
249
262
|
|