Merge pull request #12461 from jumpserver/master

v3.10.1
pull/12580/head
Bryan 2023-12-29 11:33:05 +05:00 committed by GitHub
commit a9620a3cbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 105 additions and 65 deletions

View File

@ -94,7 +94,8 @@ JumpServer 堡垒机帮助企业以更安全的方式管控和登录各种类型
| [KoKo](https://github.com/jumpserver/koko) | <a href="https://github.com/jumpserver/koko/releases"><img alt="Koko release" src="https://img.shields.io/github/release/jumpserver/koko.svg" /></a> | JumpServer 字符协议 Connector 项目 | | [KoKo](https://github.com/jumpserver/koko) | <a href="https://github.com/jumpserver/koko/releases"><img alt="Koko release" src="https://img.shields.io/github/release/jumpserver/koko.svg" /></a> | JumpServer 字符协议 Connector 项目 |
| [Lion](https://github.com/jumpserver/lion-release) | <a href="https://github.com/jumpserver/lion-release/releases"><img alt="Lion release" src="https://img.shields.io/github/release/jumpserver/lion-release.svg" /></a> | JumpServer 图形协议 Connector 项目,依赖 [Apache Guacamole](https://guacamole.apache.org/) | | [Lion](https://github.com/jumpserver/lion-release) | <a href="https://github.com/jumpserver/lion-release/releases"><img alt="Lion release" src="https://img.shields.io/github/release/jumpserver/lion-release.svg" /></a> | JumpServer 图形协议 Connector 项目,依赖 [Apache Guacamole](https://guacamole.apache.org/) |
| [Razor](https://github.com/jumpserver/razor) | <img alt="Chen" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer RDP 代理 Connector 项目 | | [Razor](https://github.com/jumpserver/razor) | <img alt="Chen" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer RDP 代理 Connector 项目 |
| [Tinker](https://github.com/jumpserver/tinker) | <img alt="Tinker" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer 远程应用 Connector 项目 | | [Tinker](https://github.com/jumpserver/tinker) | <img alt="Tinker" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer 远程应用 Connector 项目 (Windows) |
| [Panda](https://github.com/jumpserver/Panda) | <img alt="Panda" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer 远程应用 Connector 项目 (Linux) |
| [Magnus](https://github.com/jumpserver/magnus-release) | <a href="https://github.com/jumpserver/magnus-release/releases"><img alt="Magnus release" src="https://img.shields.io/github/release/jumpserver/magnus-release.svg" /> | JumpServer 数据库代理 Connector 项目 | | [Magnus](https://github.com/jumpserver/magnus-release) | <a href="https://github.com/jumpserver/magnus-release/releases"><img alt="Magnus release" src="https://img.shields.io/github/release/jumpserver/magnus-release.svg" /> | JumpServer 数据库代理 Connector 项目 |
| [Chen](https://github.com/jumpserver/chen-release) | <a href="https://github.com/jumpserver/chen-release/releases"><img alt="Chen release" src="https://img.shields.io/github/release/jumpserver/chen-release.svg" /> | JumpServer Web DB 项目,替代原来的 OmniDB | | [Chen](https://github.com/jumpserver/chen-release) | <a href="https://github.com/jumpserver/chen-release/releases"><img alt="Chen release" src="https://img.shields.io/github/release/jumpserver/chen-release.svg" /> | JumpServer Web DB 项目,替代原来的 OmniDB |
| [Kael](https://github.com/jumpserver/kael) | <a href="https://github.com/jumpserver/kael/releases"><img alt="Kael release" src="https://img.shields.io/github/release/jumpserver/kael.svg" /> | JumpServer 连接 GPT 资产的组件项目 | | [Kael](https://github.com/jumpserver/kael) | <a href="https://github.com/jumpserver/kael/releases"><img alt="Kael release" src="https://img.shields.io/github/release/jumpserver/kael.svg" /> | JumpServer 连接 GPT 资产的组件项目 |

View File

@ -3,13 +3,13 @@ import time
from collections import defaultdict, OrderedDict from collections import defaultdict, OrderedDict
from django.conf import settings from django.conf import settings
from openpyxl import Workbook
from rest_framework import serializers from rest_framework import serializers
from xlsxwriter import Workbook
from accounts.const.automation import AccountBackupType from accounts.const.automation import AccountBackupType
from accounts.models.automations.backup_account import AccountBackupAutomation
from accounts.notifications import AccountBackupExecutionTaskMsg, AccountBackupByObjStorageExecutionTaskMsg from accounts.notifications import AccountBackupExecutionTaskMsg, AccountBackupByObjStorageExecutionTaskMsg
from accounts.serializers import AccountSecretSerializer from accounts.serializers import AccountSecretSerializer
from accounts.models.automations.backup_account import AccountBackupAutomation
from assets.const import AllTypes from assets.const import AllTypes
from common.utils.file import encrypt_and_compress_zip_file, zip_files from common.utils.file import encrypt_and_compress_zip_file, zip_files
from common.utils.timezone import local_now_filename, local_now_display from common.utils.timezone import local_now_filename, local_now_display
@ -144,10 +144,11 @@ class AccountBackupHandler:
wb = Workbook(filename) wb = Workbook(filename)
for sheet, data in data_map.items(): for sheet, data in data_map.items():
ws = wb.create_sheet(str(sheet)) ws = wb.add_worksheet(str(sheet))
for row in data: for row in data:
ws.append(row) for col, _data in enumerate(row):
wb.save(filename) ws.write_string(0, col, _data)
wb.close()
files.append(filename) files.append(filename)
timedelta = round((time.time() - time_start), 2) timedelta = round((time.time() - time_start), 2)
print('创建备份文件完成: 用时 {}s'.format(timedelta)) print('创建备份文件完成: 用时 {}s'.format(timedelta))

View File

@ -4,7 +4,7 @@ from copy import deepcopy
from django.conf import settings from django.conf import settings
from django.utils import timezone from django.utils import timezone
from openpyxl import Workbook from xlsxwriter import Workbook
from accounts.const import AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy from accounts.const import AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy
from accounts.models import ChangeSecretRecord from accounts.models import ChangeSecretRecord
@ -227,8 +227,9 @@ class ChangeSecretManager(AccountBasePlaybookManager):
rows.insert(0, header) rows.insert(0, header)
wb = Workbook(filename) wb = Workbook(filename)
ws = wb.create_sheet('Sheet1') ws = wb.add_worksheet('Sheet1')
for row in rows: for row in rows:
ws.append(row) for col, data in enumerate(row):
wb.save(filename) ws.write_string(0, col, data)
wb.close()
return True return True

View File

@ -72,7 +72,7 @@ class GatherAccountsManager(AccountBasePlaybookManager):
) )
gathered_accounts.append(gathered_account) gathered_accounts.append(gathered_account)
if not self.is_sync_account: if not self.is_sync_account:
return continue
GatheredAccount.sync_accounts(gathered_accounts) GatheredAccount.sync_accounts(gathered_accounts)
def run(self, *args, **kwargs): def run(self, *args, **kwargs):

View File

@ -16,10 +16,11 @@
- name: "Rename user home directory if it exists" - name: "Rename user home directory if it exists"
ansible.builtin.command: ansible.builtin.command:
cmd: "mv {{ user_home_dir.stdout }} {{ user_home_dir.stdout }}.bak" cmd: "mv {{ user_home_dir.stdout }} {{ user_home_dir.stdout }}.bak"
when: home_dir.stat.exists and user_home_dir.stdout != "" when: home_dir.stat | default(false) and user_home_dir.stdout != ""
- name: "Remove account" - name: "Remove account"
ansible.builtin.user: ansible.builtin.user:
name: "{{ account.username }}" name: "{{ account.username }}"
state: absent state: absent
remove: "{{ home_dir.stat.exists }}" remove: "{{ home_dir.stat.exists }}"
when: home_dir.stat | default(false)

View File

@ -1,6 +1,7 @@
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from accounts.models import Account
from assets.models import Asset from assets.models import Asset
from audits.models import UserLoginLog from audits.models import UserLoginLog
from notifications.notifications import UserMessage from notifications.notifications import UserMessage
@ -16,12 +17,11 @@ class UserLoginReminderMsg(UserMessage):
def get_html_msg(self) -> dict: def get_html_msg(self) -> dict:
user_log = self.user_log user_log = self.user_log
context = { context = {
'ip': user_log.ip, 'ip': user_log.ip,
'city': user_log.city, 'city': user_log.city,
'username': user_log.username, 'username': user_log.username,
'recipient': self.user.username, 'recipient': self.user,
'user_agent': user_log.user_agent, 'user_agent': user_log.user_agent,
} }
message = render_to_string('acls/user_login_reminder.html', context) message = render_to_string('acls/user_login_reminder.html', context)
@ -48,11 +48,14 @@ class AssetLoginReminderMsg(UserMessage):
super().__init__(user) super().__init__(user)
def get_html_msg(self) -> dict: def get_html_msg(self) -> dict:
account = Account.objects.get(asset=self.asset, username=self.account_username)
context = { context = {
'recipient': self.user.username, 'recipient': self.user,
'username': self.login_user.username, 'username': self.login_user.username,
'name': self.login_user.name,
'asset': str(self.asset), 'asset': str(self.asset),
'account': self.account_username, 'account': self.account_username,
'account_name': account.name,
} }
message = render_to_string('acls/asset_login_reminder.html', context) message = render_to_string('acls/asset_login_reminder.html', context)

View File

@ -1,10 +1,10 @@
{% load i18n %} {% load i18n %}
<h3>{% trans 'Respectful' %}{{ recipient }}</h3> <h3>{% trans 'Respectful' %}: {{ recipient.name }}[{{ recipient.username }}]</h3>
<hr> <hr>
<p><strong>{% trans 'Username' %}:</strong> [{{ username }}]</p> <p><strong>{% trans 'User' %}:</strong> [{{ name }}({{ username }})]</p>
<p><strong>{% trans 'Assets' %}:</strong> [{{ asset }}]</p> <p><strong>{% trans 'Assets' %}:</strong> [{{ asset }}]</p>
<p><strong>{% trans 'Account' %}:</strong> [{{ account }}]</p> <p><strong>{% trans 'Account' %}:</strong> [{{ account_name }}({{ account }})]</p>
<hr> <hr>
<p>{% trans 'The user has just logged in to the asset. Please ensure that this is an authorized operation. If you suspect that this is an unauthorized access, please take appropriate measures immediately.' %}</p> <p>{% trans 'The user has just logged in to the asset. Please ensure that this is an authorized operation. If you suspect that this is an unauthorized access, please take appropriate measures immediately.' %}</p>

View File

@ -1,8 +1,8 @@
{% load i18n %} {% load i18n %}
<h3>{% trans 'Respectful' %}{{ recipient }}</h3> <h3>{% trans 'Respectful' %}: {{ recipient.name }}[{{ recipient.username }}]</h3>
<hr> <hr>
<p><strong>{% trans 'Username' %}:</strong> [{{ username }}]</p> <p><strong>{% trans 'User' %}:</strong> [{{ username }}]</p>
<p><strong>IP:</strong> [{{ ip }}]</p> <p><strong>IP:</strong> [{{ ip }}]</p>
<p><strong>{% trans 'Login city' %}:</strong> [{{ city }}]</p> <p><strong>{% trans 'Login city' %}:</strong> [{{ city }}]</p>
<p><strong>{% trans 'User agent' %}:</strong> [{{ user_agent }}]</p> <p><strong>{% trans 'User agent' %}:</strong> [{{ user_agent }}]</p>

View File

@ -93,7 +93,7 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
model = Asset model = Asset
filterset_class = AssetFilterSet filterset_class = AssetFilterSet
search_fields = ("name", "address", "comment") search_fields = ("name", "address", "comment")
ordering_fields = ('name', 'connectivity', 'platform', 'date_updated', 'date_created') ordering_fields = ('name', 'address', 'connectivity', 'platform', 'date_updated', 'date_created')
serializer_classes = ( serializer_classes = (
("default", serializers.AssetSerializer), ("default", serializers.AssetSerializer),
("platform", serializers.PlatformSerializer), ("platform", serializers.PlatformSerializer),

View File

@ -122,7 +122,8 @@ def send_login_info_to_reviewers(instance: UserLoginLog | str, auth_acl_id):
def on_user_auth_success(sender, user, request, login_type=None, **kwargs): def on_user_auth_success(sender, user, request, login_type=None, **kwargs):
logger.debug('User login success: {}'.format(user.username)) logger.debug('User login success: {}'.format(user.username))
check_different_city_login_if_need(user, request) check_different_city_login_if_need(user, request)
data = generate_data(user.username, request, login_type=login_type) username = f"{user.name}({user.username})"
data = generate_data(username, request, login_type=login_type)
request.session['login_time'] = data['datetime'].strftime('%Y-%m-%d %H:%M:%S') request.session['login_time'] = data['datetime'].strftime('%Y-%m-%d %H:%M:%S')
data.update({'mfa': int(user.mfa_enabled), 'status': True}) data.update({'mfa': int(user.mfa_enabled), 'status': True})
instance = write_login_log(**data) instance = write_login_log(**data)

View File

@ -152,6 +152,8 @@ class SessionCookieMiddleware(MiddlewareMixin):
value = 'close' value = 'close'
age = request.session.get_expiry_age() age = request.session.get_expiry_age()
expire_timestamp = request.session.get_expiry_date().timestamp()
response.set_cookie('jms_session_expire_timestamp', expire_timestamp)
response.set_cookie('jms_session_expire', value, max_age=age) response.set_cookie('jms_session_expire', value, max_age=age)
request.session.pop('auth_session_expiration_required', None) request.session.pop('auth_session_expiration_required', None)

View File

@ -1 +1 @@
from jumpserver.rewriting import db # noqa 采用猴子补丁的方式重写atomic ForeignKey OneToOneField

View File

@ -1,2 +1,2 @@
from . import db

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-21 16:12+0800\n" "POT-Creation-Date: 2023-12-26 14:13+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -476,7 +476,7 @@ msgstr "終了日"
#: accounts/models/automations/change_secret.py:43 #: accounts/models/automations/change_secret.py:43
#: assets/models/automations/base.py:113 audits/models.py:208 #: assets/models/automations/base.py:113 audits/models.py:208
#: audits/serializers.py:54 ops/models/base.py:49 ops/models/job.py:227 #: audits/serializers.py:54 ops/models/base.py:49 ops/models/job.py:227
#: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:140 #: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140
#: terminal/models/component/status.py:30 #: terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99 #: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:18 terminal/serializers/applet_host.py:136 #: terminal/serializers/applet.py:18 terminal/serializers/applet_host.py:136
@ -742,7 +742,7 @@ msgstr "アカウントの存在ポリシー"
#: assets/models/label.py:21 assets/models/platform.py:96 #: assets/models/label.py:21 assets/models/platform.py:96
#: assets/serializers/asset/common.py:122 assets/serializers/cagegory.py:12 #: assets/serializers/asset/common.py:122 assets/serializers/cagegory.py:12
#: assets/serializers/platform.py:140 assets/serializers/platform.py:236 #: assets/serializers/platform.py:140 assets/serializers/platform.py:236
#: perms/serializers/user_permission.py:25 settings/models.py:35 #: perms/serializers/user_permission.py:26 settings/models.py:35
#: tickets/models/ticket/apply_application.py:13 users/models/preference.py:12 #: tickets/models/ticket/apply_application.py:13 users/models/preference.py:12
msgid "Category" msgid "Category"
msgstr "カテゴリ" msgstr "カテゴリ"
@ -756,7 +756,7 @@ msgstr "カテゴリ"
#: assets/serializers/platform.py:139 audits/serializers.py:53 #: assets/serializers/platform.py:139 audits/serializers.py:53
#: audits/serializers.py:170 #: audits/serializers.py:170
#: authentication/serializers/connect_token_secret.py:126 ops/models/job.py:144 #: authentication/serializers/connect_token_secret.py:126 ops/models/job.py:144
#: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:39 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:39
#: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:57
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29
#: terminal/serializers/session.py:21 terminal/serializers/storage.py:264 #: terminal/serializers/session.py:21 terminal/serializers/storage.py:264
@ -923,7 +923,7 @@ msgstr "关联平台,可以配置推送参数,如果不关联,则使用默
#: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26 #: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26
#: ops/models/job.py:152 ops/models/playbook.py:31 rbac/models/role.py:37 #: ops/models/job.py:152 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:38 terminal/models/applet/applet.py:45 #: settings/models.py:38 terminal/models/applet/applet.py:45
#: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:143 #: terminal/models/applet/applet.py:321 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:25 #: terminal/models/component/endpoint.py:25
#: terminal/models/component/endpoint.py:105 #: terminal/models/component/endpoint.py:105
#: terminal/models/session/session.py:46 #: terminal/models/session/session.py:46
@ -1720,7 +1720,7 @@ msgstr "アドレス"
#: assets/models/asset/common.py:161 assets/models/platform.py:126 #: assets/models/asset/common.py:161 assets/models/platform.py:126
#: authentication/backends/passkey/models.py:12 #: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:118 #: authentication/serializers/connect_token_secret.py:118
#: perms/serializers/user_permission.py:24 xpack/plugins/cloud/models.py:329 #: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:329
msgid "Platform" msgid "Platform"
msgstr "プラットフォーム" msgstr "プラットフォーム"
@ -1886,8 +1886,7 @@ msgstr "値"
#: assets/serializers/platform.py:119 #: assets/serializers/platform.py:119
#: authentication/serializers/connect_token_secret.py:124 #: authentication/serializers/connect_token_secret.py:124
#: common/serializers/common.py:85 labels/models.py:17 labels/models.py:33 #: common/serializers/common.py:85 labels/models.py:17 labels/models.py:33
#: labels/serializers.py:45 perms/serializers/user_permission.py:27 #: labels/serializers.py:45 settings/serializers/msg.py:83
#: settings/serializers/msg.py:83
msgid "Label" msgid "Label"
msgstr "ラベル" msgstr "ラベル"
@ -3707,7 +3706,7 @@ msgid "Invalid ids for ids, should be a list"
msgstr "無効なID、リストでなければなりません" msgstr "無効なID、リストでなければなりません"
#: common/db/fields.py:585 common/db/fields.py:590 #: common/db/fields.py:585 common/db/fields.py:590
#: common/serializers/fields.py:134 tickets/serializers/ticket/common.py:58 #: common/serializers/fields.py:133 tickets/serializers/ticket/common.py:58
#: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:56
#: xpack/plugins/cloud/serializers/account_attrs.py:79 #: xpack/plugins/cloud/serializers/account_attrs.py:79
#: xpack/plugins/cloud/serializers/account_attrs.py:150 #: xpack/plugins/cloud/serializers/account_attrs.py:150
@ -3880,21 +3879,21 @@ msgstr "{} 秒待ってから送信してください"
msgid "Children" msgid "Children"
msgstr "ノード" msgstr "ノード"
#: common/serializers/fields.py:135 #: common/serializers/fields.py:134
#, python-brace-format #, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist." msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "無効な pk \"{pk_value}\" - オブジェクトが存在しません" msgstr "無効な pk \"{pk_value}\" - オブジェクトが存在しません"
#: common/serializers/fields.py:136 #: common/serializers/fields.py:135
#, python-brace-format #, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}." msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "エラータイプ。 予想される pk 値、受信 {data_type}。" msgstr "エラータイプ。 予想される pk 値、受信 {data_type}。"
#: common/serializers/fields.py:210 #: common/serializers/fields.py:209
msgid "Invalid data type, should be list" msgid "Invalid data type, should be list"
msgstr "間違ったデータ タイプです。リストにする必要があります" msgstr "間違ったデータ タイプです。リストにする必要があります"
#: common/serializers/fields.py:225 #: common/serializers/fields.py:224
msgid "Invalid choice: {}" msgid "Invalid choice: {}"
msgstr "無効なオプション: {}" msgstr "無効なオプション: {}"
@ -4815,7 +4814,7 @@ msgid "My assets"
msgstr "私の資産" msgstr "私の資産"
#: rbac/tree.py:58 terminal/models/applet/applet.py:52 #: rbac/tree.py:58 terminal/models/applet/applet.py:52
#: terminal/models/applet/applet.py:316 terminal/models/applet/host.py:30 #: terminal/models/applet/applet.py:317 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:15 #: terminal/serializers/applet.py:15
msgid "Applet" msgid "Applet"
msgstr "リモートアプリケーション" msgstr "リモートアプリケーション"
@ -6597,7 +6596,7 @@ msgstr "カスタムプラットフォームのみをサポート"
msgid "Missing type in platform.yml" msgid "Missing type in platform.yml"
msgstr "platform.ymlにタイプがありません" msgstr "platform.ymlにタイプがありません"
#: terminal/models/applet/applet.py:318 terminal/models/applet/host.py:36 #: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138 #: terminal/models/applet/host.py:138
msgid "Hosting" msgid "Hosting"
msgstr "ホスト マシン" msgstr "ホスト マシン"

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:853320b42ac7795fa983c4216f89b3a776a889453d90e11dc425d1388ff9b803 oid sha256:80dd11dde678e4f9b64df18906175125218fd9f719bfe9aaa667ad6e2d055d40
size 139012 size 139012

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n" "Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-21 16:12+0800\n" "POT-Creation-Date: 2023-12-26 14:13+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n" "Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -475,7 +475,7 @@ msgstr "结束日期"
#: accounts/models/automations/change_secret.py:43 #: accounts/models/automations/change_secret.py:43
#: assets/models/automations/base.py:113 audits/models.py:208 #: assets/models/automations/base.py:113 audits/models.py:208
#: audits/serializers.py:54 ops/models/base.py:49 ops/models/job.py:227 #: audits/serializers.py:54 ops/models/base.py:49 ops/models/job.py:227
#: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:140 #: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140
#: terminal/models/component/status.py:30 #: terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99 #: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:18 terminal/serializers/applet_host.py:136 #: terminal/serializers/applet.py:18 terminal/serializers/applet_host.py:136
@ -740,7 +740,7 @@ msgstr "账号存在策略"
#: assets/models/label.py:21 assets/models/platform.py:96 #: assets/models/label.py:21 assets/models/platform.py:96
#: assets/serializers/asset/common.py:122 assets/serializers/cagegory.py:12 #: assets/serializers/asset/common.py:122 assets/serializers/cagegory.py:12
#: assets/serializers/platform.py:140 assets/serializers/platform.py:236 #: assets/serializers/platform.py:140 assets/serializers/platform.py:236
#: perms/serializers/user_permission.py:25 settings/models.py:35 #: perms/serializers/user_permission.py:26 settings/models.py:35
#: tickets/models/ticket/apply_application.py:13 users/models/preference.py:12 #: tickets/models/ticket/apply_application.py:13 users/models/preference.py:12
msgid "Category" msgid "Category"
msgstr "类别" msgstr "类别"
@ -754,7 +754,7 @@ msgstr "类别"
#: assets/serializers/platform.py:139 audits/serializers.py:53 #: assets/serializers/platform.py:139 audits/serializers.py:53
#: audits/serializers.py:170 #: audits/serializers.py:170
#: authentication/serializers/connect_token_secret.py:126 ops/models/job.py:144 #: authentication/serializers/connect_token_secret.py:126 ops/models/job.py:144
#: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:39 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:39
#: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:57
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29
#: terminal/serializers/session.py:21 terminal/serializers/storage.py:264 #: terminal/serializers/session.py:21 terminal/serializers/storage.py:264
@ -921,7 +921,7 @@ msgstr "关联平台,可配置推送参数,如果不关联,将使用默认
#: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26 #: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26
#: ops/models/job.py:152 ops/models/playbook.py:31 rbac/models/role.py:37 #: ops/models/job.py:152 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:38 terminal/models/applet/applet.py:45 #: settings/models.py:38 terminal/models/applet/applet.py:45
#: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:143 #: terminal/models/applet/applet.py:321 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:25 #: terminal/models/component/endpoint.py:25
#: terminal/models/component/endpoint.py:105 #: terminal/models/component/endpoint.py:105
#: terminal/models/session/session.py:46 #: terminal/models/session/session.py:46
@ -1712,7 +1712,7 @@ msgstr "地址"
#: assets/models/asset/common.py:161 assets/models/platform.py:126 #: assets/models/asset/common.py:161 assets/models/platform.py:126
#: authentication/backends/passkey/models.py:12 #: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:118 #: authentication/serializers/connect_token_secret.py:118
#: perms/serializers/user_permission.py:24 xpack/plugins/cloud/models.py:329 #: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:329
msgid "Platform" msgid "Platform"
msgstr "系统平台" msgstr "系统平台"
@ -1878,8 +1878,7 @@ msgstr "值"
#: assets/serializers/platform.py:119 #: assets/serializers/platform.py:119
#: authentication/serializers/connect_token_secret.py:124 #: authentication/serializers/connect_token_secret.py:124
#: common/serializers/common.py:85 labels/models.py:17 labels/models.py:33 #: common/serializers/common.py:85 labels/models.py:17 labels/models.py:33
#: labels/serializers.py:45 perms/serializers/user_permission.py:27 #: labels/serializers.py:45 settings/serializers/msg.py:83
#: settings/serializers/msg.py:83
msgid "Label" msgid "Label"
msgstr "标签" msgstr "标签"
@ -3663,7 +3662,7 @@ msgid "Invalid ids for ids, should be a list"
msgstr "无效的ID应为列表" msgstr "无效的ID应为列表"
#: common/db/fields.py:585 common/db/fields.py:590 #: common/db/fields.py:585 common/db/fields.py:590
#: common/serializers/fields.py:134 tickets/serializers/ticket/common.py:58 #: common/serializers/fields.py:133 tickets/serializers/ticket/common.py:58
#: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:56
#: xpack/plugins/cloud/serializers/account_attrs.py:79 #: xpack/plugins/cloud/serializers/account_attrs.py:79
#: xpack/plugins/cloud/serializers/account_attrs.py:150 #: xpack/plugins/cloud/serializers/account_attrs.py:150
@ -3834,21 +3833,21 @@ msgstr "请在 {} 秒后发送"
msgid "Children" msgid "Children"
msgstr "节点" msgstr "节点"
#: common/serializers/fields.py:135 #: common/serializers/fields.py:134
#, python-brace-format #, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist." msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "错误的 pk \"{pk_value}\" - 对象不存在" msgstr "错误的 pk \"{pk_value}\" - 对象不存在"
#: common/serializers/fields.py:136 #: common/serializers/fields.py:135
#, python-brace-format #, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}." msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "错误类型。期望 pk 值,收到 {data_type}。" msgstr "错误类型。期望 pk 值,收到 {data_type}。"
#: common/serializers/fields.py:210 #: common/serializers/fields.py:209
msgid "Invalid data type, should be list" msgid "Invalid data type, should be list"
msgstr "错误的数据类型,应该是列表" msgstr "错误的数据类型,应该是列表"
#: common/serializers/fields.py:225 #: common/serializers/fields.py:224
msgid "Invalid choice: {}" msgid "Invalid choice: {}"
msgstr "无效选项: {}" msgstr "无效选项: {}"
@ -4762,7 +4761,7 @@ msgid "My assets"
msgstr "我的资产" msgstr "我的资产"
#: rbac/tree.py:58 terminal/models/applet/applet.py:52 #: rbac/tree.py:58 terminal/models/applet/applet.py:52
#: terminal/models/applet/applet.py:316 terminal/models/applet/host.py:30 #: terminal/models/applet/applet.py:317 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:15 #: terminal/serializers/applet.py:15
msgid "Applet" msgid "Applet"
msgstr "远程应用" msgstr "远程应用"
@ -5464,7 +5463,7 @@ msgstr "启用 Vault"
#: settings/serializers/feature.py:55 #: settings/serializers/feature.py:55
msgid "Mount Point" msgid "Mount Point"
msgstr "挂点" msgstr "挂点"
#: settings/serializers/feature.py:60 #: settings/serializers/feature.py:60
msgid "Chat AI" msgid "Chat AI"
@ -6504,7 +6503,7 @@ msgstr "只支持自定义平台"
msgid "Missing type in platform.yml" msgid "Missing type in platform.yml"
msgstr "在 platform.yml 中缺少类型" msgstr "在 platform.yml 中缺少类型"
#: terminal/models/applet/applet.py:318 terminal/models/applet/host.py:36 #: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138 #: terminal/models/applet/host.py:138
msgid "Hosting" msgid "Hosting"
msgstr "宿主机" msgstr "宿主机"

View File

@ -26,6 +26,7 @@ def common_argument_spec():
class SSHClient: class SSHClient:
TIMEOUT = 20
SLEEP_INTERVAL = 2 SLEEP_INTERVAL = 2
COMPLETE_FLAG = 'complete' COMPLETE_FLAG = 'complete'
@ -170,7 +171,12 @@ class SSHClient:
time.sleep(self.SLEEP_INTERVAL) time.sleep(self.SLEEP_INTERVAL)
output += self._get_recv() output += self._get_recv()
continue continue
start_time = time.time()
while self.COMPLETE_FLAG not in output: while self.COMPLETE_FLAG not in output:
if time.time() - start_time > self.TIMEOUT:
error_msg = output
print("切换用户操作超时,跳出循环。")
break
time.sleep(self.SLEEP_INTERVAL) time.sleep(self.SLEEP_INTERVAL)
received_output = self._get_recv().replace(f'"{self.COMPLETE_FLAG}"', '') received_output = self._get_recv().replace(f'"{self.COMPLETE_FLAG}"', '')
output += received_output output += received_output

View File

@ -217,6 +217,7 @@ class JobExecutionTaskDetail(APIView):
'is_success': execution.is_success, 'is_success': execution.is_success,
'time_cost': execution.time_cost, 'time_cost': execution.time_cost,
'job_id': execution.job.id, 'job_id': execution.job.id,
'summary': execution.summary
}) })

View File

@ -10,6 +10,7 @@ from assets.const import Category, AllTypes
from assets.models import Node, Asset, Platform from assets.models import Node, Asset, Platform
from assets.serializers.asset.common import AssetLabelSerializer, AssetProtocolsPermsSerializer from assets.serializers.asset.common import AssetLabelSerializer, AssetProtocolsPermsSerializer
from common.serializers.fields import ObjectRelatedField, LabeledChoiceField from common.serializers.fields import ObjectRelatedField, LabeledChoiceField
from common.serializers import ResourceLabelsMixin
from orgs.mixins.serializers import OrgResourceModelSerializerMixin from orgs.mixins.serializers import OrgResourceModelSerializerMixin
from perms.serializers.permission import ActionChoicesField from perms.serializers.permission import ActionChoicesField
@ -19,12 +20,11 @@ __all__ = [
] ]
class AssetPermedSerializer(OrgResourceModelSerializerMixin): class AssetPermedSerializer(OrgResourceModelSerializerMixin, ResourceLabelsMixin):
""" 被授权资产的数据结构 """ """ 被授权资产的数据结构 """
platform = ObjectRelatedField(required=False, queryset=Platform.objects, label=_('Platform')) platform = ObjectRelatedField(required=False, queryset=Platform.objects, label=_('Platform'))
category = LabeledChoiceField(choices=Category.choices, read_only=True, label=_('Category')) category = LabeledChoiceField(choices=Category.choices, read_only=True, label=_('Category'))
type = LabeledChoiceField(choices=AllTypes.choices(), read_only=True, label=_('Type')) type = LabeledChoiceField(choices=AllTypes.choices(), read_only=True, label=_('Type'))
labels = AssetLabelSerializer(many=True, required=False, label=_('Label'))
domain = ObjectRelatedField(required=False, queryset=Node.objects, label=_('Domain')) domain = ObjectRelatedField(required=False, queryset=Node.objects, label=_('Domain'))
class Meta: class Meta:

View File

@ -30,6 +30,7 @@ exclude_permissions = (
('users', 'userpasswordhistory', '*', '*'), ('users', 'userpasswordhistory', '*', '*'),
('users', 'usersession', '*', '*'), ('users', 'usersession', '*', '*'),
('assets', 'adminuser', '*', '*'), ('assets', 'adminuser', '*', '*'),
('assets', 'label', '*', '*'),
('assets', 'assetgroup', '*', '*'), ('assets', 'assetgroup', '*', '*'),
('assets', 'cluster', '*', '*'), ('assets', 'cluster', '*', '*'),
('assets', 'systemuser', '*', '*'), ('assets', 'systemuser', '*', '*'),

View File

@ -7,14 +7,14 @@ from ..models import Permission
__all__ = ['PermissionSerializer', 'UserPermsSerializer'] __all__ = ['PermissionSerializer', 'UserPermsSerializer']
class ContentTypeSerializer(serializers.ModelSerializer): class PermissionContentTypeSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = ContentType model = ContentType
fields = ['id', 'app_label', 'model'] fields = ['id', 'app_label', 'model']
class PermissionSerializer(serializers.ModelSerializer): class PermissionSerializer(serializers.ModelSerializer):
content_type = ContentTypeSerializer(read_only=True) content_type = PermissionContentTypeSerializer(read_only=True)
class Meta: class Meta:
model = Permission model = Permission

View File

@ -86,7 +86,7 @@ class ChatAISettingSerializer(serializers.Serializer):
return return
gpt_api_model = Protocol.gpt_protocols()[Protocol.chatgpt]['setting']['api_mode'] gpt_api_model = Protocol.gpt_protocols()[Protocol.chatgpt]['setting']['api_mode']
choices = gpt_api_model['choices'] choices = gpt_api_model['choices']
field_gpt_model._choices = choices field_gpt_model.choices = choices
field_gpt_model.default = gpt_api_model['default'] field_gpt_model.default = gpt_api_model['default']
cls = self.__class__ cls = self.__class__
if cls.GPT_MODEL_CHOICES: if cls.GPT_MODEL_CHOICES:

View File

@ -172,8 +172,9 @@ class Applet(JMSBaseModel):
return None return None
spec_label = asset.labels.filter(label__name__in=['AppletHost', '发布机']).first() spec_label = asset.labels.filter(label__name__in=['AppletHost', '发布机']).first()
if spec_label: if spec_label and spec_label.label:
matched = [host for host in hosts if host.name == spec_label.value] label_value = spec_label.label.value
matched = [host for host in hosts if host.name == label_value]
if matched: if matched:
return matched[0] return matched[0]

View File

@ -16,6 +16,10 @@ class UserUserGroupRelationViewSet(JMSBulkRelationModelViewSet):
search_fields = filterset_fields search_fields = filterset_fields
serializer_class = serializers.User2GroupRelationSerializer serializer_class = serializers.User2GroupRelationSerializer
m2m_field = User.groups.field m2m_field = User.groups.field
rbac_perms = {
'create': 'users.change_usergroup',
'bulk_destroy': 'users.change_usergroup',
}
def get_queryset(self): def get_queryset(self):
return super().get_queryset().annotate( return super().get_queryset().annotate(

View File

@ -867,6 +867,7 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterM
queryset = cls.objects.all() queryset = cls.objects.all()
if not current_org.is_root(): if not current_org.is_root():
queryset = current_org.get_members() queryset = current_org.get_members()
queryset = queryset.exclude(is_service_account=True)
return queryset return queryset
@property @property

View File

@ -16,7 +16,8 @@ __all__ = [
class UserGroupSerializer(ResourceLabelsMixin, BulkOrgResourceModelSerializer): class UserGroupSerializer(ResourceLabelsMixin, BulkOrgResourceModelSerializer):
users = ObjectRelatedField( users = ObjectRelatedField(
required=False, many=True, queryset=User.objects, label=_('User'), required=False, many=True, queryset=User.objects,
attrs=("id", "name", "is_service_account"), label=_('User'),
) )
class Meta: class Meta:

18
poetry.lock generated
View File

@ -7540,6 +7540,22 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple" url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "tsinghua" reference = "tsinghua"
[[package]]
name = "xlsxwriter"
version = "3.1.9"
description = "A Python module for creating Excel XLSX files."
optional = false
python-versions = ">=3.6"
files = [
{file = "XlsxWriter-3.1.9-py3-none-any.whl", hash = "sha256:b61c1a0c786f82644936c0936ec96ee96cd3afb9440094232f7faef9b38689f0"},
{file = "XlsxWriter-3.1.9.tar.gz", hash = "sha256:de810bf328c6a4550f4ffd6b0b34972aeb7ffcf40f3d285a0413734f9b63a929"},
]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "tsinghua"
[[package]] [[package]]
name = "xmlsec" name = "xmlsec"
version = "1.3.13" version = "1.3.13"
@ -7755,4 +7771,4 @@ reference = "tsinghua"
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "397cb294c81da3ce74f1a1c3044bd778669284c0c280177162ed9d51e623a7c8" content-hash = "19950a5300f8a4425e3e3c9a096fc3782cb544e02152e92ac1bc09d1d9b5274a"

View File

@ -145,6 +145,7 @@ user-agents = "^2.2.0"
django-cors-headers = "^4.3.0" django-cors-headers = "^4.3.0"
mistune = "0.8.4" mistune = "0.8.4"
openai = "^1.3.7" openai = "^1.3.7"
xlsxwriter = "^3.1.9"
[tool.poetry.group.xpack.dependencies] [tool.poetry.group.xpack.dependencies]