// vi: ts=8 sts=4 sw=4 /* This file is part of the KDE libraries Copyright (C) 1998 Pietro Iglio Copyright (C) 1999,2000 Geert Jansen Copyright (C) 2004,2005 Andrew Coles Copyright (C) 2007 Michaƫl Larouche Copyright (C) 2009 Christoph Feck This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "knewpassworddialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_knewpassworddialog.h" class KNewPasswordDialog::KNewPasswordDialogPrivate { public: KNewPasswordDialogPrivate(KNewPasswordDialog *parent) : q(parent), minimumPasswordLength(0), passwordStrengthWarningLevel(1), reasonablePasswordLength(8) { } void init(); void _k_textChanged(); KNewPasswordDialog *q; int minimumPasswordLength; int passwordStrengthWarningLevel; int reasonablePasswordLength; int effectivePasswordLength(const QString &password); QString pass; Ui::KNewPasswordDialog ui; }; void KNewPasswordDialog::KNewPasswordDialogPrivate::init() { q->setButtons( Ok | Cancel ); q->setDefaultButton( Ok ); ui.setupUi( q->mainWidget() ); ui.pixmapIcon->setPixmap( KIcon("dialog-password").pixmap(96, 96) ); ui.labelMatch->setHidden(true); const QString strengthBarWhatsThis( i18n( "The password strength meter gives an indication of the security " "of the password you have entered. To improve the strength of " "the password, try:\n" " - using a longer password;\n" " - using a mixture of upper- and lower-case letters;\n" " - using numbers or symbols, such as #, as well as letters." ) ); ui.labelStrengthMeter->setWhatsThis(strengthBarWhatsThis); ui.strengthBar->setWhatsThis(strengthBarWhatsThis); connect(ui.linePassword, SIGNAL(textChanged(QString)), q, SLOT(_k_textChanged())); connect(ui.lineVerifyPassword, SIGNAL(textChanged(QString)), q, SLOT(_k_textChanged())); ui.linePassword->setFocus(); _k_textChanged(); } int KNewPasswordDialog::KNewPasswordDialogPrivate::effectivePasswordLength(const QString &password) { enum Category { Digit, Upper, Vowel, Consonant, Special }; Category previousCategory = Vowel; QString vowels("aeiou"); int count = 0; for (int i = 0; i < password.length(); ++i) { QChar currentChar = password.at(i); if (!password.left(i).contains(currentChar)) { Category currentCategory; switch (currentChar.category()) { case QChar::Letter_Uppercase: { currentCategory = Upper; break; } case QChar::Letter_Lowercase: { if (vowels.contains(currentChar)) { currentCategory = Vowel; } else { currentCategory = Consonant; } break; } case QChar::Number_DecimalDigit: { currentCategory = Digit; break; } default: { currentCategory = Special; break; } } switch (currentCategory) { case Vowel: { if (previousCategory != Consonant) { ++count; } break; } case Consonant: { if (previousCategory != Vowel) { ++count; } break; } default: { if (previousCategory != currentCategory) { ++count; } break; } } previousCategory = currentCategory; } } return count; } void KNewPasswordDialog::KNewPasswordDialogPrivate::_k_textChanged() { const bool match = ui.linePassword->text() == ui.lineVerifyPassword->text(); const int minPasswordLength = q->minimumPasswordLength(); if (ui.linePassword->text().length() < minPasswordLength) { q->enableButtonOk(false); } else { q->enableButtonOk(match); } if ( match && !q->allowEmptyPasswords() && ui.linePassword->text().isEmpty()) { ui.labelMatch->setPixmap(KIcon("dialog-error")); ui.labelMatch->setText(i18n("Password is empty")); } else { if ( ui.linePassword->text().length() < minPasswordLength ) { ui.labelMatch->setPixmap( KIcon("dialog-error") ); ui.labelMatch->setText( i18np("Password must be at least 1 character long", "Password must be at least %1 characters long", minPasswordLength) ); } else { ui.labelMatch->setPixmap(match ? KIcon("dialog-ok") : KIcon("dialog-error")); // "ok" icon should probably be "dialog-success", but we don't have that icon in KDE 4.0 ui.labelMatch->setText(match? i18n("Passwords match") : i18n("Passwords do not match")); } } // Password strength calculator int pwstrength = (20 * ui.linePassword->text().length() + 80 * effectivePasswordLength(ui.linePassword->text())) / qMax(reasonablePasswordLength, 2); if (pwstrength < 0) { pwstrength = 0; } else if (pwstrength > 100) { pwstrength = 100; } ui.strengthBar->setValue(pwstrength); } KNewPasswordDialog::KNewPasswordDialog( QWidget *parent) : KDialog(parent), d(new KNewPasswordDialogPrivate(this)) { d->init(); } KNewPasswordDialog::~KNewPasswordDialog() { delete d; } void KNewPasswordDialog::setPrompt(const QString &prompt) { d->ui.labelPrompt->setText(prompt); } QString KNewPasswordDialog::prompt() const { return d->ui.labelPrompt->text(); } void KNewPasswordDialog::setPixmap(const QPixmap &pixmap) { d->ui.pixmapIcon->setPixmap(pixmap); d->ui.pixmapIcon->setFixedSize(d->ui.pixmapIcon->sizeHint()); } QPixmap KNewPasswordDialog::pixmap() const { return d->ui.pixmapIcon->pixmap(); } bool KNewPasswordDialog::checkAndGetPassword(QString *pwd) { pwd->clear(); if ( d->ui.linePassword->text() != d->ui.lineVerifyPassword->text() ) { d->ui.labelMatch->setPixmap(KTitleWidget::ErrorMessage); d->ui.labelMatch->setText(i18n("You entered two different passwords. Please try again.")); d->ui.linePassword->clear(); d->ui.lineVerifyPassword->clear(); return false; } if (d->ui.strengthBar && d->ui.strengthBar->value() < d->passwordStrengthWarningLevel) { int retVal = KMessageBox::warningYesNo( this, i18n( "The password you have entered has a low strength. " "To improve the strength of " "the password, try:\n" " - using a longer password;\n" " - using a mixture of upper- and lower-case letters;\n" " - using numbers or symbols as well as letters.\n" "\n" "Would you like to use this password anyway?" ), i18n("Low Password Strength") ); if (retVal == KMessageBox::No) { return false; } } if (!checkPassword(d->ui.linePassword->text())) { return false; } *pwd = d->ui.linePassword->text(); return true; } void KNewPasswordDialog::accept() { QString pwd; if (!checkAndGetPassword(&pwd)) { return; } d->pass = pwd; emit newPassword( d->pass ); KDialog::accept(); } void KNewPasswordDialog::setAllowEmptyPasswords(bool allowed) { setMinimumPasswordLength(allowed ? 0 : 1); d->_k_textChanged(); } bool KNewPasswordDialog::allowEmptyPasswords() const { return d->minimumPasswordLength == 0; } void KNewPasswordDialog::setMinimumPasswordLength(int minLength) { d->minimumPasswordLength = minLength; d->_k_textChanged(); } int KNewPasswordDialog::minimumPasswordLength() const { return d->minimumPasswordLength; } void KNewPasswordDialog::setMaximumPasswordLength(int maxLength) { d->ui.linePassword->setMaxLength(maxLength); d->ui.lineVerifyPassword->setMaxLength(maxLength); } int KNewPasswordDialog::maximumPasswordLength() const { return d->ui.linePassword->maxLength(); } void KNewPasswordDialog::setReasonablePasswordLength(int reasonableLength) { if (reasonableLength < 1) { reasonableLength = 1; } if (reasonableLength >= maximumPasswordLength()) { reasonableLength = maximumPasswordLength(); } d->reasonablePasswordLength = reasonableLength; } int KNewPasswordDialog::reasonablePasswordLength() const { return d->reasonablePasswordLength; } void KNewPasswordDialog::setPasswordStrengthWarningLevel(int warningLevel) { if (warningLevel < 0) { warningLevel = 0; } if (warningLevel > 99) { warningLevel = 99; } d->passwordStrengthWarningLevel = warningLevel; } int KNewPasswordDialog::passwordStrengthWarningLevel() const { return d->passwordStrengthWarningLevel; } QString KNewPasswordDialog::password() const { return d->pass; } bool KNewPasswordDialog::checkPassword(const QString &) { return true; } #include "moc_knewpassworddialog.cpp"