diff --git a/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.cpp b/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.cpp index cdbd6b7c..ed7b30cb 100644 --- a/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.cpp +++ b/libnymea-core/hardware/network/upnp/upnpdiscoveryimplementation.cpp @@ -128,27 +128,41 @@ void UpnpDiscoveryImplementation::respondToSearchRequest(QHostAddress host, int // TODO: Once DeviceManager (and with that this can be moved into the server, use NymeaCore's configuration manager instead of parsing the config here... NymeaSettings globalSettings(NymeaSettings::SettingsRoleGlobal); globalSettings.beginGroup("nymead"); - QByteArray uuid = globalSettings.value("uuid", QUuid()).toByteArray(); + QByteArray uuid = globalSettings.value("uuid", QUuid()).toString().remove(QRegExp("[{}]")).toUtf8(); globalSettings.endGroup(); globalSettings.beginGroup("WebServer"); int serverPort = -1; - bool useSsl = false; + bool useSSL = false; foreach (const QString &group, globalSettings.childGroups()) { globalSettings.beginGroup(group); QHostAddress serverInterface = QHostAddress(globalSettings.value("address").toString()); - if (serverInterface == host || serverInterface == QHostAddress("0.0.0.0")) { - serverPort = globalSettings.value("port", -1).toInt(); - useSsl = globalSettings.value("sslEnabled", true).toBool(); - } + bool ssl = globalSettings.value("sslEnabled", true).toBool(); + int port = globalSettings.value("port", -1).toInt(); globalSettings.endGroup(); + + // We prefer unencrypted WebServers in this case. Most UPnP clients will bail out on our certificate... + // However, if there is none without encryption, still use one with, so that at least our own clients find it. + if (serverPort == -1) { // Don't have a better option yet. Use this. + serverPort = port; + useSSL = ssl; + continue; + } + if (!ssl && useSSL) { // There is one without ssl. Use that. + serverPort = port; + useSSL = false; + break; + } } globalSettings.endGroup(); if (serverPort == -1) { - qCWarning(dcConnection) << "No matching WebServer configuration found. Discarding UPnP request!"; + qCWarning(dcUpnp()) << "No matching WebServer configuration found. Discarding UPnP request! UPnP requires a plaintext webserver."; return; } + if (useSSL) { + qCWarning(dcUpnp()) << "Could not find a WebServer without SSL. Using one with SSL. This will not work with many clients."; + } foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { foreach (QNetworkAddressEntry entry, interface.addressEntries()) { @@ -157,7 +171,7 @@ void UpnpDiscoveryImplementation::respondToSearchRequest(QHostAddress host, int // check subnet if (host.isInSubnet(QHostAddress::parseSubnet(entry.ip().toString() + "/24"))) { QString locationString; - if (useSsl) { + if (useSSL) { locationString = "https://" + entry.ip().toString() + ":" + QString::number(serverPort) + "/server.xml"; } else { locationString = "http://" + entry.ip().toString() + ":" + QString::number(serverPort) + "/server.xml"; @@ -168,11 +182,10 @@ void UpnpDiscoveryImplementation::respondToSearchRequest(QHostAddress host, int "CACHE-CONTROL: max-age=1900\r\n" "DATE: " + QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT\r\n" "EXT:\r\n" - "CONTENT-LENGTH:0\r\n" "LOCATION: " + locationString.toUtf8() + "\r\n" "SERVER: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n" - "ST:upnp:rootdevice\r\n" - "USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" + "ST: upnp:rootdevice\r\n" + "USN: uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" "\r\n"); qCDebug(dcUpnp()) << QString("Sending response to %1:%2").arg(host.toString()).arg(port); diff --git a/libnymea-core/webserver.cpp b/libnymea-core/webserver.cpp index c6be1f7a..b2bb820a 100644 --- a/libnymea-core/webserver.cpp +++ b/libnymea-core/webserver.cpp @@ -605,7 +605,7 @@ bool WebServer::stopServer() QByteArray WebServer::createServerXmlDocument(QHostAddress address) { - QByteArray uuid = NymeaCore::instance()->configuration()->serverUuid().toByteArray(); + QByteArray uuid = NymeaCore::instance()->configuration()->serverUuid().toString().remove(QRegExp("[{}]")).toUtf8(); QByteArray data; QXmlStreamWriter writer(&data); @@ -619,57 +619,12 @@ QByteArray WebServer::createServerXmlDocument(QHostAddress address) writer.writeTextElement("minor", "1"); writer.writeEndElement(); // specVersion - if (m_configuration.sslEnabled) { - writer.writeTextElement("URLBase", "https://" + address.toString() + ":" + QString::number(m_configuration.port)); - } else { - writer.writeTextElement("URLBase", "http://" + address.toString() + ":" + QString::number(m_configuration.port)); - } - - ServerConfiguration websocketConfiguration; - bool webSocketServerFound = false; - foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->webSocketServerConfigurations()) { - if (config.address == QHostAddress("0.0.0.0") || config.address == address) { - if (!webSocketServerFound) { - websocketConfiguration = config; - webSocketServerFound = true; - } else if (!websocketConfiguration.sslEnabled && config.sslEnabled) { - // If the previous one is plaintext but we also have a secure one, upgrade to that. - websocketConfiguration = config; - } - } - } - if (webSocketServerFound) { - if (websocketConfiguration.sslEnabled) { - writer.writeTextElement("websocketURL", "wss://" + address.toString() + ":" + QString::number(websocketConfiguration.port)); - } else { - writer.writeTextElement("websocketURL", "ws://" + address.toString() + ":" + QString::number(websocketConfiguration.port)); - } - } - - ServerConfiguration tcpServerConfiguration; - bool tcpServerFound = false; - foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->tcpServerConfigurations()) { - if (config.address == QHostAddress("0.0.0.0") || config.address == address) { - if (!tcpServerFound) { - tcpServerConfiguration = config; - tcpServerFound = true; - } else if (!tcpServerConfiguration.sslEnabled && config.sslEnabled) { - // If the previous one is plaintext but we also have a secure one, upgrade to that. - tcpServerConfiguration = config; - } - } - } - if (tcpServerFound) { - if (tcpServerConfiguration.sslEnabled) { - writer.writeTextElement("nymeaRpcURL", "nymeas://" + address.toString() + ":" + QString::number(tcpServerConfiguration.port)); - } else { - writer.writeTextElement("nymeaRpcURL", "nymea://" + address.toString() + ":" + QString::number(tcpServerConfiguration.port)); - } - } - - writer.writeTextElement("presentationURL", "/"); - + QString presentationUrl = QString("%1://%2:%3") + .arg(m_configuration.sslEnabled ? "https" : "http") + .arg(address.toString()) + .arg(m_configuration.port); writer.writeStartElement("device"); + writer.writeTextElement("presentationURL", presentationUrl); writer.writeTextElement("deviceType", "urn:schemas-upnp-org:device:Basic:1"); writer.writeTextElement("friendlyName", NymeaCore::instance()->configuration()->serverName()); writer.writeTextElement("manufacturer", "guh GmbH"); @@ -764,6 +719,36 @@ QByteArray WebServer::createServerXmlDocument(QHostAddress address) writer.writeEndElement(); // iconList + writer.writeStartElement("serviceList"); + + int counter = 1; + int sslCounter = 1; + foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->webSocketServerConfigurations()) { + if (config.address == QHostAddress("0.0.0.0") || config.address == address) { + writer.writeStartElement("service"); + writer.writeTextElement("serviceType", QString("urn:nymea.io:service:%1:%2").arg(config.sslEnabled ? "wss" : "ws").arg(config.sslEnabled ? sslCounter : counter)); + writer.writeTextElement("serviceId", QString("urn:nymea.io:serviceId:%1:%2").arg(config.sslEnabled ? "wss" : "ws").arg(config.sslEnabled ? sslCounter++ : counter++)); + QString url = QString("%1%2:%3").arg(config.sslEnabled ? "wss://" : "ws://").arg(address.toString()).arg(config.port); + writer.writeTextElement("SCPDURL", url); + writer.writeEndElement(); // service + } + } + + counter = 1; + sslCounter = 1; + foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->tcpServerConfigurations()) { + if (config.address == QHostAddress("0.0.0.0") || config.address == address) { + writer.writeStartElement("service"); + writer.writeTextElement("serviceType", QString("urn:nymea.io:service:%1:%2").arg(config.sslEnabled ? "nymeas" : "nymea").arg(config.sslEnabled ? sslCounter : counter)); + writer.writeTextElement("serviceId", QString("urn:nymea.io:serviceId:%1:%2").arg(config.sslEnabled ? "nymeas" : "nymea").arg(config.sslEnabled ? sslCounter++ : counter++)); + QString url = QString("%1%2:%3").arg(config.sslEnabled ? "nymeas://" : "nymea://").arg(address.toString()).arg(config.port); + writer.writeTextElement("SCPDURL", url); + writer.writeEndElement(); // service + } + } + + writer.writeEndElement(); // serviceList + writer.writeEndElement(); // device writer.writeEndElement(); // root writer.writeEndDocument();