From 8f949277f68be1f4baeb282b3c483948400dd6ca Mon Sep 17 00:00:00 2001 From: blue Date: Thu, 14 Apr 2022 11:13:27 +0300 Subject: [PATCH] actual pasword reasking on failed authentication --- CHANGELOG.md | 1 + core/account.cpp | 7 ++ core/account.h | 8 ++ core/squawk.cpp | 25 +++- core/squawk.h | 2 +- ui/dialogqueue.cpp | 50 ++++++-- ui/dialogqueue.h | 9 +- ui/squawk.cpp | 10 +- ui/squawk.h | 4 +- ui/widgets/accounts/CMakeLists.txt | 3 + ui/widgets/accounts/credentialsprompt.cpp | 60 +++++++++ ui/widgets/accounts/credentialsprompt.h | 52 ++++++++ ui/widgets/accounts/credentialsprompt.ui | 144 ++++++++++++++++++++++ 13 files changed, 347 insertions(+), 28 deletions(-) create mode 100644 ui/widgets/accounts/credentialsprompt.cpp create mode 100644 ui/widgets/accounts/credentialsprompt.h create mode 100644 ui/widgets/accounts/credentialsprompt.ui diff --git a/CHANGELOG.md b/CHANGELOG.md index 410ff11..55ef1f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ### New features - new "About" window with links, license, gratitudes +- if the authentication failed Squawk will ask againg for your password and login ## Squawk 0.2.1 (Apr 02, 2022) ### Bug fixes diff --git a/core/account.cpp b/core/account.cpp index 4d0480f..3b9d7ec 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -43,6 +43,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& reconnectTimer(new QTimer), network(p_net), passwordType(Shared::AccountPassword::plain), + lastError(Error::none), pepSupport(false), active(p_active), notReadyPassword(false), @@ -183,6 +184,7 @@ void Core::Account::onClientStateChange(QXmppClient::State st) dm->requestItems(getServer()); dm->requestInfo(getServer()); } + lastError = Error::none; emit connectionStateChanged(state); } } else { @@ -415,6 +417,7 @@ void Core::Account::onClientError(QXmppClient::Error err) qDebug() << "Error"; QString errorText; QString errorType; + lastError = Error::other; switch (err) { case QXmppClient::SocketError: errorText = client.socketErrorString(); @@ -456,6 +459,7 @@ void Core::Account::onClientError(QXmppClient::Error err) break; case QXmppStanza::Error::NotAuthorized: errorText = "Authentication error"; + lastError = Error::authentication; break; #if (QXMPP_VERSION) < QT_VERSION_CHECK(1, 3, 0) case QXmppStanza::Error::PaymentRequired: @@ -750,3 +754,6 @@ void Core::Account::renameContactRequest(const QString& jid, const QString& newN void Core::Account::invalidatePassword() { notReadyPassword = true;} +Core::Account::Error Core::Account::getLastError() const { + return lastError;} + diff --git a/core/account.h b/core/account.h index aa65b27..2c9ec70 100644 --- a/core/account.h +++ b/core/account.h @@ -61,6 +61,12 @@ class Account : public QObject friend class RosterHandler; friend class VCardHandler; public: + enum class Error { + authentication, + other, + none + }; + Account( const QString& p_login, const QString& p_server, @@ -82,6 +88,7 @@ public: QString getFullJid() const; Shared::Availability getAvailability() const; Shared::AccountPassword getPasswordType() const; + Error getLastError() const; bool getActive() const; void setName(const QString& p_name); @@ -166,6 +173,7 @@ private: NetworkAccess* network; Shared::AccountPassword passwordType; + Error lastError; bool pepSupport; bool active; bool notReadyPassword; diff --git a/core/squawk.cpp b/core/squawk.cpp index 49a2b34..0f8fe9f 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -260,7 +260,10 @@ void Core::Squawk::disconnectAccount(const QString& account) void Core::Squawk::onAccountConnectionStateChanged(Shared::ConnectionState p_state) { Account* acc = static_cast(sender()); - emit changeAccount(acc->getName(), {{"state", QVariant::fromValue(p_state)}}); + emit changeAccount(acc->getName(), { + {"state", QVariant::fromValue(p_state)}, + {"error", ""} + }); #ifdef WITH_KWALLET if (p_state == Shared::ConnectionState::connected) { @@ -398,6 +401,7 @@ void Core::Squawk::modifyAccountRequest(const QString& name, const QMapgetState(); QMap::const_iterator mItr; bool needToReconnect = false; + bool wentReconnecting = false; mItr = map.find("login"); if (mItr != map.end()) { @@ -428,6 +432,7 @@ void Core::Squawk::modifyAccountRequest(const QString& name, const QMaptoBool() == acc->getActive()) { if (needToReconnect && st != Shared::ConnectionState::disconnected) { acc->reconnect(); + wentReconnecting = true; } } else { acc->setActive(mItr->toBool()); @@ -468,8 +473,12 @@ void Core::Squawk::modifyAccountRequest(const QString& name, const QMapgetActive() && state != Shared::Availability::offline) { - acc->connect(); + if (state != Shared::Availability::offline) { + if (activeChanged && acc->getActive()) { + acc->connect(); + } else if (!wentReconnecting && acc->getActive() && acc->getLastError() == Account::Error::authentication) { + acc->connect(); + } } emit changeAccount(name, map); @@ -479,6 +488,10 @@ void Core::Squawk::onAccountError(const QString& text) { Account* acc = static_cast(sender()); emit changeAccount(acc->getName(), {{"error", text}}); + + if (acc->getLastError() == Account::Error::authentication) { + emit requestPassword(acc->getName(), true); + } } void Core::Squawk::removeAccountRequest(const QString& name) @@ -733,7 +746,7 @@ void Core::Squawk::onAccountNeedPassword() Account* acc = static_cast(sender()); switch (acc->getPasswordType()) { case Shared::AccountPassword::alwaysAsk: - emit requestPassword(acc->getName()); + emit requestPassword(acc->getName(), false); break; case Shared::AccountPassword::kwallet: { #ifdef WITH_KWALLET @@ -741,7 +754,7 @@ void Core::Squawk::onAccountNeedPassword() kwallet.requestReadPassword(acc->getName()); } else { #endif - emit requestPassword(acc->getName()); + emit requestPassword(acc->getName(), false); #ifdef WITH_KWALLET } #endif @@ -754,7 +767,7 @@ void Core::Squawk::onAccountNeedPassword() void Core::Squawk::onWalletRejectPassword(const QString& login) { - emit requestPassword(login); + emit requestPassword(login, false); } void Core::Squawk::responsePassword(const QString& account, const QString& password) diff --git a/core/squawk.h b/core/squawk.h index 6cb3115..c82b1c8 100644 --- a/core/squawk.h +++ b/core/squawk.h @@ -86,7 +86,7 @@ signals: void responseVCard(const QString& jid, const Shared::VCard& card); void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap& data); - void requestPassword(const QString& account); + void requestPassword(const QString& account, bool authernticationError); public slots: void start(); diff --git a/ui/dialogqueue.cpp b/ui/dialogqueue.cpp index f5be82b..02f8688 100644 --- a/ui/dialogqueue.cpp +++ b/ui/dialogqueue.cpp @@ -76,16 +76,31 @@ void DialogQueue::performNextAction() case none: actionDone(); break; - case askPassword: - prompt = new QInputDialog(squawk); - connect(prompt, &QDialog::accepted, this, &DialogQueue::onPropmtAccepted); - connect(prompt, &QDialog::rejected, this, &DialogQueue::onPropmtRejected); - prompt->setInputMode(QInputDialog::TextInput); - prompt->setTextEchoMode(QLineEdit::Password); - prompt->setLabelText(tr("Input the password for account %1").arg(currentSource)); - prompt->setWindowTitle(tr("Password for account %1").arg(currentSource)); - prompt->setTextValue(""); - prompt->exec(); + case askPassword: { + QInputDialog* dialog = new QInputDialog(squawk); + prompt = dialog; + connect(dialog, &QDialog::accepted, this, &DialogQueue::onPropmtAccepted); + connect(dialog, &QDialog::rejected, this, &DialogQueue::onPropmtRejected); + dialog->setInputMode(QInputDialog::TextInput); + dialog->setTextEchoMode(QLineEdit::Password); + dialog->setLabelText(tr("Input the password for account %1").arg(currentSource)); + dialog->setWindowTitle(tr("Password for account %1").arg(currentSource)); + dialog->setTextValue(""); + dialog->exec(); + } + break; + case askCredentials: { + CredentialsPrompt* dialog = new CredentialsPrompt(squawk); + prompt = dialog; + connect(dialog, &QDialog::accepted, this, &DialogQueue::onPropmtAccepted); + connect(dialog, &QDialog::rejected, this, &DialogQueue::onPropmtRejected); + Models::Account* acc = squawk->rosterModel.getAccount(currentSource); + dialog->setAccount(currentSource); + dialog->setLogin(acc->getLogin()); + dialog->setPassword(acc->getPassword()); + dialog->exec(); + } + break; } } @@ -94,8 +109,18 @@ void DialogQueue::onPropmtAccepted() switch (currentAction) { case none: break; - case askPassword: - emit squawk->responsePassword(currentSource, prompt->textValue()); + case askPassword: { + QInputDialog* dialog = static_cast(prompt); + emit squawk->responsePassword(currentSource, dialog->textValue()); + } + break; + case askCredentials: { + CredentialsPrompt* dialog = static_cast(prompt); + emit squawk->modifyAccountRequest(currentSource, { + {"login", dialog->getLogin()}, + {"password", dialog->getPassword()} + }); + } break; } actionDone(); @@ -107,6 +132,7 @@ void DialogQueue::onPropmtRejected() case none: break; case askPassword: + case askCredentials: emit squawk->disconnectAccount(currentSource); break; } diff --git a/ui/dialogqueue.h b/ui/dialogqueue.h index c5bf011..bfc1f21 100644 --- a/ui/dialogqueue.h +++ b/ui/dialogqueue.h @@ -24,9 +24,7 @@ #include #include -/** - * @todo write docs - */ +#include class Squawk; @@ -36,7 +34,8 @@ class DialogQueue : public QObject public: enum Action { none, - askPassword + askPassword, + askCredentials }; DialogQueue(Squawk* squawk); @@ -85,7 +84,7 @@ private: Collection& collection; Sequence& sequence; - QInputDialog* prompt; + QDialog* prompt; Squawk* squawk; }; diff --git a/ui/squawk.cpp b/ui/squawk.cpp index a447458..a0f16b2 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -880,8 +880,14 @@ void Squawk::onItemCollepsed(const QModelIndex& index) } } -void Squawk::requestPassword(const QString& account) { - dialogueQueue.addAction(account, DialogQueue::askPassword);} +void Squawk::requestPassword(const QString& account, bool authenticationError) { + if (authenticationError) { + dialogueQueue.addAction(account, DialogQueue::askCredentials); + } else { + dialogueQueue.addAction(account, DialogQueue::askPassword); + } + +} void Squawk::subscribeConversation(Conversation* conv) { diff --git a/ui/squawk.h b/ui/squawk.h index 6ee666c..5a77f17 100644 --- a/ui/squawk.h +++ b/ui/squawk.h @@ -51,7 +51,7 @@ class Squawk; class Squawk : public QMainWindow { Q_OBJECT - + friend class DialogQueue; public: explicit Squawk(QWidget *parent = nullptr); ~Squawk() override; @@ -114,7 +114,7 @@ public slots: void fileUploadComplete(const std::list msgs, const QString& url, const QString& path); void responseVCard(const QString& jid, const Shared::VCard& card); void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap& data); - void requestPassword(const QString& account); + void requestPassword(const QString& account, bool authenticationError); private: typedef std::map Conversations; diff --git a/ui/widgets/accounts/CMakeLists.txt b/ui/widgets/accounts/CMakeLists.txt index ad2f117..970985d 100644 --- a/ui/widgets/accounts/CMakeLists.txt +++ b/ui/widgets/accounts/CMakeLists.txt @@ -5,4 +5,7 @@ target_sources(squawk PRIVATE accounts.cpp accounts.h accounts.ui + credentialsprompt.cpp + credentialsprompt.h + credentialsprompt.ui ) diff --git a/ui/widgets/accounts/credentialsprompt.cpp b/ui/widgets/accounts/credentialsprompt.cpp new file mode 100644 index 0000000..3d1bafa --- /dev/null +++ b/ui/widgets/accounts/credentialsprompt.cpp @@ -0,0 +1,60 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "credentialsprompt.h" +#include "ui_credentialsprompt.h" + +CredentialsPrompt::CredentialsPrompt(QWidget* parent): + QDialog(parent), + m_ui(new Ui::CredentialsPrompt), + title(), + message() +{ + m_ui->setupUi(this); + + title = windowTitle(); + message = m_ui->message->text(); +} + +CredentialsPrompt::~CredentialsPrompt() +{ +} + +void CredentialsPrompt::setAccount(const QString& account) +{ + m_ui->message->setText(message.arg(account)); + setWindowTitle(title.arg(account)); +} + +QString CredentialsPrompt::getLogin() const +{ + return m_ui->login->text(); +} + +QString CredentialsPrompt::getPassword() const +{ + return m_ui->password->text(); +} + +void CredentialsPrompt::setLogin(const QString& login) +{ + m_ui->login->setText(login); +} + +void CredentialsPrompt::setPassword(const QString& password) +{ + m_ui->password->setText(password); +} diff --git a/ui/widgets/accounts/credentialsprompt.h b/ui/widgets/accounts/credentialsprompt.h new file mode 100644 index 0000000..ce9a791 --- /dev/null +++ b/ui/widgets/accounts/credentialsprompt.h @@ -0,0 +1,52 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef CREDENTIALSPROMPT_H +#define CREDENTIALSPROMPT_H + +#include +#include + +namespace Ui +{ +class CredentialsPrompt; +} + +/** + * @todo write docs + */ +class CredentialsPrompt : public QDialog +{ + Q_OBJECT + +public: + CredentialsPrompt(QWidget* parent = nullptr); + ~CredentialsPrompt(); + + void setAccount(const QString& account); + void setLogin(const QString& login); + void setPassword(const QString& password); + + QString getLogin() const; + QString getPassword() const; + +private: + QScopedPointer m_ui; + QString title; + QString message; +}; + +#endif // CREDENTIALSPROMPT_H diff --git a/ui/widgets/accounts/credentialsprompt.ui b/ui/widgets/accounts/credentialsprompt.ui new file mode 100644 index 0000000..2ad4d8d --- /dev/null +++ b/ui/widgets/accounts/credentialsprompt.ui @@ -0,0 +1,144 @@ + + + CredentialsPrompt + + + + 0 + 0 + 318 + 229 + + + + Authentication error: %1 + + + + + + true + + + + 0 + 0 + + + + Couldn't authenticate account %1: login or password is icorrect. +Would you like to check them and try again? + + + Qt::AlignCenter + + + true + + + + + + + + + Login + + + + + + + Your account login (without @server.domain) + + + + + + + Password + + + + + + + Your password + + + Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhSensitiveData + + + + + + QLineEdit::Password + + + false + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + CredentialsPrompt + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonBox + rejected() + CredentialsPrompt + reject() + + + 20 + 20 + + + 20 + 20 + + + + +