mirror of https://github.com/jumpserver/jumpserver
merge: with dev
commit
31da139eb3
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-28 10:38+0800\n"
|
||||
"POT-Creation-Date: 2023-07-25 15:37+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"
|
||||
|
@ -202,6 +202,7 @@ msgstr "作成のみ"
|
|||
#: terminal/backends/command/models.py:17 terminal/models/session/session.py:31
|
||||
#: terminal/notifications.py:155 terminal/serializers/command.py:17
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:4
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:4
|
||||
#: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:212
|
||||
msgid "Asset"
|
||||
msgstr "資産"
|
||||
|
@ -236,6 +237,7 @@ msgstr "ソース ID"
|
|||
#: perms/models/asset_permission.py:70 perms/serializers/permission.py:39
|
||||
#: terminal/backends/command/models.py:18 terminal/models/session/session.py:33
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:8
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:8
|
||||
#: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85
|
||||
msgid "Account"
|
||||
msgstr "アカウント"
|
||||
|
@ -314,7 +316,7 @@ msgid "Trigger mode"
|
|||
msgstr "トリガーモード"
|
||||
|
||||
#: accounts/models/automations/backup_account.py:97 audits/models.py:194
|
||||
#: terminal/models/session/sharing.py:111 xpack/plugins/cloud/models.py:168
|
||||
#: terminal/models/session/sharing.py:117 xpack/plugins/cloud/models.py:168
|
||||
msgid "Reason"
|
||||
msgstr "理由"
|
||||
|
||||
|
@ -655,10 +657,11 @@ msgstr "ID"
|
|||
#: perms/api/user_permission/mixin.py:55 perms/models/asset_permission.py:58
|
||||
#: perms/serializers/permission.py:30 rbac/builtin.py:123
|
||||
#: rbac/models/rolebinding.py:49 terminal/backends/command/models.py:16
|
||||
#: terminal/models/session/session.py:29 terminal/models/session/sharing.py:32
|
||||
#: terminal/models/session/session.py:29 terminal/models/session/sharing.py:33
|
||||
#: terminal/notifications.py:156 terminal/notifications.py:205
|
||||
#: terminal/serializers/command.py:16
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:6
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:6
|
||||
#: tickets/models/comment.py:21 users/const.py:14 users/models/user.py:947
|
||||
#: users/models/user.py:983 users/serializers/group.py:18
|
||||
msgid "User"
|
||||
|
@ -745,7 +748,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:76 terminal/models/session/sharing.py:107
|
||||
#: terminal/const.py:76 terminal/models/session/sharing.py:113
|
||||
#: tickets/views/approve.py:115
|
||||
msgid "Success"
|
||||
msgstr "成功"
|
||||
|
@ -829,7 +832,7 @@ msgstr "レビュー担当者"
|
|||
#: acls/models/base.py:43 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
|
||||
#: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:28
|
||||
#: tickets/const.py:37
|
||||
msgid "Active"
|
||||
msgstr "アクティブ"
|
||||
|
@ -1187,11 +1190,11 @@ msgstr "SSLの使用"
|
|||
|
||||
#: assets/const/protocol.py:127
|
||||
msgid "SYSDBA"
|
||||
msgstr ""
|
||||
msgstr "SYSDBA"
|
||||
|
||||
#: assets/const/protocol.py:128
|
||||
msgid "Connect as SYSDBA"
|
||||
msgstr ""
|
||||
msgstr "SYSDBA として接続"
|
||||
|
||||
#: assets/const/protocol.py:157
|
||||
msgid "Auth username"
|
||||
|
@ -2002,6 +2005,7 @@ msgstr "マップディレクトリ"
|
|||
|
||||
#: audits/const.py:23 rbac/tree.py:229
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:18
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:10
|
||||
msgid "View"
|
||||
msgstr "表示"
|
||||
|
||||
|
@ -2065,7 +2069,7 @@ msgid "Job audit log"
|
|||
msgstr "ジョブ監査ログ"
|
||||
|
||||
#: audits/models.py:51 audits/models.py:95 audits/models.py:166
|
||||
#: terminal/models/session/session.py:38 terminal/models/session/sharing.py:99
|
||||
#: terminal/models/session/session.py:38 terminal/models/session/sharing.py:105
|
||||
msgid "Remote addr"
|
||||
msgstr "リモートaddr"
|
||||
|
||||
|
@ -2082,8 +2086,8 @@ msgid "File"
|
|||
msgstr "書類"
|
||||
|
||||
#: audits/models.py:62 terminal/backends/command/models.py:21
|
||||
#: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18
|
||||
#: terminal/models/session/sharing.py:81
|
||||
#: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:19
|
||||
#: terminal/models/session/sharing.py:87
|
||||
#: terminal/templates/terminal/_msg_command_alert.html:10
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:17
|
||||
#: tickets/models/ticket/command_confirm.py:15
|
||||
|
@ -2944,7 +2948,8 @@ msgid "request new one"
|
|||
msgstr "新しいものを要求する"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password_code.html:12
|
||||
#: terminal/models/session/sharing.py:25 terminal/models/session/sharing.py:83
|
||||
#: terminal/models/session/sharing.py:26 terminal/models/session/sharing.py:89
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:12
|
||||
#: users/forms/profile.py:107 users/templates/users/forgot_password.html:66
|
||||
msgid "Verify code"
|
||||
msgstr "コードの確認"
|
||||
|
@ -3692,7 +3697,7 @@ msgstr "アルグ"
|
|||
|
||||
#: ops/models/adhoc.py:25 ops/models/base.py:16 ops/models/base.py:53
|
||||
#: ops/models/job.py:106 ops/models/job.py:192 ops/models/playbook.py:25
|
||||
#: terminal/models/session/sharing.py:23
|
||||
#: terminal/models/session/sharing.py:24
|
||||
msgid "Creator"
|
||||
msgstr "作成者"
|
||||
|
||||
|
@ -3733,7 +3738,7 @@ msgstr "タスクモニターを表示できます"
|
|||
msgid "Kwargs"
|
||||
msgstr "クワーグ"
|
||||
|
||||
#: ops/models/celery.py:61 terminal/models/session/sharing.py:114
|
||||
#: ops/models/celery.py:61 terminal/models/session/sharing.py:120
|
||||
#: tickets/const.py:25
|
||||
msgid "Finished"
|
||||
msgstr "終了"
|
||||
|
@ -3929,6 +3934,7 @@ msgstr "アプリ組織"
|
|||
#: rbac/const.py:7 rbac/models/rolebinding.py:56
|
||||
#: rbac/serializers/rolebinding.py:40 settings/serializers/auth/ldap.py:63
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:21
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:14
|
||||
#: tickets/models/ticket/general.py:302 tickets/serializers/ticket/ticket.py:60
|
||||
msgid "Organization"
|
||||
msgstr "組織"
|
||||
|
@ -6010,7 +6016,7 @@ msgstr "セッション再生をダウンロードできます"
|
|||
msgid "Account id"
|
||||
msgstr "アカウント ID"
|
||||
|
||||
#: terminal/models/session/session.py:36 terminal/models/session/sharing.py:104
|
||||
#: terminal/models/session/session.py:36 terminal/models/session/sharing.py:110
|
||||
msgid "Login from"
|
||||
msgstr "ログイン元"
|
||||
|
||||
|
@ -6042,7 +6048,7 @@ msgstr "セッションを終了できます"
|
|||
msgid "Can validate session action perm"
|
||||
msgstr "セッションアクションのパーマを検証できます"
|
||||
|
||||
#: terminal/models/session/sharing.py:30
|
||||
#: terminal/models/session/sharing.py:31
|
||||
msgid "Expired time (min)"
|
||||
msgstr "期限切れ時間 (分)"
|
||||
|
||||
|
@ -6051,47 +6057,52 @@ msgstr "期限切れ時間 (分)"
|
|||
msgid "Action permission"
|
||||
msgstr "アクションパーミッション"
|
||||
|
||||
#: terminal/models/session/sharing.py:40 terminal/models/session/sharing.py:86
|
||||
#: terminal/models/session/sharing.py:37
|
||||
msgid "Origin"
|
||||
msgstr "ソース"
|
||||
|
||||
#: terminal/models/session/sharing.py:41 terminal/models/session/sharing.py:92
|
||||
#: terminal/notifications.py:261
|
||||
msgid "Session sharing"
|
||||
msgstr "セッション共有"
|
||||
|
||||
#: terminal/models/session/sharing.py:42
|
||||
#: terminal/models/session/sharing.py:43
|
||||
msgid "Can add super session sharing"
|
||||
msgstr "スーパーセッション共有を追加できます"
|
||||
|
||||
#: terminal/models/session/sharing.py:69
|
||||
#: terminal/models/session/sharing.py:75
|
||||
msgid "Link not active"
|
||||
msgstr "リンクがアクティブでない"
|
||||
|
||||
#: terminal/models/session/sharing.py:71
|
||||
#: terminal/models/session/sharing.py:77
|
||||
msgid "Link expired"
|
||||
msgstr "リンク期限切れ"
|
||||
|
||||
#: terminal/models/session/sharing.py:73
|
||||
#: terminal/models/session/sharing.py:79
|
||||
msgid "User not allowed to join"
|
||||
msgstr "ユーザーはセッションに参加できません"
|
||||
|
||||
#: terminal/models/session/sharing.py:90 terminal/serializers/sharing.py:71
|
||||
#: terminal/models/session/sharing.py:96 terminal/serializers/sharing.py:71
|
||||
msgid "Joiner"
|
||||
msgstr "ジョイナー"
|
||||
|
||||
#: terminal/models/session/sharing.py:93
|
||||
#: terminal/models/session/sharing.py:99
|
||||
msgid "Date joined"
|
||||
msgstr "参加日"
|
||||
|
||||
#: terminal/models/session/sharing.py:96
|
||||
#: terminal/models/session/sharing.py:102
|
||||
msgid "Date left"
|
||||
msgstr "日付が残っています"
|
||||
|
||||
#: terminal/models/session/sharing.py:119
|
||||
#: terminal/models/session/sharing.py:125
|
||||
msgid "Session join record"
|
||||
msgstr "セッション参加記録"
|
||||
|
||||
#: terminal/models/session/sharing.py:135
|
||||
#: terminal/models/session/sharing.py:141
|
||||
msgid "Invalid verification code"
|
||||
msgstr "検証コードが無効"
|
||||
|
||||
#: terminal/models/session/sharing.py:142
|
||||
#: terminal/models/session/sharing.py:148
|
||||
msgid "You have already joined this session"
|
||||
msgstr "すでにこのセッションに参加しています"
|
||||
|
||||
|
@ -6400,6 +6411,10 @@ msgstr "チェックコマンドと録画ストレージの接続性"
|
|||
msgid "view"
|
||||
msgstr "表示"
|
||||
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:10
|
||||
msgid "Session sharing URL"
|
||||
msgstr "セッション共有 URL"
|
||||
|
||||
#: terminal/utils/db_port_mapper.py:85
|
||||
msgid ""
|
||||
"No available port is matched. The number of databases may have exceeded the "
|
||||
|
|
|
@ -201,6 +201,7 @@ msgstr "仅创建"
|
|||
#: terminal/backends/command/models.py:17 terminal/models/session/session.py:31
|
||||
#: terminal/notifications.py:155 terminal/serializers/command.py:17
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:4
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:4
|
||||
#: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:212
|
||||
msgid "Asset"
|
||||
msgstr "资产"
|
||||
|
@ -235,6 +236,7 @@ msgstr "来源 ID"
|
|||
#: perms/models/asset_permission.py:70 perms/serializers/permission.py:39
|
||||
#: terminal/backends/command/models.py:18 terminal/models/session/session.py:33
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:8
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:8
|
||||
#: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85
|
||||
msgid "Account"
|
||||
msgstr "账号"
|
||||
|
@ -313,7 +315,7 @@ msgid "Trigger mode"
|
|||
msgstr "触发模式"
|
||||
|
||||
#: accounts/models/automations/backup_account.py:97 audits/models.py:194
|
||||
#: terminal/models/session/sharing.py:111 xpack/plugins/cloud/models.py:168
|
||||
#: terminal/models/session/sharing.py:117 xpack/plugins/cloud/models.py:168
|
||||
msgid "Reason"
|
||||
msgstr "原因"
|
||||
|
||||
|
@ -651,10 +653,11 @@ msgstr "ID"
|
|||
#: perms/api/user_permission/mixin.py:55 perms/models/asset_permission.py:58
|
||||
#: perms/serializers/permission.py:30 rbac/builtin.py:123
|
||||
#: rbac/models/rolebinding.py:49 terminal/backends/command/models.py:16
|
||||
#: terminal/models/session/session.py:29 terminal/models/session/sharing.py:32
|
||||
#: terminal/models/session/session.py:29 terminal/models/session/sharing.py:33
|
||||
#: terminal/notifications.py:156 terminal/notifications.py:205
|
||||
#: terminal/serializers/command.py:16
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:6
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:6
|
||||
#: tickets/models/comment.py:21 users/const.py:14 users/models/user.py:947
|
||||
#: users/models/user.py:983 users/serializers/group.py:18
|
||||
msgid "User"
|
||||
|
@ -741,7 +744,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:76 terminal/models/session/sharing.py:107
|
||||
#: terminal/const.py:76 terminal/models/session/sharing.py:113
|
||||
#: tickets/views/approve.py:115
|
||||
msgid "Success"
|
||||
msgstr "成功"
|
||||
|
@ -825,7 +828,7 @@ msgstr "审批人"
|
|||
#: acls/models/base.py:43 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
|
||||
#: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:28
|
||||
#: tickets/const.py:37
|
||||
msgid "Active"
|
||||
msgstr "激活中"
|
||||
|
@ -1180,11 +1183,11 @@ msgstr "使用 SSL"
|
|||
|
||||
#: assets/const/protocol.py:127
|
||||
msgid "SYSDBA"
|
||||
msgstr ""
|
||||
msgstr "SYSDBA"
|
||||
|
||||
#: assets/const/protocol.py:128
|
||||
msgid "Connect as SYSDBA"
|
||||
msgstr ""
|
||||
msgstr "以 SYSDBA 角色连接"
|
||||
|
||||
#: assets/const/protocol.py:157
|
||||
msgid "Auth username"
|
||||
|
@ -1986,6 +1989,7 @@ msgstr "映射目录"
|
|||
|
||||
#: audits/const.py:23 rbac/tree.py:229
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:18
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:10
|
||||
msgid "View"
|
||||
msgstr "查看"
|
||||
|
||||
|
@ -2049,7 +2053,7 @@ msgid "Job audit log"
|
|||
msgstr "作业审计日志"
|
||||
|
||||
#: audits/models.py:51 audits/models.py:95 audits/models.py:166
|
||||
#: terminal/models/session/session.py:38 terminal/models/session/sharing.py:99
|
||||
#: terminal/models/session/session.py:38 terminal/models/session/sharing.py:105
|
||||
msgid "Remote addr"
|
||||
msgstr "远端地址"
|
||||
|
||||
|
@ -2066,8 +2070,8 @@ msgid "File"
|
|||
msgstr "文件"
|
||||
|
||||
#: audits/models.py:62 terminal/backends/command/models.py:21
|
||||
#: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18
|
||||
#: terminal/models/session/sharing.py:81
|
||||
#: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:19
|
||||
#: terminal/models/session/sharing.py:87
|
||||
#: terminal/templates/terminal/_msg_command_alert.html:10
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:17
|
||||
#: tickets/models/ticket/command_confirm.py:15
|
||||
|
@ -2908,7 +2912,8 @@ msgid "request new one"
|
|||
msgstr "重新申请"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password_code.html:12
|
||||
#: terminal/models/session/sharing.py:25 terminal/models/session/sharing.py:83
|
||||
#: terminal/models/session/sharing.py:26 terminal/models/session/sharing.py:89
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:12
|
||||
#: users/forms/profile.py:107 users/templates/users/forgot_password.html:66
|
||||
msgid "Verify code"
|
||||
msgstr "验证码"
|
||||
|
@ -3645,7 +3650,7 @@ msgstr "参数"
|
|||
|
||||
#: ops/models/adhoc.py:25 ops/models/base.py:16 ops/models/base.py:53
|
||||
#: ops/models/job.py:106 ops/models/job.py:192 ops/models/playbook.py:25
|
||||
#: terminal/models/session/sharing.py:23
|
||||
#: terminal/models/session/sharing.py:24
|
||||
msgid "Creator"
|
||||
msgstr "创建者"
|
||||
|
||||
|
@ -3686,7 +3691,7 @@ msgstr "可以查看任务监控"
|
|||
msgid "Kwargs"
|
||||
msgstr "其它参数"
|
||||
|
||||
#: ops/models/celery.py:61 terminal/models/session/sharing.py:114
|
||||
#: ops/models/celery.py:61 terminal/models/session/sharing.py:120
|
||||
#: tickets/const.py:25
|
||||
msgid "Finished"
|
||||
msgstr "结束"
|
||||
|
@ -3881,6 +3886,7 @@ msgstr "组织管理"
|
|||
#: rbac/const.py:7 rbac/models/rolebinding.py:56
|
||||
#: rbac/serializers/rolebinding.py:40 settings/serializers/auth/ldap.py:63
|
||||
#: terminal/templates/terminal/_msg_command_warning.html:21
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:14
|
||||
#: tickets/models/ticket/general.py:302 tickets/serializers/ticket/ticket.py:60
|
||||
msgid "Organization"
|
||||
msgstr "组织"
|
||||
|
@ -5923,7 +5929,7 @@ msgstr "可以下载会话录像"
|
|||
msgid "Account id"
|
||||
msgstr "账号 ID"
|
||||
|
||||
#: terminal/models/session/session.py:36 terminal/models/session/sharing.py:104
|
||||
#: terminal/models/session/session.py:36 terminal/models/session/sharing.py:110
|
||||
msgid "Login from"
|
||||
msgstr "登录来源"
|
||||
|
||||
|
@ -5955,7 +5961,7 @@ msgstr "可以终断会话"
|
|||
msgid "Can validate session action perm"
|
||||
msgstr "可以验证会话动作权限"
|
||||
|
||||
#: terminal/models/session/sharing.py:30
|
||||
#: terminal/models/session/sharing.py:31
|
||||
msgid "Expired time (min)"
|
||||
msgstr "过期时间 (分)"
|
||||
|
||||
|
@ -5964,47 +5970,52 @@ msgstr "过期时间 (分)"
|
|||
msgid "Action permission"
|
||||
msgstr "操作权限"
|
||||
|
||||
#: terminal/models/session/sharing.py:40 terminal/models/session/sharing.py:86
|
||||
#: terminal/models/session/sharing.py:37
|
||||
msgid "Origin"
|
||||
msgstr "来源"
|
||||
|
||||
#: terminal/models/session/sharing.py:41 terminal/models/session/sharing.py:92
|
||||
#: terminal/notifications.py:261
|
||||
msgid "Session sharing"
|
||||
msgstr "会话分享"
|
||||
|
||||
#: terminal/models/session/sharing.py:42
|
||||
#: terminal/models/session/sharing.py:43
|
||||
msgid "Can add super session sharing"
|
||||
msgstr "可以创建超级会话分享"
|
||||
|
||||
#: terminal/models/session/sharing.py:69
|
||||
#: terminal/models/session/sharing.py:75
|
||||
msgid "Link not active"
|
||||
msgstr "链接失效"
|
||||
|
||||
#: terminal/models/session/sharing.py:71
|
||||
#: terminal/models/session/sharing.py:77
|
||||
msgid "Link expired"
|
||||
msgstr "链接过期"
|
||||
|
||||
#: terminal/models/session/sharing.py:73
|
||||
#: terminal/models/session/sharing.py:79
|
||||
msgid "User not allowed to join"
|
||||
msgstr "该用户无权加入会话"
|
||||
|
||||
#: terminal/models/session/sharing.py:90 terminal/serializers/sharing.py:71
|
||||
#: terminal/models/session/sharing.py:96 terminal/serializers/sharing.py:71
|
||||
msgid "Joiner"
|
||||
msgstr "加入者"
|
||||
|
||||
#: terminal/models/session/sharing.py:93
|
||||
#: terminal/models/session/sharing.py:99
|
||||
msgid "Date joined"
|
||||
msgstr "加入日期"
|
||||
|
||||
#: terminal/models/session/sharing.py:96
|
||||
#: terminal/models/session/sharing.py:102
|
||||
msgid "Date left"
|
||||
msgstr "结束日期"
|
||||
|
||||
#: terminal/models/session/sharing.py:119
|
||||
#: terminal/models/session/sharing.py:125
|
||||
msgid "Session join record"
|
||||
msgstr "会话加入记录"
|
||||
|
||||
#: terminal/models/session/sharing.py:135
|
||||
#: terminal/models/session/sharing.py:141
|
||||
msgid "Invalid verification code"
|
||||
msgstr "验证码不正确"
|
||||
|
||||
#: terminal/models/session/sharing.py:142
|
||||
#: terminal/models/session/sharing.py:148
|
||||
msgid "You have already joined this session"
|
||||
msgstr "您已经加入过此会话"
|
||||
|
||||
|
@ -6308,6 +6319,10 @@ msgstr "检查命令及录像存储可连接性 "
|
|||
msgid "view"
|
||||
msgstr "查看"
|
||||
|
||||
#: terminal/templates/terminal/_msg_session_sharing.html:10
|
||||
msgid "Session sharing URL"
|
||||
msgstr "会话分享 URL"
|
||||
|
||||
#: terminal/utils/db_port_mapper.py:85
|
||||
msgid ""
|
||||
"No available port is matched. The number of databases may have exceeded the "
|
||||
|
|
|
@ -4,13 +4,14 @@ from rest_framework.permissions import AllowAny
|
|||
|
||||
from common.permissions import IsValidUserOrConnectionToken
|
||||
from common.utils import get_logger, lazyproperty
|
||||
from common.utils.timezone import local_now
|
||||
from jumpserver.utils import has_valid_xpack_license, get_xpack_license_info
|
||||
from .. import serializers
|
||||
from ..utils import get_interface_setting_or_default
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
__all__ = ['PublicSettingApi', 'OpenPublicSettingApi']
|
||||
__all__ = ['PublicSettingApi', 'OpenPublicSettingApi', 'ServerInfoApi']
|
||||
|
||||
|
||||
class OpenPublicSettingApi(generics.RetrieveAPIView):
|
||||
|
@ -55,3 +56,13 @@ class PublicSettingApi(OpenPublicSettingApi):
|
|||
# 提前把异常爆出来
|
||||
values[name] = getattr(settings, name)
|
||||
return values
|
||||
|
||||
|
||||
class ServerInfoApi(generics.RetrieveAPIView):
|
||||
permission_classes = (IsValidUserOrConnectionToken,)
|
||||
serializer_class = serializers.ServerInfoSerializer
|
||||
|
||||
def get_object(self):
|
||||
return {
|
||||
"CURRENT_TIME": local_now(),
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
from rest_framework import serializers
|
||||
|
||||
__all__ = ['PublicSettingSerializer', 'PrivateSettingSerializer']
|
||||
__all__ = [
|
||||
'PublicSettingSerializer', 'PrivateSettingSerializer', 'ServerInfoSerializer'
|
||||
]
|
||||
|
||||
|
||||
class PublicSettingSerializer(serializers.Serializer):
|
||||
|
@ -50,3 +52,7 @@ class PrivateSettingSerializer(PublicSettingSerializer):
|
|||
|
||||
TICKETS_ENABLED = serializers.BooleanField()
|
||||
CONNECTION_TOKEN_REUSABLE = serializers.BooleanField()
|
||||
|
||||
|
||||
class ServerInfoSerializer(serializers.Serializer):
|
||||
CURRENT_TIME = serializers.DateTimeField()
|
||||
|
|
|
@ -23,4 +23,5 @@ urlpatterns = [
|
|||
path('logo/', api.SettingsLogoApi.as_view(), name='settings-logo'),
|
||||
path('public/', api.PublicSettingApi.as_view(), name='public-setting'),
|
||||
path('public/open/', api.OpenPublicSettingApi.as_view(), name='open-public-setting'),
|
||||
path('server-info/', api.ServerInfoApi.as_view(), name='server-info'),
|
||||
]
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
#
|
||||
|
||||
from .ldap import *
|
||||
from .common import *
|
||||
from .ping import *
|
||||
from .telnet import *
|
||||
from .nmap import *
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import time
|
||||
import nmap
|
||||
|
||||
from IPy import IP
|
||||
|
||||
from common.utils.timezone import local_now_display
|
||||
|
||||
|
||||
def generate_ips(ip_string):
|
||||
# 支持的格式
|
||||
# 192.168.1.1-12 | 192.168.1.1-192.168.1.12 | 192.168.1.0/30 | 192.168.1.1
|
||||
ip_list = ip_string.split('-')
|
||||
ips = []
|
||||
try:
|
||||
if len(ip_list) == 2:
|
||||
start_ip, end_ip = ip_list
|
||||
if ip_list[1].find('.') == -1:
|
||||
end_ip = start_ip[:start_ip.rindex('.') + 1] + end_ip
|
||||
for ip in range(IP(start_ip).int(), IP(end_ip).int() + 1):
|
||||
ips.extend(IP(ip))
|
||||
else:
|
||||
ips.extend(IP(ip_list[0]))
|
||||
except Exception:
|
||||
ips = []
|
||||
return ips
|
||||
|
||||
|
||||
def once_nmap(nm, ip, ports, timeout, display):
|
||||
nmap_version = '.'.join(map(lambda x: str(x), nm.nmap_version()))
|
||||
display(f'Starting Nmap {nmap_version} at {local_now_display()} for {ip}')
|
||||
try:
|
||||
is_ok = True
|
||||
nm.scan(ip, arguments='-sS -sU -F', ports=ports, timeout=timeout)
|
||||
tcp_port = nm[ip].get('tcp', {})
|
||||
udp_port = nm[ip].get('udp', {})
|
||||
display(f'PORT\tSTATE\tSERVICE')
|
||||
for port, info in tcp_port.items():
|
||||
display(f"{port}\t{info.get('state', 'unknown')}\t{info.get('name', 'unknown')}")
|
||||
for port, info in udp_port.items():
|
||||
display(f"{port}\t{info.get('state', 'unknown')}\t{info.get('name', 'unknown')}")
|
||||
except Exception:
|
||||
is_ok = False
|
||||
display(f'Nmap scan report for {ip} error.')
|
||||
return is_ok
|
||||
|
||||
|
||||
def verbose_nmap(dest_ip, dest_port=None, timeout=None, display=print):
|
||||
dest_port = ','.join(list(dest_port)) if dest_port else None
|
||||
|
||||
ips = generate_ips(dest_ip)
|
||||
nm = nmap.PortScanner()
|
||||
success_num, start_time = 0, time.time()
|
||||
display(f'[Summary] Nmap: {len(ips)} IP addresses were scanned')
|
||||
for ip in ips:
|
||||
ok = once_nmap(nm, str(ip), dest_port, timeout, display)
|
||||
if ok:
|
||||
success_num += 1
|
||||
display('')
|
||||
display(f'[Done] Nmap: {len(ips)} IP addresses ({success_num} hosts up) '
|
||||
f'scanned in {round(time.time() - start_time, 2)} seconds')
|
|
@ -128,30 +128,37 @@ def ping(dest_addr, timeout, psize, flag=0):
|
|||
return delay
|
||||
|
||||
|
||||
def verbose_ping(dest_addr, timeout=2, count=5, psize=64, display=None):
|
||||
def verbose_ping(dest_ip, timeout=2, count=5, psize=64, display=None):
|
||||
"""
|
||||
Send `count' ping with `psize' size to `dest_addr' with
|
||||
the given `timeout' and display the result.
|
||||
"""
|
||||
ip = lookup_domain(dest_addr)
|
||||
ip = lookup_domain(dest_ip)
|
||||
if not ip:
|
||||
return
|
||||
if display is None:
|
||||
display = print
|
||||
display("PING %s (%s): 56 data bytes" % (dest_addr, ip))
|
||||
error_count = 0
|
||||
display("PING %s (%s): 56 data bytes" % (dest_ip, ip))
|
||||
for i in range(count):
|
||||
try:
|
||||
delay = ping(dest_addr, timeout, psize)
|
||||
delay = ping(dest_ip, timeout, psize)
|
||||
except socket.gaierror as e:
|
||||
display("failed. (socket error: '%s')" % str(e))
|
||||
error_count += 1
|
||||
break
|
||||
|
||||
if delay is None:
|
||||
display("Request timeout for icmp_seq %i" % i)
|
||||
error_count += 1
|
||||
else:
|
||||
delay = delay * 1000
|
||||
delay *= 1000
|
||||
display("64 bytes from %s: icmp_seq=0 ttl=115 time=%.3f ms" % (ip, delay))
|
||||
time.sleep(1)
|
||||
display(f'--- {dest_ip} ping statistics ---')
|
||||
display(f'{count} packets transmitted, '
|
||||
f'{count - error_count} packets received, '
|
||||
f'{(error_count / count) * 100}% packet loss')
|
||||
print()
|
||||
|
||||
|
||||
|
|
|
@ -18,21 +18,21 @@ def telnet(dest_addr, port_number=23, timeout=10):
|
|||
return True, output.decode('utf-8', 'ignore')
|
||||
|
||||
|
||||
def verbose_telnet(dest_addr, port_number=23, timeout=10, display=None):
|
||||
def verbose_telnet(dest_ip, dest_port=23, timeout=10, display=None):
|
||||
if display is None:
|
||||
display = print
|
||||
ip = lookup_domain(dest_addr)
|
||||
ip = lookup_domain(dest_ip)
|
||||
if not ip:
|
||||
return
|
||||
msg = 'Trying %s (%s:%s)' % (dest_addr, ip, port_number)
|
||||
msg = 'Trying %s (%s:%s)' % (dest_ip, ip, dest_port)
|
||||
display(msg)
|
||||
try:
|
||||
is_connective, resp = telnet(dest_addr, port_number, timeout)
|
||||
is_connective, resp = telnet(dest_ip, dest_port, timeout)
|
||||
if is_connective:
|
||||
template = 'Connected to {0} {1}.\r\n{2}Connection closed by foreign host.'
|
||||
else:
|
||||
template = 'telnet: connect to {0} {1} {2}\r\ntelnet: Unable to connect to remote host'
|
||||
msg = template.format(dest_addr, port_number, resp)
|
||||
msg = template.format(dest_ip, dest_port, resp)
|
||||
except Exception as e:
|
||||
msg = 'Error: %s' % e
|
||||
display(msg)
|
||||
|
|
|
@ -7,7 +7,7 @@ from channels.generic.websocket import JsonWebsocketConsumer
|
|||
|
||||
from common.db.utils import close_old_connections
|
||||
from common.utils import get_logger
|
||||
from .utils import verbose_ping, verbose_telnet
|
||||
from .utils import verbose_ping, verbose_telnet, verbose_nmap
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
@ -24,27 +24,28 @@ class ToolsWebsocket(JsonWebsocketConsumer):
|
|||
def send_msg(self, msg):
|
||||
self.send_json({'msg': msg + '\r\n'})
|
||||
|
||||
def imitate_ping(self, dest_addr, timeout=3, count=5, psize=64):
|
||||
def imitate_ping(self, dest_ip, timeout=3, count=5, psize=64):
|
||||
"""
|
||||
Send `count' ping with `psize' size to `dest_addr' with
|
||||
Send `count' ping with `psize' size to `dest_ip' with
|
||||
the given `timeout' and display the result.
|
||||
"""
|
||||
logger.info('receive request ping {}'.format(dest_addr))
|
||||
verbose_ping(dest_addr, timeout, count, psize, display=self.send_msg)
|
||||
logger.info('receive request ping {}'.format(dest_ip))
|
||||
verbose_ping(dest_ip, timeout, count, psize, display=self.send_msg)
|
||||
|
||||
def imitate_telnet(self, dest_addr, port_num=23, timeout=10):
|
||||
logger.info('receive request telnet {}'.format(dest_addr))
|
||||
verbose_telnet(dest_addr, port_num, timeout, display=self.send_msg)
|
||||
def imitate_telnet(self, dest_ip, dest_port=23, timeout=10):
|
||||
logger.info('receive request telnet {}'.format(dest_ip))
|
||||
verbose_telnet(dest_ip, dest_port, timeout, display=self.send_msg)
|
||||
|
||||
def imitate_nmap(self, dest_ip, dest_port=None, timeout=None):
|
||||
logger.info('receive request nmap {}'.format(dest_ip))
|
||||
verbose_nmap(dest_ip, dest_port, timeout, display=self.send_msg)
|
||||
|
||||
def receive(self, text_data=None, bytes_data=None, **kwargs):
|
||||
data = json.loads(text_data)
|
||||
tool_type = data.get('tool_type', 'Ping')
|
||||
dest_addr = data.get('dest_addr')
|
||||
if tool_type == 'Ping':
|
||||
self.imitate_ping(dest_addr)
|
||||
else:
|
||||
port_num = data.get('port_num')
|
||||
self.imitate_telnet(dest_addr, port_num)
|
||||
tool_type = data.pop('tool_type', 'Ping')
|
||||
|
||||
tool_func = getattr(self, f'imitate_{tool_type.lower()}')
|
||||
tool_func(**data)
|
||||
self.close()
|
||||
|
||||
def disconnect(self, code):
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.1.10 on 2023-07-26 10:55
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('terminal', '0063_auto_20230621_1133'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='sessionsharing',
|
||||
name='origin',
|
||||
field=models.URLField(blank=True, null=True, verbose_name='Origin'),
|
||||
),
|
||||
]
|
|
@ -3,6 +3,7 @@ import datetime
|
|||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from common.db.models import JMSBaseModel
|
||||
from orgs.mixins.models import OrgModelMixin
|
||||
|
@ -30,10 +31,10 @@ class SessionSharing(JMSBaseModel, OrgModelMixin):
|
|||
default=0, verbose_name=_('Expired time (min)'), db_index=True
|
||||
)
|
||||
users = models.TextField(blank=True, verbose_name=_("User"))
|
||||
|
||||
action_permission = models.CharField(
|
||||
max_length=16, verbose_name=_('Action permission'), default='writable'
|
||||
)
|
||||
origin = models.URLField(blank=True, null=True, verbose_name=_('Origin'))
|
||||
|
||||
class Meta:
|
||||
ordering = ('-date_created',)
|
||||
|
@ -45,15 +46,24 @@ class SessionSharing(JMSBaseModel, OrgModelMixin):
|
|||
def __str__(self):
|
||||
return 'Creator: {}'.format(self.creator)
|
||||
|
||||
@cached_property
|
||||
def url(self):
|
||||
return '%s/koko/share/%s/' % (self.origin, self.id)
|
||||
|
||||
@cached_property
|
||||
def users_display(self):
|
||||
if not self.users:
|
||||
return []
|
||||
with tmp_to_root_org():
|
||||
user_ids = self.users.split(',')
|
||||
users = User.objects.filter(id__in=user_ids)
|
||||
users = self.users_queryset
|
||||
users = [str(user) for user in users]
|
||||
return users
|
||||
|
||||
@cached_property
|
||||
def users_queryset(self):
|
||||
user_ids = self.users.split(',')
|
||||
return User.objects.filter(id__in=user_ids)
|
||||
|
||||
@property
|
||||
def date_expired(self):
|
||||
return self.date_created + datetime.timedelta(minutes=self.expired_time)
|
||||
|
|
|
@ -255,3 +255,27 @@ class StorageConnectivityMessage(SystemMessage):
|
|||
'subject': subject,
|
||||
'message': message
|
||||
}
|
||||
|
||||
|
||||
class SessionSharingMessage(UserMessage):
|
||||
message_type_label = _('Session sharing')
|
||||
|
||||
def __init__(self, user, instance):
|
||||
super().__init__(user)
|
||||
self.instance = instance
|
||||
|
||||
def get_html_msg(self) -> dict:
|
||||
instance = self.instance
|
||||
context = {
|
||||
'asset': instance.session.asset,
|
||||
'created_by': instance.created_by,
|
||||
'account': instance.session.account,
|
||||
'url': instance.url,
|
||||
'verify_code': instance.verify_code,
|
||||
'org': instance.org_name,
|
||||
}
|
||||
message = render_to_string('terminal/_msg_session_sharing.html', context)
|
||||
return {
|
||||
'subject': self.message_type_label + ' ' + self.instance.created_by,
|
||||
'message': message
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class SessionSharingSerializer(OrgResourceModelSerializerMixin):
|
|||
fields_small = fields_mini + [
|
||||
'verify_code', 'is_active', 'expired_time', 'created_by',
|
||||
'date_created', 'date_updated', 'users', 'users_display',
|
||||
'action_permission'
|
||||
'action_permission', 'origin', 'url',
|
||||
]
|
||||
fields_fk = ['session', 'creator']
|
||||
fields = fields_small + fields_fk
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from .applet import *
|
||||
from .db_port import *
|
||||
from .terminal import *
|
||||
from .session_sharing import *
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from terminal.models import SessionSharing
|
||||
from terminal.notifications import SessionSharingMessage
|
||||
|
||||
|
||||
@receiver(post_save, sender=SessionSharing)
|
||||
def on_session_sharing_created(sender, instance: SessionSharing, created, **kwargs):
|
||||
if not created:
|
||||
return
|
||||
for user in instance.users_queryset:
|
||||
SessionSharingMessage(user, instance).publish_async()
|
|
@ -0,0 +1,16 @@
|
|||
{% load i18n %}
|
||||
|
||||
<div>
|
||||
<b>{% trans 'Asset' %}: </b> <span>{{ asset }}</span>
|
||||
<br/>
|
||||
<b>{% trans 'User' %}: </b> <span>{{ created_by }}</span>
|
||||
<br/>
|
||||
<b>{% trans 'Account' %}: </b> <span>{{ account }}</span>
|
||||
<br/>
|
||||
<b>{% trans 'Session sharing URL' %}: </b><a href="{{ url }}" target="_blank">{% trans 'View' %}</a>
|
||||
<br/>
|
||||
<b>{% trans 'Verify code' %}: </b> <span>{{ verify_code }}</span>
|
||||
<br/>
|
||||
<b>{% trans 'Organization' %}: </b> <span>{{ org }}</span>
|
||||
<br/>
|
||||
</div>
|
Loading…
Reference in New Issue