Merge branch 'dev' of github.com:jumpserver/jumpserver into dev

pull/11838/head
ibuler 2023-10-13 15:26:22 +08:00
commit ce976f215f
13 changed files with 228 additions and 127 deletions

View File

@ -46,7 +46,7 @@ class AccountTemplateViewSet(OrgBulkModelViewSet):
} }
rbac_perms = { rbac_perms = {
'su_from_account_templates': 'accounts.view_accounttemplate', 'su_from_account_templates': 'accounts.view_accounttemplate',
'sync_related_accounts': 'accounts.change_accounttemplate', 'sync_related_accounts': 'accounts.change_account',
} }
@action(methods=['get'], detail=False, url_path='su-from-account-templates') @action(methods=['get'], detail=False, url_path='su-from-account-templates')

View File

@ -41,9 +41,10 @@ class UserLoginReminderMsg(UserMessage):
class AssetLoginReminderMsg(UserMessage): class AssetLoginReminderMsg(UserMessage):
subject = _('Asset login reminder') subject = _('Asset login reminder')
def __init__(self, user, asset: Asset, login_user: User): def __init__(self, user, asset: Asset, login_user: User, account_username):
self.asset = asset self.asset = asset
self.login_user = login_user self.login_user = login_user
self.account_username = account_username
super().__init__(user) super().__init__(user)
def get_html_msg(self) -> dict: def get_html_msg(self) -> dict:
@ -51,6 +52,7 @@ class AssetLoginReminderMsg(UserMessage):
'recipient': self.user.username, 'recipient': self.user.username,
'username': self.login_user.username, 'username': self.login_user.username,
'asset': str(self.asset), 'asset': str(self.asset),
'account': self.account_username,
} }
message = render_to_string('acls/asset_login_reminder.html', context) message = render_to_string('acls/asset_login_reminder.html', context)

View File

@ -4,9 +4,10 @@
<hr> <hr>
<p><strong>{% trans 'Username' %}:</strong> [{{ username }}]</p> <p><strong>{% trans 'Username' %}:</strong> [{{ username }}]</p>
<p><strong>{% trans 'Assets' %}:</strong> [{{ asset }}]</p> <p><strong>{% trans 'Assets' %}:</strong> [{{ asset }}]</p>
<p><strong>{% trans 'Account' %}:</strong> [{{ account }}]</p>
<hr> <hr>
<p>{% trans 'The user has just successfully logged into the asset. Please ensure that this is an authorized operation. If you suspect that this is an unauthorized access, please take appropriate measures immediately.' %}</p> <p>{% trans 'The user has just logged in to the asset. Please ensure that this is an authorized operation. If you suspect that this is an unauthorized access, please take appropriate measures immediately.' %}</p>
<p>{% trans 'Thank you' %}</p> <p>{% trans 'Thank you' %}</p>

View File

@ -1,9 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from collections import defaultdict
import django_filters import django_filters
from django.db.models import Q from django.db.models import Q
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from rest_framework import status
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK from rest_framework.status import HTTP_200_OK
@ -12,7 +15,7 @@ from accounts.tasks import push_accounts_to_assets_task, verify_accounts_connect
from assets import serializers from assets import serializers
from assets.exceptions import NotSupportedTemporarilyError from assets.exceptions import NotSupportedTemporarilyError
from assets.filters import IpInFilterBackend, LabelFilterBackend, NodeFilterBackend from assets.filters import IpInFilterBackend, LabelFilterBackend, NodeFilterBackend
from assets.models import Asset, Gateway, Platform from assets.models import Asset, Gateway, Platform, Protocol
from assets.tasks import test_assets_connectivity_manual, update_assets_hardware_info_manual from assets.tasks import test_assets_connectivity_manual, update_assets_hardware_info_manual
from common.api import SuggestionMixin from common.api import SuggestionMixin
from common.drf.filters import BaseFilterSet, AttrRulesFilterBackend from common.drf.filters import BaseFilterSet, AttrRulesFilterBackend
@ -115,6 +118,7 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
("gateways", "assets.view_gateway"), ("gateways", "assets.view_gateway"),
("spec_info", "assets.view_asset"), ("spec_info", "assets.view_asset"),
("gathered_info", "assets.view_asset"), ("gathered_info", "assets.view_asset"),
("sync_platform_protocols", "assets.change_asset"),
) )
extra_filter_backends = [ extra_filter_backends = [
LabelFilterBackend, IpInFilterBackend, LabelFilterBackend, IpInFilterBackend,
@ -152,6 +156,39 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
gateways = asset.domain.gateways gateways = asset.domain.gateways
return self.get_paginated_response_from_queryset(gateways) return self.get_paginated_response_from_queryset(gateways)
@action(methods=['post'], detail=False, url_path='sync-platform-protocols')
def sync_platform_protocols(self, request, *args, **kwargs):
platform_id = request.data.get('platform_id')
platform = get_object_or_404(Platform, pk=platform_id)
assets = platform.assets.all()
platform_protocols = {
p['name']: p['port']
for p in platform.protocols.values('name', 'port')
}
asset_protocols_map = defaultdict(set)
protocols = assets.prefetch_related('protocols').values_list(
'id', 'protocols__name'
)
for asset_id, protocol in protocols:
asset_id = str(asset_id)
asset_protocols_map[asset_id].add(protocol)
objs = []
for asset_id, protocols in asset_protocols_map.items():
protocol_names = set(platform_protocols) - protocols
if not protocol_names:
continue
for name in protocol_names:
objs.append(
Protocol(
name=name,
port=platform_protocols[name],
asset_id=asset_id,
)
)
Protocol.objects.bulk_create(objs)
return Response(status=status.HTTP_200_OK)
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
if request.path.find('/api/v1/assets/assets/') > -1: if request.path.find('/api/v1/assets/assets/') > -1:
error = _('Cannot create asset directly, you should create a host or other') error = _('Cannot create asset directly, you should create a host or other')

View File

@ -159,7 +159,7 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
return return
if isinstance(self.initial_data, list): if isinstance(self.initial_data, list):
return return
accounts = self.initial_data.get('accounts', None) accounts = self.initial_data.pop('accounts', None)
self._accounts = accounts self._accounts = accounts
def _get_protocols_required_default(self): def _get_protocols_required_default(self):
@ -298,10 +298,37 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
self.perform_nodes_display_create(instance, nodes_display) self.perform_nodes_display_create(instance, nodes_display)
return instance return instance
@staticmethod
def sync_platform_protocols(instance, old_platform):
platform = instance.platform
if str(old_platform.id) == str(instance.platform_id):
return
platform_protocols = {
p['name']: p['port']
for p in platform.protocols.values('name', 'port')
}
protocols = set(instance.protocols.values_list('name', flat=True))
protocol_names = set(platform_protocols) - protocols
objs = []
for name in protocol_names:
objs.append(
Protocol(
name=name,
port=platform_protocols[name],
asset_id=instance.id,
)
)
Protocol.objects.bulk_create(objs)
@atomic @atomic
def update(self, instance, validated_data): def update(self, instance, validated_data):
old_platform = instance.platform
nodes_display = validated_data.pop('nodes_display', '') nodes_display = validated_data.pop('nodes_display', '')
instance = super().update(instance, validated_data) instance = super().update(instance, validated_data)
self.sync_platform_protocols(instance, old_platform)
self.perform_nodes_display_create(instance, nodes_display) self.perform_nodes_display_create(instance, nodes_display)
return instance return instance

View File

@ -5,15 +5,16 @@ from django.utils.translation import gettext as _
from rest_framework import serializers from rest_framework import serializers
from rest_framework.response import Response from rest_framework.response import Response
from authentication.permissions import UserConfirmation
from common.api import JMSModelViewSet from common.api import JMSModelViewSet
from rbac.permissions import RBACPermission from rbac.permissions import RBACPermission
from ..const import ConfirmType from ..serializers import AccessKeySerializer, AccessKeyCreateSerializer
from ..serializers import AccessKeySerializer
class AccessKeyViewSet(JMSModelViewSet): class AccessKeyViewSet(JMSModelViewSet):
serializer_class = AccessKeySerializer serializer_classes = {
'default': AccessKeySerializer,
'create': AccessKeyCreateSerializer
}
search_fields = ['^id'] search_fields = ['^id']
permission_classes = [RBACPermission] permission_classes = [RBACPermission]
@ -26,19 +27,20 @@ class AccessKeyViewSet(JMSModelViewSet):
if self.action == 'create': if self.action == 'create':
self.permission_classes = [ self.permission_classes = [
RBACPermission, UserConfirmation.require(ConfirmType.PASSWORD) RBACPermission,
] ]
return super().get_permissions() return super().get_permissions()
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
key = self.perform_create(serializer)
serializer = self.get_serializer(instance=key)
return Response(serializer.data, status=201)
def perform_create(self, serializer): def perform_create(self, serializer):
user = self.request.user user = self.request.user
if user.access_keys.count() >= 10: if user.access_keys.count() >= 10:
raise serializers.ValidationError(_('Access keys can be created at most 10')) raise serializers.ValidationError(_('Access keys can be created at most 10'))
key = user.create_access_key() key = user.create_access_key()
return key return key
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
key = self.perform_create(serializer)
return Response({'secret': key.secret, 'id': key.id}, status=201)

View File

@ -22,6 +22,7 @@ from common.utils import random_string, get_logger, get_request_ip
from common.utils.django import get_request_os from common.utils.django import get_request_os
from common.utils.http import is_true, is_false from common.utils.http import is_true, is_false
from orgs.mixins.api import RootOrgViewMixin from orgs.mixins.api import RootOrgViewMixin
from orgs.utils import tmp_to_org
from perms.models import ActionChoices from perms.models import ActionChoices
from terminal.connect_methods import NativeClient, ConnectMethodUtil from terminal.connect_methods import NativeClient, ConnectMethodUtil
from terminal.models import EndpointRule, Endpoint from terminal.models import EndpointRule, Endpoint
@ -360,9 +361,10 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
if account.has_secret: if account.has_secret:
data['input_secret'] = '' data['input_secret'] = ''
input_username = data.get('input_username', '')
if account.username != AliasAccount.INPUT: if account.username != AliasAccount.INPUT:
data['input_username'] = '' data['input_username'] = ''
ticket = self._validate_acl(user, asset, account) ticket = self._validate_acl(user, asset, account, input_username)
if ticket: if ticket:
data['from_ticket'] = ticket data['from_ticket'] = ticket
data['is_active'] = False data['is_active'] = False
@ -381,9 +383,13 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
return account return account
@staticmethod @staticmethod
def _record_operate_log(acl, asset): def _record_operate_log(acl, asset, input_username):
from audits.handler import create_or_update_operate_log from audits.handler import create_or_update_operate_log
after = {str(_('Assets')): str(asset)} with tmp_to_org(asset.org_id):
after = {
str(_('Assets')): str(asset),
str(_('Account')): input_username
}
object_name = acl._meta.object_name object_name = acl._meta.object_name
resource_type = acl._meta.verbose_name resource_type = acl._meta.verbose_name
create_or_update_operate_log( create_or_update_operate_log(
@ -391,7 +397,7 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
after=after, object_name=object_name after=after, object_name=object_name
) )
def _validate_acl(self, user, asset, account): def _validate_acl(self, user, asset, account, input_username):
from acls.models import LoginAssetACL from acls.models import LoginAssetACL
acls = LoginAssetACL.filter_queryset(user=user, asset=asset, account=account) acls = LoginAssetACL.filter_queryset(user=user, asset=asset, account=account)
ip = get_request_ip(self.request) ip = get_request_ip(self.request)
@ -399,19 +405,19 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
if not acl: if not acl:
return return
if acl.is_action(acl.ActionChoices.accept): if acl.is_action(acl.ActionChoices.accept):
self._record_operate_log(acl, asset) self._record_operate_log(acl, asset, input_username)
return return
if acl.is_action(acl.ActionChoices.reject): if acl.is_action(acl.ActionChoices.reject):
self._record_operate_log(acl, asset) self._record_operate_log(acl, asset, input_username)
msg = _('ACL action is reject: {}({})'.format(acl.name, acl.id)) msg = _('ACL action is reject: {}({})'.format(acl.name, acl.id))
raise JMSException(code='acl_reject', detail=msg) raise JMSException(code='acl_reject', detail=msg)
if acl.is_action(acl.ActionChoices.review): if acl.is_action(acl.ActionChoices.review):
if not self.request.query_params.get('create_ticket'): if not self.request.query_params.get('create_ticket'):
msg = _('ACL action is review') msg = _('ACL action is review')
raise JMSException(code='acl_review', detail=msg) raise JMSException(code='acl_review', detail=msg)
self._record_operate_log(acl, asset) self._record_operate_log(acl, asset, input_username)
ticket = LoginAssetACL.create_login_asset_review_ticket( ticket = LoginAssetACL.create_login_asset_review_ticket(
user=user, asset=asset, account_username=account.username, user=user, asset=asset, account_username=input_username,
assignees=acl.reviewers.all(), org_id=asset.org_id assignees=acl.reviewers.all(), org_id=asset.org_id
) )
return ticket return ticket
@ -419,9 +425,12 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
reviewers = acl.reviewers.all() reviewers = acl.reviewers.all()
if not reviewers: if not reviewers:
return return
self._record_operate_log(acl, asset)
self._record_operate_log(acl, asset, input_username)
for reviewer in reviewers: for reviewer in reviewers:
AssetLoginReminderMsg(reviewer, asset, user).publish_async() AssetLoginReminderMsg(
reviewer, asset, user, input_username
).publish_async()
class SuperConnectionTokenViewSet(ConnectionTokenViewSet): class SuperConnectionTokenViewSet(ConnectionTokenViewSet):

View File

@ -12,6 +12,7 @@ from ..models import AccessKey, TempToken
__all__ = [ __all__ = [
'AccessKeySerializer', 'BearerTokenSerializer', 'AccessKeySerializer', 'BearerTokenSerializer',
'SSOTokenSerializer', 'TempTokenSerializer', 'SSOTokenSerializer', 'TempTokenSerializer',
'AccessKeyCreateSerializer'
] ]
@ -22,6 +23,11 @@ class AccessKeySerializer(serializers.ModelSerializer):
read_only_fields = ['id', 'date_created', 'date_last_used'] read_only_fields = ['id', 'date_created', 'date_last_used']
class AccessKeyCreateSerializer(AccessKeySerializer):
class Meta(AccessKeySerializer.Meta):
fields = AccessKeySerializer.Meta.fields + ['secret']
class BearerTokenSerializer(serializers.Serializer): class BearerTokenSerializer(serializers.Serializer):
username = serializers.CharField(allow_null=True, required=False, write_only=True) username = serializers.CharField(allow_null=True, required=False, write_only=True)
password = serializers.CharField(write_only=True, allow_null=True, password = serializers.CharField(write_only=True, allow_null=True,

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:38bd8a6653f3f4dc63552b1c86379f82067f9f9daac227bacb3af3f9f62134f9 oid sha256:d7366743ab156daec72625cd241f76420c551c6a48330266a57e3d0b808d4164
size 161704 size 162675

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-10-12 09:51+0800\n" "POT-Creation-Date: 2023-10-13 15:03+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -263,10 +263,12 @@ msgstr "ソース ID"
#: accounts/models/account.py:60 #: accounts/models/account.py:60
#: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:112
#: accounts/serializers/automations/change_secret.py:132 #: accounts/serializers/automations/change_secret.py:132
#: acls/serializers/base.py:124 assets/serializers/asset/common.py:125 #: acls/serializers/base.py:124 acls/templates/acls/asset_login_reminder.html:7
#: assets/serializers/gateway.py:28 audits/models.py:57 ops/models/base.py:18 #: assets/serializers/asset/common.py:125 assets/serializers/gateway.py:28
#: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: audits/models.py:57 authentication/api/connection_token.py:391
#: terminal/backends/command/models.py:18 terminal/models/session/session.py:33 #: ops/models/base.py:18 perms/models/asset_permission.py:70
#: perms/serializers/permission.py:39 terminal/backends/command/models.py:18
#: terminal/models/session/session.py:33
#: terminal/templates/terminal/_msg_command_warning.html:8 #: terminal/templates/terminal/_msg_command_warning.html:8
#: terminal/templates/terminal/_msg_session_sharing.html:8 #: terminal/templates/terminal/_msg_session_sharing.html:8
#: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:89 #: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:89
@ -712,7 +714,7 @@ msgstr "編集済み"
#: acls/templates/acls/asset_login_reminder.html:6 #: acls/templates/acls/asset_login_reminder.html:6
#: assets/models/automations/base.py:19 #: assets/models/automations/base.py:19
#: assets/serializers/automations/base.py:20 #: assets/serializers/automations/base.py:20
#: authentication/api/connection_token.py:386 ops/models/base.py:17 #: authentication/api/connection_token.py:390 ops/models/base.py:17
#: ops/models/job.py:139 ops/serializers/job.py:21 #: ops/models/job.py:139 ops/serializers/job.py:21
#: terminal/templates/terminal/_msg_command_execute_alert.html:16 #: terminal/templates/terminal/_msg_command_execute_alert.html:16
msgid "Assets" msgid "Assets"
@ -789,7 +791,7 @@ msgid "Key password"
msgstr "キーパスワード" msgstr "キーパスワード"
#: accounts/serializers/account/base.py:78 #: accounts/serializers/account/base.py:78
#: assets/serializers/asset/common.py:311 #: assets/serializers/asset/common.py:338
msgid "Spec info" msgid "Spec info"
msgstr "特別情報" msgstr "特別情報"
@ -1024,7 +1026,7 @@ msgid "Users"
msgstr "ユーザー" msgstr "ユーザー"
#: acls/models/base.py:98 assets/models/automations/base.py:17 #: acls/models/base.py:98 assets/models/automations/base.py:17
#: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:310 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:337
#: rbac/tree.py:35 #: rbac/tree.py:35
msgid "Accounts" msgid "Accounts"
msgstr "アカウント" msgstr "アカウント"
@ -1173,17 +1175,16 @@ msgstr "期間"
msgid "Respectful" msgid "Respectful"
msgstr "尊敬する" msgstr "尊敬する"
#: acls/templates/acls/asset_login_reminder.html:9 #: acls/templates/acls/asset_login_reminder.html:10
msgid "" msgid ""
"The user has just successfully logged into the asset. Please ensure that " "The user has just logged in to the asset. Please ensure that this is an "
"this is an authorized operation. If you suspect that this is an unauthorized " "authorized operation. If you suspect that this is an unauthorized access, "
"access, please take appropriate measures immediately." "please take appropriate measures immediately."
msgstr "" msgstr ""
"ユーザーは資産に正常にログインしたばかりです。許可されたアクションであること" "ユーザーは資産にログインしています。許可されたアクションであることを確認して"
"を確認してください。不正アクセスが疑われる場合は、すぐに適切な措置を取ってく" "ください。不正アクセスが疑われる場合は、すぐに適切な措置を取ってください。"
"ださい。"
#: acls/templates/acls/asset_login_reminder.html:11 #: acls/templates/acls/asset_login_reminder.html:12
#: acls/templates/acls/user_login_reminder.html:13 #: acls/templates/acls/user_login_reminder.html:13
msgid "Thank you" msgid "Thank you"
msgstr "ありがとうございます。" msgstr "ありがとうございます。"
@ -1227,7 +1228,7 @@ msgstr "アプリケーション"
msgid "Can match application" msgid "Can match application"
msgstr "アプリケーションを一致させることができます" msgstr "アプリケーションを一致させることができます"
#: assets/api/asset/asset.py:157 #: assets/api/asset/asset.py:194
msgid "Cannot create asset directly, you should create a host or other" msgid "Cannot create asset directly, you should create a host or other"
msgstr "" msgstr ""
"資産を直接作成することはできません。ホストまたはその他を作成する必要がありま" "資産を直接作成することはできません。ホストまたはその他を作成する必要がありま"
@ -1646,7 +1647,7 @@ msgstr "ドメイン"
msgid "Labels" msgid "Labels"
msgstr "ラベル" msgstr "ラベル"
#: assets/models/asset/common.py:158 assets/serializers/asset/common.py:312 #: assets/models/asset/common.py:158 assets/serializers/asset/common.py:339
#: assets/serializers/asset/host.py:11 #: assets/serializers/asset/host.py:11
msgid "Gathered info" msgid "Gathered info"
msgstr "資産ハードウェア情報の収集" msgstr "資産ハードウェア情報の収集"
@ -1983,7 +1984,7 @@ msgid "Node path"
msgstr "ノードパスです" msgstr "ノードパスです"
#: assets/serializers/asset/common.py:145 #: assets/serializers/asset/common.py:145
#: assets/serializers/asset/common.py:313 #: assets/serializers/asset/common.py:340
msgid "Auto info" msgid "Auto info"
msgstr "自動情報" msgstr "自動情報"
@ -1999,19 +2000,10 @@ msgstr "ポート番号が範囲外です (0-65535)"
msgid "Protocol is required: {}" msgid "Protocol is required: {}"
msgstr "プロトコルが必要です: {}" msgstr "プロトコルが必要です: {}"
#: assets/serializers/asset/database.py:13 #: assets/serializers/asset/database.py:12
msgid "Default database" msgid "Default database"
msgstr "デフォルト・データベース" msgstr "デフォルト・データベース"
#: assets/serializers/asset/database.py:28 common/db/fields.py:570
#: common/db/fields.py:575 common/serializers/fields.py:104
#: tickets/serializers/ticket/common.py:58
#: xpack/plugins/cloud/serializers/account_attrs.py:56
#: xpack/plugins/cloud/serializers/account_attrs.py:79
#: xpack/plugins/cloud/serializers/account_attrs.py:143
msgid "This field is required."
msgstr "このフィールドは必須です。"
#: assets/serializers/asset/gpt.py:20 #: assets/serializers/asset/gpt.py:20
msgid "" msgid ""
"If the server cannot directly connect to the API address, you need set up an " "If the server cannot directly connect to the API address, you need set up an "
@ -2539,33 +2531,33 @@ msgstr "外部ストレージへのFTPファイルのアップロード"
msgid "Access keys can be created at most 10" msgid "Access keys can be created at most 10"
msgstr "" msgstr ""
#: authentication/api/confirm.py:40 #: authentication/api/confirm.py:41
msgid "This action require verify your MFA" msgid "This action require verify your MFA"
msgstr "この操作には、MFAを検証する必要があります" msgstr "この操作には、MFAを検証する必要があります"
#: authentication/api/connection_token.py:261 #: authentication/api/connection_token.py:262
msgid "Reusable connection token is not allowed, global setting not enabled" msgid "Reusable connection token is not allowed, global setting not enabled"
msgstr "" msgstr ""
"再使用可能な接続トークンの使用は許可されていません。グローバル設定は有効に" "再使用可能な接続トークンの使用は許可されていません。グローバル設定は有効に"
"なっていません" "なっていません"
#: authentication/api/connection_token.py:357 #: authentication/api/connection_token.py:358
msgid "Anonymous account is not supported for this asset" msgid "Anonymous account is not supported for this asset"
msgstr "匿名アカウントはこのプロパティではサポートされていません" msgstr "匿名アカウントはこのプロパティではサポートされていません"
#: authentication/api/connection_token.py:376 #: authentication/api/connection_token.py:378
msgid "Account not found" msgid "Account not found"
msgstr "アカウントが見つかりません" msgstr "アカウントが見つかりません"
#: authentication/api/connection_token.py:379 #: authentication/api/connection_token.py:381
msgid "Permission expired" msgid "Permission expired"
msgstr "承認の有効期限が切れています" msgstr "承認の有効期限が切れています"
#: authentication/api/connection_token.py:406 #: authentication/api/connection_token.py:412
msgid "ACL action is reject: {}({})" msgid "ACL action is reject: {}({})"
msgstr "ACL アクションは拒否です: {}({})" msgstr "ACL アクションは拒否です: {}({})"
#: authentication/api/connection_token.py:410 #: authentication/api/connection_token.py:416
msgid "ACL action is review" msgid "ACL action is review"
msgstr "ACL アクションはレビューです" msgstr "ACL アクションはレビューです"
@ -2815,15 +2807,15 @@ msgstr "パスワードが無効です"
msgid "Please wait for %s seconds before retry" msgid "Please wait for %s seconds before retry"
msgstr "%s 秒後に再試行してください" msgstr "%s 秒後に再試行してください"
#: authentication/errors/redirect.py:85 authentication/mixins.py:324 #: authentication/errors/redirect.py:85 authentication/mixins.py:323
msgid "Your password is too simple, please change it for security" msgid "Your password is too simple, please change it for security"
msgstr "パスワードがシンプルすぎるので、セキュリティのために変更してください" msgstr "パスワードがシンプルすぎるので、セキュリティのために変更してください"
#: authentication/errors/redirect.py:93 authentication/mixins.py:331 #: authentication/errors/redirect.py:93 authentication/mixins.py:330
msgid "You should to change your password before login" msgid "You should to change your password before login"
msgstr "ログインする前にパスワードを変更する必要があります" msgstr "ログインする前にパスワードを変更する必要があります"
#: authentication/errors/redirect.py:101 authentication/mixins.py:338 #: authentication/errors/redirect.py:101 authentication/mixins.py:337
msgid "Your password has expired, please reset before logging in" msgid "Your password has expired, please reset before logging in"
msgstr "" msgstr ""
"パスワードの有効期限が切れました。ログインする前にリセットしてください。" "パスワードの有効期限が切れました。ログインする前にリセットしてください。"
@ -2938,11 +2930,11 @@ msgstr ""
"管理者は「ユーザーソースからのみログインを許可」をオンにしており、現在のユー" "管理者は「ユーザーソースからのみログインを許可」をオンにしており、現在のユー"
"ザーソースは {} です。管理者に連絡してください。" "ザーソースは {} です。管理者に連絡してください。"
#: authentication/mixins.py:274 #: authentication/mixins.py:273
msgid "The MFA type ({}) is not enabled" msgid "The MFA type ({}) is not enabled"
msgstr "MFAタイプ ({}) が有効になっていない" msgstr "MFAタイプ ({}) が有効になっていない"
#: authentication/mixins.py:314 #: authentication/mixins.py:313
msgid "Please change your password" msgid "Please change your password"
msgstr "パスワードを変更してください" msgstr "パスワードを変更してください"
@ -3577,6 +3569,14 @@ msgstr "無効なタイプです。all、ids、またはattrsでなければな
msgid "Invalid ids for ids, should be a list" msgid "Invalid ids for ids, should be a list"
msgstr "無効なID、リストでなければなりません" msgstr "無効なID、リストでなければなりません"
#: common/db/fields.py:570 common/db/fields.py:575
#: common/serializers/fields.py:104 tickets/serializers/ticket/common.py:58
#: xpack/plugins/cloud/serializers/account_attrs.py:56
#: xpack/plugins/cloud/serializers/account_attrs.py:79
#: xpack/plugins/cloud/serializers/account_attrs.py:143
msgid "This field is required."
msgstr "このフィールドは必須です。"
#: common/db/fields.py:573 common/db/fields.py:578 #: common/db/fields.py:573 common/db/fields.py:578
msgid "Invalid attrs, should be a list of dict" msgid "Invalid attrs, should be a list of dict"
msgstr "無効な属性、dictリストでなければなりません" msgstr "無効な属性、dictリストでなければなりません"
@ -8145,12 +8145,14 @@ msgid "Task strategy"
msgstr "ミッション戦略です" msgstr "ミッション戦略です"
#: xpack/plugins/cloud/models.py:285 #: xpack/plugins/cloud/models.py:285
msgid "Equal" msgid "Exact"
msgstr "等しい" msgstr ""
#: xpack/plugins/cloud/models.py:286 #: xpack/plugins/cloud/models.py:286
msgid "Not equal" #, fuzzy
msgstr "不等于" #| msgid "No"
msgid "Not"
msgstr "否"
#: xpack/plugins/cloud/models.py:287 #: xpack/plugins/cloud/models.py:287
msgid "In" msgid "In"
@ -8581,3 +8583,9 @@ msgstr "エンタープライズプロフェッショナル版"
#: xpack/plugins/license/models.py:86 #: xpack/plugins/license/models.py:86
msgid "Ultimate edition" msgid "Ultimate edition"
msgstr "エンタープライズ・フラッグシップ・エディション" msgstr "エンタープライズ・フラッグシップ・エディション"
#~ msgid "Equal"
#~ msgstr "等しい"
#~ msgid "Not equal"
#~ msgstr "不等于"

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:25c1d449875189c84c0d586792424d70651a1f86f55b93332287dfef44db2f2f oid sha256:4be95c6d05beb08730dd3cee943e7f84aa94e8e711a41e2fce5b0aebf84e831b
size 132289 size 133014

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n" "Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-10-12 09:51+0800\n" "POT-Creation-Date: 2023-10-13 15:03+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n" "Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -262,10 +262,12 @@ msgstr "来源 ID"
#: accounts/models/account.py:60 #: accounts/models/account.py:60
#: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:112
#: accounts/serializers/automations/change_secret.py:132 #: accounts/serializers/automations/change_secret.py:132
#: acls/serializers/base.py:124 assets/serializers/asset/common.py:125 #: acls/serializers/base.py:124 acls/templates/acls/asset_login_reminder.html:7
#: assets/serializers/gateway.py:28 audits/models.py:57 ops/models/base.py:18 #: assets/serializers/asset/common.py:125 assets/serializers/gateway.py:28
#: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: audits/models.py:57 authentication/api/connection_token.py:391
#: terminal/backends/command/models.py:18 terminal/models/session/session.py:33 #: ops/models/base.py:18 perms/models/asset_permission.py:70
#: perms/serializers/permission.py:39 terminal/backends/command/models.py:18
#: terminal/models/session/session.py:33
#: terminal/templates/terminal/_msg_command_warning.html:8 #: terminal/templates/terminal/_msg_command_warning.html:8
#: terminal/templates/terminal/_msg_session_sharing.html:8 #: terminal/templates/terminal/_msg_session_sharing.html:8
#: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:89 #: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:89
@ -710,7 +712,7 @@ msgstr "已修改"
#: acls/templates/acls/asset_login_reminder.html:6 #: acls/templates/acls/asset_login_reminder.html:6
#: assets/models/automations/base.py:19 #: assets/models/automations/base.py:19
#: assets/serializers/automations/base.py:20 #: assets/serializers/automations/base.py:20
#: authentication/api/connection_token.py:386 ops/models/base.py:17 #: authentication/api/connection_token.py:390 ops/models/base.py:17
#: ops/models/job.py:139 ops/serializers/job.py:21 #: ops/models/job.py:139 ops/serializers/job.py:21
#: terminal/templates/terminal/_msg_command_execute_alert.html:16 #: terminal/templates/terminal/_msg_command_execute_alert.html:16
msgid "Assets" msgid "Assets"
@ -787,7 +789,7 @@ msgid "Key password"
msgstr "密钥密码" msgstr "密钥密码"
#: accounts/serializers/account/base.py:78 #: accounts/serializers/account/base.py:78
#: assets/serializers/asset/common.py:311 #: assets/serializers/asset/common.py:338
msgid "Spec info" msgid "Spec info"
msgstr "特殊信息" msgstr "特殊信息"
@ -1021,7 +1023,7 @@ msgid "Users"
msgstr "用户管理" msgstr "用户管理"
#: acls/models/base.py:98 assets/models/automations/base.py:17 #: acls/models/base.py:98 assets/models/automations/base.py:17
#: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:310 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:337
#: rbac/tree.py:35 #: rbac/tree.py:35
msgid "Accounts" msgid "Accounts"
msgstr "账号管理" msgstr "账号管理"
@ -1169,16 +1171,16 @@ msgstr "时段"
msgid "Respectful" msgid "Respectful"
msgstr "尊敬的" msgstr "尊敬的"
#: acls/templates/acls/asset_login_reminder.html:9 #: acls/templates/acls/asset_login_reminder.html:10
msgid "" msgid ""
"The user has just successfully logged into the asset. Please ensure that " "The user has just logged in to the asset. Please ensure that this is an "
"this is an authorized operation. If you suspect that this is an unauthorized " "authorized operation. If you suspect that this is an unauthorized access, "
"access, please take appropriate measures immediately." "please take appropriate measures immediately."
msgstr "" msgstr ""
"用户刚刚成功登录到资产。请确保这是授权的操作。如果您怀疑这是一个未经授权的访" "用户刚刚在登录资产。请确保这是授权的操作。如果您怀疑这是一个未经授权的访问,"
"问,请立即采取适当的措施。" "请立即采取适当的措施。"
#: acls/templates/acls/asset_login_reminder.html:11 #: acls/templates/acls/asset_login_reminder.html:12
#: acls/templates/acls/user_login_reminder.html:13 #: acls/templates/acls/user_login_reminder.html:13
msgid "Thank you" msgid "Thank you"
msgstr "谢谢" msgstr "谢谢"
@ -1221,7 +1223,7 @@ msgstr "应用程序"
msgid "Can match application" msgid "Can match application"
msgstr "匹配应用" msgstr "匹配应用"
#: assets/api/asset/asset.py:157 #: assets/api/asset/asset.py:194
msgid "Cannot create asset directly, you should create a host or other" msgid "Cannot create asset directly, you should create a host or other"
msgstr "不能直接创建资产, 你应该创建主机或其他资产" msgstr "不能直接创建资产, 你应该创建主机或其他资产"
@ -1638,7 +1640,7 @@ msgstr "网域"
msgid "Labels" msgid "Labels"
msgstr "标签管理" msgstr "标签管理"
#: assets/models/asset/common.py:158 assets/serializers/asset/common.py:312 #: assets/models/asset/common.py:158 assets/serializers/asset/common.py:339
#: assets/serializers/asset/host.py:11 #: assets/serializers/asset/host.py:11
msgid "Gathered info" msgid "Gathered info"
msgstr "收集资产硬件信息" msgstr "收集资产硬件信息"
@ -1973,7 +1975,7 @@ msgid "Node path"
msgstr "节点路径" msgstr "节点路径"
#: assets/serializers/asset/common.py:145 #: assets/serializers/asset/common.py:145
#: assets/serializers/asset/common.py:313 #: assets/serializers/asset/common.py:340
msgid "Auto info" msgid "Auto info"
msgstr "自动化信息" msgstr "自动化信息"
@ -1989,19 +1991,10 @@ msgstr "端口超出范围 (0-65535)"
msgid "Protocol is required: {}" msgid "Protocol is required: {}"
msgstr "协议是必填的: {}" msgstr "协议是必填的: {}"
#: assets/serializers/asset/database.py:13 #: assets/serializers/asset/database.py:12
msgid "Default database" msgid "Default database"
msgstr "默认数据库" msgstr "默认数据库"
#: assets/serializers/asset/database.py:28 common/db/fields.py:570
#: common/db/fields.py:575 common/serializers/fields.py:104
#: tickets/serializers/ticket/common.py:58
#: xpack/plugins/cloud/serializers/account_attrs.py:56
#: xpack/plugins/cloud/serializers/account_attrs.py:79
#: xpack/plugins/cloud/serializers/account_attrs.py:143
msgid "This field is required."
msgstr "该字段是必填项。"
#: assets/serializers/asset/gpt.py:20 #: assets/serializers/asset/gpt.py:20
msgid "" msgid ""
"If the server cannot directly connect to the API address, you need set up an " "If the server cannot directly connect to the API address, you need set up an "
@ -2522,31 +2515,31 @@ msgstr "上传 FTP 文件到外部存储"
msgid "Access keys can be created at most 10" msgid "Access keys can be created at most 10"
msgstr "" msgstr ""
#: authentication/api/confirm.py:40 #: authentication/api/confirm.py:41
msgid "This action require verify your MFA" msgid "This action require verify your MFA"
msgstr "该操作需要验证您的 MFA, 请先开启并配置" msgstr "该操作需要验证您的 MFA, 请先开启并配置"
#: authentication/api/connection_token.py:261 #: authentication/api/connection_token.py:262
msgid "Reusable connection token is not allowed, global setting not enabled" msgid "Reusable connection token is not allowed, global setting not enabled"
msgstr "不允许使用可重复使用的连接令牌,未启用全局设置" msgstr "不允许使用可重复使用的连接令牌,未启用全局设置"
#: authentication/api/connection_token.py:357 #: authentication/api/connection_token.py:358
msgid "Anonymous account is not supported for this asset" msgid "Anonymous account is not supported for this asset"
msgstr "匿名账号不支持当前资产" msgstr "匿名账号不支持当前资产"
#: authentication/api/connection_token.py:376 #: authentication/api/connection_token.py:378
msgid "Account not found" msgid "Account not found"
msgstr "账号未找到" msgstr "账号未找到"
#: authentication/api/connection_token.py:379 #: authentication/api/connection_token.py:381
msgid "Permission expired" msgid "Permission expired"
msgstr "授权已过期" msgstr "授权已过期"
#: authentication/api/connection_token.py:406 #: authentication/api/connection_token.py:412
msgid "ACL action is reject: {}({})" msgid "ACL action is reject: {}({})"
msgstr "ACL 动作是拒绝: {}({})" msgstr "ACL 动作是拒绝: {}({})"
#: authentication/api/connection_token.py:410 #: authentication/api/connection_token.py:416
msgid "ACL action is review" msgid "ACL action is review"
msgstr "ACL 动作是复核" msgstr "ACL 动作是复核"
@ -2787,15 +2780,15 @@ msgstr "您的密码无效"
msgid "Please wait for %s seconds before retry" msgid "Please wait for %s seconds before retry"
msgstr "请在 %s 秒后重试" msgstr "请在 %s 秒后重试"
#: authentication/errors/redirect.py:85 authentication/mixins.py:324 #: authentication/errors/redirect.py:85 authentication/mixins.py:323
msgid "Your password is too simple, please change it for security" msgid "Your password is too simple, please change it for security"
msgstr "你的密码过于简单,为了安全,请修改" msgstr "你的密码过于简单,为了安全,请修改"
#: authentication/errors/redirect.py:93 authentication/mixins.py:331 #: authentication/errors/redirect.py:93 authentication/mixins.py:330
msgid "You should to change your password before login" msgid "You should to change your password before login"
msgstr "登录完成前,请先修改密码" msgstr "登录完成前,请先修改密码"
#: authentication/errors/redirect.py:101 authentication/mixins.py:338 #: authentication/errors/redirect.py:101 authentication/mixins.py:337
msgid "Your password has expired, please reset before logging in" msgid "Your password has expired, please reset before logging in"
msgstr "您的密码已过期,先修改再登录" msgstr "您的密码已过期,先修改再登录"
@ -2906,11 +2899,11 @@ msgid ""
" The current user source is {}. Please contact the administrator." " The current user source is {}. Please contact the administrator."
msgstr "管理员已开启'仅允许从用户来源登录',当前用户来源为{},请联系管理员。" msgstr "管理员已开启'仅允许从用户来源登录',当前用户来源为{},请联系管理员。"
#: authentication/mixins.py:274 #: authentication/mixins.py:273
msgid "The MFA type ({}) is not enabled" msgid "The MFA type ({}) is not enabled"
msgstr "该 MFA ({}) 方式没有启用" msgstr "该 MFA ({}) 方式没有启用"
#: authentication/mixins.py:314 #: authentication/mixins.py:313
msgid "Please change your password" msgid "Please change your password"
msgstr "请修改密码" msgstr "请修改密码"
@ -3533,6 +3526,14 @@ msgstr "无效类型,应为 all、ids 或 attrs"
msgid "Invalid ids for ids, should be a list" msgid "Invalid ids for ids, should be a list"
msgstr "无效的ID应为列表" msgstr "无效的ID应为列表"
#: common/db/fields.py:570 common/db/fields.py:575
#: common/serializers/fields.py:104 tickets/serializers/ticket/common.py:58
#: xpack/plugins/cloud/serializers/account_attrs.py:56
#: xpack/plugins/cloud/serializers/account_attrs.py:79
#: xpack/plugins/cloud/serializers/account_attrs.py:143
msgid "This field is required."
msgstr "该字段是必填项。"
#: common/db/fields.py:573 common/db/fields.py:578 #: common/db/fields.py:573 common/db/fields.py:578
msgid "Invalid attrs, should be a list of dict" msgid "Invalid attrs, should be a list of dict"
msgstr "无效的属性应为dict列表" msgstr "无效的属性应为dict列表"
@ -8029,12 +8030,14 @@ msgid "Task strategy"
msgstr "任务策略" msgstr "任务策略"
#: xpack/plugins/cloud/models.py:285 #: xpack/plugins/cloud/models.py:285
msgid "Equal" msgid "Exact"
msgstr "等于" msgstr ""
#: xpack/plugins/cloud/models.py:286 #: xpack/plugins/cloud/models.py:286
msgid "Not equal" #, fuzzy
msgstr "不等于" #| msgid "No"
msgid "Not"
msgstr "否"
#: xpack/plugins/cloud/models.py:287 #: xpack/plugins/cloud/models.py:287
msgid "In" msgid "In"
@ -8462,3 +8465,9 @@ msgstr "企业专业版"
#: xpack/plugins/license/models.py:86 #: xpack/plugins/license/models.py:86
msgid "Ultimate edition" msgid "Ultimate edition"
msgstr "企业旗舰版" msgstr "企业旗舰版"
#~ msgid "Equal"
#~ msgstr "等于"
#~ msgid "Not equal"
#~ msgstr "不等于"

View File

@ -293,8 +293,8 @@ class ServiceAccountSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
from authentication.serializers import AccessKeySerializer from authentication.serializers import AccessKeyCreateSerializer
self.fields["access_key"] = AccessKeySerializer(read_only=True) self.fields["access_key"] = AccessKeyCreateSerializer(read_only=True)
def get_username(self): def get_username(self):
return self.initial_data.get("name") return self.initial_data.get("name")