Implement backend access with SSO

This commit is contained in:
2025-11-03 13:18:14 +01:00
parent 0909bfb0e7
commit 587d61ce55
24 changed files with 429 additions and 569 deletions
+1 -1
View File
@@ -1203,7 +1203,7 @@
</message> </message>
</context> </context>
<context> <context>
<name>DevicesConnection</name> <name>DeviceConnection</name>
<message> <message>
<location filename="../../flotten-updater/deviceconnection.cpp" line="79"/> <location filename="../../flotten-updater/deviceconnection.cpp" line="79"/>
<location filename="../../flotten-updater/deviceconnection.cpp" line="311"/> <location filename="../../flotten-updater/deviceconnection.cpp" line="311"/>
+5
View File
@@ -160,6 +160,11 @@ NavigationPage {
text: qsTr("Skip server cert verification") text: qsTr("Skip server cert verification")
} }
GeneralOnOffSwitch {
apiKey: "ocppt"
text: qsTr("Accept time from backend")
}
// TODO clientKey // TODO clientKey
// TODO clientCert // TODO clientCert
+3 -3
View File
@@ -12,9 +12,9 @@ qt_add_executable(flotten-updater WIN32 MACOSX_BUNDLE
devicesmodel.h devicesmodel.h
flottenupdatersettings.cpp flottenupdatersettings.cpp
flottenupdatersettings.h flottenupdatersettings.h
importcertificatedialog.cpp importcredentialsdialog.cpp
importcertificatedialog.h importcredentialsdialog.h
importcertificatedialog.ui importcredentialsdialog.ui
main.cpp main.cpp
mainwindow.cpp mainwindow.cpp
mainwindow.h mainwindow.h
+110 -99
View File
@@ -24,42 +24,44 @@ const constexpr QColor blue{150, 150, 255};
const constexpr QColor magenta{255, 150, 255}; const constexpr QColor magenta{255, 150, 255};
} }
DevicesConnection::DevicesConnection(const QSslKey &key, const QSslCertificate &cert, QString &&serial, QObject *parent) : DeviceConnection::DeviceConnection(const QByteArray &username, const QByteArray &password, QString &&serial, QObject *parent) :
QObject{parent}, QObject{parent},
m_serial(std::move(serial)), m_serial(std::move(serial)),
m_key{key}, m_username{username},
m_cert{cert} m_password{password}
{ {
init(); init();
} }
DevicesConnection::DevicesConnection(const QSslKey &key, const QSslCertificate &cert, const QString &serial, QObject *parent) : DeviceConnection::DeviceConnection(const QByteArray &username, const QByteArray &password, const QString &serial, QObject *parent) :
QObject{parent}, QObject{parent},
m_serial(serial), m_serial(serial),
m_key{key}, m_username{username},
m_cert{cert} m_password{password}
{ {
init(); init();
} }
void DevicesConnection::start() void DeviceConnection::start()
{ {
const QUrl url{QString("wss://solalaweb.com/%0").arg(m_serial)}; QNetworkRequest request{QString("wss://solalaweb.com/%0").arg(m_serial)};
qDebug() << url; QString credentials = m_username + ':' + m_password;
m_websocket.open(url); QString base64 = credentials.toUtf8().toBase64();
request.setRawHeader("Authorization", "Basic " + base64.toUtf8());
m_websocket.open(request);
} }
void DevicesConnection::stop() void DeviceConnection::stop()
{ {
m_websocket.close(); m_websocket.close();
} }
QString DevicesConnection::wsStatusText() const QString DeviceConnection::wsStatusText() const
{ {
return QMetaEnum::fromType<QAbstractSocket::SocketState>().valueToKey(m_websocket.state()); return QMetaEnum::fromType<QAbstractSocket::SocketState>().valueToKey(m_websocket.state());
} }
QBrush DevicesConnection::wsStatusBackground() const QBrush DeviceConnection::wsStatusBackground() const
{ {
switch (m_websocket.state()) switch (m_websocket.state())
{ {
@@ -72,7 +74,7 @@ QBrush DevicesConnection::wsStatusBackground() const
return {}; return {};
} }
QString DevicesConnection::statusText() const QString DeviceConnection::statusText() const
{ {
switch (m_status) switch (m_status)
{ {
@@ -84,7 +86,7 @@ QString DevicesConnection::statusText() const
return QString::number(std::to_underlying(m_status)); return QString::number(std::to_underlying(m_status));
} }
QBrush DevicesConnection::statusBackground() const QBrush DeviceConnection::statusBackground() const
{ {
switch (m_status) switch (m_status)
{ {
@@ -95,7 +97,7 @@ QBrush DevicesConnection::statusBackground() const
return {}; return {};
} }
QString DevicesConnection::variantText() const QString DeviceConnection::variantText() const
{ {
if (!m_fullStatus.contains("var")) if (!m_fullStatus.contains("var"))
return {}; return {};
@@ -103,7 +105,7 @@ QString DevicesConnection::variantText() const
return m_fullStatus.value("var").toString(); return m_fullStatus.value("var").toString();
} }
QBrush DevicesConnection::variantBackground() const QBrush DeviceConnection::variantBackground() const
{ {
if (!m_fullStatus.contains("var")) if (!m_fullStatus.contains("var"))
return {}; return {};
@@ -116,7 +118,7 @@ QBrush DevicesConnection::variantBackground() const
return red; return red;
} }
QString DevicesConnection::isGoText() const QString DeviceConnection::isGoText() const
{ {
if (!m_fullStatus.contains("isgo")) if (!m_fullStatus.contains("isgo"))
return {}; return {};
@@ -124,7 +126,7 @@ QString DevicesConnection::isGoText() const
return m_fullStatus.value("isgo").toBool() ? "yes" : "no"; return m_fullStatus.value("isgo").toBool() ? "yes" : "no";
} }
QBrush DevicesConnection::isGoBackground() const QBrush DeviceConnection::isGoBackground() const
{ {
if (!m_fullStatus.contains("isgo")) if (!m_fullStatus.contains("isgo"))
return {}; return {};
@@ -132,7 +134,7 @@ QBrush DevicesConnection::isGoBackground() const
return m_fullStatus.value("isgo").toBool() ? blue : yellow; return m_fullStatus.value("isgo").toBool() ? blue : yellow;
} }
QString DevicesConnection::isAustralienText() const QString DeviceConnection::isAustralienText() const
{ {
if (!m_fullStatus.contains("aus")) if (!m_fullStatus.contains("aus"))
return {}; return {};
@@ -140,7 +142,7 @@ QString DevicesConnection::isAustralienText() const
return m_fullStatus.value("aus").toBool() ? "yes" : "no"; return m_fullStatus.value("aus").toBool() ? "yes" : "no";
} }
QBrush DevicesConnection::isAustralienBackground() const QBrush DeviceConnection::isAustralienBackground() const
{ {
if (!m_fullStatus.contains("aus")) if (!m_fullStatus.contains("aus"))
return {}; return {};
@@ -148,7 +150,7 @@ QBrush DevicesConnection::isAustralienBackground() const
return m_fullStatus.value("aus").toBool() ? yellow : blue; return m_fullStatus.value("aus").toBool() ? yellow : blue;
} }
QString DevicesConnection::resetCardText() const QString DeviceConnection::resetCardText() const
{ {
if (!m_fullStatus.contains("frci")) if (!m_fullStatus.contains("frci"))
return {}; return {};
@@ -156,7 +158,7 @@ QString DevicesConnection::resetCardText() const
return m_fullStatus.value("frci").toBool() ? "yes" : "no"; return m_fullStatus.value("frci").toBool() ? "yes" : "no";
} }
QBrush DevicesConnection::resetCardBackground() const QBrush DeviceConnection::resetCardBackground() const
{ {
if (!m_fullStatus.contains("frci")) if (!m_fullStatus.contains("frci"))
return {}; return {};
@@ -164,7 +166,7 @@ QBrush DevicesConnection::resetCardBackground() const
return m_fullStatus.value("frci").toBool() ? green : red; return m_fullStatus.value("frci").toBool() ? green : red;
} }
QString DevicesConnection::connectedWifiText() const QString DeviceConnection::connectedWifiText() const
{ {
if (!m_fullStatus.contains("ccw")) if (!m_fullStatus.contains("ccw"))
return {}; return {};
@@ -176,7 +178,7 @@ QString DevicesConnection::connectedWifiText() const
return apd.value("ssid").toString(); return apd.value("ssid").toString();
} }
QString DevicesConnection::projectText() const QString DeviceConnection::projectText() const
{ {
if (!m_fullStatus.contains("apd")) if (!m_fullStatus.contains("apd"))
return {}; return {};
@@ -188,7 +190,7 @@ QString DevicesConnection::projectText() const
return apd.value("project_name").toString(); return apd.value("project_name").toString();
} }
QString DevicesConnection::versionText() const QString DeviceConnection::versionText() const
{ {
if (!m_fullStatus.contains("apd")) if (!m_fullStatus.contains("apd"))
return {}; return {};
@@ -200,7 +202,7 @@ QString DevicesConnection::versionText() const
return apd.value("version").toString(); return apd.value("version").toString();
} }
QString DevicesConnection::idfVersionText() const QString DeviceConnection::idfVersionText() const
{ {
if (!m_fullStatus.contains("apd")) if (!m_fullStatus.contains("apd"))
return {}; return {};
@@ -212,7 +214,7 @@ QString DevicesConnection::idfVersionText() const
return apd.value("idf_ver").toString(); return apd.value("idf_ver").toString();
} }
QString DevicesConnection::updateText() const QString DeviceConnection::updateText() const
{ {
if (!m_fullStatus.contains("ocs")) if (!m_fullStatus.contains("ocs"))
return {}; return {};
@@ -241,7 +243,7 @@ QString DevicesConnection::updateText() const
return QString::number(ocs); return QString::number(ocs);
} }
QBrush DevicesConnection::updateBackground() const QBrush DeviceConnection::updateBackground() const
{ {
if (!m_fullStatus.contains("ocs")) if (!m_fullStatus.contains("ocs"))
return {}; return {};
@@ -259,7 +261,7 @@ QBrush DevicesConnection::updateBackground() const
return {}; return {};
} }
std::optional<qulonglong> DevicesConnection::uptime() const std::optional<qulonglong> DeviceConnection::uptime() const
{ {
if (!m_fullStatus.contains("rbt")) if (!m_fullStatus.contains("rbt"))
return {}; return {};
@@ -267,7 +269,7 @@ std::optional<qulonglong> DevicesConnection::uptime() const
return m_fullStatus.value("rbt").toULongLong(); return m_fullStatus.value("rbt").toULongLong();
} }
QString DevicesConnection::uptimeText() const QString DeviceConnection::uptimeText() const
{ {
if (!m_fullStatus.contains("rbt")) if (!m_fullStatus.contains("rbt"))
return {}; return {};
@@ -275,7 +277,7 @@ QString DevicesConnection::uptimeText() const
return QString::number(m_fullStatus.value("rbt").toULongLong()); return QString::number(m_fullStatus.value("rbt").toULongLong());
} }
QString DevicesConnection::currentPartition() const QString DeviceConnection::currentPartition() const
{ {
if (!m_fullStatus.contains("otap")) if (!m_fullStatus.contains("otap"))
return {}; return {};
@@ -287,7 +289,7 @@ QString DevicesConnection::currentPartition() const
return otap.value("label").toString(); return otap.value("label").toString();
} }
std::optional<int> DevicesConnection::reboots() const std::optional<int> DeviceConnection::reboots() const
{ {
if (!m_fullStatus.contains("rbc")) if (!m_fullStatus.contains("rbc"))
return {}; return {};
@@ -295,7 +297,7 @@ std::optional<int> DevicesConnection::reboots() const
return m_fullStatus.value("rbc").toInt(); return m_fullStatus.value("rbc").toInt();
} }
QString DevicesConnection::rebootsText() const QString DeviceConnection::rebootsText() const
{ {
if (!m_fullStatus.contains("rbc")) if (!m_fullStatus.contains("rbc"))
return {}; return {};
@@ -303,7 +305,7 @@ QString DevicesConnection::rebootsText() const
return QString::number(m_fullStatus.value("rbc").toInt()); return QString::number(m_fullStatus.value("rbc").toInt());
} }
QString DevicesConnection::carStateText() const QString DeviceConnection::carStateText() const
{ {
if (!m_fullStatus.contains("car")) if (!m_fullStatus.contains("car"))
return {}; return {};
@@ -315,7 +317,7 @@ QString DevicesConnection::carStateText() const
return QString::number(car); return QString::number(car);
} }
std::optional<double> DevicesConnection::energy() const std::optional<double> DeviceConnection::energy() const
{ {
if (!m_fullStatus.contains("eto")) if (!m_fullStatus.contains("eto"))
return {}; return {};
@@ -323,7 +325,7 @@ std::optional<double> DevicesConnection::energy() const
return m_fullStatus.value("eto").toDouble(); return m_fullStatus.value("eto").toDouble();
} }
QString DevicesConnection::energyText() const QString DeviceConnection::energyText() const
{ {
if (!m_fullStatus.contains("eto")) if (!m_fullStatus.contains("eto"))
return {}; return {};
@@ -331,7 +333,7 @@ QString DevicesConnection::energyText() const
return QString("%0kWh").arg(m_fullStatus.value("eto").toDouble() / 1000.); return QString("%0kWh").arg(m_fullStatus.value("eto").toDouble() / 1000.);
} }
QString DevicesConnection::livedataText() const QString DeviceConnection::livedataText() const
{ {
if (!m_fullStatus.contains("nrg")) if (!m_fullStatus.contains("nrg"))
return {}; return {};
@@ -346,85 +348,94 @@ QString DevicesConnection::livedataText() const
return {}; return {};
} }
QVariant DevicesConnection::getApiKey(const QString &apiKey) const QVariant DeviceConnection::getApiKey(const QString &apiKey) const
{ {
return m_fullStatus.value(apiKey); return m_fullStatus.value(apiKey);
} }
void DevicesConnection::sendMessage(const QJsonDocument &doc) void DeviceConnection::sendMessage(const QJsonDocument &doc)
{ {
sendMessage(QString::fromUtf8(doc.toJson())); sendMessage(QString::fromUtf8(doc.toJson()));
} }
void DevicesConnection::sendMessage(const QJsonObject &obj) void DeviceConnection::sendMessage(const QJsonObject &obj)
{ {
sendMessage(QJsonDocument{obj}); sendMessage(QJsonDocument{obj});
} }
void DevicesConnection::sendMessage(const QString &msg) void DeviceConnection::sendMessage(const QString &msg)
{ {
qDebug() << msg << m_websocket.errorString(); qDebug() << msg << m_websocket.errorString();
if (const auto written = m_websocket.sendTextMessage(msg); written != msg.size()) if (const auto written = m_websocket.sendTextMessage(msg); written != msg.size())
qCritical() << "sending message failed" << written << "(expected:" << msg.size() << ')'; qCritical() << "sending message failed" << written << "(expected:" << msg.size() << ')';
} }
void DevicesConnection::init() QString DeviceConnection::errorString() const
{
return m_websocket.errorString();
}
void DeviceConnection::init()
{ {
if (auto model = qobject_cast<DevicesModel*>(parent())) if (auto model = qobject_cast<DevicesModel*>(parent()))
{ {
connect(this, &DevicesConnection::wsStatusChanged, model, &DevicesModel::wsStatusChanged); connect(this, &DeviceConnection::wsStatusChanged, model, &DevicesModel::wsStatusChanged);
connect(this, &DevicesConnection::statusChanged, model, &DevicesModel::statusChanged); connect(this, &DeviceConnection::statusChanged, model, &DevicesModel::statusChanged);
connect(this, &DevicesConnection::variantChanged, model, &DevicesModel::variantChanged); connect(this, &DeviceConnection::variantChanged, model, &DevicesModel::variantChanged);
connect(this, &DevicesConnection::isGoChanged, model, &DevicesModel::isGoChanged); connect(this, &DeviceConnection::isGoChanged, model, &DevicesModel::isGoChanged);
connect(this, &DevicesConnection::isAustralienChanged, model, &DevicesModel::isAustralienChanged); connect(this, &DeviceConnection::isAustralienChanged, model, &DevicesModel::isAustralienChanged);
connect(this, &DevicesConnection::resetCardChanged, model, &DevicesModel::resetCardChanged); connect(this, &DeviceConnection::resetCardChanged, model, &DevicesModel::resetCardChanged);
connect(this, &DevicesConnection::connectedWifiChanged, model, &DevicesModel::connectedWifiChanged); connect(this, &DeviceConnection::connectedWifiChanged, model, &DevicesModel::connectedWifiChanged);
connect(this, &DevicesConnection::projectChanged, model, &DevicesModel::projectChanged); connect(this, &DeviceConnection::projectChanged, model, &DevicesModel::projectChanged);
connect(this, &DevicesConnection::versionChanged, model, &DevicesModel::versionChanged); connect(this, &DeviceConnection::versionChanged, model, &DevicesModel::versionChanged);
connect(this, &DevicesConnection::idfVersionChanged, model, &DevicesModel::idfVersionChanged); connect(this, &DeviceConnection::idfVersionChanged, model, &DevicesModel::idfVersionChanged);
connect(this, &DevicesConnection::updateChanged, model, &DevicesModel::updateChanged); connect(this, &DeviceConnection::updateChanged, model, &DevicesModel::updateChanged);
connect(this, &DevicesConnection::uptimeChanged, model, &DevicesModel::uptimeChanged); connect(this, &DeviceConnection::uptimeChanged, model, &DevicesModel::uptimeChanged);
connect(this, &DevicesConnection::currentPartitionChanged, model, &DevicesModel::currentPartitionChanged); connect(this, &DeviceConnection::currentPartitionChanged, model, &DevicesModel::currentPartitionChanged);
connect(this, &DevicesConnection::rebootsChanged, model, &DevicesModel::rebootsChanged); connect(this, &DeviceConnection::rebootsChanged, model, &DevicesModel::rebootsChanged);
connect(this, &DevicesConnection::carStateChanged, model, &DevicesModel::carStateChanged); connect(this, &DeviceConnection::carStateChanged, model, &DevicesModel::carStateChanged);
connect(this, &DevicesConnection::energyChanged, model, &DevicesModel::energyChanged); connect(this, &DeviceConnection::energyChanged, model, &DevicesModel::energyChanged);
connect(this, &DevicesConnection::livedataChanged, model, &DevicesModel::livedataChanged); connect(this, &DeviceConnection::livedataChanged, model, &DevicesModel::livedataChanged);
connect(this, &DevicesConnection::apiKeyChanged, model, &DevicesModel::apiKeyChanged); connect(this, &DeviceConnection::apiKeyChanged, model, &DevicesModel::apiKeyChanged);
} }
else else
qWarning() << "unexpected parent"; qWarning() << "unexpected parent";
{ //{
auto sslConfig = m_websocket.sslConfiguration(); // auto sslConfig = m_websocket.sslConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); // sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
//sslConfig.setPeerVerifyMode(QSslSocket::VerifyPeer); // //sslConfig.setPeerVerifyMode(QSslSocket::VerifyPeer);
{ // {
auto caCerts = QSslCertificate::fromPath(":/goe-root-ca.pem"); // auto caCerts = QSslCertificate::fromPath(":/goe-root-ca.pem");
if (caCerts.empty()) // if (caCerts.empty())
qFatal("could not parse root ca"); // qFatal("could not parse root ca");
for (const auto &caCert : std::as_const(caCerts)) // for (const auto &caCert : std::as_const(caCerts))
qDebug() << caCert.issuerDisplayName(); // qDebug() << caCert.issuerDisplayName();
sslConfig.setCaCertificates(std::move(caCerts)); // sslConfig.setCaCertificates(std::move(caCerts));
} // }
sslConfig.setPrivateKey(m_key); // sslConfig.setPrivateKey(m_key);
sslConfig.setLocalCertificate(m_cert); // sslConfig.setLocalCertificate(m_cert);
m_websocket.setSslConfiguration(sslConfig); // m_websocket.setSslConfiguration(sslConfig);
m_websocket.ignoreSslErrors(); // m_websocket.ignoreSslErrors();
} //}
connect(&m_websocket, &QWebSocket::connected, this, &DevicesConnection::connected); connect(&m_websocket, &QWebSocket::connected, this, &DeviceConnection::connectedSignal);
connect(&m_websocket, &QWebSocket::disconnected, this, &DevicesConnection::disconnected); connect(&m_websocket, &QWebSocket::disconnected, this, &DeviceConnection::disconnectedSignal);
connect(&m_websocket, &QWebSocket::stateChanged, this, &DevicesConnection::stateChanged); connect(&m_websocket, &QWebSocket::errorOccurred, this, &DeviceConnection::errorOccurredSignal);
connect(&m_websocket, &QWebSocket::textMessageReceived, this, &DevicesConnection::textMessageReceived);
connect(&m_websocket, &QWebSocket::binaryMessageReceived, this, &DevicesConnection::binaryMessageReceived); connect(&m_websocket, &QWebSocket::connected, this, &DeviceConnection::connected);
connect(&m_websocket, &QWebSocket::errorOccurred, this, &DevicesConnection::errorOccurred); connect(&m_websocket, &QWebSocket::disconnected, this, &DeviceConnection::disconnected);
connect(&m_websocket, &QWebSocket::peerVerifyError, this, &DevicesConnection::peerVerifyError); connect(&m_websocket, &QWebSocket::stateChanged, this, &DeviceConnection::stateChanged);
connect(&m_websocket, &QWebSocket::sslErrors, this, &DevicesConnection::sslErrors); connect(&m_websocket, &QWebSocket::textMessageReceived, this, &DeviceConnection::textMessageReceived);
connect(&m_websocket, &QWebSocket::alertReceived, this, &DevicesConnection::alertReceived); connect(&m_websocket, &QWebSocket::binaryMessageReceived, this, &DeviceConnection::binaryMessageReceived);
connect(&m_websocket, &QWebSocket::handshakeInterruptedOnError, this, &DevicesConnection::handshakeInterruptedOnError); connect(&m_websocket, &QWebSocket::errorOccurred, this, &DeviceConnection::errorOccurred);
connect(&m_websocket, &QWebSocket::peerVerifyError, this, &DeviceConnection::peerVerifyError);
connect(&m_websocket, &QWebSocket::sslErrors, this, &DeviceConnection::sslErrors);
connect(&m_websocket, &QWebSocket::alertReceived, this, &DeviceConnection::alertReceived);
connect(&m_websocket, &QWebSocket::handshakeInterruptedOnError, this, &DeviceConnection::handshakeInterruptedOnError);
} }
void DevicesConnection::maintainStatus(const QJsonObject &msg, bool forceChange) void DeviceConnection::maintainStatus(const QJsonObject &msg, bool forceChange)
{ {
bool variantChanged{forceChange}; bool variantChanged{forceChange};
bool isGoChanged{forceChange}; bool isGoChanged{forceChange};
@@ -507,17 +518,17 @@ void DevicesConnection::maintainStatus(const QJsonObject &msg, bool forceChange)
emit this->livedataChanged(); emit this->livedataChanged();
} }
void DevicesConnection::connected() void DeviceConnection::connected()
{ {
qDebug() << "called"; qDebug() << "called";
} }
void DevicesConnection::disconnected() void DeviceConnection::disconnected()
{ {
qDebug() << "called"; qDebug() << "called";
} }
void DevicesConnection::stateChanged(QAbstractSocket::SocketState state) void DeviceConnection::stateChanged(QAbstractSocket::SocketState state)
{ {
// qDebug() << "called" << state; // qDebug() << "called" << state;
@@ -533,7 +544,7 @@ void DevicesConnection::stateChanged(QAbstractSocket::SocketState state)
emit wsStatusChanged(); emit wsStatusChanged();
} }
void DevicesConnection::textMessageReceived(const QString &message) void DeviceConnection::textMessageReceived(const QString &message)
{ {
// qDebug() << "called" << message; // qDebug() << "called" << message;
@@ -614,32 +625,32 @@ void DevicesConnection::textMessageReceived(const QString &message)
qWarning() << "unknown message type" << msgObj; qWarning() << "unknown message type" << msgObj;
} }
void DevicesConnection::binaryMessageReceived(const QByteArray &message) void DeviceConnection::binaryMessageReceived(const QByteArray &message)
{ {
qDebug() << "called" << message; qDebug() << "called" << message;
} }
void DevicesConnection::errorOccurred(QAbstractSocket::SocketError error) void DeviceConnection::errorOccurred(QAbstractSocket::SocketError error)
{ {
qDebug() << "called" << QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey(error) << m_websocket.errorString(); qDebug() << "called" << QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey(error) << m_websocket.errorString();
} }
void DevicesConnection::peerVerifyError(const QSslError &error) void DeviceConnection::peerVerifyError(const QSslError &error)
{ {
qDebug() << "called" << error; qDebug() << "called" << error;
} }
void DevicesConnection::sslErrors(const QList<QSslError> &errors) void DeviceConnection::sslErrors(const QList<QSslError> &errors)
{ {
qDebug() << "called" << errors; qDebug() << "called" << errors;
} }
void DevicesConnection::alertReceived(QSsl::AlertLevel level, QSsl::AlertType type, const QString &description) void DeviceConnection::alertReceived(QSsl::AlertLevel level, QSsl::AlertType type, const QString &description)
{ {
qDebug() << "called" << std::to_underlying(level) << std::to_underlying(type) << description; qDebug() << "called" << std::to_underlying(level) << std::to_underlying(type) << description;
} }
void DevicesConnection::handshakeInterruptedOnError(const QSslError &error) void DeviceConnection::handshakeInterruptedOnError(const QSslError &error)
{ {
qDebug() << "called" << error; qDebug() << "called" << error;
} }
+11 -5
View File
@@ -9,13 +9,13 @@ class QSslKey;
class QSslCertificate; class QSslCertificate;
class QJsonObject; class QJsonObject;
class DevicesConnection : public QObject class DeviceConnection : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit DevicesConnection(const QSslKey &key, const QSslCertificate &cert, QString &&serial, QObject *parent = nullptr); explicit DeviceConnection(const QByteArray &username, const QByteArray &password, QString &&serial, QObject *parent = nullptr);
explicit DevicesConnection(const QSslKey &key, const QSslCertificate &cert, const QString &serial, QObject *parent = nullptr); explicit DeviceConnection(const QByteArray &username, const QByteArray &password, const QString &serial, QObject *parent = nullptr);
void start(); void start();
void stop(); void stop();
@@ -72,7 +72,13 @@ public:
void sendMessage(const QJsonObject &obj); void sendMessage(const QJsonObject &obj);
void sendMessage(const QString &msg); void sendMessage(const QString &msg);
QString errorString() const;
signals: signals:
void connectedSignal();
void disconnectedSignal();
void errorOccurredSignal(QAbstractSocket::SocketError error);
void responseReceived(const QString &requestId, const QJsonObject &msg); void responseReceived(const QString &requestId, const QJsonObject &msg);
void wsStatusChanged(); void wsStatusChanged();
@@ -112,8 +118,8 @@ private slots:
private: private:
const QString m_serial; const QString m_serial;
const QSslKey &m_key; const QByteArray m_username;
const QSslCertificate &m_cert; const QByteArray m_password;
enum Status { enum Status {
Unknown, Unknown,
+11 -11
View File
@@ -34,12 +34,12 @@ enum {
}; };
} }
DevicesModel::DevicesModel(FlottenUpdaterSettings &settings, const QSslKey &key, DevicesModel::DevicesModel(FlottenUpdaterSettings &settings, const QByteArray &username,
const QSslCertificate &cert, QObject *parent) : const QByteArray &password, QObject *parent) :
QAbstractTableModel{parent}, QAbstractTableModel{parent},
m_settings{settings}, m_settings{settings},
m_key{key}, m_username{username},
m_cert{cert}, m_password{password},
m_customColumns{settings.customColumns()} m_customColumns{settings.customColumns()}
{ {
for (const auto &serial : m_settings.serials()) for (const auto &serial : m_settings.serials())
@@ -47,7 +47,7 @@ DevicesModel::DevicesModel(FlottenUpdaterSettings &settings, const QSslKey &key,
if (std::none_of(std::cbegin(m_devices), std::cend(m_devices), [&serial](auto &ptr){ if (std::none_of(std::cbegin(m_devices), std::cend(m_devices), [&serial](auto &ptr){
return ptr->serial() == serial; return ptr->serial() == serial;
})) }))
m_devices.emplace_back(std::make_shared<DevicesConnection>(m_key, m_cert, serial, this)); m_devices.emplace_back(std::make_shared<DeviceConnection>(m_username, m_password, serial, this));
} }
} }
@@ -71,7 +71,7 @@ QVariant DevicesModel::data(const QModelIndex &index, int role) const
return {}; return {};
} }
const DevicesConnection &device = **std::next(std::begin(m_devices), index.row()); const DeviceConnection &device = **std::next(std::begin(m_devices), index.row());
switch (index.column()) switch (index.column())
{ {
@@ -332,7 +332,7 @@ bool DevicesModel::addClient(const QString &serial)
beginInsertRows({}, m_devices.size(), m_devices.size()); beginInsertRows({}, m_devices.size(), m_devices.size());
auto clientPtr = std::make_shared<DevicesConnection>(m_key, m_cert, serial, this); auto clientPtr = std::make_shared<DeviceConnection>(m_username, m_password, serial, this);
auto client = clientPtr.get(); auto client = clientPtr.get();
m_devices.emplace_back(std::move(clientPtr)); m_devices.emplace_back(std::move(clientPtr));
@@ -343,7 +343,7 @@ bool DevicesModel::addClient(const QString &serial)
return true; return true;
} }
std::shared_ptr<DevicesConnection> DevicesModel::getDevice(QModelIndex index) std::shared_ptr<DeviceConnection> DevicesModel::getDevice(QModelIndex index)
{ {
Q_ASSERT(!index.parent().isValid()); Q_ASSERT(!index.parent().isValid());
Q_ASSERT(index.row() >= 0 && index.row() < m_devices.size()); Q_ASSERT(index.row() >= 0 && index.row() < m_devices.size());
@@ -352,7 +352,7 @@ std::shared_ptr<DevicesConnection> DevicesModel::getDevice(QModelIndex index)
return device; return device;
} }
std::shared_ptr<const DevicesConnection> DevicesModel::getDevice(QModelIndex index) const std::shared_ptr<const DeviceConnection> DevicesModel::getDevice(QModelIndex index) const
{ {
Q_ASSERT(!index.parent().isValid()); Q_ASSERT(!index.parent().isValid());
return m_devices.at(index.row()); return m_devices.at(index.row());
@@ -500,14 +500,14 @@ void DevicesModel::apiKeyChanged(const QString &apiKey)
void DevicesModel::columnChanged(int column, const QList<int> &roles) void DevicesModel::columnChanged(int column, const QList<int> &roles)
{ {
auto device = qobject_cast<DevicesConnection*>(sender()); auto device = qobject_cast<DeviceConnection*>(sender());
if (!device) if (!device)
{ {
qWarning() << "unknown sender" << sender(); qWarning() << "unknown sender" << sender();
return; return;
} }
auto iter = std::find_if(std::cbegin(m_devices), std::cend(m_devices), [&device](const std::shared_ptr<DevicesConnection> &ptr){ return device == ptr.get(); }); auto iter = std::find_if(std::cbegin(m_devices), std::cend(m_devices), [&device](const std::shared_ptr<DeviceConnection> &ptr){ return device == ptr.get(); });
if (iter == std::cend(m_devices)) if (iter == std::cend(m_devices))
{ {
qWarning() << "unknown sender" << device; qWarning() << "unknown sender" << device;
+8 -8
View File
@@ -9,7 +9,7 @@ class QSslKey;
class QSslCertificate; class QSslCertificate;
class FlottenUpdaterSettings; class FlottenUpdaterSettings;
class DevicesConnection; class DeviceConnection;
class DevicesModel : public QAbstractTableModel class DevicesModel : public QAbstractTableModel
{ {
@@ -18,8 +18,8 @@ class DevicesModel : public QAbstractTableModel
using base = QAbstractTableModel; using base = QAbstractTableModel;
public: public:
explicit DevicesModel(FlottenUpdaterSettings &settings, const QSslKey &key, explicit DevicesModel(FlottenUpdaterSettings &settings, const QByteArray &username,
const QSslCertificate &cert, QObject *parent = nullptr); const QByteArray &password, QObject *parent = nullptr);
~DevicesModel() override; ~DevicesModel() override;
int rowCount(const QModelIndex &parent) const override; int rowCount(const QModelIndex &parent) const override;
@@ -30,8 +30,8 @@ public:
bool addClient(const QString &serial); bool addClient(const QString &serial);
std::shared_ptr<DevicesConnection> getDevice(QModelIndex index); std::shared_ptr<DeviceConnection> getDevice(QModelIndex index);
std::shared_ptr<const DevicesConnection> getDevice(QModelIndex index) const; std::shared_ptr<const DeviceConnection> getDevice(QModelIndex index) const;
void addCustomColumn(const QString &apiKey); void addCustomColumn(const QString &apiKey);
bool customColumnRemovable(int section); bool customColumnRemovable(int section);
@@ -64,11 +64,11 @@ public slots:
private: private:
FlottenUpdaterSettings &m_settings; FlottenUpdaterSettings &m_settings;
const QSslKey &m_key; const QByteArray m_username;
const QSslCertificate &m_cert; const QByteArray m_password;
void columnChanged(int column, const QList<int> &roles = QList<int>()); void columnChanged(int column, const QList<int> &roles = QList<int>());
std::vector<std::shared_ptr<DevicesConnection>> m_devices; std::vector<std::shared_ptr<DeviceConnection>> m_devices;
QStringList m_customColumns; QStringList m_customColumns;
}; };
+8 -8
View File
@@ -1,23 +1,23 @@
#include "flottenupdatersettings.h" #include "flottenupdatersettings.h"
QByteArray FlottenUpdaterSettings::privateKey() const QByteArray FlottenUpdaterSettings::username() const
{ {
return value("privateKey").toByteArray(); return value("username").toByteArray();
} }
void FlottenUpdaterSettings::setPrivateKey(const QByteArray &key) void FlottenUpdaterSettings::setUsername(const QByteArray &username)
{ {
setValue("privateKey", key); setValue("username", username);
} }
QByteArray FlottenUpdaterSettings::privateCert() const QByteArray FlottenUpdaterSettings::password() const
{ {
return value("privateCert").toByteArray(); return value("password").toByteArray();
} }
void FlottenUpdaterSettings::setPrivateCert(const QByteArray &cert) void FlottenUpdaterSettings::setPassword(const QByteArray &password)
{ {
setValue("privateCert", cert); setValue("password", password);
} }
QStringList FlottenUpdaterSettings::customColumns() const QStringList FlottenUpdaterSettings::customColumns() const
+4 -4
View File
@@ -9,11 +9,11 @@ class FlottenUpdaterSettings : public QSettings
public: public:
using QSettings::QSettings; using QSettings::QSettings;
QByteArray privateKey() const; QByteArray username() const;
void setPrivateKey(const QByteArray &key); void setUsername(const QByteArray &key);
QByteArray privateCert() const; QByteArray password() const;
void setPrivateCert(const QByteArray &cert); void setPassword(const QByteArray &cert);
QStringList customColumns() const; QStringList customColumns() const;
void setCustomColumns(const QStringList &customColumns); void setCustomColumns(const QStringList &customColumns);
-157
View File
@@ -1,157 +0,0 @@
#include "importcertificatedialog.h"
#include "ui_importcertificatedialog.h"
#include <QFileDialog>
#include <QFile>
#include <QMessageBox>
#include <QInputDialog>
#include <QSslSocket>
#ifdef HAS_OPENSSL
#include <openssl/provider.h>
#endif
#ifdef HAS_OPENSSL
namespace {
OSSL_PROVIDER *legacy{};
}
#endif
ImportCertificateDialog::ImportCertificateDialog(QWidget *parent) :
QDialog{parent},
m_ui{std::make_unique<Ui::ImportCertificateDialog>()}
{
m_ui->setupUi(this);
connect(m_ui->pushButtonImport, &QPushButton::clicked, this, &ImportCertificateDialog::loadP12File);
connect(m_ui->plainTextEditKey, &QPlainTextEdit::textChanged, this, &ImportCertificateDialog::keyChanged);
connect(m_ui->plainTextEditCert, &QPlainTextEdit::textChanged, this, &ImportCertificateDialog::certChanged);
m_ui->labelSupportsSslValue->setText(QSslSocket::supportsSsl() ? tr("Yes") : tr("No"));
m_ui->labelSslLibraryVersionValue->setText(QSslSocket::sslLibraryVersionString());
m_ui->labelSslLibraryBuildVersionValue->setText(QSslSocket::sslLibraryBuildVersionString());
const auto &availableBackends = QSslSocket::availableBackends();
for (const auto &backend : availableBackends)
m_ui->comboBoxSslBackend->addItem(backend);
m_ui->comboBoxSslBackend->setCurrentText(QSslSocket::activeBackend());
connect(m_ui->comboBoxSslBackend, &QComboBox::currentIndexChanged,
this, &ImportCertificateDialog::updateActiveBackend);
}
ImportCertificateDialog::~ImportCertificateDialog() = default;
void ImportCertificateDialog::accept()
{
if (m_key.isNull())
return;
if (m_cert.isNull())
return;
QDialog::accept();
}
void ImportCertificateDialog::loadP12File()
{
auto selected = QFileDialog::getOpenFileName(this, tr("Select certificate..."), {}, "Certificates (*.p12)");
if (selected.isEmpty())
return;
QFile file{selected};
if (!file.open(QIODevice::ReadOnly))
{
QMessageBox::warning(this, tr("Could not open file!"), tr("Could not open file!") + "\n\n" + file.errorString());
return;
}
bool ok{};
QString passwordStr = QInputDialog::getText(this, tr("Please enter password"), tr("Certificate password:"), QLineEdit::PasswordEchoOnEdit, {}, &ok);
if (!ok)
return;
auto password = passwordStr.toUtf8();
QSslKey key;
QSslCertificate cert;
QList<QSslCertificate> certChain;
#ifdef HAS_OPENSSL
if (QSslSocket::activeBackend() == "openssl" && !legacy)
{
legacy = OSSL_PROVIDER_load(NULL, "legacy");
if (!legacy)
QMessageBox::warning(this, tr("Failed to load openssl legacy provider!"), tr("Failed to load openssl legacy provider!"));
}
#endif
if (!QSslCertificate::importPkcs12(&file, &key, &cert, &certChain, password))
{
QMessageBox::warning(this, tr("Failed processing certificate!"), tr("Failed processing certificate!") + "\n\n" + tr("Possible reasons: openssl has a problem, the file is corrupt/invalid or the password is incorrect."));
return;
}
if (key.isNull())
{
QMessageBox::warning(this, tr("Failed processing certificate!"), tr("Failed processing certificate!") + "\n\n" + tr("The key seems to be invalid."));
return;
}
if (cert.isNull())
{
QMessageBox::warning(this, tr("Failed processing certificate!"), tr("Failed processing certificate!") + "\n\n" + tr("The cert seems to be invalid."));
return;
}
m_key = std::move(key);
m_cert = std::move(cert);
{
QSignalBlocker blocker{m_ui->plainTextEditKey};
m_ui->plainTextEditKey->setPlainText(m_key.toPem());
}
{
auto palette = m_ui->plainTextEditKey->palette();
palette.setBrush(QPalette::Base, QColor{200, 255, 200});
palette.setBrush(QPalette::Window, QColor{200, 255, 200});
m_ui->plainTextEditKey->setPalette(palette);
}
{
QSignalBlocker blocker{m_ui->plainTextEditCert};
m_ui->plainTextEditCert->setPlainText(m_cert.toPem());
}
{
auto palette = m_ui->plainTextEditCert->palette();
palette.setBrush(QPalette::Base, QColor{200, 255, 200});
palette.setBrush(QPalette::Window, QColor{200, 255, 200});
m_ui->plainTextEditCert->setPalette(palette);
}
}
void ImportCertificateDialog::keyChanged()
{
m_key = QSslKey{m_ui->plainTextEditKey->toPlainText().toUtf8(), QSsl::KeyAlgorithm::Rsa, QSsl::Pem};
auto palette = m_ui->plainTextEditKey->palette();
palette.setBrush(QPalette::Base, m_key.isNull() ? QColor{255, 200, 200} : QColor{200, 255, 200});
palette.setBrush(QPalette::Window, m_key.isNull() ? QColor{255, 200, 200} : QColor{200, 255, 200});
m_ui->plainTextEditKey->setPalette(palette);
}
void ImportCertificateDialog::certChanged()
{
m_cert = QSslCertificate{m_ui->plainTextEditCert->toPlainText().toUtf8()};
auto palette = m_ui->plainTextEditCert->palette();
palette.setBrush(QPalette::Base, m_cert.isNull() ? QColor{255, 200, 200} : QColor{200, 255, 200});
palette.setBrush(QPalette::Window, m_cert.isNull() ? QColor{255, 200, 200} : QColor{200, 255, 200});
m_ui->plainTextEditCert->setPalette(palette);
}
void ImportCertificateDialog::updateActiveBackend()
{
if (!QSslSocket::setActiveBackend(m_ui->comboBoxSslBackend->currentText()))
QMessageBox::warning(this, tr("Could not change active backend"), tr("Could not change active backend"));
m_ui->comboBoxSslBackend->setCurrentText(QSslSocket::activeBackend());
}
-36
View File
@@ -1,36 +0,0 @@
#pragma once
#include <QDialog>
#include <QSslKey>
#include <QSslCertificate>
#include <memory>
namespace Ui { class ImportCertificateDialog; }
class ImportCertificateDialog : public QDialog
{
Q_OBJECT
public:
explicit ImportCertificateDialog(QWidget *parent = nullptr);
~ImportCertificateDialog();
const QSslKey &privateKey() const { return m_key; }
const QSslCertificate &privateCert() const { return m_cert; }
public slots:
void accept() override;
private slots:
void loadP12File();
void keyChanged();
void certChanged();
void updateActiveBackend();
private:
const std::unique_ptr<Ui::ImportCertificateDialog> m_ui;
QSslKey m_key;
QSslCertificate m_cert;
};
-184
View File
@@ -1,184 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ImportCertificateDialog</class>
<widget class="QDialog" name="ImportCertificateDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>459</width>
<height>429</height>
</rect>
</property>
<property name="windowTitle">
<string>Import Certificate</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelSupportsSsl">
<property name="text">
<string>Supports Ssl:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="labelSupportsSslValue">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelSslLibraryVersion">
<property name="text">
<string>Ssl Library Version:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelSslLibraryVersionValue">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelSslLibraryBuildVersion">
<property name="text">
<string>Ssl Library Build Version:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="labelSslLibraryBuildVersionValue">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelSslBackend">
<property name="text">
<string>Ssl Backend:</string>
</property>
<property name="buddy">
<cstring>comboBoxSslBackend</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxSslBackend"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelAutomaticImport">
<property name="text">
<string>Automatic Import:</string>
</property>
<property name="buddy">
<cstring>pushButtonImport</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="pushButtonImport">
<property name="text">
<string>Load p12 file...</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelPrivateKey">
<property name="text">
<string>Private Key:</string>
</property>
<property name="buddy">
<cstring>plainTextEditKey</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPlainTextEdit" name="plainTextEditKey">
<property name="autoFillBackground">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="labelPrivateCert">
<property name="text">
<string>Private Cert:</string>
</property>
<property name="buddy">
<cstring>plainTextEditCert</cstring>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QPlainTextEdit" name="plainTextEditCert">
<property name="autoFillBackground">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="labelWarning">
<property name="text">
<string>Warning: Your private key and cert will be stored on this machine, but can later be erased from the main window.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ImportCertificateDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ImportCertificateDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,89 @@
#include "importcredentialsdialog.h"
#include "ui_importcredentialsdialog.h"
#include <QMessageBox>
#include <QPushButton>
#include "deviceconnection.h"
ImportCredentialsDialog::ImportCredentialsDialog(QWidget *parent) :
QDialog{parent},
m_ui{std::make_unique<Ui::ImportCredentialsDialog>()}
{
m_ui->setupUi(this);
}
ImportCredentialsDialog::~ImportCredentialsDialog() = default;
QByteArray ImportCredentialsDialog::username() const
{
return m_ui->lineEditUsername->text().toUtf8();
}
QByteArray ImportCredentialsDialog::password() const
{
return m_ui->lineEditPassword->text().toUtf8();
}
void ImportCredentialsDialog::accept()
{
if (username().isEmpty() ||
password().isEmpty())
{
QMessageBox::warning(this, tr("Please fill out all fields!"), tr("Please fill out all fields!"));
return;
}
m_ui->lineEditUsername->setEnabled(false);
m_ui->lineEditPassword->setEnabled(false);
if (auto button = m_ui->buttonBox->button(QDialogButtonBox::Save))
button->setEnabled(false);
m_testConnection = std::make_unique<DeviceConnection>(username(), password(), "123456");
connect(m_testConnection.get(), &DeviceConnection::connectedSignal,
this, &ImportCredentialsDialog::connected);
connect(m_testConnection.get(), &DeviceConnection::disconnectedSignal,
this, &ImportCredentialsDialog::disconnected);
connect(m_testConnection.get(), &DeviceConnection::errorOccurredSignal,
this, &ImportCredentialsDialog::errorOccurred);
m_testConnection->start();
}
void ImportCredentialsDialog::connected()
{
qDebug() << "called";
QDialog::accept();
finishTestConnection();
}
void ImportCredentialsDialog::disconnected()
{
qDebug() << "called";
finishTestConnection();
}
void ImportCredentialsDialog::errorOccurred(QAbstractSocket::SocketError error)
{
Q_ASSERT(m_testConnection);
QMessageBox::warning(this,
tr("Problem verifying credentials!"),
QString("%0\n\n%1")
.arg(QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey(error))
.arg(m_testConnection->errorString())
);
}
void ImportCredentialsDialog::finishTestConnection()
{
Q_ASSERT(m_testConnection);
m_ui->lineEditUsername->setEnabled(true);
m_ui->lineEditPassword->setEnabled(true);
if (auto button = m_ui->buttonBox->button(QDialogButtonBox::Save))
button->setEnabled(true);
m_testConnection.release()->deleteLater();
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include <QDialog>
#include <QAbstractSocket>
#include <memory>
namespace Ui { class ImportCredentialsDialog; }
class DeviceConnection;
class ImportCredentialsDialog : public QDialog
{
Q_OBJECT
public:
explicit ImportCredentialsDialog(QWidget *parent = nullptr);
~ImportCredentialsDialog();
QByteArray username() const;
QByteArray password() const;
public slots:
void accept() override;
private slots:
void connected();
void disconnected();
void errorOccurred(QAbstractSocket::SocketError error);
private:
void finishTestConnection();
const std::unique_ptr<Ui::ImportCredentialsDialog> m_ui;
std::unique_ptr<DeviceConnection> m_testConnection;
};
+114
View File
@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ImportCredentialsDialog</class>
<widget class="QDialog" name="ImportCredentialsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>442</width>
<height>164</height>
</rect>
</property>
<property name="windowTitle">
<string>Import Credentials</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="labelTitle">
<property name="text">
<string>Please enter your credentials to access solalaweb.com:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Please create an app password in &lt;a href=&quot;https://auth.go-e.com/if/user/#/settings;{%22page%22:%22page-tokens%22}&quot;&gt;our SSO&lt;/a&gt;.</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0">
<widget class="QLabel" name="labelUsername">
<property name="text">
<string>Username:</string>
</property>
<property name="buddy">
<cstring>lineEditUsername</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelPassword">
<property name="text">
<string>App-Password:</string>
</property>
<property name="buddy">
<cstring>lineEditPassword</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditUsername"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEditPassword"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ImportCredentialsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ImportCredentialsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+14 -37
View File
@@ -1,14 +1,9 @@
#include <QApplication> #include <QApplication>
#include <QMessageBox> #include <QMessageBox>
#include <QDebug> #include <QDebug>
#include <QSslKey>
#include <QSslCertificate>
#ifdef Q_OS_WIN
#include <QSslSocket>
#endif
#include "flottenupdatersettings.h" #include "flottenupdatersettings.h"
#include "importcertificatedialog.h" #include "importcredentialsdialog.h"
#include "mainwindow.h" #include "mainwindow.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@@ -36,50 +31,32 @@ int main(int argc, char *argv[])
#endif #endif
FlottenUpdaterSettings settings; FlottenUpdaterSettings settings;
QByteArray keyBuf = settings.privateKey(); QByteArray username = settings.username();
QByteArray certBuf = settings.privateCert(); QByteArray password = settings.password();
QSslKey key{keyBuf, QSsl::KeyAlgorithm::Rsa, QSsl::Pem};
QSslCertificate cert{certBuf};
if (keyBuf.isEmpty()) if (username.isEmpty())
goto loadCert; goto loadCredentials;
if (certBuf.isEmpty()) if (password.isEmpty())
goto loadCert; goto loadCredentials;
if (key.isNull())
{
QMessageBox::warning(nullptr,
QCoreApplication::translate("main", "Could not parse private key!"),
QCoreApplication::translate("main", "Could not parse private key!"));
goto loadCert;
}
if (cert.isNull())
{
QMessageBox::warning(nullptr,
QCoreApplication::translate("main", "Could not parse private cert!"),
QCoreApplication::translate("main", "Could not parse private cert!"));
goto loadCert;
}
goto showMainWindow; goto showMainWindow;
{ {
loadCert: loadCredentials:
ImportCertificateDialog dialog; ImportCredentialsDialog dialog;
if (dialog.exec() != QDialog::Accepted) if (dialog.exec() != QDialog::Accepted)
return 0; return 0;
key = dialog.privateKey(); username = dialog.username();
cert = dialog.privateCert(); password = dialog.password();
settings.setPrivateKey(key.toPem()); settings.setUsername(username);
settings.setPrivateCert(cert.toPem()); settings.setPassword(password);
} }
showMainWindow: showMainWindow:
MainWindow mainWindow{settings, key, cert}; MainWindow mainWindow{settings, username, password};
mainWindow.show(); mainWindow.show();
return app.exec(); return app.exec();
+4 -4
View File
@@ -18,12 +18,12 @@
#include "setarbitraryapikeydialog.h" #include "setarbitraryapikeydialog.h"
#include "addserialsrangedialog.h" #include "addserialsrangedialog.h"
MainWindow::MainWindow(FlottenUpdaterSettings &settings, const QSslKey &key, MainWindow::MainWindow(FlottenUpdaterSettings &settings, const QByteArray &username,
const QSslCertificate &cert, QWidget *parent) : const QByteArray &password, QWidget *parent) :
QMainWindow{parent}, QMainWindow{parent},
m_ui{std::make_unique<Ui::MainWindow>()}, m_ui{std::make_unique<Ui::MainWindow>()},
m_settings{settings}, m_settings{settings},
m_model{std::make_unique<DevicesModel>(settings, key, cert, this)}, m_model{std::make_unique<DevicesModel>(settings, username, password, this)},
m_proxyModel{std::make_unique<QSortFilterProxyModel>(this)} m_proxyModel{std::make_unique<QSortFilterProxyModel>(this)}
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@@ -146,7 +146,7 @@ void MainWindow::contextMenuRequested(const QPoint &pos)
[&](const QModelIndex &index){ return m_proxyModel->mapToSource(index); }); [&](const QModelIndex &index){ return m_proxyModel->mapToSource(index); });
// get all the devices for selected indices // get all the devices for selected indices
std::vector<std::shared_ptr<DevicesConnection>> devices; std::vector<std::shared_ptr<DeviceConnection>> devices;
devices.reserve(selectedRows.size()); devices.reserve(selectedRows.size());
std::transform(std::begin(selectedRows), std::end(selectedRows), std::back_inserter(devices), std::transform(std::begin(selectedRows), std::end(selectedRows), std::back_inserter(devices),
[&](const QModelIndex &index){ auto device = m_model->getDevice(index); Q_ASSERT(device); return device; }); [&](const QModelIndex &index){ auto device = m_model->getDevice(index); Q_ASSERT(device); return device; });
+2 -2
View File
@@ -18,8 +18,8 @@ class MainWindow : public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
explicit MainWindow(FlottenUpdaterSettings &settings, const QSslKey &key, explicit MainWindow(FlottenUpdaterSettings &settings, const QByteArray &username,
const QSslCertificate &cert, QWidget *parent = nullptr); const QByteArray &password, QWidget *parent = nullptr);
~MainWindow() override; ~MainWindow() override;
private slots: private slots:
+1 -1
View File
@@ -7,7 +7,7 @@
#include "deviceconnection.h" #include "deviceconnection.h"
#include "requestmodel.h" #include "requestmodel.h"
RequestDialog::RequestDialog(QJsonObject &&msg, std::vector<std::shared_ptr<DevicesConnection>> &&devices, QWidget *parent) : RequestDialog::RequestDialog(QJsonObject &&msg, std::vector<std::shared_ptr<DeviceConnection>> &&devices, QWidget *parent) :
QDialog{parent}, QDialog{parent},
m_ui{std::make_unique<Ui::RequestDialog>()}, m_ui{std::make_unique<Ui::RequestDialog>()},
m_model{std::make_unique<RequestModel>(std::move(msg), std::move(devices), this)} m_model{std::make_unique<RequestModel>(std::move(msg), std::move(devices), this)}
+2 -2
View File
@@ -5,7 +5,7 @@
#include <memory> #include <memory>
class QJsonObject; class QJsonObject;
class DevicesConnection; class DeviceConnection;
class RequestModel; class RequestModel;
namespace Ui { class RequestDialog; } namespace Ui { class RequestDialog; }
@@ -15,7 +15,7 @@ class RequestDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit RequestDialog(QJsonObject &&msg, std::vector<std::shared_ptr<DevicesConnection>> &&devices, QWidget *parent = nullptr); explicit RequestDialog(QJsonObject &&msg, std::vector<std::shared_ptr<DeviceConnection>> &&devices, QWidget *parent = nullptr);
~RequestDialog(); ~RequestDialog();
private: private:
+2 -2
View File
@@ -21,7 +21,7 @@ enum {
QString getRandomString(); QString getRandomString();
} }
RequestModel::RequestModel(QJsonObject &&msg, std::vector<std::shared_ptr<DevicesConnection>> &&devices, QObject *parent) : RequestModel::RequestModel(QJsonObject &&msg, std::vector<std::shared_ptr<DeviceConnection>> &&devices, QObject *parent) :
QAbstractTableModel{parent} QAbstractTableModel{parent}
{ {
m_requests.reserve(devices.size()); m_requests.reserve(devices.size());
@@ -33,7 +33,7 @@ RequestModel::RequestModel(QJsonObject &&msg, std::vector<std::shared_ptr<Device
.requestId = getRandomString() .requestId = getRandomString()
}; };
connect(request.device.get(), &DevicesConnection::responseReceived, this, &RequestModel::responseReceived); connect(request.device.get(), &DeviceConnection::responseReceived, this, &RequestModel::responseReceived);
{ {
QJsonObject msg2 = msg; QJsonObject msg2 = msg;
+3 -3
View File
@@ -6,14 +6,14 @@
#include <memory> #include <memory>
class QJsonObject; class QJsonObject;
class DevicesConnection; class DeviceConnection;
class RequestModel : public QAbstractTableModel class RequestModel : public QAbstractTableModel
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit RequestModel(QJsonObject &&msg, std::vector<std::shared_ptr<DevicesConnection>> &&devices, QObject *parent = nullptr); explicit RequestModel(QJsonObject &&msg, std::vector<std::shared_ptr<DeviceConnection>> &&devices, QObject *parent = nullptr);
~RequestModel() override; ~RequestModel() override;
// QAbstractItemModel interface // QAbstractItemModel interface
@@ -27,7 +27,7 @@ private slots:
private: private:
struct Request { struct Request {
std::shared_ptr<DevicesConnection> device; std::shared_ptr<DeviceConnection> device;
QString requestId; QString requestId;
enum class Status { Pending, Failed, Succeeded }; enum class Status { Pending, Failed, Succeeded };
Status status{Status::Pending}; Status status{Status::Pending};