Merge pull request #11452 from jumpserver/pr@dev@feat_audit_view_download_replay

feat: 查看/下载录像记录在操作及活动日志中
pull/11468/head
老广 2023-08-30 13:48:53 +08:00 committed by GitHub
commit 894249a3d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 267 additions and 199 deletions

View File

@ -7,10 +7,10 @@ from rest_framework.status import HTTP_200_OK
from accounts import serializers
from accounts.filters import AccountFilterSet
from accounts.models import Account
from accounts.mixins import AccountRecordViewLogMixin
from assets.models import Asset, Node
from common.api.mixin import ExtraFilterFieldsMixin
from common.permissions import UserConfirmation, ConfirmType, IsValidUser
from common.views.mixins import RecordViewLogMixin
from orgs.mixins.api import OrgBulkModelViewSet
from rbac.permissions import RBACPermission
@ -86,7 +86,7 @@ class AccountViewSet(OrgBulkModelViewSet):
return Response(status=HTTP_200_OK)
class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet):
class AccountSecretsViewSet(AccountRecordViewLogMixin, AccountViewSet):
"""
因为可能要导出所有账号所以单独建立了一个 viewset
"""
@ -115,7 +115,7 @@ class AssetAccountBulkCreateApi(CreateAPIView):
return Response(data=serializer.data, status=HTTP_200_OK)
class AccountHistoriesSecretAPI(ExtraFilterFieldsMixin, RecordViewLogMixin, ListAPIView):
class AccountHistoriesSecretAPI(ExtraFilterFieldsMixin, AccountRecordViewLogMixin, ListAPIView):
model = Account.history.model
serializer_class = serializers.AccountHistorySerializer
http_method_names = ['get', 'options']

View File

@ -4,10 +4,10 @@ from rest_framework.response import Response
from accounts import serializers
from accounts.models import AccountTemplate
from accounts.mixins import AccountRecordViewLogMixin
from assets.const import Protocol
from common.drf.filters import BaseFilterSet
from common.permissions import UserConfirmation, ConfirmType
from common.views.mixins import RecordViewLogMixin
from orgs.mixins.api import OrgBulkModelViewSet
from rbac.permissions import RBACPermission
@ -55,7 +55,7 @@ class AccountTemplateViewSet(OrgBulkModelViewSet):
return Response(data=serializer.data)
class AccountTemplateSecretsViewSet(RecordViewLogMixin, AccountTemplateViewSet):
class AccountTemplateSecretsViewSet(AccountRecordViewLogMixin, AccountTemplateViewSet):
serializer_classes = {
'default': serializers.AccountTemplateSecretSerializer,
}

75
apps/accounts/mixins.py Normal file
View File

@ -0,0 +1,75 @@
from rest_framework.response import Response
from rest_framework import status
from django.utils import translation
from django.utils.translation import gettext_noop
from audits.const import ActionChoices
from common.views.mixins import RecordViewLogMixin
from common.utils import i18n_fmt
class AccountRecordViewLogMixin(RecordViewLogMixin):
get_object: callable
get_queryset: callable
@staticmethod
def _filter_params(params):
new_params = {}
need_pop_params = ('format', 'order')
for key, value in params.items():
if key in need_pop_params:
continue
if isinstance(value, list):
value = list(filter(None, value))
if value:
new_params[key] = value
return new_params
def get_resource_display(self, request):
query_params = dict(request.query_params)
params = self._filter_params(query_params)
spm_filter = params.pop("spm", None)
if not params and not spm_filter:
display_message = gettext_noop("Export all")
elif spm_filter:
display_message = gettext_noop("Export only selected items")
else:
query = ",".join(
["%s=%s" % (key, value) for key, value in params.items()]
)
display_message = i18n_fmt(gettext_noop("Export filtered: %s"), query)
return display_message
@property
def detail_msg(self):
return i18n_fmt(
gettext_noop('User %s view/export secret'), self.request.user
)
def list(self, request, *args, **kwargs):
list_func = getattr(super(), 'list')
if not callable(list_func):
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
response = list_func(request, *args, **kwargs)
with translation.override('en'):
resource_display = self.get_resource_display(request)
ids = [q.id for q in self.get_queryset()]
self.record_logs(
ids, ActionChoices.view, self.detail_msg, resource_display=resource_display
)
return response
def retrieve(self, request, *args, **kwargs):
retrieve_func = getattr(super(), 'retrieve')
if not callable(retrieve_func):
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
response = retrieve_func(request, *args, **kwargs)
with translation.override('en'):
resource = self.get_object()
self.record_logs(
[resource.id], ActionChoices.view, self.detail_msg, resource=resource
)
return response

View File

@ -25,6 +25,7 @@ class ActionChoices(TextChoices):
delete = "delete", _("Delete")
create = "create", _("Create")
# Activities action
download = "download", _("Download")
connect = "connect", _("Connect")
login = "login", _("Login")
change_auth = "change_password", _("Change password")

View File

@ -88,6 +88,7 @@ class AsyncApiMixin(InterceptMixin):
if not self.is_need_async():
return handler(*args, **kwargs)
resp = self.do_async(handler, *args, **kwargs)
self.async_callback(*args, **kwargs)
return resp
def is_need_refresh(self):
@ -98,6 +99,9 @@ class AsyncApiMixin(InterceptMixin):
def is_need_async(self):
return False
def async_callback(self, *args, **kwargs):
pass
def do_async(self, handler, *args, **kwargs):
data = self.get_cache_data()
if not data:

View File

@ -2,16 +2,15 @@
#
from django.contrib.auth.mixins import UserPassesTestMixin
from django.http.response import JsonResponse
from django.db.models import Model
from django.utils import translation
from django.utils.translation import gettext_noop
from rest_framework import permissions
from rest_framework.request import Request
from audits.const import ActionChoices, ActivityChoices
from audits.const import ActivityChoices
from audits.handler import create_or_update_operate_log
from audits.models import ActivityLog
from common.exceptions import UserConfirmRequired
from common.utils import i18n_fmt
from orgs.utils import current_org
__all__ = [
@ -49,66 +48,20 @@ class PermissionsMixin(UserPassesTestMixin):
class RecordViewLogMixin:
ACTION = ActionChoices.view
model: Model
@staticmethod
def _filter_params(params):
new_params = {}
need_pop_params = ('format', 'order')
for key, value in params.items():
if key in need_pop_params:
continue
if isinstance(value, list):
value = list(filter(None, value))
if value:
new_params[key] = value
return new_params
def get_resource_display(self, request):
query_params = dict(request.query_params)
params = self._filter_params(query_params)
spm_filter = params.pop("spm", None)
if not params and not spm_filter:
display_message = gettext_noop("Export all")
elif spm_filter:
display_message = gettext_noop("Export only selected items")
else:
query = ",".join(
["%s=%s" % (key, value) for key, value in params.items()]
)
display_message = i18n_fmt(gettext_noop("Export filtered: %s"), query)
return display_message
def record_logs(self, ids, **kwargs):
resource_type = self.model._meta.verbose_name
create_or_update_operate_log(
self.ACTION, resource_type, force=True, **kwargs
)
detail = i18n_fmt(
gettext_noop('User %s view/export secret'), self.request.user
)
activities = [
ActivityLog(
resource_id=getattr(resource_id, 'pk', resource_id),
type=ActivityChoices.operate_log, detail=detail, org_id=current_org.id,
)
for resource_id in ids
]
ActivityLog.objects.bulk_create(activities)
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
def record_logs(self, ids, action, detail, model=None, **kwargs):
with translation.override('en'):
resource_display = self.get_resource_display(request)
ids = [q.id for q in self.get_queryset()]
self.record_logs(ids, resource_display=resource_display)
return response
def retrieve(self, request, *args, **kwargs):
response = super().retrieve(request, *args, **kwargs)
with translation.override('en'):
resource = self.get_object()
self.record_logs([resource.id], resource=resource)
return response
model = model or self.model
resource_type = model._meta.verbose_name
create_or_update_operate_log(
action, resource_type, force=True, **kwargs
)
activities = [
ActivityLog(
resource_id=resource_id, type=ActivityChoices.operate_log,
detail=detail, org_id=current_org.id,
)
for resource_id in ids
]
ActivityLog.objects.bulk_create(activities)

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-08-28 10:55+0800\n"
"POT-Creation-Date: 2023-08-29 15:14+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -93,7 +93,7 @@ msgid "Update"
msgstr "更新"
#: accounts/const/account.py:33
#: accounts/serializers/automations/change_secret.py:156 audits/const.py:54
#: accounts/serializers/automations/change_secret.py:156 audits/const.py:55
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
#: ops/const.py:61 terminal/const.py:77 xpack/plugins/cloud/const.py:43
msgid "Failed"
@ -227,7 +227,7 @@ msgstr "から切り替え"
#: accounts/models/account.py:54 assets/const/protocol.py:162
#: settings/serializers/auth/cas.py:20 settings/serializers/auth/feishu.py:20
#: terminal/models/applet/applet.py:34
#: terminal/models/applet/applet.py:35
msgid "Version"
msgstr "バージョン"
@ -331,56 +331,56 @@ msgstr "成功は"
msgid "Account backup execution"
msgstr "アカウントバックアップの実行"
#: accounts/models/automations/base.py:20
#: accounts/models/automations/base.py:19
msgid "Account automation task"
msgstr "アカウント自動化タスク"
#: accounts/models/automations/base.py:34
#: accounts/models/automations/base.py:33
msgid "Automation execution"
msgstr "自動実行"
#: accounts/models/automations/base.py:35
#: accounts/models/automations/base.py:34
msgid "Automation executions"
msgstr "自動実行"
#: accounts/models/automations/base.py:37
#: accounts/models/automations/base.py:36
msgid "Can view change secret execution"
msgstr "改密実行の表示"
#: accounts/models/automations/base.py:38
#: accounts/models/automations/base.py:37
msgid "Can add change secret execution"
msgstr "改密実行の作成"
#: accounts/models/automations/base.py:40
#: accounts/models/automations/base.py:39
msgid "Can view gather accounts execution"
msgstr "コレクションアカウントの実行を表示"
#: accounts/models/automations/base.py:41
#: accounts/models/automations/base.py:40
msgid "Can add gather accounts execution"
msgstr "回収口座作成の実行"
#: accounts/models/automations/base.py:43
#: accounts/models/automations/base.py:42
msgid "Can view push account execution"
msgstr "プッシュ アカウントの実行を表示する"
#: accounts/models/automations/base.py:44
#: accounts/models/automations/base.py:43
msgid "Can add push account execution"
msgstr "プッシュ アカウントの作成の実行"
#: accounts/models/automations/base.py:56 accounts/models/template.py:21
#: accounts/models/automations/base.py:55 accounts/models/template.py:21
#: accounts/serializers/automations/change_secret.py:40
msgid "Secret strategy"
msgstr "鍵ポリシー"
#: accounts/models/automations/base.py:58
#: accounts/models/automations/base.py:57
msgid "Password rules"
msgstr "パスワードルール"
#: accounts/models/automations/base.py:61
#: accounts/models/automations/base.py:60
msgid "SSH key change strategy"
msgstr "SSHキープッシュ方式"
#: accounts/models/automations/base.py:71 accounts/models/base.py:36
#: accounts/models/automations/base.py:70 accounts/models/base.py:36
#: accounts/serializers/account/account.py:429
#: accounts/serializers/account/base.py:16
#: accounts/serializers/automations/change_secret.py:46
@ -389,7 +389,7 @@ msgstr "SSHキープッシュ方式"
msgid "Secret type"
msgstr "鍵の種類"
#: accounts/models/automations/base.py:73 accounts/models/mixins/vault.py:48
#: accounts/models/automations/base.py:72 accounts/models/mixins/vault.py:48
#: accounts/serializers/account/base.py:19
#: authentication/models/temp_token.py:10
#: authentication/templates/authentication/_access_key_modal.html:31
@ -510,7 +510,7 @@ msgstr "アカウントの確認"
#: ops/models/job.py:126 ops/models/playbook.py:28 ops/serializers/job.py:20
#: orgs/models.py:82 perms/models/asset_permission.py:56 rbac/models/role.py:29
#: settings/models.py:32 settings/serializers/msg.py:82
#: terminal/models/applet/applet.py:32 terminal/models/component/endpoint.py:12
#: terminal/models/applet/applet.py:33 terminal/models/component/endpoint.py:12
#: terminal/models/component/endpoint.py:94
#: terminal/models/component/storage.py:26 terminal/models/component/task.py:13
#: terminal/models/component/terminal.py:84 users/forms/profile.py:33
@ -528,7 +528,7 @@ msgstr "特権アカウント"
#: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39
#: assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:114
#: terminal/models/applet/applet.py:39
#: terminal/models/applet/applet.py:40
#: terminal/models/component/endpoint.py:105 users/serializers/user.py:170
msgid "Is active"
msgstr "アクティブです。"
@ -652,7 +652,7 @@ msgstr "カテゴリ"
#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:112
#: assets/serializers/platform.py:127 audits/serializers.py:49
#: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:137
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:39
#: terminal/models/component/storage.py:57
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29
#: terminal/serializers/session.py:21 terminal/serializers/storage.py:226
@ -792,8 +792,8 @@ msgstr "关联平台,可以配置推送参数,如果不关联,则使用默
#: assets/models/cmd_filter.py:40 assets/models/cmd_filter.py:88
#: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26
#: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:37 terminal/models/applet/applet.py:44
#: terminal/models/applet/applet.py:284 terminal/models/applet/host.py:142
#: settings/models.py:37 terminal/models/applet/applet.py:45
#: terminal/models/applet/applet.py:302 terminal/models/applet/host.py:142
#: terminal/models/component/endpoint.py:24
#: terminal/models/component/endpoint.py:104
#: terminal/models/session/session.py:46 tickets/models/comment.py:32
@ -844,7 +844,7 @@ msgstr "* パスワードの長さの範囲6-30ビット"
msgid "Automation task execution"
msgstr "自動タスク実行履歴"
#: accounts/serializers/automations/change_secret.py:155 audits/const.py:53
#: accounts/serializers/automations/change_secret.py:155 audits/const.py:54
#: audits/models.py:59 audits/signal_handlers/activity_log.py:33
#: common/const/choices.py:18 ops/const.py:59 ops/serializers/celery.py:40
#: terminal/const.py:76 terminal/models/session/sharing.py:121
@ -852,7 +852,8 @@ msgstr "自動タスク実行履歴"
msgid "Success"
msgstr "成功"
#: accounts/signal_handlers.py:47
#: accounts/signal_handlers.py:46
#, python-format
msgid "Push related accounts to assets: %s, by system"
msgstr "関連するアカウントをアセットにプッシュ: %s, by system"
@ -1166,7 +1167,7 @@ msgstr "認証に失敗しました"
msgid "Connect failed"
msgstr "接続に失敗しました"
#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:36
#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:37
#: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31
#: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104
msgid "Unknown"
@ -1188,7 +1189,7 @@ msgstr "テストゲートウェイ"
msgid "Gather facts"
msgstr "資産情報の収集"
#: assets/const/base.py:33 audits/const.py:47
#: assets/const/base.py:33 audits/const.py:48
#: terminal/serializers/applet_host.py:32
msgid "Disabled"
msgstr "無効"
@ -1219,8 +1220,8 @@ msgid "Cloud service"
msgstr "クラウド サービス"
#: assets/const/category.py:14 assets/models/asset/gpt.py:11
#: assets/models/asset/web.py:16 audits/const.py:34
#: terminal/models/applet/applet.py:26
#: assets/models/asset/web.py:16 audits/const.py:35
#: terminal/models/applet/applet.py:27
msgid "Web"
msgstr "Web"
@ -1240,7 +1241,7 @@ msgstr "私有雲"
msgid "Kubernetes"
msgstr "Kubernetes"
#: assets/const/device.py:7 terminal/models/applet/applet.py:25
#: assets/const/device.py:7 terminal/models/applet/applet.py:26
#: tickets/const.py:8
msgid "General"
msgstr "一般"
@ -1433,7 +1434,7 @@ msgstr "ユーザーと同じユーザー名"
#: assets/models/_user.py:52 authentication/models/connection_token.py:41
#: authentication/serializers/connect_token_secret.py:111
#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:19
#: terminal/models/applet/applet.py:42 terminal/serializers/session.py:19
#: terminal/serializers/session.py:42 terminal/serializers/storage.py:70
msgid "Protocol"
msgstr "プロトコル"
@ -1572,7 +1573,7 @@ msgstr "アセットの自動化タスク"
#: assets/models/automations/base.py:113 audits/models.py:199
#: audits/serializers.py:50 ops/models/base.py:49 ops/models/job.py:220
#: terminal/models/applet/applet.py:283 terminal/models/applet/host.py:139
#: terminal/models/applet/applet.py:301 terminal/models/applet/host.py:139
#: terminal/models/component/status.py:30 terminal/serializers/applet.py:18
#: terminal/serializers/applet_host.py:115 tickets/models/ticket/general.py:283
#: tickets/serializers/super_ticket.py:13
@ -1717,7 +1718,7 @@ msgstr "開ける"
msgid "Setting"
msgstr "設定"
#: assets/models/platform.py:38 audits/const.py:48 settings/models.py:36
#: assets/models/platform.py:38 audits/const.py:49 settings/models.py:36
#: terminal/serializers/applet_host.py:33
msgid "Enabled"
msgstr "有効化"
@ -2129,7 +2130,8 @@ msgstr "名前の変更"
msgid "Symlink"
msgstr "Symlink"
#: audits/const.py:18 perms/const.py:14
#: audits/const.py:18 audits/const.py:28 perms/const.py:14
#: terminal/api/session/session.py:141
msgid "Download"
msgstr "ダウンロード"
@ -2137,7 +2139,7 @@ msgstr "ダウンロード"
msgid "Rename dir"
msgstr "マップディレクトリ"
#: audits/const.py:23 rbac/tree.py:232
#: audits/const.py:23 rbac/tree.py:232 terminal/api/session/session.py:234
#: terminal/templates/terminal/_msg_command_warning.html:18
#: terminal/templates/terminal/_msg_session_sharing.html:10
msgid "View"
@ -2149,44 +2151,44 @@ msgstr "表示"
msgid "Create"
msgstr "作成"
#: audits/const.py:28 perms/const.py:12
#: audits/const.py:29 perms/const.py:12
msgid "Connect"
msgstr "接続"
#: audits/const.py:29 authentication/templates/authentication/login.html:252
#: audits/const.py:30 authentication/templates/authentication/login.html:252
#: authentication/templates/authentication/login.html:325
#: templates/_header_bar.html:89
msgid "Login"
msgstr "ログイン"
#: audits/const.py:30 ops/const.py:9
#: audits/const.py:31 ops/const.py:9
msgid "Change password"
msgstr "パスワードを変更する"
#: audits/const.py:35 settings/serializers/terminal.py:6
#: audits/const.py:36 settings/serializers/terminal.py:6
#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:164
#: terminal/serializers/session.py:49 terminal/serializers/session.py:63
msgid "Terminal"
msgstr "ターミナル"
#: audits/const.py:40 audits/models.py:127
#: audits/const.py:41 audits/models.py:127
msgid "Operate log"
msgstr "ログの操作"
#: audits/const.py:41
#: audits/const.py:42
msgid "Session log"
msgstr "セッションログ"
#: audits/const.py:42
#: audits/const.py:43
msgid "Login log"
msgstr "ログインログ"
#: audits/const.py:43 terminal/models/applet/host.py:143
#: audits/const.py:44 terminal/models/applet/host.py:143
#: terminal/models/component/task.py:22
msgid "Task"
msgstr "タスク"
#: audits/const.py:49
#: audits/const.py:50
msgid "-"
msgstr "-"
@ -2412,7 +2414,7 @@ msgstr "ACL アクションはレビューです"
msgid "Current user not support mfa type: {}"
msgstr "現在のユーザーはmfaタイプをサポートしていません: {}"
#: authentication/api/password.py:32 terminal/api/session/session.py:259
#: authentication/api/password.py:32 terminal/api/session/session.py:282
#: users/views/profile/reset.py:44
msgid "User does not exist: {}"
msgstr "ユーザーが存在しない: {}"
@ -4099,7 +4101,7 @@ msgstr "デフォルト組織"
msgid "SYSTEM"
msgstr "システム組織"
#: orgs/models.py:83 rbac/models/role.py:36 terminal/models/applet/applet.py:40
#: orgs/models.py:83 rbac/models/role.py:36 terminal/models/applet/applet.py:41
msgid "Builtin"
msgstr "ビルトイン"
@ -4336,7 +4338,7 @@ msgstr "パーマ"
msgid "Users amount"
msgstr "ユーザー数"
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:33
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:34
msgid "Display name"
msgstr "表示名"
@ -4396,8 +4398,8 @@ msgstr "タスクセンター"
msgid "My assets"
msgstr "私の資産"
#: rbac/tree.py:56 terminal/models/applet/applet.py:51
#: terminal/models/applet/applet.py:280 terminal/models/applet/host.py:29
#: rbac/tree.py:56 terminal/models/applet/applet.py:52
#: terminal/models/applet/applet.py:298 terminal/models/applet/host.py:29
#: terminal/serializers/applet.py:15
msgid "Applet"
msgstr "リモートアプリケーション"
@ -5902,15 +5904,20 @@ msgstr "テスト失敗: アカウントが無効"
msgid "Have online sessions"
msgstr "オンラインセッションを持つ"
#: terminal/api/session/session.py:251
#: terminal/api/session/session.py:46
#, python-format
msgid "User %s %s session %s replay"
msgstr "ユーザー%s %sこのセッション %s の録画です"
#: terminal/api/session/session.py:274
msgid "Session does not exist: {}"
msgstr "セッションが存在しません: {}"
#: terminal/api/session/session.py:254
#: terminal/api/session/session.py:277
msgid "Session is finished or the protocol not supported"
msgstr "セッションが終了したか、プロトコルがサポートされていません"
#: terminal/api/session/session.py:267
#: terminal/api/session/session.py:290
msgid "User does not have permission"
msgstr "ユーザーに権限がありません"
@ -6028,51 +6035,51 @@ msgstr "一括作成非サポート"
msgid "Storage is invalid"
msgstr "ストレージが無効です"
#: terminal/models/applet/applet.py:29
#: terminal/models/applet/applet.py:30
msgid "Community"
msgstr "コミュニティ版"
#: terminal/models/applet/applet.py:30
#: terminal/models/applet/applet.py:31
msgid "Enterprise"
msgstr "エンタープライズ版"
#: terminal/models/applet/applet.py:35
#: terminal/models/applet/applet.py:36
msgid "Author"
msgstr "著者"
#: terminal/models/applet/applet.py:37 terminal/serializers/applet.py:31
#: terminal/models/applet/applet.py:38 terminal/serializers/applet.py:31
msgid "Edition"
msgstr "バージョン"
#: terminal/models/applet/applet.py:42
#: terminal/models/applet/applet.py:43
msgid "Can concurrent"
msgstr "同時実行可能"
#: terminal/models/applet/applet.py:43
#: terminal/models/applet/applet.py:44
msgid "Tags"
msgstr "ラベル"
#: terminal/models/applet/applet.py:47 terminal/serializers/storage.py:159
#: terminal/models/applet/applet.py:48 terminal/serializers/storage.py:159
msgid "Hosts"
msgstr "ホスト"
#: terminal/models/applet/applet.py:92
#: terminal/models/applet/applet.py:93
msgid "Applet pkg not valid, Missing file {}"
msgstr "無効なアプレット パッケージ、ファイル {} がありません"
#: terminal/models/applet/applet.py:111
#: terminal/models/applet/applet.py:112
msgid "Load platform.yml failed: {}"
msgstr "platform.ymlのロードに失敗しました:{}"
#: terminal/models/applet/applet.py:114
#: terminal/models/applet/applet.py:115
msgid "Only support custom platform"
msgstr "カスタムプラットフォームのみをサポート"
#: terminal/models/applet/applet.py:119
#: terminal/models/applet/applet.py:120
msgid "Missing type in platform.yml"
msgstr "platform.ymlにタイプがありません"
#: terminal/models/applet/applet.py:282 terminal/models/applet/host.py:35
#: terminal/models/applet/applet.py:300 terminal/models/applet/host.py:35
#: terminal/models/applet/host.py:137
msgid "Hosting"
msgstr "ホスト マシン"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-08-28 10:55+0800\n"
"POT-Creation-Date: 2023-08-29 14:45+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -92,7 +92,7 @@ msgid "Update"
msgstr "更新"
#: accounts/const/account.py:33
#: accounts/serializers/automations/change_secret.py:156 audits/const.py:54
#: accounts/serializers/automations/change_secret.py:156 audits/const.py:55
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
#: ops/const.py:61 terminal/const.py:77 xpack/plugins/cloud/const.py:43
msgid "Failed"
@ -226,7 +226,7 @@ msgstr "切换自"
#: accounts/models/account.py:54 assets/const/protocol.py:162
#: settings/serializers/auth/cas.py:20 settings/serializers/auth/feishu.py:20
#: terminal/models/applet/applet.py:34
#: terminal/models/applet/applet.py:35
msgid "Version"
msgstr "版本"
@ -330,56 +330,56 @@ msgstr "是否成功"
msgid "Account backup execution"
msgstr "账号备份执行"
#: accounts/models/automations/base.py:20
#: accounts/models/automations/base.py:19
msgid "Account automation task"
msgstr "账号自动化任务"
#: accounts/models/automations/base.py:34
#: accounts/models/automations/base.py:33
msgid "Automation execution"
msgstr "自动化执行"
#: accounts/models/automations/base.py:35
#: accounts/models/automations/base.py:34
msgid "Automation executions"
msgstr "自动化执行"
#: accounts/models/automations/base.py:37
#: accounts/models/automations/base.py:36
msgid "Can view change secret execution"
msgstr "查看改密执行"
#: accounts/models/automations/base.py:38
#: accounts/models/automations/base.py:37
msgid "Can add change secret execution"
msgstr "创建改密执行"
#: accounts/models/automations/base.py:40
#: accounts/models/automations/base.py:39
msgid "Can view gather accounts execution"
msgstr "查看收集账号执行"
#: accounts/models/automations/base.py:41
#: accounts/models/automations/base.py:40
msgid "Can add gather accounts execution"
msgstr "创建收集账号执行"
#: accounts/models/automations/base.py:43
#: accounts/models/automations/base.py:42
msgid "Can view push account execution"
msgstr "查看推送账号执行"
#: accounts/models/automations/base.py:44
#: accounts/models/automations/base.py:43
msgid "Can add push account execution"
msgstr "创建推送账号执行"
#: accounts/models/automations/base.py:56 accounts/models/template.py:21
#: accounts/models/automations/base.py:55 accounts/models/template.py:21
#: accounts/serializers/automations/change_secret.py:40
msgid "Secret strategy"
msgstr "密文策略"
#: accounts/models/automations/base.py:58
#: accounts/models/automations/base.py:57
msgid "Password rules"
msgstr "密码规则"
#: accounts/models/automations/base.py:61
#: accounts/models/automations/base.py:60
msgid "SSH key change strategy"
msgstr "SSH 密钥推送方式"
#: accounts/models/automations/base.py:71 accounts/models/base.py:36
#: accounts/models/automations/base.py:70 accounts/models/base.py:36
#: accounts/serializers/account/account.py:429
#: accounts/serializers/account/base.py:16
#: accounts/serializers/automations/change_secret.py:46
@ -388,7 +388,7 @@ msgstr "SSH 密钥推送方式"
msgid "Secret type"
msgstr "密文类型"
#: accounts/models/automations/base.py:73 accounts/models/mixins/vault.py:48
#: accounts/models/automations/base.py:72 accounts/models/mixins/vault.py:48
#: accounts/serializers/account/base.py:19
#: authentication/models/temp_token.py:10
#: authentication/templates/authentication/_access_key_modal.html:31
@ -509,7 +509,7 @@ msgstr "账号验证"
#: ops/models/job.py:126 ops/models/playbook.py:28 ops/serializers/job.py:20
#: orgs/models.py:82 perms/models/asset_permission.py:56 rbac/models/role.py:29
#: settings/models.py:32 settings/serializers/msg.py:82
#: terminal/models/applet/applet.py:32 terminal/models/component/endpoint.py:12
#: terminal/models/applet/applet.py:33 terminal/models/component/endpoint.py:12
#: terminal/models/component/endpoint.py:94
#: terminal/models/component/storage.py:26 terminal/models/component/task.py:13
#: terminal/models/component/terminal.py:84 users/forms/profile.py:33
@ -527,7 +527,7 @@ msgstr "特权账号"
#: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39
#: assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:114
#: terminal/models/applet/applet.py:39
#: terminal/models/applet/applet.py:40
#: terminal/models/component/endpoint.py:105 users/serializers/user.py:170
msgid "Is active"
msgstr "激活"
@ -650,7 +650,7 @@ msgstr "类别"
#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:112
#: assets/serializers/platform.py:127 audits/serializers.py:49
#: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:137
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:39
#: terminal/models/component/storage.py:57
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29
#: terminal/serializers/session.py:21 terminal/serializers/storage.py:226
@ -790,8 +790,8 @@ msgstr "关联平台,可配置推送参数,如果不关联,将使用默认
#: assets/models/cmd_filter.py:40 assets/models/cmd_filter.py:88
#: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26
#: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:37 terminal/models/applet/applet.py:44
#: terminal/models/applet/applet.py:284 terminal/models/applet/host.py:142
#: settings/models.py:37 terminal/models/applet/applet.py:45
#: terminal/models/applet/applet.py:302 terminal/models/applet/host.py:142
#: terminal/models/component/endpoint.py:24
#: terminal/models/component/endpoint.py:104
#: terminal/models/session/session.py:46 tickets/models/comment.py:32
@ -842,7 +842,7 @@ msgstr "* 密码长度范围 6-30 位"
msgid "Automation task execution"
msgstr "自动化任务执行历史"
#: accounts/serializers/automations/change_secret.py:155 audits/const.py:53
#: accounts/serializers/automations/change_secret.py:155 audits/const.py:54
#: audits/models.py:59 audits/signal_handlers/activity_log.py:33
#: common/const/choices.py:18 ops/const.py:59 ops/serializers/celery.py:40
#: terminal/const.py:76 terminal/models/session/sharing.py:121
@ -850,8 +850,8 @@ msgstr "自动化任务执行历史"
msgid "Success"
msgstr "成功"
#: accounts/signal_handlers.py:47
#, fpython-format
#: accounts/signal_handlers.py:46
#, python-format
msgid "Push related accounts to assets: %s, by system"
msgstr "推送账号到资产: %s, 由系统执行"
@ -1162,7 +1162,7 @@ msgstr "认证失败"
msgid "Connect failed"
msgstr "连接失败"
#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:36
#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:37
#: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31
#: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104
msgid "Unknown"
@ -1184,7 +1184,7 @@ msgstr "测试网关"
msgid "Gather facts"
msgstr "收集资产信息"
#: assets/const/base.py:33 audits/const.py:47
#: assets/const/base.py:33 audits/const.py:48
#: terminal/serializers/applet_host.py:32
msgid "Disabled"
msgstr "禁用"
@ -1215,8 +1215,8 @@ msgid "Cloud service"
msgstr "云服务"
#: assets/const/category.py:14 assets/models/asset/gpt.py:11
#: assets/models/asset/web.py:16 audits/const.py:34
#: terminal/models/applet/applet.py:26
#: assets/models/asset/web.py:16 audits/const.py:35
#: terminal/models/applet/applet.py:27
msgid "Web"
msgstr "Web"
@ -1236,7 +1236,7 @@ msgstr "私有云"
msgid "Kubernetes"
msgstr "Kubernetes"
#: assets/const/device.py:7 terminal/models/applet/applet.py:25
#: assets/const/device.py:7 terminal/models/applet/applet.py:26
#: tickets/const.py:8
msgid "General"
msgstr "一般"
@ -1430,7 +1430,7 @@ msgstr "用户名与用户相同"
#: assets/models/_user.py:52 authentication/models/connection_token.py:41
#: authentication/serializers/connect_token_secret.py:111
#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:19
#: terminal/models/applet/applet.py:42 terminal/serializers/session.py:19
#: terminal/serializers/session.py:42 terminal/serializers/storage.py:70
msgid "Protocol"
msgstr "协议"
@ -1569,7 +1569,7 @@ msgstr "资产自动化任务"
#: assets/models/automations/base.py:113 audits/models.py:199
#: audits/serializers.py:50 ops/models/base.py:49 ops/models/job.py:220
#: terminal/models/applet/applet.py:283 terminal/models/applet/host.py:139
#: terminal/models/applet/applet.py:301 terminal/models/applet/host.py:139
#: terminal/models/component/status.py:30 terminal/serializers/applet.py:18
#: terminal/serializers/applet_host.py:115 tickets/models/ticket/general.py:283
#: tickets/serializers/super_ticket.py:13
@ -1714,7 +1714,7 @@ msgstr "开放的"
msgid "Setting"
msgstr "设置"
#: assets/models/platform.py:38 audits/const.py:48 settings/models.py:36
#: assets/models/platform.py:38 audits/const.py:49 settings/models.py:36
#: terminal/serializers/applet_host.py:33
msgid "Enabled"
msgstr "启用"
@ -2117,7 +2117,7 @@ msgstr "重命名"
msgid "Symlink"
msgstr "建立软链接"
#: audits/const.py:18 perms/const.py:14
#: audits/const.py:18 audits/const.py:28 perms/const.py:14
msgid "Download"
msgstr "下载"
@ -2137,44 +2137,44 @@ msgstr "查看"
msgid "Create"
msgstr "创建"
#: audits/const.py:28 perms/const.py:12
#: audits/const.py:29 perms/const.py:12
msgid "Connect"
msgstr "连接"
#: audits/const.py:29 authentication/templates/authentication/login.html:252
#: audits/const.py:30 authentication/templates/authentication/login.html:252
#: authentication/templates/authentication/login.html:325
#: templates/_header_bar.html:89
msgid "Login"
msgstr "登录"
#: audits/const.py:30 ops/const.py:9
#: audits/const.py:31 ops/const.py:9
msgid "Change password"
msgstr "改密"
#: audits/const.py:35 settings/serializers/terminal.py:6
#: audits/const.py:36 settings/serializers/terminal.py:6
#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:164
#: terminal/serializers/session.py:49 terminal/serializers/session.py:63
msgid "Terminal"
msgstr "终端"
#: audits/const.py:40 audits/models.py:127
#: audits/const.py:41 audits/models.py:127
msgid "Operate log"
msgstr "操作日志"
#: audits/const.py:41
#: audits/const.py:42
msgid "Session log"
msgstr "会话日志"
#: audits/const.py:42
#: audits/const.py:43
msgid "Login log"
msgstr "登录日志"
#: audits/const.py:43 terminal/models/applet/host.py:143
#: audits/const.py:44 terminal/models/applet/host.py:143
#: terminal/models/component/task.py:22
msgid "Task"
msgstr "任务"
#: audits/const.py:49
#: audits/const.py:50
msgid "-"
msgstr "-"
@ -2398,7 +2398,7 @@ msgstr "ACL 动作是复核"
msgid "Current user not support mfa type: {}"
msgstr "当前用户不支持 MFA 类型: {}"
#: authentication/api/password.py:32 terminal/api/session/session.py:259
#: authentication/api/password.py:32 terminal/api/session/session.py:284
#: users/views/profile/reset.py:44
msgid "User does not exist: {}"
msgstr "用户不存在: {}"
@ -4055,7 +4055,7 @@ msgstr "默认组织"
msgid "SYSTEM"
msgstr "系统组织"
#: orgs/models.py:83 rbac/models/role.py:36 terminal/models/applet/applet.py:40
#: orgs/models.py:83 rbac/models/role.py:36 terminal/models/applet/applet.py:41
msgid "Builtin"
msgstr "内置的"
@ -4291,7 +4291,7 @@ msgstr "权限"
msgid "Users amount"
msgstr "用户数量"
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:33
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:34
msgid "Display name"
msgstr "显示名称"
@ -4351,8 +4351,8 @@ msgstr "任务中心"
msgid "My assets"
msgstr "我的资产"
#: rbac/tree.py:56 terminal/models/applet/applet.py:51
#: terminal/models/applet/applet.py:280 terminal/models/applet/host.py:29
#: rbac/tree.py:56 terminal/models/applet/applet.py:52
#: terminal/models/applet/applet.py:298 terminal/models/applet/host.py:29
#: terminal/serializers/applet.py:15
msgid "Applet"
msgstr "远程应用"
@ -5818,15 +5818,20 @@ msgstr "测试失败: 账号无效"
msgid "Have online sessions"
msgstr "有在线会话"
#: terminal/api/session/session.py:251
#: terminal/api/session/session.py:47
#, python-format
msgid "User %s %s session %s replay"
msgstr "用户 %s %s 了会话 %s 的录像"
#: terminal/api/session/session.py:276
msgid "Session does not exist: {}"
msgstr "会话不存在: {}"
#: terminal/api/session/session.py:254
#: terminal/api/session/session.py:279
msgid "Session is finished or the protocol not supported"
msgstr "会话已经完成或协议不支持"
#: terminal/api/session/session.py:267
#: terminal/api/session/session.py:292
msgid "User does not have permission"
msgstr "用户没有权限"
@ -5944,51 +5949,51 @@ msgstr "不支持批量创建"
msgid "Storage is invalid"
msgstr "存储无效"
#: terminal/models/applet/applet.py:29
#: terminal/models/applet/applet.py:30
msgid "Community"
msgstr "社区版"
#: terminal/models/applet/applet.py:30
#: terminal/models/applet/applet.py:31
msgid "Enterprise"
msgstr "企业版"
#: terminal/models/applet/applet.py:35
#: terminal/models/applet/applet.py:36
msgid "Author"
msgstr "作者"
#: terminal/models/applet/applet.py:37 terminal/serializers/applet.py:31
#: terminal/models/applet/applet.py:38 terminal/serializers/applet.py:31
msgid "Edition"
msgstr "版本"
#: terminal/models/applet/applet.py:42
#: terminal/models/applet/applet.py:43
msgid "Can concurrent"
msgstr "可以并发"
#: terminal/models/applet/applet.py:43
#: terminal/models/applet/applet.py:44
msgid "Tags"
msgstr "标签"
#: terminal/models/applet/applet.py:47 terminal/serializers/storage.py:159
#: terminal/models/applet/applet.py:48 terminal/serializers/storage.py:159
msgid "Hosts"
msgstr "主机"
#: terminal/models/applet/applet.py:92
#: terminal/models/applet/applet.py:93
msgid "Applet pkg not valid, Missing file {}"
msgstr "Applet pkg 无效,缺少文件 {}"
#: terminal/models/applet/applet.py:111
#: terminal/models/applet/applet.py:112
msgid "Load platform.yml failed: {}"
msgstr "加载 platform.yml 失败: {}"
#: terminal/models/applet/applet.py:114
#: terminal/models/applet/applet.py:115
msgid "Only support custom platform"
msgstr "只支持自定义平台"
#: terminal/models/applet/applet.py:119
#: terminal/models/applet/applet.py:120
msgid "Missing type in platform.yml"
msgstr "在 platform.yml 中缺少类型"
#: terminal/models/applet/applet.py:282 terminal/models/applet/host.py:35
#: terminal/models/applet/applet.py:300 terminal/models/applet/host.py:35
#: terminal/models/applet/host.py:137
msgid "Hosting"
msgstr "宿主机"

View File

@ -8,7 +8,7 @@ from django.db.models import F
from django.http import FileResponse
from django.shortcuts import get_object_or_404, reverse
from django.utils.encoding import escape_uri_path
from django.utils.translation import gettext as _
from django.utils.translation import gettext_noop, gettext as _
from django_filters import rest_framework as filters
from rest_framework import generics
from rest_framework import viewsets, views
@ -16,14 +16,16 @@ from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from audits.const import ActionChoices
from common.api import AsyncApiMixin
from common.const.http import GET
from common.drf.filters import BaseFilterSet
from common.drf.filters import DatetimeRangeFilterBackend
from common.drf.renders import PassthroughRenderer
from common.storage.replay import ReplayStorageHandler
from common.utils import data_to_json, is_uuid
from common.utils import data_to_json, is_uuid, i18n_fmt
from common.utils import get_logger, get_object_or_none
from common.views.mixins import RecordViewLogMixin
from orgs.mixins.api import OrgBulkModelViewSet
from orgs.utils import tmp_to_root_org, tmp_to_org
from rbac.permissions import RBACPermission
@ -41,6 +43,8 @@ __all__ = [
logger = get_logger(__name__)
REPLAY_OP = gettext_noop('User %s %s session %s replay')
class MySessionAPIView(generics.ListAPIView):
permission_classes = (IsAuthenticated,)
@ -70,7 +74,7 @@ class SessionFilterSet(BaseFilterSet):
return queryset.filter(terminal__name=value)
class SessionViewSet(OrgBulkModelViewSet):
class SessionViewSet(RecordViewLogMixin, OrgBulkModelViewSet):
model = Session
serializer_classes = {
'default': serializers.SessionSerializer,
@ -132,6 +136,14 @@ class SessionViewSet(OrgBulkModelViewSet):
filename = escape_uri_path('{}.tar'.format(storage.obj.id))
disposition = "attachment; filename*=UTF-8''{}".format(filename)
response["Content-Disposition"] = disposition
detail = i18n_fmt(
REPLAY_OP, self.request.user, _('Download'), str(storage.obj)
)
self.record_logs(
[storage.obj.asset_id], ActionChoices.download, detail,
model=Session, resource_display=str(storage.obj)
)
return response
def get_queryset(self):
@ -152,7 +164,7 @@ class SessionViewSet(OrgBulkModelViewSet):
return super().perform_create(serializer)
class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet):
class SessionReplayViewSet(AsyncApiMixin, RecordViewLogMixin, viewsets.ViewSet):
serializer_class = serializers.ReplaySerializer
download_cache_key = "SESSION_REPLAY_DOWNLOAD_{}"
session = None
@ -215,6 +227,17 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet):
return False
return True
def async_callback(self, *args, **kwargs):
session_id = kwargs.get('pk')
session = get_object_or_404(Session, id=session_id)
detail = i18n_fmt(
REPLAY_OP, self.request.user, _('View'), str(session)
)
self.record_logs(
[session.asset_id], ActionChoices.download, detail,
model=Session, resource_display=str(session)
)
def retrieve(self, request, *args, **kwargs):
session_id = kwargs.get('pk')
session = get_object_or_404(Session, id=session_id)