summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJani Honkonen <jani.honkonen@digia.com>2012-02-03 14:57:58 (GMT)
committerQt by Nokia <qt-info@nokia.com>2012-08-22 00:59:33 (GMT)
commitc09e9f71173a698670d6c728291ee24f53d50800 (patch)
treeeece03b674f7783807205b4aa01a097914ce4a6e
parent1de75716d6f0691cc57feb21768f250236eebfd4 (diff)
downloadQt-c09e9f71173a698670d6c728291ee24f53d50800.zip
Qt-c09e9f71173a698670d6c728291ee24f53d50800.tar.gz
Qt-c09e9f71173a698670d6c728291ee24f53d50800.tar.bz2
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. Backported from Qt5 SHA1: 121062d8848986dcfaf421388a5603b3b48a1e58 Task-number: QTBUG-14226 Change-Id: Ia712f95e8a2e45537a95d48b70686a1a8dd95da2 Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
-rw-r--r--src/gui/widgets/qlinecontrol.cpp22
-rw-r--r--src/gui/widgets/qlinecontrol_p.h4
-rw-r--r--tests/auto/qlineedit/tst_qlineedit.cpp66
3 files changed, 90 insertions, 2 deletions
diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp
index 8c7822c..d626bde 100644
--- a/src/gui/widgets/qlinecontrol.cpp
+++ b/src/gui/widgets/qlinecontrol.cpp
@@ -1202,6 +1202,13 @@ void QLineControl::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) {
@@ -1891,6 +1898,21 @@ void QLineControl::processKeyEvent(QKeyEvent* event)
event->accept();
}
+bool QLineControl::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 == QLineControl::Insert);
+}
+
+bool QLineControl::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
diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h
index 20ecdfd..b5ae92f 100644
--- a/src/gui/widgets/qlinecontrol_p.h
+++ b/src/gui/widgets/qlinecontrol_p.h
@@ -113,8 +113,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; }
diff --git a/tests/auto/qlineedit/tst_qlineedit.cpp b/tests/auto/qlineedit/tst_qlineedit.cpp
index cbbe1e7..d96fc9b 100644
--- a/tests/auto/qlineedit/tst_qlineedit.cpp
+++ b/tests/auto/qlineedit/tst_qlineedit.cpp
@@ -295,6 +295,9 @@ private slots:
void bidiLogicalMovement_data();
void bidiLogicalMovement();
+ void undoRedoAndEchoModes_data();
+ void undoRedoAndEchoModes();
+
protected slots:
#ifdef QT3_SUPPORT
void lostFocus();
@@ -3979,5 +3982,68 @@ void tst_QLineEdit::bidiLogicalMovement()
} while (moved && i >= 0);
}
+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"