Mostly working, cleanup still to be done
This commit is contained in:
parent
22dd3fe27d
commit
f75b66c0ff
@ -7,6 +7,7 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QSettings>
|
||||
#include <QUuid>
|
||||
#include <QTimer>
|
||||
|
||||
#include "sigv4utils.h"
|
||||
|
||||
@ -872,6 +873,11 @@ bool AWSClient::postToMQTT(const QString &boxId, const QString ×tamp, std::
|
||||
// }
|
||||
// qDebug() << "Payload:" << payload;
|
||||
QNetworkReply *reply = m_nam->post(request, payload);
|
||||
QTimer::singleShot(5000, reply, [reply, callback](){
|
||||
reply->deleteLater();
|
||||
qWarning() << "Timeout posting to MQTT";
|
||||
callback(false);
|
||||
});
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, callback]() {
|
||||
reply->deleteLater();
|
||||
QByteArray data = reply->readAll();
|
||||
|
||||
@ -54,6 +54,7 @@ bool CloudTransport::connect(const QUrl &url)
|
||||
m_timestamp = QDateTime::currentDateTime();
|
||||
bool postResult = m_awsClient->postToMQTT(url.host(), QString::number(m_timestamp.toMSecsSinceEpoch()), [this](bool success) {
|
||||
if (success) {
|
||||
qDebug() << "MQTT Post done. Connecting to remote proxy";
|
||||
m_remoteproxyConnection->connectServer(QUrl("wss://remoteproxy.nymea.io"));
|
||||
} else {
|
||||
qDebug() << "Posting to MQTT failed";
|
||||
|
||||
@ -180,12 +180,13 @@ void ZeroconfDiscovery::serviceEntryRemoved(const QZeroConfService &entry)
|
||||
}
|
||||
|
||||
// Ok, now we need to remove it
|
||||
host->connections()->removeConnection(connection);
|
||||
// host->connections()->removeConnection(connection);
|
||||
connection->setOnline(false);
|
||||
|
||||
// And if there aren't any connections left, remove the entire device
|
||||
if (host->connections()->rowCount() == 0) {
|
||||
qDebug() << "Zeroconf: Removing connection from host:" << host->name() << url.toString();
|
||||
m_nymeaHosts->removeHost(host);
|
||||
}
|
||||
// if (host->connections()->rowCount() == 0) {
|
||||
// qDebug() << "Zeroconf: Removing connection from host:" << host->name() << url.toString();
|
||||
// m_nymeaHosts->removeHost(host);
|
||||
// }
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include <QStandardPaths>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
|
||||
#include "nymeatransportinterface.h"
|
||||
|
||||
@ -32,6 +33,9 @@ NymeaConnection::NymeaConnection(QObject *parent) : QObject(parent)
|
||||
void NymeaConnection::acceptCertificate(const QString &url, const QByteArray &pem)
|
||||
{
|
||||
storePem(url, pem);
|
||||
if (m_currentHost) {
|
||||
connectInternal(m_currentHost);
|
||||
}
|
||||
}
|
||||
|
||||
bool NymeaConnection::isTrusted(const QString &url)
|
||||
@ -62,6 +66,11 @@ bool NymeaConnection::connected()
|
||||
return m_currentHost && m_currentTransport && m_currentTransport->connectionState() == NymeaTransportInterface::ConnectionStateConnected;
|
||||
}
|
||||
|
||||
NymeaConnection::ConnectionStatus NymeaConnection::connectionStatus() const
|
||||
{
|
||||
return m_connectionStatus;
|
||||
}
|
||||
|
||||
NymeaHost *NymeaConnection::currentHost() const
|
||||
{
|
||||
return m_currentHost;
|
||||
@ -91,6 +100,9 @@ void NymeaConnection::setCurrentHost(NymeaHost *host)
|
||||
m_currentHost = host;
|
||||
emit currentHostChanged();
|
||||
|
||||
m_connectionStatus = ConnectionStatusConnecting;
|
||||
emit connectionStatusChanged();
|
||||
|
||||
if (m_currentHost) {
|
||||
connectInternal(m_currentHost);
|
||||
}
|
||||
@ -175,6 +187,8 @@ void NymeaConnection::onSslErrors(const QList<QSslError> &errors)
|
||||
// info << tr("Name Qualifier:")<< error.certificate().issuerInfo(QSslCertificate::DistinguishedNameQualifier);
|
||||
// info << tr("Email:")<< error.certificate().issuerInfo(QSslCertificate::EmailAddress);
|
||||
|
||||
m_connectionStatus = ConnectionStatusSslUntrusted;
|
||||
emit connectionStatusChanged();
|
||||
emit verifyConnectionCertificate(transport->url().toString(), info, certificateFingerprint, error.certificate().toPem());
|
||||
}
|
||||
} else {
|
||||
@ -196,22 +210,58 @@ void NymeaConnection::onError(QAbstractSocket::SocketError error)
|
||||
|
||||
NymeaTransportInterface* transport = qobject_cast<NymeaTransportInterface*>(sender());
|
||||
|
||||
ConnectionStatus errorStatus = ConnectionStatusUnknownError;
|
||||
switch (error) {
|
||||
case QAbstractSocket::ConnectionRefusedError:
|
||||
errorStatus = ConnectionStatusConnectionRefused;
|
||||
break;
|
||||
case QAbstractSocket::HostNotFoundError:
|
||||
errorStatus = ConnectionStatusHostNotFound;
|
||||
break;
|
||||
case QAbstractSocket::NetworkError:
|
||||
errorStatus = ConnectionStatusBearerFailed;
|
||||
break;
|
||||
case QAbstractSocket::RemoteHostClosedError:
|
||||
errorStatus = ConnectionStatusRemoteHostClosed;
|
||||
break;
|
||||
case QAbstractSocket::SocketTimeoutError:
|
||||
errorStatus = ConnectionStatusTimeout;
|
||||
break;
|
||||
case QAbstractSocket::SslInternalError:
|
||||
case QAbstractSocket::SslInvalidUserDataError:
|
||||
errorStatus = ConnectionStatusSslError;
|
||||
break;
|
||||
case QAbstractSocket::SslHandshakeFailedError:
|
||||
errorStatus = ConnectionStatusSslUntrusted;
|
||||
break;
|
||||
default:
|
||||
errorStatus = ConnectionStatusUnknownError;
|
||||
}
|
||||
|
||||
if (transport == m_currentTransport) {
|
||||
qDebug() << "Current transport failed:" << error;
|
||||
// The current transport failed, forward the error
|
||||
emit connectionError(errorString);
|
||||
m_connectionStatus = errorStatus;
|
||||
emit connectionStatusChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_currentTransport) {
|
||||
// We're trying to connect and one of the transports failed...
|
||||
qDebug() << "A transport error happened for" << transport->url() << error;
|
||||
qDebug() << "A transport error happened for" << transport->url() << error << "(Still trying on" << m_transportCandidates.count() << "connections)";
|
||||
if (m_transportCandidates.contains(transport)) {
|
||||
m_transportCandidates.remove(transport);
|
||||
transport->deleteLater();
|
||||
}
|
||||
if (m_transportCandidates.isEmpty()) {
|
||||
emit connectionError(errorString);
|
||||
m_connectionStatus = errorStatus;
|
||||
emit connectionStatusChanged();
|
||||
|
||||
if (m_connectionStatus != ConnectionStatusSslUntrusted) {
|
||||
QTimer::singleShot(1000, m_currentHost, [this](){
|
||||
connectInternal(m_currentHost);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -263,7 +313,10 @@ void NymeaConnection::onDisconnected()
|
||||
qDebug() << "NymeaConnection: disconnected.";
|
||||
emit connectedChanged(false);
|
||||
|
||||
connectInternal(m_currentHost);
|
||||
// Try to reconnect, only if we're not waiting for SSL certs to be trusted.
|
||||
if (m_connectionStatus != ConnectionStatusSslUntrusted) {
|
||||
connectInternal(m_currentHost);
|
||||
}
|
||||
}
|
||||
|
||||
void NymeaConnection::updateActiveBearers()
|
||||
@ -277,18 +330,20 @@ void NymeaConnection::updateActiveBearers()
|
||||
}
|
||||
// qDebug() << "Available bearers:" << availableBearerTypes;
|
||||
if (m_availableBearerTypes != availableBearerTypes) {
|
||||
qDebug() << "Available Bearer Types changed:" << availableBearerTypes;
|
||||
|
||||
qDebug() << "Available Bearer Types changed:" << availableBearerTypes;
|
||||
m_availableBearerTypes = availableBearerTypes;
|
||||
emit availableBearerTypesChanged();
|
||||
}
|
||||
|
||||
if (!m_currentHost) {
|
||||
// No host set... Nothing to do...
|
||||
qDebug() << "No current host... Nothing to do...";
|
||||
return;
|
||||
}
|
||||
if (!m_currentTransport) {
|
||||
// There's a host but no connection. Try connecting now...
|
||||
qDebug() << "There's a host but no connection. Trying to connect now...";
|
||||
connectInternal(m_currentHost);
|
||||
}
|
||||
|
||||
@ -338,6 +393,7 @@ bool NymeaConnection::storePem(const QUrl &host, const QByteArray &pem)
|
||||
bool NymeaConnection::loadPem(const QUrl &host, QByteArray &pem)
|
||||
{
|
||||
QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/sslcerts/");
|
||||
qDebug() << "Loading certificates from:" << dir.absoluteFilePath(host.host() + ".pem");
|
||||
QFile certFile(dir.absoluteFilePath(host.host() + ".pem"));
|
||||
if (!certFile.open(QFile::ReadOnly)) {
|
||||
return false;
|
||||
@ -361,6 +417,12 @@ void NymeaConnection::connect(NymeaHost *nymeaHost)
|
||||
|
||||
void NymeaConnection::connectInternal(NymeaHost *host)
|
||||
{
|
||||
if (m_availableBearerTypes == Connection::BearerTypeNone) {
|
||||
qDebug() << "No available bearer. Not connecting... (" << m_availableBearerTypes << ")";
|
||||
m_connectionStatus = ConnectionStatusNoBearerAvailable;
|
||||
emit connectionStatusChanged();
|
||||
return;
|
||||
}
|
||||
if (m_availableBearerTypes.testFlag(Connection::BearerTypeWifi) || m_availableBearerTypes.testFlag(Connection::BearerTypeEthernet)) {
|
||||
Connection* lanConnection = host->connections()->bestMatch(Connection::BearerTypeWifi | Connection::BearerTypeEthernet);
|
||||
if (lanConnection) {
|
||||
|
||||
@ -21,8 +21,24 @@ class NymeaConnection : public QObject
|
||||
Q_PROPERTY(NymeaHost* currentHost READ currentHost WRITE setCurrentHost NOTIFY currentHostChanged)
|
||||
Q_PROPERTY(Connection* currentConnection READ currentConnection NOTIFY currentConnectionChanged)
|
||||
Q_PROPERTY(Connection::BearerTypes availableBearerTypes READ availableBearerTypes NOTIFY availableBearerTypesChanged)
|
||||
Q_PROPERTY(ConnectionStatus connectionStatus READ connectionStatus NOTIFY connectionStatusChanged)
|
||||
|
||||
public:
|
||||
enum ConnectionStatus {
|
||||
ConnectionStatusUnconnected,
|
||||
ConnectionStatusConnecting,
|
||||
ConnectionStatusNoBearerAvailable,
|
||||
ConnectionStatusBearerFailed,
|
||||
ConnectionStatusHostNotFound,
|
||||
ConnectionStatusConnectionRefused,
|
||||
ConnectionStatusRemoteHostClosed,
|
||||
ConnectionStatusTimeout,
|
||||
ConnectionStatusSslError,
|
||||
ConnectionStatusSslUntrusted,
|
||||
ConnectionStatusUnknownError,
|
||||
ConnectionStatusConnected
|
||||
};
|
||||
Q_ENUM(ConnectionStatus)
|
||||
explicit NymeaConnection(QObject *parent = nullptr);
|
||||
|
||||
void registerTransport(NymeaTransportInterfaceFactory *transportFactory);
|
||||
@ -35,12 +51,14 @@ public:
|
||||
Connection::BearerTypes availableBearerTypes() const;
|
||||
|
||||
bool connected();
|
||||
ConnectionStatus connectionStatus() const;
|
||||
|
||||
NymeaHost* currentHost() const;
|
||||
void setCurrentHost(NymeaHost *host);
|
||||
|
||||
Connection* currentConnection() const;
|
||||
|
||||
|
||||
void sendData(const QByteArray &data);
|
||||
|
||||
signals:
|
||||
@ -48,8 +66,8 @@ signals:
|
||||
void verifyConnectionCertificate(const QString &url, const QStringList &issuerInfo, const QByteArray &fingerprint, const QByteArray &pem);
|
||||
void currentHostChanged();
|
||||
void connectedChanged(bool connected);
|
||||
void connectionStatusChanged();
|
||||
void currentConnectionChanged();
|
||||
void connectionError(const QString &error);
|
||||
void dataAvailable(const QByteArray &data);
|
||||
|
||||
private slots:
|
||||
@ -69,6 +87,7 @@ private:
|
||||
Connection::BearerType qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type) const;
|
||||
|
||||
private:
|
||||
ConnectionStatus m_connectionStatus = ConnectionStatusUnconnected;
|
||||
QNetworkConfigurationManager *m_networkConfigManager = nullptr;
|
||||
Connection::BearerTypes m_availableBearerTypes = Connection::BearerTypeNone;
|
||||
|
||||
|
||||
@ -158,7 +158,7 @@ void NymeaHostsFilterModel::setNymeaConnection(NymeaConnection *nymeaConnection)
|
||||
emit nymeaConnectionChanged();
|
||||
|
||||
connect(m_nymeaConnection, &NymeaConnection::availableBearerTypesChanged, this, [this](){
|
||||
qDebug() << "Bearer Types Changed!";
|
||||
// qDebug() << "Bearer Types Changed!";
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
});
|
||||
|
||||
@ -163,5 +163,6 @@
|
||||
<file>ui/thingconfiguration/SetupWizard.qml</file>
|
||||
<file>ui/thingconfiguration/EditThingsPage.qml</file>
|
||||
<file>ui/thingconfiguration/ConfigureThingPage.qml</file>
|
||||
<file>ui/connection/CertificateDialog.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@ -75,7 +75,7 @@ Item {
|
||||
height: swipeView.height
|
||||
width: swipeView.width
|
||||
objectName: "pageStack"
|
||||
initialItem: ConnectPage {}
|
||||
initialItem: Page {}
|
||||
|
||||
property var tabSettings: Settings {
|
||||
category: "tabSettings" + index
|
||||
@ -98,23 +98,30 @@ Item {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// pageStack.push(Qt.resolvedUrl("connection/ConnectPage.qml"), StackView.Immediate)
|
||||
// setupPushNotifications();
|
||||
if (tabSettings.lastConnectedHost.length > 0) {
|
||||
print("Last connected host was", tabSettings.lastConnectedHost)
|
||||
var cachedHost = discovery.nymeaHosts.find(tabSettings.lastConnectedHost);
|
||||
if (cachedHost) {
|
||||
engine.connection.currentHost = cachedHost
|
||||
} else {
|
||||
print("Warning: There is a last connected host but UUID is unknown to discovery...")
|
||||
}
|
||||
} else {
|
||||
PlatformHelper.hideSplashScreen();
|
||||
pageStack.push(Qt.resolvedUrl("connection/ConnectPage.qml"), StackView.Immediate)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
print("calling init. Auth required:", engine.jsonRpcClient.authenticationRequired, "initial setup required:", engine.jsonRpcClient.initialSetupRequired, "jsonrpc connected:", engine.jsonRpcClient.connected, "Current host:", engine.connection.currentHost)
|
||||
pageStack.clear()
|
||||
if (!engine.connection.currentHost) {
|
||||
print("pushing ConnectPage")
|
||||
pageStack.push(Qt.resolvedUrl("connection/ConnectPage.qml"))
|
||||
PlatformHelper.hideSplashScreen();
|
||||
return;
|
||||
}
|
||||
if (engine.jsonRpcClient.connected) {
|
||||
pageStack.push(Qt.resolvedUrl("MainPage.qml"))
|
||||
PlatformHelper.hideSplashScreen();
|
||||
return;
|
||||
}
|
||||
|
||||
if (engine.jsonRpcClient.authenticationRequired || engine.jsonRpcClient.initialSetupRequired) {
|
||||
PlatformHelper.hideSplashScreen();
|
||||
@ -126,6 +133,7 @@ Item {
|
||||
engine.connection.disconnect();
|
||||
init();
|
||||
})
|
||||
return;
|
||||
} else {
|
||||
var page = pageStack.push(Qt.resolvedUrl("LoginPage.qml"));
|
||||
page.backPressed.connect(function() {
|
||||
@ -133,9 +141,22 @@ Item {
|
||||
engine.connection.disconnect()
|
||||
init();
|
||||
})
|
||||
return;
|
||||
}
|
||||
}
|
||||
pageStack.push(Qt.resolvedUrl("connection/ConnectingPage.qml"))
|
||||
|
||||
if (engine.jsonRpcClient.connected) {
|
||||
pageStack.push(Qt.resolvedUrl("MainPage.qml"))
|
||||
PlatformHelper.hideSplashScreen();
|
||||
return;
|
||||
}
|
||||
|
||||
print("pushing ConnectingPage")
|
||||
PlatformHelper.hideSplashScreen();
|
||||
var page = pageStack.push(Qt.resolvedUrl("connection/ConnectingPage.qml"));
|
||||
page.cancel.connect(function(){
|
||||
engine.connection.disconnect();
|
||||
})
|
||||
}
|
||||
|
||||
function handleCloseEvent(close) {
|
||||
@ -179,8 +200,15 @@ Item {
|
||||
onCurrentHostChanged: {
|
||||
init();
|
||||
}
|
||||
onVerifyConnectionCertificate: {
|
||||
print("verify cert!")
|
||||
var certDialogComponent = Qt.createComponent(Qt.resolvedUrl("connection/CertificateDialog.qml"));
|
||||
var popup = certDialogComponent.createObject(root, {url: url, issuerInfo: issuerInfo, fingerprint: fingerprint, pem: pem});
|
||||
popup.open();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Connections {
|
||||
target: engine.jsonRpcClient
|
||||
onConnectedChanged: {
|
||||
|
||||
110
nymea-app/ui/connection/CertificateDialog.qml
Normal file
110
nymea-app/ui/connection/CertificateDialog.qml
Normal file
@ -0,0 +1,110 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls.Material 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import Nymea 1.0
|
||||
import "../components"
|
||||
|
||||
Dialog {
|
||||
id: certDialog
|
||||
width: Math.min(parent.width * .9, 400)
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
standardButtons: Dialog.Yes | Dialog.No
|
||||
|
||||
property string url
|
||||
property var fingerprint
|
||||
property var issuerInfo
|
||||
property var pem
|
||||
|
||||
readonly property bool hasOldFingerprint: engine.connection.isTrusted(url)
|
||||
|
||||
ColumnLayout {
|
||||
id: certLayout
|
||||
anchors.fill: parent
|
||||
// spacing: app.margins
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize * 2
|
||||
Layout.preferredWidth: height
|
||||
name: certDialog.hasOldFingerprint ? "../images/lock-broken.svg" : "../images/info.svg"
|
||||
color: certDialog.hasOldFingerprint ? "red" : app.accentColor
|
||||
}
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: certDialog.hasOldFingerprint ? qsTr("Warning") : qsTr("Hi there!")
|
||||
color: certDialog.hasOldFingerprint ? "red" : app.accentColor
|
||||
font.pixelSize: app.largeFont
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: certDialog.hasOldFingerprint ? qsTr("The certificate of this %1 box has changed!").arg(app.systemName) : qsTr("It seems this is the first time you connect to this %1 box.").arg(app.systemName)
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: certDialog.hasOldFingerprint ? qsTr("Did you change the box's configuration? Verify if this information is correct.") : qsTr("This is the box's certificate. Once you trust it, an encrypted connection will be established.")
|
||||
}
|
||||
|
||||
ThinDivider {}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitHeight: certGridLayout.implicitHeight
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
contentHeight: certGridLayout.implicitHeight
|
||||
clip: true
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: contentHeight > height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: certGridLayout
|
||||
columns: 2
|
||||
width: parent.width
|
||||
|
||||
Repeater {
|
||||
model: certDialog.issuerInfo
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: modelData
|
||||
}
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
text: qsTr("Fingerprint: ") + certDialog.fingerprint
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThinDivider {}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: certDialog.hasOldFingerprint ? qsTr("Do you want to connect nevertheless?") : qsTr("Do you want to trust this device?")
|
||||
font.bold: true
|
||||
}
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
engine.connection.acceptCertificate(certDialog.url, certDialog.pem)
|
||||
}
|
||||
}
|
||||
@ -12,28 +12,8 @@ Page {
|
||||
|
||||
Component.onCompleted: {
|
||||
print("Ready to connect")
|
||||
if (tabSettings.lastConnectedHost.length > 0) {
|
||||
print("Last connected host was", tabSettings.lastConnectedHost)
|
||||
var cachedHost = discovery.nymeaHosts.find(tabSettings.lastConnectedHost);
|
||||
if (cachedHost) {
|
||||
engine.connection.currentHost = cachedHost
|
||||
} else {
|
||||
print("Warning: There is a last connected host but UUID is unknown to discovery...")
|
||||
}
|
||||
} else {
|
||||
PlatformHelper.hideSplashScreen();
|
||||
}
|
||||
|
||||
// if (settings.lastConnectedHost.length > 0 && Engine.connection.connect(tabSettings.lastConnectedHost)) {
|
||||
// var page = pageStack.push(Qt.resolvedUrl("ConnectingPage.qml"))
|
||||
// page.cancel.connect(function() {
|
||||
// Engine.connection.disconnect();
|
||||
// pageStack.pop(root, StackView.Immediate);
|
||||
// pageStack.push(discoveryPage)
|
||||
// })
|
||||
// } else {
|
||||
pageStack.push(discoveryPage, StackView.Immediate)
|
||||
// }
|
||||
pageStack.push(discoveryPage, StackView.Immediate)
|
||||
}
|
||||
|
||||
|
||||
@ -65,55 +45,6 @@ Page {
|
||||
nymeaConnection: engine.connection
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: engine.connection
|
||||
onVerifyConnectionCertificate: {
|
||||
print("verify cert!")
|
||||
var popup = certDialogComponent.createObject(root, {url: url, issuerInfo: issuerInfo, fingerprint: fingerprint, pem: pem});
|
||||
popup.open();
|
||||
}
|
||||
onConnectionError: {
|
||||
var errorMessage;
|
||||
switch (error) {
|
||||
case "ConnectionRefusedError":
|
||||
errorMessage = qsTr("The host has rejected our connection. This probably means that %1 stopped running. Did you unplug your %1 box?").arg(app.systemName);
|
||||
break;
|
||||
case "SslInvalidUserDataError":
|
||||
case "SslHandshakeFailedError":
|
||||
// silently ignore. They'll be handled by the SSL logic
|
||||
return;
|
||||
case "HostNotFoundError":
|
||||
errorMessage = qsTr("%1:core could not be found on this address. Please make sure you entered the address correctly and that the box is powered on.").arg(app.systemName);
|
||||
break;
|
||||
case "NetworkError":
|
||||
errorMessage = qsTr("It seems you're not connected to the network.");
|
||||
break;
|
||||
case "RemoteHostClosedError":
|
||||
errorMessage = qsTr("%1:core has closed the connection. This probably means it has been turned off or restarted.").arg(app.systemName);
|
||||
break;
|
||||
case "SocketTimeoutError":
|
||||
errorMessage = qsTr("%1:core did not respond. Please make sure your network connection works properly").arg(app.systemName);
|
||||
break;
|
||||
default:
|
||||
errorMessage = qsTr("An unknown error happened. We're very sorry for that. (Error code: %1)").arg(error);
|
||||
}
|
||||
|
||||
pageStack.pop(root, StackView.Immediate)
|
||||
pageStack.push(discoveryPage)
|
||||
|
||||
print("opening ErrorDialog with message:", errorMessage, error)
|
||||
var comp = Qt.createComponent(Qt.resolvedUrl("../components/ErrorDialog.qml"))
|
||||
var popup = comp.createObject(app, {text: errorMessage})
|
||||
popup.open()
|
||||
}
|
||||
onConnectedChanged: {
|
||||
if (!connected) {
|
||||
pageStack.pop(root, StackView.Immediate)
|
||||
pageStack.push(discoveryPage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: discoveryPage
|
||||
|
||||
@ -357,116 +288,6 @@ Page {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: certDialogComponent
|
||||
|
||||
Dialog {
|
||||
id: certDialog
|
||||
width: Math.min(parent.width * .9, 400)
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
standardButtons: Dialog.Yes | Dialog.No
|
||||
|
||||
property string url
|
||||
property var fingerprint
|
||||
property var issuerInfo
|
||||
property var pem
|
||||
|
||||
readonly property bool hasOldFingerprint: engine.connection.isTrusted(url)
|
||||
|
||||
ColumnLayout {
|
||||
id: certLayout
|
||||
anchors.fill: parent
|
||||
// spacing: app.margins
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize * 2
|
||||
Layout.preferredWidth: height
|
||||
name: certDialog.hasOldFingerprint ? "../images/lock-broken.svg" : "../images/info.svg"
|
||||
color: certDialog.hasOldFingerprint ? "red" : app.accentColor
|
||||
}
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: certDialog.hasOldFingerprint ? qsTr("Warning") : qsTr("Hi there!")
|
||||
color: certDialog.hasOldFingerprint ? "red" : app.accentColor
|
||||
font.pixelSize: app.largeFont
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: certDialog.hasOldFingerprint ? qsTr("The certificate of this %1 box has changed!").arg(app.systemName) : qsTr("It seems this is the first time you connect to this %1 box.").arg(app.systemName)
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: certDialog.hasOldFingerprint ? qsTr("Did you change the box's configuration? Verify if this information is correct.") : qsTr("This is the box's certificate. Once you trust it, an encrypted connection will be established.")
|
||||
}
|
||||
|
||||
ThinDivider {}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitHeight: certGridLayout.implicitHeight
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
contentHeight: certGridLayout.implicitHeight
|
||||
clip: true
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: contentHeight > height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: certGridLayout
|
||||
columns: 2
|
||||
width: parent.width
|
||||
|
||||
Repeater {
|
||||
model: certDialog.issuerInfo
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: modelData
|
||||
}
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
text: qsTr("Fingerprint: ") + certDialog.fingerprint
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThinDivider {}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: certDialog.hasOldFingerprint ? qsTr("Do you want to connect nevertheless?") : qsTr("Do you want to trust this device?")
|
||||
font.bold: true
|
||||
}
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
engine.connection.acceptCertificate(certDialog.url, certDialog.pem)
|
||||
root.connectToHost(certDialog.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component {
|
||||
id: infoDialog
|
||||
Dialog {
|
||||
|
||||
@ -33,6 +33,51 @@ Page {
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: {
|
||||
var errorMessage;
|
||||
switch (engine.connection.connectionStatus) {
|
||||
case NymeaConnection.ConnectionStatusUnconnected:
|
||||
case NymeaConnection.ConnectionStatusConnecting:
|
||||
case NymeaConnection.ConnectionStatusConnected:
|
||||
errorMessage = "";
|
||||
break;
|
||||
case NymeaConnection.ConnectionStatusBearerFailed:
|
||||
errorMessage = qsTr("The network connection failed.")
|
||||
break;
|
||||
case NymeaConnection.ConnectionStatusNoBearerAvailable:
|
||||
errorMessage = qsTr("It seems you're not connected to the network.");
|
||||
break;
|
||||
case NymeaConnection.ConnectionStatusHostNotFound:
|
||||
errorMessage = qsTr("%1:core could not be found on this address. Please make sure you entered the address correctly and that the box is powered on.").arg(app.systemName);
|
||||
break;
|
||||
case NymeaConnection.ConnectionStatusConnectionRefused:
|
||||
errorMessage = qsTr("The host has rejected our connection. This probably means that %1 stopped running. Did you unplug your %1 box?").arg(app.systemName);
|
||||
break;
|
||||
case NymeaConnection.ConnectionStatusRemoteHostClosed:
|
||||
errorMessage = qsTr("%1:core has closed the connection. This probably means it has been turned off or restarted.").arg(app.systemName);
|
||||
break;
|
||||
|
||||
case NymeaConnection.ConnectionStatusTimeout:
|
||||
errorMessage = qsTr("%1:core did not respond. Please make sure your network connection works properly").arg(app.systemName);
|
||||
break;
|
||||
case NymeaConnection.ConnectionStatusSslError:
|
||||
errorMessage = qsTr("An unrecovareable SSL Error happened. Please make sure certificates are installed correctly.");
|
||||
break;
|
||||
case NymeaConnection.ConnectionStatusSslUntrusted:
|
||||
errorMessage = qsTr("The SSL Certificate is not trusted.");
|
||||
break;
|
||||
case NymeaConnection.ConnectionStatusUnknownError:
|
||||
default:
|
||||
errorMessage = qsTr("An unknown error happened. We're very sorry for that. (Error code: %1)").arg(engine.connection.connectionStatus);
|
||||
}
|
||||
return errorMessage;
|
||||
}
|
||||
font.pixelSize: app.smallFont
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
|
||||
Reference in New Issue
Block a user