From 3eb3b8ad8a1e788c227c0cf7c79ebfcab4990aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 1 Mar 2022 13:51:27 +0100 Subject: [PATCH] Fix tunnel proxy configuration and make it independent from the cloud configuration --- libnymea-core/nymeaconfiguration.cpp | 52 +++++++++++---------- libnymea-core/nymeaconfiguration.h | 16 +++++++ libnymea-core/servermanager.cpp | 45 ++++++++++-------- libnymea-core/servers/tunnelproxyserver.cpp | 25 +++++++--- libnymea-core/servers/tunnelproxyserver.h | 6 ++- 5 files changed, 93 insertions(+), 51 deletions(-) diff --git a/libnymea-core/nymeaconfiguration.cpp b/libnymea-core/nymeaconfiguration.cpp index a8148624..e3ac74f1 100644 --- a/libnymea-core/nymeaconfiguration.cpp +++ b/libnymea-core/nymeaconfiguration.cpp @@ -212,33 +212,14 @@ NymeaConfiguration::NymeaConfiguration(QObject *parent) : } // Tunnel Proxy Server - createDefaults = !settings.childGroups().contains("TunnelProxyServer"); if (settings.childGroups().contains("TunnelProxyServer")) { settings.beginGroup("TunnelProxyServer"); - if (settings.value("disabled").toBool()) { - qCDebug(dcConfiguration) << "Tunnel proxy server disabled by configuration."; - } else if (!settings.childGroups().isEmpty()) { - foreach (const QString &key, settings.childGroups()) { - TunnelProxyServerConfiguration config = readTunnelProxyServerConfig(key); - m_tunnelProxyServerConfigs[config.id] = config; - } - } else { - createDefaults = true; + foreach (const QString &key, settings.childGroups()) { + TunnelProxyServerConfiguration config = readTunnelProxyServerConfig(key); + m_tunnelProxyServerConfigs[config.id] = config; } settings.endGroup(); } - if (createDefaults) { - qCWarning(dcConfiguration) << "No Tunnel Proxy server configuration found. Generating default of remoteproxy.nymea.io:2213"; - TunnelProxyServerConfiguration config; - config.id = "default"; - config.address = "remoteproxy.nymea.io"; - config.port = 2213; - config.sslEnabled = true; - config.authenticationEnabled = true; - config.ignoreSslErrors = false; - m_tunnelProxyServerConfigs[config.id] = config; - storeTunnelProxyServerConfig(config); - } // Write defaults for log settings settings.beginGroup("Logs"); @@ -403,7 +384,7 @@ QHash NymeaConfiguration::tunnelProxySe void NymeaConfiguration::setTunnelProxyServerConfiguration(const TunnelProxyServerConfiguration &config) { m_tunnelProxyServerConfigs[config.id] = config; - storeServerConfig("TunnelProxyServer", config); + storeTunnelProxyServerConfig(config); emit tunnelProxyServerConfigurationChanged(config.id); } @@ -791,7 +772,30 @@ QDebug operator <<(QDebug debug, const ServerConfiguration &configuration) debug.nospace() << ", " << configuration.id; debug.nospace() << ", " << QString("%1:%2").arg(configuration.address).arg(configuration.port); debug.nospace() << ") "; - return debug; + return debug.maybeSpace(); +} + +QDebug operator <<(QDebug debug, const TunnelProxyServerConfiguration &configuration) +{ + debug.nospace() << "TunnelProxyServerConfiguration(" << configuration.id; + debug.nospace() << ", " << QString("%1:%2").arg(configuration.address).arg(configuration.port); + if (configuration.sslEnabled) { + debug.nospace() << ", SSL enabled"; + } else { + debug.nospace() << ", SSL disabled"; + } + if (configuration.authenticationEnabled) { + debug.nospace() << ", Authentication enabled"; + } else { + debug.nospace() << ", Authentication disabled"; + } + + if (configuration.ignoreSslErrors) { + debug.nospace() << ", Ignoring SSL errors"; + } + + debug.nospace() << ") "; + return debug.maybeSpace(); } } diff --git a/libnymea-core/nymeaconfiguration.h b/libnymea-core/nymeaconfiguration.h index 18fdc8f1..a828469a 100644 --- a/libnymea-core/nymeaconfiguration.h +++ b/libnymea-core/nymeaconfiguration.h @@ -46,6 +46,7 @@ class ServerConfiguration { Q_PROPERTY(uint port MEMBER port) Q_PROPERTY(bool sslEnabled MEMBER sslEnabled) Q_PROPERTY(bool authenticationEnabled MEMBER authenticationEnabled) + public: QString id; QString address; @@ -69,19 +70,34 @@ class WebServerConfiguration: public ServerConfiguration { Q_GADGET Q_PROPERTY(QString publicFolder MEMBER publicFolder) + public: QString publicFolder; bool restServerEnabled = false; + + bool operator==(const WebServerConfiguration &other) const { + return ServerConfiguration::operator==(other) + && publicFolder == other.publicFolder + && restServerEnabled == other.restServerEnabled; + } }; class TunnelProxyServerConfiguration: public ServerConfiguration { Q_GADGET Q_PROPERTY(bool ignoreSslErrors MEMBER ignoreSslErrors) + public: bool ignoreSslErrors = false; + + bool operator==(const TunnelProxyServerConfiguration &other) const { + return ServerConfiguration::operator==(other) + && ignoreSslErrors == other.ignoreSslErrors; + } }; +QDebug operator <<(QDebug debug, const TunnelProxyServerConfiguration &configuration); + class MqttPolicy { Q_GADGET diff --git a/libnymea-core/servermanager.cpp b/libnymea-core/servermanager.cpp index 84437975..ff2fe160 100644 --- a/libnymea-core/servermanager.cpp +++ b/libnymea-core/servermanager.cpp @@ -169,7 +169,7 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati foreach (const TunnelProxyServerConfiguration &config, configuration->tunnelProxyServerConfigurations()) { TunnelProxyServer *tunnelProxyServer = new TunnelProxyServer(configuration->serverName(), configuration->serverUuid(), config, this); - qCDebug(dcServerManager()) << "Creating tunnel proxy server" << config; + qCDebug(dcServerManager()) << "Creating tunnel proxy server using" << config; m_tunnelProxyServers.insert(config.id, tunnelProxyServer); connect(tunnelProxyServer, &TunnelProxyServer::runningChanged, this, [this, tunnelProxyServer](bool running){ if (running) { @@ -183,10 +183,7 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati // FIXME: make use of SSL over tunnel proxy connections // FIXME: make sure the authentication is enabled for the tunnel proxy - // Note: only start the tunnel proxy server if cloud is connected - if (configuration->cloudEnabled()) { - tunnelProxyServer->startServer(); - } + tunnelProxyServer->startServer(); } foreach (const WebServerConfiguration &config, configuration->webServerConfigurations()) { @@ -248,12 +245,12 @@ void ServerManager::tcpServerConfigurationChanged(const QString &id) ServerConfiguration config = NymeaCore::instance()->configuration()->tcpServerConfigurations().value(id); TcpServer *server = m_tcpServers.value(id); if (server) { - qDebug(dcServerManager()) << "Restarting TCP server for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); + qCDebug(dcServerManager()) << "Restarting TCP server for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); unregisterZeroConfService(config.id, "tcp"); server->stopServer(); server->setConfiguration(config); } else { - qDebug(dcServerManager()) << "Received a TCP Server config change event but don't have a TCP Server instance for it. Creating new Server instance."; + qCDebug(dcServerManager()) << "Received a TCP Server config change event but don't have a TCP Server instance for it. Creating new Server instance."; server = new TcpServer(config, m_sslConfiguration, this); m_tcpServers.insert(config.id, server); } @@ -266,7 +263,7 @@ void ServerManager::tcpServerConfigurationChanged(const QString &id) void ServerManager::tcpServerConfigurationRemoved(const QString &id) { if (!m_tcpServers.contains(id)) { - qWarning(dcServerManager()) << "Received a TCP Server config removed event but don't have a TCP Server instance for it."; + qCWarning(dcServerManager()) << "Received a TCP Server config removed event but don't have a TCP Server instance for it."; return; } TcpServer *server = m_tcpServers.take(id); @@ -281,12 +278,12 @@ void ServerManager::webSocketServerConfigurationChanged(const QString &id) WebSocketServer *server = m_webSocketServers.value(id); ServerConfiguration config = NymeaCore::instance()->configuration()->webSocketServerConfigurations().value(id); if (server) { - qDebug(dcServerManager()) << "Restarting WebSocket server for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); + qCDebug(dcServerManager()) << "Restarting WebSocket server for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); unregisterZeroConfService(id, "ws"); server->stopServer(); server->setConfiguration(config); } else { - qDebug(dcServerManager()) << "Received a WebSocket Server config change event but don't have a WebSocket Server instance for it. Creating new instance."; + qCDebug(dcServerManager()) << "Received a WebSocket Server config change event but don't have a WebSocket Server instance for it. Creating new instance."; server = new WebSocketServer(config, m_sslConfiguration, this); m_webSocketServers.insert(server->configuration().id, server); } @@ -299,7 +296,7 @@ void ServerManager::webSocketServerConfigurationChanged(const QString &id) void ServerManager::webSocketServerConfigurationRemoved(const QString &id) { if (!m_webSocketServers.contains(id)) { - qWarning(dcServerManager()) << "Received a WebSocket Server config removed event but don't have a WebSocket Server instance for it."; + qCWarning(dcServerManager()) << "Received a WebSocket Server config removed event but don't have a WebSocket Server instance for it."; return; } WebSocketServer *server = m_webSocketServers.take(id); @@ -314,12 +311,12 @@ void ServerManager::webServerConfigurationChanged(const QString &id) WebServerConfiguration config = NymeaCore::instance()->configuration()->webServerConfigurations().value(id); WebServer *server = m_webServers.value(id); if (server) { - qDebug(dcServerManager()) << "Restarting Web server for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); + qCDebug(dcServerManager()) << "Restarting Web server for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); unregisterZeroConfService(id, "http"); server->stopServer(); server->setConfiguration(config); } else { - qDebug(dcServerManager()) << "Received a Web Server config change event but don't have a Web Server instance for it. Creating new WebServer instance on" << config.address << config.port << "(SSL:" << config.sslEnabled << ")"; + qCDebug(dcServerManager()) << "Received a Web Server config change event but don't have a Web Server instance for it. Creating new WebServer instance on" << config.address << config.port << "(SSL:" << config.sslEnabled << ")"; server = new WebServer(config, m_sslConfiguration, this); m_webServers.insert(config.id, server); } @@ -331,7 +328,7 @@ void ServerManager::webServerConfigurationChanged(const QString &id) void ServerManager::webServerConfigurationRemoved(const QString &id) { if (!m_webServers.contains(id)) { - qWarning(dcServerManager()) << "Received a Web Server config removed event but don't have a Web Server instance for it."; + qCWarning(dcServerManager()) << "Received a Web Server config removed event but don't have a Web Server instance for it."; return; } WebServer *server = m_webServers.take(id); @@ -373,23 +370,31 @@ void ServerManager::tunnelProxyServerConfigurationChanged(const QString &id) TunnelProxyServer *server = m_tunnelProxyServers.value(id); TunnelProxyServerConfiguration config = NymeaCore::instance()->configuration()->tunnelProxyServerConfigurations().value(id); if (server) { - qDebug(dcServerManager()) << "Restarting tunnel proxy connection for" << config.address << config.port << "SSL" << (config.sslEnabled ? "enabled" : "disabled") << "Authentication" << (config.authenticationEnabled ? "enabled" : "disabled"); - unregisterZeroConfService(id, "ws"); + qCDebug(dcServerManager()) << "Restarting tunnel proxy connection using" << config; server->stopServer(); - server->setConfiguration(config); + server->setTunnelProxyConfig(config); } else { - qDebug(dcServerManager()) << "Received a tunnel proxy config change event but don't have a WebSocket Server instance for it. Creating new instance."; + qCDebug(dcServerManager()) << "Received a tunnel proxy config change event but don't have a tunnel proxy server instance for it."; + qCDebug(dcServerManager()) << "Creating tunnel proxy server using" << config; server = new TunnelProxyServer(m_nymeaConfiguration->serverName(), m_nymeaConfiguration->serverUuid(), config, this); m_tunnelProxyServers.insert(server->configuration().id, server); + connect(server, &TunnelProxyServer::runningChanged, this, [this, server](bool running){ + if (running) { + // Note: enable authentication in any case, we don't want to expose unprotected access trough the internet + m_jsonServer->registerTransportInterface(server, true); + } else { + m_jsonServer->unregisterTransportInterface(server); + } + }); } - m_jsonServer->registerTransportInterface(server, config.authenticationEnabled); + server->startServer(); } void ServerManager::tunnelProxyServerConfigurationRemoved(const QString &id) { if (!m_tunnelProxyServers.contains(id)) { - qWarning(dcServerManager()) << "Received a tunnel proxy config removed event but don't have a tunnel proxy connection for it."; + qCWarning(dcServerManager()) << "Received a tunnel proxy config removed event but don't have a tunnel proxy connection for it."; return; } TunnelProxyServer *server = m_tunnelProxyServers.take(id); diff --git a/libnymea-core/servers/tunnelproxyserver.cpp b/libnymea-core/servers/tunnelproxyserver.cpp index 8ba763d3..3c01ed69 100644 --- a/libnymea-core/servers/tunnelproxyserver.cpp +++ b/libnymea-core/servers/tunnelproxyserver.cpp @@ -37,7 +37,7 @@ namespace nymeaserver { TunnelProxyServer::TunnelProxyServer(const QString &serverName, const QUuid &serverUuid, const TunnelProxyServerConfiguration &configuration, QObject *parent) : TransportInterface(configuration, parent), - m_config(configuration), + m_tunnelProxyConfig(configuration), m_serverName(serverName), m_serverUuid(serverUuid) { @@ -47,9 +47,7 @@ TunnelProxyServer::TunnelProxyServer(const QString &serverName, const QUuid &ser qCWarning(dcTunnelProxyServer()) << "====================================================================================================================="; } - m_serverUrl.setScheme(configuration.sslEnabled ? "ssl" : "tcp"); - m_serverUrl.setHost(configuration.address); - m_serverUrl.setPort(configuration.port); + initConfiguration(); m_tunnelProxySocketServer = new TunnelProxySocketServer(m_serverUuid, m_serverName, this); connect(m_tunnelProxySocketServer, &TunnelProxySocketServer::stateChanged, this, &TunnelProxyServer::onStateChanged); @@ -99,8 +97,15 @@ void TunnelProxyServer::setServerName(const QString &serverName) m_serverName = serverName; } +void TunnelProxyServer::setTunnelProxyConfig(const TunnelProxyServerConfiguration &tunnelProxyConfig) +{ + m_tunnelProxyConfig = tunnelProxyConfig; +} + bool TunnelProxyServer::startServer() { + initConfiguration(); + qCDebug(dcTunnelProxyServer()) << "Connecting to tunnel proxy server at:" << m_serverUrl; m_tunnelProxySocketServer->startServer(m_serverUrl); return true; @@ -142,8 +147,7 @@ void TunnelProxyServer::onServerErrorOccurred(TunnelProxySocketServer::Error err void TunnelProxyServer::onSslErrors(const QList &errors) { qCDebug(dcTunnelProxyServer()) << "Remote proxy connection SSL errors occurred" << errors; - // FIXME: make this configurable - if (m_config.ignoreSslErrors) { + if (m_tunnelProxyConfig.ignoreSslErrors) { qCWarning(dcTunnelProxyServer()) << "Ingoring SSL errors on tunnel proxy connection:" << errors; m_tunnelProxySocketServer->ignoreSslErrors(); } else { @@ -172,4 +176,13 @@ void TunnelProxyServer::onClientDisconnected(TunnelProxySocket *tunnelProxySocke emit clientDisconnected(clientId); } +void TunnelProxyServer::initConfiguration() +{ + qCDebug(dcTunnelProxyServer()) << "Init configuration" << m_tunnelProxyConfig; + m_serverUrl.setScheme(m_tunnelProxyConfig.sslEnabled ? "ssl" : "tcp"); + m_serverUrl.setHost(m_tunnelProxyConfig.address); + m_serverUrl.setPort(m_tunnelProxyConfig.port); + qCDebug(dcTunnelProxyServer()) << "Using server URL" << m_serverUrl.toString(); +} + } diff --git a/libnymea-core/servers/tunnelproxyserver.h b/libnymea-core/servers/tunnelproxyserver.h index 38268bc5..4ef15bed 100644 --- a/libnymea-core/servers/tunnelproxyserver.h +++ b/libnymea-core/servers/tunnelproxyserver.h @@ -57,6 +57,8 @@ public: public slots: void setServerName(const QString &serverName) override; + void setTunnelProxyConfig(const TunnelProxyServerConfiguration &tunnelProxyConfig); + bool startServer() override; bool stopServer() override; @@ -74,7 +76,7 @@ private slots: void onClientDisconnected(TunnelProxySocket *tunnelProxySocket); private: - TunnelProxyServerConfiguration m_config; + TunnelProxyServerConfiguration m_tunnelProxyConfig; TunnelProxySocketServer *m_tunnelProxySocketServer = nullptr; QString m_serverName; QUuid m_serverUuid; @@ -82,6 +84,8 @@ private: QHash m_clients; + void initConfiguration(); + }; }