Skip to content

Commit 622e056

Browse files
committed
Add debug implementation
1 parent 4c46c38 commit 622e056

File tree

7 files changed

+140
-17
lines changed

7 files changed

+140
-17
lines changed

src/app/dialogs/connect.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ ConnectionWindow::ConnectionWindow(QWeakPointer<ConnectionsManager> manager, QWi
2020
// connect slots to signals
2121
connect(ui.okButton, SIGNAL(clicked()), this, SLOT(OnOkButtonClick()));
2222
connect(ui.selectPrivateKeyPath, SIGNAL(clicked()), this, SLOT(OnBrowseSshKeyClick()));
23+
connect(ui.sslCACertButton, &QPushButton::clicked, this, [this]() {
24+
OnBrowsePemFileClick(ui.sslCACertEdit);
25+
});
2326
connect(ui.testConnectionButton, SIGNAL(clicked()), this, SLOT(OnTestConnectionButtonClick()));
2427
connect(ui.showPasswordCheckbox, SIGNAL(stateChanged(int)), this, SLOT(OnShowPasswordCheckboxChanged(int)));
2528

@@ -70,6 +73,11 @@ void ConnectionWindow::loadValuesFromConfig(const RedisClient::ConnectionConfig&
7073
ui.sshKeysGroup->setChecked(true);
7174
}
7275
}
76+
77+
if (config.useSsl()) {
78+
ui.useSsl->setCheckState(Qt::Checked);
79+
ui.sslCACertEdit->setText(config.param<QString>("ssl_ca_cert_path"));
80+
}
7381
}
7482

7583
void ConnectionWindow::markFieldInvalid(QWidget* w)
@@ -127,6 +135,16 @@ void ConnectionWindow::OnBrowseSshKeyClick()
127135
ui.privateKeyPath->setText(fileName);
128136
}
129137

138+
void ConnectionWindow::OnBrowsePemFileClick(QLineEdit* target)
139+
{
140+
QString fileName = QFileDialog::getOpenFileName(this, "Select PEM file", "", tr("All Files (*.pem)"));
141+
142+
if (fileName.isEmpty())
143+
return;
144+
145+
target->setText(fileName);
146+
}
147+
130148
void ConnectionWindow::OnTestConnectionButtonClick()
131149
{
132150
ui.validationWarning->hide();
@@ -248,6 +266,11 @@ bool ConnectionWindow::isSshTunnelUsed()
248266
return ui.useSshTunnel->checkState() == Qt::Checked;
249267
}
250268

269+
bool ConnectionWindow::isSslUsed()
270+
{
271+
return ui.useSsl->checkState() == Qt::Checked;
272+
}
273+
251274
RedisClient::ConnectionConfig ConnectionWindow::getConectionConfigFromFormData()
252275
{
253276
RedisClient::ConnectionConfig conf(ui.hostEdit->text().trimmed(),
@@ -273,5 +296,9 @@ RedisClient::ConnectionConfig ConnectionWindow::getConectionConfigFromFormData()
273296
(ui.sshKeysGroup->isChecked() ? ui.privateKeyPath->text().trimmed() : ""));
274297
}
275298

299+
if (isSslUsed()) {
300+
conf.setParam("ssl_ca_cert_path", ui.sslCACertEdit->text());
301+
}
302+
276303
return conf;
277304
}

src/app/dialogs/connect.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ConnectionWindow : public QDialog
2727
bool isSshSettingsValid();
2828
bool isAdvancedSettingsValid();
2929
bool isSshTunnelUsed();
30+
bool isSslUsed();
3031

3132
void loadValuesFromConfig(const RedisClient::ConnectionConfig& config);
3233

@@ -37,5 +38,6 @@ private slots:
3738
void OnOkButtonClick();
3839
void OnShowPasswordCheckboxChanged(int);
3940
void OnBrowseSshKeyClick();
41+
void OnBrowsePemFileClick(QLineEdit *target);
4042
void OnTestConnectionButtonClick();
4143
};

src/app/forms/connection.ui

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,14 @@
148148
</attribute>
149149
<layout class="QGridLayout" name="gridLayout_5">
150150
<item row="1" column="1">
151-
<widget class="QLineEdit" name="sslPublicKeyEdit">
151+
<widget class="QLineEdit" name="sslCACertEdit">
152152
<property name="placeholderText">
153153
<string>Public key in PEM format</string>
154154
</property>
155155
</widget>
156156
</item>
157157
<item row="3" column="1">
158-
<widget class="QLineEdit" name="sslAuthorityEdit">
158+
<widget class="QLineEdit" name="sslLocalCertEdit">
159159
<property name="placeholderText">
160160
<string>(Optional) Authority in PEM format</string>
161161
</property>
@@ -214,7 +214,7 @@
214214
</widget>
215215
</item>
216216
<item row="1" column="2">
217-
<widget class="QPushButton" name="pushButton">
217+
<widget class="QPushButton" name="sslCACertButton">
218218
<property name="maximumSize">
219219
<size>
220220
<width>60</width>
@@ -227,7 +227,7 @@
227227
</widget>
228228
</item>
229229
<item row="2" column="2">
230-
<widget class="QPushButton" name="pushButton_2">
230+
<widget class="QPushButton" name="sslPrivateKeyButton">
231231
<property name="maximumSize">
232232
<size>
233233
<width>60</width>
@@ -240,7 +240,7 @@
240240
</widget>
241241
</item>
242242
<item row="3" column="2">
243-
<widget class="QPushButton" name="pushButton_3">
243+
<widget class="QPushButton" name="sslLocalCertButton">
244244
<property name="maximumSize">
245245
<size>
246246
<width>60</width>
@@ -253,7 +253,7 @@
253253
</widget>
254254
</item>
255255
<item row="0" column="0" colspan="3">
256-
<widget class="QCheckBox" name="checkBox">
256+
<widget class="QCheckBox" name="useSsl">
257257
<property name="layoutDirection">
258258
<enum>Qt::LeftToRight</enum>
259259
</property>

src/modules/redisclient/connectionconfig.cpp

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,25 @@ int RedisClient::ConnectionConfig::connectionTimeout() const
5353
return param<int>("timeout_connect");
5454
}
5555

56+
QList<QSslCertificate> RedisClient::ConnectionConfig::sslCaCertificates() const
57+
{
58+
QString path = param<QString>("ssl_ca_cert_path");
59+
if (!path.isEmpty() && QFile::exists(path))
60+
return QSslCertificate::fromPath(path);
61+
62+
return QList<QSslCertificate>();
63+
}
64+
65+
QString RedisClient::ConnectionConfig::sslPrivateKeyPath() const
66+
{
67+
return getValidPathFromParameter("ssl_private_key_path");
68+
}
69+
70+
QString RedisClient::ConnectionConfig::sslLocalCertPath() const
71+
{
72+
return getValidPathFromParameter("ssl_local_cert_path");
73+
}
74+
5675
bool RedisClient::ConnectionConfig::isSshPasswordUsed()
5776
{
5877
return !param<QString>("ssh_password").isEmpty();
@@ -93,6 +112,11 @@ bool RedisClient::ConnectionConfig::useAuth() const
93112
return !param<QString>("auth").isEmpty();
94113
}
95114

115+
bool RedisClient::ConnectionConfig::useSsl() const
116+
{
117+
return !param<QString>("ssl_ca_cert_path").isEmpty();
118+
}
119+
96120
bool RedisClient::ConnectionConfig::isValid() const
97121
{
98122
return isNull() == false
@@ -112,11 +136,7 @@ QWeakPointer<RedisClient::Connection> RedisClient::ConnectionConfig::getOwner()
112136

113137
QString RedisClient::ConnectionConfig::getSshPrivateKey()
114138
{
115-
QString path = param<QString>("ssh_private_key_path");
116-
if (path.isEmpty() || !QFile::exists(path))
117-
return QString();
118-
119-
return path;
139+
return getValidPathFromParameter("ssh_private_key_path");
120140
}
121141

122142
QString RedisClient::ConnectionConfig::keysPattern() const
@@ -145,6 +165,9 @@ RedisClient::ConnectionConfig RedisClient::ConnectionConfig::fromXml(QDomNode &
145165
valueMapping.insert("sshPassword", "ssh_password");
146166
valueMapping.insert("sshPort", "ssh_port");
147167
valueMapping.insert("sshPrivateKey", "ssh_private_key_path");
168+
valueMapping.insert("ssl_ca_cert_path", "");
169+
valueMapping.insert("ssl_private_key_path", "");
170+
valueMapping.insert("ssl_local_cert_path", "");
148171
valueMapping.insert("namespaceSeparator", "namespace_separator");
149172
valueMapping.insert("connectionTimeout", "timeout_connect");
150173
valueMapping.insert("executeTimeout", "timeout_execute");
@@ -212,6 +235,12 @@ QDomElement RedisClient::ConnectionConfig::toXml()
212235
saveXmlAttribute(dom, xml, "sshPrivateKey", param<QString>("ssh_private_key_path"));
213236
}
214237

238+
if (useSsl()) {
239+
saveXmlAttribute(dom, xml, "ssl_ca_cert_path", param<QString>("ssl_ca_cert_path"));
240+
saveXmlAttribute(dom, xml, "ssl_private_key_path", param<QString>("ssl_private_key_path"));
241+
saveXmlAttribute(dom, xml, "ssl_local_cert_path", param<QString>("ssl_local_cert_path"));
242+
}
243+
215244
return xml;
216245
}
217246

@@ -221,3 +250,12 @@ void RedisClient::ConnectionConfig::saveXmlAttribute(QDomDocument & document, QD
221250
attr.setValue(value);
222251
root.setAttributeNode(attr);
223252
}
253+
254+
QString RedisClient::ConnectionConfig::getValidPathFromParameter(const QString &name) const
255+
{
256+
QString path = param<QString>(name);
257+
if (path.isEmpty() || !QFile::exists(path))
258+
return QString();
259+
260+
return path;
261+
}

src/modules/redisclient/connectionconfig.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <QtCore>
44
#include <QtXml>
5+
#include <QSslCertificate>
56

67
#define DEFAULT_REDIS_PORT 6379
78
#define DEFAULT_SSH_PORT 22
@@ -25,9 +26,14 @@ class ConnectionConfig
2526
int executeTimeout() const;
2627
int connectionTimeout() const;
2728

29+
QList<QSslCertificate> sslCaCertificates() const;
30+
QString sslPrivateKeyPath() const;
31+
QString sslLocalCertPath() const;
32+
2833
bool isNull() const;
2934
bool useSshTunnel() const;
3035
bool useAuth() const;
36+
bool useSsl() const;
3137
bool isValid() const;
3238
bool isSshPasswordUsed();
3339

@@ -67,6 +73,7 @@ class ConnectionConfig
6773
const QString& name,
6874
const QString& value);
6975

76+
QString getValidPathFromParameter(const QString& param) const;
7077
private:
7178
QWeakPointer<Connection> m_owner;
7279
QVariantHash m_parameters;

src/modules/redisclient/transporters/defaulttransporter.cpp

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,22 @@ RedisClient::DefaultTransporter::~DefaultTransporter()
1313

1414
void RedisClient::DefaultTransporter::init()
1515
{
16+
using namespace RedisClient;
17+
1618
if (!socket.isNull())
1719
return;
1820

1921
executionTimer = QSharedPointer<QTimer>(new QTimer);
2022
executionTimer->setSingleShot(true);
2123
connect(executionTimer.data(), SIGNAL(timeout()), this, SLOT(executionTimeout()));
2224

23-
socket = QSharedPointer<QTcpSocket>(new QTcpSocket());
25+
socket = QSharedPointer<QSslSocket>(new QSslSocket());
2426
socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
2527

26-
connect(socket.data(), SIGNAL(readyRead()), this, SLOT(readyRead()));
28+
connect(socket.data(), &QSslSocket::readyRead, this, &DefaultTransporter::readyRead);
29+
connect(socket.data(), &QSslSocket::encrypted, this, &DefaultTransporter::encrypted);
2730
connect(socket.data(), SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
31+
connect(socket.data(), SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslError(const QList<QSslError> &)));
2832

2933
connectToHost();
3034
}
@@ -43,19 +47,50 @@ bool RedisClient::DefaultTransporter::connectToHost()
4347
{
4448
m_errorOccurred = false;
4549

46-
socket->connectToHost(m_connection->config.host(), m_connection->config.port());
50+
RedisClient::ConnectionConfig& conf = m_connection->config;
51+
52+
bool connectionResult = false;
53+
54+
if (conf.useSsl()) {
55+
QList<QSslCertificate> trustedCas = conf.sslCaCertificates(); // Required
56+
57+
if (trustedCas.empty()) {
58+
emit errorOccurred("SSL Error: no trusted Cas");
59+
return false;
60+
}
61+
62+
socket->setCaCertificates(trustedCas);
63+
64+
QString privateKey = conf.sslPrivateKeyPath();
65+
if (!privateKey.isEmpty()) {
66+
socket->setPrivateKey(privateKey);
67+
}
68+
69+
QString localCert = conf.sslLocalCertPath();
70+
if (!localCert.isEmpty()) {
71+
socket->setLocalCertificate(localCert);
72+
}
73+
74+
socket->connectToHostEncrypted(conf.host(), conf.port());
75+
connectionResult = socket->waitForEncrypted(conf.connectionTimeout())
76+
&& socket->waitForConnected(conf.connectionTimeout());
4777

48-
if (socket->waitForConnected(m_connection->config.connectionTimeout()))
78+
} else {
79+
socket->connectToHost(conf.host(), conf.port());
80+
connectionResult = socket->waitForConnected(conf.connectionTimeout());
81+
}
82+
83+
if (connectionResult)
4984
{
5085
emit connected();
51-
emit logEvent(QString("%1 > connected").arg(m_connection->config.name()));
86+
emit logEvent(QString("%1 > connected").arg(conf.name()));
5287
return true;
5388
}
5489

5590
if (!m_errorOccurred)
5691
emit errorOccurred("Connection timeout");
5792

58-
emit logEvent(QString("%1 > connection failed").arg(m_connection->config.name()));
93+
emit logEvent(QString("%1 > connection failed").arg(conf.name()));
5994
return false;
6095
}
6196

@@ -137,3 +172,15 @@ void RedisClient::DefaultTransporter::reconnect()
137172
socket->abort();
138173
connectToHost();
139174
}
175+
176+
void RedisClient::DefaultTransporter::sslError(const QList<QSslError> errors)
177+
{
178+
m_errorOccurred = true;
179+
QSslError first = errors.at(0);
180+
emit errorOccurred(QString("SSL error: %1").arg(first.errorString()));
181+
}
182+
183+
void RedisClient::DefaultTransporter::encrypted()
184+
{
185+
emit logEvent("SSL encryption: OK");
186+
}

src/modules/redisclient/transporters/defaulttransporter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ private slots:
2222
void error(QAbstractSocket::SocketError error);
2323
void stateChanged(QAbstractSocket::SocketState socketState);
2424
void reconnect();
25+
void sslError(const QList<QSslError> errors);
26+
void encrypted();
2527
private:
2628
QSharedPointer<QSslSocket> socket;
2729
bool m_errorOccurred;

0 commit comments

Comments
 (0)