KWidgetsAddons

knewpasswordwidget.cpp
1// vi: ts=8 sts=4 sw=4
2/*
3 This file is part of the KDE libraries
4 SPDX-FileCopyrightText: 1998 Pietro Iglio <iglio@fub.it>
5 SPDX-FileCopyrightText: 1999, 2000 Geert Jansen <jansen@kde.org>
6 SPDX-FileCopyrightText: 2004, 2005 Andrew Coles <andrew_coles@yahoo.co.uk>
7 SPDX-FileCopyrightText: 2007 Michaƫl Larouche <larouche@kde.org>
8 SPDX-FileCopyrightText: 2009 Christoph Feck <cfeck@kde.org>
9 SPDX-FileCopyrightText: 2015 Elvis Angelaccio <elvis.angelaccio@kde.org>
10
11 SPDX-License-Identifier: LGPL-2.0-only
12*/
13
14#include "knewpasswordwidget.h"
15#include "ui_knewpasswordwidget.h"
16
17class KNewPasswordWidgetPrivate
18{
19 Q_DECLARE_TR_FUNCTIONS(KNewPasswordWidget)
20
21public:
22 KNewPasswordWidgetPrivate(KNewPasswordWidget *parent)
23 : q(parent)
24 {
25 }
26
27 void init();
28 void passwordChanged();
29 void toggleEchoMode();
30 int effectivePasswordLength(QStringView password);
31 void updatePasswordStatus(KNewPasswordWidget::PasswordStatus status);
32
33 KNewPasswordWidget *const q;
34
36 int minimumPasswordLength = 0;
37 int passwordStrengthWarningLevel = 1;
38 int reasonablePasswordLength = 8;
39
40 QAction *toggleEchoModeAction = nullptr;
41 QColor backgroundWarningColor;
42 QColor defaultBackgroundColor;
43
44 Ui::KNewPasswordWidget ui;
45};
46
47void KNewPasswordWidgetPrivate::init()
48{
49 ui.setupUi(q);
50
51 const QString strengthBarWhatsThis(
52 tr("The password strength meter gives an indication of the security "
53 "of the password you have entered. To improve the strength of the password, try:"
54 "<ul><li>using a longer password;</li>"
55 "<li>using a mixture of upper- and lower-case letters;</li>"
56 "<li>using numbers or symbols, such as #, as well as letters.</li></ul>",
57 "@info:whatsthis"));
58 ui.labelStrengthMeter->setWhatsThis(strengthBarWhatsThis);
59 ui.strengthBar->setWhatsThis(strengthBarWhatsThis);
60
61 QObject::connect(ui.linePassword, &KPasswordLineEdit::echoModeChanged, q, [this]() {
62 toggleEchoMode();
63 });
64
65 QObject::connect(ui.linePassword, &KPasswordLineEdit::passwordChanged, q, [this]() {
66 passwordChanged();
67 });
68 QObject::connect(ui.lineVerifyPassword, &QLineEdit::textChanged, q, [this]() {
69 passwordChanged();
70 });
71
72 defaultBackgroundColor = q->palette().color(QPalette::Active, QPalette::Base);
73 backgroundWarningColor = defaultBackgroundColor;
74
75 passwordChanged();
76}
77
78void KNewPasswordWidgetPrivate::passwordChanged()
79{
80 const QString password = ui.linePassword->password();
81 const QString verification = ui.lineVerifyPassword->text();
82 const bool match = (password == verification);
83 const bool partialMatch = password.startsWith(verification);
84 const int minPasswordLength = q->minimumPasswordLength();
85
86 QPalette palette = q->palette();
87 palette.setColor(QPalette::Active, QPalette::Base, (match || partialMatch) ? defaultBackgroundColor : backgroundWarningColor);
88 ui.lineVerifyPassword->setPalette(palette);
89
90 // Password strength calculator
91 int pwstrength =
92 (20 * ui.linePassword->password().length() + 80 * effectivePasswordLength(ui.linePassword->password())) / qMax(reasonablePasswordLength, 2);
93 ui.strengthBar->setValue(qBound(0, pwstrength, 100));
94
95 // update the current password status
96 if (match || ui.lineVerifyPassword->isHidden()) {
97 if (!q->allowEmptyPasswords() && ui.linePassword->password().isEmpty()) {
99 } else if (ui.linePassword->password().length() < minPasswordLength) {
100 updatePasswordStatus(KNewPasswordWidget::PasswordTooShort);
101 } else if (ui.strengthBar && ui.strengthBar->value() < passwordStrengthWarningLevel) {
102 updatePasswordStatus(KNewPasswordWidget::WeakPassword);
103 } else {
104 updatePasswordStatus(KNewPasswordWidget::StrongPassword);
105 }
106 } else {
107 updatePasswordStatus(KNewPasswordWidget::PasswordNotVerified);
108 }
109}
110
111void KNewPasswordWidgetPrivate::toggleEchoMode()
112{
113 if (ui.linePassword->lineEdit()->echoMode() == QLineEdit::Normal) {
114 ui.lineVerifyPassword->hide();
115 ui.labelVerifyPassword->hide();
116 } else if (ui.linePassword->lineEdit()->echoMode() == QLineEdit::Password) {
117 ui.lineVerifyPassword->show();
118 ui.labelVerifyPassword->show();
119 }
120 passwordChanged();
121}
122
123int KNewPasswordWidgetPrivate::effectivePasswordLength(QStringView password)
124{
125 enum Category {
126 Digit,
127 Upper,
128 Vowel,
129 Consonant,
130 Special,
131 };
132
133 Category previousCategory = Vowel;
134 static const QLatin1String vowels("aeiou");
135 int count = 0;
136
137 const int len = password.length();
138 for (int i = 0; i < len; ++i) {
139 const QChar currentChar = password.at(i);
140 if (!password.left(i).contains(currentChar)) {
141 Category currentCategory;
142 switch (currentChar.category()) {
144 currentCategory = Upper;
145 break;
147 if (vowels.contains(currentChar)) {
148 currentCategory = Vowel;
149 } else {
150 currentCategory = Consonant;
151 }
152 break;
154 currentCategory = Digit;
155 break;
156 default:
157 currentCategory = Special;
158 break;
159 }
160 switch (currentCategory) {
161 case Vowel:
162 if (previousCategory != Consonant) {
163 ++count;
164 }
165 break;
166 case Consonant:
167 if (previousCategory != Vowel) {
168 ++count;
169 }
170 break;
171 default:
172 if (previousCategory != currentCategory) {
173 ++count;
174 }
175 break;
176 }
177 previousCategory = currentCategory;
178 }
179 }
180 return count;
181}
182
183void KNewPasswordWidgetPrivate::updatePasswordStatus(KNewPasswordWidget::PasswordStatus status)
184{
185 if (passwordStatus == status) {
186 return;
187 }
188
189 passwordStatus = status;
190 Q_EMIT q->passwordStatusChanged();
191}
192
194 : QWidget(parent)
195 , d(new KNewPasswordWidgetPrivate(this))
196{
197 d->init();
198}
199
201
202KNewPasswordWidget::PasswordStatus KNewPasswordWidget::passwordStatus() const
203{
204 return d->passwordStatus;
205}
206
207bool KNewPasswordWidget::allowEmptyPasswords() const
208{
209 return d->minimumPasswordLength == 0;
210}
211
212int KNewPasswordWidget::minimumPasswordLength() const
213{
214 return d->minimumPasswordLength;
215}
216
217int KNewPasswordWidget::maximumPasswordLength() const
218{
219 return d->ui.linePassword->lineEdit()->maxLength();
220}
221
222int KNewPasswordWidget::reasonablePasswordLength() const
223{
224 return d->reasonablePasswordLength;
225}
226
227int KNewPasswordWidget::passwordStrengthWarningLevel() const
228{
229 return d->passwordStrengthWarningLevel;
230}
231
232QColor KNewPasswordWidget::backgroundWarningColor() const
233{
234 return d->backgroundWarningColor;
235}
236
238{
239 return d->ui.labelStrengthMeter->isVisible() && d->ui.strengthBar->isVisible();
240}
241
242#if KWIDGETSADDONS_ENABLE_DEPRECATED_SINCE(6, 0)
243#pragma GCC diagnostic push
244#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
246{
247 return d->ui.linePassword->isRevealPasswordAvailable();
248}
249#pragma GCC diagnostic pop
250#endif
251
252KPassword::RevealMode KNewPasswordWidget::revealPasswordMode() const
253{
254 return d->ui.linePassword->revealPasswordMode();
255}
256
258{
259 return d->ui.linePassword->password();
260}
261
263{
264 setMinimumPasswordLength(allowed ? 0 : 1);
265 d->passwordChanged();
266}
267
269{
270 d->minimumPasswordLength = minLength;
271 d->passwordChanged();
272}
273
275{
276 if (maxLength < minimumPasswordLength()) {
277 maxLength = minimumPasswordLength();
278 }
279
280 d->ui.linePassword->lineEdit()->setMaxLength(maxLength);
281 d->ui.lineVerifyPassword->setMaxLength(maxLength);
282}
283
284// reasonable password length code contributed by Steffen Mthing
285
287{
288 d->reasonablePasswordLength = qBound(1, reasonableLength, maximumPasswordLength());
289}
290
292{
293 d->passwordStrengthWarningLevel = qBound(0, warningLevel, 99);
294}
295
297{
298 d->backgroundWarningColor = color;
299 update();
300}
301
303{
304 d->ui.labelStrengthMeter->setVisible(visible);
305 d->ui.strengthBar->setVisible(visible);
306}
307
308#if KWIDGETSADDONS_ENABLE_DEPRECATED_SINCE(6, 0)
309#pragma GCC diagnostic push
310#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
312{
313 d->ui.linePassword->setRevealPasswordAvailable(reveal);
314}
315#pragma GCC diagnostic pop
316#endif
317
318void KNewPasswordWidget::setRevealPasswordMode(KPassword::RevealMode revealPasswordMode)
319{
320 d->ui.linePassword->setRevealPasswordMode(revealPasswordMode);
321}
322
323#include "moc_knewpasswordwidget.cpp"
A password input widget.
void setRevealPasswordAvailable(bool reveal)
Whether to show the visibility trailing action in the line edit.
void passwordStatusChanged()
Notify about the current status of the password being typed.
PasswordStatus
Status of the password being typed in the widget.
@ PasswordNotVerified
Password and verification password don't match.
@ StrongPassword
Passwords match and the strength level is good.
@ WeakPassword
Passwords match but the strength level is not enough.
@ EmptyPasswordNotAllowed
Both passwords fields empty, but minimum length > 0.
@ PasswordTooShort
Password length is too low.
KNewPasswordWidget(QWidget *parent=nullptr)
Constructs a password widget.
~KNewPasswordWidget() override
Destructs the password widget.
void setAllowEmptyPasswords(bool allowed)
Allow empty passwords? - Default: true.
bool isRevealPasswordAvailable() const
Whether the visibility trailing action in the line edit is visible.
void setPasswordStrengthWarningLevel(int warningLevel)
Set the password strength level below which a warning is given The value is guaranteed to be in the r...
void setBackgroundWarningColor(const QColor &color)
When the verification password does not match, the background color of the verification field is set ...
void setReasonablePasswordLength(int reasonableLength)
Password length that is expected to be reasonably safe.
void setPasswordStrengthMeterVisible(bool visible)
Whether to show the password strength meter (label and progress bar).
void setMaximumPasswordLength(int maxLength)
Maximum acceptable password length.
bool isPasswordStrengthMeterVisible() const
Whether the password strength meter is visible.
QString password() const
Returns the password entered.
void setRevealPasswordMode(KPassword::RevealMode revealPasswordMode)
Set when the reveal password button will be visible.
void setMinimumPasswordLength(int minLength)
Minimum acceptable password length.
void echoModeChanged(QLineEdit::EchoMode echoMode)
When we click on visibility icon echo mode is switched between Normal echo mode and Password echo mod...
Q_SCRIPTABLE CaptureState status()
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
Letter_Uppercase
Category category(char32_t ucs4)
void textChanged(const QString &text)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
void setColor(ColorGroup group, ColorRole role, const QColor &color)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QStringView left(qsizetype length) const const
QChar at(qsizetype n) const const
bool contains(QChar c, Qt::CaseSensitivity cs) const const
qsizetype length() const const
void update()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.