From 202b913005215e9f5ed63c527cf5f2b16ac1a719 Mon Sep 17 00:00:00 2001 From: yeshanshan Date: Wed, 8 Jul 2026 17:44:01 +0800 Subject: [PATCH] fix: disable copy/cut/paste and block undo/redo in DPasswordEdit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Default-disable copy/cut for security, intercept undo/redo shortcuts and context menu actions to prevent password leakage. DPasswordEdit构造时默认禁用复制、剪切功能,拦截撤消、重做快捷键及右键菜单项,防止密码信息泄露。 Log: DPasswordEdit禁用复制粘贴及撤销重做,防止密码泄露 PMS: TASK-392179 Influence: DPasswordEdit密文明文均禁止复制粘贴和撤销重做,提升密码输入安全性。 --- src/widgets/dpasswordedit.cpp | 43 +++++++++++++++++++- tests/testcases/widgets/ut_dpasswordedit.cpp | 17 +++++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/widgets/dpasswordedit.cpp b/src/widgets/dpasswordedit.cpp index ba5eebc9c..2da29b92c 100644 --- a/src/widgets/dpasswordedit.cpp +++ b/src/widgets/dpasswordedit.cpp @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include DWIDGET_BEGIN_NAMESPACE @@ -42,6 +44,9 @@ DPasswordEdit::DPasswordEdit(QWidget *parent) D_D(DPasswordEdit); d->init(); + + setCopyEnabled(false); + setCutEnabled(false); } /*! @@ -135,13 +140,49 @@ bool DPasswordEdit::eventFilter(QObject* watcher, QEvent* event) } } #endif + + if (watcher == lineEdit() && event->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast(event); + if (keyEvent->matches(QKeySequence::Undo) + || keyEvent->matches(QKeySequence::Redo)) { + return true; + } + } + + if (watcher == lineEdit() && event->type() == QEvent::ContextMenu) { + QMenu *menu = lineEdit()->createStandardContextMenu(); + if (!menu) + return DLineEdit::eventFilter(watcher, event); + + for (QAction *action : menu->actions()) { + const auto &text = action->text(); + if (text.startsWith(QLineEdit::tr("&Undo")) + || text.startsWith(QLineEdit::tr("&Redo"))) { + action->setEnabled(false); + } + if (text.startsWith(QLineEdit::tr("Cu&t")) && !cutEnabled()) { + action->setEnabled(false); + } + if (text.startsWith(QLineEdit::tr("&Copy")) && !copyEnabled()) { + action->setEnabled(false); + } + if (text.startsWith(QLineEdit::tr("&Paste")) && !pasteEnabled()) { + action->setEnabled(false); + } + } + + menu->popup(static_cast(event)->globalPos()); + event->accept(); + lineEdit()->setFocus(); + return true; + } + return DLineEdit::eventFilter(watcher, event); } DPasswordEditPrivate::DPasswordEditPrivate(DPasswordEdit *q) : DLineEditPrivate(q) { - } void DPasswordEditPrivate::init() diff --git a/tests/testcases/widgets/ut_dpasswordedit.cpp b/tests/testcases/widgets/ut_dpasswordedit.cpp index 2bb1398b3..a0881cc8b 100644 --- a/tests/testcases/widgets/ut_dpasswordedit.cpp +++ b/tests/testcases/widgets/ut_dpasswordedit.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2021 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -38,6 +38,8 @@ TEST_F(ut_DPasswordEdit, setEchoMode) TEST_F(ut_DPasswordEdit, setCopyEnabled) { + ASSERT_FALSE(target->copyEnabled()); + target->setCopyEnabled(true); ASSERT_TRUE(target->copyEnabled()); @@ -47,6 +49,8 @@ TEST_F(ut_DPasswordEdit, setCopyEnabled) TEST_F(ut_DPasswordEdit, setCutEnabled) { + ASSERT_FALSE(target->cutEnabled()); + target->setCutEnabled(true); ASSERT_TRUE(target->cutEnabled()); @@ -54,3 +58,14 @@ TEST_F(ut_DPasswordEdit, setCutEnabled) ASSERT_FALSE(target->cutEnabled()); } +TEST_F(ut_DPasswordEdit, setPasteEnabled) +{ + ASSERT_TRUE(target->pasteEnabled()); + + target->setPasteEnabled(true); + ASSERT_TRUE(target->pasteEnabled()); + + target->setPasteEnabled(false); + ASSERT_FALSE(target->pasteEnabled()); +} +