mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-12-18 10:02:35 +00:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a005c78653 | ||
|
|
6d92ddf2d3 | ||
|
|
296112bed8 | ||
|
|
50a857e182 | ||
|
|
cfca2cdf5c | ||
|
|
599797299f | ||
|
|
eee7333745 | ||
|
|
e7ed098503 | ||
|
|
29fb518156 | ||
|
|
e16e2cb964 | ||
|
|
a41b6b41e0 | ||
|
|
933e6e4c15 | ||
|
|
46384e19b5 | ||
|
|
e388a7efa0 | ||
|
|
4bc345542c | ||
|
|
829e9b1497 | ||
|
|
8e703d306c | ||
|
|
af908480f4 | ||
|
|
fc2d4ae751 | ||
|
|
cde5fb7a3e | ||
|
|
19da95c6fb | ||
|
|
bc4f29a6f6 | ||
|
|
1d0db2ba8b | ||
|
|
e617245b26 | ||
|
|
9280884c1c | ||
|
|
f31994fdcd | ||
|
|
71766418bb | ||
|
|
a9399dd709 | ||
|
|
d0cb9e5432 | ||
|
|
558188da90 | ||
|
|
ad5460dab8 | ||
|
|
4d37dca0de | ||
|
|
2ca4002624 | ||
|
|
053d640e4c | ||
|
|
f3acc28ded | ||
|
|
25987545db | ||
|
|
6720ecc6e0 | ||
|
|
0b3a7bb020 | ||
|
|
56373e362b | ||
|
|
02fc045370 | ||
|
|
e4ac73896f | ||
|
|
1518f792d6 | ||
|
|
67277dd622 | ||
|
|
82e7f020ea | ||
|
|
f20b9e01ab | ||
|
|
8cf8a3701b | ||
|
|
7ba24293d1 | ||
|
|
f10114c9ed | ||
|
|
cf31cbfb07 | ||
|
|
0edad24d5d | ||
|
|
1f1c1a9157 | ||
|
|
6c9d271ae1 | ||
|
|
6ff852e225 | ||
|
|
baa75dc735 | ||
|
|
8a9f0436b8 | ||
|
|
a9620a3cbe | ||
|
|
769e7dc8a0 | ||
|
|
2a70449411 | ||
|
|
8df720f19e | ||
|
|
dabbb45f6e | ||
|
|
ce24c1c3fd | ||
|
|
3c54c82ce9 |
@@ -1,3 +1,4 @@
|
|||||||
|
from django.conf import settings
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@@ -166,7 +167,7 @@ class AccountViewSet(OrgBulkModelViewSet):
|
|||||||
|
|
||||||
class AccountSecretsViewSet(AccountRecordViewLogMixin, AccountViewSet):
|
class AccountSecretsViewSet(AccountRecordViewLogMixin, AccountViewSet):
|
||||||
"""
|
"""
|
||||||
因为可能要导出所有账号,所以单独建立了一个 viewset
|
因为可能要导出所有账号,所以单独建立了一个 viewset
|
||||||
"""
|
"""
|
||||||
serializer_classes = {
|
serializer_classes = {
|
||||||
'default': serializers.AccountSecretSerializer,
|
'default': serializers.AccountSecretSerializer,
|
||||||
|
|||||||
@@ -81,4 +81,7 @@ class IntegrationApplicationViewSet(OrgBulkModelViewSet):
|
|||||||
remote_addr=get_request_ip(request), service=service.name, service_id=service.id,
|
remote_addr=get_request_ip(request), service=service.name, service_id=service.id,
|
||||||
account=f'{account.name}({account.username})', asset=f'{asset.name}({asset.address})',
|
account=f'{account.name}({account.username})', asset=f'{asset.name}({asset.address})',
|
||||||
)
|
)
|
||||||
return Response(data={'id': request.user.id, 'secret': account.secret})
|
|
||||||
|
# 根据配置决定是否返回密码
|
||||||
|
secret = account.secret if settings.SECURITY_ACCOUNT_SECRET_READ else None
|
||||||
|
return Response(data={'id': request.user.id, 'secret': secret})
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_filters import rest_framework as drf_filters
|
from django_filters import rest_framework as drf_filters
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class AutomationExecutionViewSet(
|
|||||||
mixins.CreateModelMixin, mixins.ListModelMixin,
|
mixins.CreateModelMixin, mixins.ListModelMixin,
|
||||||
mixins.RetrieveModelMixin, viewsets.GenericViewSet
|
mixins.RetrieveModelMixin, viewsets.GenericViewSet
|
||||||
):
|
):
|
||||||
search_fields = ('trigger', 'automation__name')
|
search_fields = ('id', 'trigger', 'automation__name')
|
||||||
filterset_fields = ('trigger', 'automation_id', 'automation__name')
|
filterset_fields = ('trigger', 'automation_id', 'automation__name')
|
||||||
filterset_class = AutomationExecutionFilterSet
|
filterset_class = AutomationExecutionFilterSet
|
||||||
serializer_class = serializers.AutomationExecutionSerializer
|
serializer_class = serializers.AutomationExecutionSerializer
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ class AutomationExecutionFilterSet(DaysExecutionFilterMixin, BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AutomationExecution
|
model = AutomationExecution
|
||||||
fields = ["days", 'trigger', 'automation__name']
|
fields = ["id", "days", 'trigger', 'automation__name']
|
||||||
|
|
||||||
|
|
||||||
class PushAccountRecordFilterSet(SecretRecordMixin, UUIDFilterMixin, BaseFilterSet):
|
class PushAccountRecordFilterSet(SecretRecordMixin, UUIDFilterMixin, BaseFilterSet):
|
||||||
|
|||||||
@@ -81,7 +81,9 @@ class VaultModelMixin(models.Model):
|
|||||||
def mark_secret_save_to_vault(self):
|
def mark_secret_save_to_vault(self):
|
||||||
self._secret = self._secret_save_to_vault_mark
|
self._secret = self._secret_save_to_vault_mark
|
||||||
self.skip_history_when_saving = True
|
self.skip_history_when_saving = True
|
||||||
self.save()
|
# Avoid calling overridden `save()` on concrete models (e.g. AccountTemplate)
|
||||||
|
# which may mutate `secret/_secret` again and cause post_save recursion.
|
||||||
|
super(VaultModelMixin, self).save(update_fields=['_secret'])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def secret_has_save_to_vault(self):
|
def secret_has_save_to_vault(self):
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from accounts.models import Account, AccountTemplate, GatheredAccount
|
|||||||
from accounts.tasks import push_accounts_to_assets_task
|
from accounts.tasks import push_accounts_to_assets_task
|
||||||
from assets.const import Category, AllTypes
|
from assets.const import Category, AllTypes
|
||||||
from assets.models import Asset
|
from assets.models import Asset
|
||||||
from common.serializers import SecretReadableMixin, CommonBulkModelSerializer
|
from common.serializers import SecretReadableMixin, SecretReadableCheckMixin, CommonBulkModelSerializer
|
||||||
from common.serializers.fields import ObjectRelatedField, LabeledChoiceField
|
from common.serializers.fields import ObjectRelatedField, LabeledChoiceField
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from .base import BaseAccountSerializer, AuthValidateMixin
|
from .base import BaseAccountSerializer, AuthValidateMixin
|
||||||
@@ -478,7 +478,7 @@ class AssetAccountBulkSerializer(
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
class AccountSecretSerializer(SecretReadableMixin, AccountSerializer):
|
class AccountSecretSerializer(SecretReadableCheckMixin, SecretReadableMixin, AccountSerializer):
|
||||||
spec_info = serializers.DictField(label=_('Spec info'), read_only=True)
|
spec_info = serializers.DictField(label=_('Spec info'), read_only=True)
|
||||||
|
|
||||||
class Meta(AccountSerializer.Meta):
|
class Meta(AccountSerializer.Meta):
|
||||||
@@ -491,9 +491,10 @@ class AccountSecretSerializer(SecretReadableMixin, AccountSerializer):
|
|||||||
exclude_backup_fields = [
|
exclude_backup_fields = [
|
||||||
'passphrase', 'push_now', 'params', 'spec_info'
|
'passphrase', 'push_now', 'params', 'spec_info'
|
||||||
]
|
]
|
||||||
|
secret_fields = ['secret']
|
||||||
|
|
||||||
|
|
||||||
class AccountHistorySerializer(serializers.ModelSerializer):
|
class AccountHistorySerializer(SecretReadableCheckMixin, serializers.ModelSerializer):
|
||||||
secret_type = LabeledChoiceField(choices=SecretType.choices, label=_('Secret type'))
|
secret_type = LabeledChoiceField(choices=SecretType.choices, label=_('Secret type'))
|
||||||
secret = serializers.CharField(label=_('Secret'), read_only=True)
|
secret = serializers.CharField(label=_('Secret'), read_only=True)
|
||||||
id = serializers.IntegerField(label=_('ID'), source='history_id', read_only=True)
|
id = serializers.IntegerField(label=_('ID'), source='history_id', read_only=True)
|
||||||
@@ -509,6 +510,7 @@ class AccountHistorySerializer(serializers.ModelSerializer):
|
|||||||
'history_user': {'label': _('User')},
|
'history_user': {'label': _('User')},
|
||||||
'history_date': {'label': _('Date')},
|
'history_date': {'label': _('Date')},
|
||||||
}
|
}
|
||||||
|
secret_fields = ['secret']
|
||||||
|
|
||||||
|
|
||||||
class AccountTaskSerializer(serializers.Serializer):
|
class AccountTaskSerializer(serializers.Serializer):
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from accounts.models import AccountTemplate
|
from accounts.models import AccountTemplate
|
||||||
from common.serializers import SecretReadableMixin
|
from common.serializers import SecretReadableMixin, SecretReadableCheckMixin
|
||||||
from common.serializers.fields import ObjectRelatedField
|
from common.serializers.fields import ObjectRelatedField
|
||||||
from .base import BaseAccountSerializer
|
from .base import BaseAccountSerializer
|
||||||
|
|
||||||
@@ -62,10 +62,11 @@ class AccountDetailTemplateSerializer(AccountTemplateSerializer):
|
|||||||
fields = AccountTemplateSerializer.Meta.fields + ['spec_info']
|
fields = AccountTemplateSerializer.Meta.fields + ['spec_info']
|
||||||
|
|
||||||
|
|
||||||
class AccountTemplateSecretSerializer(SecretReadableMixin, AccountDetailTemplateSerializer):
|
class AccountTemplateSecretSerializer(SecretReadableCheckMixin, SecretReadableMixin, AccountDetailTemplateSerializer):
|
||||||
class Meta(AccountDetailTemplateSerializer.Meta):
|
class Meta(AccountDetailTemplateSerializer.Meta):
|
||||||
fields = AccountDetailTemplateSerializer.Meta.fields
|
fields = AccountDetailTemplateSerializer.Meta.fields
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
**AccountDetailTemplateSerializer.Meta.extra_kwargs,
|
**AccountDetailTemplateSerializer.Meta.extra_kwargs,
|
||||||
'secret': {'write_only': False},
|
'secret': {'write_only': False},
|
||||||
}
|
}
|
||||||
|
secret_fields = ['secret']
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class VaultSignalHandler(object):
|
|||||||
else:
|
else:
|
||||||
vault_client.update(instance)
|
vault_client.update(instance)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Vault save failed: {}'.format(e))
|
logger.exception('Vault save failed: %s', e)
|
||||||
raise VaultException()
|
raise VaultException()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -87,7 +87,7 @@ class VaultSignalHandler(object):
|
|||||||
try:
|
try:
|
||||||
vault_client.delete(instance)
|
vault_client.delete(instance)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Vault delete failed: {}'.format(e))
|
logger.exception('Vault delete failed: %s', e)
|
||||||
raise VaultException()
|
raise VaultException()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from accounts.backends import vault_client
|
from accounts.backends import vault_client
|
||||||
from accounts.const import VaultTypeChoices
|
from accounts.const import VaultTypeChoices
|
||||||
from accounts.models import Account, AccountTemplate
|
from accounts.models import AccountTemplate, Account
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from orgs.utils import tmp_to_root_org
|
from orgs.utils import tmp_to_root_org
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ class BaseManager:
|
|||||||
self.execution.save()
|
self.execution.save()
|
||||||
|
|
||||||
def print_summary(self):
|
def print_summary(self):
|
||||||
content = "\nSummery: \n"
|
content = "\nSummary: \n"
|
||||||
for k, v in self.summary.items():
|
for k, v in self.summary.items():
|
||||||
content += f"\t - {k}: {v}\n"
|
content += f"\t - {k}: {v}\n"
|
||||||
content += "\t - Using: {}s\n".format(self.duration)
|
content += "\t - Using: {}s\n".format(self.duration)
|
||||||
|
|||||||
@@ -219,8 +219,18 @@ class RDPFileClientProtocolURLMixin:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
|
if connect_method_dict['type'] == 'virtual_app':
|
||||||
|
endpoint_protocol = 'vnc'
|
||||||
|
token_protocol = 'vnc'
|
||||||
|
data.update({
|
||||||
|
'protocol': 'vnc',
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
endpoint_protocol = connect_method_dict['endpoint_protocol']
|
||||||
|
token_protocol = token.protocol
|
||||||
|
|
||||||
endpoint = self.get_smart_endpoint(
|
endpoint = self.get_smart_endpoint(
|
||||||
protocol=connect_method_dict['endpoint_protocol'],
|
protocol=endpoint_protocol,
|
||||||
asset=asset
|
asset=asset
|
||||||
)
|
)
|
||||||
data.update({
|
data.update({
|
||||||
@@ -236,7 +246,7 @@ class RDPFileClientProtocolURLMixin:
|
|||||||
},
|
},
|
||||||
'endpoint': {
|
'endpoint': {
|
||||||
'host': endpoint.host,
|
'host': endpoint.host,
|
||||||
'port': endpoint.get_port(token.asset, token.protocol),
|
'port': endpoint.get_port(token.asset, token_protocol),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return data
|
return data
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ class SessionAuthentication(authentication.SessionAuthentication):
|
|||||||
user = getattr(request._request, 'user', None)
|
user = getattr(request._request, 'user', None)
|
||||||
|
|
||||||
# Unauthenticated, CSRF validation not required
|
# Unauthenticated, CSRF validation not required
|
||||||
if not user or not user.is_active:
|
if not user or not user.is_active or not user.is_valid:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class MFAMiddleware:
|
|||||||
# 这个是 mfa 登录页需要的请求, 也得放出来, 用户其实已经在 CAS/OIDC 中完成登录了
|
# 这个是 mfa 登录页需要的请求, 也得放出来, 用户其实已经在 CAS/OIDC 中完成登录了
|
||||||
white_urls = [
|
white_urls = [
|
||||||
'login/mfa', 'mfa/select', 'face/context', 'jsi18n/', '/static/',
|
'login/mfa', 'mfa/select', 'face/context', 'jsi18n/', '/static/',
|
||||||
'/profile/otp', '/logout/',
|
'/profile/otp', '/logout/', '/media/'
|
||||||
]
|
]
|
||||||
for url in white_urls:
|
for url in white_urls:
|
||||||
if request.path.find(url) > -1:
|
if request.path.find(url) > -1:
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import re
|
import re
|
||||||
import uuid
|
|
||||||
import time
|
import time
|
||||||
|
import uuid
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.test import Client
|
from django.test import Client
|
||||||
from django.urls import URLPattern, URLResolver
|
from django.urls import URLPattern, URLResolver
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from django.contrib.auth.models import AnonymousUser
|
|
||||||
|
|
||||||
from jumpserver.urls import api_v1
|
from jumpserver.urls import api_v1
|
||||||
|
|
||||||
@@ -81,7 +80,8 @@ known_unauth_urls = [
|
|||||||
"/api/v1/authentication/mfa/send-code/",
|
"/api/v1/authentication/mfa/send-code/",
|
||||||
"/api/v1/authentication/sso/login/",
|
"/api/v1/authentication/sso/login/",
|
||||||
"/api/v1/authentication/user-session/",
|
"/api/v1/authentication/user-session/",
|
||||||
"/api/v1/settings/i18n/zh-hans/"
|
"/api/v1/settings/i18n/zh-hans/",
|
||||||
|
"/api/v1/settings/client/versions/"
|
||||||
]
|
]
|
||||||
|
|
||||||
known_error_urls = [
|
known_error_urls = [
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import os
|
||||||
from ctypes import *
|
from ctypes import *
|
||||||
|
|
||||||
from .exception import PiicoError
|
from .exception import PiicoError
|
||||||
from .session import Session
|
from .session import Session
|
||||||
from .cipher import *
|
from .cipher import *
|
||||||
from .digest import *
|
from .digest import *
|
||||||
|
from django.core.cache import cache
|
||||||
|
from redis_lock import Lock as RedisLock
|
||||||
|
|
||||||
|
|
||||||
class Device:
|
class Device:
|
||||||
@@ -71,10 +74,28 @@ class Device:
|
|||||||
self.__device = device
|
self.__device = device
|
||||||
|
|
||||||
def __reset_key_store(self):
|
def __reset_key_store(self):
|
||||||
|
redis_client = cache.client.get_client()
|
||||||
|
server_hostname = os.environ.get("SERVER_HOSTNAME")
|
||||||
|
RESET_LOCK_KEY = f"spiico:{server_hostname}:reset"
|
||||||
|
LOCK_EXPIRE_SECONDS = 300
|
||||||
|
|
||||||
if self._driver is None:
|
if self._driver is None:
|
||||||
raise PiicoError("no driver loaded", 0)
|
raise PiicoError("no driver loaded", 0)
|
||||||
if self.__device is None:
|
if self.__device is None:
|
||||||
raise PiicoError("device not open", 0)
|
raise PiicoError("device not open", 0)
|
||||||
|
|
||||||
|
# ---- 分布式锁(Redis-Lock 实现 Redlock) ----
|
||||||
|
lock = RedisLock(
|
||||||
|
redis_client,
|
||||||
|
RESET_LOCK_KEY,
|
||||||
|
expire=LOCK_EXPIRE_SECONDS, # 锁自动过期
|
||||||
|
auto_renewal=False, # 不自动续租
|
||||||
|
)
|
||||||
|
|
||||||
|
# 尝试获取锁,拿不到直接返回
|
||||||
|
if not lock.acquire(blocking=False):
|
||||||
|
return
|
||||||
|
# ---- 真正执行 reset ----
|
||||||
ret = self._driver.SPII_ResetModule(self.__device)
|
ret = self._driver.SPII_ResetModule(self.__device)
|
||||||
if ret != 0:
|
if ret != 0:
|
||||||
raise PiicoError("reset device failed", ret)
|
raise PiicoError("reset device failed", ret)
|
||||||
@@ -30,12 +30,30 @@ __all__ = [
|
|||||||
"CommonSerializerMixin",
|
"CommonSerializerMixin",
|
||||||
"CommonBulkSerializerMixin",
|
"CommonBulkSerializerMixin",
|
||||||
"SecretReadableMixin",
|
"SecretReadableMixin",
|
||||||
|
"SecretReadableCheckMixin",
|
||||||
"CommonModelSerializer",
|
"CommonModelSerializer",
|
||||||
"CommonBulkModelSerializer",
|
"CommonBulkModelSerializer",
|
||||||
"ResourceLabelsMixin",
|
"ResourceLabelsMixin",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class SecretReadableCheckMixin(serializers.Serializer):
|
||||||
|
"""
|
||||||
|
根据 SECURITY_ACCOUNT_SECRET_READ 配置控制密码字段的可读性
|
||||||
|
当配置为 False 时,密码字段返回 None
|
||||||
|
"""
|
||||||
|
|
||||||
|
def to_representation(self, instance):
|
||||||
|
ret = super().to_representation(instance)
|
||||||
|
|
||||||
|
if not settings.SECURITY_ACCOUNT_SECRET_READ:
|
||||||
|
secret_fields = getattr(self.Meta, 'secret_fields', ['secret'])
|
||||||
|
for field_name in secret_fields:
|
||||||
|
if field_name in ret:
|
||||||
|
ret[field_name] = '<REDACTED>'
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class SecretReadableMixin(serializers.Serializer):
|
class SecretReadableMixin(serializers.Serializer):
|
||||||
"""加密字段 (EncryptedField) 可读性"""
|
"""加密字段 (EncryptedField) 可读性"""
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1636,6 +1636,7 @@
|
|||||||
"setVariable": "Set variable",
|
"setVariable": "Set variable",
|
||||||
"userId": "User ID",
|
"userId": "User ID",
|
||||||
"userName": "User name",
|
"userName": "User name",
|
||||||
|
"AccountSecretReadDisabled": "Account secret reading has been disabled by administrator",
|
||||||
"AccessToken": "Access tokens",
|
"AccessToken": "Access tokens",
|
||||||
"AccessTokenTip": "Access Token is a temporary credential generated through the OAuth2 (Authorization Code Grant) flow using the JumpServer client, which is used to access protected resources.",
|
"AccessTokenTip": "Access Token is a temporary credential generated through the OAuth2 (Authorization Code Grant) flow using the JumpServer client, which is used to access protected resources.",
|
||||||
"Revoke": "Revoke"
|
"Revoke": "Revoke"
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
"AccessDistribution": "Distribución de visitas",
|
"AccessDistribution": "Distribución de visitas",
|
||||||
"AccessIP": "Lista blanca de IP",
|
"AccessIP": "Lista blanca de IP",
|
||||||
"AccessKey": "Clave de acceso",
|
"AccessKey": "Clave de acceso",
|
||||||
|
"AccessToken": "Token de acceso",
|
||||||
|
"AccessTokenTip": "El token de acceso es un certificado temporal generado a través del cliente JumpServer utilizando el flujo de OAuth2 (autorización por código) para acceder a recursos protegidos.",
|
||||||
"Account": "Información de la cuenta",
|
"Account": "Información de la cuenta",
|
||||||
"AccountActivities": "Actividad de la cuenta",
|
"AccountActivities": "Actividad de la cuenta",
|
||||||
"AccountAndPasswordChangeRank": "Clasificación de cambio de contraseña de cuenta",
|
"AccountAndPasswordChangeRank": "Clasificación de cambio de contraseña de cuenta",
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"AccountPushUpdate": "Actualizar la notificación de la cuenta",
|
"AccountPushUpdate": "Actualizar la notificación de la cuenta",
|
||||||
"AccountReport": "Informe de cuentas",
|
"AccountReport": "Informe de cuentas",
|
||||||
"AccountResult": "Cambio de contraseña de cuenta exitoso/fallido",
|
"AccountResult": "Cambio de contraseña de cuenta exitoso/fallido",
|
||||||
|
"AccountSecretReadDisabled": "La función de lectura de nombre de usuario y contraseña ha sido desactivada por el administrador",
|
||||||
"AccountSelectHelpText": "La lista de cuentas agrega el nombre de usuario de la cuenta. Tipo de contraseña.",
|
"AccountSelectHelpText": "La lista de cuentas agrega el nombre de usuario de la cuenta. Tipo de contraseña.",
|
||||||
"AccountSessions": "Sesión de cuenta",
|
"AccountSessions": "Sesión de cuenta",
|
||||||
"AccountStatisticsReport": "Informe estadístico de cuentas",
|
"AccountStatisticsReport": "Informe estadístico de cuentas",
|
||||||
@@ -279,6 +282,7 @@
|
|||||||
"CACertificate": "Certificado CA",
|
"CACertificate": "Certificado CA",
|
||||||
"CAS": "CAS",
|
"CAS": "CAS",
|
||||||
"CMPP2": "CMPP v2.0",
|
"CMPP2": "CMPP v2.0",
|
||||||
|
"CTYun": "Tianyi Cloud",
|
||||||
"CTYunPrivate": "eCloud Nube Privada",
|
"CTYunPrivate": "eCloud Nube Privada",
|
||||||
"CalculationResults": "Error en la expresión cron",
|
"CalculationResults": "Error en la expresión cron",
|
||||||
"CallRecords": "Registro de llamadas",
|
"CallRecords": "Registro de llamadas",
|
||||||
@@ -1176,6 +1180,8 @@
|
|||||||
"RetrySelected": "Reintentar selección",
|
"RetrySelected": "Reintentar selección",
|
||||||
"Review": "Revisión",
|
"Review": "Revisión",
|
||||||
"Reviewer": "Aprobador",
|
"Reviewer": "Aprobador",
|
||||||
|
"Revoke": "Revocar",
|
||||||
|
"Risk": "Riesgo",
|
||||||
"RiskDetection": "Detección de riesgos",
|
"RiskDetection": "Detección de riesgos",
|
||||||
"RiskDetectionDetail": "Detalles de detección de riesgos",
|
"RiskDetectionDetail": "Detalles de detección de riesgos",
|
||||||
"RiskyAccount": "Cuenta de riesgo",
|
"RiskyAccount": "Cuenta de riesgo",
|
||||||
@@ -1639,6 +1645,7 @@
|
|||||||
"overwriteProtocolsAndPortsMsg": "Esta acción reemplazará todos los protocolos y puertos, ¿continuar?",
|
"overwriteProtocolsAndPortsMsg": "Esta acción reemplazará todos los protocolos y puertos, ¿continuar?",
|
||||||
"pleaseSelectAssets": "Por favor, seleccione un activo.",
|
"pleaseSelectAssets": "Por favor, seleccione un activo.",
|
||||||
"removeWarningMsg": "¿Está seguro de que desea eliminar?",
|
"removeWarningMsg": "¿Está seguro de que desea eliminar?",
|
||||||
|
"selectFiles": "Se ha seleccionado el archivo número {number}",
|
||||||
"selectedAssets": "Activos seleccionados",
|
"selectedAssets": "Activos seleccionados",
|
||||||
"setVariable": "configurar parámetros",
|
"setVariable": "configurar parámetros",
|
||||||
"userId": "ID de usuario",
|
"userId": "ID de usuario",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
"AccessDistribution": "アクセス分布",
|
"AccessDistribution": "アクセス分布",
|
||||||
"AccessIP": "IP ホワイトリスト",
|
"AccessIP": "IP ホワイトリスト",
|
||||||
"AccessKey": "アクセスキー",
|
"AccessKey": "アクセスキー",
|
||||||
|
"AccessToken": "アクセス・トークン",
|
||||||
|
"AccessTokenTip": "アクセス・トークンは、JumpServer クライアントを通じて OAuth2(Authorization Code Grant)フローを使用して生成される一時的な証明書であり、保護されたリソースへのアクセスに使用されます。",
|
||||||
"Account": "アカウント情報",
|
"Account": "アカウント情報",
|
||||||
"AccountActivities": "アカウント活動",
|
"AccountActivities": "アカウント活動",
|
||||||
"AccountAmount": "アカウント数",
|
"AccountAmount": "アカウント数",
|
||||||
@@ -46,6 +48,7 @@
|
|||||||
"AccountPushUpdate": "アカウント更新プッシュ",
|
"AccountPushUpdate": "アカウント更新プッシュ",
|
||||||
"AccountReport": "アカウントレポート",
|
"AccountReport": "アカウントレポート",
|
||||||
"AccountResult": "アカウントパスワード変更成功/失敗",
|
"AccountResult": "アカウントパスワード変更成功/失敗",
|
||||||
|
"AccountSecretReadDisabled": "アカウントパスワードの読み取り機能は管理者によって無効になっています。",
|
||||||
"AccountSelectHelpText": "アカウント一覧に追加されている内容は、アカウントのユーザー名",
|
"AccountSelectHelpText": "アカウント一覧に追加されている内容は、アカウントのユーザー名",
|
||||||
"AccountSessions": " アカウントセッション ",
|
"AccountSessions": " アカウントセッション ",
|
||||||
"AccountStatisticsReport": "アカウント統計レポート",
|
"AccountStatisticsReport": "アカウント統計レポート",
|
||||||
@@ -283,6 +286,7 @@
|
|||||||
"CACertificate": "CA 証明書",
|
"CACertificate": "CA 証明書",
|
||||||
"CAS": "CAS",
|
"CAS": "CAS",
|
||||||
"CMPP2": "CMPP v2.0",
|
"CMPP2": "CMPP v2.0",
|
||||||
|
"CTYun": "天翼クラウド",
|
||||||
"CTYunPrivate": "イークラウド・プライベートクラウド",
|
"CTYunPrivate": "イークラウド・プライベートクラウド",
|
||||||
"CalculationResults": "cron 式のエラー",
|
"CalculationResults": "cron 式のエラー",
|
||||||
"CallRecords": "つうわきろく",
|
"CallRecords": "つうわきろく",
|
||||||
@@ -1181,6 +1185,8 @@
|
|||||||
"RetrySelected": "選択したものを再試行",
|
"RetrySelected": "選択したものを再試行",
|
||||||
"Review": "審査",
|
"Review": "審査",
|
||||||
"Reviewer": "承認者",
|
"Reviewer": "承認者",
|
||||||
|
"Revoke": "取り消し",
|
||||||
|
"Risk": "リスク",
|
||||||
"RiskDetection": "リスク検出",
|
"RiskDetection": "リスク検出",
|
||||||
"RiskDetectionDetail": "リスク検出の詳細",
|
"RiskDetectionDetail": "リスク検出の詳細",
|
||||||
"RiskyAccount": "リスクアカウント",
|
"RiskyAccount": "リスクアカウント",
|
||||||
@@ -1644,6 +1650,7 @@
|
|||||||
"overwriteProtocolsAndPortsMsg": "この操作はすべてのプロトコルとポートを上書きしますが、続行してよろしいですか?",
|
"overwriteProtocolsAndPortsMsg": "この操作はすべてのプロトコルとポートを上書きしますが、続行してよろしいですか?",
|
||||||
"pleaseSelectAssets": "資産を選択してください",
|
"pleaseSelectAssets": "資産を選択してください",
|
||||||
"removeWarningMsg": "削除してもよろしいですか",
|
"removeWarningMsg": "削除してもよろしいですか",
|
||||||
|
"selectFiles": "{number}ファイルを選択しました。",
|
||||||
"selectedAssets": "選択した資産",
|
"selectedAssets": "選択した資産",
|
||||||
"setVariable": "パラメータ設定",
|
"setVariable": "パラメータ設定",
|
||||||
"userId": "ユーザーID",
|
"userId": "ユーザーID",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
"AccessDistribution": "방문 분포",
|
"AccessDistribution": "방문 분포",
|
||||||
"AccessIP": "IP 화이트리스트",
|
"AccessIP": "IP 화이트리스트",
|
||||||
"AccessKey": "액세스 키",
|
"AccessKey": "액세스 키",
|
||||||
|
"AccessToken": "접속 토큰",
|
||||||
|
"AccessTokenTip": "접속 토큰은 JumpServer 클라이언트를 통해 OAuth2(인증 코드 인증) 프로세스를 사용하여 생성된 임시 자격 증명으로, 보호된 리소스에 접근하는 데 사용됩니다.",
|
||||||
"Account": "계정",
|
"Account": "계정",
|
||||||
"AccountActivities": "계정 활동",
|
"AccountActivities": "계정 활동",
|
||||||
"AccountAndPasswordChangeRank": "계정 비밀번호 변경 순위",
|
"AccountAndPasswordChangeRank": "계정 비밀번호 변경 순위",
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"AccountPushUpdate": "계정 업데이트 푸시",
|
"AccountPushUpdate": "계정 업데이트 푸시",
|
||||||
"AccountReport": "계정 보고서",
|
"AccountReport": "계정 보고서",
|
||||||
"AccountResult": "계정 비밀번호 변경 성공/실패",
|
"AccountResult": "계정 비밀번호 변경 성공/실패",
|
||||||
|
"AccountSecretReadDisabled": "계정 비밀번호 읽기 기능은 관리자가 비활성화하였습니다.",
|
||||||
"AccountSelectHelpText": "계정 목록에 추가하는 것은 계정의 사용자 이름—암호 유형입니다.",
|
"AccountSelectHelpText": "계정 목록에 추가하는 것은 계정의 사용자 이름—암호 유형입니다.",
|
||||||
"AccountSessions": "계정 세션",
|
"AccountSessions": "계정 세션",
|
||||||
"AccountStatisticsReport": "계정 통계 보고서",
|
"AccountStatisticsReport": "계정 통계 보고서",
|
||||||
@@ -279,6 +282,7 @@
|
|||||||
"CACertificate": "CA 인증서",
|
"CACertificate": "CA 인증서",
|
||||||
"CAS": "CAS",
|
"CAS": "CAS",
|
||||||
"CMPP2": "CMPP v2.0",
|
"CMPP2": "CMPP v2.0",
|
||||||
|
"CTYun": "천윳 클라우드",
|
||||||
"CTYunPrivate": "천翼 개인 클라우드",
|
"CTYunPrivate": "천翼 개인 클라우드",
|
||||||
"CalculationResults": "cron 표현식 오류",
|
"CalculationResults": "cron 표현식 오류",
|
||||||
"CallRecords": "호출 기록",
|
"CallRecords": "호출 기록",
|
||||||
@@ -1176,6 +1180,8 @@
|
|||||||
"RetrySelected": "선택한 항목 재시도",
|
"RetrySelected": "선택한 항목 재시도",
|
||||||
"Review": "검토",
|
"Review": "검토",
|
||||||
"Reviewer": "승인자",
|
"Reviewer": "승인자",
|
||||||
|
"Revoke": "취소",
|
||||||
|
"Risk": "위험",
|
||||||
"RiskDetection": "위험 감지",
|
"RiskDetection": "위험 감지",
|
||||||
"RiskDetectionDetail": "위험 감지 상세 정보",
|
"RiskDetectionDetail": "위험 감지 상세 정보",
|
||||||
"RiskyAccount": "위험 계정",
|
"RiskyAccount": "위험 계정",
|
||||||
@@ -1639,6 +1645,7 @@
|
|||||||
"overwriteProtocolsAndPortsMsg": "이 작업은 모든 프로토콜과 포트를 덮어씌우게 됩니다. 계속하시겠습니까?",
|
"overwriteProtocolsAndPortsMsg": "이 작업은 모든 프로토콜과 포트를 덮어씌우게 됩니다. 계속하시겠습니까?",
|
||||||
"pleaseSelectAssets": "자산을 선택해 주세요",
|
"pleaseSelectAssets": "자산을 선택해 주세요",
|
||||||
"removeWarningMsg": "제거할 것인지 확실합니까?",
|
"removeWarningMsg": "제거할 것인지 확실합니까?",
|
||||||
|
"selectFiles": "선택한 파일 {number}개",
|
||||||
"selectedAssets": "선택한 자산",
|
"selectedAssets": "선택한 자산",
|
||||||
"setVariable": "설정 매개변수",
|
"setVariable": "설정 매개변수",
|
||||||
"userId": "사용자 ID",
|
"userId": "사용자 ID",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
"AccessDistribution": "Distribuição de Acesso",
|
"AccessDistribution": "Distribuição de Acesso",
|
||||||
"AccessIP": "Lista branca de IP",
|
"AccessIP": "Lista branca de IP",
|
||||||
"AccessKey": "Chave de Acesso",
|
"AccessKey": "Chave de Acesso",
|
||||||
|
"AccessToken": "Token de acesso",
|
||||||
|
"AccessTokenTip": "O token de acesso é um credencial temporário gerado pelo cliente JumpServer usando o fluxo OAuth2 (autorização por código), utilizado para acessar recursos protegidos.",
|
||||||
"Account": "Informações da conta",
|
"Account": "Informações da conta",
|
||||||
"AccountActivities": "Atividades da conta",
|
"AccountActivities": "Atividades da conta",
|
||||||
"AccountAndPasswordChangeRank": "Alteração de Senha por Classificação",
|
"AccountAndPasswordChangeRank": "Alteração de Senha por Classificação",
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"AccountPushUpdate": " Atualização de notificação de conta ",
|
"AccountPushUpdate": " Atualização de notificação de conta ",
|
||||||
"AccountReport": "Relatório de Contas",
|
"AccountReport": "Relatório de Contas",
|
||||||
"AccountResult": "Alteração de senha da conta bem-sucedida/falhada",
|
"AccountResult": "Alteração de senha da conta bem-sucedida/falhada",
|
||||||
|
"AccountSecretReadDisabled": "A funcionalidade de leitura de nome de usuário e senha foi desativada pelo administrador",
|
||||||
"AccountSelectHelpText": "A lista de contas inclui o nome de usuário da conta",
|
"AccountSelectHelpText": "A lista de contas inclui o nome de usuário da conta",
|
||||||
"AccountSessions": "Conta de sessão ",
|
"AccountSessions": "Conta de sessão ",
|
||||||
"AccountStatisticsReport": "Relatório de Estatísticas de Contas",
|
"AccountStatisticsReport": "Relatório de Estatísticas de Contas",
|
||||||
@@ -280,6 +283,7 @@
|
|||||||
"CACertificate": " Certificado CA",
|
"CACertificate": " Certificado CA",
|
||||||
"CAS": "CAS",
|
"CAS": "CAS",
|
||||||
"CMPP2": "CMPP v2.0",
|
"CMPP2": "CMPP v2.0",
|
||||||
|
"CTYun": "Tianyi Cloud",
|
||||||
"CTYunPrivate": " eCloud Nuvem Privada",
|
"CTYunPrivate": " eCloud Nuvem Privada",
|
||||||
"CalculationResults": "Erro de expressão cron",
|
"CalculationResults": "Erro de expressão cron",
|
||||||
"CallRecords": "Registro de chamadas",
|
"CallRecords": "Registro de chamadas",
|
||||||
@@ -1177,6 +1181,8 @@
|
|||||||
"RetrySelected": "repetir a seleção",
|
"RetrySelected": "repetir a seleção",
|
||||||
"Review": "Revisar",
|
"Review": "Revisar",
|
||||||
"Reviewer": "Aprovador",
|
"Reviewer": "Aprovador",
|
||||||
|
"Revoke": "Revogar",
|
||||||
|
"Risk": "Risco",
|
||||||
"RiskDetection": " Detecção de risco ",
|
"RiskDetection": " Detecção de risco ",
|
||||||
"RiskDetectionDetail": "Detalhes da Detecção de Risco",
|
"RiskDetectionDetail": "Detalhes da Detecção de Risco",
|
||||||
"RiskyAccount": " Conta de risco ",
|
"RiskyAccount": " Conta de risco ",
|
||||||
@@ -1640,6 +1646,7 @@
|
|||||||
"overwriteProtocolsAndPortsMsg": "Esta ação substituirá todos os protocolos e portas. Deseja continuar?",
|
"overwriteProtocolsAndPortsMsg": "Esta ação substituirá todos os protocolos e portas. Deseja continuar?",
|
||||||
"pleaseSelectAssets": "Por favor, selecione um ativo.",
|
"pleaseSelectAssets": "Por favor, selecione um ativo.",
|
||||||
"removeWarningMsg": "Tem certeza de que deseja remover",
|
"removeWarningMsg": "Tem certeza de que deseja remover",
|
||||||
|
"selectFiles": "Foram selecionados {number} arquivos",
|
||||||
"selectedAssets": "Ativos selecionados",
|
"selectedAssets": "Ativos selecionados",
|
||||||
"setVariable": "Parâmetros de configuração",
|
"setVariable": "Parâmetros de configuração",
|
||||||
"userId": "ID do usuário",
|
"userId": "ID do usuário",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
"AccessDistribution": "Распределение доступа",
|
"AccessDistribution": "Распределение доступа",
|
||||||
"AccessIP": "Белый список IP",
|
"AccessIP": "Белый список IP",
|
||||||
"AccessKey": "Ключ доступа",
|
"AccessKey": "Ключ доступа",
|
||||||
|
"AccessToken": "Токен доступа",
|
||||||
|
"AccessTokenTip": "Токен доступа создается через клиент JumpServer с использованием процесса OAuth2 (авторизация через код) в качестве временного удостоверения для доступа к защищенным ресурсам.",
|
||||||
"Account": "Информация об УЗ",
|
"Account": "Информация об УЗ",
|
||||||
"AccountActivities": "Активность учетной записи",
|
"AccountActivities": "Активность учетной записи",
|
||||||
"AccountAndPasswordChangeRank": "Рейтинг изменений паролей и учётных записей",
|
"AccountAndPasswordChangeRank": "Рейтинг изменений паролей и учётных записей",
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"AccountPushUpdate": "Обновление УЗ для публикации",
|
"AccountPushUpdate": "Обновление УЗ для публикации",
|
||||||
"AccountReport": "Отчет по УЗ",
|
"AccountReport": "Отчет по УЗ",
|
||||||
"AccountResult": "Успешное или неудачное изменение секрета УЗ",
|
"AccountResult": "Успешное или неудачное изменение секрета УЗ",
|
||||||
|
"AccountSecretReadDisabled": "Функция чтения логина и пароля была отключена администратором",
|
||||||
"AccountSelectHelpText": "В списке учетных записей отображается имя пользователя",
|
"AccountSelectHelpText": "В списке учетных записей отображается имя пользователя",
|
||||||
"AccountSessions": "Сессии учетной записи",
|
"AccountSessions": "Сессии учетной записи",
|
||||||
"AccountStatisticsReport": "Отчет по учетным записям",
|
"AccountStatisticsReport": "Отчет по учетным записям",
|
||||||
@@ -279,6 +282,7 @@
|
|||||||
"CACertificate": "Сертификат ЦС",
|
"CACertificate": "Сертификат ЦС",
|
||||||
"CAS": "CAS",
|
"CAS": "CAS",
|
||||||
"CMPP2": "CMPP v2.0",
|
"CMPP2": "CMPP v2.0",
|
||||||
|
"CTYun": "Tianyi Cloud",
|
||||||
"CTYunPrivate": "eCloud Private Cloud",
|
"CTYunPrivate": "eCloud Private Cloud",
|
||||||
"CalculationResults": "Ошибка в выражении cron",
|
"CalculationResults": "Ошибка в выражении cron",
|
||||||
"CallRecords": "Запись вызовов",
|
"CallRecords": "Запись вызовов",
|
||||||
@@ -1176,6 +1180,8 @@
|
|||||||
"RetrySelected": "Повторить выбранное",
|
"RetrySelected": "Повторить выбранное",
|
||||||
"Review": "Требовать одобрения",
|
"Review": "Требовать одобрения",
|
||||||
"Reviewer": "Утверждающий",
|
"Reviewer": "Утверждающий",
|
||||||
|
"Revoke": "Отмена",
|
||||||
|
"Risk": "Риск",
|
||||||
"RiskDetection": "Выявление рисков",
|
"RiskDetection": "Выявление рисков",
|
||||||
"RiskDetectionDetail": "Детали обнаружения риска",
|
"RiskDetectionDetail": "Детали обнаружения риска",
|
||||||
"RiskyAccount": "УЗ с риском",
|
"RiskyAccount": "УЗ с риском",
|
||||||
@@ -1639,6 +1645,7 @@
|
|||||||
"overwriteProtocolsAndPortsMsg": "Это действие заменит все протоколы и порты. Продолжить?",
|
"overwriteProtocolsAndPortsMsg": "Это действие заменит все протоколы и порты. Продолжить?",
|
||||||
"pleaseSelectAssets": "Пожалуйста, выберите актив",
|
"pleaseSelectAssets": "Пожалуйста, выберите актив",
|
||||||
"removeWarningMsg": "Вы уверены, что хотите удалить",
|
"removeWarningMsg": "Вы уверены, что хотите удалить",
|
||||||
|
"selectFiles": "Выбрано {number} файлов",
|
||||||
"selectedAssets": "Выбранные активы",
|
"selectedAssets": "Выбранные активы",
|
||||||
"setVariable": "Задать переменную",
|
"setVariable": "Задать переменную",
|
||||||
"userId": "ID пользователя",
|
"userId": "ID пользователя",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
"AccessDistribution": "Phân bố truy cập",
|
"AccessDistribution": "Phân bố truy cập",
|
||||||
"AccessIP": "Danh sách trắng IP",
|
"AccessIP": "Danh sách trắng IP",
|
||||||
"AccessKey": "Khóa truy cập",
|
"AccessKey": "Khóa truy cập",
|
||||||
|
"AccessToken": "Mã thông hành",
|
||||||
|
"AccessTokenTip": "Mã thông hành là giấy chứng nhận tạm thời được tạo ra thông qua quy trình OAuth2 (ủy quyền mã) sử dụng khách hàng JumpServer, dùng để truy cập tài nguyên được bảo vệ.",
|
||||||
"Account": "Tài khoản",
|
"Account": "Tài khoản",
|
||||||
"AccountActivities": "Tài khoản hoạt động",
|
"AccountActivities": "Tài khoản hoạt động",
|
||||||
"AccountAndPasswordChangeRank": "Thay đổi mật khẩu tài khoản xếp hạng",
|
"AccountAndPasswordChangeRank": "Thay đổi mật khẩu tài khoản xếp hạng",
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"AccountPushUpdate": "Cập nhật thông tin tài khoản",
|
"AccountPushUpdate": "Cập nhật thông tin tài khoản",
|
||||||
"AccountReport": "Báo cáo tài khoản",
|
"AccountReport": "Báo cáo tài khoản",
|
||||||
"AccountResult": "Thay đổi mật khẩu tài khoản thành công/thất bại",
|
"AccountResult": "Thay đổi mật khẩu tài khoản thành công/thất bại",
|
||||||
|
"AccountSecretReadDisabled": "Chức năng đọc tài khoản mật khẩu đã bị quản lý bởi quản trị viên vô hiệu hóa",
|
||||||
"AccountSelectHelpText": "Danh sách tài khoản thêm tên người dùng của tài khoản",
|
"AccountSelectHelpText": "Danh sách tài khoản thêm tên người dùng của tài khoản",
|
||||||
"AccountSessions": "Phiên tài khoản",
|
"AccountSessions": "Phiên tài khoản",
|
||||||
"AccountStatisticsReport": "Báo cáo thống kê tài khoản",
|
"AccountStatisticsReport": "Báo cáo thống kê tài khoản",
|
||||||
@@ -279,6 +282,7 @@
|
|||||||
"CACertificate": "Chứng chỉ CA",
|
"CACertificate": "Chứng chỉ CA",
|
||||||
"CAS": "CAS",
|
"CAS": "CAS",
|
||||||
"CMPP2": "CMPP v2.0",
|
"CMPP2": "CMPP v2.0",
|
||||||
|
"CTYun": "Điện toán đám mây Thiên Vân",
|
||||||
"CTYunPrivate": "Đám mây riêng Tianyi",
|
"CTYunPrivate": "Đám mây riêng Tianyi",
|
||||||
"CalculationResults": "Biểu thức cron sai",
|
"CalculationResults": "Biểu thức cron sai",
|
||||||
"CallRecords": "Ghi chép gọi",
|
"CallRecords": "Ghi chép gọi",
|
||||||
@@ -1176,6 +1180,8 @@
|
|||||||
"RetrySelected": "Thử lại đã chọn",
|
"RetrySelected": "Thử lại đã chọn",
|
||||||
"Review": "Xem xét",
|
"Review": "Xem xét",
|
||||||
"Reviewer": "Người phê duyệt",
|
"Reviewer": "Người phê duyệt",
|
||||||
|
"Revoke": "Huỷ bỏ",
|
||||||
|
"Risk": "Rủi ro",
|
||||||
"RiskDetection": "Phát hiện rủi ro",
|
"RiskDetection": "Phát hiện rủi ro",
|
||||||
"RiskDetectionDetail": "Chi tiết phát hiện rủi ro",
|
"RiskDetectionDetail": "Chi tiết phát hiện rủi ro",
|
||||||
"RiskyAccount": "Tài khoản rủi ro",
|
"RiskyAccount": "Tài khoản rủi ro",
|
||||||
@@ -1639,6 +1645,7 @@
|
|||||||
"overwriteProtocolsAndPortsMsg": "Hành động này sẽ ghi đè lên tất cả các giao thức và cổng, có tiếp tục không?",
|
"overwriteProtocolsAndPortsMsg": "Hành động này sẽ ghi đè lên tất cả các giao thức và cổng, có tiếp tục không?",
|
||||||
"pleaseSelectAssets": "Vui lòng chọn tài sản.",
|
"pleaseSelectAssets": "Vui lòng chọn tài sản.",
|
||||||
"removeWarningMsg": "Bạn có chắc chắn muốn xóa bỏ?",
|
"removeWarningMsg": "Bạn có chắc chắn muốn xóa bỏ?",
|
||||||
|
"selectFiles": "Đã chọn chọn {number} tệp tin",
|
||||||
"selectedAssets": "Tài sản đã chọn",
|
"selectedAssets": "Tài sản đã chọn",
|
||||||
"setVariable": "Cài đặt tham số",
|
"setVariable": "Cài đặt tham số",
|
||||||
"userId": "ID người dùng",
|
"userId": "ID người dùng",
|
||||||
|
|||||||
@@ -1648,5 +1648,6 @@
|
|||||||
"selectFiles": "已选择选择{number}文件",
|
"selectFiles": "已选择选择{number}文件",
|
||||||
"AccessToken": "访问令牌",
|
"AccessToken": "访问令牌",
|
||||||
"AccessTokenTip": "访问令牌是通过 JumpServer 客户端使用 OAuth2(授权码授权)流程生成的临时凭证,用于访问受保护的资源。",
|
"AccessTokenTip": "访问令牌是通过 JumpServer 客户端使用 OAuth2(授权码授权)流程生成的临时凭证,用于访问受保护的资源。",
|
||||||
"Revoke": "撤销"
|
"Revoke": "撤销",
|
||||||
|
"AccountSecretReadDisabled": "账号密码读取功能已被管理员禁用"
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
"AccessDistribution": "訪問分布",
|
"AccessDistribution": "訪問分布",
|
||||||
"AccessIP": "IP 白名單",
|
"AccessIP": "IP 白名單",
|
||||||
"AccessKey": "訪問金鑰",
|
"AccessKey": "訪問金鑰",
|
||||||
|
"AccessToken": "訪問令牌",
|
||||||
|
"AccessTokenTip": "訪問令牌是透過 JumpServer 客戶端使用 OAuth2(授權碼授權)流程生成的臨時憑證,用於訪問受保護的資源。",
|
||||||
"Account": "雲帳號",
|
"Account": "雲帳號",
|
||||||
"AccountActivities": "帳號活動",
|
"AccountActivities": "帳號活動",
|
||||||
"AccountAmount": "帳號數量",
|
"AccountAmount": "帳號數量",
|
||||||
@@ -46,6 +48,7 @@
|
|||||||
"AccountPushUpdate": "更新帳號推送",
|
"AccountPushUpdate": "更新帳號推送",
|
||||||
"AccountReport": "帳號報表",
|
"AccountReport": "帳號報表",
|
||||||
"AccountResult": "帳號改密成功/失敗",
|
"AccountResult": "帳號改密成功/失敗",
|
||||||
|
"AccountSecretReadDisabled": "帳號密碼讀取功能已被管理員禁用",
|
||||||
"AccountSelectHelpText": "帳號清單所加入的是使用者名稱",
|
"AccountSelectHelpText": "帳號清單所加入的是使用者名稱",
|
||||||
"AccountSessions": "帳號會話",
|
"AccountSessions": "帳號會話",
|
||||||
"AccountStatisticsReport": "帳號統計報告",
|
"AccountStatisticsReport": "帳號統計報告",
|
||||||
@@ -283,6 +286,7 @@
|
|||||||
"CACertificate": "CA 證書",
|
"CACertificate": "CA 證書",
|
||||||
"CAS": "CAS",
|
"CAS": "CAS",
|
||||||
"CMPP2": "CMPP v2.0",
|
"CMPP2": "CMPP v2.0",
|
||||||
|
"CTYun": "天翼雲",
|
||||||
"CTYunPrivate": "天翼私有雲",
|
"CTYunPrivate": "天翼私有雲",
|
||||||
"CalculationResults": "呼叫記錄",
|
"CalculationResults": "呼叫記錄",
|
||||||
"CallRecords": "調用記錄",
|
"CallRecords": "調用記錄",
|
||||||
@@ -1181,6 +1185,8 @@
|
|||||||
"RetrySelected": "重新嘗試所選",
|
"RetrySelected": "重新嘗試所選",
|
||||||
"Review": "審查",
|
"Review": "審查",
|
||||||
"Reviewer": "審批人",
|
"Reviewer": "審批人",
|
||||||
|
"Revoke": "撤銷",
|
||||||
|
"Risk": "風險",
|
||||||
"RiskDetection": "風險檢測",
|
"RiskDetection": "風險檢測",
|
||||||
"RiskDetectionDetail": "風險檢測詳情",
|
"RiskDetectionDetail": "風險檢測詳情",
|
||||||
"RiskyAccount": "風險帳號",
|
"RiskyAccount": "風險帳號",
|
||||||
@@ -1644,6 +1650,7 @@
|
|||||||
"overwriteProtocolsAndPortsMsg": "此操作將覆蓋所有協議和端口,是否繼續?",
|
"overwriteProtocolsAndPortsMsg": "此操作將覆蓋所有協議和端口,是否繼續?",
|
||||||
"pleaseSelectAssets": "請選擇資產",
|
"pleaseSelectAssets": "請選擇資產",
|
||||||
"removeWarningMsg": "你確定要移除",
|
"removeWarningMsg": "你確定要移除",
|
||||||
|
"selectFiles": "已選擇{number}文件",
|
||||||
"selectedAssets": "已選資產",
|
"selectedAssets": "已選資產",
|
||||||
"setVariable": "設置參數",
|
"setVariable": "設置參數",
|
||||||
"userId": "用戶ID",
|
"userId": "用戶ID",
|
||||||
|
|||||||
@@ -288,5 +288,6 @@
|
|||||||
"start time": "Start time",
|
"start time": "Start time",
|
||||||
"success": "Success",
|
"success": "Success",
|
||||||
"system user": "System user",
|
"system user": "System user",
|
||||||
"user": "User"
|
"user": "User",
|
||||||
|
"tabLimits": "15 tabs are currently open.\nTo ensure system stability, would you like to open Luna in a new browser tab to continue?"
|
||||||
}
|
}
|
||||||
@@ -288,5 +288,6 @@
|
|||||||
"start time": "Hora de inicio",
|
"start time": "Hora de inicio",
|
||||||
"success": "Éxito",
|
"success": "Éxito",
|
||||||
"system user": "Usuario del sistema",
|
"system user": "Usuario del sistema",
|
||||||
|
"tabLimits": "Actualmente tienes 15 pestañas abiertas. \n¿Para garantizar la estabilidad del sistema, deberías abrir Luna en una nueva pestaña del navegador para continuar con la operación?",
|
||||||
"user": "Usuario"
|
"user": "Usuario"
|
||||||
}
|
}
|
||||||
@@ -288,5 +288,6 @@
|
|||||||
"start time": "開始時間",
|
"start time": "開始時間",
|
||||||
"success": "成功",
|
"success": "成功",
|
||||||
"system user": "システムユーザー",
|
"system user": "システムユーザー",
|
||||||
|
"tabLimits": "現在、15個のタブが開かれています。システムの安定性を確保するために、新しいブラウザのタブでLunaを開いて操作を続けますか?",
|
||||||
"user": "ユーザー"
|
"user": "ユーザー"
|
||||||
}
|
}
|
||||||
@@ -288,5 +288,6 @@
|
|||||||
"start time": "시작 시간",
|
"start time": "시작 시간",
|
||||||
"success": "성공",
|
"success": "성공",
|
||||||
"system user": "시스템 사용자",
|
"system user": "시스템 사용자",
|
||||||
|
"tabLimits": "현재 15개의 탭이 열려 있습니다. 시스템의 안정성을 위해 Luna를 계속 사용하려면 새로운 브라우저 탭에서 열어보시겠습니까?",
|
||||||
"user": "사용자"
|
"user": "사용자"
|
||||||
}
|
}
|
||||||
@@ -288,5 +288,6 @@
|
|||||||
"start time": "Hora de início",
|
"start time": "Hora de início",
|
||||||
"success": " Sucesso",
|
"success": " Sucesso",
|
||||||
"system user": "Usuário do Sistema",
|
"system user": "Usuário do Sistema",
|
||||||
|
"tabLimits": "Atualmente, 15 abas estão abertas. Para garantir a estabilidade do sistema, você deseja abrir o Luna em uma nova aba do navegador para continuar a operação?",
|
||||||
"user": "Usuário"
|
"user": "Usuário"
|
||||||
}
|
}
|
||||||
@@ -288,5 +288,6 @@
|
|||||||
"start time": "время начала",
|
"start time": "время начала",
|
||||||
"success": "успешно",
|
"success": "успешно",
|
||||||
"system user": "системный пользователь",
|
"system user": "системный пользователь",
|
||||||
|
"tabLimits": "В данный момент открыто 15 вкладок. \nЧтобы обеспечить стабильность системы, стоит ли открыть Luna в новой вкладке браузера для продолжения работы?",
|
||||||
"user": "пользователь"
|
"user": "пользователь"
|
||||||
}
|
}
|
||||||
@@ -288,5 +288,6 @@
|
|||||||
"start time": "Thời gian bắt đầu",
|
"start time": "Thời gian bắt đầu",
|
||||||
"success": "Thành công",
|
"success": "Thành công",
|
||||||
"system user": "Tên đăng nhập",
|
"system user": "Tên đăng nhập",
|
||||||
|
"tabLimits": "Hiện tại đã mở 15 tab. \nĐể đảm bảo tính ổn định của hệ thống, có qua tab trình duyệt mới để mở Luna và tiếp tục thao tác không?",
|
||||||
"user": "Người dùng"
|
"user": "Người dùng"
|
||||||
}
|
}
|
||||||
@@ -288,5 +288,6 @@
|
|||||||
"start time": "开始时间",
|
"start time": "开始时间",
|
||||||
"success": "成功",
|
"success": "成功",
|
||||||
"system user": "系统用户",
|
"system user": "系统用户",
|
||||||
"user": "用户"
|
"user": "用户",
|
||||||
|
"tabLimits": "当前已打开 15 个标签页。\n为保证系统稳定是否在新的浏览器标签页中打开 Luna 以继续操作?"
|
||||||
}
|
}
|
||||||
@@ -289,5 +289,6 @@
|
|||||||
"start time": "開始時間",
|
"start time": "開始時間",
|
||||||
"success": "成功",
|
"success": "成功",
|
||||||
"system user": "系統用戶",
|
"system user": "系統用戶",
|
||||||
|
"tabLimits": "當前已打開 15 個標籤頁。 \n為了確保系統穩定,是否在新的瀏覽器標籤頁中打開 Luna 以繼續操作?",
|
||||||
"user": "用戶"
|
"user": "用戶"
|
||||||
}
|
}
|
||||||
@@ -13,11 +13,11 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
import types
|
import types
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from urllib.parse import urljoin, urlparse, quote
|
from urllib.parse import urljoin, urlparse, quote
|
||||||
|
|
||||||
|
import sys
|
||||||
import yaml
|
import yaml
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@@ -575,6 +575,7 @@ class Config(dict):
|
|||||||
],
|
],
|
||||||
'SECURITY_SERVICE_ACCOUNT_REGISTRATION': 'auto',
|
'SECURITY_SERVICE_ACCOUNT_REGISTRATION': 'auto',
|
||||||
'SECURITY_VIEW_AUTH_NEED_MFA': True,
|
'SECURITY_VIEW_AUTH_NEED_MFA': True,
|
||||||
|
'SECURITY_ACCOUNT_SECRET_READ': True,
|
||||||
'SECURITY_MAX_IDLE_TIME': 30,
|
'SECURITY_MAX_IDLE_TIME': 30,
|
||||||
'SECURITY_MAX_SESSION_TIME': 24,
|
'SECURITY_MAX_SESSION_TIME': 24,
|
||||||
'SECURITY_PASSWORD_EXPIRATION_TIME': 9999,
|
'SECURITY_PASSWORD_EXPIRATION_TIME': 9999,
|
||||||
@@ -698,6 +699,7 @@ class Config(dict):
|
|||||||
'LIMIT_SUPER_PRIV': False,
|
'LIMIT_SUPER_PRIV': False,
|
||||||
|
|
||||||
# Chat AI
|
# Chat AI
|
||||||
|
'IS_CUSTOM_MODEL': False,
|
||||||
'CHAT_AI_ENABLED': False,
|
'CHAT_AI_ENABLED': False,
|
||||||
'CHAT_AI_METHOD': 'api',
|
'CHAT_AI_METHOD': 'api',
|
||||||
'CHAT_AI_EMBED_URL': '',
|
'CHAT_AI_EMBED_URL': '',
|
||||||
@@ -706,10 +708,12 @@ class Config(dict):
|
|||||||
'GPT_API_KEY': '',
|
'GPT_API_KEY': '',
|
||||||
'GPT_PROXY': '',
|
'GPT_PROXY': '',
|
||||||
'GPT_MODEL': 'gpt-4o-mini',
|
'GPT_MODEL': 'gpt-4o-mini',
|
||||||
|
'CUSTOM_GPT_MODEL': 'gpt-4o-mini',
|
||||||
'DEEPSEEK_BASE_URL': '',
|
'DEEPSEEK_BASE_URL': '',
|
||||||
'DEEPSEEK_API_KEY': '',
|
'DEEPSEEK_API_KEY': '',
|
||||||
'DEEPSEEK_PROXY': '',
|
'DEEPSEEK_PROXY': '',
|
||||||
'DEEPSEEK_MODEL': 'deepseek-chat',
|
'DEEPSEEK_MODEL': 'deepseek-chat',
|
||||||
|
'CUSTOM_DEEPSEEK_MODEL': 'deepseek-chat',
|
||||||
'VIRTUAL_APP_ENABLED': False,
|
'VIRTUAL_APP_ENABLED': False,
|
||||||
|
|
||||||
'FILE_UPLOAD_SIZE_LIMIT_MB': 200,
|
'FILE_UPLOAD_SIZE_LIMIT_MB': 200,
|
||||||
@@ -717,11 +721,6 @@ class Config(dict):
|
|||||||
'TICKET_APPLY_ASSET_SCOPE': 'all',
|
'TICKET_APPLY_ASSET_SCOPE': 'all',
|
||||||
'LEAK_PASSWORD_DB_PATH': os.path.join(PROJECT_DIR, 'data', 'system', 'leak_passwords.db'),
|
'LEAK_PASSWORD_DB_PATH': os.path.join(PROJECT_DIR, 'data', 'system', 'leak_passwords.db'),
|
||||||
|
|
||||||
# Ansible Receptor
|
|
||||||
'RECEPTOR_ENABLED': False,
|
|
||||||
'ANSIBLE_RECEPTOR_GATEWAY_PROXY_HOST': 'jms_celery',
|
|
||||||
'ANSIBLE_RECEPTOR_TCP_LISTEN_ADDRESS': 'receptor:7521',
|
|
||||||
|
|
||||||
'FILE_UPLOAD_TEMP_DIR': None,
|
'FILE_UPLOAD_TEMP_DIR': None,
|
||||||
|
|
||||||
'LOKI_LOG_ENABLED': False,
|
'LOKI_LOG_ENABLED': False,
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ VERIFY_CODE_TTL = CONFIG.VERIFY_CODE_TTL
|
|||||||
SECURITY_MFA_VERIFY_TTL = CONFIG.SECURITY_MFA_VERIFY_TTL
|
SECURITY_MFA_VERIFY_TTL = CONFIG.SECURITY_MFA_VERIFY_TTL
|
||||||
SECURITY_UNCOMMON_USERS_TTL = CONFIG.SECURITY_UNCOMMON_USERS_TTL
|
SECURITY_UNCOMMON_USERS_TTL = CONFIG.SECURITY_UNCOMMON_USERS_TTL
|
||||||
SECURITY_VIEW_AUTH_NEED_MFA = CONFIG.SECURITY_VIEW_AUTH_NEED_MFA
|
SECURITY_VIEW_AUTH_NEED_MFA = CONFIG.SECURITY_VIEW_AUTH_NEED_MFA
|
||||||
|
SECURITY_ACCOUNT_SECRET_READ = CONFIG.SECURITY_ACCOUNT_SECRET_READ
|
||||||
SECURITY_SERVICE_ACCOUNT_REGISTRATION = CONFIG.SECURITY_SERVICE_ACCOUNT_REGISTRATION
|
SECURITY_SERVICE_ACCOUNT_REGISTRATION = CONFIG.SECURITY_SERVICE_ACCOUNT_REGISTRATION
|
||||||
SECURITY_LOGIN_CAPTCHA_ENABLED = CONFIG.SECURITY_LOGIN_CAPTCHA_ENABLED
|
SECURITY_LOGIN_CAPTCHA_ENABLED = CONFIG.SECURITY_LOGIN_CAPTCHA_ENABLED
|
||||||
SECURITY_MFA_IN_LOGIN_PAGE = CONFIG.SECURITY_MFA_IN_LOGIN_PAGE
|
SECURITY_MFA_IN_LOGIN_PAGE = CONFIG.SECURITY_MFA_IN_LOGIN_PAGE
|
||||||
@@ -238,6 +239,9 @@ LIMIT_SUPER_PRIV = CONFIG.LIMIT_SUPER_PRIV
|
|||||||
ASSET_SIZE = 'small'
|
ASSET_SIZE = 'small'
|
||||||
|
|
||||||
# Chat AI
|
# Chat AI
|
||||||
|
IS_CUSTOM_MODEL = CONFIG.IS_CUSTOM_MODEL
|
||||||
|
CUSTOM_GPT_MODEL = CONFIG.CUSTOM_GPT_MODEL
|
||||||
|
CUSTOM_DEEPSEEK_MODEL = CONFIG.CUSTOM_DEEPSEEK_MODEL
|
||||||
CHAT_AI_ENABLED = CONFIG.CHAT_AI_ENABLED
|
CHAT_AI_ENABLED = CONFIG.CHAT_AI_ENABLED
|
||||||
CHAT_AI_METHOD = CONFIG.CHAT_AI_METHOD
|
CHAT_AI_METHOD = CONFIG.CHAT_AI_METHOD
|
||||||
CHAT_AI_EMBED_URL = CONFIG.CHAT_AI_EMBED_URL
|
CHAT_AI_EMBED_URL = CONFIG.CHAT_AI_EMBED_URL
|
||||||
@@ -257,11 +261,6 @@ FILE_UPLOAD_SIZE_LIMIT_MB = CONFIG.FILE_UPLOAD_SIZE_LIMIT_MB
|
|||||||
|
|
||||||
TICKET_APPLY_ASSET_SCOPE = CONFIG.TICKET_APPLY_ASSET_SCOPE
|
TICKET_APPLY_ASSET_SCOPE = CONFIG.TICKET_APPLY_ASSET_SCOPE
|
||||||
|
|
||||||
# Ansible Receptor
|
|
||||||
RECEPTOR_ENABLED = CONFIG.RECEPTOR_ENABLED
|
|
||||||
ANSIBLE_RECEPTOR_GATEWAY_PROXY_HOST = CONFIG.ANSIBLE_RECEPTOR_GATEWAY_PROXY_HOST
|
|
||||||
ANSIBLE_RECEPTOR_TCP_LISTEN_ADDRESS = CONFIG.ANSIBLE_RECEPTOR_TCP_LISTEN_ADDRESS
|
|
||||||
|
|
||||||
LOKI_LOG_ENABLED = CONFIG.LOKI_LOG_ENABLED
|
LOKI_LOG_ENABLED = CONFIG.LOKI_LOG_ENABLED
|
||||||
LOKI_BASE_URL = CONFIG.LOKI_BASE_URL
|
LOKI_BASE_URL = CONFIG.LOKI_BASE_URL
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#
|
#
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
REDIS_SSL_CA, REDIS_SSL_CERT, REDIS_SSL_KEY, REDIS_SSL_REQUIRED, REDIS_USE_SSL,
|
REDIS_SSL_CA, REDIS_SSL_CERT, REDIS_SSL_KEY, REDIS_SSL_REQUIRED, REDIS_USE_SSL,
|
||||||
REDIS_PROTOCOL, REDIS_SENTINEL_SERVICE_NAME, REDIS_SENTINELS, REDIS_SENTINEL_PASSWORD,
|
REDIS_PROTOCOL, REDIS_SENTINEL_SERVICE_NAME, REDIS_SENTINELS, REDIS_SENTINEL_PASSWORD,
|
||||||
@@ -30,8 +31,8 @@ REST_FRAMEWORK = {
|
|||||||
),
|
),
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||||
# 'rest_framework.authentication.BasicAuthentication',
|
# 'rest_framework.authentication.BasicAuthentication',
|
||||||
'authentication.backends.drf.SignatureAuthentication',
|
|
||||||
'authentication.backends.drf.ServiceAuthentication',
|
'authentication.backends.drf.ServiceAuthentication',
|
||||||
|
'authentication.backends.drf.SignatureAuthentication',
|
||||||
'authentication.backends.drf.PrivateTokenAuthentication',
|
'authentication.backends.drf.PrivateTokenAuthentication',
|
||||||
'authentication.backends.drf.AccessTokenAuthentication',
|
'authentication.backends.drf.AccessTokenAuthentication',
|
||||||
"oauth2_provider.contrib.rest_framework.OAuth2Authentication",
|
"oauth2_provider.contrib.rest_framework.OAuth2Authentication",
|
||||||
|
|||||||
@@ -115,7 +115,11 @@ LOGGING = {
|
|||||||
'azure': {
|
'azure': {
|
||||||
'handlers': ['null'],
|
'handlers': ['null'],
|
||||||
'level': 'ERROR'
|
'level': 'ERROR'
|
||||||
}
|
},
|
||||||
|
'oauth2_provider': {
|
||||||
|
'handlers': ['console', 'file'],
|
||||||
|
'level': LOG_LEVEL,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class ResourceDownload(TemplateView):
|
|||||||
OPENSSH_VERSION=v9.4.0.0
|
OPENSSH_VERSION=v9.4.0.0
|
||||||
TINKER_VERSION=v0.1.6
|
TINKER_VERSION=v0.1.6
|
||||||
VIDEO_PLAYER_VERSION=0.6.0
|
VIDEO_PLAYER_VERSION=0.6.0
|
||||||
CLIENT_VERSION=4.0.0
|
CLIENT_VERSION=4.1.0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_meta_json(self):
|
def get_meta_json(self):
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from django.conf import settings
|
|
||||||
from django.utils.functional import LazyObject
|
from django.utils.functional import LazyObject
|
||||||
|
|
||||||
from ops.ansible import AnsibleNativeRunner
|
from ops.ansible import AnsibleNativeRunner
|
||||||
@@ -15,9 +14,7 @@ class _LazyRunnerInterface(LazyObject):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def make_interface():
|
def make_interface():
|
||||||
runner_type = AnsibleNativeRunner
|
runner_type = AnsibleNativeRunner
|
||||||
gateway_host = settings.ANSIBLE_RECEPTOR_GATEWAY_PROXY_HOST \
|
return RunnerInterface(runner_type=runner_type, gateway_proxy_host='127.0.0.1')
|
||||||
if settings.ANSIBLE_RECEPTOR_GATEWAY_PROXY_HOST else '127.0.0.1'
|
|
||||||
return RunnerInterface(runner_type=runner_type, gateway_proxy_host=gateway_host)
|
|
||||||
|
|
||||||
|
|
||||||
interface = _LazyRunnerInterface()
|
interface = _LazyRunnerInterface()
|
||||||
|
|||||||
@@ -42,16 +42,22 @@ class ChatAITestingAPI(GenericAPIView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tp = config['CHAT_AI_TYPE']
|
tp = config['CHAT_AI_TYPE']
|
||||||
|
is_custom_model = config['IS_CUSTOM_MODEL']
|
||||||
if tp == ChatAITypeChoices.gpt:
|
if tp == ChatAITypeChoices.gpt:
|
||||||
url = config['GPT_BASE_URL']
|
url = config['GPT_BASE_URL']
|
||||||
api_key = config['GPT_API_KEY']
|
api_key = config['GPT_API_KEY']
|
||||||
proxy = config['GPT_PROXY']
|
proxy = config['GPT_PROXY']
|
||||||
model = config['GPT_MODEL']
|
model = config['GPT_MODEL']
|
||||||
|
custom_model = config['CUSTOM_GPT_MODEL']
|
||||||
else:
|
else:
|
||||||
url = config['DEEPSEEK_BASE_URL']
|
url = config['DEEPSEEK_BASE_URL']
|
||||||
api_key = config['DEEPSEEK_API_KEY']
|
api_key = config['DEEPSEEK_API_KEY']
|
||||||
proxy = config['DEEPSEEK_PROXY']
|
proxy = config['DEEPSEEK_PROXY']
|
||||||
model = config['DEEPSEEK_MODEL']
|
model = config['DEEPSEEK_MODEL']
|
||||||
|
custom_model = config['CUSTOM_DEEPSEEK_MODEL']
|
||||||
|
|
||||||
|
model = custom_model or model \
|
||||||
|
if is_custom_model else model
|
||||||
|
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'base_url': url or None,
|
'base_url': url or None,
|
||||||
|
|||||||
@@ -222,4 +222,4 @@ class ClientVersionView(APIView):
|
|||||||
permission_classes = (AllowAny,)
|
permission_classes = (AllowAny,)
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
return Response(['4.0.0'], status=status.HTTP_200_OK)
|
return Response(['4.0.0', '4.1.0'], status=status.HTTP_200_OK)
|
||||||
|
|||||||
@@ -19,11 +19,23 @@ class ChatAITypeChoices(TextChoices):
|
|||||||
|
|
||||||
|
|
||||||
class GPTModelChoices(TextChoices):
|
class GPTModelChoices(TextChoices):
|
||||||
gpt_4o_mini = 'gpt-4o-mini', 'gpt-4o-mini'
|
# 🚀 Latest flagship dialogue model
|
||||||
gpt_4o = 'gpt-4o', 'gpt-4o'
|
GPT_5_2 = 'gpt-5.2', 'gpt-5.2'
|
||||||
o3_mini = 'o3-mini', 'o3-mini'
|
GPT_5_2_PRO = 'gpt-5.2-pro', 'gpt-5.2-pro'
|
||||||
o1_mini = 'o1-mini', 'o1-mini'
|
|
||||||
o1 = 'o1', 'o1'
|
GPT_5_1 = 'gpt-5.1', 'gpt-5.1'
|
||||||
|
GPT_5 = 'gpt-5', 'gpt-5'
|
||||||
|
|
||||||
|
# 💡 Lightweight & Cost-Friendly Version
|
||||||
|
GPT_5_MINI = 'gpt-5-mini', 'gpt-5-mini'
|
||||||
|
GPT_5_NANO = 'gpt-5-nano', 'gpt-5-nano'
|
||||||
|
|
||||||
|
# 🧠 GPT-4 series of dialogues (still supports chat tasks)
|
||||||
|
GPT_4O = 'gpt-4o', 'gpt-4o'
|
||||||
|
GPT_4O_MINI = 'gpt-4o-mini', 'gpt-4o-mini'
|
||||||
|
GPT_4_1 = 'gpt-4.1', 'gpt-4.1'
|
||||||
|
GPT_4_1_MINI = 'gpt-4.1-mini', 'gpt-4.1-mini'
|
||||||
|
GPT_4_1_NANO = 'gpt-4.1-nano', 'gpt-4.1-nano'
|
||||||
|
|
||||||
|
|
||||||
class DeepSeekModelChoices(TextChoices):
|
class DeepSeekModelChoices(TextChoices):
|
||||||
|
|||||||
@@ -203,12 +203,16 @@ def get_chatai_data():
|
|||||||
'proxy': settings.GPT_PROXY,
|
'proxy': settings.GPT_PROXY,
|
||||||
'model': settings.GPT_MODEL,
|
'model': settings.GPT_MODEL,
|
||||||
}
|
}
|
||||||
|
custom_model = settings.CUSTOM_GPT_MODEL
|
||||||
if settings.CHAT_AI_TYPE != ChatAITypeChoices.gpt:
|
if settings.CHAT_AI_TYPE != ChatAITypeChoices.gpt:
|
||||||
data['url'] = settings.DEEPSEEK_BASE_URL
|
data['url'] = settings.DEEPSEEK_BASE_URL
|
||||||
data['api_key'] = settings.DEEPSEEK_API_KEY
|
data['api_key'] = settings.DEEPSEEK_API_KEY
|
||||||
data['proxy'] = settings.DEEPSEEK_PROXY
|
data['proxy'] = settings.DEEPSEEK_PROXY
|
||||||
data['model'] = settings.DEEPSEEK_MODEL
|
data['model'] = settings.DEEPSEEK_MODEL
|
||||||
|
custom_model = settings.CUSTOM_DEEPSEEK_MODEL
|
||||||
|
|
||||||
|
data['model'] = custom_model or data['model'] \
|
||||||
|
if settings.IS_CUSTOM_MODEL else data['model']
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ class ChatAISettingSerializer(serializers.Serializer):
|
|||||||
help_text=_('The proxy server address of the GPT service. For example: http://ip:port')
|
help_text=_('The proxy server address of the GPT service. For example: http://ip:port')
|
||||||
)
|
)
|
||||||
GPT_MODEL = serializers.ChoiceField(
|
GPT_MODEL = serializers.ChoiceField(
|
||||||
default=GPTModelChoices.gpt_4o_mini, choices=GPTModelChoices.choices,
|
default=GPTModelChoices.GPT_4_1_MINI, choices=GPTModelChoices.choices,
|
||||||
label=_("GPT Model"), required=False,
|
label=_("GPT Model"), required=False,
|
||||||
)
|
)
|
||||||
DEEPSEEK_BASE_URL = serializers.CharField(
|
DEEPSEEK_BASE_URL = serializers.CharField(
|
||||||
@@ -168,6 +168,18 @@ class ChatAISettingSerializer(serializers.Serializer):
|
|||||||
default=DeepSeekModelChoices.deepseek_chat, choices=DeepSeekModelChoices.choices,
|
default=DeepSeekModelChoices.deepseek_chat, choices=DeepSeekModelChoices.choices,
|
||||||
label=_("DeepSeek Model"), required=False,
|
label=_("DeepSeek Model"), required=False,
|
||||||
)
|
)
|
||||||
|
IS_CUSTOM_MODEL = serializers.BooleanField(
|
||||||
|
required=False, default=False, label=_("Custom Model"),
|
||||||
|
help_text=_("Whether to use a custom model")
|
||||||
|
)
|
||||||
|
CUSTOM_GPT_MODEL = serializers.CharField(
|
||||||
|
max_length=256, allow_blank=True,
|
||||||
|
required=False, label=_('Custom gpt model'),
|
||||||
|
)
|
||||||
|
CUSTOM_DEEPSEEK_MODEL = serializers.CharField(
|
||||||
|
max_length=256, allow_blank=True,
|
||||||
|
required=False, label=_('Custom DeepSeek model'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TicketSettingSerializer(serializers.Serializer):
|
class TicketSettingSerializer(serializers.Serializer):
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class PrivateSettingSerializer(PublicSettingSerializer):
|
|||||||
TICKET_AUTHORIZE_DEFAULT_TIME_UNIT = serializers.CharField()
|
TICKET_AUTHORIZE_DEFAULT_TIME_UNIT = serializers.CharField()
|
||||||
AUTH_LDAP_SYNC_ORG_IDS = serializers.ListField()
|
AUTH_LDAP_SYNC_ORG_IDS = serializers.ListField()
|
||||||
SECURITY_MAX_IDLE_TIME = serializers.IntegerField()
|
SECURITY_MAX_IDLE_TIME = serializers.IntegerField()
|
||||||
|
SECURITY_ACCOUNT_SECRET_READ = serializers.BooleanField()
|
||||||
SECURITY_VIEW_AUTH_NEED_MFA = serializers.BooleanField()
|
SECURITY_VIEW_AUTH_NEED_MFA = serializers.BooleanField()
|
||||||
SECURITY_MFA_AUTH = serializers.IntegerField()
|
SECURITY_MFA_AUTH = serializers.IntegerField()
|
||||||
SECURITY_MFA_VERIFY_TTL = serializers.IntegerField()
|
SECURITY_MFA_VERIFY_TTL = serializers.IntegerField()
|
||||||
|
|||||||
@@ -18,40 +18,28 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 重定向中的样式 */
|
/* 重定向中的样式 */
|
||||||
.redirecting-container {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.redirecting-container.show {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-container {
|
.confirm-container {
|
||||||
transition: opacity 0.3s ease-out;
|
transition: opacity 0.3s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.confirm-container.hide {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<div>
|
<div>
|
||||||
<!-- 确认内容 -->
|
<!-- 确认内容 -->
|
||||||
<div class="confirm-container" id="confirmContainer">
|
<div class="confirm-container" id="confirmContainer">
|
||||||
<p>
|
<p>
|
||||||
<div class="alert {% if error %} alert-danger {% else %} alert-info {% endif %}" id="messages">
|
<div class="alert {% if error %} alert-danger {% else %} alert-info {% endif %}" id="messages">
|
||||||
{% trans 'You are about to be redirected to an external website.' %}
|
{% trans 'You are about to be redirected to an external website.' %}
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
{% trans 'Please confirm that you trust this link: ' %}
|
{% trans 'Please confirm that you trust this link: ' %}
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<a class="target-url" href="javascript:void(0)" onclick="handleRedirect(event)">{{ target_url }}</a>
|
<a class="target-url" href="javascript:void(0)" onclick="handleRedirect(event)">{{ target_url }}</a>
|
||||||
</div>
|
</div>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<a href="/" class="btn btn-default block full-width m-b">
|
<a id="backBtn" href="/" class="btn btn-default block full-width m-b">
|
||||||
{% trans 'Back' %}
|
{% trans 'Back' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,45 +50,60 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 重定向中内容 -->
|
|
||||||
<div class="redirecting-container" id="redirectingContainer">
|
|
||||||
<p>
|
|
||||||
<div class="alert alert-info" id="messages">
|
|
||||||
{% trans 'Redirecting you to the Desktop App ( JumpServer Client )' %}
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
{% trans 'You can safely close this window and return to the application.' %}
|
|
||||||
</div>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const targetUrl = '{{ target_url }}';
|
if (sessionStorage.getItem('page_refreshed')) {
|
||||||
|
// 用户刷新了页面,清除标记并跳转到首页
|
||||||
// 判断是否是 jms:// 协议
|
sessionStorage.removeItem('page_refreshed');
|
||||||
function isJmsProtocol(url) {
|
window.location.href = '/';
|
||||||
return url.toLowerCase().startsWith('jms://');
|
} else {
|
||||||
|
// 第一次加载,设置标记
|
||||||
|
window.addEventListener('beforeunload', function() {
|
||||||
|
sessionStorage.setItem('page_refreshed', 'true');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const targetUrl = '{{ target_url }}';
|
||||||
|
|
||||||
|
let countdownTimer = null;
|
||||||
|
let countdownSeconds = 30;
|
||||||
|
let startedCountdown = false;
|
||||||
|
|
||||||
function handleRedirect(event) {
|
function handleRedirect(event) {
|
||||||
// 如果有 event,阻止默认行为
|
|
||||||
if (event) {
|
if (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isJmsProtocol(targetUrl)) {
|
|
||||||
// 隐藏确认内容
|
|
||||||
document.getElementById('confirmContainer').classList.add('hide');
|
|
||||||
// 显示重定向中
|
|
||||||
document.getElementById('redirectingContainer').classList.add('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 延迟后执行跳转(让用户看到加载动画)
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.href = targetUrl;
|
if (targetUrl.startsWith('jms://')) {
|
||||||
|
if (startedCountdown) {
|
||||||
|
// 已经开始倒计时,直接跳转但不再重置倒计时
|
||||||
|
window.location.href = targetUrl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startedCountdown = true;
|
||||||
|
countdownSeconds = 30;
|
||||||
|
window.location.href = targetUrl;
|
||||||
|
const backBtn = document.getElementById('backBtn');
|
||||||
|
if (backBtn) {
|
||||||
|
const backButtonContent = backBtn.textContent;
|
||||||
|
backBtn.textContent = `${backButtonContent} (${countdownSeconds})`;
|
||||||
|
countdownTimer = setInterval(() => {
|
||||||
|
countdownSeconds--;
|
||||||
|
if (countdownSeconds > 0) {
|
||||||
|
backBtn.textContent = `${backButtonContent} (${countdownSeconds})`;
|
||||||
|
} else {
|
||||||
|
backBtn.textContent = `${backButtonContent}`;
|
||||||
|
clearInterval(countdownTimer);
|
||||||
|
countdownTimer = null;
|
||||||
|
window.location.href = '/';
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.location.href = targetUrl;
|
||||||
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -19,10 +19,3 @@ fi
|
|||||||
echo "4. For Apple processor"
|
echo "4. For Apple processor"
|
||||||
LDFLAGS="-L$(brew --prefix freetds)/lib -L$(brew --prefix openssl@1.1)/lib" CFLAGS="-I$(brew --prefix freetds)/include" pip install $(grep 'pymssql' requirements.txt)
|
LDFLAGS="-L$(brew --prefix freetds)/lib -L$(brew --prefix openssl@1.1)/lib" CFLAGS="-I$(brew --prefix freetds)/include" pip install $(grep 'pymssql' requirements.txt)
|
||||||
export PKG_CONFIG_PATH="/opt/homebrew/opt/mysql-client/lib/pkgconfig"
|
export PKG_CONFIG_PATH="/opt/homebrew/opt/mysql-client/lib/pkgconfig"
|
||||||
|
|
||||||
|
|
||||||
echo "5. Install Ansible Receptor"
|
|
||||||
export RECEPTOR_VERSION=v1.4.5
|
|
||||||
export ARCH=`arch`
|
|
||||||
wget -O ${TMPDIR}receptor.tar.gz https://github.com/ansible/receptor/releases/download/${RECEPTOR_VERSION}/receptor_${RECEPTOR_VERSION/v/}_darwin_${ARCH}.tar.gz
|
|
||||||
tar -xf ${TMPDIR}receptor.tar.gz -C /opt/homebrew/bin/
|
|
||||||
Reference in New Issue
Block a user