From 7e6fa277193b97d8108c20bef34a0a79a6bb3081 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Fri, 10 Sep 2021 17:54:34 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=80=9A=E7=9F=A5=20?= =?UTF-8?q?(#6798)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: 优化通知 * perf: 优化危险命令提示 * fix: i18n * fix: i18n Co-authored-by: ibuler Co-authored-by: Michael Bai --- apps/locale/zh/LC_MESSAGES/django.mo | Bin 93382 -> 94985 bytes apps/locale/zh/LC_MESSAGES/django.po | 462 +++++++++++++------------- apps/notifications/notifications.py | 9 +- apps/settings/serializers/security.py | 2 +- apps/terminal/notifications.py | 101 +++--- 5 files changed, 290 insertions(+), 284 deletions(-) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index ab8fc5a7994ee8fa11e7d7012cfb0df67bd2f892..5217e3e638f0a8d329478dd58b805f0c1cb7cd86 100644 GIT binary patch delta 28693 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 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 45b34a9d4..7ed887ae4 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: 2021-09-10 16:13+0800\n" +"POT-Creation-Date: 2021-09-10 17:46+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -60,7 +60,7 @@ msgstr "激活中" #: orgs/models.py:27 perms/models/base.py:53 settings/models.py:34 #: terminal/models/storage.py:26 terminal/models/terminal.py:114 #: tickets/models/ticket.py:71 users/models/group.py:16 -#: users/models/user.py:637 xpack/plugins/change_auth_plan/models.py:88 +#: users/models/user.py:637 xpack/plugins/change_auth_plan/models/base.py:41 #: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:113 #: xpack/plugins/gathered_user/models.py:26 msgid "Comment" @@ -125,7 +125,7 @@ msgstr "系统用户" #: terminal/backends/command/serializers.py:13 terminal/models/session.py:40 #: users/templates/users/user_asset_permission.html:40 #: users/templates/users/user_asset_permission.html:70 -#: xpack/plugins/change_auth_plan/models.py:315 +#: xpack/plugins/change_auth_plan/models/asset.py:195 #: xpack/plugins/cloud/models.py:217 msgid "Asset" msgstr "资产" @@ -139,7 +139,7 @@ msgstr "审批人" msgid "Login asset confirm" msgstr "登录资产复核" -#: acls/serializers/login_acl.py:18 xpack/plugins/cloud/serializers.py:165 +#: acls/serializers/login_acl.py:18 xpack/plugins/cloud/serializers/task.py:23 msgid "IP address invalid: `{}`" msgstr "IP 地址无效: `{}`" @@ -179,9 +179,9 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. " #: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17 #: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:602 #: users/templates/users/_select_user_modal.html:14 -#: xpack/plugins/change_auth_plan/models.py:51 -#: xpack/plugins/change_auth_plan/models.py:311 -#: xpack/plugins/cloud/serializers.py:67 +#: xpack/plugins/change_auth_plan/models/asset.py:35 +#: xpack/plugins/change_auth_plan/models/asset.py:191 +#: xpack/plugins/cloud/serializers/account_attrs.py:62 msgid "Username" msgstr "用户名" @@ -234,6 +234,7 @@ msgstr "我的应用" #: applications/const.py:8 applications/models/account.py:10 #: applications/serializers/attrs/application_category/db.py:14 #: applications/serializers/attrs/application_type/mysql_workbench.py:26 +#: xpack/plugins/change_auth_plan/models/app.py:32 msgid "Database" msgstr "数据库" @@ -257,6 +258,8 @@ msgstr "自定义" #: users/templates/users/user_asset_permission.html:159 #: users/templates/users/user_database_app_permission.html:40 #: users/templates/users/user_database_app_permission.html:67 +#: xpack/plugins/change_auth_plan/models/app.py:36 +#: xpack/plugins/change_auth_plan/models/app.py:142 msgid "System user" msgstr "系统用户" @@ -266,7 +269,7 @@ msgid "Version" msgstr "版本" #: applications/models/account.py:18 xpack/plugins/cloud/models.py:82 -#: xpack/plugins/cloud/serializers.py:207 +#: xpack/plugins/cloud/serializers/task.py:65 msgid "Account" msgstr "账户" @@ -279,6 +282,7 @@ msgstr "应用管理" #: perms/models/application_permission.py:20 #: perms/serializers/application/user_permission.py:33 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:20 +#: xpack/plugins/change_auth_plan/models/app.py:25 msgid "Category" msgstr "类别" @@ -289,6 +293,8 @@ msgstr "类别" #: terminal/models/storage.py:55 terminal/models/storage.py:116 #: tickets/models/flow.py:51 tickets/models/ticket.py:48 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:27 +#: xpack/plugins/change_auth_plan/models/app.py:28 +#: xpack/plugins/change_auth_plan/models/app.py:148 msgid "Type" msgstr "类型" @@ -329,7 +335,7 @@ msgstr "集群" #: applications/serializers/attrs/application_category/db.py:11 #: ops/models/adhoc.py:146 settings/serializers/auth/radius.py:14 -#: xpack/plugins/cloud/serializers.py:65 +#: xpack/plugins/cloud/serializers/account_attrs.py:60 msgid "Host" msgstr "主机" @@ -339,7 +345,8 @@ msgstr "主机" #: applications/serializers/attrs/application_type/oracle.py:11 #: applications/serializers/attrs/application_type/pgsql.py:11 #: assets/models/asset.py:185 assets/models/domain.py:62 -#: settings/serializers/auth/radius.py:15 xpack/plugins/cloud/serializers.py:66 +#: settings/serializers/auth/radius.py:15 +#: xpack/plugins/cloud/serializers/account_attrs.py:61 msgid "Port" msgstr "端口" @@ -351,6 +358,7 @@ msgid "Application path" msgstr "应用路径" #: applications/serializers/attrs/application_category/remote_app.py:45 +#: xpack/plugins/cloud/serializers/account_attrs.py:44 msgid "This field is required." msgstr "该字段是必填项。" @@ -370,10 +378,10 @@ msgstr "目标URL" #: users/templates/users/user_otp_check_password.html:13 #: users/templates/users/user_password_update.html:43 #: users/templates/users/user_password_verify.html:18 -#: xpack/plugins/change_auth_plan/models.py:72 -#: xpack/plugins/change_auth_plan/models.py:207 -#: xpack/plugins/change_auth_plan/models.py:318 -#: xpack/plugins/cloud/serializers.py:69 +#: xpack/plugins/change_auth_plan/models/base.py:39 +#: xpack/plugins/change_auth_plan/models/base.py:114 +#: xpack/plugins/change_auth_plan/models/base.py:182 +#: xpack/plugins/cloud/serializers/account_attrs.py:64 msgid "Password" msgstr "密码" @@ -425,13 +433,13 @@ msgstr "系统平台" #: assets/models/asset.py:186 assets/serializers/asset.py:65 #: perms/serializers/asset/user_permission.py:41 -#: xpack/plugins/cloud/models.py:104 xpack/plugins/cloud/serializers.py:184 +#: xpack/plugins/cloud/models.py:104 xpack/plugins/cloud/serializers/task.py:42 msgid "Protocols" msgstr "协议组" #: assets/models/asset.py:189 assets/models/user.py:198 #: perms/models/asset_permission.py:100 -#: xpack/plugins/change_auth_plan/models.py:60 +#: xpack/plugins/change_auth_plan/models/asset.py:44 #: xpack/plugins/gathered_user/models.py:24 msgid "Nodes" msgstr "节点" @@ -520,7 +528,8 @@ msgstr "标签管理" #: assets/models/cmd_filter.py:67 assets/models/group.py:21 #: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:25 #: orgs/models.py:437 perms/models/base.py:51 users/models/user.py:645 -#: users/serializers/group.py:33 xpack/plugins/change_auth_plan/models.py:92 +#: users/serializers/group.py:33 +#: xpack/plugins/change_auth_plan/models/base.py:45 #: xpack/plugins/cloud/models.py:119 xpack/plugins/gathered_user/models.py:30 msgid "Created by" msgstr "创建者" @@ -548,7 +557,7 @@ msgid "Ok" msgstr "成功" #: assets/models/base.py:32 audits/models.py:102 -#: xpack/plugins/cloud/const.py:27 +#: xpack/plugins/cloud/const.py:28 msgid "Failed" msgstr "失败" @@ -560,15 +569,15 @@ msgstr "可连接性" msgid "Date verified" msgstr "校验日期" -#: assets/models/base.py:178 xpack/plugins/change_auth_plan/models.py:82 -#: xpack/plugins/change_auth_plan/models.py:214 -#: xpack/plugins/change_auth_plan/models.py:325 +#: assets/models/base.py:178 xpack/plugins/change_auth_plan/models/asset.py:54 +#: xpack/plugins/change_auth_plan/models/asset.py:126 +#: xpack/plugins/change_auth_plan/models/asset.py:202 msgid "SSH private key" msgstr "SSH密钥" -#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models.py:85 -#: xpack/plugins/change_auth_plan/models.py:210 -#: xpack/plugins/change_auth_plan/models.py:321 +#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models/asset.py:57 +#: xpack/plugins/change_auth_plan/models/asset.py:122 +#: xpack/plugins/change_auth_plan/models/asset.py:198 msgid "SSH public key" msgstr "SSH公钥" @@ -726,7 +735,7 @@ msgstr "ssh私钥" #: users/templates/users/user_asset_permission.html:41 #: users/templates/users/user_asset_permission.html:73 #: users/templates/users/user_asset_permission.html:158 -#: xpack/plugins/cloud/models.py:93 xpack/plugins/cloud/serializers.py:210 +#: xpack/plugins/cloud/models.py:93 xpack/plugins/cloud/serializers/task.py:68 msgid "Node" msgstr "节点" @@ -747,7 +756,7 @@ msgid "Username same with user" msgstr "用户名与用户相同" #: assets/models/user.py:200 assets/serializers/domain.py:28 -#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:56 +#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models/asset.py:40 msgid "Assets" msgstr "资产" @@ -1076,8 +1085,8 @@ msgstr "成功" #: terminal/models/session.py:52 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:53 #: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:45 -#: xpack/plugins/change_auth_plan/models.py:194 -#: xpack/plugins/change_auth_plan/models.py:340 +#: xpack/plugins/change_auth_plan/models/base.py:105 +#: xpack/plugins/change_auth_plan/models/base.py:189 #: xpack/plugins/gathered_user/models.py:76 msgid "Date start" msgstr "开始日期" @@ -1149,7 +1158,7 @@ msgid "MFA" msgstr "多因子认证" #: audits/models.py:111 terminal/models/sharing.py:88 -#: xpack/plugins/change_auth_plan/models.py:336 +#: xpack/plugins/change_auth_plan/models/base.py:187 #: xpack/plugins/cloud/models.py:176 msgid "Reason" msgstr "原因" @@ -1563,15 +1572,12 @@ msgstr "" "被临时 锁定 {block_time} 分钟)" #: authentication/errors.py:74 -#, fuzzy, python-brace-format -#| msgid "" -#| "The MFA type({mfa_type}) is not supported, You can also try {times_try} " -#| "times (The account will be temporarily locked for {block_time} minutes)" +#, python-brace-format msgid "" "The MFA type({mfa_type}) is not supportedYou can also try {times_try} times " "(The account will be temporarily locked for {block_time} minutes)" msgstr "" -"该({mfa_type}) MFA 类型不支持。 您还可以尝试 {times_try} 次(账号将被临时 锁" +"该 ({mfa_type}) MFA 类型不支持。 您还可以尝试 {times_try} 次(账号将被临时 锁" "定 {block_time} 分钟)" #: authentication/errors.py:79 @@ -2067,17 +2073,17 @@ msgid "Invalid SMS sign and template: {}" msgstr "无效的短信签名和模版: {}" #: common/message/backends/sms/__init__.py:43 -#, fuzzy -#| msgid "Alibaba Cloud" msgid "Alibaba cloud" msgstr "阿里云" #: common/message/backends/sms/__init__.py:44 -#, fuzzy -#| msgid "Tencent Cloud" msgid "Tencent cloud" msgstr "腾讯云" +#: common/message/backends/sms/__init__.py:74 +msgid "SMS provider not support: {}" +msgstr "不支持 SMS 服务商: {}" + #: common/message/backends/sms/alibaba.py:56 msgid "Signature does not match" msgstr "签名不匹配" @@ -2176,7 +2182,7 @@ msgid "Regularly perform" msgstr "定期执行" #: ops/mixin.py:106 ops/mixin.py:147 -#: xpack/plugins/change_auth_plan/serializers.py:60 +#: xpack/plugins/change_auth_plan/serializers/base.py:42 msgid "Periodic perform" msgstr "定时执行" @@ -2255,8 +2261,8 @@ msgstr "开始时间" msgid "End time" msgstr "完成时间" -#: ops/models/adhoc.py:246 xpack/plugins/change_auth_plan/models.py:197 -#: xpack/plugins/change_auth_plan/models.py:343 +#: ops/models/adhoc.py:246 xpack/plugins/change_auth_plan/models/base.py:108 +#: xpack/plugins/change_auth_plan/models/base.py:190 #: xpack/plugins/gathered_user/models.py:79 msgid "Time" msgstr "时间" @@ -2644,7 +2650,8 @@ msgstr "" "用户属性映射代表怎样将LDAP中用户属性映射到jumpserver用户上,username, name," "email 是jumpserver的用户需要属性" -#: settings/serializers/auth/ldap.py:58 xpack/plugins/cloud/serializers.py:211 +#: settings/serializers/auth/ldap.py:58 +#: xpack/plugins/cloud/serializers/task.py:69 #: xpack/plugins/gathered_user/serializers.py:20 msgid "Periodic display" msgstr "定时执行" @@ -2669,7 +2676,8 @@ msgstr "JumpServer 地址" msgid "Client Id" msgstr "客户端 ID" -#: settings/serializers/auth/oidc.py:18 xpack/plugins/cloud/serializers.py:33 +#: settings/serializers/auth/oidc.py:18 +#: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Client Secret" msgstr "客户端密钥" @@ -2762,10 +2770,8 @@ msgid "Enable SMS" msgstr "启用 SMS" #: settings/serializers/auth/sms.py:11 -#, fuzzy -#| msgid "Provider" msgid "SMS provider" -msgstr "云服务商" +msgstr "SMS 服务商" #: settings/serializers/auth/sms.py:15 settings/serializers/email.py:69 msgid "Signature" @@ -2773,7 +2779,7 @@ msgstr "署名" #: settings/serializers/auth/sms.py:16 msgid "Template" -msgstr "" +msgstr "模版" #: settings/serializers/auth/sms.py:20 msgid "Test phone" @@ -3145,14 +3151,12 @@ msgid "Enabled, Allows user active session to be shared with other users" msgstr "开启后允许用户分享已连接的资产会话给它人,协同工作" #: settings/serializers/security.py:115 -#, fuzzy -#| msgid "Login confirm" msgid "Login Confirm" msgstr "登录复核" #: settings/serializers/security.py:116 -msgid "After opening, please go to the personal information setting approver" -msgstr "开启后, 请前往个人信息设置审批人" +msgid "Enabled, please go to the user detail add approver" +msgstr "启用后, 请在用户详情中添加审批人" #: settings/serializers/sms.py:7 msgid "Label" @@ -3502,7 +3506,7 @@ msgstr "数据库应用" msgid "Perms" msgstr "权限管理" -#: templates/_nav.html:97 terminal/notifications.py:16 +#: templates/_nav.html:97 terminal/notifications.py:18 msgid "Sessions" msgstr "会话管理" @@ -3938,7 +3942,8 @@ msgstr "加入日期" msgid "Date left" msgstr "结束日期" -#: terminal/models/sharing.py:91 xpack/plugins/change_auth_plan/models.py:307 +#: terminal/models/sharing.py:91 +#: xpack/plugins/change_auth_plan/models/base.py:178 msgid "Finished" msgstr "结束" @@ -4010,52 +4015,45 @@ msgstr "命令存储" msgid "Replay storage" msgstr "录像存储" -#: terminal/notifications.py:50 +#: terminal/notifications.py:68 msgid "Danger command alert" msgstr "危险命令告警" -#: terminal/notifications.py:59 +#: terminal/notifications.py:81 #, python-format msgid "" "\n" -" Command: %(command)s\n" -"
\n" -" Asset: %(host_name)s (%(host_ip)s)\n" -"
\n" -" User: %(user)s\n" -"
\n" -" Level: %(risk_level)s\n" -"
\n" -" Session: session " +" Command: %(command)s\n" +"
\n" +" Asset: %(hostname)s (%(host_ip)s)\n" +"
\n" +" User: %(user)s\n" +"
\n" +" Level: %(risk_level)s\n" +"
\n" +" Session:
session " "detail\n" -"
\n" -" " +"
\n" +" " msgstr "" "\n" " 命令: %(command)s\n" "
\n" -" 资产: %(host_name)s (%(host_ip)s)\n" +" 资产: %(hostname)s (%(host_ip)s)\n" "
\n" " 用户: %(user)s\n" "
\n" " 等级: %(risk_level)s\n" "
\n" -" 会话: 会话详情\n" +" 会话: 会话详情\n" "
\n" " " -#: terminal/notifications.py:99 -#, python-format -msgid "" -"Insecure Command Alert: [%(name)s->%(login_from)s@%(remote_addr)s] $" -"%(command)s" -msgstr "危险命令告警: [%(name)s->%(login_from)s@%(remote_addr)s] $%(command)s" - -#: terminal/notifications.py:117 +#: terminal/notifications.py:116 msgid "Batch danger command alert" msgstr "批量危险命令告警" -#: terminal/notifications.py:128 +#: terminal/notifications.py:127 #, python-format msgid "" "\n" @@ -4080,17 +4078,13 @@ msgstr "" "
\n" " 等级: %(risk_level)s\n" "
\n" -"\n" +"
\n" " ----------------- 命令 ----------------
\n" " %(command)s
\n" " ----------------- 命令 ----------------
\n" +"
\n" " " -#: terminal/notifications.py:150 -#, python-format -msgid "Insecure Web Command Execution Alert: [%(name)s]" -msgstr "批量危险命令告警: [%(name)s]" - #: terminal/serializers/session.py:31 msgid "User ID" msgstr "用户 ID" @@ -5194,8 +5188,9 @@ msgstr "两次密码不一致" msgid "Is first login" msgstr "首次登录" -#: users/serializers/user.py:22 xpack/plugins/change_auth_plan/models.py:65 -#: xpack/plugins/change_auth_plan/serializers.py:33 +#: users/serializers/user.py:22 +#: xpack/plugins/change_auth_plan/models/base.py:32 +#: xpack/plugins/change_auth_plan/serializers/base.py:24 msgid "Password strategy" msgstr "密码策略" @@ -5584,154 +5579,163 @@ msgstr "* 新密码不能是最近 {} 次的密码" msgid "Reset password success, return to login page" msgstr "重置密码成功,返回到登录页面" +#: xpack/plugins/change_auth_plan/api/app.py:112 +#: xpack/plugins/change_auth_plan/api/asset.py:100 +msgid "The parameter 'action' must be [{}]" +msgstr "参数 'action' 必须是 [{}]" + #: xpack/plugins/change_auth_plan/meta.py:9 -#: xpack/plugins/change_auth_plan/models.py:100 -#: xpack/plugins/change_auth_plan/models.py:201 +#: xpack/plugins/change_auth_plan/models/asset.py:63 +#: xpack/plugins/change_auth_plan/models/asset.py:119 msgid "Change auth plan" msgstr "改密计划" -#: xpack/plugins/change_auth_plan/models.py:40 -msgid "Custom password" -msgstr "自定义密码" +#: xpack/plugins/change_auth_plan/models/app.py:41 +#: xpack/plugins/change_auth_plan/models/app.py:90 +msgid "Application change auth plan" +msgstr "应用改密计划执行" -#: xpack/plugins/change_auth_plan/models.py:41 -msgid "All assets use the same random password" -msgstr "使用相同的随机密码" +#: xpack/plugins/change_auth_plan/models/app.py:94 +#: xpack/plugins/change_auth_plan/models/app.py:146 +msgid "Application change auth plan execution" +msgstr "应用改密计划执行" -#: xpack/plugins/change_auth_plan/models.py:42 -msgid "All assets use different random password" -msgstr "使用不同的随机密码" +#: xpack/plugins/change_auth_plan/models/app.py:139 +msgid "App" +msgstr "应用" -#: xpack/plugins/change_auth_plan/models.py:46 +#: xpack/plugins/change_auth_plan/models/app.py:151 +msgid "Application change auth plan task" +msgstr "用用改密计划任务" + +#: xpack/plugins/change_auth_plan/models/asset.py:30 msgid "Append SSH KEY" -msgstr "" +msgstr "追加" -#: xpack/plugins/change_auth_plan/models.py:47 +#: xpack/plugins/change_auth_plan/models/asset.py:31 msgid "Empty and append SSH KEY" -msgstr "" +msgstr "清空所有并添加" -#: xpack/plugins/change_auth_plan/models.py:48 -msgid "Empty current user and append SSH KEY" -msgstr "" +#: xpack/plugins/change_auth_plan/models/asset.py:32 +msgid "Empty pre add and append SSH KEY" +msgstr "清空上次并添加" -#: xpack/plugins/change_auth_plan/models.py:69 -msgid "Password rules" -msgstr "密码规则" - -#: xpack/plugins/change_auth_plan/models.py:78 -#: xpack/plugins/change_auth_plan/serializers.py:35 -#, fuzzy -#| msgid "SSH Key Reset" +#: xpack/plugins/change_auth_plan/models/asset.py:50 +#: xpack/plugins/change_auth_plan/serializers/asset.py:34 msgid "SSH Key strategy" -msgstr "重置SSH密钥" +msgstr "SSH 密钥策略" -#: xpack/plugins/change_auth_plan/models.py:189 -msgid "Manual trigger" -msgstr "" - -#: xpack/plugins/change_auth_plan/models.py:190 -msgid "Timing trigger" -msgstr "" - -#: xpack/plugins/change_auth_plan/models.py:204 -msgid "Change auth plan snapshot" -msgstr "改密计划快照" - -#: xpack/plugins/change_auth_plan/models.py:218 -#: xpack/plugins/change_auth_plan/serializers.py:166 -msgid "Trigger mode" -msgstr "" - -#: xpack/plugins/change_auth_plan/models.py:223 -#: xpack/plugins/change_auth_plan/models.py:329 +#: xpack/plugins/change_auth_plan/models/asset.py:130 +#: xpack/plugins/change_auth_plan/models/asset.py:206 msgid "Change auth plan execution" msgstr "改密计划执行" -#: xpack/plugins/change_auth_plan/models.py:302 -msgid "Ready" -msgstr "准备" - -#: xpack/plugins/change_auth_plan/models.py:303 -msgid "Preflight check" -msgstr "改密前的校验" - -#: xpack/plugins/change_auth_plan/models.py:304 -msgid "Change auth" -msgstr "执行改密" - -#: xpack/plugins/change_auth_plan/models.py:305 -msgid "Verify auth" -msgstr "验证密码/密钥" - -#: xpack/plugins/change_auth_plan/models.py:306 -msgid "Keep auth" -msgstr "保存密码/密钥" - -#: xpack/plugins/change_auth_plan/models.py:333 -msgid "Step" -msgstr "步骤" - -#: xpack/plugins/change_auth_plan/models.py:350 +#: xpack/plugins/change_auth_plan/models/asset.py:213 msgid "Change auth plan task" msgstr "改密计划任务" -#: xpack/plugins/change_auth_plan/serializers.py:29 -#, fuzzy -#| msgid "Password" +#: xpack/plugins/change_auth_plan/models/base.py:24 +msgid "Custom password" +msgstr "自定义密码" + +#: xpack/plugins/change_auth_plan/models/base.py:25 +msgid "All assets use the same random password" +msgstr "使用相同的随机密码" + +#: xpack/plugins/change_auth_plan/models/base.py:26 +msgid "All assets use different random password" +msgstr "使用不同的随机密码" + +#: xpack/plugins/change_auth_plan/models/base.py:36 +msgid "Password rules" +msgstr "密码规则" + +#: xpack/plugins/change_auth_plan/models/base.py:100 +msgid "Manual trigger" +msgstr "手动触发" + +#: xpack/plugins/change_auth_plan/models/base.py:101 +msgid "Timing trigger" +msgstr "定时触发" + +#: xpack/plugins/change_auth_plan/models/base.py:111 +msgid "Change auth plan snapshot" +msgstr "改密计划快照" + +#: xpack/plugins/change_auth_plan/models/base.py:118 +#: xpack/plugins/change_auth_plan/serializers/base.py:70 +msgid "Trigger mode" +msgstr "触发模式" + +#: xpack/plugins/change_auth_plan/models/base.py:173 +msgid "Ready" +msgstr "准备" + +#: xpack/plugins/change_auth_plan/models/base.py:174 +msgid "Preflight check" +msgstr "改密前的校验" + +#: xpack/plugins/change_auth_plan/models/base.py:175 +msgid "Change auth" +msgstr "执行改密" + +#: xpack/plugins/change_auth_plan/models/base.py:176 +msgid "Verify auth" +msgstr "验证密码/密钥" + +#: xpack/plugins/change_auth_plan/models/base.py:177 +msgid "Keep auth" +msgstr "保存密码/密钥" + +#: xpack/plugins/change_auth_plan/models/base.py:185 +msgid "Step" +msgstr "步骤" + +#: xpack/plugins/change_auth_plan/serializers/asset.py:31 msgid "Change Password" -msgstr "密码" +msgstr "更改密码" -#: xpack/plugins/change_auth_plan/serializers.py:30 -#, fuzzy -#| msgid "Change by" +#: xpack/plugins/change_auth_plan/serializers/asset.py:32 msgid "Change SSH Key" -msgstr "修改者" +msgstr "修改 SSH Key" -#: xpack/plugins/change_auth_plan/serializers.py:61 +#: xpack/plugins/change_auth_plan/serializers/asset.py:65 +msgid "Require password strategy perform setting" +msgstr "需要密码策略设置" + +#: xpack/plugins/change_auth_plan/serializers/asset.py:68 +msgid "Require password perform setting" +msgstr "需要密码设置" + +#: xpack/plugins/change_auth_plan/serializers/asset.py:71 +msgid "Require password rule perform setting" +msgstr "需要密码规则设置" + +#: xpack/plugins/change_auth_plan/serializers/asset.py:87 +msgid "Require ssh key strategy or ssh key perform setting" +msgstr "需要 ssh key 策略 配置" + +#: xpack/plugins/change_auth_plan/serializers/base.py:43 msgid "Run times" msgstr "执行次数" -#: xpack/plugins/change_auth_plan/serializers.py:79 -#, fuzzy -#| msgid "Require periodic or regularly perform setting" -msgid "Require password strategy perform setting" -msgstr "需要周期或定期设置" - -#: xpack/plugins/change_auth_plan/serializers.py:82 -#, fuzzy -#| msgid "Require periodic or regularly perform setting" -msgid "Require password perform setting" -msgstr "需要周期或定期设置" - -#: xpack/plugins/change_auth_plan/serializers.py:85 -#, fuzzy -#| msgid "Require periodic or regularly perform setting" -msgid "Require password rule perform setting" -msgstr "需要周期或定期设置" - -#: xpack/plugins/change_auth_plan/serializers.py:97 +#: xpack/plugins/change_auth_plan/serializers/base.py:54 msgid "* Please enter the correct password length" msgstr "* 请输入正确的密码长度" -#: xpack/plugins/change_auth_plan/serializers.py:100 +#: xpack/plugins/change_auth_plan/serializers/base.py:57 msgid "* Password length range 6-30 bits" msgstr "* 密码长度范围 6-30 位" -#: xpack/plugins/change_auth_plan/serializers.py:118 -#, fuzzy -#| msgid "Require periodic or regularly perform setting" -msgid "Require ssh key strategy or ssh key perform setting" -msgstr "需要周期或定期设置" - -#: xpack/plugins/change_auth_plan/utils.py:485 +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:248 msgid "Invalid/incorrect password" msgstr "无效/错误 密码" -#: xpack/plugins/change_auth_plan/utils.py:487 +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:250 msgid "Failed to connect to the host" msgstr "连接主机失败" -#: xpack/plugins/change_auth_plan/utils.py:489 +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:252 msgid "Data could not be sent to remote" msgstr "无法将数据发送到远程" @@ -5787,31 +5791,35 @@ msgstr "华为私有云" msgid "Qingyun Private Cloud" msgstr "青云私有云" -#: xpack/plugins/cloud/const.py:22 +#: xpack/plugins/cloud/const.py:19 +msgid "Google Cloud Platform" +msgstr "谷歌云" + +#: xpack/plugins/cloud/const.py:23 msgid "Instance name" msgstr "实例名称" -#: xpack/plugins/cloud/const.py:23 +#: xpack/plugins/cloud/const.py:24 msgid "Instance name and Partial IP" msgstr "实例名称和部分IP" -#: xpack/plugins/cloud/const.py:28 +#: xpack/plugins/cloud/const.py:29 msgid "Succeed" msgstr "成功" -#: xpack/plugins/cloud/const.py:32 +#: xpack/plugins/cloud/const.py:33 msgid "Unsync" msgstr "未同步" -#: xpack/plugins/cloud/const.py:33 +#: xpack/plugins/cloud/const.py:34 msgid "New Sync" msgstr "新同步" -#: xpack/plugins/cloud/const.py:34 +#: xpack/plugins/cloud/const.py:35 msgid "Synced" msgstr "已同步" -#: xpack/plugins/cloud/const.py:35 +#: xpack/plugins/cloud/const.py:36 msgid "Released" msgstr "已释放" @@ -5827,7 +5835,7 @@ msgstr "云服务商" msgid "Cloud account" msgstr "云账号" -#: xpack/plugins/cloud/models.py:85 xpack/plugins/cloud/serializers.py:179 +#: xpack/plugins/cloud/models.py:85 xpack/plugins/cloud/serializers/task.py:37 msgid "Regions" msgstr "地域" @@ -5835,23 +5843,19 @@ msgstr "地域" msgid "Hostname strategy" msgstr "主机名策略" -#: xpack/plugins/cloud/models.py:97 xpack/plugins/cloud/serializers.py:208 -#, fuzzy -#| msgid "Only admin users" +#: xpack/plugins/cloud/models.py:97 xpack/plugins/cloud/serializers/task.py:66 msgid "Unix admin user" -msgstr "仅管理员" +msgstr "Unix 管理员" -#: xpack/plugins/cloud/models.py:101 xpack/plugins/cloud/serializers.py:209 -#, fuzzy -#| msgid "Only admin users" +#: xpack/plugins/cloud/models.py:101 xpack/plugins/cloud/serializers/task.py:67 msgid "Windows admin user" -msgstr "仅管理员" +msgstr "Windows 管理员" -#: xpack/plugins/cloud/models.py:107 xpack/plugins/cloud/serializers.py:187 +#: xpack/plugins/cloud/models.py:107 xpack/plugins/cloud/serializers/task.py:45 msgid "IP network segment group" msgstr "IP网段组" -#: xpack/plugins/cloud/models.py:110 xpack/plugins/cloud/serializers.py:212 +#: xpack/plugins/cloud/models.py:110 xpack/plugins/cloud/serializers/task.py:70 msgid "Always update" msgstr "总是更新" @@ -6019,35 +6023,40 @@ msgstr "西南-贵阳1" msgid "EU-Paris" msgstr "欧洲-巴黎" -#: xpack/plugins/cloud/serializers.py:21 +#: xpack/plugins/cloud/serializers/account_attrs.py:13 msgid "AccessKey ID" msgstr "" -#: xpack/plugins/cloud/serializers.py:24 +#: xpack/plugins/cloud/serializers/account_attrs.py:16 msgid "AccessKey Secret" msgstr "" -#: xpack/plugins/cloud/serializers.py:30 +#: xpack/plugins/cloud/serializers/account_attrs.py:23 msgid "Client ID" msgstr "客户端 ID" -#: xpack/plugins/cloud/serializers.py:36 +#: xpack/plugins/cloud/serializers/account_attrs.py:29 msgid "Tenant ID" msgstr "租户 ID" -#: xpack/plugins/cloud/serializers.py:39 +#: xpack/plugins/cloud/serializers/account_attrs.py:32 msgid "Subscription ID" msgstr "订阅 ID" -#: xpack/plugins/cloud/serializers.py:51 -msgid "This field is required" -msgstr "该字段是必填项。" - -#: xpack/plugins/cloud/serializers.py:85 xpack/plugins/cloud/serializers.py:89 +#: xpack/plugins/cloud/serializers/account_attrs.py:81 +#: xpack/plugins/cloud/serializers/account_attrs.py:86 msgid "API Endpoint" msgstr "API 端点" -#: xpack/plugins/cloud/serializers.py:171 +#: xpack/plugins/cloud/serializers/account_attrs.py:92 +msgid "Service account key" +msgstr "账户密钥" + +#: xpack/plugins/cloud/serializers/account_attrs.py:93 +msgid "The file is in JSON format" +msgstr "JSON 格式的文件" + +#: xpack/plugins/cloud/serializers/task.py:29 msgid "" "The IP address that is first matched to will be used as the IP of the " "created asset.
The default * indicates a random match.
Format for " @@ -6056,11 +6065,11 @@ msgstr "" "第一个匹配到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示随机匹配。" "
格式为以逗号分隔的字符串,例如:192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/cloud/serializers.py:177 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "History count" msgstr "执行次数" -#: xpack/plugins/cloud/serializers.py:178 +#: xpack/plugins/cloud/serializers/task.py:36 msgid "Instance count" msgstr "实例个数" @@ -6157,6 +6166,3 @@ msgstr "社区版" #~ msgid "Tencent" #~ msgstr "腾讯云" - -#~ msgid "* Please enter custom password" -#~ msgstr "* 请输入自定义密码" diff --git a/apps/notifications/notifications.py b/apps/notifications/notifications.py index 1141c104f..97ff30469 100644 --- a/apps/notifications/notifications.py +++ b/apps/notifications/notifications.py @@ -1,7 +1,6 @@ from typing import Iterable import traceback from itertools import chain -from collections import defaultdict from celery import shared_task @@ -90,6 +89,11 @@ class Message(metaclass=MessageType): except: traceback.print_exc() + def send_test_msg(self): + from users.models import User + users = User.objects.filter(username='admin') + self.send_msg(users, []) + def get_common_msg(self) -> dict: raise NotImplementedError @@ -115,7 +119,7 @@ class Message(metaclass=MessageType): return self.common_msg def get_sms_msg(self) -> dict: - raise NotImplementedError + return self.common_msg # -------------------------------------------------------------- @@ -136,6 +140,7 @@ class SystemMessage(Message): self.send_msg(users, receive_backends) + @classmethod def post_insert_to_db(cls, subscription: SystemMsgSubscription): pass diff --git a/apps/settings/serializers/security.py b/apps/settings/serializers/security.py index e2f8cb48d..1681b08a3 100644 --- a/apps/settings/serializers/security.py +++ b/apps/settings/serializers/security.py @@ -113,6 +113,6 @@ class SecuritySettingSerializer(SecurityPasswordRuleSerializer, SecurityAuthSeri ) LOGIN_CONFIRM_ENABLE = serializers.BooleanField( required=False, label=_('Login Confirm'), - help_text=_("After opening, please go to the personal information setting approver") + help_text=_("Enabled, please go to the user detail add approver") ) diff --git a/apps/terminal/notifications.py b/apps/terminal/notifications.py index 46ac5b18d..22e1acf6d 100644 --- a/apps/terminal/notifications.py +++ b/apps/terminal/notifications.py @@ -1,3 +1,5 @@ +from typing import Callable + from django.utils.translation import gettext_lazy as _ from django.conf import settings @@ -17,19 +19,35 @@ CATEGORY_LABEL = _('Sessions') class CommandAlertMixin: + command: dict + _get_message: Callable + message_type_label: str + def get_dingtalk_msg(self) -> str: msg = self._get_message() msg = msg.replace('
', '') return msg + def get_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" % { + 'cmd': _input + } + return subject + @classmethod def post_insert_to_db(cls, subscription: SystemMsgSubscription): """ - 兼容操作,试图用 `settings.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER` 的邮件地址assets_systemuser_assets找到 - 用户,把用户设置为默认接收者 + 兼容操作,试图用 `settings.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER` 的邮件地址 + assets_systemuser_assets找到用户,把用户设置为默认接收者 """ from settings.models import Setting - db_setting = Setting.objects.filter(name='SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER').first() + db_setting = Setting.objects.filter( + name='SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER' + ).first() if db_setting: emails = db_setting.value else: @@ -54,60 +72,41 @@ class CommandAlertMessage(CommandAlertMixin, SystemMessage): def _get_message(self): command = self.command - session_obj = Session.objects.get(id=command['session']) + session = Session.objects.get(id=command['session']) + session_detail_url = reverse( + 'api-terminal:session-detail', kwargs={'pk': command['session']}, + external=True, api_to_ui=True + ) message = _(""" - Command: %(command)s -
- Asset: %(host_name)s (%(host_ip)s) -
- User: %(user)s -
- Level: %(risk_level)s -
- Session: session detail -
- """) % { + Command: %(command)s +
+ Asset: %(hostname)s (%(host_ip)s) +
+ User: %(user)s +
+ Level: %(risk_level)s +
+ Session: session detail +
+ """) % { 'command': command['input'], - 'host_name': command['asset'], - 'host_ip': session_obj.asset_obj.ip, + 'hostname': command['asset'], + 'host_ip': session.asset_obj.ip, 'user': command['user'], 'risk_level': Command.get_risk_level_str(command['risk_level']), - 'session_detail_url': reverse('api-terminal:session-detail', - kwargs={'pk': command['session']}, - external=True, api_to_ui=True), + 'session_detail_url': session_detail_url, + 'oid': session.org_id } - return message def get_common_msg(self): msg = self._get_message() - - return { - 'subject': msg[:80], - 'message': msg - } - - def get_email_msg(self): - command = self.command - session_obj = Session.objects.get(id=command['session']) - - input = command['input'] - if isinstance(input, str): - input = input.replace('\r\n', ' ').replace('\r', ' ').replace('\n', ' ') - - subject = _("Insecure Command Alert: [%(name)s->%(login_from)s@%(remote_addr)s] $%(command)s") % { - 'name': command['user'], - 'login_from': session_obj.get_login_from_display(), - 'remote_addr': session_obj.remote_addr, - 'command': input - } - - message = self._get_message() + subject = self.get_subject() return { 'subject': subject, - 'message': message + 'message': msg } @@ -121,8 +120,8 @@ class CommandExecutionAlert(CommandAlertMixin, SystemMessage): def _get_message(self): command = self.command - input = command['input'] - input = input.replace('\n', '
') + _input = command['input'] + _input = _input.replace('\n', '
') assets = ', '.join([str(asset) for asset in command['assets']]) message = _(""" @@ -137,19 +136,15 @@ class CommandExecutionAlert(CommandAlertMixin, SystemMessage): %(command)s
----------------- Commands ----------------
""") % { - 'command': input, + 'command': _input, 'assets': assets, 'user': command['user'], - 'risk_level': Command.get_risk_level_str(command['risk_level']), + 'risk_level': Command.get_risk_level_str(command['risk_level']) } return message def get_common_msg(self): - command = self.command - - subject = _("Insecure Web Command Execution Alert: [%(name)s]") % { - 'name': command['user'], - } + subject = self.get_subject() message = self._get_message() return {