From 64f9ff490d0f4361402faaf7259ef86ed48c0852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Aug 2021 12:28:54 +0200 Subject: [PATCH 1/8] Add tunnel proxy transport basic structure and prepare connecting --- libnymea-app/connection/cloudtransport.cpp | 2 +- .../connection/tunnelproxytransport.cpp | 133 ++++++++++++++++++ .../connection/tunnelproxytransport.h | 76 ++++++++++ libnymea-app/libnymea-app.pri | 2 + nymea-remoteproxy | 2 +- 5 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 libnymea-app/connection/tunnelproxytransport.cpp create mode 100644 libnymea-app/connection/tunnelproxytransport.h diff --git a/libnymea-app/connection/cloudtransport.cpp b/libnymea-app/connection/cloudtransport.cpp index 59fb9eb5..7820a2bf 100644 --- a/libnymea-app/connection/cloudtransport.cpp +++ b/libnymea-app/connection/cloudtransport.cpp @@ -66,7 +66,7 @@ CloudTransport::CloudTransport(AWSClient *awsClient, QObject *parent): QObject::connect(m_remoteproxyConnection, &RemoteProxyConnection::dataReady, this, [this](const QByteArray &data) { emit dataReady(data); }); - QObject::connect(m_remoteproxyConnection, &RemoteProxyConnection::errorOccured, this, [] (QAbstractSocket::SocketError error) { + QObject::connect(m_remoteproxyConnection, &RemoteProxyConnection::errorOccurred, this, [] (QAbstractSocket::SocketError error) { qDebug() << "Remote proxy Error:" << error; // emit NymeaTransportInterface::error(QAbstractSocket::ConnectionRefusedError); }); diff --git a/libnymea-app/connection/tunnelproxytransport.cpp b/libnymea-app/connection/tunnelproxytransport.cpp new file mode 100644 index 00000000..ba078e92 --- /dev/null +++ b/libnymea-app/connection/tunnelproxytransport.cpp @@ -0,0 +1,133 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, GNU version 3. This project is distributed in the hope that it +* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +* Public License for more details. +* +* You should have received a copy of the GNU General Public License along with +* this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "tunnelproxytransport.h" + +#include + +TunnelProxyTransport::TunnelProxyTransport(QObject *parent) : + NymeaTransportInterface(parent) +{ + m_remoteConnection = new TunnelProxyRemoteConnection(QUuid::createUuid(), qApp->applicationName(), this); + QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::stateChanged, this, &TunnelProxyTransport::onRemoteConnectionStateChanged); + QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::remoteConnectedChanged, this, &TunnelProxyTransport::onRemoteConnectedChanged); + QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::dataReady, this, &TunnelProxyTransport::dataReady); + QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::errorOccurred, this, &TunnelProxyTransport::onRemoteConnectionErrorOccurred); + QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList &errors){ + qWarning() << "Remote tunnel proxy server SSL errors occurred:"; + foreach (const QSslError &sslError, errors) { + qWarning() << " --> " << sslError.errorString(); + } + }); + +} + +bool TunnelProxyTransport::connect(const QUrl &url) +{ + + m_url = url; + + // FIXME: get nymea uuid from URL somehow... + + //QUrl("ssl://dev-remoteproxy.nymea.io:2213"); + + //m_remoteConnection->connectServer() + + return false; +} + +QUrl TunnelProxyTransport::url() const +{ + return m_url; +} + +NymeaTransportInterface::ConnectionState TunnelProxyTransport::connectionState() const +{ + switch (m_remoteConnection->state()) { + case TunnelProxyRemoteConnection::StateRemoteConnected: + return NymeaTransportInterface::ConnectionStateConnected; + case TunnelProxyRemoteConnection::StateConnecting: + case TunnelProxyRemoteConnection::StateHostLookup: + case TunnelProxyRemoteConnection::StateConnected: + case TunnelProxyRemoteConnection::StateInitializing: + case TunnelProxyRemoteConnection::StateRegister: + return NymeaTransportInterface::ConnectionStateConnecting; + case TunnelProxyRemoteConnection::StateDiconnecting: + case TunnelProxyRemoteConnection::StateDisconnected: + return NymeaTransportInterface::ConnectionStateDisconnected; + } +} + +void TunnelProxyTransport::disconnect() +{ + m_remoteConnection->disconnectServer(); +} + +void TunnelProxyTransport::sendData(const QByteArray &data) +{ + m_remoteConnection->sendData(data); +} + +void TunnelProxyTransport::ignoreSslErrors(const QList &errors) +{ + // FIXME: once the tunnel connection implements SSL connection trought the tunnel proxy, we need to implement this + Q_UNUSED(errors) +} + +bool TunnelProxyTransport::isEncrypted() const +{ + return false; +} + +QSslCertificate TunnelProxyTransport::serverCertificate() const +{ + // FIXME: once the tunnel connection implements SSL connection trought the tunnel proxy, we need to implement this + return QSslCertificate(); +} + +void TunnelProxyTransport::onRemoteConnectedChanged(bool remoteConnected) +{ + qDebug() << "Tunnel proxy remote connection" << (remoteConnected ? "connected" : "disconnected"); +} + +void TunnelProxyTransport::onRemoteConnectionErrorOccurred(QAbstractSocket::SocketError error) +{ + qWarning() << "Tunnel proxy socket error occurred" << error; +} + +NymeaTransportInterface *TunnelProxyTransportFactory::createTransport(QObject *parent) const +{ + return new TunnelProxyTransport(parent); +} + +QStringList TunnelProxyTransportFactory::supportedSchemes() const +{ + return { "tunnel" }; +} diff --git a/libnymea-app/connection/tunnelproxytransport.h b/libnymea-app/connection/tunnelproxytransport.h new file mode 100644 index 00000000..10c2cfcc --- /dev/null +++ b/libnymea-app/connection/tunnelproxytransport.h @@ -0,0 +1,76 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, GNU version 3. This project is distributed in the hope that it +* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +* Public License for more details. +* +* You should have received a copy of the GNU General Public License along with +* this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef TUNNELPROXYTRANSPORT_H +#define TUNNELPROXYTRANSPORT_H + +#include +#include + +#include "nymeatransportinterface.h" +#include "tunnelproxy/tunnelproxyremoteconnection.h" + +class TunnelProxyTransportFactory: public NymeaTransportInterfaceFactory +{ +public: + NymeaTransportInterface* createTransport(QObject *parent = nullptr) const override; + QStringList supportedSchemes() const override; +}; + +using namespace remoteproxyclient; + +class TunnelProxyTransport : public NymeaTransportInterface +{ + Q_OBJECT +public: + explicit TunnelProxyTransport(QObject *parent = nullptr); + + bool connect(const QUrl &url) override; + QUrl url() const override; + ConnectionState connectionState() const override; + void disconnect() override; + void sendData(const QByteArray &data) override; + void ignoreSslErrors(const QList &errors) override; + + bool isEncrypted() const override; + QSslCertificate serverCertificate() const override; + +private slots: + void onRemoteConnectionStateChanged(TunnelProxyRemoteConnection::State state); + void onRemoteConnectedChanged(bool remoteConnected); + void onRemoteConnectionErrorOccurred(QAbstractSocket::SocketError error); + +private: + QUrl m_url; + TunnelProxyRemoteConnection *m_remoteConnection = nullptr; + +}; + +#endif // TUNNELPROXYTRANSPORT_H diff --git a/libnymea-app/libnymea-app.pri b/libnymea-app/libnymea-app.pri index 94567d94..6328a745 100644 --- a/libnymea-app/libnymea-app.pri +++ b/libnymea-app/libnymea-app.pri @@ -25,6 +25,7 @@ SOURCES += \ $$PWD/energy/energymanager.cpp \ $$PWD/energy/powerbalancelogs.cpp \ $$PWD/energy/thingpowerlogs.cpp \ + $$PWD/connection/tunnelproxytransport.cpp \ $$PWD/models/scriptsproxymodel.cpp \ $$PWD/tagwatcher.cpp \ $$PWD/zigbee/zigbeenode.cpp \ @@ -185,6 +186,7 @@ HEADERS += \ $$PWD/energy/energymanager.h \ $$PWD/energy/powerbalancelogs.h \ $$PWD/energy/thingpowerlogs.h \ + $$PWD/connection/tunnelproxytransport.h \ $$PWD/models/scriptsproxymodel.h \ $$PWD/tagwatcher.h \ $$PWD/zigbee/zigbeenode.h \ diff --git a/nymea-remoteproxy b/nymea-remoteproxy index 9c707519..99bf6349 160000 --- a/nymea-remoteproxy +++ b/nymea-remoteproxy @@ -1 +1 @@ -Subproject commit 9c7075192b2b799feb302b48618eb4ef4d942172 +Subproject commit 99bf634990dcd2231e6a265581a35aeffaf30037 From 5a6c809ed12dc05277771b58cdb6bee347bcb753 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 16 Dec 2021 20:37:31 +0100 Subject: [PATCH 2/8] intermediate commit --- .../connection/discovery/nymeadiscovery.cpp | 1 + libnymea-app/connection/nymeahost.cpp | 20 ++++++++++++++++++- libnymea-app/connection/nymeahost.h | 2 ++ .../connection/tunnelproxytransport.cpp | 7 +++++++ .../connection/tunnelproxytransport.h | 5 ++--- libnymea-app/jsonrpc/jsonrpcclient.cpp | 10 ++++++---- nymea-app/ui/RootItem.qml | 1 + 7 files changed, 38 insertions(+), 8 deletions(-) diff --git a/libnymea-app/connection/discovery/nymeadiscovery.cpp b/libnymea-app/connection/discovery/nymeadiscovery.cpp index 677631b1..32e0740f 100644 --- a/libnymea-app/connection/discovery/nymeadiscovery.cpp +++ b/libnymea-app/connection/discovery/nymeadiscovery.cpp @@ -152,6 +152,7 @@ void NymeaDiscovery::cacheHost(NymeaHost *host) QList connections; Connection *remoteConnection = host->connections()->bestMatch(Connection::BearerTypeCloud); if (remoteConnection) { + qCritical() << "*********** caching" << remoteConnection->url(); connections.append(remoteConnection); } Connection *loopbackConnection = host->connections()->bestMatch(Connection::BearerTypeLoopback); diff --git a/libnymea-app/connection/nymeahost.cpp b/libnymea-app/connection/nymeahost.cpp index 80b6fb26..578b8c71 100644 --- a/libnymea-app/connection/nymeahost.cpp +++ b/libnymea-app/connection/nymeahost.cpp @@ -101,6 +101,21 @@ bool NymeaHost::online() const return m_online; } +void NymeaHost::addTunnelConnection() +{ + for (int i = 0; i < m_connections->rowCount(); i++) { + if (m_connections->get(i)->url().scheme() == "tunnel") { + return; + } + } + QUrl url; + url.setScheme("tunnel"); + url.setHost(m_uuid.toString().remove(QRegExp("[{}]"))); + qCritical() << "Adding tunnel connection" << url << m_uuid; + Connection *connection = new Connection(url, Connection::BearerTypeCloud, true, "foooobaaaar", this); + m_connections->addConnection(connection); +} + void NymeaHost::syncOnlineState() { for (int i = 0; i < m_connections->rowCount(); i++) { @@ -217,7 +232,7 @@ Connection *Connections::bestMatch(Connection::BearerTypes bearerTypes) const { Connection *best = nullptr; foreach (Connection *c, m_connections) { -// qDebug() << "have connection:" << bearerTypes << c->url() << c->bearerType() << bearerTypes.testFlag(c->bearerType()); +// qWarning() << "have connection:" << bearerTypes << c->url() << c->bearerType() << bearerTypes.testFlag(c->bearerType()); if ((bearerTypes & c->bearerType()) == Connection::BearerTypeNone) { continue; } @@ -320,6 +335,9 @@ int Connection::priority() const break; case BearerTypeCloud: prio += 200; + if (m_url.scheme().startsWith("tunnel")) { + prio += 1; + } break; case BearerTypeBluetooth: prio += 100; diff --git a/libnymea-app/connection/nymeahost.h b/libnymea-app/connection/nymeahost.h index 4620d1fe..c02c7b71 100644 --- a/libnymea-app/connection/nymeahost.h +++ b/libnymea-app/connection/nymeahost.h @@ -156,6 +156,8 @@ public: bool online() const; + Q_INVOKABLE void addTunnelConnection(); + signals: void nameChanged(); void versionChanged(); diff --git a/libnymea-app/connection/tunnelproxytransport.cpp b/libnymea-app/connection/tunnelproxytransport.cpp index ba078e92..783f8b6b 100644 --- a/libnymea-app/connection/tunnelproxytransport.cpp +++ b/libnymea-app/connection/tunnelproxytransport.cpp @@ -32,6 +32,8 @@ #include +using namespace remoteproxyclient; + TunnelProxyTransport::TunnelProxyTransport(QObject *parent) : NymeaTransportInterface(parent) { @@ -112,6 +114,11 @@ QSslCertificate TunnelProxyTransport::serverCertificate() const return QSslCertificate(); } +void TunnelProxyTransport::onRemoteConnectionStateChanged(remoteproxyclient::TunnelProxyRemoteConnection::State state) +{ + qCritical() << "FIXME TODO! remoteConnectionStateChanged"; +} + void TunnelProxyTransport::onRemoteConnectedChanged(bool remoteConnected) { qDebug() << "Tunnel proxy remote connection" << (remoteConnected ? "connected" : "disconnected"); diff --git a/libnymea-app/connection/tunnelproxytransport.h b/libnymea-app/connection/tunnelproxytransport.h index 10c2cfcc..6d619936 100644 --- a/libnymea-app/connection/tunnelproxytransport.h +++ b/libnymea-app/connection/tunnelproxytransport.h @@ -44,7 +44,6 @@ public: QStringList supportedSchemes() const override; }; -using namespace remoteproxyclient; class TunnelProxyTransport : public NymeaTransportInterface { @@ -63,13 +62,13 @@ public: QSslCertificate serverCertificate() const override; private slots: - void onRemoteConnectionStateChanged(TunnelProxyRemoteConnection::State state); + void onRemoteConnectionStateChanged(remoteproxyclient::TunnelProxyRemoteConnection::State state); void onRemoteConnectedChanged(bool remoteConnected); void onRemoteConnectionErrorOccurred(QAbstractSocket::SocketError error); private: QUrl m_url; - TunnelProxyRemoteConnection *m_remoteConnection = nullptr; + remoteproxyclient::TunnelProxyRemoteConnection *m_remoteConnection = nullptr; }; diff --git a/libnymea-app/jsonrpc/jsonrpcclient.cpp b/libnymea-app/jsonrpc/jsonrpcclient.cpp index 7a76dbc5..497ebaa1 100644 --- a/libnymea-app/jsonrpc/jsonrpcclient.cpp +++ b/libnymea-app/jsonrpc/jsonrpcclient.cpp @@ -37,6 +37,7 @@ #include "connection/websockettransport.h" #include "connection/bluetoothtransport.h" #include "connection/cloudtransport.h" +#include "connection/tunnelproxytransport.h" #include #include @@ -57,10 +58,11 @@ JsonRpcClient::JsonRpcClient(QObject *parent) : m_id(0) { m_connection = new NymeaConnection(this); - m_connection->registerTransport(new TcpSocketTransportFactory()); - m_connection->registerTransport(new WebsocketTransportFactory()); - m_connection->registerTransport(new BluetoothTransportFactoy()); - m_connection->registerTransport(new CloudTransportFactory()); +// m_connection->registerTransport(new TcpSocketTransportFactory()); +// m_connection->registerTransport(new WebsocketTransportFactory()); +// m_connection->registerTransport(new BluetoothTransportFactoy()); +// m_connection->registerTransport(new CloudTransportFactory()); + m_connection->registerTransport(new TunnelProxyTransportFactory()); connect(m_connection, &NymeaConnection::availableBearerTypesChanged, this, &JsonRpcClient::availableBearerTypesChanged); connect(m_connection, &NymeaConnection::connectionStatusChanged, this, &JsonRpcClient::connectionStatusChanged); diff --git a/nymea-app/ui/RootItem.qml b/nymea-app/ui/RootItem.qml index b59f0607..ab9bfcca 100644 --- a/nymea-app/ui/RootItem.qml +++ b/nymea-app/ui/RootItem.qml @@ -312,6 +312,7 @@ Item { onConnectedChanged: { print("json client connected changed", engine.jsonRpcClient.connected, engine.jsonRpcClient.serverUuid) if (engine.jsonRpcClient.connected) { + engine.jsonRpcClient.currentHost.addTunnelConnection(); nymeaDiscovery.cacheHost(engine.jsonRpcClient.currentHost) configuredHost.uuid = engine.jsonRpcClient.serverUuid // tabSettings.lastConnectedHost = engine.jsonRpcClient.serverUuid From 39ec26f5ff3d0d289540345622b7a053d8372617 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 17 Dec 2021 19:06:35 +0100 Subject: [PATCH 3/8] JSONRPC.Hello working now, hanging at first call after that --- .../connection/tunnelproxytransport.cpp | 31 ++++++++++++------- .../connection/tunnelproxytransport.h | 1 - libnymea-app/jsonrpc/jsonrpcclient.cpp | 8 ++--- nymea-remoteproxy | 2 +- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/libnymea-app/connection/tunnelproxytransport.cpp b/libnymea-app/connection/tunnelproxytransport.cpp index 783f8b6b..245b1f2e 100644 --- a/libnymea-app/connection/tunnelproxytransport.cpp +++ b/libnymea-app/connection/tunnelproxytransport.cpp @@ -34,12 +34,17 @@ using namespace remoteproxyclient; +#include "logging.h" + +// Note: Re-registering the same category as the proxy lib offers, so we can control it in the app +// However, as we can't link the same category twice, let's just create a dummy here with the category string matching the lib +NYMEA_LOGGING_CATEGORY(dcTunnelProxyRemoteConnectionDummy, "TunnelProxyRemoteConnection") + TunnelProxyTransport::TunnelProxyTransport(QObject *parent) : NymeaTransportInterface(parent) { m_remoteConnection = new TunnelProxyRemoteConnection(QUuid::createUuid(), qApp->applicationName(), this); QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::stateChanged, this, &TunnelProxyTransport::onRemoteConnectionStateChanged); - QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::remoteConnectedChanged, this, &TunnelProxyTransport::onRemoteConnectedChanged); QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::dataReady, this, &TunnelProxyTransport::dataReady); QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::errorOccurred, this, &TunnelProxyTransport::onRemoteConnectionErrorOccurred); QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList &errors){ @@ -56,13 +61,13 @@ bool TunnelProxyTransport::connect(const QUrl &url) m_url = url; - // FIXME: get nymea uuid from URL somehow... - //QUrl("ssl://dev-remoteproxy.nymea.io:2213"); + QUrl serverUrl = QUrl("ssl://dev-remoteproxy.nymea.io:2213"); + QUuid serverUuid = url.host(); - //m_remoteConnection->connectServer() + qCritical() << "Calling connect"; - return false; + return m_remoteConnection->connectServer(serverUrl, serverUuid); } QUrl TunnelProxyTransport::url() const @@ -116,12 +121,16 @@ QSslCertificate TunnelProxyTransport::serverCertificate() const void TunnelProxyTransport::onRemoteConnectionStateChanged(remoteproxyclient::TunnelProxyRemoteConnection::State state) { - qCritical() << "FIXME TODO! remoteConnectionStateChanged"; -} - -void TunnelProxyTransport::onRemoteConnectedChanged(bool remoteConnected) -{ - qDebug() << "Tunnel proxy remote connection" << (remoteConnected ? "connected" : "disconnected"); + switch (state) { + case remoteproxyclient::TunnelProxyRemoteConnection::StateRemoteConnected: + emit connected(); + break; + case remoteproxyclient::TunnelProxyRemoteConnection::StateDisconnected: + emit disconnected(); + break; + default: + ; + } } void TunnelProxyTransport::onRemoteConnectionErrorOccurred(QAbstractSocket::SocketError error) diff --git a/libnymea-app/connection/tunnelproxytransport.h b/libnymea-app/connection/tunnelproxytransport.h index 6d619936..80129f04 100644 --- a/libnymea-app/connection/tunnelproxytransport.h +++ b/libnymea-app/connection/tunnelproxytransport.h @@ -63,7 +63,6 @@ public: private slots: void onRemoteConnectionStateChanged(remoteproxyclient::TunnelProxyRemoteConnection::State state); - void onRemoteConnectedChanged(bool remoteConnected); void onRemoteConnectionErrorOccurred(QAbstractSocket::SocketError error); private: diff --git a/libnymea-app/jsonrpc/jsonrpcclient.cpp b/libnymea-app/jsonrpc/jsonrpcclient.cpp index 497ebaa1..c7b69095 100644 --- a/libnymea-app/jsonrpc/jsonrpcclient.cpp +++ b/libnymea-app/jsonrpc/jsonrpcclient.cpp @@ -58,10 +58,10 @@ JsonRpcClient::JsonRpcClient(QObject *parent) : m_id(0) { m_connection = new NymeaConnection(this); -// m_connection->registerTransport(new TcpSocketTransportFactory()); -// m_connection->registerTransport(new WebsocketTransportFactory()); -// m_connection->registerTransport(new BluetoothTransportFactoy()); -// m_connection->registerTransport(new CloudTransportFactory()); + m_connection->registerTransport(new TcpSocketTransportFactory()); + m_connection->registerTransport(new WebsocketTransportFactory()); + m_connection->registerTransport(new BluetoothTransportFactoy()); + m_connection->registerTransport(new CloudTransportFactory()); m_connection->registerTransport(new TunnelProxyTransportFactory()); connect(m_connection, &NymeaConnection::availableBearerTypesChanged, this, &JsonRpcClient::availableBearerTypesChanged); diff --git a/nymea-remoteproxy b/nymea-remoteproxy index 99bf6349..7235a132 160000 --- a/nymea-remoteproxy +++ b/nymea-remoteproxy @@ -1 +1 @@ -Subproject commit 99bf634990dcd2231e6a265581a35aeffaf30037 +Subproject commit 7235a132b7fd77a9903d3b34b10dc4bf2a570085 From efee31410183db9e30dd7585314e597b08d4b630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 20 Dec 2021 15:05:11 +0100 Subject: [PATCH 4/8] Fix switch on remote connected changed --- libnymea-app/connection/tunnelproxytransport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libnymea-app/connection/tunnelproxytransport.cpp b/libnymea-app/connection/tunnelproxytransport.cpp index 245b1f2e..dcf50abf 100644 --- a/libnymea-app/connection/tunnelproxytransport.cpp +++ b/libnymea-app/connection/tunnelproxytransport.cpp @@ -129,7 +129,7 @@ void TunnelProxyTransport::onRemoteConnectionStateChanged(remoteproxyclient::Tun emit disconnected(); break; default: - ; + break; } } From e826e5dcd01264aeebe0fbe1798861048674311e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 20 Dec 2021 15:07:41 +0100 Subject: [PATCH 5/8] Update remoteproxy submodule --- nymea-remoteproxy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nymea-remoteproxy b/nymea-remoteproxy index 7235a132..32c33ec2 160000 --- a/nymea-remoteproxy +++ b/nymea-remoteproxy @@ -1 +1 @@ -Subproject commit 7235a132b7fd77a9903d3b34b10dc4bf2a570085 +Subproject commit 32c33ec23f975a457017b3eb7744a040bb4bd257 From 72f6f185b8c61e29d9289fd1353e8c67f8d35853 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 1 Jan 2022 17:50:59 +0100 Subject: [PATCH 6/8] Interim commit --- .../configuration/nymeaconfiguration.cpp | 55 +++++++++++++++++-- .../configuration/nymeaconfiguration.h | 9 +++ .../configuration/serverconfiguration.cpp | 29 ++++++++-- .../configuration/serverconfiguration.h | 27 ++++++++- .../configuration/serverconfigurations.h | 11 ++++ libnymea-app/libnymea-app-core.h | 2 + .../ui/system/ConnectionInterfacesPage.qml | 49 +++++++++++++++++ 7 files changed, 168 insertions(+), 14 deletions(-) diff --git a/libnymea-app/configuration/nymeaconfiguration.cpp b/libnymea-app/configuration/nymeaconfiguration.cpp index 097287d1..0122c35e 100644 --- a/libnymea-app/configuration/nymeaconfiguration.cpp +++ b/libnymea-app/configuration/nymeaconfiguration.cpp @@ -49,6 +49,7 @@ NymeaConfiguration::NymeaConfiguration(JsonRpcClient *client, QObject *parent): m_tcpServerConfigurations(new ServerConfigurations(this)), m_webSocketServerConfigurations(new ServerConfigurations(this)), m_webServerConfigurations(new WebServerConfigurations(this)), + m_tunnelProxyServerConfigurations(new TunnelProxyServerConfigurations(this)), m_mqttServerConfigurations(new ServerConfigurations(this)), m_mqttPolicies(new MqttPolicies(this)) { @@ -123,6 +124,11 @@ WebServerConfigurations *NymeaConfiguration::webServerConfigurations() const return m_webServerConfigurations; } +TunnelProxyServerConfigurations *NymeaConfiguration::tunnelProxyServerConfigurations() const +{ + return m_tunnelProxyServerConfigurations; +} + ServerConfigurations *NymeaConfiguration::mqttServerConfigurations() const { return m_mqttServerConfigurations; @@ -135,12 +141,12 @@ MqttPolicies *NymeaConfiguration::mqttPolicies() const ServerConfiguration *NymeaConfiguration::createServerConfiguration(const QString &address, int port, bool authEnabled, bool sslEnabled) { - return new ServerConfiguration(QUuid::createUuid().toString(), QHostAddress(address), port, authEnabled, sslEnabled); + return new ServerConfiguration(QUuid::createUuid().toString(), address, port, authEnabled, sslEnabled); } WebServerConfiguration *NymeaConfiguration::createWebServerConfiguration(const QString &address, int port, bool authEnabled, bool sslEnabled, const QString &publicFolder) { - auto ret = new WebServerConfiguration(QUuid::createUuid().toString(), QHostAddress(address), port, authEnabled, sslEnabled); + auto ret = new WebServerConfiguration(QUuid::createUuid().toString(), address, port, authEnabled, sslEnabled); ret->setPublicFolder(publicFolder); return ret; } @@ -190,6 +196,20 @@ void NymeaConfiguration::setWebServerConfiguration(WebServerConfiguration *confi m_client->sendCommand("Configuration.SetWebServerConfiguration", params, this, "setWebConfigReply"); } +void NymeaConfiguration::setTunnelProxyServerConfiguration(TunnelProxyServerConfiguration *configuration) +{ + QVariantMap params; + QVariantMap configurationMap; + configurationMap.insert("id", configuration->id()); + configurationMap.insert("address", configuration->address()); + configurationMap.insert("port", configuration->port()); + configurationMap.insert("authenticationEnabled", configuration->authenticationEnabled()); + configurationMap.insert("sslEnabled", configuration->sslEnabled()); + configurationMap.insert("ignoreSslErrors", configuration->ignoreSslErrors()); + params.insert("configuration", configurationMap); + m_client->sendCommand("Configuration.SetTunnelProxyServerConfiguration", params, this, "setTunnelProxyServerConfigReply"); +} + void NymeaConfiguration::setMqttServerConfiguration(ServerConfiguration *configuration) { QVariantMap params; @@ -224,6 +244,13 @@ void NymeaConfiguration::deleteWebServerConfiguration(const QString &id) m_client->sendCommand("Configuration.DeleteWebServerConfiguration", params, this, "deleteWebConfigReply"); } +void NymeaConfiguration::deleteTunnelProxyServerConfiguration(const QString &id) +{ + QVariantMap params; + params.insert("id", id); + m_client->sendCommand("Configuration.DeleteTunnelProxyServerConfiguration", params, this, "deleteTunnelProxyServerConfigReply"); +} + void NymeaConfiguration::deleteMqttServerConfiguration(const QString &id) { QVariantMap params; @@ -268,23 +295,29 @@ void NymeaConfiguration::getConfigurationsResponse(int commandId, const QVariant foreach (const QVariant &tcpServerVariant, params.value("tcpServerConfigurations").toList()) { // qDebug() << "tcp server config:" << tcpServerVariant; QVariantMap tcpConfigMap = tcpServerVariant.toMap(); - ServerConfiguration *config = new ServerConfiguration(tcpConfigMap.value("id").toString(), QHostAddress(tcpConfigMap.value("address").toString()), tcpConfigMap.value("port").toInt(), tcpConfigMap.value("authenticationEnabled").toBool(), tcpConfigMap.value("sslEnabled").toBool()); + ServerConfiguration *config = new ServerConfiguration(tcpConfigMap.value("id").toString(), tcpConfigMap.value("address").toString(), tcpConfigMap.value("port").toInt(), tcpConfigMap.value("authenticationEnabled").toBool(), tcpConfigMap.value("sslEnabled").toBool()); m_tcpServerConfigurations->addConfiguration(config); } webSocketServerConfigurations()->clear(); foreach (const QVariant &websocketServerVariant, params.value("webSocketServerConfigurations").toList()) { QVariantMap websocketConfigMap = websocketServerVariant.toMap(); - ServerConfiguration *config = new ServerConfiguration(websocketConfigMap.value("id").toString(), QHostAddress(websocketConfigMap.value("address").toString()), websocketConfigMap.value("port").toInt(), websocketConfigMap.value("authenticationEnabled").toBool(), websocketConfigMap.value("sslEnabled").toBool()); + ServerConfiguration *config = new ServerConfiguration(websocketConfigMap.value("id").toString(), websocketConfigMap.value("address").toString(), websocketConfigMap.value("port").toInt(), websocketConfigMap.value("authenticationEnabled").toBool(), websocketConfigMap.value("sslEnabled").toBool()); m_webSocketServerConfigurations->addConfiguration(config); } webServerConfigurations()->clear(); foreach (const QVariant &webServerVariant, params.value("webServerConfigurations").toList()) { QVariantMap webServerConfigMap = webServerVariant.toMap(); - WebServerConfiguration* config = new WebServerConfiguration(webServerConfigMap.value("id").toString(), QHostAddress(webServerConfigMap.value("address").toString()), webServerConfigMap.value("port").toInt(), webServerConfigMap.value("authenticationEnabled").toBool(), webServerConfigMap.value("sslEnabled").toBool()); + WebServerConfiguration* config = new WebServerConfiguration(webServerConfigMap.value("id").toString(), webServerConfigMap.value("address").toString(), webServerConfigMap.value("port").toInt(), webServerConfigMap.value("authenticationEnabled").toBool(), webServerConfigMap.value("sslEnabled").toBool()); config->setPublicFolder(webServerConfigMap.value("publicFolder").toString()); m_webServerConfigurations->addConfiguration(config); } + + foreach (const QVariant &tunnelProxyServerVariant, params.value("tunnelProxyServerConfigurations").toList()) { + QVariantMap tunnelProxyServerConfigMap = tunnelProxyServerVariant.toMap(); + TunnelProxyServerConfiguration *config = new TunnelProxyServerConfiguration(tunnelProxyServerConfigMap.value("id").toString(), tunnelProxyServerConfigMap.value("address").toString(), tunnelProxyServerConfigMap.value("port").toInt(), tunnelProxyServerConfigMap.value("authenticationEnabled").toBool(), tunnelProxyServerConfigMap.value("sslEnabled").toBool(), tunnelProxyServerConfigMap.value("ignoreSslErrors").toBool()); + m_tunnelProxyServerConfigurations->addConfiguration(config); + } } void NymeaConfiguration::setServerNameResponse(int commandId, const QVariantMap ¶ms) @@ -342,13 +375,23 @@ void NymeaConfiguration::deleteWebSocketConfigReply(int commandId, const QVarian qDebug() << "Delete web socket server config reply" << commandId << params; } +void NymeaConfiguration::setTunnelProxyServerConfigReply(int commandId, const QVariantMap ¶ms) +{ + qDebug() << "Set tunnel proxy server config reply" << commandId << params; +} + +void NymeaConfiguration::deleteTunnelProxyServerConfigReply(int commandId, const QVariantMap ¶ms) +{ + qDebug() << "Delete tunnel proxy server config reply" << commandId << params; +} + void NymeaConfiguration::getMqttServerConfigsReply(int commandId, const QVariantMap ¶ms) { Q_UNUSED(commandId) m_mqttServerConfigurations->clear(); foreach (const QVariant &mqttServerVariant, params.value("mqttServerConfigurations").toList()) { QVariantMap mqttConfigMap = mqttServerVariant.toMap(); - ServerConfiguration *config = new ServerConfiguration(mqttConfigMap.value("id").toString(), QHostAddress(mqttConfigMap.value("address").toString()), mqttConfigMap.value("port").toInt(), mqttConfigMap.value("authenticationEnabled").toBool(), mqttConfigMap.value("sslEnabled").toBool()); + ServerConfiguration *config = new ServerConfiguration(mqttConfigMap.value("id").toString(), mqttConfigMap.value("address").toString(), mqttConfigMap.value("port").toInt(), mqttConfigMap.value("authenticationEnabled").toBool(), mqttConfigMap.value("sslEnabled").toBool()); m_mqttServerConfigurations->addConfiguration(config); } } diff --git a/libnymea-app/configuration/nymeaconfiguration.h b/libnymea-app/configuration/nymeaconfiguration.h index 9f752d03..9a6ca1c2 100644 --- a/libnymea-app/configuration/nymeaconfiguration.h +++ b/libnymea-app/configuration/nymeaconfiguration.h @@ -38,6 +38,8 @@ class ServerConfiguration; class ServerConfigurations; class WebServerConfiguration; class WebServerConfigurations; +class TunnelProxyServerConfiguration; +class TunnelProxyServerConfigurations; class MqttPolicy; class MqttPolicies; @@ -53,6 +55,7 @@ class NymeaConfiguration : public QObject Q_PROPERTY(ServerConfigurations* tcpServerConfigurations READ tcpServerConfigurations CONSTANT) Q_PROPERTY(ServerConfigurations* webSocketServerConfigurations READ webSocketServerConfigurations CONSTANT) Q_PROPERTY(WebServerConfigurations* webServerConfigurations READ webServerConfigurations CONSTANT) + Q_PROPERTY(TunnelProxyServerConfigurations* tunnelProxyServerConfigurations READ tunnelProxyServerConfigurations CONSTANT) Q_PROPERTY(ServerConfigurations* mqttServerConfigurations READ mqttServerConfigurations CONSTANT) Q_PROPERTY(MqttPolicies* mqttPolicies READ mqttPolicies CONSTANT) @@ -80,6 +83,7 @@ public: ServerConfigurations *tcpServerConfigurations() const; ServerConfigurations *webSocketServerConfigurations() const; WebServerConfigurations *webServerConfigurations() const; + TunnelProxyServerConfigurations *tunnelProxyServerConfigurations() const; ServerConfigurations *mqttServerConfigurations() const; MqttPolicies *mqttPolicies() const; @@ -90,11 +94,13 @@ public: Q_INVOKABLE void setTcpServerConfiguration(ServerConfiguration *configuration); Q_INVOKABLE void setWebSocketServerConfiguration(ServerConfiguration *configuration); Q_INVOKABLE void setWebServerConfiguration(WebServerConfiguration *configuration); + Q_INVOKABLE void setTunnelProxyServerConfiguration(TunnelProxyServerConfiguration *configuration); Q_INVOKABLE void setMqttServerConfiguration(ServerConfiguration *configuration); Q_INVOKABLE void deleteTcpServerConfiguration(const QString &id); Q_INVOKABLE void deleteWebSocketServerConfiguration(const QString &id); Q_INVOKABLE void deleteWebServerConfiguration(const QString &id); + Q_INVOKABLE void deleteTunnelProxyServerConfiguration(const QString &id); Q_INVOKABLE void deleteMqttServerConfiguration(const QString &id); Q_INVOKABLE void updateMqttPolicy(MqttPolicy* policy); @@ -112,6 +118,8 @@ private: Q_INVOKABLE void deleteTcpConfigReply(int commandId, const QVariantMap ¶ms); Q_INVOKABLE void setWebSocketConfigReply(int commandId, const QVariantMap ¶ms); Q_INVOKABLE void deleteWebSocketConfigReply(int commandId, const QVariantMap ¶ms); + Q_INVOKABLE void setTunnelProxyServerConfigReply(int commandId, const QVariantMap ¶ms); + Q_INVOKABLE void deleteTunnelProxyServerConfigReply(int commandId, const QVariantMap ¶ms); Q_INVOKABLE void setWebConfigReply(int commandId, const QVariantMap ¶ms); Q_INVOKABLE void deleteWebConfigReply(int commandId, const QVariantMap ¶ms); Q_INVOKABLE void getMqttServerConfigsReply(int commandId, const QVariantMap ¶ms); @@ -138,6 +146,7 @@ private: ServerConfigurations *m_tcpServerConfigurations = nullptr; ServerConfigurations *m_webSocketServerConfigurations = nullptr; WebServerConfigurations* m_webServerConfigurations = nullptr; + TunnelProxyServerConfigurations *m_tunnelProxyServerConfigurations = nullptr; ServerConfigurations *m_mqttServerConfigurations = nullptr; MqttPolicies *m_mqttPolicies = nullptr; diff --git a/libnymea-app/configuration/serverconfiguration.cpp b/libnymea-app/configuration/serverconfiguration.cpp index aac5e054..a12c2199 100644 --- a/libnymea-app/configuration/serverconfiguration.cpp +++ b/libnymea-app/configuration/serverconfiguration.cpp @@ -30,7 +30,7 @@ #include "serverconfiguration.h" -ServerConfiguration::ServerConfiguration(const QString &id, const QHostAddress &address, int port, bool authEnabled, bool sslEnabled, QObject *parent): +ServerConfiguration::ServerConfiguration(const QString &id, const QString &address, int port, bool authEnabled, bool sslEnabled, QObject *parent): QObject(parent), m_id(id), m_hostAddress(address), @@ -48,13 +48,13 @@ QString ServerConfiguration::id() const QString ServerConfiguration::address() const { - return m_hostAddress.toString(); + return m_hostAddress; } void ServerConfiguration::setAddress(const QString &address) { - if (m_hostAddress != QHostAddress(address)) { - m_hostAddress = QHostAddress(address); + if (m_hostAddress != address) { + m_hostAddress = address; emit addressChanged(); } } @@ -119,7 +119,26 @@ void WebServerConfiguration::setPublicFolder(const QString &publicFolder) ServerConfiguration *WebServerConfiguration::clone() const { - WebServerConfiguration *ret = new WebServerConfiguration(id(), QHostAddress(address()), port(), authenticationEnabled(), sslEnabled()); + WebServerConfiguration *ret = new WebServerConfiguration(id(), address(), port(), authenticationEnabled(), sslEnabled()); ret->setPublicFolder(m_publicFolder); return ret; } + +bool TunnelProxyServerConfiguration::ignoreSslErrors() const +{ + return m_ignoreSslErrors; +} + +void TunnelProxyServerConfiguration::setIgnoreSslErrors(bool ignoreSslErrors) +{ + if (m_ignoreSslErrors != ignoreSslErrors) { + m_ignoreSslErrors = ignoreSslErrors; + emit ignoreSslErrorsChanged(); + } +} + +ServerConfiguration *TunnelProxyServerConfiguration::clone() const +{ + TunnelProxyServerConfiguration *ret = new TunnelProxyServerConfiguration(id(), address(), port(), authenticationEnabled(), ignoreSslErrors()); + return ret; +} diff --git a/libnymea-app/configuration/serverconfiguration.h b/libnymea-app/configuration/serverconfiguration.h index e8c5a508..3ea194df 100644 --- a/libnymea-app/configuration/serverconfiguration.h +++ b/libnymea-app/configuration/serverconfiguration.h @@ -45,7 +45,7 @@ class ServerConfiguration : public QObject Q_PROPERTY(bool sslEnabled READ sslEnabled WRITE setSslEnabled NOTIFY sslEnabledChanged) public: - explicit ServerConfiguration(const QString &id, const QHostAddress &address = QHostAddress(), int port = 0, bool authEnabled = false, bool sslEnabled = false, QObject *parent = nullptr); + explicit ServerConfiguration(const QString &id, const QString &address = QString(), int port = 0, bool authEnabled = false, bool sslEnabled = false, QObject *parent = nullptr); QString id() const; @@ -71,7 +71,7 @@ signals: private: QString m_id; - QHostAddress m_hostAddress; + QString m_hostAddress; int m_port; bool m_authEnabled; bool m_sslEnabled; @@ -82,7 +82,7 @@ class WebServerConfiguration: public ServerConfiguration Q_OBJECT Q_PROPERTY(QString publicFolder READ publicFolder WRITE setPublicFolder NOTIFY publicFolderChanged) public: - explicit WebServerConfiguration(const QString &id, const QHostAddress &address = QHostAddress(), int port = 0, bool authEnabled = false, bool sslEnabled = false, QObject *parent = nullptr) + explicit WebServerConfiguration(const QString &id, const QString &address = QString(), int port = 0, bool authEnabled = false, bool sslEnabled = false, QObject *parent = nullptr) : ServerConfiguration(id, address, port, authEnabled, sslEnabled, parent) {} QString publicFolder() const; @@ -97,4 +97,25 @@ private: QString m_publicFolder; }; +class TunnelProxyServerConfiguration: public ServerConfiguration +{ + Q_OBJECT + Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors NOTIFY ignoreSslErrorsChanged) +public: + explicit TunnelProxyServerConfiguration(const QString &id, const QString &address = QString(), int port = 0, bool authenticationEnabled = false, bool sslEnabled = false, bool ignoreSslErrors = false, QObject *parent = nullptr) + : ServerConfiguration(id, address, port, authenticationEnabled, sslEnabled, parent), + m_ignoreSslErrors(ignoreSslErrors) {} + + bool ignoreSslErrors() const; + void setIgnoreSslErrors(bool ignoreSslErrors); + + Q_INVOKABLE ServerConfiguration* clone() const override; + +signals: + void ignoreSslErrorsChanged(); + +private: + bool m_ignoreSslErrors = false; +}; + #endif // SERVERCONFIGURATION_H diff --git a/libnymea-app/configuration/serverconfigurations.h b/libnymea-app/configuration/serverconfigurations.h index 634d27ea..90b3931e 100644 --- a/libnymea-app/configuration/serverconfigurations.h +++ b/libnymea-app/configuration/serverconfigurations.h @@ -84,4 +84,15 @@ public: } }; +class TunnelProxyServerConfigurations: public ServerConfigurations +{ + Q_OBJECT +public: + TunnelProxyServerConfigurations(QObject *parent = nullptr): ServerConfigurations(parent) {} + + Q_INVOKABLE TunnelProxyServerConfiguration* getTunnelProxyServerConfiguration(int index) const { + return dynamic_cast(m_list.at(index)); + } +}; + #endif // SERVERCONFIGURATIONS_H diff --git a/libnymea-app/libnymea-app-core.h b/libnymea-app/libnymea-app-core.h index 0c9afc61..7ca31376 100644 --- a/libnymea-app/libnymea-app-core.h +++ b/libnymea-app/libnymea-app-core.h @@ -256,6 +256,8 @@ void registerQmlTypes() { qmlRegisterUncreatableType(uri, 1, 0, "ServerConfigurations", "Get it from NymeaConfiguration"); qmlRegisterUncreatableType(uri, 1, 0, "WebServerConfiguration", "Get it from NymeaConfiguration"); qmlRegisterUncreatableType(uri, 1, 0, "WebServerConfigurations", "Get it from NymeaConfiguration"); + qmlRegisterUncreatableType(uri, 1, 0, "TunnelProxyServerConfiguration", "Get it from NymeaConfiguration"); + qmlRegisterUncreatableType(uri, 1, 0, "TunnelProxyServerConfigurations", "Get it from NymeaConfiguration"); qmlRegisterUncreatableType(uri, 1, 0, "MqttPolicy", "Get it from NymeaConfiguration"); qmlRegisterUncreatableType(uri, 1, 0, "MqttPolicies", "Get it from NymeaConfiguration"); diff --git a/nymea-app/ui/system/ConnectionInterfacesPage.qml b/nymea-app/ui/system/ConnectionInterfacesPage.qml index 90362107..6d7e8101 100644 --- a/nymea-app/ui/system/ConnectionInterfacesPage.qml +++ b/nymea-app/ui/system/ConnectionInterfacesPage.qml @@ -136,4 +136,53 @@ SettingsPageBase { popup.open() } } + SettingsPageSectionHeader { + text: qsTr("Remote connection server interfaces") + } + + Repeater { + model: engine.nymeaConfiguration.tunnelProxyServerConfigurations + delegate: ConnectionInterfaceDelegate { + Layout.fillWidth: true + text: qsTr("Server: %1").arg(model.address) + iconColor: inUse ? Style.accentColor : Style.iconColor + readonly property bool inUse: (engine.jsonRpcClient.currentConnection.hostAddress === model.address || model.address === "0.0.0.0") + && engine.jsonRpcClient.currentConnection.port === model.port + canDelete: !inUse + onClicked: { + var component = Qt.createComponent(Qt.resolvedUrl("ServerConfigurationDialog.qml")); + var popup = component.createObject(root, { serverConfiguration: engine.nymeaConfiguration.tunnelProxyServerConfigurations.get(index).clone() }); + popup.accepted.connect(function() { + print("configuring:", popup.serverConfiguration.port) + engine.nymeaConfiguration.setTunnelProxyServerConfiguration(popup.serverConfiguration) + popup.serverConfiguration.destroy(); + }) + popup.rejected.connect(function() { + popup.serverConfiguration.destroy(); + }) + popup.open() + } + onDeleteClicked: { + engine.nymeaConfiguration.deleteTunnelProxyServerConfiguration(model.id) + } + } + } + Button { + Layout.fillWidth: true + Layout.margins: app.margins + text: qsTr("Add") + onClicked: { + var config = engine.nymeaConfiguration.createTunnelProxyServerConfiguration("0.0.0.0", 4444 + engine.nymeaConfiguration.webSocketServerConfigurations.count, false, false); + var component = Qt.createComponent(Qt.resolvedUrl("ServerConfigurationDialog.qml")); + var popup = component.createObject(root, { serverConfiguration: config }); + popup.accepted.connect(function() { + engine.nymeaConfiguration.setWebSocketServerConfiguration(popup.serverConfiguration) + popup.serverConfiguration.destroy(); + }) + popup.rejected.connect(function() { + popup.serverConfiguration.destroy(); + }) + popup.open() + } + } } From 8f015aeee3ac0c0c69ada498df674cc9346ea06b Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 21 Jan 2022 16:17:00 +0100 Subject: [PATCH 7/8] Intermediate commit --- .../configuration/nymeaconfiguration.cpp | 28 +++++ .../configuration/nymeaconfiguration.h | 7 ++ .../connection/discovery/nymeadiscovery.cpp | 1 - libnymea-app/connection/nymeahost.cpp | 8 +- libnymea-app/connection/nymeahost.h | 8 +- .../connection/tunnelproxytransport.cpp | 14 ++- libnymea-app/jsonrpc/jsonrpcclient.cpp | 2 +- nymea-app/resources.qrc | 1 + nymea-app/ui/RootItem.qml | 33 ++++- .../ui/system/ConnectionInterfacesPage.qml | 8 +- .../TunnelProxyServerConfigurationDialog.qml | 114 ++++++++++++++++++ 11 files changed, 207 insertions(+), 17 deletions(-) create mode 100644 nymea-app/ui/system/TunnelProxyServerConfigurationDialog.qml diff --git a/libnymea-app/configuration/nymeaconfiguration.cpp b/libnymea-app/configuration/nymeaconfiguration.cpp index 0122c35e..52932091 100644 --- a/libnymea-app/configuration/nymeaconfiguration.cpp +++ b/libnymea-app/configuration/nymeaconfiguration.cpp @@ -56,11 +56,20 @@ NymeaConfiguration::NymeaConfiguration(JsonRpcClient *client, QObject *parent): client->registerNotificationHandler(this, "Configuration", "notificationReceived"); } +bool NymeaConfiguration::fetchingData() const +{ + return m_fetchingData; +} + void NymeaConfiguration::init() { + m_fetchingData = true; + emit fetchingDataChanged(); + m_tcpServerConfigurations->clear(); m_webSocketServerConfigurations->clear(); m_mqttServerConfigurations->clear(); + m_tunnelProxyServerConfigurations->clear(); m_client->sendCommand("Configuration.GetConfigurations", this, "getConfigurationsResponse"); m_client->sendCommand("Configuration.GetMqttServerConfigurations", this, "getMqttServerConfigsReply"); m_client->sendCommand("Configuration.GetMqttPolicies", this, "getMqttPoliciesReply"); @@ -151,6 +160,11 @@ WebServerConfiguration *NymeaConfiguration::createWebServerConfiguration(const Q return ret; } +TunnelProxyServerConfiguration *NymeaConfiguration::createTunnelProxyServerConfiguration(const QString &address, int port, bool authEnabled, bool sslEnabled, bool ignoreSslErrors) +{ + return new TunnelProxyServerConfiguration(QUuid::createUuid().toString(), address, port, authEnabled, sslEnabled, ignoreSslErrors); +} + MqttPolicy *NymeaConfiguration::createMqttPolicy() const { return new MqttPolicy(QString(), QString(), QString(), {"#"}, {"#"}); @@ -318,6 +332,9 @@ void NymeaConfiguration::getConfigurationsResponse(int commandId, const QVariant TunnelProxyServerConfiguration *config = new TunnelProxyServerConfiguration(tunnelProxyServerConfigMap.value("id").toString(), tunnelProxyServerConfigMap.value("address").toString(), tunnelProxyServerConfigMap.value("port").toInt(), tunnelProxyServerConfigMap.value("authenticationEnabled").toBool(), tunnelProxyServerConfigMap.value("sslEnabled").toBool(), tunnelProxyServerConfigMap.value("ignoreSslErrors").toBool()); m_tunnelProxyServerConfigurations->addConfiguration(config); } + + m_fetchingData = false; + emit fetchingDataChanged(); } void NymeaConfiguration::setServerNameResponse(int commandId, const QVariantMap ¶ms) @@ -436,6 +453,7 @@ void NymeaConfiguration::deleteMqttPolicyReply(int commandId, const QVariantMap void NymeaConfiguration::notificationReceived(const QVariantMap ¬ification) { QString notif = notification.value("notification").toString(); + qWarning() << "Config notification received" << notif; if (notif == "Configuration.BasicConfigurationChanged") { QVariantMap params = notification.value("params").toMap().value("basicConfiguration").toMap(); m_debugServerEnabled = params.value("debugServerEnabled").toBool(); @@ -465,6 +483,10 @@ void NymeaConfiguration::notificationReceived(const QVariantMap ¬ification) configModel = m_webSocketServerConfigurations; params = notification.value("params").toMap().value("webSocketServerConfiguration").toMap(); } + if (notif == "Configuration.TunnelProxyServerConfigurationChanged") { + configModel = m_tunnelProxyServerConfigurations; + params = notification.value("params").toMap().value("tunnelProxyServerConfiguration").toMap(); + } if (notif == "Configuration.WebServerConfigurationChanged") { configModel = m_webServerConfigurations; params = notification.value("params").toMap().value("webServerConfiguration").toMap(); @@ -487,6 +509,8 @@ void NymeaConfiguration::notificationReceived(const QVariantMap ¬ification) if (!serverConfig) { if (notif == "Configuration.WebServerConfigurationChanged") { serverConfig = new WebServerConfiguration(params.value("id").toString()); + } else if (notif == "Configuration.TunnelProxyServerConfigurationChanged") { + serverConfig = new TunnelProxyServerConfiguration(params.value("id").toString()); } else { serverConfig = new ServerConfiguration(params.value("id").toString()); } @@ -510,6 +534,10 @@ void NymeaConfiguration::notificationReceived(const QVariantMap ¬ification) m_webSocketServerConfigurations->removeConfiguration(notification.value("params").toMap().value("id").toString()); return; } + if (notif == "Configuration.TunnelProxyServerConfigurationRemoved") { + m_tunnelProxyServerConfigurations->removeConfiguration(notification.value("params").toMap().value("id").toString()); + return; + } if (notif == "Configuration.WebServerConfigurationRemoved") { m_webServerConfigurations->removeConfiguration(notification.value("params").toMap().value("id").toString()); return; diff --git a/libnymea-app/configuration/nymeaconfiguration.h b/libnymea-app/configuration/nymeaconfiguration.h index 9a6ca1c2..8fc01a85 100644 --- a/libnymea-app/configuration/nymeaconfiguration.h +++ b/libnymea-app/configuration/nymeaconfiguration.h @@ -47,6 +47,8 @@ class NymeaConfiguration : public QObject { Q_OBJECT + Q_PROPERTY(bool fetchingData READ fetchingData NOTIFY fetchingDataChanged) + Q_PROPERTY(QString serverName READ serverName WRITE setServerName NOTIFY serverNameChanged) Q_PROPERTY(bool cloudEnabled READ cloudEnabled WRITE setCloudEnabled NOTIFY cloudEnabledChanged) @@ -63,6 +65,8 @@ class NymeaConfiguration : public QObject public: explicit NymeaConfiguration(JsonRpcClient* client, QObject *parent = nullptr); + bool fetchingData() const; + QString serverName() const; void setServerName(const QString &serverName); @@ -89,6 +93,7 @@ public: Q_INVOKABLE ServerConfiguration* createServerConfiguration(const QString &address = "0.0.0.0", int port = 0, bool authEnabled = false, bool sslEnabled = false); Q_INVOKABLE WebServerConfiguration* createWebServerConfiguration(const QString &address = "0.0.0.0", int port = 0, bool authEnabled = false, bool sslEnabled = false, const QString &publicFolder = QString()); + Q_INVOKABLE TunnelProxyServerConfiguration* createTunnelProxyServerConfiguration(const QString &address, int port, bool authEnabled = true, bool sslEnabled = true, bool ignoreSslErrors = false); Q_INVOKABLE MqttPolicy* createMqttPolicy() const; Q_INVOKABLE void setTcpServerConfiguration(ServerConfiguration *configuration); @@ -132,6 +137,7 @@ private: Q_INVOKABLE void notificationReceived(const QVariantMap ¬ification); signals: + void fetchingDataChanged(); void debugServerEnabledChanged(); void serverNameChanged(); void cloudEnabledChanged(); @@ -139,6 +145,7 @@ signals: private: JsonRpcClient* m_client = nullptr; + bool m_fetchingData = false; bool m_debugServerEnabled = false; QString m_serverName; bool m_cloudEnabled = false; diff --git a/libnymea-app/connection/discovery/nymeadiscovery.cpp b/libnymea-app/connection/discovery/nymeadiscovery.cpp index 32e0740f..677631b1 100644 --- a/libnymea-app/connection/discovery/nymeadiscovery.cpp +++ b/libnymea-app/connection/discovery/nymeadiscovery.cpp @@ -152,7 +152,6 @@ void NymeaDiscovery::cacheHost(NymeaHost *host) QList connections; Connection *remoteConnection = host->connections()->bestMatch(Connection::BearerTypeCloud); if (remoteConnection) { - qCritical() << "*********** caching" << remoteConnection->url(); connections.append(remoteConnection); } Connection *loopbackConnection = host->connections()->bestMatch(Connection::BearerTypeLoopback); diff --git a/libnymea-app/connection/nymeahost.cpp b/libnymea-app/connection/nymeahost.cpp index 578b8c71..d0b90a8d 100644 --- a/libnymea-app/connection/nymeahost.cpp +++ b/libnymea-app/connection/nymeahost.cpp @@ -247,6 +247,12 @@ Connection *Connections::bestMatch(Connection::BearerTypes bearerTypes) const return best; } +void Connections::addConnection(const QUrl &url, Connection::BearerType bearerType, bool secure, const QString &displayName) +{ + Connection *connection = new Connection(url, bearerType, secure, displayName); + addConnection(connection); +} + QHash Connections::roleNames() const { QHash roles; @@ -265,7 +271,7 @@ Connection::Connection(const QUrl &url, Connection::BearerType bearerType, bool m_secure(secure), m_displayName(displayName) { - + qRegisterMetaType("Connection.BearerType"); } Connection::~Connection() diff --git a/libnymea-app/connection/nymeahost.h b/libnymea-app/connection/nymeahost.h index c02c7b71..b1f25d9e 100644 --- a/libnymea-app/connection/nymeahost.h +++ b/libnymea-app/connection/nymeahost.h @@ -109,14 +109,16 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; - void addConnection(Connection *connection); - void removeConnection(Connection *connection); - void removeConnection(int index); Q_INVOKABLE Connection* find(const QUrl &url) const; Q_INVOKABLE Connection* get(int index) const; Q_INVOKABLE Connection* bestMatch(Connection::BearerTypes bearerTypes = Connection::BearerTypeAll) const; + void addConnection(Connection *connection); + Q_INVOKABLE void addConnection(const QUrl &url, Connection::BearerType bearerType, bool secure, const QString &displayName); + Q_INVOKABLE void removeConnection(Connection *connection); + Q_INVOKABLE void removeConnection(int index); + signals: void countChanged(); void connectionAdded(Connection *connection); diff --git a/libnymea-app/connection/tunnelproxytransport.cpp b/libnymea-app/connection/tunnelproxytransport.cpp index dcf50abf..4bda46fe 100644 --- a/libnymea-app/connection/tunnelproxytransport.cpp +++ b/libnymea-app/connection/tunnelproxytransport.cpp @@ -31,6 +31,7 @@ #include "tunnelproxytransport.h" #include +#include using namespace remoteproxyclient; @@ -58,14 +59,15 @@ TunnelProxyTransport::TunnelProxyTransport(QObject *parent) : bool TunnelProxyTransport::connect(const QUrl &url) { - m_url = url; + QUrl serverUrl; + serverUrl.setScheme(url.scheme() == "tunnels" ? "ssl" : "tcp"); + serverUrl.setHost(url.host()); + serverUrl.setPort(url.port()); + QUuid serverUuid = QUrlQuery(url).queryItemValue("uuid"); - QUrl serverUrl = QUrl("ssl://dev-remoteproxy.nymea.io:2213"); - QUuid serverUuid = url.host(); - - qCritical() << "Calling connect"; + qCritical() << "Calling connect on" << serverUrl << serverUuid; return m_remoteConnection->connectServer(serverUrl, serverUuid); } @@ -145,5 +147,5 @@ NymeaTransportInterface *TunnelProxyTransportFactory::createTransport(QObject *p QStringList TunnelProxyTransportFactory::supportedSchemes() const { - return { "tunnel" }; + return { "tunnel", "tunnels" }; } diff --git a/libnymea-app/jsonrpc/jsonrpcclient.cpp b/libnymea-app/jsonrpc/jsonrpcclient.cpp index c7b69095..c9187391 100644 --- a/libnymea-app/jsonrpc/jsonrpcclient.cpp +++ b/libnymea-app/jsonrpc/jsonrpcclient.cpp @@ -645,7 +645,7 @@ void JsonRpcClient::dataReceived(const QByteArray &data) JsonRpcReply *reply = m_replies.take(commandId); if (reply) { reply->deleteLater(); - qWarning() << QString("JsonRpc: got response for %1.%2: %3").arg(reply->nameSpace(), reply->method(), QString::fromUtf8(jsonDoc.toJson(QJsonDocument::Indented))) << reply->callback() << reply->callback(); +// qWarning() << QString("JsonRpc: got response for %1.%2: %3").arg(reply->nameSpace(), reply->method(), QString::fromUtf8(jsonDoc.toJson(QJsonDocument::Indented))) << reply->callback() << reply->callback(); if (dataMap.value("status").toString() == "unauthorized") { qWarning() << "Something's off with the token"; diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc index 74f77410..9efd9221 100644 --- a/nymea-app/resources.qrc +++ b/nymea-app/resources.qrc @@ -274,5 +274,6 @@ ui/components/NymeaToolTip.qml ui/components/SettingsTile.qml ui/components/NymeaTextField.qml + ui/system/TunnelProxyServerConfigurationDialog.qml diff --git a/nymea-app/ui/RootItem.qml b/nymea-app/ui/RootItem.qml index ab9bfcca..315aa3ae 100644 --- a/nymea-app/ui/RootItem.qml +++ b/nymea-app/ui/RootItem.qml @@ -312,7 +312,6 @@ Item { onConnectedChanged: { print("json client connected changed", engine.jsonRpcClient.connected, engine.jsonRpcClient.serverUuid) if (engine.jsonRpcClient.connected) { - engine.jsonRpcClient.currentHost.addTunnelConnection(); nymeaDiscovery.cacheHost(engine.jsonRpcClient.currentHost) configuredHost.uuid = engine.jsonRpcClient.serverUuid // tabSettings.lastConnectedHost = engine.jsonRpcClient.serverUuid @@ -345,6 +344,38 @@ Item { } } + Connections { + target: engine.nymeaConfiguration + onFetchingDataChanged: { + if (!engine.nymeaConfiguration.fetchingData) { + syncRemoteConnection() + } + } + } + Connections { + target: engien.nymeaConfiguration.tunnelProxyServerConfigurations + onCountChanged: syncRemoteConnection(); + } + + function syncRemoteConnection() { + for (var i = 0; i < engine.jsonRpcClient.currentHost.connections.count; i++) { + var connection = engine.jsonRpcClient.currentHost.connections.get(i) + if (connection.url.toString().startsWith("tunnel")) { + engine.jsonRpcClient.currentHost.connections.removeConnection(i--); + } + } + + for (var i = 0; i < engine.nymeaConfiguration.tunnelProxyServerConfigurations.count; i++) { + var tunnelProxyConfig = engine.nymeaConfiguration.tunnelProxyServerConfigurations.get(i); + var url = tunnelProxyConfig.sslEnabled ? "tunnels://" : "tunnel://"; + url += tunnelProxyConfig.address + url += ":" + tunnelProxyConfig.port + url += "?uuid=" + engine.jsonRpcClient.currentHost.uuid + engine.jsonRpcClient.currentHost.connections.addConnection(url, Connection.BearerTypeCloud, tunnelProxyConfig.sslEnabled, "Remote proxy connection"); + } + nymeaDiscovery.cacheHost(engine.jsonRpcClient.currentHost) + } + Connections { target: Qt.application enabled: engine.jsonRpcClient.connected && settings.returnToHome diff --git a/nymea-app/ui/system/ConnectionInterfacesPage.qml b/nymea-app/ui/system/ConnectionInterfacesPage.qml index 6d7e8101..db3c2c3f 100644 --- a/nymea-app/ui/system/ConnectionInterfacesPage.qml +++ b/nymea-app/ui/system/ConnectionInterfacesPage.qml @@ -150,7 +150,7 @@ SettingsPageBase { && engine.jsonRpcClient.currentConnection.port === model.port canDelete: !inUse onClicked: { - var component = Qt.createComponent(Qt.resolvedUrl("ServerConfigurationDialog.qml")); + var component = Qt.createComponent(Qt.resolvedUrl("TunnelProxyServerConfigurationDialog.qml")); var popup = component.createObject(root, { serverConfiguration: engine.nymeaConfiguration.tunnelProxyServerConfigurations.get(index).clone() }); popup.accepted.connect(function() { print("configuring:", popup.serverConfiguration.port) @@ -172,11 +172,11 @@ SettingsPageBase { Layout.margins: app.margins text: qsTr("Add") onClicked: { - var config = engine.nymeaConfiguration.createTunnelProxyServerConfiguration("0.0.0.0", 4444 + engine.nymeaConfiguration.webSocketServerConfigurations.count, false, false); - var component = Qt.createComponent(Qt.resolvedUrl("ServerConfigurationDialog.qml")); + var config = engine.nymeaConfiguration.createTunnelProxyServerConfiguration("dev-remoteproxy.nymea.io", 2213, true, true, false); + var component = Qt.createComponent(Qt.resolvedUrl("TunnelProxyServerConfigurationDialog.qml")); var popup = component.createObject(root, { serverConfiguration: config }); popup.accepted.connect(function() { - engine.nymeaConfiguration.setWebSocketServerConfiguration(popup.serverConfiguration) + engine.nymeaConfiguration.setTunnelProxyServerConfiguration(popup.serverConfiguration) popup.serverConfiguration.destroy(); }) popup.rejected.connect(function() { diff --git a/nymea-app/ui/system/TunnelProxyServerConfigurationDialog.qml b/nymea-app/ui/system/TunnelProxyServerConfigurationDialog.qml new file mode 100644 index 00000000..2f0f053a --- /dev/null +++ b/nymea-app/ui/system/TunnelProxyServerConfigurationDialog.qml @@ -0,0 +1,114 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, GNU version 3. This project is distributed in the hope that it +* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +* Public License for more details. +* +* You should have received a copy of the GNU General Public License along with +* this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import QtQuick 2.9 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.1 +import QtQuick.Layouts 1.1 +import Nymea 1.0 + +Dialog { + id: root + title: qsTr("Proxy server configuration") + width: parent.width * .8 + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + + property ServerConfiguration serverConfiguration: null + standardButtons: Dialog.Ok | Dialog.Cancel + + ColumnLayout { + anchors { left: parent.left; top: parent.top; right: parent.right } + RowLayout { + Label { + text: qsTr("Proxy server address:") + Layout.fillWidth: true + } + TextField { + id: addressTextField + Layout.fillWidth: true + text: root.serverConfiguration ? root.serverConfiguration.address : "" + onEditingFinished: root.serverConfiguration.address = text + } + } + + RowLayout { + Label { + text: qsTr("Port:") + Layout.fillWidth: true + } + TextField { + inputMethodHints: Qt.ImhDigitsOnly + text: root.serverConfiguration ? root.serverConfiguration.port : 0 + validator: IntValidator { bottom: 0; top: 65535 } + onEditingFinished: root.serverConfiguration.port = text + } + } + + RowLayout { + Label { + Layout.fillWidth: true + text: qsTr("Require login") + } + CheckBox { + checkState: root.serverConfiguration && root.serverConfiguration.authenticationEnabled ? Qt.Checked : Qt.Unchecked + onClicked: root.serverConfiguration.authenticationEnabled = checked + } + } + Label { + Layout.fillWidth: true + wrapMode: Text.WordWrap + text: qsTr("Not requiring a login for the remote connection will allow anyone on the internet to connect to your %1 system.").arg(Configuration.systemName) + color: Style.red + visible: root.serverConfiguration && !root.serverConfiguration.authenticationEnabled + } + + RowLayout { + Label { + Layout.fillWidth: true + text: qsTr("SSL enabled") + } + CheckBox { + checkState: root.serverConfiguration && root.serverConfiguration.sslEnabled ? Qt.Checked : Qt.Unchecked + onClicked: root.serverConfiguration.sslEnabled = checked + } + } + RowLayout { + Label { + Layout.fillWidth: true + text: qsTr("Ignore SSL errors") + } + CheckBox { + checkState: root.serverConfiguration && root.serverConfiguration.ignoreSslErrors ? Qt.Checked : Qt.Unchecked + onClicked: root.serverConfiguration.ignoreSslErrors = checked + } + } + } +} From b7ccd5c923f67267bc3399b5f6d99bdb6572c602 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 21 Jan 2022 16:56:05 +0100 Subject: [PATCH 8/8] Add suppor for manual connections to remote proxy --- libnymea-app/jsonrpc/jsonrpcclient.cpp | 11 ++++--- libnymea-app/usermanager.cpp | 18 +++++++++++ libnymea-app/usermanager.h | 2 ++ nymea-app/configuredhostsmodel.cpp | 17 ---------- nymea-app/resources.qrc | 1 - nymea-app/ui/MainPage.qml | 1 - nymea-app/ui/RootItem.qml | 8 +---- .../ui/connection/NewConnectionWizard.qml | 31 ++++++++++++++++--- .../ui/system/ConnectionInterfacesPage.qml | 2 ++ nymea-app/ui/system/UsersSettingsPage.qml | 2 +- 10 files changed, 56 insertions(+), 37 deletions(-) diff --git a/libnymea-app/jsonrpc/jsonrpcclient.cpp b/libnymea-app/jsonrpc/jsonrpcclient.cpp index c9187391..0ba19841 100644 --- a/libnymea-app/jsonrpc/jsonrpcclient.cpp +++ b/libnymea-app/jsonrpc/jsonrpcclient.cpp @@ -445,6 +445,7 @@ void JsonRpcClient::processAuthenticate(int /*commandId*/, const QVariantMap &da } else { m_permissionScopes = UserInfo::PermissionScopeAdmin; } + emit permissionsChanged(); QSettings settings; settings.beginGroup("jsonTokens"); settings.setValue(m_serverUuid, m_token); @@ -720,6 +721,11 @@ void JsonRpcClient::helloReply(int /*commandId*/, const QVariantMap ¶ms) qCInfo(dcJsonRpc()) << "Handshake reply:" << "Protocol version:" << protoVersionString << "InitRequired:" << m_initialSetupRequired << "AuthRequired:" << m_authenticationRequired << "PushButtonAvailable:" << m_pushButtonAuthAvailable; + if (m_connection->currentHost()->uuid().isNull()) { + qCDebug(dcJsonRpc()) << "Updating Server UUID in connection:" << m_connection->currentHost()->uuid().toString() << "->" << m_serverUuid; + m_connection->currentHost()->setUuid(m_serverUuid); + } + QVersionNumber minimumRequiredVersion = QVersionNumber(5, 0); QVersionNumber maximumMajorVersion = QVersionNumber(6); if (m_jsonRpcVersion < minimumRequiredVersion) { @@ -795,11 +801,6 @@ void JsonRpcClient::helloReply(int /*commandId*/, const QVariantMap ¶ms) emit handshakeReceived(); - if (m_connection->currentHost()->uuid().isNull()) { - qCDebug(dcJsonRpc()) << "Updating Server UUID in connection:" << m_connection->currentHost()->uuid().toString() << "->" << m_serverUuid; - m_connection->currentHost()->setUuid(m_serverUuid); - } - if (m_initialSetupRequired) { qCInfo(dcJsonRpc()) << "Initial setup is required for this nymea instance!"; emit initialSetupRequiredChanged(); diff --git a/libnymea-app/usermanager.cpp b/libnymea-app/usermanager.cpp index 3689f660..15fa8390 100644 --- a/libnymea-app/usermanager.cpp +++ b/libnymea-app/usermanager.cpp @@ -279,6 +279,10 @@ QVariant Users::data(const QModelIndex &index, int role) const switch (role) { case RoleUsername: return m_users.at(index.row())->username(); + case RoleDisplayName: + return m_users.at(index.row())->displayName(); + case RoleEmail: + return m_users.at(index.row())->email(); case RoleScopes: return static_cast(m_users.at(index.row())->scopes()); } @@ -289,6 +293,8 @@ QHash Users::roleNames() const { QHash roles; roles.insert(RoleUsername, "username"); + roles.insert(RoleDisplayName, "displayName"); + roles.insert(RoleEmail, "email"); roles.insert(RoleScopes, "scopes"); return roles; } @@ -296,6 +302,18 @@ QHash Users::roleNames() const void Users::insertUser(UserInfo *userInfo) { userInfo->setParent(this); + connect(userInfo, &UserInfo::displayNameChanged, this, [=](){ + int idx = m_users.indexOf(userInfo); + if (idx >= 0) { + emit dataChanged(index(idx), index(idx), {RoleDisplayName}); + } + }); + connect(userInfo, &UserInfo::emailChanged, this, [=](){ + int idx = m_users.indexOf(userInfo); + if (idx >= 0) { + emit dataChanged(index(idx), index(idx), {RoleEmail}); + } + }); connect(userInfo, &UserInfo::scopesChanged, this, [=](){ int idx = m_users.indexOf(userInfo); if (idx >= 0) { diff --git a/libnymea-app/usermanager.h b/libnymea-app/usermanager.h index 3d380940..e84164ec 100644 --- a/libnymea-app/usermanager.h +++ b/libnymea-app/usermanager.h @@ -97,6 +97,8 @@ class Users: public QAbstractListModel { public: enum Roles { RoleUsername, + RoleDisplayName, + RoleEmail, RoleScopes }; Q_ENUM(Roles) diff --git a/nymea-app/configuredhostsmodel.cpp b/nymea-app/configuredhostsmodel.cpp index 0a97f0c4..04ed7ce6 100644 --- a/nymea-app/configuredhostsmodel.cpp +++ b/nymea-app/configuredhostsmodel.cpp @@ -21,23 +21,6 @@ ConfiguredHostsModel::ConfiguredHostsModel(QObject *parent) : QAbstractListModel m_currentIndex = settings.value("currentIndex", 0).toInt(); settings.endGroup(); - // If there aren't any in the config, try migrating settings from old tab model - if (m_list.isEmpty() && settings.contains("tabCount")) { - qCInfo(dcApplication()) << "Migrating tab settings to mainmenumodel"; - int tabCount = settings.value("tabCount", 0).toInt(); - qCDebug(dcApplication()) << "Tab count:" << tabCount; - - for (int i = 0; i < tabCount; i++) { - settings.beginGroup(QString("tabSettings%1").arg(i)); - QUuid uuid = settings.value("lastConnectedHost").toUuid(); - ConfiguredHost *host = new ConfiguredHost(uuid, this); - addHost(host); - settings.endGroup(); - } - - settings.remove("tabCount"); - } - // There must be always 1 at least if (m_list.isEmpty()) { createHost(); diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc index 9efd9221..9f6268d9 100644 --- a/nymea-app/resources.qrc +++ b/nymea-app/resources.qrc @@ -12,7 +12,6 @@ ui/mainviews/FavoritesView.qml ui/mainviews/ThingsView.qml ui/connection/ConnectPage.qml - ui/connection/ManualConnectPage.qml ui/connection/ConnectingPage.qml ui/connection/wifisetup/BluetoothDiscoveryPage.qml ui/connection/wifisetup/WirelessSetupPage.qml diff --git a/nymea-app/ui/MainPage.qml b/nymea-app/ui/MainPage.qml index 66b0bda8..33ed2d8c 100644 --- a/nymea-app/ui/MainPage.qml +++ b/nymea-app/ui/MainPage.qml @@ -721,7 +721,6 @@ Page { text: qsTr("Disconnect") Layout.preferredWidth: Math.max(cancelButton.implicitWidth, disconnectButton.implicitWidth) onClicked: { - tabSettings.lastConnectedHost = ""; engine.jsonRpcClient.disconnectFromHost(); } } diff --git a/nymea-app/ui/RootItem.qml b/nymea-app/ui/RootItem.qml index 315aa3ae..22aca65d 100644 --- a/nymea-app/ui/RootItem.qml +++ b/nymea-app/ui/RootItem.qml @@ -173,7 +173,6 @@ Item { print("opening push button auth") var page = pageStack.push(Qt.resolvedUrl("PushButtonAuthPage.qml")) page.backPressed.connect(function() { -// tabSettings.lastConnectedHost = ""; engine.jsonRpcClient.disconnectFromHost(); init(); }) @@ -182,7 +181,6 @@ Item { if (engine.jsonRpcClient.initialSetupRequired) { var page = pageStack.push(Qt.resolvedUrl("connection/SetupWizard.qml")); page.backPressed.connect(function() { -// tabSettings.lastConnectedHost = ""; engine.jsonRpcClient.disconnectFromHost() init(); }) @@ -191,7 +189,6 @@ Item { var page = pageStack.push(Qt.resolvedUrl("connection/LoginPage.qml")); page.backPressed.connect(function() { -// tabSettings.lastConnectedHost = ""; engine.jsonRpcClient.disconnectFromHost() init(); }) @@ -314,7 +311,6 @@ Item { if (engine.jsonRpcClient.connected) { nymeaDiscovery.cacheHost(engine.jsonRpcClient.currentHost) configuredHost.uuid = engine.jsonRpcClient.serverUuid -// tabSettings.lastConnectedHost = engine.jsonRpcClient.serverUuid } init(); } @@ -333,14 +329,12 @@ Item { popup.actualVersion = actualVersion; popup.minVersion = minVersion; popup.open() -// tabSettings.lastConnectedHost = "" } onInvalidMaximumVersion: { var popup = invalidVersionComponent.createObject(app.contentItem); popup.actualVersion = actualVersion; popup.maxVersion = maxVersion; popup.open() -// tabSettings.lastConnectedHost = "" } } @@ -353,7 +347,7 @@ Item { } } Connections { - target: engien.nymeaConfiguration.tunnelProxyServerConfigurations + target: engine.nymeaConfiguration.tunnelProxyServerConfigurations onCountChanged: syncRemoteConnection(); } diff --git a/nymea-app/ui/connection/NewConnectionWizard.qml b/nymea-app/ui/connection/NewConnectionWizard.qml index 5d1e430e..b09514f9 100644 --- a/nymea-app/ui/connection/NewConnectionWizard.qml +++ b/nymea-app/ui/connection/NewConnectionWizard.qml @@ -308,6 +308,12 @@ WizardPageBase { } else { rpcUrl = "ws://" + hostAddress + ":" + port } + } else if (connectionTypeComboBox.currentIndex == 2) { + if (secureCheckBox.checked) { + rpcUrl = "tunnels://" + hostAddress + ":" + port + "?uuid=" + serverUuidTextInput.text + } else { + rpcUrl = "tunnel://" + hostAddress + ":" + port + "?uuid=" + serverUuidTextInput.text + } } print("Try to connect ", rpcUrl) @@ -331,28 +337,43 @@ WizardPageBase { ComboBox { id: connectionTypeComboBox Layout.fillWidth: true - model: [ qsTr("TCP"), qsTr("Websocket") ] + model: [ qsTr("TCP"), qsTr("Websocket"), qsTr("Remote proxy") ] } - Label { text: qsTr("Address:") } + Label { + text: connectionTypeComboBox.currentIndex < 2 ? qsTr("Address:") : qsTr("Proxy address:") + } TextField { id: addressTextInput objectName: "addressTextInput" Layout.fillWidth: true - placeholderText: "127.0.0.1" + placeholderText: connectionTypeComboBox.currentIndex < 2 ? "127.0.0.1" : "dev-remoteproxy.nymea.io" } + Label { + text: qsTr("%1 UUID:").arg(Configuration.systemName) + visible: connectionTypeComboBox.currentIndex == 2 + } + TextField { + id: serverUuidTextInput + Layout.fillWidth: true + visible: connectionTypeComboBox.currentIndex == 2 + } Label { text: qsTr("Port:") } TextField { id: portTextInput Layout.fillWidth: true - placeholderText: connectionTypeComboBox.currentIndex === 0 ? "2222" : "4444" + placeholderText: connectionTypeComboBox.currentIndex === 0 + ? "2222" + : connectionTypeComboBox.currentIndex == 1 + ? "4444" + : "2213" validator: IntValidator{bottom: 1; top: 65535;} } Label { Layout.fillWidth: true - text: qsTr("Encrypted connection:") + text: qsTr("SSL:") } CheckBox { id: secureCheckBox diff --git a/nymea-app/ui/system/ConnectionInterfacesPage.qml b/nymea-app/ui/system/ConnectionInterfacesPage.qml index db3c2c3f..82f324d7 100644 --- a/nymea-app/ui/system/ConnectionInterfacesPage.qml +++ b/nymea-app/ui/system/ConnectionInterfacesPage.qml @@ -138,6 +138,7 @@ SettingsPageBase { } SettingsPageSectionHeader { text: qsTr("Remote connection server interfaces") + visible: engine.jsonRpcClient.ensureServerVersion("6.0") } Repeater { @@ -171,6 +172,7 @@ SettingsPageBase { Layout.fillWidth: true Layout.margins: app.margins text: qsTr("Add") + visible: engine.jsonRpcClient.ensureServerVersion("6.0") onClicked: { var config = engine.nymeaConfiguration.createTunnelProxyServerConfiguration("dev-remoteproxy.nymea.io", 2213, true, true, false); var component = Qt.createComponent(Qt.resolvedUrl("TunnelProxyServerConfigurationDialog.qml")); diff --git a/nymea-app/ui/system/UsersSettingsPage.qml b/nymea-app/ui/system/UsersSettingsPage.qml index 6ac5404c..674b4dc8 100644 --- a/nymea-app/ui/system/UsersSettingsPage.qml +++ b/nymea-app/ui/system/UsersSettingsPage.qml @@ -278,7 +278,7 @@ SettingsPageBase { model: userManager.users delegate: NymeaItemDelegate { Layout.fillWidth: true - text: engine.jsonRpcClient.ensureServerVersion("6.0") && model.displayName ? model.displayName : model.username + text: engine.jsonRpcClient.ensureServerVersion("6.0") && model.displayName !== "" ? model.displayName : model.username subText: engine.jsonRpcClient.ensureServerVersion("6.0") && model.displayName ? model.username : "" iconName: "/ui/images/account.svg" iconColor: userManager.userInfo.scopes & UserInfo.PermissionScopeAdmin ? Style.accentColor : Style.iconColor