Add basic websocket server.

This commit is contained in:
Simon Stürz 2018-08-02 17:42:23 +02:00
parent e892fe2b46
commit 8b14e3bc06
22 changed files with 551 additions and 76 deletions

View File

@ -22,8 +22,8 @@ In the build directory you can find the resulting library and binary files.
If you want to start the proxy server from the build directory, you need to export the library path before starting the application:
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/libnymea-remoteproxy
$ ./server/nymea-remoteproxy
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/libnymea-remoteproxy:$(pwd)/libnymea-remoteproxyclient
$ ./server/nymea-remoteproxy -c ../nymea-remoteproxy/tests/test-certificate.crt -k ../nymea-remoteproxy/tests/test-certificate.key
# Install
@ -46,24 +46,28 @@ In order to get information about the server you can start the command with the
$ nymea-remoteproxy --help
usage: nymea-remoteproxy [options]
Usage: nymea-remoteproxy [options]
The nymea remote proxy server.
The nymea remote proxy server. This server allowes nymea-cloud users and registered nymea deamons to establish a tunnel connection.
Copyright © 2018 Simon Stürz <simon.stuerz@guh.io>
Options:
-h, --help Displays this help.
-l, --logging <logfile> Write log file to the given logfile.
-s, --server <url> The authentication server url.
-p, --port <port> The proxy server port.
-c, --certificate <certificate> The path to the SSL certificate.
-s, --server <hostaddress> The server address this proxy will
listen on. Default is 127.0.0.1
-p, --port <port> The proxy server port. Default is
1212
-c, --certificate <certificate> The path to the SSL certificate used
for this proxy server.
-k, --certificate-key <certificate-key> The path to the SSL certificate key
(KEY).
-v, --verbose Print the whole traffic.
used for this proxy server.
-a, --authentication-server <url> The server url of the AWS
authentication server.
-v, --verbose Print more verbose.
# Server API
Once a client connects to the proxy server, he must authenticate him self by passing the token received from the nymea-cloud mqtt connection request.

View File

@ -1,4 +1,5 @@
#include "engine.h"
#include "websocketserver.h"
#include "loggingcategories.h"
Engine *Engine::s_instance = nullptr;
@ -30,24 +31,40 @@ void Engine::destroy()
void Engine::start()
{
qCDebug(dcEngine()) << "Start server engine";
if (!m_running)
qCDebug(dcEngine()) << "Start server engine";
QUrl proxyUrl;
proxyUrl.setScheme("wss");
proxyUrl.setHost("0.0.0.0");
proxyUrl.setPort(static_cast<int>(m_port));
proxyUrl.setHost(m_webSocketServerHostAddress.toString());
proxyUrl.setPort(m_webSocketServerPort);
qCDebug(dcApplication()) << "Authentication server" << m_authenticationServerUrl.toString();
qCDebug(dcApplication()) << "Start server" << proxyUrl.toString();
// TODO: init stuff
// Init WebSocketServer
if (m_webSocketServer) {
delete m_webSocketServer;
m_webSocketServer = nullptr;
}
m_webSocketServer = new WebSocketServer(m_sslConfiguration, this);
m_webSocketServer->setServerUrl(proxyUrl);
m_webSocketServer->startServer();
setRunning(true);
}
void Engine::stop()
{
qCDebug(dcEngine()) << "Stop server engine";
if (m_running)
qCDebug(dcEngine()) << "Stop server engine";
// TODO: deinit stuff
if (m_webSocketServer) {
m_webSocketServer->stopServer();
m_webSocketServer->deleteLater();
m_webSocketServer = nullptr;
}
setRunning(false);
}
@ -57,32 +74,49 @@ bool Engine::running() const
return m_running;
}
void Engine::setHost(const QHostAddress &hostAddress)
void Engine::setWebSocketServerHostAddress(const QHostAddress &hostAddress)
{
m_hostAddress = hostAddress;
qCDebug(dcEngine()) << "Websocket server host address:" << hostAddress;
m_webSocketServerHostAddress = hostAddress;
}
void Engine::setAuthenticationServerUrl(const QUrl &url)
void Engine::setWebSocketServerPort(const quint16 &port)
{
m_authenticationServerUrl = url;
}
void Engine::setPort(const quint16 &port)
{
m_port = port;
qCDebug(dcEngine()) << "Websocket server port:" << port;
m_webSocketServerPort = port;
}
void Engine::setSslConfiguration(const QSslConfiguration &configuration)
{
qCDebug(dcEngine()) << "SSL Configuration:";
qCDebug(dcEngine()) << " Common name:" << configuration.localCertificate().issuerInfo(QSslCertificate::CommonName);
qCDebug(dcEngine()) << " Organisation:" << configuration.localCertificate().issuerInfo(QSslCertificate::Organization);
qCDebug(dcEngine()) << " Organisation unit name:" << configuration.localCertificate().issuerInfo(QSslCertificate::OrganizationalUnitName);
qCDebug(dcEngine()) << " Country name:" << configuration.localCertificate().issuerInfo(QSslCertificate::CountryName);
qCDebug(dcEngine()) << " Locality name:" << configuration.localCertificate().issuerInfo(QSslCertificate::LocalityName);
qCDebug(dcEngine()) << " State/Province:" << configuration.localCertificate().issuerInfo(QSslCertificate::StateOrProvinceName);
qCDebug(dcEngine()) << " Email address:" << configuration.localCertificate().issuerInfo(QSslCertificate::EmailAddress);
m_sslConfiguration = configuration;
}
void Engine::setAuthenticationServerUrl(const QUrl &url)
{
qCDebug(dcEngine()) << "Authentication server URL" << url.toString();
m_authenticationServerUrl = url;
}
Engine::Engine(QObject *parent) :
QObject(parent)
{
}
Engine::~Engine()
{
stop();
}
void Engine::setRunning(bool running)
{
if (m_running == running)

View File

@ -6,6 +6,8 @@
#include <QHostAddress>
#include <QSslConfiguration>
class WebSocketServer;
class Engine : public QObject
{
Q_OBJECT
@ -19,23 +21,27 @@ public:
bool running() const;
void setHost(const QHostAddress &hostAddress);
void setAuthenticationServerUrl(const QUrl &url);
void setPort(const quint16 &port);
void setWebSocketServerHostAddress(const QHostAddress &hostAddress);
void setWebSocketServerPort(const quint16 &port);
void setSslConfiguration(const QSslConfiguration &configuration);
void setAuthenticationServerUrl(const QUrl &url);
private:
explicit Engine(QObject *parent = nullptr);
~Engine();
static Engine *s_instance;
bool m_running = false;
quint16 m_port = 0;
QHostAddress m_hostAddress;
QSslConfiguration m_sslConfiguration;
quint16 m_webSocketServerPort = 1212;
QHostAddress m_webSocketServerHostAddress = QHostAddress::LocalHost;
QSslConfiguration m_sslConfiguration;
QUrl m_authenticationServerUrl;
WebSocketServer *m_webSocketServer = nullptr;
void setRunning(bool running);
signals:

View File

@ -5,8 +5,21 @@ TARGET = nymea-remoteproxy
HEADERS += \
engine.h \
loggingcategories.h
loggingcategories.h \
transportinterface.h \
websocketserver.h
SOURCES += \
engine.cpp \
loggingcategories.cpp
loggingcategories.cpp \
transportinterface.cpp \
websocketserver.cpp
# install header file with relative subdirectory
for(header, HEADERS) {
path = /usr/include/nymea-remoteproxy/$${dirname(header)}
eval(headers_$${path}.files += $${header})
eval(headers_$${path}.path = $${path})
eval(INSTALLS *= headers_$${path})
}

View File

@ -4,6 +4,7 @@ Q_LOGGING_CATEGORY(dcApplication, "Application")
Q_LOGGING_CATEGORY(dcEngine, "Engine")
Q_LOGGING_CATEGORY(dcJsonRpc, "JsonRpc")
Q_LOGGING_CATEGORY(dcWebSocketServer, "WebSocketServer")
Q_LOGGING_CATEGORY(dcWebSocketServerTraffic, "WebSocketServerTraffic")
Q_LOGGING_CATEGORY(dcAuthenticator, "Authenticator")
Q_LOGGING_CATEGORY(dcDebug, "Debug")
Q_LOGGING_CATEGORY(dcConnectionManager, "ConnectionManager")

View File

@ -8,6 +8,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcApplication)
Q_DECLARE_LOGGING_CATEGORY(dcEngine)
Q_DECLARE_LOGGING_CATEGORY(dcJsonRpc)
Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServer)
Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServerTraffic)
Q_DECLARE_LOGGING_CATEGORY(dcAuthenticator)
Q_DECLARE_LOGGING_CATEGORY(dcConnectionManager)
Q_DECLARE_LOGGING_CATEGORY(dcDebug)

View File

@ -0,0 +1,12 @@
#include "transportinterface.h"
TransportInterface::TransportInterface(QObject *parent) :
QObject(parent)
{
}
TransportInterface::~TransportInterface()
{
}

View File

@ -0,0 +1,27 @@
#ifndef TRANSPORTINTERFACE_H
#define TRANSPORTINTERFACE_H
#include <QObject>
class TransportInterface : public QObject
{
Q_OBJECT
public:
explicit TransportInterface(QObject *parent = nullptr);
virtual ~TransportInterface() = 0;
virtual void sendData(const QUuid &clientId, const QByteArray &data) = 0;
virtual void sendData(const QList<QUuid> &clients, const QByteArray &data) = 0;
signals:
void clientConnected(const QUuid &clientId);
void clientDisconnected(const QUuid &clientId);
void dataAvailable(const QUuid &clientId, const QByteArray &data);
public slots:
virtual bool startServer() = 0;
virtual bool stopServer() = 0;
};
#endif // TRANSPORTINTERFACE_H

View File

@ -0,0 +1,162 @@
#include "websocketserver.h"
#include "loggingcategories.h"
#include <QCoreApplication>
WebSocketServer::WebSocketServer(const QSslConfiguration &sslConfiguration, QObject *parent) :
TransportInterface(parent),
m_sslConfiguration(sslConfiguration)
{
}
WebSocketServer::~WebSocketServer()
{
stopServer();
}
QUrl WebSocketServer::serverUrl() const
{
return m_serverUrl;
}
void WebSocketServer::setServerUrl(const QUrl &serverUrl)
{
m_serverUrl = serverUrl;
}
bool WebSocketServer::running() const
{
return m_server->isListening();
}
QSslConfiguration WebSocketServer::sslConfiguration() const
{
return m_sslConfiguration;
}
void WebSocketServer::sendData(const QUuid &clientId, const QByteArray &data)
{
QWebSocket *client = nullptr;
client = m_clientList.value(clientId);
if (client) {
qCDebug(dcWebSocketServerTraffic()) << "--> Sending data to client:" << data;
client->sendTextMessage(data + '\n');
} else {
qCWarning(dcWebSocketServer()) << "Client" << clientId << "unknown to this transport";
}
}
void WebSocketServer::sendData(const QList<QUuid> &clients, const QByteArray &data)
{
foreach (const QUuid &client, clients) {
sendData(client, data);
}
}
void WebSocketServer::onClientConnected()
{
// Got a new client connected
QWebSocket *client = m_server->nextPendingConnection();
// Check websocket version
if (client->version() != QWebSocketProtocol::Version13) {
qCWarning(dcWebSocketServer()) << "Client with invalid protocol version" << client->version() << ". Rejecting.";
client->close(QWebSocketProtocol::CloseCodeProtocolError, QString("invalid protocol version: %1 != Supported Version 13").arg(client->version()));
delete client;
return;
}
// Create new uuid for this connection
QUuid clientId = QUuid::createUuid();
qCDebug(dcWebSocketServer()) << "New client connected:" << client->peerAddress().toString() << clientId;
// Append the new client to the client list
m_clientList.insert(clientId, client);
connect(client, SIGNAL(pong(quint64,QByteArray)), this, SLOT(onPing(quint64,QByteArray)));
connect(client, SIGNAL(binaryMessageReceived(QByteArray)), this, SLOT(onBinaryMessageReceived(QByteArray)));
connect(client, SIGNAL(textMessageReceived(QString)), this, SLOT(onTextMessageReceived(QString)));
connect(client, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onClientError(QAbstractSocket::SocketError)));
connect(client, SIGNAL(disconnected()), this, SLOT(onClientDisconnected()));
emit clientConnected(clientId);
}
void WebSocketServer::onClientDisconnected()
{
QWebSocket *client = static_cast<QWebSocket *>(sender());
QUuid clientId = m_clientList.key(client);
qCDebug(dcWebSocketServer()) << "Client disconnected:" << client->peerAddress().toString() << clientId;
m_clientList.take(clientId)->deleteLater();
emit clientDisconnected(clientId);
}
void WebSocketServer::onBinaryMessageReceived(const QByteArray &data)
{
QWebSocket *client = static_cast<QWebSocket *>(sender());
qCDebug(dcWebSocketServerTraffic()) << "<-- Binary message from" << client->peerAddress().toString() << ":" << data;
}
void WebSocketServer::onTextMessageReceived(const QString &message)
{
QWebSocket *client = static_cast<QWebSocket *>(sender());
qCDebug(dcWebSocketServerTraffic()) << "Text message from" << client->peerAddress().toString() << ":" << message;
emit dataAvailable(m_clientList.key(client), message.toUtf8());
}
void WebSocketServer::onClientError(QAbstractSocket::SocketError error)
{
QWebSocket *client = static_cast<QWebSocket *>(sender());
qCWarning(dcWebSocketServer()) << "Client error occured:" << error << client->errorString();
}
void WebSocketServer::onServerError(QAbstractSocket::SocketError error)
{
qCWarning(dcWebSocketServer()) << "Server error occured:" << error << m_server->errorString();
}
void WebSocketServer::onPing(quint64 elapsedTime, const QByteArray &payload)
{
QWebSocket *client = static_cast<QWebSocket *>(sender());
qCDebug(dcWebSocketServer) << "ping response" << client->peerAddress() << elapsedTime << payload;
}
bool WebSocketServer::startServer()
{
m_server = new QWebSocketServer(QCoreApplication::applicationName(), QWebSocketServer::SecureMode, this);
m_server->setSslConfiguration(m_sslConfiguration);
connect (m_server, &QWebSocketServer::newConnection, this, &WebSocketServer::onClientConnected);
connect (m_server, &QWebSocketServer::acceptError, this, &WebSocketServer::onServerError);
qCDebug(dcWebSocketServer()) << "Starting server" << m_server->serverName() << m_serverUrl.toString();
if (!m_server->listen(QHostAddress(m_serverUrl.host()), static_cast<quint16>(m_serverUrl.port()))) {
qCWarning(dcWebSocketServer()) << "Server" << m_server->serverName() << "could not listen on" << serverUrl().toString();
return false;
}
qCDebug(dcWebSocketServer()) << "Server started successfully.";
return true;
}
bool WebSocketServer::stopServer()
{
// Clean up client connections
foreach (QWebSocket *client, m_clientList.values()) {
client->close(QWebSocketProtocol::CloseCodeNormal, "Stop server");
}
// Delete the server object
if (m_server) {
qCDebug(dcWebSocketServer()) << "Stop server" << m_server->serverName() << m_serverUrl.toString();
m_server->close();
delete m_server;
m_server = nullptr;
}
return true;
}

View File

@ -0,0 +1,53 @@
#ifndef WEBSOCKETSERVER_H
#define WEBSOCKETSERVER_H
#include <QUrl>
#include <QUuid>
#include <QObject>
#include <QWebSocket>
#include <QWebSocketServer>
#include <QSslConfiguration>
#include "transportinterface.h"
class WebSocketServer : public TransportInterface
{
Q_OBJECT
public:
explicit WebSocketServer(const QSslConfiguration &sslConfiguration, QObject *parent = nullptr);
~WebSocketServer() override;
QUrl serverUrl() const;
void setServerUrl(const QUrl &serverUrl);
bool running() const;
QSslConfiguration sslConfiguration() const;
void sendData(const QUuid &clientId, const QByteArray &data) override;
void sendData(const QList<QUuid> &clients, const QByteArray &data) override;
private:
QUrl m_serverUrl;
QWebSocketServer *m_server = nullptr;
QSslConfiguration m_sslConfiguration;
bool m_enabled = false;
QHash<QUuid, QWebSocket *> m_clientList;
private slots:
void onClientConnected();
void onClientDisconnected();
void onBinaryMessageReceived(const QByteArray &data);
void onTextMessageReceived(const QString &message);
void onClientError(QAbstractSocket::SocketError error);
void onServerError(QAbstractSocket::SocketError error);
void onPing(quint64 elapsedTime, const QByteArray & payload);
public slots:
bool startServer() override;
bool stopServer() override;
};
#endif // WEBSOCKETSERVER_H

View File

@ -0,0 +1,20 @@
include(../nymea-remoteproxy.pri)
TEMPLATE = lib
TARGET = nymea-remoteproxyclient
HEADERS += \
remoteproxyconnector.h
SOURCES += \
remoteproxyconnector.cpp
# install header file with relative subdirectory
for(header, HEADERS) {
path = /usr/include/nymea-remoteproxyclient/$${dirname(header)}
eval(headers_$${path}.files += $${header})
eval(headers_$${path}.path = $${path})
eval(INSTALLS *= headers_$${path})
}

View File

@ -0,0 +1,6 @@
#include "remoteproxyconnector.h"
RemoteProxyConnector::RemoteProxyConnector(QObject *parent) : QObject(parent)
{
}

View File

@ -0,0 +1,18 @@
#ifndef REMOTEPROXYCONNECTOR_H
#define REMOTEPROXYCONNECTOR_H
#include <QObject>
class RemoteProxyConnector : public QObject
{
Q_OBJECT
public:
explicit RemoteProxyConnector(QObject *parent = nullptr);
signals:
public slots:
};
#endif // REMOTEPROXYCONNECTOR_H

View File

@ -1,4 +1,4 @@
QT *= network
QT *= network websockets
QT -= gui
CONFIG += c++11 console

View File

@ -1,8 +1,8 @@
include(nymea-remoteproxy.pri)
TEMPLATE=subdirs
SUBDIRS += server libnymea-remoteproxy tests
SUBDIRS += server libnymea-remoteproxy libnymea-remoteproxyclient tests
server.depends = libnymea-remoteproxy
tests.depends = libnymea-remoteproxy
tests.depends = libnymea-remoteproxy libnymea-remoteproxyclient

View File

@ -97,25 +97,28 @@ int main(int argc, char *argv[])
// command line parser
QCommandLineParser parser;
parser.addHelpOption();
parser.setApplicationDescription(QString("\nThe nymea remote proxy server.\n\n"
parser.setApplicationDescription(QString("\nThe nymea remote proxy server. This server allowes nymea-cloud users and registered nymea deamons to establish a tunnel connection.\n\n"
"Copyright %1 2018 Simon Stürz <simon.stuerz@guh.io>").arg(QChar(0xA9)));
QCommandLineOption logfileOption(QStringList() << "l" << "logging", "Write log file to the given logfile.", "logfile", "/var/log/nymea-remoteproxy.log");
parser.addOption(logfileOption);
QCommandLineOption serverOption(QStringList() << "s" << "server", "The authentication server url.", "url", "http://localhost:8000");
QCommandLineOption serverOption(QStringList() << "s" << "server", "The server address this proxy will listen on. Default is 127.0.0.1", "hostaddress", "127.0.0.1");
parser.addOption(serverOption);
QCommandLineOption portOption(QStringList() << "p" << "port", "The proxy server port.", "port", "1212");
QCommandLineOption portOption(QStringList() << "p" << "port", "The proxy server port. Default is 1212", "port", "1212");
parser.addOption(portOption);
QCommandLineOption certOption(QStringList() << "c" <<"certificate", "The path to the SSL certificate.", "certificate");
QCommandLineOption certOption(QStringList() << "c" <<"certificate", "The path to the SSL certificate used for this proxy server.", "certificate");
parser.addOption(certOption);
QCommandLineOption certKeyOption(QStringList() << "k" << "certificate-key", "The path to the SSL certificate key (KEY).", "certificate-key");
QCommandLineOption certKeyOption(QStringList() << "k" << "certificate-key", "The path to the SSL certificate key used for this proxy server.", "certificate-key");
parser.addOption(certKeyOption);
QCommandLineOption verboseOption(QStringList() << "v" << "verbose", "Print the whole traffic.");
QCommandLineOption authenticationUrlOption(QStringList() << "a" << "authentication-server", "The server url of the AWS authentication server.", "url", "https://127.0.0.1");
parser.addOption(authenticationUrlOption);
QCommandLineOption verboseOption(QStringList() << "v" << "verbose", "Print more verbose.");
parser.addOption(verboseOption);
parser.process(application);
@ -141,37 +144,24 @@ int main(int argc, char *argv[])
s_loggingEnabled = true;
}
qCDebug(dcApplication()) << "==============================================";
qCDebug(dcApplication()) << "Starting" << application.applicationName() << application.applicationVersion();
qCDebug(dcApplication()) << "==============================================";
if (s_loggingEnabled)
qCDebug(dcApplication()) << "Logging enabled. Writing logs to" << s_logFile.fileName();
// Authentication server url
QUrl serverUrl("http://localhost:8000");
if (parser.isSet(serverOption))
serverUrl = QUrl(parser.value(serverOption));
if (!serverUrl.isValid()) {
qCCritical(dcApplication()) << "Invalid authentication server url:" << parser.value(serverOption);
// Proxy server host address
QHostAddress serverHostAddress = QHostAddress(parser.value(serverOption));
if (serverHostAddress.isNull()) {
qCCritical(dcApplication()) << "Invalid hostaddress for the proxy server:" << parser.value(serverOption);
exit(-1);
}
// Port
uint port = 1212;
if (parser.isSet(portOption)) {
bool ok = false;
port = parser.value(portOption).toUInt(&ok);
if (!ok) {
qCCritical(dcApplication()) << "Invalud port value:" << parser.value(portOption);
exit(-1);
}
bool ok = false;
uint port = parser.value(portOption).toUInt(&ok);
if (!ok) {
qCCritical(dcApplication()) << "Invalid port value:" << parser.value(portOption);
exit(-1);
}
if (port > 65535) {
qCCritical(dcApplication()) << "Port value is out of range:" << parser.value(portOption);
exit(-1);
}
if (port > 65535) {
qCCritical(dcApplication()) << "Port value is out of range:" << parser.value(portOption);
exit(-1);
}
// SSL certificate
@ -198,18 +188,40 @@ int main(int argc, char *argv[])
if (parser.isSet(certKeyOption)) {
QFile certKeyFile(parser.value(certKeyOption));
if (!certKeyFile.open(QIODevice::ReadOnly)) {
qCCritical(dcApplication()) << "ERROR: Could not open certificate key file:" << parser.value(certKeyOption) << certKeyFile.errorString();
qCCritical(dcApplication()) << "Could not open certificate key file:" << parser.value(certKeyOption) << certKeyFile.errorString();
exit(-1);
}
QSslKey sslKey(&certKeyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
qCDebug(dcApplication()) << "Loaded successfully certificate key" << parser.value(certKeyOption);
certKeyFile.close();
sslConfiguration.setPrivateKey(sslKey);
}
Engine::instance()->setAuthenticationServerUrl(serverUrl);
Engine::instance()->setPort(static_cast<quint16>(port));
if (sslConfiguration.isNull()) {
qCCritical(dcApplication()) << "No SSL configuration specified. The server does not suppoert insecure connections.";
exit(-1);
}
// Authentication server url
QUrl authenticationServerUrl(parser.value(authenticationUrlOption));
if (!authenticationServerUrl.isValid()) {
qCCritical(dcApplication()) << "Invalid authentication server url:" << parser.value(authenticationUrlOption);
exit(-1);
}
qCDebug(dcApplication()) << "==============================================";
qCDebug(dcApplication()) << "Starting" << application.applicationName() << application.applicationVersion();
qCDebug(dcApplication()) << "==============================================";
if (s_loggingEnabled)
qCDebug(dcApplication()) << "Logging enabled. Writing logs to" << s_logFile.fileName();
// Configure and start the engines
Engine::instance()->setWebSocketServerHostAddress(serverHostAddress);
Engine::instance()->setWebSocketServerPort(static_cast<quint16>(port));
Engine::instance()->setSslConfiguration(sslConfiguration);
Engine::instance()->setAuthenticationServerUrl(authenticationServerUrl);
Engine::instance()->start();
return application.exec();

6
tests/certificate.qrc Normal file
View File

@ -0,0 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>test-certificate.crt</file>
<file>test-certificate.key</file>
</qresource>
</RCC>

View File

@ -6,7 +6,28 @@
RemoteProxyTests::RemoteProxyTests(QObject *parent) :
QObject(parent)
{
QFile certificateFile(":/test-certificate.crt");
if (!certificateFile.open(QIODevice::ReadOnly)) {
qWarning() << "Could not open resource file" << certificateFile.fileName();
exit(1);
}
QByteArray certificateData = certificateFile.readAll();
//qDebug() << "Certificate:" << endl << qUtf8Printable(certificateData);
QFile keyFile(":/test-certificate.key");
if (!keyFile.open(QIODevice::ReadOnly)) {
qWarning() << "Could not open resource file" << keyFile.fileName();
exit(1);
}
QByteArray keyData = keyFile.readAll();
//qDebug() << "Certificate key:" << endl << qUtf8Printable(keyData);
m_sslConfiguration.setPrivateKey(QSslKey(keyData, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey));
m_sslConfiguration.setLocalCertificate(QSslCertificate(certificateData, QSsl::Pem));
m_sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
m_sslConfiguration.setProtocol(QSsl::TlsV1_2OrLater);
}
void RemoteProxyTests::cleanUpEngine()
@ -25,6 +46,17 @@ void RemoteProxyTests::restartEngine()
QVERIFY(Engine::exists());
}
void RemoteProxyTests::startServer()
{
restartEngine();
Engine::instance()->setWebSocketServerPort(m_port);
Engine::instance()->setWebSocketServerHostAddress(QHostAddress::LocalHost);
Engine::instance()->setSslConfiguration(m_sslConfiguration);
Engine::instance()->start();
}
void RemoteProxyTests::initTestCase()
{
qCDebug(dcApplication()) << "Init test case.";
@ -37,6 +69,14 @@ void RemoteProxyTests::cleanupTestCase()
cleanUpEngine();
}
void RemoteProxyTests::authenticate()
{
startServer();
Engine::instance()->stop();
}
void RemoteProxyTests::startStopServer()
{
cleanUpEngine();

View File

@ -2,7 +2,11 @@
#define NYMEA_REMOTEPROXY_TESTS_H
#include <QtTest>
#include <QSslKey>
#include <QObject>
#include <QHostAddress>
#include <QSslCertificate>
#include <QSslConfiguration>
class RemoteProxyTests : public QObject
{
@ -11,8 +15,13 @@ public:
explicit RemoteProxyTests(QObject *parent = nullptr);
private:
quint16 m_port = 1212;
QHostAddress m_serverAddress = QHostAddress::LocalHost;
QSslConfiguration m_sslConfiguration;
void cleanUpEngine();
void restartEngine();
void startServer();
protected slots:
void initTestCase();
@ -21,9 +30,7 @@ protected slots:
private slots:
void startStopServer();
void authenticate();
};

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID4TCCAsmgAwIBAgIJAPikDhNDwsqGMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYD
VQQGEwJBVDEPMA0GA1UECAwGVmllbm5hMQ8wDQYDVQQHDAZWaWVubmExEjAQBgNV
BAoMCWd1aCBHbWJILjELMAkGA1UECwwCUUExEjAQBgNVBAMMCWxvY2FsaG9zdDEf
MB0GCSqGSIb3DQEJARYQZGV2ZWxvcGVyQGd1aC5pbzAgFw0xODA4MDIxNDU3NTZa
GA8yMTE4MDcwOTE0NTc1NlowgYUxCzAJBgNVBAYTAkFUMQ8wDQYDVQQIDAZWaWVu
bmExDzANBgNVBAcMBlZpZW5uYTESMBAGA1UECgwJZ3VoIEdtYkguMQswCQYDVQQL
DAJRQTESMBAGA1UEAwwJbG9jYWxob3N0MR8wHQYJKoZIhvcNAQkBFhBkZXZlbG9w
ZXJAZ3VoLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoNm4oJfX
4E7RNzJsscs1+sAgDG2I0fDAwHM1evStk9hjZTHy+T2aLPih1nkAiZvt5mso8v6W
rrRc1a3MtHinJRXP4wv/WPLxACmEzNhEzRpl4d+JmcOHwNclT3xjRJCBsW5SNxr1
Z2GQICTFJeIBmyHzVcLNGnlrXL61tkSeDCaY3TiaxCRXgtPBtdoJttFFJTXWld2P
V4QSlkPA+9edQmdG6jr5MW/LxxdEyp1kqp+9erZ0BbLFly/sNv2hL1Gy6rlPBdxJ
S09IYXAvqCjSwzA1VN0P35/iHZLigrwe9bt5jMC8bYAU1yOKrMHVwQhSBe6fij7g
EezK1C90BWLOgwIDAQABo1AwTjAdBgNVHQ4EFgQUrT5VDdjUEOzKPWRYelLAI3Nw
4uUwHwYDVR0jBBgwFoAUrT5VDdjUEOzKPWRYelLAI3Nw4uUwDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAQEARHMVjrBEKbfNXTsfNAQcSRkAMkCbWG5/NQDl
wHbNEu+VV0OF0AJ0IE1NCC4ZLuyUxSztMJdTOSM2lLmSGjCWyUlKhGvq79MDlomN
jHYLPhSV3pYwaO86qNTtBqAQ1YXuauFboxHrpvsXx5a6ivPl1UyiDP9EtHDvkUpo
tSW0HBC0n+o78vHbGXyzvlyI25UE9jnIDPD2K3jm7bcGqiqrDgT06QyE7GD43eeL
0X6dBKYQWUWcG6cBR9Cvoj1Ec3IcXuprHwfbNrVtYOwdO7678U6gJuk1GeblcsgX
9HfkjP61NIqUpu2U0BQrd3mDkjsNuta2IKLW7ojALRpP1shorA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCg2bigl9fgTtE3
MmyxyzX6wCAMbYjR8MDAczV69K2T2GNlMfL5PZos+KHWeQCJm+3mayjy/pautFzV
rcy0eKclFc/jC/9Y8vEAKYTM2ETNGmXh34mZw4fA1yVPfGNEkIGxblI3GvVnYZAg
JMUl4gGbIfNVws0aeWtcvrW2RJ4MJpjdOJrEJFeC08G12gm20UUlNdaV3Y9XhBKW
Q8D7151CZ0bqOvkxb8vHF0TKnWSqn716tnQFssWXL+w2/aEvUbLquU8F3ElLT0hh
cC+oKNLDMDVU3Q/fn+IdkuKCvB71u3mMwLxtgBTXI4qswdXBCFIF7p+KPuAR7MrU
L3QFYs6DAgMBAAECggEAIp+bAV6OBmeQ21vMT90ZKneOrn4pdF9pbkOeYHAoqOls
Q80jqwjalhGS7JKxTe21oOKyNtQcZVDHpus5ZCOQfwgZ7pqXhXMN82X8gweOj8O9
6Ifwm5ueLiFhk6GH0Kt2b1X69oekCXPTzUd89HGYvObq9SvwcGFwfc9DWA+fIagZ
3PRZunEIJlWYRtksMCdsiHMOCeUt2alz4XMYLb0ng+dHEmjnQEWPGPbKMBUnIM0t
g5yKZCJ0i/FG+to27+hio9dzG4K/bRLvwlFswLZRfEcvqkBXpQ+aATUNA7jQpRxp
e6sWAhpiS+tn2nMniLI+voe0W+v0s+5XLtDRX7LFUQKBgQDQhBTcKXXdnykIOslm
p9D+rFaUf10aXpFz3aq0jjy5lHkCXOPc1NTG29e7Ysi8xKwlZdSca6l+zu0zQf1m
cW4r/ejzwKM3qrLLeh4Hn7wpoWpliH5Z7BCdkTmeqGJI/9h1VxXgjc6j1DTGsyGb
nezNEsNEYmaSZZreConLVGHcuwKBgQDFet79wnbTnqPohySLJy4Q3j+zYXHs/+3I
dgRSg9Q/W2uE2ki58oDc10CRgGCet3iyXL5Pbq+QO/N50jpJHKow0DZqka3PTaLz
hqqj1FK08/Ual6cZ4TViZ09DE6TnQYXEKtdqakr+iNhNu1O4NQpvW+fjMUaSTqTy
DCfqMVrc2QKBgDc6JIRDfvJaC3Ygi+Nio1owryXZrgEj9wZnOaVk3vSQPJTBoaCF
xm19IOCCw4Qr2yR0miFr6pKpn+2plsIhXPrN33tgFFrUHVMDXxzJ0/56wEFwK3cJ
rUTuiAJbutx21xANJsA5DvgZZnkSTN54r5WJWKquHVi9DI2u4Nw310utAoGBALRm
m6DbbivB52A7XLHWF+oG7dBTu3xTDAitbyNmFJXQUPdrZTahBwE3jl+dFCbJ2nOt
75imt7EeYzytRNuXWQ4Al0VhUZNoC+1F30qMYwW1OvqRAXDN4DPFxo2zO1ia7bUX
ofQvp9TAdEEGWOOVaLP0FHDiieKL/3iyjCAP+D55AoGBAMKi7ZkIBqzRhknwp13v
iutRynDO8lXUeLxp/WhPj5Go5S7LbUxEwTlEikxAEdYqtCl7DMxWBgaDojxOahY6
LBuK53LWCG9y06laGy8gxbNJ86VbjpwwTm1eQeryPg/CSRPVb4G5Rhe4hZJEMdv3
Kt0IfWn4z2YLCtPtOrqMERSk
-----END PRIVATE KEY-----

View File

@ -8,6 +8,8 @@ TARGET = nymea-remoteproxy-tests
INCLUDEPATH += ../libnymea-remoteproxy
LIBS += -L$$top_builddir/libnymea-remoteproxy/ -lnymea-remoteproxy
RESOURCES += certificate.qrc
HEADERS += nymea-remoteproxy-tests.h
SOURCES += nymea-remoteproxy-tests.cpp