From ab05dc1bb6ced4efd141677206c1439b05b8829e Mon Sep 17 00:00:00 2001 From: lettimepassby <86416409@qq.com> Date: Mon, 22 Jun 2026 11:01:14 +0800 Subject: [PATCH] feat: add fine-grained clipboard permission control for graphical sessions --- .../Form/FormFields/ClipboardPolicy.vue | 99 +++++++++++++++++++ src/i18n/langs/en.json | 11 ++- src/i18n/langs/zh.json | 11 ++- src/i18n/langs/zh_hant.json | 11 ++- .../AssetPermissionCreateUpdate.vue | 19 +++- .../AssetPermissionDetail.vue | 12 +++ 6 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 src/components/Form/FormFields/ClipboardPolicy.vue diff --git a/src/components/Form/FormFields/ClipboardPolicy.vue b/src/components/Form/FormFields/ClipboardPolicy.vue new file mode 100644 index 0000000000..9a9b1b1115 --- /dev/null +++ b/src/components/Form/FormFields/ClipboardPolicy.vue @@ -0,0 +1,99 @@ + + + onToggle(item.key, val)" + >{{ $t(item.label) }} + + {{ $t(item.limitLabel) }} + + + + + + + + + + + diff --git a/src/i18n/langs/en.json b/src/i18n/langs/en.json index ec8bd4f25a..47ecba9acb 100644 --- a/src/i18n/langs/en.json +++ b/src/i18n/langs/en.json @@ -21,5 +21,14 @@ "Confirm": "Confirm", "Ignore": "Ignore", "Please enter a reason": "Please enter a reason", - "PleaseEnterReason": "Please enter a reason | Please enter reasons" + "PleaseEnterReason": "Please enter a reason | Please enter reasons", + "Clipboard": "Clipboard", + "FileUpload": "File upload", + "FileDownload": "File download", + "TextCopy": "Text copy", + "TextPaste": "Text paste", + "TextCopyMaxLength": "Text copy character limit", + "TextPasteMaxLength": "Text paste character limit", + "ZeroMeansUnlimited": "0 means unlimited", + "ClipboardPolicyTip": "Controls clipboard file upload/download and text copy/paste for this permission in RDP sessions. Requires the copy/paste actions to take effect." } \ No newline at end of file diff --git a/src/i18n/langs/zh.json b/src/i18n/langs/zh.json index 6d1d5ad2d8..10ed9c9d18 100644 --- a/src/i18n/langs/zh.json +++ b/src/i18n/langs/zh.json @@ -19,5 +19,14 @@ "Other": "其他", "Details": "详情", "Confirm": "确认", - "Ignore": "忽略" + "Ignore": "忽略", + "Clipboard": "剪贴板", + "FileUpload": "文件上行", + "FileDownload": "文件下行", + "TextCopy": "字符串复制", + "TextPaste": "字符串粘贴", + "TextCopyMaxLength": "字符串复制字符数限制", + "TextPasteMaxLength": "字符串粘贴字符数限制", + "ZeroMeansUnlimited": "0 表示不限制", + "ClipboardPolicyTip": "控制该授权在 RDP 会话剪贴板中的文件上行/下行与字符串复制/粘贴权限,需配合动作中的复制、粘贴权限生效" } diff --git a/src/i18n/langs/zh_hant.json b/src/i18n/langs/zh_hant.json index cd7765272c..dcc0611aa5 100644 --- a/src/i18n/langs/zh_hant.json +++ b/src/i18n/langs/zh_hant.json @@ -7,5 +7,14 @@ "notAlphanumericUnderscore": "仅支持字母、数字和下划线。", "notParenthesis": "不能包含括号。", "InvalidJson": "JSON 格式错误.", - "requiredHasUserNameMapped": "用户名属性是必需的。" + "requiredHasUserNameMapped": "用户名属性是必需的。", + "Clipboard": "剪貼簿", + "FileUpload": "檔案上行", + "FileDownload": "檔案下行", + "TextCopy": "字串複製", + "TextPaste": "字串貼上", + "TextCopyMaxLength": "字串複製字元數限制", + "TextPasteMaxLength": "字串貼上字元數限制", + "ZeroMeansUnlimited": "0 表示不限制", + "ClipboardPolicyTip": "控制該授權在 RDP 工作階段剪貼簿中的檔案上行/下行與字串複製/貼上權限,需搭配動作中的複製、貼上權限生效" } diff --git a/src/views/perms/AssetPermission/AssetPermissionCreateUpdate.vue b/src/views/perms/AssetPermission/AssetPermissionCreateUpdate.vue index 63dbb2b4a9..113c106b3d 100644 --- a/src/views/perms/AssetPermission/AssetPermissionCreateUpdate.vue +++ b/src/views/perms/AssetPermission/AssetPermissionCreateUpdate.vue @@ -14,6 +14,7 @@ import AssetSelect from '@/components/Apps/AssetSelect' import AccountFormatter from './components/AccountFormatter' import { AllAccount } from '../const' import ProtocolsSelect from '@/components/Form/FormFields/AllOrSpec.vue' +import ClipboardPolicy, { applyActionsToClipboardPolicy, defaultClipboardPolicy } from '@/components/Form/FormFields/ClipboardPolicy.vue' export default { name: 'AccountFormatter', @@ -33,7 +34,8 @@ export default { initial: { nodes: nodesInitial, assets: assetsInitial, - accounts: [AllAccount] + accounts: [AllAccount], + clipboard_policy: defaultClipboardPolicy() }, fields: [ [this.$t('Basic'), ['name']], @@ -43,6 +45,7 @@ export default { [this.$t('Account'), ['accounts']], [this.$t('Protocol'), ['protocols']], [this.$t('Action'), ['actions']], + [this.$t('Clipboard'), ['clipboard_policy']], [this.$t('Other'), ['is_active', 'date_start', 'date_expired', 'comment']] ], url: '/api/v1/perms/asset-permissions/', @@ -124,6 +127,19 @@ export default { label: this.$t('Action'), helpText: this.$t('ActionsTips') }, + clipboard_policy: { + label: this.$t('Clipboard'), + component: ClipboardPolicy, + helpText: this.$t('ClipboardPolicyTip'), + el: { + actions: [] + }, + hidden: (formValue) => { + // Feed the live actions into the component so each clipboard + // sub-permission is gated by its matching action. + this.fieldsMeta.clipboard_policy.el.actions = formValue.actions || [] + } + }, date_start: {}, date_expired: {}, comment: {}, @@ -135,6 +151,7 @@ export default { if (!Array.isArray(value.accounts)) { value.accounts = value.accounts ? value.accounts.split(',') : [] } + value.clipboard_policy = applyActionsToClipboardPolicy(value.clipboard_policy, value.actions) return value } } diff --git a/src/views/perms/AssetPermission/AssetPermissionDetail/AssetPermissionDetail.vue b/src/views/perms/AssetPermission/AssetPermissionDetail/AssetPermissionDetail.vue index 064cc31bca..14c921fa9b 100644 --- a/src/views/perms/AssetPermission/AssetPermissionDetail/AssetPermissionDetail.vue +++ b/src/views/perms/AssetPermission/AssetPermissionDetail/AssetPermissionDetail.vue @@ -72,6 +72,18 @@ export default { ) } }, + { + key: this.$t('Clipboard'), + value: this.object.clipboard_policy, + formatter: (row, p = {}) => { + const items = [ + ['FileUpload', p.file_upload], ['FileDownload', p.file_download], + ['TextCopy', p.text_copy, p.text_copy_max_length], ['TextPaste', p.text_paste, p.text_paste_max_length] + ] + const labels = items.filter(i => i[1]).map(i => this.$t(i[0]) + (i[2] > 0 ? `(${i[2]})` : '')) + return labels.length ? labels.join('、') : '-' + } + }, 'date_start', 'date_expired', 'date_created', 'created_by', 'comment' ] }