Fix undo and redo in QLineEdit when in password mode
There are some security issues with undo/redo. User should not be able to get the erased password back in any situation. Therefore redo must be disabled completely and undo is limited only for erasing previously entered text. Task-number: QTBUG-14226 Change-Id: I2b38aca84adbad1c14db76b56ad6303d56b35b4d Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
This commit is contained in:
parent
d19589b90a
commit
121062d884
@ -1279,6 +1279,13 @@ void QWidgetLineControl::internalUndo(int until)
|
||||
return;
|
||||
cancelPasswordEchoTimer();
|
||||
internalDeselect();
|
||||
|
||||
// Undo works only for clearing the line when in any of password the modes
|
||||
if (m_echoMode != QLineEdit::Normal) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
while (m_undoState && m_undoState > until) {
|
||||
Command& cmd = m_history[--m_undoState];
|
||||
switch (cmd.type) {
|
||||
@ -1868,6 +1875,21 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
|
||||
event->accept();
|
||||
}
|
||||
|
||||
bool QWidgetLineControl::isUndoAvailable() const
|
||||
{
|
||||
// For security reasons undo is not available in any password mode (NoEcho included)
|
||||
// with the exception that the user can clear the password with undo.
|
||||
return !m_readOnly && m_undoState
|
||||
&& (m_echoMode == QLineEdit::Normal || m_history[m_undoState - 1].type == QWidgetLineControl::Insert);
|
||||
}
|
||||
|
||||
bool QWidgetLineControl::isRedoAvailable() const
|
||||
{
|
||||
// Same as with undo. Disabled for password modes.
|
||||
return !m_readOnly
|
||||
&& m_echoMode == QLineEdit::Normal
|
||||
&& m_undoState < m_history.size();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
@ -125,8 +125,8 @@ public:
|
||||
return (c != -1 ? c : 0);
|
||||
}
|
||||
|
||||
bool isUndoAvailable() const { return !m_readOnly && m_undoState; }
|
||||
bool isRedoAvailable() const { return !m_readOnly && m_undoState < (int)m_history.size(); }
|
||||
bool isUndoAvailable() const;
|
||||
bool isRedoAvailable() const;
|
||||
void clearUndo() { m_history.clear(); m_modifiedState = m_undoState = 0; }
|
||||
|
||||
bool isModified() const { return m_modifiedState != m_undoState; }
|
||||
|
@ -287,6 +287,9 @@ private slots:
|
||||
void inputMethodQueryImHints_data();
|
||||
void inputMethodQueryImHints();
|
||||
|
||||
void undoRedoAndEchoModes_data();
|
||||
void undoRedoAndEchoModes();
|
||||
|
||||
protected slots:
|
||||
void editingFinished();
|
||||
|
||||
@ -3954,5 +3957,68 @@ void tst_QLineEdit::inputMethodQueryImHints()
|
||||
QCOMPARE(static_cast<Qt::InputMethodHints>(value.toInt()), hints);
|
||||
}
|
||||
|
||||
void tst_QLineEdit::undoRedoAndEchoModes_data()
|
||||
{
|
||||
QTest::addColumn<int>("echoMode");
|
||||
QTest::addColumn<QStringList>("input");
|
||||
QTest::addColumn<QStringList>("expected");
|
||||
|
||||
QStringList input(QList<QString>() << "aaa" << "bbb" << "ccc");
|
||||
|
||||
QTest::newRow("Normal")
|
||||
<< (int) QLineEdit::Normal
|
||||
<< input
|
||||
<< QStringList(QList<QString>() << "aaa" << "ccc" << "");
|
||||
|
||||
QTest::newRow("NoEcho")
|
||||
<< (int) QLineEdit::NoEcho
|
||||
<< input
|
||||
<< QStringList(QList<QString>() << "" << "" << "");
|
||||
|
||||
QTest::newRow("Password")
|
||||
<< (int) QLineEdit::Password
|
||||
<< input
|
||||
<< QStringList(QList<QString>() << "" << "" << "");
|
||||
|
||||
QTest::newRow("PasswordEchoOnEdit")
|
||||
<< (int) QLineEdit::PasswordEchoOnEdit
|
||||
<< input
|
||||
<< QStringList(QList<QString>() << "" << "" << "");
|
||||
}
|
||||
|
||||
void tst_QLineEdit::undoRedoAndEchoModes()
|
||||
{
|
||||
QFETCH(int, echoMode);
|
||||
QFETCH(QStringList, input);
|
||||
QFETCH(QStringList, expected);
|
||||
|
||||
// create some history for the QLineEdit
|
||||
testWidget->clear();
|
||||
testWidget->setEchoMode(QLineEdit::EchoMode(echoMode));
|
||||
testWidget->insert(input.at(0));
|
||||
testWidget->selectAll();
|
||||
testWidget->backspace();
|
||||
testWidget->insert(input.at(1));
|
||||
|
||||
// test undo
|
||||
QVERIFY(testWidget->isUndoAvailable());
|
||||
testWidget->undo();
|
||||
QCOMPARE(testWidget->text(), expected.at(0));
|
||||
testWidget->insert(input.at(2));
|
||||
testWidget->selectAll();
|
||||
testWidget->backspace();
|
||||
QCOMPARE(testWidget->isUndoAvailable(), echoMode == QLineEdit::Normal);
|
||||
testWidget->undo();
|
||||
QCOMPARE(testWidget->text(), expected.at(1));
|
||||
|
||||
// test redo
|
||||
QCOMPARE(testWidget->isRedoAvailable(), echoMode == QLineEdit::Normal);
|
||||
testWidget->redo();
|
||||
QCOMPARE(testWidget->text(), expected.at(2));
|
||||
QVERIFY(!testWidget->isRedoAvailable());
|
||||
testWidget->redo();
|
||||
QCOMPARE(testWidget->text(), expected.at(2));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QLineEdit)
|
||||
#include "tst_qlineedit.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user