diff --git a/apps/acls/models/__init__.py b/apps/acls/models/__init__.py index 28fe366b3..0a4cc2a6e 100644 --- a/apps/acls/models/__init__.py +++ b/apps/acls/models/__init__.py @@ -2,3 +2,4 @@ from .command_acl import * from .connect_method import * from .login_acl import * from .login_asset_acl import * +from .base import ActionChoices diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index cbc5c6e4e..c84ea3fcf 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -10,6 +10,7 @@ from orgs.mixins.models import OrgModelMixin, OrgManager __all__ = [ 'BaseACL', 'UserBaseACL', 'UserAssetAccountBaseACL', + 'ActionChoices', ] from orgs.utils import tmp_to_root_org @@ -20,6 +21,7 @@ class ActionChoices(models.TextChoices): reject = 'reject', _('Reject') accept = 'accept', _('Accept') review = 'review', _('Review') + warning = 'warning', _('Warning') class BaseACLQuerySet(models.QuerySet): diff --git a/apps/acls/serializers/base.py b/apps/acls/serializers/base.py index d8a172c93..3892553d9 100644 --- a/apps/acls/serializers/base.py +++ b/apps/acls/serializers/base.py @@ -84,6 +84,7 @@ class BaserACLSerializer(ActionAclSerializer, serializers.Serializer): extra_kwargs = { "priority": {"default": 50}, "is_active": {"default": True}, + 'reviewers': {'label': _('Recipients')}, } def validate_reviewers(self, reviewers): diff --git a/apps/jumpserver/api.py b/apps/jumpserver/api.py index 6e2e49691..10b0afa55 100644 --- a/apps/jumpserver/api.py +++ b/apps/jumpserver/api.py @@ -22,6 +22,7 @@ from orgs.utils import current_org from terminal.models import Session, Command from terminal.utils import ComponentsPrometheusMetricsUtil from users.models import User +from terminal.const import RiskLevelChoices __all__ = ['IndexApi'] @@ -248,7 +249,7 @@ class DatesLoginMetricMixin: @lazyproperty def commands_danger_amount(self): - return self.command_queryset.filter(risk_level=Command.RiskLevelChoices.dangerous).count() + return self.command_queryset.filter(risk_level=RiskLevelChoices.reject).count() @lazyproperty def job_logs_running_amount(self): diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index b45d415ff..c78b136bb 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-07-11 11:18+0800\n" +"POT-Creation-Date: 2023-07-11 12:03+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -50,10 +50,8 @@ msgid "Token" msgstr "トークン" #: accounts/const/account.py:10 -#, fuzzy -#| msgid "API Key" msgid "API key" -msgstr "API Key" +msgstr "" #: accounts/const/account.py:14 common/db/fields.py:244 #: settings/serializers/terminal.py:14 @@ -97,7 +95,7 @@ msgstr "更新" #: accounts/const/account.py:29 #: accounts/serializers/automations/change_secret.py:156 audits/const.py:54 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 -#: ops/const.py:58 terminal/const.py:63 xpack/plugins/cloud/const.py:43 +#: ops/const.py:58 terminal/const.py:72 xpack/plugins/cloud/const.py:43 msgid "Failed" msgstr "失敗しました" @@ -196,13 +194,14 @@ msgstr "作成のみ" #: accounts/serializers/account/gathered_account.py:10 #: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:132 -#: acls/serializers/base.py:118 assets/models/asset/common.py:93 +#: acls/serializers/base.py:119 assets/models/asset/common.py:93 #: assets/models/asset/common.py:331 assets/models/cmd_filter.py:36 #: assets/serializers/domain.py:19 assets/serializers/label.py:27 #: audits/models.py:53 authentication/models/connection_token.py:36 #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 -#: terminal/backends/command/models.py:20 terminal/models/session/session.py:31 -#: terminal/notifications.py:95 terminal/serializers/command.py:17 +#: terminal/backends/command/models.py:18 terminal/models/session/session.py:31 +#: terminal/notifications.py:134 terminal/serializers/command.py:18 +#: terminal/templates/terminal/_msg_command_warning.html:4 #: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:212 msgid "Asset" msgstr "資産" @@ -232,10 +231,10 @@ msgstr "ソース ID" #: accounts/models/account.py:61 #: accounts/serializers/automations/change_secret.py:113 #: accounts/serializers/automations/change_secret.py:133 -#: acls/serializers/base.py:119 assets/serializers/asset/common.py:125 +#: acls/serializers/base.py:120 assets/serializers/asset/common.py:125 #: assets/serializers/gateway.py:28 audits/models.py:54 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 -#: terminal/backends/command/models.py:21 terminal/models/session/session.py:33 +#: terminal/backends/command/models.py:19 terminal/models/session/session.py:33 #: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 msgid "Account" msgstr "アカウント" @@ -468,7 +467,7 @@ msgstr "アカウントのコレクション" msgid "Triggers" msgstr "トリガー方式" -#: accounts/models/automations/push_account.py:16 acls/models/base.py:46 +#: accounts/models/automations/push_account.py:16 acls/models/base.py:48 #: acls/serializers/base.py:56 assets/models/cmd_filter.py:81 #: audits/models.py:87 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:116 @@ -484,7 +483,7 @@ msgstr "アカウントプッシュ" msgid "Verify asset account" msgstr "アカウントの確認" -#: accounts/models/base.py:33 acls/models/base.py:40 acls/models/base.py:101 +#: accounts/models/base.py:33 acls/models/base.py:42 acls/models/base.py:103 #: acls/models/command_acl.py:21 acls/serializers/base.py:34 #: applications/models.py:9 assets/models/_user.py:22 #: assets/models/asset/common.py:91 assets/models/asset/common.py:149 @@ -618,7 +617,7 @@ msgid "Changed" msgstr "編集済み" #: accounts/serializers/account/account.py:250 -#: accounts/serializers/automations/base.py:22 acls/models/base.py:102 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:104 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -646,7 +645,7 @@ msgstr "アカウントはすでに存在しています" msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:427 acls/serializers/base.py:111 +#: accounts/serializers/account/account.py:427 acls/serializers/base.py:112 #: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:49 #: audits/models.py:85 audits/models.py:163 #: authentication/models/connection_token.py:32 @@ -654,10 +653,10 @@ msgstr "ID" #: notifications/models/notification.py:12 #: perms/api/user_permission/mixin.py:55 perms/models/asset_permission.py:58 #: perms/serializers/permission.py:30 rbac/builtin.py:122 -#: rbac/models/rolebinding.py:49 terminal/backends/command/models.py:19 +#: rbac/models/rolebinding.py:49 terminal/backends/command/models.py:17 #: terminal/models/session/session.py:29 terminal/models/session/sharing.py:32 -#: terminal/notifications.py:96 terminal/notifications.py:144 -#: terminal/serializers/command.py:16 tickets/models/comment.py:21 +#: terminal/notifications.py:135 terminal/notifications.py:183 +#: terminal/serializers/command.py:17 tickets/models/comment.py:21 #: users/const.py:14 users/models/user.py:947 users/models/user.py:978 #: users/serializers/group.py:18 msgid "User" @@ -665,7 +664,7 @@ msgstr "ユーザー" #: accounts/serializers/account/account.py:428 #: authentication/templates/authentication/_access_key_modal.html:33 -#: terminal/notifications.py:98 terminal/notifications.py:146 +#: terminal/notifications.py:137 terminal/notifications.py:185 msgid "Date" msgstr "日付" @@ -744,7 +743,7 @@ msgstr "自動タスク実行履歴" #: accounts/serializers/automations/change_secret.py:155 audits/const.py:53 #: audits/models.py:59 audits/signal_handlers/activity_log.py:33 #: common/const/choices.py:18 ops/const.py:56 ops/serializers/celery.py:40 -#: terminal/const.py:62 terminal/models/session/sharing.py:107 +#: terminal/const.py:71 terminal/models/session/sharing.py:107 #: tickets/views/approve.py:114 msgid "Success" msgstr "成功" @@ -793,35 +792,39 @@ msgstr "秘密鍵が無効またはpassphraseエラー" msgid "Acls" msgstr "Acls" -#: acls/models/base.py:20 tickets/const.py:45 +#: acls/models/base.py:21 terminal/const.py:11 tickets/const.py:45 #: tickets/templates/tickets/approve_check_password.html:49 msgid "Reject" msgstr "拒否" -#: acls/models/base.py:21 +#: acls/models/base.py:22 terminal/const.py:9 msgid "Accept" msgstr "受け入れられる" -#: acls/models/base.py:22 +#: acls/models/base.py:23 msgid "Review" msgstr "レビュー担当者" -#: acls/models/base.py:42 assets/models/_user.py:51 +#: acls/models/base.py:24 terminal/const.py:10 +msgid "Warning" +msgstr "警告" + +#: acls/models/base.py:44 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:93 msgid "Priority" msgstr "優先順位" -#: acls/models/base.py:43 assets/models/_user.py:51 +#: acls/models/base.py:45 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:94 msgid "1-100, the lower the value will be match first" msgstr "1-100、低い値は最初に一致します" -#: acls/models/base.py:47 assets/models/cmd_filter.py:86 +#: acls/models/base.py:49 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "レビュー担当者" -#: acls/models/base.py:48 authentication/models/access_key.py:17 +#: acls/models/base.py:50 authentication/models/access_key.py:17 #: authentication/models/connection_token.py:53 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 @@ -829,21 +832,22 @@ msgstr "レビュー担当者" msgid "Active" msgstr "アクティブ" -#: acls/models/base.py:86 users/apps.py:9 +#: acls/models/base.py:88 users/apps.py:9 msgid "Users" msgstr "ユーザー" -#: acls/models/base.py:103 assets/models/automations/base.py:17 +#: acls/models/base.py:105 assets/models/automations/base.py:17 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 #: rbac/tree.py:35 msgid "Accounts" msgstr "アカウント" #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 -#: ops/serializers/job.py:55 terminal/const.py:70 -#: terminal/models/session/session.py:42 terminal/serializers/command.py:18 +#: ops/serializers/job.py:55 terminal/const.py:79 +#: terminal/models/session/session.py:42 terminal/serializers/command.py:19 #: terminal/templates/terminal/_msg_command_alert.html:12 #: terminal/templates/terminal/_msg_command_execute_alert.html:10 +#: terminal/templates/terminal/_msg_command_warning.html:16 msgid "Command" msgstr "コマンド" @@ -875,6 +879,7 @@ msgid "The generated regular expression is incorrect: {}" msgstr "生成された正規表現が正しくありません: {}" #: acls/models/command_acl.py:100 +#: terminal/templates/terminal/_msg_command_warning.html:10 msgid "Command acl" msgstr "コマンドフィルタリング" @@ -929,11 +934,15 @@ msgstr "" msgid "IP/Host" msgstr "IP/ホスト" -#: acls/serializers/base.py:98 tickets/serializers/ticket/ticket.py:77 +#: acls/serializers/base.py:87 +msgid "Recipients" +msgstr "受信者" + +#: acls/serializers/base.py:99 tickets/serializers/ticket/ticket.py:77 msgid "The organization `{}` does not exist" msgstr "組織 '{}'は存在しません" -#: acls/serializers/base.py:104 +#: acls/serializers/base.py:105 msgid "None of the reviewers belong to Organization `{}`" msgstr "いずれのレビューアも組織 '{}' に属していません" @@ -1139,62 +1148,60 @@ msgstr "" msgid "Other" msgstr "その他" -#: assets/const/protocol.py:42 +#: assets/const/protocol.py:43 msgid "SFTP enabled" msgstr "SFTP が有効" -#: assets/const/protocol.py:47 +#: assets/const/protocol.py:48 msgid "SFTP home" msgstr "SFTP ルート パス" -#: assets/const/protocol.py:58 +#: assets/const/protocol.py:59 msgid "Console" msgstr "Console" -#: assets/const/protocol.py:59 +#: assets/const/protocol.py:60 msgid "Connect to console session" msgstr "コンソールセッションに接続" -#: assets/const/protocol.py:63 +#: assets/const/protocol.py:64 msgid "Any" msgstr "任意" -#: assets/const/protocol.py:65 settings/serializers/security.py:151 +#: assets/const/protocol.py:66 settings/serializers/security.py:151 msgid "Security" msgstr "セキュリティ" -#: assets/const/protocol.py:66 +#: assets/const/protocol.py:67 msgid "Security layer to use for the connection" msgstr "接続に使用するセキュリティ レイヤー" -#: assets/const/protocol.py:72 -#, fuzzy -#| msgid "Domain" +#: assets/const/protocol.py:73 msgid "AD domain" -msgstr "ドメイン" +msgstr "AD ドメイン" -#: assets/const/protocol.py:91 assets/models/asset/database.py:10 +#: assets/const/protocol.py:92 assets/models/asset/database.py:10 #: settings/serializers/email.py:37 msgid "Use SSL" msgstr "SSLの使用" -#: assets/const/protocol.py:144 +#: assets/const/protocol.py:145 msgid "Auth username" msgstr "ユーザー名で認証する" -#: assets/const/protocol.py:172 assets/models/asset/web.py:10 +#: assets/const/protocol.py:173 assets/models/asset/web.py:10 msgid "Username selector" msgstr "ユーザー名ピッカー" -#: assets/const/protocol.py:177 assets/models/asset/web.py:11 +#: assets/const/protocol.py:178 assets/models/asset/web.py:11 msgid "Password selector" msgstr "パスワードセレクター" -#: assets/const/protocol.py:182 assets/models/asset/web.py:12 +#: assets/const/protocol.py:183 assets/models/asset/web.py:12 msgid "Submit selector" msgstr "ボタンセレクターを確認する" -#: assets/const/protocol.py:200 +#: assets/const/protocol.py:201 msgid "API mode" msgstr "APIモード" @@ -1723,7 +1730,9 @@ msgstr "このフィールドは必須です。" msgid "" "If the server cannot directly connect to the API address, you need set up an " "HTTP proxy. e.g. http(s)://host:port" -msgstr "サーバーが API アドレスに直接接続できない場合は、HTTP プロキシを設定する必要があります。例: http(s)://host:port" +msgstr "" +"サーバーが API アドレスに直接接続できない場合は、HTTP プロキシを設定する必要" +"があります。例: http(s)://host:port" #: assets/serializers/asset/gpt.py:23 msgid "HTTP proxy" @@ -2058,10 +2067,11 @@ msgstr "ファイル名" msgid "File" msgstr "書類" -#: audits/models.py:62 terminal/backends/command/models.py:24 +#: audits/models.py:62 terminal/backends/command/models.py:22 #: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18 #: terminal/models/session/sharing.py:81 #: terminal/templates/terminal/_msg_command_alert.html:10 +#: terminal/templates/terminal/_msg_command_warning.html:7 #: tickets/models/ticket/command_confirm.py:15 msgid "Session" msgstr "セッション" @@ -2080,7 +2090,7 @@ msgid "Resource" msgstr "リソース" #: audits/models.py:96 audits/models.py:142 audits/models.py:168 -#: terminal/serializers/command.py:50 +#: terminal/serializers/command.py:61 msgid "Datetime" msgstr "時間" @@ -3157,7 +3167,7 @@ msgstr "タイミングトリガー" msgid "Ready" msgstr "の準備を" -#: common/const/choices.py:16 terminal/const.py:61 tickets/const.py:29 +#: common/const/choices.py:16 terminal/const.py:70 tickets/const.py:29 #: tickets/const.py:39 msgid "Pending" msgstr "未定" @@ -5671,7 +5681,7 @@ msgstr "テスト失敗: {}" msgid "Test successful" msgstr "テスト成功" -#: terminal/api/component/storage.py:124 terminal/notifications.py:179 +#: terminal/api/component/storage.py:124 terminal/notifications.py:218 #: terminal/tasks.py:144 msgid "Test failure: Account invalid" msgstr "テスト失敗: アカウントが無効" @@ -5700,23 +5710,15 @@ msgstr "安全なセッション共有設定が無効になっています" msgid "Terminals" msgstr "ターミナル管理" -#: terminal/backends/command/models.py:15 -msgid "Ordinary" -msgstr "普通" - -#: terminal/backends/command/models.py:16 -msgid "Dangerous" -msgstr "危険" - -#: terminal/backends/command/models.py:22 +#: terminal/backends/command/models.py:20 msgid "Input" msgstr "入力" -#: terminal/backends/command/models.py:23 terminal/serializers/command.py:48 +#: terminal/backends/command/models.py:21 terminal/serializers/command.py:59 msgid "Output" msgstr "出力" -#: terminal/backends/command/models.py:27 terminal/serializers/command.py:22 +#: terminal/backends/command/models.py:25 terminal/serializers/command.py:23 msgid "Risk level" msgstr "リスクレベル" @@ -5724,40 +5726,52 @@ msgstr "リスクレベル" msgid "DB Client" msgstr "データベース クライアント" -#: terminal/const.py:30 +#: terminal/const.py:12 +msgid "Review & Reject" +msgstr "レビューと拒否" + +#: terminal/const.py:13 +msgid "Review & Accept" +msgstr "確認して同意する" + +#: terminal/const.py:14 +msgid "Review & Cancel" +msgstr "確認してキャンセル" + +#: terminal/const.py:39 msgid "Critical" msgstr "クリティカル" -#: terminal/const.py:31 +#: terminal/const.py:40 msgid "High" msgstr "高い" -#: terminal/const.py:32 terminal/const.py:68 +#: terminal/const.py:41 terminal/const.py:77 #: users/templates/users/reset_password.html:50 msgid "Normal" msgstr "正常" -#: terminal/const.py:33 +#: terminal/const.py:42 msgid "Offline" msgstr "オフライン" -#: terminal/const.py:64 +#: terminal/const.py:73 msgid "Mismatch" msgstr "一致しない" -#: terminal/const.py:69 +#: terminal/const.py:78 msgid "Tunnel" msgstr "" -#: terminal/const.py:71 +#: terminal/const.py:80 msgid "SFTP" msgstr "SFTP" -#: terminal/const.py:75 +#: terminal/const.py:84 msgid "Read Only" msgstr "読み取り専用" -#: terminal/const.py:76 +#: terminal/const.py:85 msgid "Writable" msgstr "書き込み可能" @@ -5932,7 +5946,7 @@ msgstr "再生ストレージ" msgid "type" msgstr "タイプ" -#: terminal/models/component/terminal.py:89 terminal/serializers/command.py:51 +#: terminal/models/component/terminal.py:89 terminal/serializers/command.py:62 msgid "Remote Address" msgstr "リモートアドレス" @@ -6053,27 +6067,31 @@ msgstr "すでにこのセッションに参加しています" msgid "Sessions" msgstr "セッション" -#: terminal/notifications.py:67 +#: terminal/notifications.py:68 +msgid "Danger command warning" +msgstr "危険コマンドアラート" + +#: terminal/notifications.py:109 msgid "Danger command alert" msgstr "危険コマンドアラート" -#: terminal/notifications.py:97 terminal/notifications.py:145 +#: terminal/notifications.py:136 terminal/notifications.py:184 msgid "Level" msgstr "レベル" -#: terminal/notifications.py:115 +#: terminal/notifications.py:154 msgid "Batch danger command alert" msgstr "一括危険コマンド警告" -#: terminal/notifications.py:163 +#: terminal/notifications.py:202 msgid "Command and replay storage" msgstr "コマンド及び録画記憶" -#: terminal/notifications.py:164 +#: terminal/notifications.py:203 msgid "Connectivity alarm" msgstr "接続性アラーム" -#: terminal/notifications.py:189 +#: terminal/notifications.py:228 #: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 msgid "Invalid storage" msgstr "無効なストレージ" @@ -6145,15 +6163,23 @@ msgstr "RDS 远程应用注销时间限制" msgid "Load status" msgstr "ロードステータス" -#: terminal/serializers/command.py:19 +#: terminal/serializers/command.py:20 msgid "Session ID" msgstr "セッションID" -#: terminal/serializers/command.py:47 +#: terminal/serializers/command.py:42 +msgid "Command Filter ACL" +msgstr "コマンドフィルター" + +#: terminal/serializers/command.py:45 +msgid "Command Group" +msgstr "コマンドグループ" + +#: terminal/serializers/command.py:58 msgid "Account " msgstr "アカウント" -#: terminal/serializers/command.py:49 +#: terminal/serializers/command.py:60 msgid "Timestamp" msgstr "タイムスタンプ" @@ -6327,9 +6353,17 @@ msgid "Check command replay storage connectivity" msgstr "チェックコマンドと録画ストレージの接続性" #: terminal/templates/terminal/_msg_command_alert.html:10 +#: terminal/templates/terminal/_msg_command_warning.html:5 +#: terminal/templates/terminal/_msg_command_warning.html:8 +#: terminal/templates/terminal/_msg_command_warning.html:11 +#: terminal/templates/terminal/_msg_command_warning.html:14 msgid "view" msgstr "表示" +#: terminal/templates/terminal/_msg_command_warning.html:13 +msgid "Command acl group" +msgstr "コマンドフィルタリンググループ" + #: terminal/utils/db_port_mapper.py:84 msgid "" "No available port is matched. The number of databases may have exceeded the " @@ -7313,10 +7347,8 @@ msgid "Google Cloud Platform" msgstr "谷歌雲" #: xpack/plugins/cloud/const.py:20 -#, fuzzy -#| msgid "Cloud" msgid "UCloud" -msgstr "クラウド サービス" +msgstr "" #: xpack/plugins/cloud/const.py:22 msgid "VMware" @@ -7735,10 +7767,8 @@ msgid "Test timeout" msgstr "テストタイムアウト" #: xpack/plugins/cloud/serializers/account_attrs.py:212 -#, fuzzy -#| msgid "Reject" msgid "Project" -msgstr "拒否" +msgstr "" #: xpack/plugins/cloud/serializers/task.py:28 msgid "" @@ -7837,9 +7867,3 @@ msgstr "究極のエディション" #: xpack/plugins/license/models.py:86 msgid "Community edition" msgstr "コミュニティ版" - -#~ msgid "e.g. http(s)://host" -#~ msgstr "HTTP プロキシ、例えば http(s)://host" - -#~ msgid "Please enable cookies and try again." -#~ msgstr "クッキーを有効にして、もう一度お試しください。" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index f5dfcabd4..b74c0fc53 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-07-11 11:18+0800\n" +"POT-Creation-Date: 2023-07-11 12:03+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -49,10 +49,8 @@ msgid "Token" msgstr "Token" #: accounts/const/account.py:10 -#, fuzzy -#| msgid "API Key" msgid "API key" -msgstr "API Key" +msgstr "" #: accounts/const/account.py:14 common/db/fields.py:244 #: settings/serializers/terminal.py:14 @@ -96,7 +94,7 @@ msgstr "更新" #: accounts/const/account.py:29 #: accounts/serializers/automations/change_secret.py:156 audits/const.py:54 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 -#: ops/const.py:58 terminal/const.py:63 xpack/plugins/cloud/const.py:43 +#: ops/const.py:58 terminal/const.py:72 xpack/plugins/cloud/const.py:43 msgid "Failed" msgstr "失败" @@ -195,13 +193,14 @@ msgstr "仅创建" #: accounts/serializers/account/gathered_account.py:10 #: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:132 -#: acls/serializers/base.py:118 assets/models/asset/common.py:93 +#: acls/serializers/base.py:119 assets/models/asset/common.py:93 #: assets/models/asset/common.py:331 assets/models/cmd_filter.py:36 #: assets/serializers/domain.py:19 assets/serializers/label.py:27 #: audits/models.py:53 authentication/models/connection_token.py:36 #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 -#: terminal/backends/command/models.py:20 terminal/models/session/session.py:31 -#: terminal/notifications.py:95 terminal/serializers/command.py:17 +#: terminal/backends/command/models.py:18 terminal/models/session/session.py:31 +#: terminal/notifications.py:134 terminal/serializers/command.py:18 +#: terminal/templates/terminal/_msg_command_warning.html:4 #: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:212 msgid "Asset" msgstr "资产" @@ -231,10 +230,10 @@ msgstr "来源 ID" #: accounts/models/account.py:61 #: accounts/serializers/automations/change_secret.py:113 #: accounts/serializers/automations/change_secret.py:133 -#: acls/serializers/base.py:119 assets/serializers/asset/common.py:125 +#: acls/serializers/base.py:120 assets/serializers/asset/common.py:125 #: assets/serializers/gateway.py:28 audits/models.py:54 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 -#: terminal/backends/command/models.py:21 terminal/models/session/session.py:33 +#: terminal/backends/command/models.py:19 terminal/models/session/session.py:33 #: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 msgid "Account" msgstr "账号" @@ -467,7 +466,7 @@ msgstr "收集账号" msgid "Triggers" msgstr "触发方式" -#: accounts/models/automations/push_account.py:16 acls/models/base.py:46 +#: accounts/models/automations/push_account.py:16 acls/models/base.py:48 #: acls/serializers/base.py:56 assets/models/cmd_filter.py:81 #: audits/models.py:87 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:116 @@ -483,7 +482,7 @@ msgstr "账号推送" msgid "Verify asset account" msgstr "账号验证" -#: accounts/models/base.py:33 acls/models/base.py:40 acls/models/base.py:101 +#: accounts/models/base.py:33 acls/models/base.py:42 acls/models/base.py:103 #: acls/models/command_acl.py:21 acls/serializers/base.py:34 #: applications/models.py:9 assets/models/_user.py:22 #: assets/models/asset/common.py:91 assets/models/asset/common.py:149 @@ -614,7 +613,7 @@ msgid "Changed" msgstr "已修改" #: accounts/serializers/account/account.py:250 -#: accounts/serializers/automations/base.py:22 acls/models/base.py:102 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:104 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -642,7 +641,7 @@ msgstr "账号已存在" msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:427 acls/serializers/base.py:111 +#: accounts/serializers/account/account.py:427 acls/serializers/base.py:112 #: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:49 #: audits/models.py:85 audits/models.py:163 #: authentication/models/connection_token.py:32 @@ -650,10 +649,10 @@ msgstr "ID" #: notifications/models/notification.py:12 #: perms/api/user_permission/mixin.py:55 perms/models/asset_permission.py:58 #: perms/serializers/permission.py:30 rbac/builtin.py:122 -#: rbac/models/rolebinding.py:49 terminal/backends/command/models.py:19 +#: rbac/models/rolebinding.py:49 terminal/backends/command/models.py:17 #: terminal/models/session/session.py:29 terminal/models/session/sharing.py:32 -#: terminal/notifications.py:96 terminal/notifications.py:144 -#: terminal/serializers/command.py:16 tickets/models/comment.py:21 +#: terminal/notifications.py:135 terminal/notifications.py:183 +#: terminal/serializers/command.py:17 tickets/models/comment.py:21 #: users/const.py:14 users/models/user.py:947 users/models/user.py:978 #: users/serializers/group.py:18 msgid "User" @@ -661,7 +660,7 @@ msgstr "用户" #: accounts/serializers/account/account.py:428 #: authentication/templates/authentication/_access_key_modal.html:33 -#: terminal/notifications.py:98 terminal/notifications.py:146 +#: terminal/notifications.py:137 terminal/notifications.py:185 msgid "Date" msgstr "日期" @@ -740,7 +739,7 @@ msgstr "自动化任务执行历史" #: accounts/serializers/automations/change_secret.py:155 audits/const.py:53 #: audits/models.py:59 audits/signal_handlers/activity_log.py:33 #: common/const/choices.py:18 ops/const.py:56 ops/serializers/celery.py:40 -#: terminal/const.py:62 terminal/models/session/sharing.py:107 +#: terminal/const.py:71 terminal/models/session/sharing.py:107 #: tickets/views/approve.py:114 msgid "Success" msgstr "成功" @@ -789,35 +788,39 @@ msgstr "密钥不合法或密钥密码错误" msgid "Acls" msgstr "访问控制" -#: acls/models/base.py:20 tickets/const.py:45 +#: acls/models/base.py:21 terminal/const.py:11 tickets/const.py:45 #: tickets/templates/tickets/approve_check_password.html:49 msgid "Reject" msgstr "拒绝" -#: acls/models/base.py:21 +#: acls/models/base.py:22 terminal/const.py:9 msgid "Accept" msgstr "接受" -#: acls/models/base.py:22 +#: acls/models/base.py:23 msgid "Review" msgstr "审批" -#: acls/models/base.py:42 assets/models/_user.py:51 +#: acls/models/base.py:24 terminal/const.py:10 +msgid "Warning" +msgstr "告警" + +#: acls/models/base.py:44 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:93 msgid "Priority" msgstr "优先级" -#: acls/models/base.py:43 assets/models/_user.py:51 +#: acls/models/base.py:45 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:94 msgid "1-100, the lower the value will be match first" msgstr "优先级可选范围为 1-100 (数值越小越优先)" -#: acls/models/base.py:47 assets/models/cmd_filter.py:86 +#: acls/models/base.py:49 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "审批人" -#: acls/models/base.py:48 authentication/models/access_key.py:17 +#: acls/models/base.py:50 authentication/models/access_key.py:17 #: authentication/models/connection_token.py:53 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 @@ -825,21 +828,22 @@ msgstr "审批人" msgid "Active" msgstr "激活中" -#: acls/models/base.py:86 users/apps.py:9 +#: acls/models/base.py:88 users/apps.py:9 msgid "Users" msgstr "用户管理" -#: acls/models/base.py:103 assets/models/automations/base.py:17 +#: acls/models/base.py:105 assets/models/automations/base.py:17 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 #: rbac/tree.py:35 msgid "Accounts" msgstr "账号管理" #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 -#: ops/serializers/job.py:55 terminal/const.py:70 -#: terminal/models/session/session.py:42 terminal/serializers/command.py:18 +#: ops/serializers/job.py:55 terminal/const.py:79 +#: terminal/models/session/session.py:42 terminal/serializers/command.py:19 #: terminal/templates/terminal/_msg_command_alert.html:12 #: terminal/templates/terminal/_msg_command_execute_alert.html:10 +#: terminal/templates/terminal/_msg_command_warning.html:16 msgid "Command" msgstr "命令" @@ -871,6 +875,7 @@ msgid "The generated regular expression is incorrect: {}" msgstr "生成的正则表达式有误" #: acls/models/command_acl.py:100 +#: terminal/templates/terminal/_msg_command_warning.html:10 msgid "Command acl" msgstr "命令过滤" @@ -924,11 +929,15 @@ msgstr "" msgid "IP/Host" msgstr "IP/主机" -#: acls/serializers/base.py:98 tickets/serializers/ticket/ticket.py:77 +#: acls/serializers/base.py:87 +msgid "Recipients" +msgstr "接收人" + +#: acls/serializers/base.py:99 tickets/serializers/ticket/ticket.py:77 msgid "The organization `{}` does not exist" msgstr "组织 `{}` 不存在" -#: acls/serializers/base.py:104 +#: acls/serializers/base.py:105 msgid "None of the reviewers belong to Organization `{}`" msgstr "所有复核人都不属于组织 `{}`" @@ -1132,62 +1141,60 @@ msgstr "ChatGPT" msgid "Other" msgstr "其它" -#: assets/const/protocol.py:42 +#: assets/const/protocol.py:43 msgid "SFTP enabled" msgstr "SFTP 已启用" -#: assets/const/protocol.py:47 +#: assets/const/protocol.py:48 msgid "SFTP home" msgstr "SFTP 根路径" -#: assets/const/protocol.py:58 +#: assets/const/protocol.py:59 msgid "Console" msgstr "控制台" -#: assets/const/protocol.py:59 +#: assets/const/protocol.py:60 msgid "Connect to console session" msgstr "连接到控制台会话" -#: assets/const/protocol.py:63 +#: assets/const/protocol.py:64 msgid "Any" msgstr "任意" -#: assets/const/protocol.py:65 settings/serializers/security.py:151 +#: assets/const/protocol.py:66 settings/serializers/security.py:151 msgid "Security" msgstr "安全" -#: assets/const/protocol.py:66 +#: assets/const/protocol.py:67 msgid "Security layer to use for the connection" msgstr "连接 RDP 使用的安全层" -#: assets/const/protocol.py:72 -#, fuzzy -#| msgid "Domain" +#: assets/const/protocol.py:73 msgid "AD domain" -msgstr "网域" +msgstr "AD 网域" -#: assets/const/protocol.py:91 assets/models/asset/database.py:10 +#: assets/const/protocol.py:92 assets/models/asset/database.py:10 #: settings/serializers/email.py:37 msgid "Use SSL" msgstr "使用 SSL" -#: assets/const/protocol.py:144 +#: assets/const/protocol.py:145 msgid "Auth username" msgstr "使用用户名认证" -#: assets/const/protocol.py:172 assets/models/asset/web.py:10 +#: assets/const/protocol.py:173 assets/models/asset/web.py:10 msgid "Username selector" msgstr "用户名选择器" -#: assets/const/protocol.py:177 assets/models/asset/web.py:11 +#: assets/const/protocol.py:178 assets/models/asset/web.py:11 msgid "Password selector" msgstr "密码选择器" -#: assets/const/protocol.py:182 assets/models/asset/web.py:12 +#: assets/const/protocol.py:183 assets/models/asset/web.py:12 msgid "Submit selector" msgstr "确认按钮选择器" -#: assets/const/protocol.py:200 +#: assets/const/protocol.py:201 msgid "API mode" msgstr "API 模式" @@ -1714,7 +1721,9 @@ msgstr "该字段是必填项。" msgid "" "If the server cannot directly connect to the API address, you need set up an " "HTTP proxy. e.g. http(s)://host:port" -msgstr "如果服务器不能直接访问 api 地址,你需要设置一个 HTTP 代理。例如 http(s)://host:port" +msgstr "" +"如果服务器不能直接访问 api 地址,你需要设置一个 HTTP 代理。例如 http(s)://" +"host:port" #: assets/serializers/asset/gpt.py:23 msgid "HTTP proxy" @@ -2042,10 +2051,11 @@ msgstr "文件名" msgid "File" msgstr "文件" -#: audits/models.py:62 terminal/backends/command/models.py:24 +#: audits/models.py:62 terminal/backends/command/models.py:22 #: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18 #: terminal/models/session/sharing.py:81 #: terminal/templates/terminal/_msg_command_alert.html:10 +#: terminal/templates/terminal/_msg_command_warning.html:7 #: tickets/models/ticket/command_confirm.py:15 msgid "Session" msgstr "会话" @@ -2064,7 +2074,7 @@ msgid "Resource" msgstr "资源" #: audits/models.py:96 audits/models.py:142 audits/models.py:168 -#: terminal/serializers/command.py:50 +#: terminal/serializers/command.py:61 msgid "Datetime" msgstr "日期" @@ -3117,7 +3127,7 @@ msgstr "定时触发" msgid "Ready" msgstr "准备" -#: common/const/choices.py:16 terminal/const.py:61 tickets/const.py:29 +#: common/const/choices.py:16 terminal/const.py:70 tickets/const.py:29 #: tickets/const.py:39 msgid "Pending" msgstr "待定的" @@ -5584,7 +5594,7 @@ msgstr "测试失败: {}" msgid "Test successful" msgstr "测试成功" -#: terminal/api/component/storage.py:124 terminal/notifications.py:179 +#: terminal/api/component/storage.py:124 terminal/notifications.py:218 #: terminal/tasks.py:144 msgid "Test failure: Account invalid" msgstr "测试失败: 账号无效" @@ -5613,23 +5623,15 @@ msgstr "未开启会话共享" msgid "Terminals" msgstr "终端管理" -#: terminal/backends/command/models.py:15 -msgid "Ordinary" -msgstr "普通" - -#: terminal/backends/command/models.py:16 -msgid "Dangerous" -msgstr "危险" - -#: terminal/backends/command/models.py:22 +#: terminal/backends/command/models.py:20 msgid "Input" msgstr "输入" -#: terminal/backends/command/models.py:23 terminal/serializers/command.py:48 +#: terminal/backends/command/models.py:21 terminal/serializers/command.py:59 msgid "Output" msgstr "输出" -#: terminal/backends/command/models.py:27 terminal/serializers/command.py:22 +#: terminal/backends/command/models.py:25 terminal/serializers/command.py:23 msgid "Risk level" msgstr "风险等级" @@ -5637,40 +5639,52 @@ msgstr "风险等级" msgid "DB Client" msgstr "数据库客户端" -#: terminal/const.py:30 +#: terminal/const.py:12 +msgid "Review & Reject" +msgstr "审批 & 拒绝" + +#: terminal/const.py:13 +msgid "Review & Accept" +msgstr "审批 & 接受" + +#: terminal/const.py:14 +msgid "Review & Cancel" +msgstr "审批 & 取消" + +#: terminal/const.py:39 msgid "Critical" msgstr "严重" -#: terminal/const.py:31 +#: terminal/const.py:40 msgid "High" msgstr "较高" -#: terminal/const.py:32 terminal/const.py:68 +#: terminal/const.py:41 terminal/const.py:77 #: users/templates/users/reset_password.html:50 msgid "Normal" msgstr "正常" -#: terminal/const.py:33 +#: terminal/const.py:42 msgid "Offline" msgstr "离线" -#: terminal/const.py:64 +#: terminal/const.py:73 msgid "Mismatch" msgstr "未匹配" -#: terminal/const.py:69 +#: terminal/const.py:78 msgid "Tunnel" msgstr "隧道" -#: terminal/const.py:71 +#: terminal/const.py:80 msgid "SFTP" msgstr "SFTP" -#: terminal/const.py:75 +#: terminal/const.py:84 msgid "Read Only" msgstr "只读" -#: terminal/const.py:76 +#: terminal/const.py:85 msgid "Writable" msgstr "读写" @@ -5845,7 +5859,7 @@ msgstr "录像存储" msgid "type" msgstr "类型" -#: terminal/models/component/terminal.py:89 terminal/serializers/command.py:51 +#: terminal/models/component/terminal.py:89 terminal/serializers/command.py:62 msgid "Remote Address" msgstr "远端地址" @@ -5966,27 +5980,31 @@ msgstr "您已经加入过此会话" msgid "Sessions" msgstr "会话管理" -#: terminal/notifications.py:67 +#: terminal/notifications.py:68 +msgid "Danger command warning" +msgstr "危险命令告警" + +#: terminal/notifications.py:109 msgid "Danger command alert" msgstr "危险命令告警" -#: terminal/notifications.py:97 terminal/notifications.py:145 +#: terminal/notifications.py:136 terminal/notifications.py:184 msgid "Level" msgstr "级别" -#: terminal/notifications.py:115 +#: terminal/notifications.py:154 msgid "Batch danger command alert" msgstr "批量危险命令告警" -#: terminal/notifications.py:163 +#: terminal/notifications.py:202 msgid "Command and replay storage" msgstr "命令及录像存储" -#: terminal/notifications.py:164 +#: terminal/notifications.py:203 msgid "Connectivity alarm" msgstr "可连接性告警" -#: terminal/notifications.py:189 +#: terminal/notifications.py:228 #: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 msgid "Invalid storage" msgstr "无效的存储" @@ -6056,15 +6074,23 @@ msgstr "RDS 远程应用注销时间限制" msgid "Load status" msgstr "负载状态" -#: terminal/serializers/command.py:19 +#: terminal/serializers/command.py:20 msgid "Session ID" msgstr "会话ID" -#: terminal/serializers/command.py:47 +#: terminal/serializers/command.py:42 +msgid "Command Filter ACL" +msgstr "命令过滤器" + +#: terminal/serializers/command.py:45 +msgid "Command Group" +msgstr "命令组" + +#: terminal/serializers/command.py:58 msgid "Account " msgstr "账号" -#: terminal/serializers/command.py:49 +#: terminal/serializers/command.py:60 msgid "Timestamp" msgstr "时间戳" @@ -6235,9 +6261,17 @@ msgid "Check command replay storage connectivity" msgstr "检查命令及录像存储可连接性 " #: terminal/templates/terminal/_msg_command_alert.html:10 +#: terminal/templates/terminal/_msg_command_warning.html:5 +#: terminal/templates/terminal/_msg_command_warning.html:8 +#: terminal/templates/terminal/_msg_command_warning.html:11 +#: terminal/templates/terminal/_msg_command_warning.html:14 msgid "view" msgstr "查看" +#: terminal/templates/terminal/_msg_command_warning.html:13 +msgid "Command acl group" +msgstr "命令过滤组" + #: terminal/utils/db_port_mapper.py:84 msgid "" "No available port is matched. The number of databases may have exceeded the " @@ -7202,10 +7236,8 @@ msgid "Google Cloud Platform" msgstr "谷歌云" #: xpack/plugins/cloud/const.py:20 -#, fuzzy -#| msgid "Cloud" msgid "UCloud" -msgstr "云服务" +msgstr "" #: xpack/plugins/cloud/const.py:22 msgid "VMware" @@ -7623,10 +7655,8 @@ msgid "Test timeout" msgstr "测试超时时间" #: xpack/plugins/cloud/serializers/account_attrs.py:212 -#, fuzzy -#| msgid "Reject" msgid "Project" -msgstr "拒绝" +msgstr "" #: xpack/plugins/cloud/serializers/task.py:28 msgid "" @@ -7723,9 +7753,3 @@ msgstr "旗舰版" #: xpack/plugins/license/models.py:86 msgid "Community edition" msgstr "社区版" - -#~ msgid "e.g. http(s)://host" -#~ msgstr "如: http(s)://host" - -#~ msgid "Please enable cookies and try again." -#~ msgstr "设置你的浏览器支持cookie" diff --git a/apps/terminal/api/session/command.py b/apps/terminal/api/session/command.py index b855181b8..dc4778b80 100644 --- a/apps/terminal/api/session/command.py +++ b/apps/terminal/api/session/command.py @@ -6,11 +6,12 @@ from rest_framework import generics from rest_framework.fields import DateTimeField from rest_framework.response import Response +from acls.models import CommandFilterACL from terminal.models import CommandStorage, Session, Command from terminal.filters import CommandFilter from orgs.utils import current_org from common.api import JMSBulkModelViewSet -from common.utils import get_logger +from common.utils import get_logger, is_uuid from terminal.serializers import ( SessionCommandSerializer, InsecureCommandAlertSerializer ) @@ -18,7 +19,8 @@ from terminal.exceptions import StorageInvalid from terminal.backends import ( get_command_storage, get_multi_command_storage ) -from terminal.notifications import CommandAlertMessage +from terminal.notifications import CommandAlertMessage, CommandWarningMessage +from terminal.const import RiskLevelChoices logger = get_logger(__name__) __all__ = ['CommandViewSet', 'InsecureCommandAlertAPI'] @@ -199,7 +201,30 @@ class InsecureCommandAlertAPI(generics.CreateAPIView): serializer = InsecureCommandAlertSerializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) commands = serializer.validated_data + + acl_ids = [] + for cmd in commands: + acl_id = cmd.get('cmd_filter_acl') + if not is_uuid(acl_id): + continue + acl_ids.append(acl_id) + + acls = CommandFilterACL.objects.filter(id__in=acl_ids) + acls_mapper = {str(acl.id): acl for acl in acls} + for command in commands: - if command['risk_level'] >= settings.SECURITY_INSECURE_COMMAND_LEVEL: + risk_level = command.get('risk_level') + + if risk_level in [RiskLevelChoices.reject, RiskLevelChoices.review_reject]: CommandAlertMessage(command).publish_async() - return Response() + elif risk_level in [RiskLevelChoices.warning]: + acl_id = command.get('cmd_filter_acl') + acl = acls_mapper.get(acl_id) + if not acl: + logger.info(f'ACL not found: {acl_id}') + continue + for reviewer in acl.reviewers.all(): + CommandWarningMessage(reviewer, command).publish_async() + else: + logger.info(f'Risk level ignore: {risk_level}') + return Response({'msg': 'ok'}) diff --git a/apps/terminal/backends/command/models.py b/apps/terminal/backends/command/models.py index da535a17c..b56f8c673 100644 --- a/apps/terminal/backends/command/models.py +++ b/apps/terminal/backends/command/models.py @@ -8,12 +8,10 @@ from django.utils.translation import ugettext_lazy as _ from common.utils.common import lazyproperty from orgs.mixins.models import OrgModelMixin +from terminal.const import RiskLevelChoices class AbstractSessionCommand(OrgModelMixin): - class RiskLevelChoices(models.IntegerChoices): - ordinary = 0, _('Ordinary') - dangerous = 5, _('Dangerous') id = models.UUIDField(default=uuid.uuid4, primary_key=True) user = models.CharField(max_length=64, db_index=True, verbose_name=_("User")) @@ -23,7 +21,7 @@ class AbstractSessionCommand(OrgModelMixin): output = models.CharField(max_length=1024, blank=True, verbose_name=_("Output")) session = models.CharField(max_length=36, db_index=True, verbose_name=_("Session")) risk_level = models.SmallIntegerField( - default=RiskLevelChoices.ordinary, choices=RiskLevelChoices.choices, db_index=True, + default=RiskLevelChoices.accept, choices=RiskLevelChoices.choices, db_index=True, verbose_name=_("Risk level") ) timestamp = models.IntegerField(db_index=True) diff --git a/apps/terminal/const.py b/apps/terminal/const.py index 16f1f0341..b05de71bb 100644 --- a/apps/terminal/const.py +++ b/apps/terminal/const.py @@ -1,10 +1,19 @@ # -*- coding: utf-8 -*- # -from django.db.models import TextChoices +from django.db.models import TextChoices, IntegerChoices from django.utils.translation import ugettext_lazy as _ +class RiskLevelChoices(IntegerChoices): + accept = 0, _('Accept') + warning = 4, _('Warning') + reject = 5, _('Reject') + review_reject = 6, _('Review & Reject') + review_accept = 7, _('Review & Accept') + review_cancel = 8, _('Review & Cancel') + + class ReplayStorageType(TextChoices): null = 'null', 'Null', server = 'server', 'Server' diff --git a/apps/terminal/migrations/0023_command_risk_level.py b/apps/terminal/migrations/0023_command_risk_level.py index 6ada1b826..0b5ed6bb6 100644 --- a/apps/terminal/migrations/0023_command_risk_level.py +++ b/apps/terminal/migrations/0023_command_risk_level.py @@ -13,6 +13,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='command', name='risk_level', - field=models.SmallIntegerField(choices=[(0, 'Ordinary'), (5, 'Dangerous')], db_index=True, default=0, verbose_name='Risk level'), + field=models.SmallIntegerField(choices=[(0, 'Accept'), (4, 'Warning'), (5, 'Reject'), (6, 'Review & Reject'), (7, 'Review & Accept'), (8, 'Review & Cancel')], db_index=True, default=0, verbose_name='Risk level'), ), ] diff --git a/apps/terminal/notifications.py b/apps/terminal/notifications.py index 919bf9c65..804f8d44b 100644 --- a/apps/terminal/notifications.py +++ b/apps/terminal/notifications.py @@ -9,7 +9,7 @@ from common.utils import lazyproperty from common.utils.timezone import local_now_display from notifications.backends import BACKEND from notifications.models import SystemMsgSubscription -from notifications.notifications import SystemMessage +from notifications.notifications import SystemMessage, UserMessage from terminal.models import Session, Command from users.models import User @@ -26,13 +26,16 @@ class CommandAlertMixin: _get_message: Callable message_type_label: str + def __str__(self): + return str(self.message_type_label) + @lazyproperty def subject(self): _input = self.command['input'] if isinstance(_input, str): _input = _input.replace('\r\n', ' ').replace('\r', ' ').replace('\n', ' ') - subject = self.message_type_label + "%(cmd)s" % { + subject = self.message_type_label + ": %(cmd)s" % { 'cmd': _input } return subject @@ -61,6 +64,45 @@ class CommandAlertMixin: subscription.save() +class CommandWarningMessage(CommandAlertMixin, UserMessage): + message_type_label = _('Danger command warning') + + def __init__(self, user, command): + super().__init__(user) + self.command = command + + def get_html_msg(self) -> dict: + session = self.command.get('session') + session_url = reverse( + 'api-terminal:session-detail', kwargs={'pk': session}, + external=True, api_to_ui=True + ) + '?oid={}'.format(self.command['org_id']) + + asset = self.command.get('asset') + asset_url = reverse( + 'assets:asset-detail', kwargs={'pk': asset}, + api_to_ui=True, external=True, is_console=True + ) + '?oid={}'.format(self.command.get('org_id')) + + cmd_filter_acl = self.command.get('cmd_filter_acl') + cmd_group = self.command.get('cmd_group') + + context = { + "command": self.command['input'], + 'asset_url': asset_url, + 'session_url': session_url.replace( + '/terminal/sessions/', '/audit/sessions/sessions/' + ), + 'cmd_filter_acl_url': settings.SITE_URL + '/ui/#/console/perms/cmd-acls/%s/' % cmd_filter_acl, + 'cmd_group_url': settings.SITE_URL + '/ui/#/console/perms/cmd-groups/%s/' % cmd_group, + } + message = render_to_string('terminal/_msg_command_warning.html', context) + return { + 'subject': self.subject, + 'message': message + } + + class CommandAlertMessage(CommandAlertMixin, SystemMessage): category = CATEGORY category_label = CATEGORY_LABEL @@ -69,9 +111,6 @@ class CommandAlertMessage(CommandAlertMixin, SystemMessage): def __init__(self, command): self.command = command - def __str__(self): - return str(self.message_type_label) - @classmethod def gen_test_msg(cls): command = Command.objects.first() diff --git a/apps/terminal/serializers/command.py b/apps/terminal/serializers/command.py index c58fd93e6..b845c6609 100644 --- a/apps/terminal/serializers/command.py +++ b/apps/terminal/serializers/command.py @@ -6,6 +6,7 @@ from common.utils import pretty_string from common.serializers.fields import LabeledChoiceField from terminal.backends.command.models import AbstractSessionCommand from terminal.models import Command +from terminal.const import RiskLevelChoices __all__ = ['SessionCommandSerializer', 'InsecureCommandAlertSerializer'] @@ -18,7 +19,7 @@ class SimpleSessionCommandSerializer(serializers.ModelSerializer): input = serializers.CharField(max_length=2048, label=_("Command")) session = serializers.CharField(max_length=36, label=_("Session ID")) risk_level = LabeledChoiceField( - choices=AbstractSessionCommand.RiskLevelChoices.choices, + choices=RiskLevelChoices.choices, required=False, label=_("Risk level"), ) org_id = serializers.CharField( @@ -37,7 +38,17 @@ class SimpleSessionCommandSerializer(serializers.ModelSerializer): class InsecureCommandAlertSerializer(SimpleSessionCommandSerializer): - pass + cmd_filter_acl = serializers.CharField( + max_length=128, required=False, label=_("Command Filter ACL") + ) + cmd_group = serializers.CharField( + max_length=128, required=True, label=_("Command Group") + ) + + class Meta(SimpleSessionCommandSerializer.Meta): + fields = SimpleSessionCommandSerializer.Meta.fields + [ + 'cmd_filter_acl', 'cmd_group' + ] class SessionCommandSerializerMixin(serializers.Serializer): diff --git a/apps/terminal/templates/terminal/_msg_command_warning.html b/apps/terminal/templates/terminal/_msg_command_warning.html new file mode 100644 index 000000000..215129dbe --- /dev/null +++ b/apps/terminal/templates/terminal/_msg_command_warning.html @@ -0,0 +1,23 @@ +{% load i18n %} + +
+ {% trans 'Asset' %}: + {% trans 'view' %} +
+ {% trans 'Session' %}: + {% trans 'view' %} +
+ {% trans 'Command acl' %}: + {% trans 'view' %} +
+ {% trans 'Command acl group' %}: + {% trans 'view' %} +
+ {% trans 'Command' %}:
+ +
 {{ command }} 
+
+