Cockatrice/cockatrice/src/interface/widgets/dialogs/dlg_connect.h
Lukas Brübach fb7f7dde55
[Security] Add challenge-response auth with scrypt verifiers and stop storing plaintext passwords
Challenge-response authentication: the client derives a scrypt verifier
(RFC 7914, EVP_PBE_scrypt, N=32768, r=8, p=1) and authenticates with
HMAC-SHA256(key, nonce), so neither the password nor its hash is
transmitted. The stored format becomes
"$scrypt$<n>$<r>$<p>$<salt>$<verifier>" and Response_PasswordSalt
now carries the cost parameters. Strict servers only accept scrypt
verifiers; legacy accounts are migrated after a successful login.

Fix #344 for challenge-response servers: a saved profile stores the
derived verifier under the password key instead of the plaintext password.
The connect dialog loads it without revealing it, autoconnect passes it
through, the change-password dialog no longer prefills the old password
field with it, and the client only persists the verifier when
"Save password" is checked.

Took 3 minutes

Took 1 minute

Took 10 seconds

Took 7 minutes
2026-08-29 15:58:57 +02:00

97 lines
2.8 KiB
C++

/**
* @file dlg_connect.h
* @ingroup ConnectionDialogs
*/
//! \todo Document this file.
#ifndef DLG_CONNECT_H
#define DLG_CONNECT_H
#include "../interface/widgets/server/handle_public_servers.h"
#include "../interface/widgets/server/user/user_info_connection.h"
#include <QCheckBox>
#include <QDialog>
#include <QLineEdit>
#include <libcockatrice/utility/macros.h>
class QCheckBox;
class QComboBox;
class QGridLayout;
class QGroupBox;
class QHBoxLayout;
class QLabel;
class QPushButton;
class QRadioButton;
class QVBoxLayout;
class DlgConnect : public QDialog
{
Q_OBJECT
signals:
void sigStartForgotPasswordRequest();
void sigPublicServersDownloaded();
public:
explicit DlgConnect(QWidget *parent = nullptr);
~DlgConnect() override;
[[nodiscard]] QString getHost() const;
[[nodiscard]] int getPort() const
{
return portEdit->text().toInt();
}
[[nodiscard]] QString getPlayerName() const
{
return playernameEdit->text();
}
[[nodiscard]] QString getPassword() const
{
return passwordEdit->text();
}
//! \brief Stored "$scrypt$..." verifier for challenge-response servers (never the plaintext password).
[[nodiscard]] QString getStoredVerifier() const
{
return storedVerifier;
}
[[nodiscard]] QString getSaveName() const
{
return saveEdit->text();
}
[[nodiscard]] bool getSavePassword() const
{
return savePasswordCheckBox->isChecked();
}
public slots:
void downloadThePublicServers();
private slots:
void actOk();
void passwordSaved(QT_STATE_CHANGED_T state);
void previousHostSelected(bool state);
void newHostSelected(bool state);
void actForgotPassword();
void actRemoveSavedServer();
void updateDisplayInfo(const QString &saveName);
void preRebuildComboBoxList();
void rebuildComboBoxList(int failure = -1);
private:
QGridLayout *connectionLayout, *loginLayout, *serverInfoLayout, *grid;
QHBoxLayout *newHolderLayout, *forgotPasswordLayout;
QGroupBox *loginGroupBox, *serverInfoGroupBox, *restrictionsGroupBox;
QVBoxLayout *mainLayout;
QLabel *hostLabel, *portLabel, *playernameLabel, *passwordLabel, *saveLabel, *serverIssuesLabel,
*serverContactLabel, *serverContactLink, *forgotPasswordLabel;
QLineEdit *hostEdit, *portEdit, *playernameEdit, *passwordEdit, *saveEdit;
QCheckBox *savePasswordCheckBox, *autoConnectCheckBox;
QComboBox *previousHosts;
QRadioButton *newHostButton, *previousHostButton;
QPushButton *btnConnect, *btnForgotPassword, *btnRefreshServers, *btnDeleteServer;
QMap<QString, std::pair<QString, UserConnection_Information>> savedHostList;
HandlePublicServers *hps;
QString storedVerifier;
const QString placeHolderText = tr("Downloading...");
};
#endif