From a74f747df81162a16a7d568d51487e635ada303e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 13 Oct 2025 14:29:10 +0200 Subject: [PATCH 1/4] Update JsonRpc debug categories and fix some inlcudes --- libnymea-core/jsonrpc/configurationhandler.cpp | 1 + libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp | 8 ++++---- libnymea-core/jsonrpc/tagshandler.cpp | 6 +++--- tests/auto/mqttbroker/testmqttbroker.cpp | 1 + 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libnymea-core/jsonrpc/configurationhandler.cpp b/libnymea-core/jsonrpc/configurationhandler.cpp index 65053482..6de2111b 100644 --- a/libnymea-core/jsonrpc/configurationhandler.cpp +++ b/libnymea-core/jsonrpc/configurationhandler.cpp @@ -71,6 +71,7 @@ #include "configurationhandler.h" #include "nymeacore.h" #include "nymeaconfiguration.h" +#include "loggingcategories.h" #include "platform/platform.h" #include "platform/platformsystemcontroller.h" diff --git a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp index 2722516e..7eb8788b 100644 --- a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp @@ -576,7 +576,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if(error.error != QJsonParseError::NoError) { - qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString(); + qCWarning(dcJsonRpc()) << "Failed to parse JSON data" << data << ":" << error.errorString(); sendErrorResponse(interface, clientId, -1, QString("Failed to parse JSON data: %1").arg(error.errorString())); return; } @@ -586,7 +586,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac bool success; int commandId = message.value("id").toInt(&success); if (!success) { - qCWarning(dcJsonRpc) << "Error parsing command. Missing \"id\":" << message; + qCWarning(dcJsonRpc()) << "Error parsing command. Missing \"id\":" << message; sendErrorResponse(interface, clientId, commandId, "Error parsing command. Missing 'id'"); return; } @@ -594,7 +594,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac QString methodString = message.value("method").toString(); QStringList commandList = methodString.split('.'); if (commandList.count() != 2) { - qCWarning(dcJsonRpc) << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\""; + qCWarning(dcJsonRpc()) << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\""; sendErrorResponse(interface, clientId, commandId, QString("Error parsing method. Got: '%1'', Expected: 'Namespace.method'").arg(message.value("method").toString())); return; } @@ -607,7 +607,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac token = message.value("token").toByteArray(); } else if (message.value("token").toByteArray() != token) { qCWarning(dcJsonRpc()) << "Client changed token without redoing the handshake."; - qCDebug(dcJsonRpc) << "Old token:" << token << "new token:" << message.value("token").toByteArray(); + qCDebug(dcJsonRpc()) << "Old token:" << token << "new token:" << message.value("token").toByteArray(); sendUnauthorizedResponse(interface, clientId, commandId, "Changing the user (token) requires a new handshake. Call JSONRPC.Hello."); interface->terminateClientConnection(clientId); qCWarning(dcJsonRpc()) << "Staring connection lockdown timer"; diff --git a/libnymea-core/jsonrpc/tagshandler.cpp b/libnymea-core/jsonrpc/tagshandler.cpp index f1845d90..45a4cefb 100644 --- a/libnymea-core/jsonrpc/tagshandler.cpp +++ b/libnymea-core/jsonrpc/tagshandler.cpp @@ -142,7 +142,7 @@ JsonReply *TagsHandler::RemoveTag(const QVariantMap ¶ms) const void TagsHandler::onTagAdded(const Tag &tag) { - qCDebug(dcJsonRpc) << "Notify \"Tags.TagAdded\""; + qCDebug(dcJsonRpc()) << "Notify \"Tags.TagAdded\""; QVariantMap params; params.insert("tag", pack(tag)); emit TagAdded(params); @@ -150,7 +150,7 @@ void TagsHandler::onTagAdded(const Tag &tag) void TagsHandler::onTagRemoved(const Tag &tag) { - qCDebug(dcJsonRpc) << "Notify \"Tags.TagRemoved\""; + qCDebug(dcJsonRpc()) << "Notify \"Tags.TagRemoved\""; QVariantMap params; params.insert("tag", pack(tag)); emit TagRemoved(params); @@ -158,7 +158,7 @@ void TagsHandler::onTagRemoved(const Tag &tag) void TagsHandler::onTagValueChanged(const Tag &tag) { - qCDebug(dcJsonRpc) << "Notify \"Tags.TagValueChanged\""; + qCDebug(dcJsonRpc()) << "Notify \"Tags.TagValueChanged\""; QVariantMap params; params.insert("tag", pack(tag)); emit TagValueChanged(params); diff --git a/tests/auto/mqttbroker/testmqttbroker.cpp b/tests/auto/mqttbroker/testmqttbroker.cpp index 84a6965a..2dc2aa31 100644 --- a/tests/auto/mqttbroker/testmqttbroker.cpp +++ b/tests/auto/mqttbroker/testmqttbroker.cpp @@ -32,6 +32,7 @@ #include "nymeacore.h" #include "servers/mqttbroker.h" #include "servers/mocktcpserver.h" +#include "loggingcategories.h" #include From e8244e931328ab8451d60622f60e6abc0469fcd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 13 Oct 2025 13:16:16 +0200 Subject: [PATCH 2/4] Disable insecure interfaces if configured using env --- .../jsonrpc/configurationhandler.cpp | 49 ++++++++++++++----- libnymea-core/jsonrpc/tagshandler.cpp | 1 + libnymea-core/nymeaconfiguration.cpp | 4 ++ libnymea-core/nymeaconfiguration.h | 3 +- libnymea-core/servermanager.cpp | 35 +++++++++++-- libnymea-core/servermanager.h | 3 +- 6 files changed, 78 insertions(+), 17 deletions(-) diff --git a/libnymea-core/jsonrpc/configurationhandler.cpp b/libnymea-core/jsonrpc/configurationhandler.cpp index 6de2111b..2647bc5b 100644 --- a/libnymea-core/jsonrpc/configurationhandler.cpp +++ b/libnymea-core/jsonrpc/configurationhandler.cpp @@ -449,9 +449,9 @@ JsonReply *ConfigurationHandler::SetLocation(const QVariantMap ¶ms) const JsonReply *ConfigurationHandler::SetTcpServerConfiguration(const QVariantMap ¶ms) const { ServerConfiguration config = unpack(params.value("configuration").toMap()); - if (config.id.isEmpty()) { + if (config.id.isEmpty()) return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId)); - } + if (config.address.isNull()) return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress)); @@ -460,8 +460,17 @@ JsonReply *ConfigurationHandler::SetTcpServerConfiguration(const QVariantMap &pa return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort)); } - qCDebug(dcJsonRpc()) << QString("Configure TCP server %1:%2").arg(config.address).arg(config.port); + // To be compliant with the EN18031 we have to make sure the user cannot configure an insecure interface to the server. + if (qEnvironmentVariable("NYMEA_INSECURE_INTERFACES_DISABLED", "0") != "0") { + bool isLocalhost = config.address == "localhost" || config.address == "127.0.0.1"; + bool isSecured = config.sslEnabled && config.authenticationEnabled; + if (!isLocalhost && !isSecured) { + qCWarning(dcJsonRpc()) << "Cannot add insecure TCP server configuration" << config << "because insecure interfaces to the core are explicit disabled."; + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorUnsupported)); + } + } + qCDebug(dcJsonRpc()) << QString("Configure TCP server %1:%2").arg(config.address).arg(config.port); NymeaCore::instance()->configuration()->setTcpServerConfiguration(config); return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorNoError)); } @@ -510,9 +519,9 @@ JsonReply *ConfigurationHandler::DeleteWebServerConfiguration(const QVariantMap JsonReply *ConfigurationHandler::SetWebSocketServerConfiguration(const QVariantMap ¶ms) const { ServerConfiguration config = unpack(params.value("configuration").toMap()); - if (config.id.isEmpty()) { + if (config.id.isEmpty()) return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId)); - } + if (config.address.isNull()) return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress)); @@ -521,6 +530,16 @@ JsonReply *ConfigurationHandler::SetWebSocketServerConfiguration(const QVariantM return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort)); } + // To be compliant with the EN18031 we have to make sure the user cannot configure an insecure interface to the server. + if (qEnvironmentVariable("NYMEA_INSECURE_INTERFACES_DISABLED", "0") != "0") { + bool isLocalhost = config.address == "localhost" || config.address == "127.0.0.1"; + bool isSecured = config.sslEnabled && config.authenticationEnabled; + if (!isLocalhost && !isSecured) { + qCWarning(dcJsonRpc()) << "Cannot add insecure WebSocket server configuration" << config << "because insecure interfaces to the core are explicit disabled."; + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorUnsupported)); + } + } + qCDebug(dcJsonRpc()) << QString("Configuring web socket server %1:%2").arg(config.address).arg(config.port); NymeaCore::instance()->configuration()->setWebSocketServerConfiguration(config); @@ -541,9 +560,9 @@ JsonReply *ConfigurationHandler::DeleteWebSocketServerConfiguration(const QVaria JsonReply *ConfigurationHandler::SetTunnelProxyServerConfiguration(const QVariantMap ¶ms) const { TunnelProxyServerConfiguration config = unpack(params.value("configuration").toMap()); - if (config.id.isEmpty()) { + if (config.id.isEmpty()) return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId)); - } + if (config.address.isNull()) return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress)); @@ -552,6 +571,14 @@ JsonReply *ConfigurationHandler::SetTunnelProxyServerConfiguration(const QVarian return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort)); } + // To be compliant with the EN18031 we have to make sure the user cannot configure an insecure interface to the server. + if (qEnvironmentVariable("NYMEA_INSECURE_INTERFACES_DISABLED", "0") != "0") { + if (!config.sslEnabled || !config.authenticationEnabled || config.ignoreSslErrors) { + qCWarning(dcJsonRpc()) << "Cannot add insecure tunnelproxy server configuration" << config << "because insecure interfaces to the core are explicit disabled."; + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorUnsupported)); + } + } + qCDebug(dcJsonRpc()) << QString("Configuring tunnel proxy server %1:%2").arg(config.address).arg(config.port); NymeaCore::instance()->configuration()->setTunnelProxyServerConfiguration(config); @@ -758,10 +785,10 @@ QVariantMap ConfigurationHandler::packBasicConfiguration() basicConfiguration.insert("timeZone", QTimeZone::systemTimeZoneId()); basicConfiguration.insert("language", NymeaCore::instance()->configuration()->locale().name()); basicConfiguration.insert("location", QVariantMap{ - {"latitude", NymeaCore::instance()->configuration()->locationLatitude()}, - {"longitude", NymeaCore::instance()->configuration()->locationLongitude()}, - {"name", NymeaCore::instance()->configuration()->locationName()} - }); + {"latitude", NymeaCore::instance()->configuration()->locationLatitude()}, + {"longitude", NymeaCore::instance()->configuration()->locationLongitude()}, + {"name", NymeaCore::instance()->configuration()->locationName()} + }); basicConfiguration.insert("debugServerEnabled", NymeaCore::instance()->configuration()->debugServerEnabled()); return basicConfiguration; } diff --git a/libnymea-core/jsonrpc/tagshandler.cpp b/libnymea-core/jsonrpc/tagshandler.cpp index 45a4cefb..5ad123af 100644 --- a/libnymea-core/jsonrpc/tagshandler.cpp +++ b/libnymea-core/jsonrpc/tagshandler.cpp @@ -30,6 +30,7 @@ #include "tagshandler.h" +#include "loggingcategories.h" #include "nymeacore.h" #include "tagging/tagsstorage.h" diff --git a/libnymea-core/nymeaconfiguration.cpp b/libnymea-core/nymeaconfiguration.cpp index b1ebaac3..dbe5a80b 100644 --- a/libnymea-core/nymeaconfiguration.cpp +++ b/libnymea-core/nymeaconfiguration.cpp @@ -325,8 +325,12 @@ QLocale NymeaConfiguration::locale() const void NymeaConfiguration::setLocale(const QLocale &locale) { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) qCDebug(dcConfiguration()) << "Configuration: Set system locale:" << locale.name() << locale.nativeCountryName() << locale.nativeLanguageName(); +#else + qCDebug(dcConfiguration()) << "Configuration: Set system locale:" << locale.name() << locale.nativeTerritoryName() << locale.nativeLanguageName(); +#endif NymeaSettings settings(NymeaSettings::SettingsRoleGlobal); settings.beginGroup("nymead"); if (settings.value("language").toString() == locale.name()) { diff --git a/libnymea-core/nymeaconfiguration.h b/libnymea-core/nymeaconfiguration.h index 982252a5..e3953cfb 100644 --- a/libnymea-core/nymeaconfiguration.h +++ b/libnymea-core/nymeaconfiguration.h @@ -129,7 +129,8 @@ public: ConfigurationErrorInvalidPort, ConfigurationErrorInvalidHostAddress, ConfigurationErrorBluetoothHardwareNotAvailable, - ConfigurationErrorInvalidCertificate + ConfigurationErrorInvalidCertificate, + ConfigurationErrorUnsupported }; Q_ENUM(ConfigurationError) diff --git a/libnymea-core/servermanager.cpp b/libnymea-core/servermanager.cpp index 7eae098d..63ee3ede 100644 --- a/libnymea-core/servermanager.cpp +++ b/libnymea-core/servermanager.cpp @@ -49,6 +49,7 @@ #include "platform/platform.h" #include "platform/platformzeroconfcontroller.h" #include "version.h" +#include "loggingcategories.h" #include "jsonrpc/jsonrpcserverimplementation.h" #include "servers/mocktcpserver.h" @@ -73,6 +74,12 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati m_nymeaConfiguration(configuration), m_sslConfiguration(QSslConfiguration()) { + // To be compliant with the EN18031 we have to make sure the user cannot configure an insecure interface to the server. + if (qEnvironmentVariable("NYMEA_INSECURE_INTERFACES_DISABLED", "0") != "0") { + qCInfo(dcServerManager()) << "Insecure interfaces to the core are explicit disabled. Not starting any unauthenticated or unencrypted interfaces."; + m_disableInsecureInterfaces = true; + } + if (!QSslSocket::supportsSsl()) { qCWarning(dcServerManager()) << "SSL is not supported/installed on this platform."; } else { @@ -102,8 +109,7 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati } } if (certsLoaded) { - // Update this to 1.3 when minimum required Qt is 5.12 (and known client apps can deal with it) - m_sslConfiguration.setProtocol(QSsl::TlsV1_2OrLater); + m_sslConfiguration.setProtocol(QSsl::TlsV1_3OrLater); m_sslConfiguration.setPrivateKey(m_certificateKey); m_sslConfiguration.setLocalCertificate(m_certificate); } @@ -149,6 +155,11 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati } foreach (const ServerConfiguration &config, configuration->tcpServerConfigurations()) { + if (m_disableInsecureInterfaces && (!config.sslEnabled || !config.authenticationEnabled)) { + qCWarning(dcServerManager()) << "Loaded insecure TCP server configuration" << config << "but insecure interfaces to the core are explicit disabled. This interface will not be started."; + continue; + } + TcpServer *tcpServer = new TcpServer(config, m_sslConfiguration, this); m_jsonServer->registerTransportInterface(tcpServer); m_tcpServers.insert(config.id, tcpServer); @@ -158,6 +169,11 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati } foreach (const ServerConfiguration &config, configuration->webSocketServerConfigurations()) { + if (m_disableInsecureInterfaces && (!config.sslEnabled || !config.authenticationEnabled)) { + qCWarning(dcServerManager()) << "Loaded insecure WebSocket server configuration" << config << "but insecure interfaces to the core are explicit disabled. This interface will not be started."; + continue; + } + WebSocketServer *webSocketServer = new WebSocketServer(config, m_sslConfiguration, this); m_jsonServer->registerTransportInterface(webSocketServer); m_webSocketServers.insert(config.id, webSocketServer); @@ -170,10 +186,19 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati m_bluetoothServer = new BluetoothServer(this); m_jsonServer->registerTransportInterface(m_bluetoothServer); if (configuration->bluetoothServerEnabled()) { - m_bluetoothServer->startServer(); + if (m_disableInsecureInterfaces) { + qCWarning(dcServerManager()) << "The bluetooth RFCOM server is enabled, but insecure server interfaces have been disabled explicitly. Not starting the bluetooth server."; + } else { + m_bluetoothServer->startServer(); + } } foreach (const TunnelProxyServerConfiguration &config, configuration->tunnelProxyServerConfigurations()) { + if (m_disableInsecureInterfaces && (!config.sslEnabled || !config.authenticationEnabled || config.ignoreSslErrors)) { + qCWarning(dcServerManager()) << "Loaded insecure tunnelproxy server configuration" << config << "but insecure interfaces to the core are explicit disabled. This interface will not be started."; + continue; + } + TunnelProxyServer *tunnelProxyServer = new TunnelProxyServer(configuration->serverName(), configuration->serverUuid(), config, this); qCDebug(dcServerManager()) << "Creating tunnel proxy server using" << config; m_tunnelProxyServers.insert(config.id, tunnelProxyServer); @@ -209,14 +234,18 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati connect(configuration, &NymeaConfiguration::tcpServerConfigurationChanged, this, &ServerManager::tcpServerConfigurationChanged); connect(configuration, &NymeaConfiguration::tcpServerConfigurationRemoved, this, &ServerManager::tcpServerConfigurationRemoved); + connect(configuration, &NymeaConfiguration::webSocketServerConfigurationChanged, this, &ServerManager::webSocketServerConfigurationChanged); connect(configuration, &NymeaConfiguration::webSocketServerConfigurationRemoved, this, &ServerManager::webSocketServerConfigurationRemoved); + connect(configuration, &NymeaConfiguration::webServerConfigurationChanged, this, &ServerManager::webServerConfigurationChanged); connect(configuration, &NymeaConfiguration::webServerConfigurationRemoved, this, &ServerManager::webServerConfigurationRemoved); + connect(configuration, &NymeaConfiguration::mqttServerConfigurationChanged, this, &ServerManager::mqttServerConfigurationChanged); connect(configuration, &NymeaConfiguration::mqttServerConfigurationRemoved, this, &ServerManager::mqttServerConfigurationRemoved); connect(configuration, &NymeaConfiguration::mqttPolicyChanged, this, &ServerManager::mqttPolicyChanged); connect(configuration, &NymeaConfiguration::mqttPolicyRemoved, this, &ServerManager::mqttPolicyRemoved); + connect(configuration, &NymeaConfiguration::tunnelProxyServerConfigurationChanged, this, &ServerManager::tunnelProxyServerConfigurationChanged); connect(configuration, &NymeaConfiguration::tunnelProxyServerConfigurationRemoved, this, &ServerManager::tunnelProxyServerConfigurationRemoved); } diff --git a/libnymea-core/servermanager.h b/libnymea-core/servermanager.h index 3c3f937c..749a930a 100644 --- a/libnymea-core/servermanager.h +++ b/libnymea-core/servermanager.h @@ -33,7 +33,6 @@ #include -#include "loggingcategories.h" #include "nymeaconfiguration.h" #include @@ -72,7 +71,6 @@ public: public slots: void setServerName(const QString &serverName); - private slots: void tcpServerConfigurationChanged(const QString &id); void tcpServerConfigurationRemoved(const QString &id); @@ -95,6 +93,7 @@ private: private: Platform *m_platform = nullptr; + bool m_disableInsecureInterfaces = false; NymeaConfiguration *m_nymeaConfiguration = nullptr; // Interfaces From 74ae874ae9e178bc18309eca9eb30feb5f1c37bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 13 Oct 2025 16:31:16 +0200 Subject: [PATCH 3/4] Add tests for NYMEA_INSECURE_INTERFACES_DISABLED env --- .../configurations/testconfigurations.cpp | 90 ++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/tests/auto/configurations/testconfigurations.cpp b/tests/auto/configurations/testconfigurations.cpp index 588f0518..07f409a8 100644 --- a/tests/auto/configurations/testconfigurations.cpp +++ b/tests/auto/configurations/testconfigurations.cpp @@ -56,6 +56,8 @@ private slots: void testDebugServerConfiguration(); + void testDisableInsecureInterfacesEnv(); + private: QVariantMap loadBasicConfiguration(); @@ -295,7 +297,7 @@ void TestConfigurations::testDebugServerConfiguration() // Webserver request QNetworkAccessManager nam; - connect(&nam, &QNetworkAccessManager::sslErrors, [](QNetworkReply* reply, const QList &) { + connect(&nam, &QNetworkAccessManager::sslErrors, this, [](QNetworkReply* reply, const QList &) { reply->ignoreSslErrors(); }); QSignalSpy namSpy(&nam, &QNetworkAccessManager::finished); @@ -329,7 +331,7 @@ void TestConfigurations::testDebugServerConfiguration() ok = false; statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(&ok); - QVERIFY2(ok, "Could not convert statuscode from response to int"); + QVERIFY2(ok, "Could not convert status code from response to int"); QCOMPARE(statusCode, 404); reply->deleteLater(); @@ -338,6 +340,90 @@ void TestConfigurations::testDebugServerConfiguration() disableNotifications(); } +void TestConfigurations::testDisableInsecureInterfacesEnv() +{ + QString id = "insecure"; + + // Create a insecure interface + QVariantMap insecureTcpConfig; + insecureTcpConfig.insert("id", id); + insecureTcpConfig.insert("address", "0.0.0.0"); + insecureTcpConfig.insert("port", 23456); + insecureTcpConfig.insert("sslEnabled", false); + insecureTcpConfig.insert("authenticationEnabled", false); + + // Create a insecure interface + QVariantMap insecureWebSocketConfig; + insecureWebSocketConfig.insert("id", id); + insecureWebSocketConfig.insert("address", "0.0.0.0"); + insecureWebSocketConfig.insert("port", 23457); + insecureWebSocketConfig.insert("sslEnabled", false); + insecureWebSocketConfig.insert("authenticationEnabled", false); + + // Create a insecure interface + QVariantMap insecureTunnelProxyConfig; + insecureTunnelProxyConfig.insert("id", id); + insecureTunnelProxyConfig.insert("address", "example.nymea.io"); + insecureTunnelProxyConfig.insert("port", 2213); + insecureTunnelProxyConfig.insert("sslEnabled", false); + insecureTunnelProxyConfig.insert("authenticationEnabled", false); + insecureTunnelProxyConfig.insert("ignoreSslErrors", true); + + QVariantMap params; QVariant response; + + params.insert("configuration", insecureTcpConfig); + response = injectAndWait("Configuration.SetTcpServerConfiguration", params); + verifyConfigurationError(response); + + params.insert("configuration", insecureWebSocketConfig); + response = injectAndWait("Configuration.SetWebSocketServerConfiguration", params); + verifyConfigurationError(response); + + params.insert("configuration", insecureTunnelProxyConfig); + response = injectAndWait("Configuration.SetTunnelProxyServerConfiguration", params); + verifyConfigurationError(response); + + // Restart with disabled insecure interfaces + qputenv("NYMEA_INSECURE_INTERFACES_DISABLED", "1"); + restartServer(); + + // FIXME: make sure the insecure servers are not running + + // Remove the insecure configs and try to add them again and expect them to fail + params.clear(); response.clear(); + params.insert("id", id); + response = injectAndWait("Configuration.DeleteTcpServerConfiguration", params); + verifyConfigurationError(response); + + params.clear(); response.clear(); + params.insert("id", id); + response = injectAndWait("Configuration.DeleteWebSocketServerConfiguration", params); + verifyConfigurationError(response); + + params.clear(); response.clear(); + params.insert("id", id); + response = injectAndWait("Configuration.DeleteTunnelProxyServerConfiguration", params); + verifyConfigurationError(response); + + // Make sure we cannot add insecure interfaces beside localhost + params.clear(); response.clear(); + params.insert("configuration", insecureTcpConfig); + response = injectAndWait("Configuration.SetTcpServerConfiguration", params); + verifyConfigurationError(response, NymeaConfiguration::ConfigurationErrorUnsupported); + + params.clear(); response.clear(); + params.insert("configuration", insecureWebSocketConfig); + response = injectAndWait("Configuration.SetWebSocketServerConfiguration", params); + verifyConfigurationError(response, NymeaConfiguration::ConfigurationErrorUnsupported); + + params.clear(); response.clear(); + params.insert("configuration", insecureTunnelProxyConfig); + response = injectAndWait("Configuration.SetTunnelProxyServerConfiguration", params); + verifyConfigurationError(response, NymeaConfiguration::ConfigurationErrorUnsupported); + + qunsetenv("NYMEA_INSECURE_INTERFACES_DISABLED"); +} + QVariantMap TestConfigurations::loadBasicConfiguration() { QVariant response = injectAndWait("Configuration.GetConfigurations"); From cf681c15c663e32cc2dd32934978673cb32ac0a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 13 Oct 2025 14:35:08 +0200 Subject: [PATCH 4/4] Bump API version to 8.3 --- nymea.pro | 2 +- tests/auto/api.json | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/nymea.pro b/nymea.pro index 008996fa..e3ad0f3b 100644 --- a/nymea.pro +++ b/nymea.pro @@ -11,7 +11,7 @@ isEmpty(NYMEA_VERSION) { # define protocol versions JSON_PROTOCOL_VERSION_MAJOR=8 -JSON_PROTOCOL_VERSION_MINOR=2 +JSON_PROTOCOL_VERSION_MINOR=3 JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}" LIBNYMEA_API_VERSION_MAJOR=9 LIBNYMEA_API_VERSION_MINOR=0 diff --git a/tests/auto/api.json b/tests/auto/api.json index b2880d19..ad82c2fb 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,4 +1,4 @@ -8.2 +8.3 { "enums": { "BasicType": [ @@ -34,7 +34,8 @@ "ConfigurationErrorInvalidPort", "ConfigurationErrorInvalidHostAddress", "ConfigurationErrorBluetoothHardwareNotAvailable", - "ConfigurationErrorInvalidCertificate" + "ConfigurationErrorInvalidCertificate", + "ConfigurationErrorUnsupported" ], "CreateMethod": [ "CreateMethodUser",