actual pasword reasking on failed authentication

This commit is contained in:
Blue 2022-04-14 11:13:27 +03:00
parent ce686e121b
commit 8f949277f6
Signed by: blue
GPG Key ID: 9B203B252A63EE38
13 changed files with 347 additions and 28 deletions

View File

@ -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

View File

@ -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;}

View File

@ -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;

View File

@ -260,7 +260,10 @@ void Core::Squawk::disconnectAccount(const QString& account)
void Core::Squawk::onAccountConnectionStateChanged(Shared::ConnectionState p_state)
{
Account* acc = static_cast<Account*>(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 QMap<QString,
Shared::ConnectionState st = acc->getState();
QMap<QString, QVariant>::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 QMap<QString,
if (mItr == map.end() || mItr->toBool() == 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 QMap<QString,
}
#endif
if (activeChanged && acc->getActive() && 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<Account*>(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<Account*>(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)

View File

@ -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<QString, QVariant>& data);
void requestPassword(const QString& account);
void requestPassword(const QString& account, bool authernticationError);
public slots:
void start();

View File

@ -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<QInputDialog*>(prompt);
emit squawk->responsePassword(currentSource, dialog->textValue());
}
break;
case askCredentials: {
CredentialsPrompt* dialog = static_cast<CredentialsPrompt*>(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;
}

View File

@ -24,9 +24,7 @@
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
/**
* @todo write docs
*/
#include <ui/widgets/accounts/credentialsprompt.h>
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;
};

View File

@ -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)
{

View File

@ -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<Shared::MessageInfo> 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<QString, QVariant>& data);
void requestPassword(const QString& account);
void requestPassword(const QString& account, bool authenticationError);
private:
typedef std::map<Models::Roster::ElId, Conversation*> Conversations;

View File

@ -5,4 +5,7 @@ target_sources(squawk PRIVATE
accounts.cpp
accounts.h
accounts.ui
credentialsprompt.cpp
credentialsprompt.h
credentialsprompt.ui
)

View File

@ -0,0 +1,60 @@
// Squawk messenger.
// Copyright (C) 2019 Yury Gubich <blue@macaw.me>
//
// 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 <http://www.gnu.org/licenses/>.
#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);
}

View File

@ -0,0 +1,52 @@
// Squawk messenger.
// Copyright (C) 2019 Yury Gubich <blue@macaw.me>
//
// 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 <http://www.gnu.org/licenses/>.
#ifndef CREDENTIALSPROMPT_H
#define CREDENTIALSPROMPT_H
#include <qdialog.h>
#include <QScopedPointer>
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<Ui::CredentialsPrompt> m_ui;
QString title;
QString message;
};
#endif // CREDENTIALSPROMPT_H

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CredentialsPrompt</class>
<widget class="QDialog" name="CredentialsPrompt">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>318</width>
<height>229</height>
</rect>
</property>
<property name="windowTitle">
<string>Authentication error: %1</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
<item>
<widget class="QLabel" name="message">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Couldn't authenticate account %1: login or password is icorrect.
Would you like to check them and try again?</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="loginLabel">
<property name="text">
<string>Login</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="login">
<property name="toolTip">
<string>Your account login (without @server.domain)</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="passwordLabel">
<property name="text">
<string>Password</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="password">
<property name="toolTip">
<string>Your password</string>
</property>
<property name="inputMethodHints">
<set>Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhSensitiveData</set>
</property>
<property name="text">
<string/>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>CredentialsPrompt</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>CredentialsPrompt</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
</connections>
</ui>