Add first online test
This commit is contained in:
parent
8f5cc9b6cb
commit
6622fa1265
2
.gitignore
vendored
2
.gitignore
vendored
@ -73,3 +73,5 @@ Thumbs.db
|
|||||||
|
|
||||||
coverage-html
|
coverage-html
|
||||||
client/nymea-remoteproxy-client
|
client/nymea-remoteproxy-client
|
||||||
|
tests/test-offline/nymea-remoteproxy-tests-offline
|
||||||
|
tests/test-online/nymea-remoteproxy-tests-online
|
||||||
|
|||||||
308
README.md
308
README.md
@ -0,0 +1,308 @@
|
|||||||
|
# nymea remote proxy server
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
The nymea remote proxy server is the meeting point of nymea servers and nymea clients in order to establishing a secure remote connection.
|
||||||
|
|
||||||
|
# Build
|
||||||
|
|
||||||
|
In order to build the proxy server you need to install the qt default package.
|
||||||
|
|
||||||
|
apt install qt5-default
|
||||||
|
|
||||||
|
Change into the source directory and run following commands
|
||||||
|
|
||||||
|
cd nymea-remoteproxy
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
qmake ../
|
||||||
|
make -j$(nproc)
|
||||||
|
|
||||||
|
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:$(pwd)/libnymea-remoteproxyclient
|
||||||
|
$ ./server/nymea-remoteproxy -c ../nymea-remoteproxy/tests/test-certificate.crt -k ../nymea-remoteproxy/tests/test-certificate.key
|
||||||
|
|
||||||
|
|
||||||
|
## AWS SDK
|
||||||
|
|
||||||
|
Get the latest source code and build dependecies
|
||||||
|
|
||||||
|
$ apt update
|
||||||
|
$ apt install git build-essential cmake libcurl4-openssl-dev libssl-dev uuid-dev zlib1g-dev libpulse-dev
|
||||||
|
|
||||||
|
$ git clone https://github.com/aws/aws-sdk-cpp.git
|
||||||
|
|
||||||
|
Create the build and install folder
|
||||||
|
|
||||||
|
$ cd aws-sdk-cpp
|
||||||
|
$ mkdir -p build/install
|
||||||
|
$ cd build
|
||||||
|
|
||||||
|
$ cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_ONLY="lambda" -DCMAKE_INSTALL_PREFIX=$(pwd)/install ../
|
||||||
|
$ make -j$(nproc)
|
||||||
|
|
||||||
|
Install build output into install directory
|
||||||
|
|
||||||
|
$ make install
|
||||||
|
|
||||||
|
#### Building debian package
|
||||||
|
|
||||||
|
$ git clone https://github.com/aws/aws-sdk-cpp.git
|
||||||
|
$ cd aws-sdk-cpp
|
||||||
|
|
||||||
|
$ git clone git@gitlab.guh.io:cloud/aws-sdk-cpp-debian.git debian
|
||||||
|
|
||||||
|
$ crossbuilder
|
||||||
|
|
||||||
|
|
||||||
|
# Install
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Configure
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Test
|
||||||
|
|
||||||
|
In order to run the test, you can call `make check` in the build directory or run the resulting executable:
|
||||||
|
|
||||||
|
$ nymea-remoteproxy-tests
|
||||||
|
|
||||||
|
|
||||||
|
## Test coverage report
|
||||||
|
|
||||||
|
If you want to create a line coverage report from the tests simply run following command in the source directory:
|
||||||
|
|
||||||
|
|
||||||
|
$ apt install lcov gcovr
|
||||||
|
$ ./create-coverage-html.sh
|
||||||
|
|
||||||
|
The resulting coverage report will be place in the `coverage-html` directory.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
In order to get information about the server you can start the command with the `--help` parameter.
|
||||||
|
|
||||||
|
$ nymea-remoteproxy --help
|
||||||
|
|
||||||
|
Usage: nymea-remoteproxy [options]
|
||||||
|
|
||||||
|
The nymea remote proxy server. This server allowes nymea-cloud users and registered nymea deamons to establish a tunnel connection.
|
||||||
|
|
||||||
|
Server version: 0.0.1
|
||||||
|
API version: 0.1
|
||||||
|
|
||||||
|
Copyright © 2018 Simon Stürz <simon.stuerz@guh.io>
|
||||||
|
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Displays this help.
|
||||||
|
-v, --version Displays version information.
|
||||||
|
-l, --logging <logfile> Write log file to the given logfile.
|
||||||
|
-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
|
||||||
|
used for this proxy server.
|
||||||
|
-a, --authentication-server <url> The server url of the AWS
|
||||||
|
authentication server.
|
||||||
|
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
## Message format
|
||||||
|
|
||||||
|
#### Request
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": integer,
|
||||||
|
"method": "Namespace.Method",
|
||||||
|
"o:params" { }
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Response
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": integer,
|
||||||
|
"status": "string",
|
||||||
|
"o:params" { },
|
||||||
|
"o:error": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Notification
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": integer,
|
||||||
|
"notification": "Namespace.Notification",
|
||||||
|
"o:params" { }
|
||||||
|
}
|
||||||
|
|
||||||
|
## Say Hello
|
||||||
|
|
||||||
|
#### Request
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"method": "RemoteProxy.Hello"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#### Response
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"params": {
|
||||||
|
"apiVersion": "0.1",
|
||||||
|
"name": "nymea-remoteproxy-testserver",
|
||||||
|
"server": "nymea-remoteproxy",
|
||||||
|
"version": "0.0.1"
|
||||||
|
},
|
||||||
|
"status": "success"
|
||||||
|
}
|
||||||
|
|
||||||
|
## Authenticate the connection
|
||||||
|
|
||||||
|
The first data a client **must** send to the proxy server is the authentication request. This request contains the token which will be verified agains the nymea-cloud infrastructure.
|
||||||
|
|
||||||
|
#### Request
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"method": "Authentication.Authenticate",
|
||||||
|
"params": {
|
||||||
|
"id": "string",
|
||||||
|
"name": "string",
|
||||||
|
"token": "tokenstring"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Response
|
||||||
|
|
||||||
|
* **On Success**: If the token was authenticated successfully, the response will look like this:
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"status": "success"
|
||||||
|
}
|
||||||
|
|
||||||
|
* **On Failure** If the token was invalid, the response will look like this and the server will close the connection immediatly:
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"status": "error",
|
||||||
|
"error": "Invalid token. You are not allowed to use this server."
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Tunnel established
|
||||||
|
|
||||||
|
Once the other client is here and ready, the server will send a notification to the clients indicating that the tunnel has been established successfully. This message is the last data comming from the proxy server.
|
||||||
|
|
||||||
|
> **Important:** Any data traffic following after this notification comes from the tunnel endpoint, __not__ from the __proxy server__ any more.
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": "0",
|
||||||
|
"notification": "RemoteProxy.TunnelEstablished",
|
||||||
|
"params": {
|
||||||
|
"name": "String",
|
||||||
|
"uuid": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## Introspect the API
|
||||||
|
|
||||||
|
|
||||||
|
#### Request
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"method": "RemoteProxy.Introspect"
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Response
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"params": {
|
||||||
|
"methods": {
|
||||||
|
"Authentication.Authenticate": {
|
||||||
|
"description": "Authenticate this connection. The returned AuthenticationError informs about the result. If the authentication was not successfull, the server will close the connection immediatly after sending the error response. The given id should be a unique id the other tunnel client can understand. Once the authentication was successfull, you can wait for the RemoteProxy.TunnelEstablished notification. If you send any data before getting this notification, the server will close the connection. If the tunnel client does not show up within 10 seconds, the server will close the connection.",
|
||||||
|
"params": {
|
||||||
|
"name": "String",
|
||||||
|
"token": "String",
|
||||||
|
"uuid": "String"
|
||||||
|
},
|
||||||
|
"returns": {
|
||||||
|
"authenticationError": "$ref:AuthenticationError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RemoteProxy.Hello": {
|
||||||
|
"description": "Once connected to this server, a client can get information about the server by saying Hello. The response informs the client about this proxy server.",
|
||||||
|
"params": {
|
||||||
|
},
|
||||||
|
"returns": {
|
||||||
|
"apiVersion": "String",
|
||||||
|
"name": "String",
|
||||||
|
"server": "String",
|
||||||
|
"version": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RemoteProxy.Introspect": {
|
||||||
|
"description": "Introspect this API.",
|
||||||
|
"params": {
|
||||||
|
},
|
||||||
|
"returns": {
|
||||||
|
"methods": "Object",
|
||||||
|
"notifications": "Object",
|
||||||
|
"types": "Object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"RemoteProxy.TunnelEstablished": {
|
||||||
|
"description": "Emitted whenever the tunnel has been established successfully. This is the last message from the remote proxy server! Any following data will be from the other tunnel client until the connection will be closed. The parameter contain some information about the other tunnel client.",
|
||||||
|
"params": {
|
||||||
|
"name": "String",
|
||||||
|
"uuid": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"types": {
|
||||||
|
"AuthenticationError": [
|
||||||
|
"AuthenticationErrorNoError",
|
||||||
|
"AuthenticationErrorUnknown",
|
||||||
|
"AuthenticationErrorTimeout",
|
||||||
|
"AuthenticationErrorAborted",
|
||||||
|
"AuthenticationErrorAuthenticationFailed",
|
||||||
|
"AuthenticationErrorAuthenticationServerNotResponding"
|
||||||
|
],
|
||||||
|
"BasicType": [
|
||||||
|
"Uuid",
|
||||||
|
"String",
|
||||||
|
"Int",
|
||||||
|
"UInt",
|
||||||
|
"Double",
|
||||||
|
"Bool",
|
||||||
|
"Variant",
|
||||||
|
"Object"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": "success"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
||||||
|
|
||||||
@ -4,7 +4,7 @@
|
|||||||
ProxyClient::ProxyClient(QObject *parent) :
|
ProxyClient::ProxyClient(QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
m_connection = new RemoteProxyConnection(QUuid::createUuid(), "nymea-remoteproxy-client", RemoteProxyConnection::ConnectionTypeWebSocket, this);
|
m_connection = new RemoteProxyConnection(QUuid::createUuid(), "nymea-remoteproxy-client", this);
|
||||||
m_connection->setInsecureConnection(true);
|
m_connection->setInsecureConnection(true);
|
||||||
connect(m_connection, &RemoteProxyConnection::ready, this, &ProxyClient::onClientReady);
|
connect(m_connection, &RemoteProxyConnection::ready, this, &ProxyClient::onClientReady);
|
||||||
connect(m_connection, &RemoteProxyConnection::authenticated, this, &ProxyClient::onAuthenticationFinished);
|
connect(m_connection, &RemoteProxyConnection::authenticated, this, &ProxyClient::onAuthenticationFinished);
|
||||||
|
|||||||
@ -8,9 +8,28 @@ qmake CONFIG+=coverage
|
|||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
make coverage-html
|
make coverage-html
|
||||||
|
|
||||||
# Clean up source directory
|
# Clean build
|
||||||
rm -v libnymea-remoteproxy/libnymea-remoteproxy.so*
|
|
||||||
rm -v libnymea-remoteproxyclient/libnymea-remoteproxyclient.so*
|
|
||||||
rm -v server/nymea-remoteproxy
|
|
||||||
rm -v tests/nymea-remoteproxy-tests
|
|
||||||
make clean
|
make clean
|
||||||
|
|
||||||
|
# Clean source directory
|
||||||
|
rm -v Makefile
|
||||||
|
|
||||||
|
rm -v libnymea-remoteproxy/libnymea-remoteproxy.so*
|
||||||
|
rm -v libnymea-remoteproxy/Makefile
|
||||||
|
|
||||||
|
rm -v libnymea-remoteproxyclient/libnymea-remoteproxyclient.so*
|
||||||
|
rm -v libnymea-remoteproxyclient/Makefile
|
||||||
|
|
||||||
|
rm -v server/nymea-remoteproxy
|
||||||
|
rm -v server/Makefile
|
||||||
|
|
||||||
|
rm -v tests/Makefile
|
||||||
|
|
||||||
|
rm -v tests/test-offline/nymea-remoteproxy-tests-offline
|
||||||
|
rm -v tests/test-offline/Makefile
|
||||||
|
|
||||||
|
rm -v tests/test-online/nymea-remoteproxy-tests-online
|
||||||
|
rm -v tests/test-online/Makefile
|
||||||
|
|
||||||
|
rm -v client/nymea-remoteproxy-client
|
||||||
|
rm -v client/Makefile
|
||||||
|
|||||||
0
copyright → debian/copyright
vendored
0
copyright → debian/copyright
vendored
@ -52,7 +52,7 @@ void AuthenticationReply::onTimeout()
|
|||||||
m_error = Authenticator::AuthenticationErrorTimeout;
|
m_error = Authenticator::AuthenticationErrorTimeout;
|
||||||
m_timer->stop();
|
m_timer->stop();
|
||||||
m_process->kill();
|
m_process->kill();
|
||||||
emit finished();
|
QTimer::singleShot(0, this, &AuthenticationReply::finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuthenticationReply::abort()
|
void AuthenticationReply::abort()
|
||||||
@ -60,7 +60,7 @@ void AuthenticationReply::abort()
|
|||||||
m_error = Authenticator::AuthenticationErrorAborted;
|
m_error = Authenticator::AuthenticationErrorAborted;
|
||||||
m_timer->stop();
|
m_timer->stop();
|
||||||
m_process->kill();
|
m_process->kill();
|
||||||
emit finished();
|
QTimer::singleShot(0, this, &AuthenticationReply::finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ void AwsAuthenticator::onAuthenticationProcessFinished(Authenticator::Authentica
|
|||||||
setReplyError(reply, error);
|
setReplyError(reply, error);
|
||||||
setReplyFinished(reply);
|
setReplyFinished(reply);
|
||||||
|
|
||||||
qCDebug(dcAuthentication()) << "" << error;
|
qCDebug(dcAuthentication()) << name() << "finished with error" << error;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthenticationReply *AwsAuthenticator::authenticate(ProxyClient *proxyClient)
|
AuthenticationReply *AwsAuthenticator::authenticate(ProxyClient *proxyClient)
|
||||||
|
|||||||
@ -32,9 +32,6 @@ bool Engine::exists()
|
|||||||
|
|
||||||
void Engine::start(ProxyConfiguration *configuration)
|
void Engine::start(ProxyConfiguration *configuration)
|
||||||
{
|
{
|
||||||
// Make sure an authenticator was registered
|
|
||||||
Q_ASSERT_X(m_authenticator != nullptr, "Engine", "There is no authenticator registerd.");
|
|
||||||
|
|
||||||
if (!m_running)
|
if (!m_running)
|
||||||
qCDebug(dcEngine()) << "Start server engine";
|
qCDebug(dcEngine()) << "Start server engine";
|
||||||
|
|
||||||
@ -42,10 +39,13 @@ void Engine::start(ProxyConfiguration *configuration)
|
|||||||
clean();
|
clean();
|
||||||
|
|
||||||
m_configuration = configuration;
|
m_configuration = configuration;
|
||||||
Q_ASSERT_X(configuration != nullptr, "Engine", "There is no configuration set.");
|
qCDebug(dcApplication()) << "Using configuration" << m_configuration;
|
||||||
|
|
||||||
|
// Make sure an authenticator was registered
|
||||||
|
Q_ASSERT_X(m_authenticator != nullptr, "Engine", "There is no authenticator registerd.");
|
||||||
|
|
||||||
m_proxyServer = new ProxyServer(this);
|
m_proxyServer = new ProxyServer(this);
|
||||||
m_webSocketServer = new WebSocketServer(m_sslConfiguration, this);
|
m_webSocketServer = new WebSocketServer(m_configuration->sslConfiguration(), this);
|
||||||
|
|
||||||
QUrl websocketServerUrl;
|
QUrl websocketServerUrl;
|
||||||
websocketServerUrl.setScheme("wss");
|
websocketServerUrl.setScheme("wss");
|
||||||
@ -84,32 +84,7 @@ bool Engine::developerMode() const
|
|||||||
|
|
||||||
QString Engine::serverName() const
|
QString Engine::serverName() const
|
||||||
{
|
{
|
||||||
return m_serverName;
|
return m_configuration->serverName();
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::setServerName(const QString &serverName)
|
|
||||||
{
|
|
||||||
m_serverName = serverName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::setConfiguration(ProxyConfiguration *configuration)
|
|
||||||
{
|
|
||||||
m_configuration = configuration;
|
|
||||||
qCDebug(dcApplication()) << "Set configuration" << m_configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::setSslConfiguration(const QSslConfiguration &configuration)
|
|
||||||
{
|
|
||||||
m_sslConfiguration = configuration;
|
|
||||||
|
|
||||||
qCDebug(dcEngine()) << "SSL certificate information:";
|
|
||||||
qCDebug(dcEngine()) << " Common name:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::CommonName);
|
|
||||||
qCDebug(dcEngine()) << " Organisation:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::Organization);
|
|
||||||
qCDebug(dcEngine()) << " Organisation unit name:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::OrganizationalUnitName);
|
|
||||||
qCDebug(dcEngine()) << " Country name:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::CountryName);
|
|
||||||
qCDebug(dcEngine()) << " Locality name:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::LocalityName);
|
|
||||||
qCDebug(dcEngine()) << " State/Province:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::StateOrProvinceName);
|
|
||||||
qCDebug(dcEngine()) << " Email address:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::EmailAddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::setAuthenticator(Authenticator *authenticator)
|
void Engine::setAuthenticator(Authenticator *authenticator)
|
||||||
|
|||||||
@ -29,12 +29,8 @@ public:
|
|||||||
bool developerMode() const;
|
bool developerMode() const;
|
||||||
|
|
||||||
QString serverName() const;
|
QString serverName() const;
|
||||||
void setServerName(const QString &serverName);
|
|
||||||
|
|
||||||
void setConfiguration(ProxyConfiguration *configuration);
|
|
||||||
void setSslConfiguration(const QSslConfiguration &configuration);
|
|
||||||
void setAuthenticator(Authenticator *authenticator);
|
void setAuthenticator(Authenticator *authenticator);
|
||||||
|
|
||||||
void setDeveloperModeEnabled(bool enabled);
|
void setDeveloperModeEnabled(bool enabled);
|
||||||
|
|
||||||
Authenticator *authenticator() const;
|
Authenticator *authenticator() const;
|
||||||
@ -48,9 +44,7 @@ private:
|
|||||||
|
|
||||||
bool m_running = false;
|
bool m_running = false;
|
||||||
bool m_developerMode = false;
|
bool m_developerMode = false;
|
||||||
QString m_serverName;
|
|
||||||
|
|
||||||
QSslConfiguration m_sslConfiguration;
|
|
||||||
ProxyConfiguration *m_configuration = nullptr;
|
ProxyConfiguration *m_configuration = nullptr;
|
||||||
Authenticator *m_authenticator = nullptr;
|
Authenticator *m_authenticator = nullptr;
|
||||||
ProxyServer *m_proxyServer = nullptr;
|
ProxyServer *m_proxyServer = nullptr;
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
#include "proxyconfiguration.h"
|
#include "proxyconfiguration.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QSslKey>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QSslCertificate>
|
||||||
|
|
||||||
namespace remoteproxy {
|
namespace remoteproxy {
|
||||||
|
|
||||||
@ -26,6 +29,7 @@ bool ProxyConfiguration::loadConfiguration(const QString &fileName)
|
|||||||
|
|
||||||
QSettings settings(fileName, QSettings::IniFormat);
|
QSettings settings(fileName, QSettings::IniFormat);
|
||||||
|
|
||||||
|
setServerName(settings.value("name", "nymea-remoteproxy").toString());
|
||||||
setWriteLogFile(settings.value("writeLogs", false).toBool());
|
setWriteLogFile(settings.value("writeLogs", false).toBool());
|
||||||
setLogFileName(settings.value("logFile", "/var/log/nymea-remoteproxy.log").toString());
|
setLogFileName(settings.value("logFile", "/var/log/nymea-remoteproxy.log").toString());
|
||||||
setSslCertificateFileName(settings.value("certificate", "/etc/ssl/certs/ssl-cert-snakeoil.pem").toString());
|
setSslCertificateFileName(settings.value("certificate", "/etc/ssl/certs/ssl-cert-snakeoil.pem").toString());
|
||||||
@ -41,9 +45,50 @@ bool ProxyConfiguration::loadConfiguration(const QString &fileName)
|
|||||||
setTcpServerPort(static_cast<quint16>(settings.value("port", 1213).toInt()));
|
setTcpServerPort(static_cast<quint16>(settings.value("port", 1213).toInt()));
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
|
// Load ssl configuration
|
||||||
|
QSslConfiguration sslConfiguration;
|
||||||
|
// Load certificate
|
||||||
|
QFile certFile(sslCertificateFileName());
|
||||||
|
if (!certFile.open(QIODevice::ReadOnly)) {
|
||||||
|
qCWarning(dcApplication()) << "Could not open certificate file" << sslCertificateFileName() << certFile.errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSslCertificate certificate(&certFile, QSsl::Pem);
|
||||||
|
qCDebug(dcApplication()) << "Loaded successfully certificate" << sslCertificateFileName();
|
||||||
|
certFile.close();
|
||||||
|
|
||||||
|
// Create SSL configuration
|
||||||
|
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||||
|
sslConfiguration.setLocalCertificate(certificate);
|
||||||
|
sslConfiguration.setProtocol(QSsl::TlsV1_2OrLater);
|
||||||
|
|
||||||
|
// SSL key
|
||||||
|
QFile certKeyFile(sslCertificateKeyFileName());
|
||||||
|
if (!certKeyFile.open(QIODevice::ReadOnly)) {
|
||||||
|
qCWarning(dcApplication()) << "Could not open certificate key file:" << sslCertificateKeyFileName() << certKeyFile.errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSslKey sslKey(&certKeyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
|
||||||
|
qCDebug(dcApplication()) << "Loaded successfully certificate key" << sslCertificateKeyFileName();
|
||||||
|
certKeyFile.close();
|
||||||
|
sslConfiguration.setPrivateKey(sslKey);
|
||||||
|
m_sslConfiguration = sslConfiguration;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ProxyConfiguration::serverName() const
|
||||||
|
{
|
||||||
|
return m_serverName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyConfiguration::setServerName(const QString &serverName)
|
||||||
|
{
|
||||||
|
m_serverName = serverName;
|
||||||
|
}
|
||||||
|
|
||||||
bool ProxyConfiguration::writeLogFile() const
|
bool ProxyConfiguration::writeLogFile() const
|
||||||
{
|
{
|
||||||
return m_writeLogFile;
|
return m_writeLogFile;
|
||||||
@ -84,6 +129,11 @@ void ProxyConfiguration::setSslCertificateKeyFileName(const QString &fileName)
|
|||||||
m_sslCertificateKeyFileName = fileName;
|
m_sslCertificateKeyFileName = fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSslConfiguration ProxyConfiguration::sslConfiguration() const
|
||||||
|
{
|
||||||
|
return m_sslConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
QHostAddress ProxyConfiguration::webSocketServerHost() const
|
QHostAddress ProxyConfiguration::webSocketServerHost() const
|
||||||
{
|
{
|
||||||
return m_webSocketServerHost;
|
return m_webSocketServerHost;
|
||||||
@ -128,10 +178,19 @@ QDebug operator<<(QDebug debug, ProxyConfiguration *configuration)
|
|||||||
{
|
{
|
||||||
debug.nospace() << endl << "========== ProxyConfiguration ==========" << endl;
|
debug.nospace() << endl << "========== ProxyConfiguration ==========" << endl;
|
||||||
debug.nospace() << "General" << endl;
|
debug.nospace() << "General" << endl;
|
||||||
|
debug.nospace() << " - name:" << configuration->serverName() << endl;
|
||||||
debug.nospace() << " - write logfile:" << configuration->writeLogFile() << endl;
|
debug.nospace() << " - write logfile:" << configuration->writeLogFile() << endl;
|
||||||
debug.nospace() << " - logfile:" << configuration->logFileName() << endl;
|
debug.nospace() << " - logfile:" << configuration->logFileName() << endl;
|
||||||
debug.nospace() << " - certificate:" << configuration->sslCertificateFileName() << endl;
|
debug.nospace() << " - certificate:" << configuration->sslCertificateFileName() << endl;
|
||||||
debug.nospace() << " - certificate key:" << configuration->sslCertificateKeyFileName() << endl;
|
debug.nospace() << " - certificate key:" << configuration->sslCertificateKeyFileName() << endl;
|
||||||
|
debug.nospace() << " - SSL certificate information:";
|
||||||
|
debug.nospace() << " Common name:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::CommonName);
|
||||||
|
debug.nospace() << " Organisation:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::Organization);
|
||||||
|
debug.nospace() << " Organisation unit name:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::OrganizationalUnitName);
|
||||||
|
debug.nospace() << " Country name:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::CountryName);
|
||||||
|
debug.nospace() << " Locality name:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::LocalityName);
|
||||||
|
debug.nospace() << " State/Province:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::StateOrProvinceName);
|
||||||
|
debug.nospace() << " Email address:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::EmailAddress);
|
||||||
debug.nospace() << "WebSocketServer" << endl;
|
debug.nospace() << "WebSocketServer" << endl;
|
||||||
debug.nospace() << " - host:" << configuration->webSocketServerHost().toString() << endl;
|
debug.nospace() << " - host:" << configuration->webSocketServerHost().toString() << endl;
|
||||||
debug.nospace() << " - port:" << configuration->webSocketServerPort() << endl;
|
debug.nospace() << " - port:" << configuration->webSocketServerPort() << endl;
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
|
#include <QSslConfiguration>
|
||||||
|
|
||||||
namespace remoteproxy {
|
namespace remoteproxy {
|
||||||
|
|
||||||
@ -16,6 +17,9 @@ public:
|
|||||||
bool loadConfiguration(const QString &fileName);
|
bool loadConfiguration(const QString &fileName);
|
||||||
|
|
||||||
// General
|
// General
|
||||||
|
QString serverName() const;
|
||||||
|
void setServerName(const QString &serverName);
|
||||||
|
|
||||||
bool writeLogFile() const;
|
bool writeLogFile() const;
|
||||||
void setWriteLogFile(bool enabled);
|
void setWriteLogFile(bool enabled);
|
||||||
|
|
||||||
@ -28,6 +32,8 @@ public:
|
|||||||
QString sslCertificateKeyFileName() const;
|
QString sslCertificateKeyFileName() const;
|
||||||
void setSslCertificateKeyFileName(const QString &fileName);
|
void setSslCertificateKeyFileName(const QString &fileName);
|
||||||
|
|
||||||
|
QSslConfiguration sslConfiguration() const;
|
||||||
|
|
||||||
// WebSocketServer
|
// WebSocketServer
|
||||||
QHostAddress webSocketServerHost() const;
|
QHostAddress webSocketServerHost() const;
|
||||||
void setWebSocketServerHost(const QHostAddress &address);
|
void setWebSocketServerHost(const QHostAddress &address);
|
||||||
@ -44,10 +50,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// General
|
// General
|
||||||
|
QString m_serverName;
|
||||||
bool m_writeLogFile = false;
|
bool m_writeLogFile = false;
|
||||||
QString m_logFileName = "/var/log/nymea-remoteproxy.log";
|
QString m_logFileName = "/var/log/nymea-remoteproxy.log";
|
||||||
QString m_sslCertificateFileName = "/etc/ssl/certs/ssl-cert-snakeoil.pem";
|
QString m_sslCertificateFileName = "/etc/ssl/certs/ssl-cert-snakeoil.pem";
|
||||||
QString m_sslCertificateKeyFileName = "/etc/ssl/private/ssl-cert-snakeoil.key";
|
QString m_sslCertificateKeyFileName = "/etc/ssl/private/ssl-cert-snakeoil.key";
|
||||||
|
QSslConfiguration m_sslConfiguration;
|
||||||
|
|
||||||
// WebSocketServer
|
// WebSocketServer
|
||||||
QHostAddress m_webSocketServerHost = QHostAddress::LocalHost;
|
QHostAddress m_webSocketServerHost = QHostAddress::LocalHost;
|
||||||
|
|||||||
@ -46,7 +46,7 @@ void WebSocketServer::sendData(const QUuid &clientId, const QByteArray &data)
|
|||||||
client = m_clientList.value(clientId);
|
client = m_clientList.value(clientId);
|
||||||
if (client) {
|
if (client) {
|
||||||
qCDebug(dcWebSocketServerTraffic()) << "--> Sending data to client:" << data;
|
qCDebug(dcWebSocketServerTraffic()) << "--> Sending data to client:" << data;
|
||||||
client->sendTextMessage(data + '\n');
|
client->sendTextMessage(data);
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcWebSocketServer()) << "Client" << clientId << "unknown to this transport";
|
qCWarning(dcWebSocketServer()) << "Client" << clientId << "unknown to this transport";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ JsonReply *JsonRpcClient::callAuthenticate(const QUuid &clientUuid, const QStrin
|
|||||||
params.insert("token", token);
|
params.insert("token", token);
|
||||||
|
|
||||||
JsonReply *reply = new JsonReply(m_commandId, "Authentication", "Authenticate", params, this);
|
JsonReply *reply = new JsonReply(m_commandId, "Authentication", "Authenticate", params, this);
|
||||||
qCDebug(dcRemoteProxyClientJsonRpc()) << "Calling" << QString("%1.%2").arg(reply->nameSpace()).arg(reply->method()) << params;
|
qCDebug(dcRemoteProxyClientJsonRpc()) << "Calling" << QString("%1.%2").arg(reply->nameSpace()).arg(reply->method()) << reply->params();
|
||||||
sendRequest(reply->requestMap());
|
sendRequest(reply->requestMap());
|
||||||
m_replies.insert(m_commandId, reply);
|
m_replies.insert(m_commandId, reply);
|
||||||
return reply;
|
return reply;
|
||||||
@ -45,11 +45,6 @@ void JsonRpcClient::sendRequest(const QVariantMap &request)
|
|||||||
m_connection->sendData(data);
|
m_connection->sendData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonRpcClient::onConnectedChanged(bool connected)
|
|
||||||
{
|
|
||||||
Q_UNUSED(connected)
|
|
||||||
}
|
|
||||||
|
|
||||||
void JsonRpcClient::processData(const QByteArray &data)
|
void JsonRpcClient::processData(const QByteArray &data)
|
||||||
{
|
{
|
||||||
qCDebug(dcRemoteProxyClientJsonRpcTraffic()) << "Received data:" << qUtf8Printable(data);
|
qCDebug(dcRemoteProxyClientJsonRpcTraffic()) << "Received data:" << qUtf8Printable(data);
|
||||||
|
|||||||
@ -36,7 +36,6 @@ signals:
|
|||||||
void tunnelEstablished(const QString clientName, const QString &clientUuid);
|
void tunnelEstablished(const QString clientName, const QString &clientUuid);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onConnectedChanged(bool connected);
|
|
||||||
void processData(const QByteArray &data);
|
void processData(const QByteArray &data);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
#include "remoteproxyconnection.h"
|
|
||||||
#include "websocketconnection.h"
|
|
||||||
#include "proxyjsonrpcclient.h"
|
|
||||||
#include "proxyconnection.h"
|
#include "proxyconnection.h"
|
||||||
|
#include "proxyjsonrpcclient.h"
|
||||||
|
#include "websocketconnection.h"
|
||||||
|
#include "remoteproxyconnection.h"
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(dcRemoteProxyClientConnection, "RemoteProxyClientConnection")
|
Q_LOGGING_CATEGORY(dcRemoteProxyClientConnection, "RemoteProxyClientConnection")
|
||||||
Q_LOGGING_CATEGORY(dcRemoteProxyClientConnectionTraffic, "RemoteProxyClientConnectionTraffic")
|
Q_LOGGING_CATEGORY(dcRemoteProxyClientConnectionTraffic, "RemoteProxyClientConnectionTraffic")
|
||||||
|
|
||||||
namespace remoteproxyclient {
|
namespace remoteproxyclient {
|
||||||
|
|
||||||
RemoteProxyConnection::RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, ConnectionType connectionType, QObject *parent) :
|
RemoteProxyConnection::RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_connectionType(connectionType),
|
|
||||||
m_clientUuid(clientUuid),
|
m_clientUuid(clientUuid),
|
||||||
m_clientName(clientName)
|
m_clientName(clientName)
|
||||||
{
|
{
|
||||||
@ -82,6 +81,11 @@ RemoteProxyConnection::ConnectionType RemoteProxyConnection::connectionType() co
|
|||||||
return m_connectionType;
|
return m_connectionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoteProxyConnection::setConnectionType(RemoteProxyConnection::ConnectionType connectionType)
|
||||||
|
{
|
||||||
|
m_connectionType = connectionType;
|
||||||
|
}
|
||||||
|
|
||||||
QHostAddress RemoteProxyConnection::serverAddress() const
|
QHostAddress RemoteProxyConnection::serverAddress() const
|
||||||
{
|
{
|
||||||
return m_serverAddress;
|
return m_serverAddress;
|
||||||
@ -150,7 +154,6 @@ void RemoteProxyConnection::cleanUp()
|
|||||||
m_connection = nullptr;
|
m_connection = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_error = ErrorNoError;
|
|
||||||
m_serverName = QString();
|
m_serverName = QString();
|
||||||
m_proxyServerName = QString();
|
m_proxyServerName = QString();
|
||||||
m_proxyServerVersion = QString();
|
m_proxyServerVersion = QString();
|
||||||
@ -164,8 +167,8 @@ void RemoteProxyConnection::setState(RemoteProxyConnection::State state)
|
|||||||
if (m_state == state)
|
if (m_state == state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qCDebug(dcRemoteProxyClientConnection()) << "State changed" << state;
|
|
||||||
m_state = state;
|
m_state = state;
|
||||||
|
qCDebug(dcRemoteProxyClientConnection()) << "State changed" << m_state;
|
||||||
emit stateChanged(m_state);
|
emit stateChanged(m_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,8 +177,8 @@ void RemoteProxyConnection::setError(RemoteProxyConnection::Error error)
|
|||||||
if (m_error == error)
|
if (m_error == error)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qCDebug(dcRemoteProxyClientConnection()) << "Error occured" << error;
|
|
||||||
m_error = error;
|
m_error = error;
|
||||||
|
qCDebug(dcRemoteProxyClientConnection()) << "Error occured" << m_error << errorString();
|
||||||
emit errorOccured(m_error);
|
emit errorOccured(m_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +237,7 @@ void RemoteProxyConnection::onHelloFinished()
|
|||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|
||||||
QVariantMap response = reply->response();
|
QVariantMap response = reply->response();
|
||||||
qCDebug(dcRemoteProxyClientConnection()) << "Hello response ready" << response;
|
qCDebug(dcRemoteProxyClientConnectionTraffic()) << "Hello response ready" << reply->commandId() << response;
|
||||||
|
|
||||||
if (response.value("status").toString() != "success") {
|
if (response.value("status").toString() != "success") {
|
||||||
qCWarning(dcRemoteProxyClientConnection()) << "Could not get initial information from proxy server.";
|
qCWarning(dcRemoteProxyClientConnection()) << "Could not get initial information from proxy server.";
|
||||||
@ -258,12 +261,21 @@ void RemoteProxyConnection::onHelloFinished()
|
|||||||
void RemoteProxyConnection::onAuthenticateFinished()
|
void RemoteProxyConnection::onAuthenticateFinished()
|
||||||
{
|
{
|
||||||
JsonReply *reply = static_cast<JsonReply *>(sender());
|
JsonReply *reply = static_cast<JsonReply *>(sender());
|
||||||
QVariantMap response = reply->response();
|
reply->deleteLater();
|
||||||
qCDebug(dcRemoteProxyClientConnection()) << "Authentication response ready" << response;
|
|
||||||
|
|
||||||
// TODO: verify success
|
QVariantMap response = reply->response();
|
||||||
setState(StateWaitTunnel);
|
qCDebug(dcRemoteProxyClientConnectionTraffic()) << "Authentication response ready" << reply->commandId() << response;
|
||||||
emit authenticated();
|
|
||||||
|
QVariantMap responseParams = response.value("params").toMap();
|
||||||
|
if (responseParams.value("authenticationError").toString() != "AuthenticationErrorNoError") {
|
||||||
|
qCWarning(dcRemoteProxyClientConnection()) << "Authentication request finished with error" << responseParams.value("authenticationError").toString();
|
||||||
|
setError(RemoteProxyConnection::ErrorProxyAuthenticationFailed);
|
||||||
|
m_connection->disconnectServer();
|
||||||
|
} else {
|
||||||
|
qCDebug(dcRemoteProxyClientConnection()) << "Successfully authenticated.";
|
||||||
|
setState(StateWaitTunnel);
|
||||||
|
emit authenticated();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyConnection::onTunnelEstablished(const QString &clientName, const QString &clientUuid)
|
void RemoteProxyConnection::onTunnelEstablished(const QString &clientName, const QString &clientUuid)
|
||||||
@ -277,6 +289,7 @@ bool RemoteProxyConnection::connectServer(const QHostAddress &serverAddress, qui
|
|||||||
{
|
{
|
||||||
m_serverAddress = serverAddress;
|
m_serverAddress = serverAddress;
|
||||||
m_serverPort = port;
|
m_serverPort = port;
|
||||||
|
m_error = ErrorNoError;
|
||||||
|
|
||||||
cleanUp();
|
cleanUp();
|
||||||
|
|
||||||
@ -295,7 +308,7 @@ bool RemoteProxyConnection::connectServer(const QHostAddress &serverAddress, qui
|
|||||||
m_jsonClient = new JsonRpcClient(m_connection, this);
|
m_jsonClient = new JsonRpcClient(m_connection, this);
|
||||||
connect(m_jsonClient, &JsonRpcClient::tunnelEstablished, this, &RemoteProxyConnection::onTunnelEstablished);
|
connect(m_jsonClient, &JsonRpcClient::tunnelEstablished, this, &RemoteProxyConnection::onTunnelEstablished);
|
||||||
|
|
||||||
qCDebug(dcRemoteProxyClientConnection()) << "Connecting to" << m_connection->serverUrl().toString();
|
qCDebug(dcRemoteProxyClientConnection()) << "Connecting to" << QString("%1:%2").arg(serverAddress.toString()).arg(port);
|
||||||
m_connection->connectServer(serverAddress, port);
|
m_connection->connectServer(serverAddress, port);
|
||||||
|
|
||||||
setState(StateConnecting);
|
setState(StateConnecting);
|
||||||
|
|||||||
@ -46,7 +46,7 @@ public:
|
|||||||
};
|
};
|
||||||
Q_ENUM(Error)
|
Q_ENUM(Error)
|
||||||
|
|
||||||
explicit RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, ConnectionType connectionType = RemoteProxyConnection::ConnectionTypeWebSocket, QObject *parent = nullptr);
|
explicit RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, QObject *parent = nullptr);
|
||||||
~RemoteProxyConnection();
|
~RemoteProxyConnection();
|
||||||
|
|
||||||
RemoteProxyConnection::State state() const;
|
RemoteProxyConnection::State state() const;
|
||||||
@ -58,6 +58,8 @@ public:
|
|||||||
bool isRemoteConnected() const;
|
bool isRemoteConnected() const;
|
||||||
|
|
||||||
RemoteProxyConnection::ConnectionType connectionType() const;
|
RemoteProxyConnection::ConnectionType connectionType() const;
|
||||||
|
void setConnectionType(RemoteProxyConnection::ConnectionType connectionType);
|
||||||
|
|
||||||
QHostAddress serverAddress() const;
|
QHostAddress serverAddress() const;
|
||||||
quint16 serverPort() const;
|
quint16 serverPort() const;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
[General]
|
name=nymea-remoteproxy
|
||||||
writeLogs=false
|
writeLogs=false
|
||||||
logFile=/var/log/nymea-remoteproxy.log
|
logFile=/var/log/nymea-remoteproxy.log
|
||||||
certificate=/etc/ssl/certs/ssl-cert-snakeoil.pem
|
certificate=/etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||||
|
|||||||
@ -167,37 +167,8 @@ int main(int argc, char *argv[])
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SSL certificate
|
// Verify SSL configuration
|
||||||
QSslConfiguration sslConfiguration;
|
if (configuration->sslConfiguration().isNull()) {
|
||||||
// Load certificate
|
|
||||||
QFile certFile(configuration->sslCertificateFileName());
|
|
||||||
if (!certFile.open(QIODevice::ReadOnly)) {
|
|
||||||
qCCritical(dcApplication()) << "Could not open certificate file" << configuration->sslCertificateFileName() << certFile.errorString();
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
QSslCertificate certificate(&certFile, QSsl::Pem);
|
|
||||||
qCDebug(dcApplication()) << "Loaded successfully certificate" << configuration->sslCertificateFileName();
|
|
||||||
certFile.close();
|
|
||||||
|
|
||||||
// Create SSL configuration
|
|
||||||
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
|
|
||||||
sslConfiguration.setLocalCertificate(certificate);
|
|
||||||
sslConfiguration.setProtocol(QSsl::TlsV1_2OrLater);
|
|
||||||
|
|
||||||
// SSL key
|
|
||||||
QFile certKeyFile(configuration->sslCertificateKeyFileName());
|
|
||||||
if (!certKeyFile.open(QIODevice::ReadOnly)) {
|
|
||||||
qCCritical(dcApplication()) << "Could not open certificate key file:" << configuration->sslCertificateKeyFileName() << certKeyFile.errorString();
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
QSslKey sslKey(&certKeyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
|
|
||||||
qCDebug(dcApplication()) << "Loaded successfully certificate key" << configuration->sslCertificateKeyFileName();
|
|
||||||
certKeyFile.close();
|
|
||||||
sslConfiguration.setPrivateKey(sslKey);
|
|
||||||
|
|
||||||
if (sslConfiguration.isNull()) {
|
|
||||||
qCCritical(dcApplication()) << "No SSL configuration specified. The server does not suppoert insecure connections.";
|
qCCritical(dcApplication()) << "No SSL configuration specified. The server does not suppoert insecure connections.";
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
@ -224,11 +195,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure and start the engines
|
// Configure and start the engines
|
||||||
Engine::instance()->setConfiguration(configuration);
|
|
||||||
Engine::instance()->setDeveloperModeEnabled(parser.isSet(developmentOption));
|
|
||||||
Engine::instance()->setSslConfiguration(sslConfiguration);
|
|
||||||
Engine::instance()->setAuthenticator(authenticator);
|
Engine::instance()->setAuthenticator(authenticator);
|
||||||
|
Engine::instance()->setDeveloperModeEnabled(parser.isSet(developmentOption));
|
||||||
Engine::instance()->start(configuration);
|
Engine::instance()->start(configuration);
|
||||||
|
|
||||||
return application.exec();
|
return application.exec();
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
include(../../nymea-remoteproxy.pri)
|
|
||||||
|
|
||||||
@ -2,5 +2,6 @@
|
|||||||
<qresource>
|
<qresource>
|
||||||
<file>test-certificate.crt</file>
|
<file>test-certificate.crt</file>
|
||||||
<file>test-certificate.key</file>
|
<file>test-certificate.key</file>
|
||||||
|
<file>test-configuration.conf</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
13
tests/resources/test-configuration.conf
Normal file
13
tests/resources/test-configuration.conf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
name=test-nymea-remoteproxy
|
||||||
|
writeLogs=false
|
||||||
|
logFile=/var/log/nymea-remoteproxy.log
|
||||||
|
certificate=:/test-certificate.crt
|
||||||
|
certificateKey=:/test-certificate.key
|
||||||
|
|
||||||
|
[WebSocketServer]
|
||||||
|
host=127.0.0.1
|
||||||
|
port=1212
|
||||||
|
|
||||||
|
[TcpServer]
|
||||||
|
host=127.0.0.1
|
||||||
|
port=1213
|
||||||
@ -10,27 +10,24 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QWebSocketServer>
|
#include <QWebSocketServer>
|
||||||
|
|
||||||
RemoteProxyTests::RemoteProxyTests(QObject *parent) :
|
RemoteProxyOfflineTests::RemoteProxyOfflineTests(QObject *parent) :
|
||||||
BaseTest(parent)
|
BaseTest(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::startStopServer()
|
void RemoteProxyOfflineTests::startStopServer()
|
||||||
{
|
{
|
||||||
startServer();
|
startServer();
|
||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::dummyAuthenticator()
|
void RemoteProxyOfflineTests::dummyAuthenticator()
|
||||||
{
|
{
|
||||||
cleanUpEngine();
|
cleanUpEngine();
|
||||||
DummyAuthenticator *dummyAuthenticator = new DummyAuthenticator(this);
|
|
||||||
|
|
||||||
// Start proxy webserver
|
// Start proxy webserver
|
||||||
Engine::instance()->setAuthenticator(dummyAuthenticator);
|
Engine::instance()->setAuthenticator(m_dummyAuthenticator);
|
||||||
Engine::instance()->setSslConfiguration(m_sslConfiguration);
|
|
||||||
|
|
||||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||||
Engine::instance()->start(m_configuration);
|
Engine::instance()->start(m_configuration);
|
||||||
runningSpy.wait();
|
runningSpy.wait();
|
||||||
@ -53,22 +50,18 @@ void RemoteProxyTests::dummyAuthenticator()
|
|||||||
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
||||||
verifyAuthenticationError(response);
|
verifyAuthenticationError(response);
|
||||||
|
|
||||||
dummyAuthenticator->deleteLater();
|
|
||||||
cleanUpEngine();
|
cleanUpEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::webserverConnectionBlocked()
|
void RemoteProxyOfflineTests::webserverConnectionBlocked()
|
||||||
{
|
{
|
||||||
// Create a dummy server which blocks the port
|
// Create a dummy server which blocks the port
|
||||||
QWebSocketServer dummyServer("dummy-server", QWebSocketServer::NonSecureMode);
|
QWebSocketServer dummyServer("dummy-server", QWebSocketServer::NonSecureMode);
|
||||||
dummyServer.listen(QHostAddress::LocalHost, m_port);
|
dummyServer.listen(QHostAddress::LocalHost, m_port);
|
||||||
|
|
||||||
// Start proxy webserver
|
// Start proxy webserver
|
||||||
Engine::instance()->setConfiguration(m_configuration);
|
|
||||||
Engine::instance()->setAuthenticator(m_authenticator);
|
|
||||||
Engine::instance()->setSslConfiguration(m_sslConfiguration);
|
|
||||||
|
|
||||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||||
|
Engine::instance()->setAuthenticator(m_authenticator);
|
||||||
Engine::instance()->start(m_configuration);
|
Engine::instance()->start(m_configuration);
|
||||||
runningSpy.wait();
|
runningSpy.wait();
|
||||||
|
|
||||||
@ -93,12 +86,7 @@ void RemoteProxyTests::webserverConnectionBlocked()
|
|||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::webserverConnection()
|
void RemoteProxyOfflineTests::getIntrospect()
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteProxyTests::getIntrospect()
|
|
||||||
{
|
{
|
||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
@ -110,7 +98,7 @@ void RemoteProxyTests::getIntrospect()
|
|||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::getHello()
|
void RemoteProxyOfflineTests::getHello()
|
||||||
{
|
{
|
||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
@ -122,7 +110,7 @@ void RemoteProxyTests::getHello()
|
|||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::apiBasicCalls_data()
|
void RemoteProxyOfflineTests::apiBasicCalls_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QByteArray>("data");
|
QTest::addColumn<QByteArray>("data");
|
||||||
QTest::addColumn<bool>("valid");
|
QTest::addColumn<bool>("valid");
|
||||||
@ -137,7 +125,7 @@ void RemoteProxyTests::apiBasicCalls_data()
|
|||||||
QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\", \"params\":{\"törööö\":\"chooo-chooo\"}}") << false;
|
QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\", \"params\":{\"törööö\":\"chooo-chooo\"}}") << false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::apiBasicCalls()
|
void RemoteProxyOfflineTests::apiBasicCalls()
|
||||||
{
|
{
|
||||||
QFETCH(QByteArray, data);
|
QFETCH(QByteArray, data);
|
||||||
QFETCH(bool, valid);
|
QFETCH(bool, valid);
|
||||||
@ -154,7 +142,7 @@ void RemoteProxyTests::apiBasicCalls()
|
|||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::authenticate_data()
|
void RemoteProxyOfflineTests::authenticate_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("uuid");
|
QTest::addColumn<QString>("uuid");
|
||||||
QTest::addColumn<QString>("name");
|
QTest::addColumn<QString>("name");
|
||||||
@ -180,7 +168,7 @@ void RemoteProxyTests::authenticate_data()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::authenticate()
|
void RemoteProxyOfflineTests::authenticate()
|
||||||
{
|
{
|
||||||
QFETCH(QString, uuid);
|
QFETCH(QString, uuid);
|
||||||
QFETCH(QString, name);
|
QFETCH(QString, name);
|
||||||
@ -192,8 +180,8 @@ void RemoteProxyTests::authenticate()
|
|||||||
startServer();
|
startServer();
|
||||||
|
|
||||||
// Configure result
|
// Configure result
|
||||||
m_authenticator->setExpectedAuthenticationError(expectedError);
|
m_mockAuthenticator->setExpectedAuthenticationError(expectedError);
|
||||||
m_authenticator->setTimeoutDuration(timeout);
|
m_mockAuthenticator->setTimeoutDuration(timeout);
|
||||||
|
|
||||||
// Create request
|
// Create request
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
@ -209,17 +197,17 @@ void RemoteProxyTests::authenticate()
|
|||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::clientConnection()
|
void RemoteProxyOfflineTests::clientConnection()
|
||||||
{
|
{
|
||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
|
|
||||||
// Configure moch authenticator
|
// Configure moch authenticator
|
||||||
m_authenticator->setTimeoutDuration(100);
|
m_mockAuthenticator->setTimeoutDuration(100);
|
||||||
m_authenticator->setExpectedAuthenticationError();
|
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||||
|
|
||||||
// Connect to the server (insecure disabled)
|
// Connect to the server (insecure disabled)
|
||||||
RemoteProxyConnection *connection = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", RemoteProxyConnection::ConnectionTypeWebSocket, this);
|
RemoteProxyConnection *connection = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", this);
|
||||||
connection->setInsecureConnection(true);
|
connection->setInsecureConnection(true);
|
||||||
|
|
||||||
// Connect to server (insecue enabled for testing)
|
// Connect to server (insecue enabled for testing)
|
||||||
@ -260,20 +248,20 @@ void RemoteProxyTests::clientConnection()
|
|||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::remoteConnection()
|
void RemoteProxyOfflineTests::remoteConnection()
|
||||||
{
|
{
|
||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
|
|
||||||
// Configure moch authenticator
|
// Configure moch authenticator
|
||||||
m_authenticator->setTimeoutDuration(100);
|
m_mockAuthenticator->setTimeoutDuration(100);
|
||||||
m_authenticator->setExpectedAuthenticationError();
|
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||||
|
|
||||||
// Create two connection
|
// Create two connection
|
||||||
RemoteProxyConnection *connectionOne = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", RemoteProxyConnection::ConnectionTypeWebSocket, this);
|
RemoteProxyConnection *connectionOne = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", this);
|
||||||
connectionOne->setInsecureConnection(true);
|
connectionOne->setInsecureConnection(true);
|
||||||
|
|
||||||
RemoteProxyConnection *connectionTwo = new RemoteProxyConnection(QUuid::createUuid(), "Test client two", RemoteProxyConnection::ConnectionTypeWebSocket, this);
|
RemoteProxyConnection *connectionTwo = new RemoteProxyConnection(QUuid::createUuid(), "Test client two", this);
|
||||||
connectionTwo->setInsecureConnection(true);
|
connectionTwo->setInsecureConnection(true);
|
||||||
|
|
||||||
// Connect one
|
// Connect one
|
||||||
@ -310,8 +298,8 @@ void RemoteProxyTests::remoteConnection()
|
|||||||
QVERIFY(connectionTwo->isAuthenticated());
|
QVERIFY(connectionTwo->isAuthenticated());
|
||||||
|
|
||||||
// Wait for both to be connected
|
// Wait for both to be connected
|
||||||
remoteConnectionEstablishedOne.wait();
|
remoteConnectionEstablishedOne.wait(500);
|
||||||
remoteConnectionEstablishedTwo.wait();
|
remoteConnectionEstablishedTwo.wait(500);
|
||||||
|
|
||||||
QVERIFY(remoteConnectionEstablishedOne.count() == 1);
|
QVERIFY(remoteConnectionEstablishedOne.count() == 1);
|
||||||
QVERIFY(remoteConnectionEstablishedTwo.count() == 1);
|
QVERIFY(remoteConnectionEstablishedTwo.count() == 1);
|
||||||
@ -326,14 +314,16 @@ void RemoteProxyTests::remoteConnection()
|
|||||||
QByteArray dataTwo = "Hello from client two :-)";
|
QByteArray dataTwo = "Hello from client two :-)";
|
||||||
|
|
||||||
connectionOne->sendData(dataOne);
|
connectionOne->sendData(dataOne);
|
||||||
remoteConnectionDataTwo.wait();
|
remoteConnectionDataTwo.wait(500);
|
||||||
QVERIFY(remoteConnectionDataTwo.count() == 1);
|
QVERIFY(remoteConnectionDataTwo.count() == 1);
|
||||||
|
QCOMPARE(remoteConnectionDataTwo.at(0).at(0).toByteArray(), dataOne);
|
||||||
|
|
||||||
// verify if data is the same
|
// verify if data is the same
|
||||||
|
|
||||||
connectionTwo->sendData(dataTwo);
|
connectionTwo->sendData(dataTwo);
|
||||||
remoteConnectionDataOne.wait();
|
remoteConnectionDataOne.wait(500);
|
||||||
QVERIFY(remoteConnectionDataOne.count() == 1);
|
QVERIFY(remoteConnectionDataOne.count() == 1);
|
||||||
|
QCOMPARE(remoteConnectionDataOne.at(0).at(0).toByteArray(), dataTwo);
|
||||||
|
|
||||||
// verify if data is the same
|
// verify if data is the same
|
||||||
|
|
||||||
@ -344,59 +334,59 @@ void RemoteProxyTests::remoteConnection()
|
|||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::sslConfigurations()
|
void RemoteProxyOfflineTests::sslConfigurations()
|
||||||
{
|
{
|
||||||
// // Start the server
|
// Start the server
|
||||||
// startServer();
|
startServer();
|
||||||
|
|
||||||
// // Connect to the server (insecure disabled)
|
// Connect to the server (insecure disabled)
|
||||||
// RemoteProxyConnection *connector = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", RemoteProxyConnection::ConnectionTypeWebSocket, this);
|
RemoteProxyConnection *connector = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", this);
|
||||||
// QSignalSpy spyError(connector, &RemoteProxyConnection::errorOccured);
|
QSignalSpy spyError(connector, &RemoteProxyConnection::errorOccured);
|
||||||
// QVERIFY(connector->connectServer(QHostAddress::LocalHost, m_port));
|
QVERIFY(connector->connectServer(QHostAddress::LocalHost, m_port));
|
||||||
// spyError.wait();
|
spyError.wait();
|
||||||
// QVERIFY(spyError.count() == 1);
|
QVERIFY(spyError.count() == 2);
|
||||||
// QVERIFY(connector->error() == RemoteProxyConnection::ErrorSslError);
|
QVERIFY(connector->error() == RemoteProxyConnection::ErrorSocketError);
|
||||||
// QVERIFY(connector->state() == RemoteProxyConnection::StateDisconnected);
|
QVERIFY(connector->state() == RemoteProxyConnection::StateDisconnected);
|
||||||
|
|
||||||
// // Connect to server (insecue enabled)
|
// Connect to server (insecue enabled)
|
||||||
// QSignalSpy spyConnected(connector, &RemoteProxyConnection::connected);
|
QSignalSpy spyConnected(connector, &RemoteProxyConnection::connected);
|
||||||
// connector->setInsecureConnection(true);
|
connector->setInsecureConnection(true);
|
||||||
// connector->connectServer(QHostAddress::LocalHost, m_port);
|
connector->connectServer(QHostAddress::LocalHost, m_port);
|
||||||
// spyConnected.wait();
|
spyConnected.wait();
|
||||||
|
|
||||||
// QVERIFY(connector->isConnected());
|
QVERIFY(connector->isConnected());
|
||||||
|
|
||||||
// // Disconnect and clean up
|
// Disconnect and clean up
|
||||||
// connector->disconnectServer();
|
connector->disconnectServer();
|
||||||
// QVERIFY(!connector->isConnected());
|
QVERIFY(!connector->isConnected());
|
||||||
|
|
||||||
// connector->deleteLater();
|
connector->deleteLater();
|
||||||
// stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyTests::timeout()
|
void RemoteProxyOfflineTests::timeout()
|
||||||
{
|
{
|
||||||
// // Start the server
|
// Start the server
|
||||||
// startServer();
|
startServer();
|
||||||
|
|
||||||
// // Configure result
|
// Configure result
|
||||||
// // Start the server
|
// Start the server
|
||||||
// startServer();
|
startServer();
|
||||||
|
|
||||||
// // Configure result
|
// Configure result
|
||||||
// m_authenticator->setExpectedAuthenticationError();
|
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||||
// m_authenticator->setTimeoutDuration(6000);
|
m_mockAuthenticator->setTimeoutDuration(6000);
|
||||||
|
|
||||||
// // Create request
|
// Create request
|
||||||
// QVariantMap params;
|
QVariantMap params;
|
||||||
// params.insert("uuid", "uuid");
|
params.insert("uuid", "uuid");
|
||||||
// params.insert("name", "name");
|
params.insert("name", "name");
|
||||||
// params.insert("token", "token");
|
params.insert("token", "token");
|
||||||
|
|
||||||
// QVariant response = invokeApiCall("Authentication.Authenticate", params);
|
QVariant response = invokeApiCall("Authentication.Authenticate", params);
|
||||||
// qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
||||||
// // Clean up
|
// Clean up
|
||||||
// stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(RemoteProxyTests)
|
QTEST_MAIN(RemoteProxyOfflineTests)
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#ifndef NYMEA_REMOTEPROXY_TESTS_H
|
#ifndef NYMEA_REMOTEPROXY_TESTS_OFFLINE_H
|
||||||
#define NYMEA_REMOTEPROXY_TESTS_H
|
#define NYMEA_REMOTEPROXY_TESTS_OFFLINE_H
|
||||||
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
@ -15,11 +15,11 @@
|
|||||||
using namespace remoteproxy;
|
using namespace remoteproxy;
|
||||||
using namespace remoteproxyclient;
|
using namespace remoteproxyclient;
|
||||||
|
|
||||||
class RemoteProxyTests : public BaseTest
|
class RemoteProxyOfflineTests : public BaseTest
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit RemoteProxyTests(QObject *parent = nullptr);
|
explicit RemoteProxyOfflineTests(QObject *parent = nullptr);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
// Basic stuff
|
// Basic stuff
|
||||||
@ -28,7 +28,6 @@ private slots:
|
|||||||
|
|
||||||
// WebSocket connection
|
// WebSocket connection
|
||||||
void webserverConnectionBlocked();
|
void webserverConnectionBlocked();
|
||||||
void webserverConnection();
|
|
||||||
|
|
||||||
// Api
|
// Api
|
||||||
void getIntrospect();
|
void getIntrospect();
|
||||||
@ -48,4 +47,4 @@ private slots:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NYMEA_REMOTEPROXY_TESTS_H
|
#endif // NYMEA_REMOTEPROXY_TESTS_OFFLINE_H
|
||||||
71
tests/test-online/nymea-remoteproxy-tests-online.cpp
Normal file
71
tests/test-online/nymea-remoteproxy-tests-online.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "engine.h"
|
||||||
|
#include "loggingcategories.h"
|
||||||
|
#include "remoteproxyconnection.h"
|
||||||
|
#include "nymea-remoteproxy-tests-online.h"
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QSignalSpy>
|
||||||
|
#include <QWebSocket>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QWebSocketServer>
|
||||||
|
|
||||||
|
RemoteProxyOnlineTests::RemoteProxyOnlineTests(QObject *parent) :
|
||||||
|
BaseTest(parent)
|
||||||
|
{
|
||||||
|
m_authenticator = qobject_cast<Authenticator *>(m_awsAuthenticator);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteProxyOnlineTests::awsStaticCredentials()
|
||||||
|
{
|
||||||
|
startServer();
|
||||||
|
|
||||||
|
// Connect to the server (insecure disabled)
|
||||||
|
RemoteProxyConnection *connection = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", this);
|
||||||
|
connection->setInsecureConnection(true);
|
||||||
|
|
||||||
|
// Connect to server (insecue enabled for testing)
|
||||||
|
QSignalSpy readySpy(connection, &RemoteProxyConnection::ready);
|
||||||
|
QVERIFY(connection->connectServer(QHostAddress::LocalHost, m_port));
|
||||||
|
readySpy.wait();
|
||||||
|
QVERIFY(readySpy.count() == 1);
|
||||||
|
QVERIFY(connection->isConnected());
|
||||||
|
QVERIFY(!connection->isRemoteConnected());
|
||||||
|
QVERIFY(connection->state() == RemoteProxyConnection::StateReady);
|
||||||
|
QVERIFY(connection->error() == RemoteProxyConnection::ErrorNoError);
|
||||||
|
QVERIFY(connection->serverAddress() == QHostAddress::LocalHost);
|
||||||
|
QVERIFY(connection->serverPort() == m_port);
|
||||||
|
QVERIFY(connection->connectionType() == RemoteProxyConnection::ConnectionTypeWebSocket);
|
||||||
|
QVERIFY(connection->insecureConnection() == true);
|
||||||
|
QVERIFY(connection->serverName() == SERVER_NAME_STRING);
|
||||||
|
QVERIFY(connection->proxyServerName() == Engine::instance()->serverName());
|
||||||
|
QVERIFY(connection->proxyServerVersion() == SERVER_VERSION_STRING);
|
||||||
|
QVERIFY(connection->proxyServerApiVersion() == API_VERSION_STRING);
|
||||||
|
|
||||||
|
QSignalSpy errorSpy(connection, &RemoteProxyConnection::errorOccured);
|
||||||
|
QSignalSpy spyDisconnected(connection, &RemoteProxyConnection::disconnected);
|
||||||
|
|
||||||
|
QVERIFY(connection->authenticate("foobar"));
|
||||||
|
errorSpy.wait();
|
||||||
|
QVERIFY(errorSpy.count() == 1);
|
||||||
|
QVERIFY(connection->error() == RemoteProxyConnection::ErrorProxyAuthenticationFailed);
|
||||||
|
|
||||||
|
// Disconnect and clean up
|
||||||
|
connection->disconnectServer();
|
||||||
|
// FIXME: check why it waits the full time here
|
||||||
|
spyDisconnected.wait(100);
|
||||||
|
QVERIFY(spyDisconnected.count() == 1);
|
||||||
|
QVERIFY(!connection->isConnected());
|
||||||
|
|
||||||
|
connection->deleteLater();
|
||||||
|
|
||||||
|
stopServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteProxyOnlineTests::awsDynamicCredentials()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(RemoteProxyOnlineTests)
|
||||||
31
tests/test-online/nymea-remoteproxy-tests-online.h
Normal file
31
tests/test-online/nymea-remoteproxy-tests-online.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef NYMEA_REMOTEPROXY_TESTS_ONLINE_H
|
||||||
|
#define NYMEA_REMOTEPROXY_TESTS_ONLINE_H
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QtTest>
|
||||||
|
#include <QSslKey>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWebSocket>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QSslCertificate>
|
||||||
|
#include <QSslConfiguration>
|
||||||
|
|
||||||
|
#include "basetest.h"
|
||||||
|
|
||||||
|
using namespace remoteproxy;
|
||||||
|
using namespace remoteproxyclient;
|
||||||
|
|
||||||
|
class RemoteProxyOnlineTests : public BaseTest
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit RemoteProxyOnlineTests(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void awsStaticCredentials();
|
||||||
|
void awsDynamicCredentials();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NYMEA_REMOTEPROXY_TESTS_ONLINE_H
|
||||||
13
tests/test-online/test-online.pro
Normal file
13
tests/test-online/test-online.pro
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
include(../../nymea-remoteproxy.pri)
|
||||||
|
include(../testbase/testbase.pri)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TARGET = nymea-remoteproxy-tests-online
|
||||||
|
|
||||||
|
HEADERS += nymea-remoteproxy-tests-online.h
|
||||||
|
|
||||||
|
SOURCES += nymea-remoteproxy-tests-online.cpp
|
||||||
|
|
||||||
|
target.path = /usr/bin
|
||||||
|
INSTALLS += target
|
||||||
@ -14,30 +14,13 @@ BaseTest::BaseTest(QObject *parent) :
|
|||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
m_configuration = new ProxyConfiguration(this);
|
m_configuration = new ProxyConfiguration(this);
|
||||||
|
m_configuration->loadConfiguration(":/test-configuration.conf");
|
||||||
|
|
||||||
QFile certificateFile(":/test-certificate.crt");
|
m_mockAuthenticator = new MockAuthenticator(this);
|
||||||
if (!certificateFile.open(QIODevice::ReadOnly)) {
|
m_dummyAuthenticator = new DummyAuthenticator(this);
|
||||||
qWarning() << "Could not open resource file" << certificateFile.fileName();
|
m_awsAuthenticator = new AwsAuthenticator(this);
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray certificateData = certificateFile.readAll();
|
m_authenticator = qobject_cast<Authenticator *>(m_mockAuthenticator);
|
||||||
//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_authenticator = new MockAuthenticator(this);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
m_testToken = "eyJraWQiOiJXdnFFT3prVVh5VDlINzFyRUpoNWdxRnkxNFhnR2l3SFAzVEIzUFQ1V3ZrPSIsImFsZyI6IlJT"
|
m_testToken = "eyJraWQiOiJXdnFFT3prVVh5VDlINzFyRUpoNWdxRnkxNFhnR2l3SFAzVEIzUFQ1V3ZrPSIsImFsZyI6IlJT"
|
||||||
"MjU2In0.eyJzdWIiOiJmZTJmZDNlNC1hMGJhLTQ1OTUtOWRiZS00ZDkxYjRiMjFlMzUiLCJhdWQiOiI4cmpoZ"
|
"MjU2In0.eyJzdWIiOiJmZTJmZDNlNC1hMGJhLTQ1OTUtOWRiZS00ZDkxYjRiMjFlMzUiLCJhdWQiOiI4cmpoZ"
|
||||||
@ -54,6 +37,13 @@ BaseTest::BaseTest(QObject *parent) :
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseTest::loadConfiguration(const QString &fileName)
|
||||||
|
{
|
||||||
|
qDebug() << "Load test configurations" << fileName;
|
||||||
|
m_configuration->loadConfiguration(fileName);
|
||||||
|
restartEngine();
|
||||||
|
}
|
||||||
|
|
||||||
void BaseTest::cleanUpEngine()
|
void BaseTest::cleanUpEngine()
|
||||||
{
|
{
|
||||||
if (Engine::exists()) {
|
if (Engine::exists()) {
|
||||||
@ -72,15 +62,9 @@ void BaseTest::restartEngine()
|
|||||||
void BaseTest::startEngine()
|
void BaseTest::startEngine()
|
||||||
{
|
{
|
||||||
if (!Engine::exists()) {
|
if (!Engine::exists()) {
|
||||||
QString serverName = "nymea-remoteproxy-testserver";
|
|
||||||
Engine::instance()->setAuthenticator(m_authenticator);
|
Engine::instance()->setAuthenticator(m_authenticator);
|
||||||
Engine::instance()->setServerName(serverName);
|
|
||||||
Engine::instance()->setConfiguration(m_configuration);
|
|
||||||
Engine::instance()->setSslConfiguration(m_sslConfiguration);
|
|
||||||
Engine::instance()->setDeveloperModeEnabled(true);
|
Engine::instance()->setDeveloperModeEnabled(true);
|
||||||
|
|
||||||
QVERIFY(Engine::exists());
|
QVERIFY(Engine::exists());
|
||||||
QVERIFY(Engine::instance()->serverName() == serverName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +74,6 @@ void BaseTest::startServer()
|
|||||||
|
|
||||||
if (!Engine::instance()->running()) {
|
if (!Engine::instance()->running()) {
|
||||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||||
Engine::instance()->setConfiguration(m_configuration);
|
|
||||||
Engine::instance()->setDeveloperModeEnabled(true);
|
Engine::instance()->setDeveloperModeEnabled(true);
|
||||||
Engine::instance()->start(m_configuration);
|
Engine::instance()->start(m_configuration);
|
||||||
runningSpy.wait();
|
runningSpy.wait();
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include "mockauthenticator.h"
|
#include "mockauthenticator.h"
|
||||||
#include "proxyconfiguration.h"
|
#include "proxyconfiguration.h"
|
||||||
#include "remoteproxyconnection.h"
|
#include "remoteproxyconnection.h"
|
||||||
|
#include "authentication/awsauthenticator.h"
|
||||||
#include "authentication/dummyauthenticator.h"
|
#include "authentication/dummyauthenticator.h"
|
||||||
|
|
||||||
using namespace remoteproxy;
|
using namespace remoteproxy;
|
||||||
@ -32,11 +33,19 @@ protected:
|
|||||||
QHostAddress m_serverAddress = QHostAddress::LocalHost;
|
QHostAddress m_serverAddress = QHostAddress::LocalHost;
|
||||||
|
|
||||||
QSslConfiguration m_sslConfiguration;
|
QSslConfiguration m_sslConfiguration;
|
||||||
MockAuthenticator *m_authenticator = nullptr;
|
|
||||||
|
Authenticator *m_authenticator = nullptr;
|
||||||
|
MockAuthenticator *m_mockAuthenticator = nullptr;
|
||||||
|
DummyAuthenticator *m_dummyAuthenticator = nullptr;
|
||||||
|
AwsAuthenticator *m_awsAuthenticator = nullptr;
|
||||||
|
|
||||||
QString m_testToken;
|
QString m_testToken;
|
||||||
|
|
||||||
int m_commandCounter = 0;
|
int m_commandCounter = 0;
|
||||||
|
|
||||||
|
void loadConfiguration(const QString &fileName);
|
||||||
|
void setAuthenticator(Authenticator *authenticator);
|
||||||
|
|
||||||
void cleanUpEngine();
|
void cleanUpEngine();
|
||||||
void restartEngine();
|
void restartEngine();
|
||||||
void startEngine();
|
void startEngine();
|
||||||
@ -50,7 +59,6 @@ protected slots:
|
|||||||
void initTestCase();
|
void initTestCase();
|
||||||
void cleanupTestCase();
|
void cleanupTestCase();
|
||||||
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void sslErrors(const QList<QSslError> &) {
|
void sslErrors(const QList<QSslError> &) {
|
||||||
QWebSocket *socket = static_cast<QWebSocket*>(sender());
|
QWebSocket *socket = static_cast<QWebSocket*>(sender());
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
RESOURCES += ../certificate.qrc
|
RESOURCES += ../resources/resources.qrc
|
||||||
|
|
||||||
|
CONFIG += testcase
|
||||||
|
QT += testlib
|
||||||
|
|
||||||
INCLUDEPATH += $${PWD} $$top_srcdir/libnymea-remoteproxy $$top_srcdir/libnymea-remoteproxyclient
|
INCLUDEPATH += $${PWD} $$top_srcdir/libnymea-remoteproxy $$top_srcdir/libnymea-remoteproxyclient
|
||||||
LIBS += -L$$top_builddir/libnymea-remoteproxy/ -lnymea-remoteproxy \
|
LIBS += -L$$top_builddir/libnymea-remoteproxy/ -lnymea-remoteproxy \
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
TEMPLATE=subdirs
|
TEMPLATE=subdirs
|
||||||
SUBDIRS += offline
|
SUBDIRS += test-offline test-online
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user