Remove deprecated proxy functionality and clean up code
This commit is contained in:
parent
0b031d7614
commit
bf7a2c0238
380
README.md
380
README.md
@ -7,8 +7,7 @@ The nymea remote proxy server is the meeting point of nymea servers and nymea cl
|
||||
|
||||
In order to build the proxy server you need to install the qt default package.
|
||||
|
||||
apt install qt5-default
|
||||
|
||||
apt install qtbase5-dev qtbase5-dev-tools libqt5websockets5-dev libncurses5-dev dpkg-dev debhelper
|
||||
|
||||
## Build from source
|
||||
Change into the source directory and run following commands
|
||||
@ -27,18 +26,12 @@ If you want to start the proxy server from the build directory, you need to expo
|
||||
$ ./server/nymea-remoteproxy -c ../nymea-remoteproxy/nymea-remoteproxy.conf
|
||||
|
||||
|
||||
## Build debian package
|
||||
|
||||
$ apt install crossbuilder
|
||||
$ cd nymea-remoteproxy
|
||||
$ crossbuilder
|
||||
|
||||
# Install
|
||||
|
||||
## From repository
|
||||
There is a public version available in the nymea repository.
|
||||
|
||||
$ apt install nymea-remoteproxy nymea-remoteproxy-client nymea-remoteproxy-monitor
|
||||
$ apt install nymea-remoteproxy nymea-remoteproxy-tunnelclient nymea-remoteproxy-monitor
|
||||
|
||||
This will install a systemd service called `nymea-remoteproxy.service` and the client application for testing.
|
||||
|
||||
@ -51,7 +44,7 @@ Simply run following command in the build dir:
|
||||
# Configure
|
||||
|
||||
The package will deliver a default configuration file with following content (`/etc/nymea/nymea-remoteproxy.conf`):
|
||||
|
||||
|
||||
[ProxyServer]
|
||||
name=nymea-remoteproxy
|
||||
writeLogs=false
|
||||
@ -59,357 +52,37 @@ The package will deliver a default configuration file with following content (`/
|
||||
logEngineEnabled=false
|
||||
monitorSocket=/tmp/nymea-remoteproxy-monitor.sock
|
||||
jsonRpcTimeout=10000
|
||||
authenticationTimeout=8000
|
||||
inactiveTimeout=8000
|
||||
aloneTimeout=8000
|
||||
|
||||
[AWS]
|
||||
region=eu-west-1
|
||||
authorizerLambdaFunction=system-services-authorizer-dev-checkToken
|
||||
awsCredentialsUrl=http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Remote-Connection-Proxy-Role
|
||||
|
||||
[SSL]
|
||||
enabled=false
|
||||
certificate=/etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
certificateKey=/etc/ssl/private/ssl-cert-snakeoil.key
|
||||
certificateChain=
|
||||
|
||||
[WebSocketServer]
|
||||
host=127.0.0.1
|
||||
port=443
|
||||
[UnixSocketServerTunnelProxy]
|
||||
unixSocketFileName=/run/nymea-remoteproxy.socket
|
||||
|
||||
[TcpServer]
|
||||
[WebSocketServerTunnelProxy]
|
||||
host=127.0.0.1
|
||||
port=80
|
||||
|
||||
|
||||
# Test
|
||||
|
||||
In order to run the test, you can call `make check` in the build directory or run the resulting executable:
|
||||
|
||||
$ nymea-remoteproxy-tests-offline
|
||||
$ nymea-remoteproxy-tests-online
|
||||
|
||||
port=2212
|
||||
|
||||
[TcpServerTunnelProxy]
|
||||
host=127.0.0.1
|
||||
port=2213
|
||||
|
||||
|
||||
## Test coverage report
|
||||
|
||||
If you want to create a line coverage report from the tests simply run following command in the source directory:
|
||||
|
||||
> Note: run `qmake` with the argument `CONFIG+=converage` in order to generate coverage data for the tests. Then run the tests before creating the coverage report.
|
||||
|
||||
$ apt install lcov gcovr
|
||||
$ ./create-coverage-html.sh
|
||||
|
||||
The resulting coverage report will be place in the `coverage-html` directory.
|
||||
|
||||
# Server 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.
|
||||
|
||||
Version: 0.1.5
|
||||
API version: 0.3
|
||||
|
||||
Copyright © 2018 Simon Stürz <simon.stuerz@nymea.io>
|
||||
|
||||
|
||||
Options:
|
||||
-h, --help Displays this help.
|
||||
-v, --version Displays version information.
|
||||
-l, --logging <logfile> Write log file to the given logfile.
|
||||
-d, --development Enable the development mode. This
|
||||
enabled the server assumes there are
|
||||
static AWS credentials provided to
|
||||
aws-cli.
|
||||
-m, --mock-authenticator Start the server using a mock
|
||||
authenticator which returns always true.
|
||||
-c, --configuration <configuration> The path to the proxy server
|
||||
configuration file. The default is
|
||||
~/.config/nymea/nymea-remoteproxy.conf
|
||||
--verbose Print more verbose.
|
||||
|
||||
|
||||
# Proxy 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.
|
||||
|
||||
## Basic flow
|
||||
|
||||
#### First client
|
||||
|
||||
1. Connect to the proxy server
|
||||
2. Say hello, in order to know the version, name and API version of the server
|
||||
3. Authenticate with a token
|
||||
4. Wait for the tunnel established notification
|
||||
|
||||
#### Second client
|
||||
|
||||
1. Connect to the proxy server
|
||||
2. Say hello, in order to know the version, name and API version of the server
|
||||
3. Authenticate with a token (this has to be the same token as the first client showed)
|
||||
4. Wait for the tunnel established notification
|
||||
|
||||
|
||||
Once both clients are authenticated, the proxy server will send the `RemoteProxy.TunnelEstablished` notification containing the information of the other tunnel participent. Any traffic coming from he socket is from the remote partner, and any messge sent to the socket will go to the remote partner.
|
||||
|
||||
If anything goes wrong, or the tunnel partner disconnects from the proxy, the server will close the other client connection. If any data will be sent between `Authenticate` method and `TunnelEstablished` notification, the server will close the socket.
|
||||
|
||||
|
||||
|
||||
## 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.2",
|
||||
"name": "community-server",
|
||||
"server": "nymea-remoteproxy",
|
||||
"version": "0.1.2"
|
||||
},
|
||||
"status": "success"
|
||||
}
|
||||
|
||||
|
||||
# Proxy server
|
||||
|
||||
## 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 and a `nonce` which has to be uniq for each connection attempt and shared between the 2 clients. The `uuid` should be a persistant uuid for this client and the name should make clear which type of connection this is and which client is connecting. The name and uuid will be sent to the tunnel partner during the tunnel establishmend.
|
||||
|
||||
#### Request
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"method": "Authentication.Authenticate",
|
||||
"params": {
|
||||
"uuid": "string",
|
||||
"name": "string",
|
||||
"token": "tokenstring"
|
||||
"nonce": "nonce"
|
||||
}
|
||||
}
|
||||
|
||||
#### 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": 1,
|
||||
"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",
|
||||
"o:nonce": "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",
|
||||
"AuthenticationErrorProxyError"
|
||||
],
|
||||
"BasicType": [
|
||||
"Uuid",
|
||||
"String",
|
||||
"Int",
|
||||
"UInt",
|
||||
"Double",
|
||||
"Bool",
|
||||
"Variant",
|
||||
"Object"
|
||||
]
|
||||
}
|
||||
},
|
||||
"status": "success"
|
||||
}
|
||||
|
||||
|
||||
# Proxy server
|
||||
|
||||
|
||||
|
||||
# Server monitor
|
||||
|
||||
The server provides a live monitor interface on a local socket server. You can follow the monitor data with:
|
||||
|
||||
$ sudo socat - UNIX-CONNECT:/tmp/nymea-remoteproxy-monitor.sock
|
||||
|
||||
There is also the package `nymea-remoteproxy-monitor` package and application which gives you a nice overview about whats going on on the proxy server.
|
||||
|
||||
|
||||
$ nymea-remoteproxy-monitor --help
|
||||
|
||||
Usage: nymea-remoteproxy-monitor [options]
|
||||
|
||||
The nymea remote proxy monitor allowes to monitor the live server activity on the a local instance.
|
||||
|
||||
Server version: 0.1.5
|
||||
API version: 0.3
|
||||
|
||||
Copyright © 2018 Simon Stürz <simon.stuerz@nymea.io>
|
||||
|
||||
|
||||
Options:
|
||||
-h, --help Displays this help.
|
||||
-v, --version Displays version information.
|
||||
-s, --socket <socket> The socket descriptor for the nymea-remoteproxy
|
||||
monitor socket. Default is
|
||||
/tmp/nymea-remoteproxy-monitor.sock
|
||||
|
||||
|
||||
|
||||
# Client usage
|
||||
|
||||
The client allowes you to test the proxy server and create a dummy client for testing the connection.
|
||||
|
||||
|
||||
$ nymea-remoteproxy-client --help
|
||||
|
||||
Usage: nymea-remoteproxy-client [options]
|
||||
|
||||
The nymea remote proxy client application. This client allowes to test a server application as client perspective.
|
||||
|
||||
Version: 0.1.5
|
||||
API version: 0.3
|
||||
|
||||
Copyright © 2018 Simon Stürz <simon.stuerz@nymea.io>
|
||||
|
||||
|
||||
Options:
|
||||
-h, --help Displays this help.
|
||||
-v, --version Displays version information.
|
||||
-u, --url <url> The proxy server url. Default
|
||||
wss://dev-remoteproxy.nymea.io:443
|
||||
-t, --token <token> The AWS token for authentication.
|
||||
-i, --igore-ssl Ignore SSL certificate errors.
|
||||
--name <name> The name of the client. Default nymea-remoteproxyclient
|
||||
--uuid <uuid> The uuid of the client. If not specified, a new one will
|
||||
be created
|
||||
--verbose Print more information about the connection.
|
||||
--very-verbose Print the complete traffic information from the
|
||||
connection.
|
||||
|
||||
# Testing a local server
|
||||
|
||||
With following steps you can test a local instance with a self signed certificate.
|
||||
@ -419,7 +92,7 @@ With following steps you can test a local instance with a self signed certificat
|
||||
In order to test a connection and play with the server API, you can install the proxy server on your machine and try to connect to it.
|
||||
|
||||
$ sudo apt update
|
||||
$ sudo apt install nymea-remoteproxy nymea-remoteproxy-client
|
||||
$ sudo apt install nymea-remoteproxy nymea-remoteproxy-tunnelclient
|
||||
|
||||
Once installed, the `nymea-remoteproxy` will start automatically using the default configurations shipped in `/etc/nymea/nymea-remoteproxy.conf`.
|
||||
Using this file allowes you to configure the server for your test purposes.
|
||||
@ -445,27 +118,10 @@ Change following configuration in the `/etc/nymea/nymea-remoteproxy.conf`:
|
||||
|
||||
Now stop the proxy server and start it manually:
|
||||
|
||||
$ sudo systemctl stop nymea-remoteproxy.conf
|
||||
$ sudo systemctl stop nymea-remoteproxy.service
|
||||
|
||||
> *Note*: the `-m` starts the proxy with a dummy authenticator, which allowes to use any token, it will always be authenticated and should be used only on localhost running servers.
|
||||
$ sudo nymea-remoteproxy -c /etc/nymea/nymea-remoteproxy --verbose
|
||||
|
||||
$ sudo nymea-remoteproxy -c /etc/nymea/nymea-remoteproxy -m --verbose
|
||||
|
||||
## Connect two clients
|
||||
|
||||
Once the server is up and running with the dummy authenticator, you can try to connect to the service using the `nymea-remoteproxy-client` in a new terminal.
|
||||
|
||||
> *Note:* assuming you are starting the client on the same system as the server:
|
||||
|
||||
$ nymea-remoteproxy-client -i -u wss://localhost -t "blubtoken"
|
||||
|
||||
Open a second terminal and start the same command again.
|
||||
|
||||
> *Note:* assuming you are starting the client on the same system as the server:
|
||||
|
||||
$ nymea-remoteproxy-client -i -u wss://localhost -t "blubtoken"
|
||||
|
||||
You can follow the connection flow on both sides using the `--very-verbose` option.
|
||||
|
||||
# License
|
||||
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
include(../nymea-remoteproxy.pri)
|
||||
include(../libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri)
|
||||
|
||||
TARGET = nymea-remoteproxy-client
|
||||
TEMPLATE = app
|
||||
|
||||
INCLUDEPATH += ../libnymea-remoteproxy
|
||||
|
||||
LIBS += -L$$top_builddir/libnymea-remoteproxyclient/ -lnymea-remoteproxyclient
|
||||
|
||||
SOURCES += main.cpp \
|
||||
proxyclient.cpp
|
||||
|
||||
target.path = $$[QT_INSTALL_PREFIX]/bin
|
||||
INSTALLS += target
|
||||
|
||||
HEADERS += \
|
||||
proxyclient.h
|
||||
190
client/main.cpp
190
client/main.cpp
@ -1,190 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <QUrl>
|
||||
#include <QHash>
|
||||
#include <QCoreApplication>
|
||||
#include <QLoggingCategory>
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
|
||||
#include "proxyclient.h"
|
||||
#include "../version.h"
|
||||
|
||||
static QHash<QString, bool> s_loggingFilters;
|
||||
static const char *const normal = "\033[0m";
|
||||
static const char *const warning = "\e[33m";
|
||||
static const char *const error = "\e[31m";
|
||||
|
||||
static void loggingCategoryFilter(QLoggingCategory *category)
|
||||
{
|
||||
if (s_loggingFilters.contains(category->categoryName())) {
|
||||
bool debugEnabled = s_loggingFilters.value(category->categoryName());
|
||||
category->setEnabled(QtDebugMsg, debugEnabled);
|
||||
category->setEnabled(QtWarningMsg, debugEnabled || s_loggingFilters.value("Warnings"));
|
||||
} else {
|
||||
// Enable default debug output
|
||||
category->setEnabled(QtDebugMsg, true);
|
||||
category->setEnabled(QtWarningMsg, s_loggingFilters.value("qml") || s_loggingFilters.value("Warnings"));
|
||||
}
|
||||
}
|
||||
|
||||
static void consoleLogHandler(QtMsgType type, const QMessageLogContext& context, const QString& message)
|
||||
{
|
||||
switch (type) {
|
||||
case QtInfoMsg:
|
||||
fprintf(stdout, "%s: %s\n", context.category, message.toUtf8().data());
|
||||
break;
|
||||
case QtDebugMsg:
|
||||
fprintf(stdout, "%s: %s\n", context.category, message.toUtf8().data());
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
fprintf(stdout, "%s%s: %s%s\n", warning, context.category, message.toUtf8().data(), normal);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
fprintf(stdout, "%s%s: %s%s\n", error, context.category, message.toUtf8().data(), normal);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
fprintf(stdout, "%s%s: %s%s\n", error, context.category, message.toUtf8().data(), normal);
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
qInstallMessageHandler(consoleLogHandler);
|
||||
|
||||
QCoreApplication application(argc, argv);
|
||||
application.setApplicationName(SERVER_NAME_STRING);
|
||||
application.setOrganizationName("nymea");
|
||||
application.setApplicationVersion(SERVER_VERSION_STRING);
|
||||
|
||||
// Default debug categories
|
||||
s_loggingFilters.insert("ProxyClient", true);
|
||||
s_loggingFilters.insert("RemoteProxyClientJsonRpc", false);
|
||||
s_loggingFilters.insert("RemoteProxyClientWebSocket", false);
|
||||
s_loggingFilters.insert("RemoteProxyClientConnection", false);
|
||||
s_loggingFilters.insert("RemoteProxyClientJsonRpcTraffic", false);
|
||||
s_loggingFilters.insert("RemoteProxyClientConnectionTraffic", false);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
parser.setApplicationDescription(QString("\nThe nymea remote proxy client application. This client allowes to test "
|
||||
"a server application as client perspective.\n\n"
|
||||
"Version: %1\n"
|
||||
"API version: %2\n\n"
|
||||
"Copyright %3 %4 nymea GmbH <developer@nymea.io>\n")
|
||||
.arg(SERVER_VERSION_STRING)
|
||||
.arg(API_VERSION_STRING)
|
||||
.arg(QChar(0xA9))
|
||||
.arg(COPYRIGHT_YEAR_STRING));
|
||||
|
||||
QCommandLineOption urlOption(QStringList() << "u" << "url", "The proxy server url. Default ssl://dev-remoteproxy.nymea.io:4433", "url");
|
||||
urlOption.setDefaultValue("ssl://dev-remoteproxy.nymea.io:4433");
|
||||
parser.addOption(urlOption);
|
||||
|
||||
QCommandLineOption tokenOption(QStringList() << "t" << "token", "The AWS token for authentication.", "token");
|
||||
parser.addOption(tokenOption);
|
||||
|
||||
QCommandLineOption nonceOption(QStringList() << "n" << "nonce", "The shared connection unique nonce for this tunnel.", "nonce");
|
||||
parser.addOption(nonceOption);
|
||||
|
||||
QCommandLineOption insecureOption(QStringList() << "i" << "ignore-ssl", "Ignore SSL certificate errors.");
|
||||
parser.addOption(insecureOption);
|
||||
|
||||
QCommandLineOption pingPongOption(QStringList() << "p" << "pingpong", "Start a ping pong traffic trough the remote connection.");
|
||||
parser.addOption(pingPongOption);
|
||||
|
||||
|
||||
QCommandLineOption nameOption(QStringList() << "name", "The name of the client. Default nymea-remoteproxyclient", "name");
|
||||
nameOption.setDefaultValue("nymea-remoteproxyclient");
|
||||
parser.addOption(nameOption);
|
||||
|
||||
QCommandLineOption uuidOption(QStringList() << "uuid", "The uuid of the client. If not specified, a new one will be created", "uuid");
|
||||
parser.addOption(uuidOption);
|
||||
|
||||
QCommandLineOption wsOption(QStringList() << "ws", "Use web socket as tronsport instead of TCP sockets.");
|
||||
parser.addOption(wsOption);
|
||||
|
||||
QCommandLineOption verboseOption(QStringList() << "verbose", "Print more information about the connection.");
|
||||
parser.addOption(verboseOption);
|
||||
|
||||
QCommandLineOption veryVerboseOption(QStringList() << "very-verbose", "Print the complete traffic information from the connection.");
|
||||
parser.addOption(veryVerboseOption);
|
||||
|
||||
parser.process(application);
|
||||
|
||||
// Enable verbose
|
||||
if (parser.isSet(verboseOption) || parser.isSet(veryVerboseOption)) {
|
||||
s_loggingFilters["RemoteProxyClientJsonRpc"] = true;
|
||||
s_loggingFilters["RemoteProxyClientWebSocket"] = true;
|
||||
s_loggingFilters["RemoteProxyClientConnection"] = true;
|
||||
}
|
||||
|
||||
// Enable very verbose
|
||||
if (parser.isSet(veryVerboseOption)) {
|
||||
s_loggingFilters["RemoteProxyClientJsonRpcTraffic"] = true;
|
||||
s_loggingFilters["RemoteProxyClientConnectionTraffic"] = true;
|
||||
}
|
||||
QLoggingCategory::installFilter(loggingCategoryFilter);
|
||||
|
||||
if (!parser.isSet(tokenOption)) {
|
||||
qCCritical(dcProxyClient()) << "Please specify the token for authentication using -t <token> or --token <token>." << "\n" << "\n";
|
||||
parser.showHelp(-1);
|
||||
}
|
||||
|
||||
QUrl serverUrl(parser.value(urlOption));
|
||||
if (!serverUrl.isValid()) {
|
||||
qCCritical(dcProxyClient()) << "Invalid proxy server url passed." << parser.value(urlOption);
|
||||
exit(-1);
|
||||
}
|
||||
qCDebug(dcProxyClient()) << "Using URL" << serverUrl;
|
||||
|
||||
QUuid uuid(parser.value(uuidOption));
|
||||
if (uuid.isNull()) {
|
||||
uuid = QUuid::createUuid();
|
||||
}
|
||||
|
||||
ProxyClient *client = nullptr;
|
||||
if (parser.isSet(wsOption)) {
|
||||
qCDebug(dcProxyClient()) << "Using web sockets as transport layer";
|
||||
client = new ProxyClient(parser.value(nameOption), uuid, RemoteProxyConnection::ConnectionTypeWebSocket);
|
||||
client->setInsecure(parser.isSet(insecureOption));
|
||||
client->setPingpong(parser.isSet(pingPongOption));
|
||||
client->start(serverUrl, parser.value(tokenOption), parser.value(nonceOption));
|
||||
} else {
|
||||
qCDebug(dcProxyClient()) << "Using TCP as transport layer";
|
||||
client = new ProxyClient(parser.value(nameOption), uuid, RemoteProxyConnection::ConnectionTypeTcpSocket);
|
||||
client->setInsecure(parser.isSet(insecureOption));
|
||||
client->setPingpong(parser.isSet(pingPongOption));
|
||||
client->start(serverUrl, parser.value(tokenOption), parser.value(nonceOption));
|
||||
}
|
||||
|
||||
return application.exec();
|
||||
}
|
||||
@ -1,125 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "proxyclient.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
Q_LOGGING_CATEGORY(dcProxyClient, "ProxyClient")
|
||||
|
||||
ProxyClient::ProxyClient(const QString &name, const QUuid &uuid, RemoteProxyConnection::ConnectionType connectionType, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_name(name),
|
||||
m_uuid(uuid)
|
||||
{
|
||||
m_connection = new RemoteProxyConnection(m_uuid, m_name, connectionType, this);
|
||||
qCDebug(dcProxyClient()) << "Creating remote proxy connection" << m_name << m_uuid.toString();
|
||||
connect(m_connection, &RemoteProxyConnection::ready, this, &ProxyClient::onClientReady);
|
||||
connect(m_connection, &RemoteProxyConnection::authenticated, this, &ProxyClient::onAuthenticationFinished);
|
||||
connect(m_connection, &RemoteProxyConnection::remoteConnectionEstablished, this, &ProxyClient::onRemoteConnectionEstablished);
|
||||
connect(m_connection, &RemoteProxyConnection::dataReady, this, &ProxyClient::onDataReady);
|
||||
connect(m_connection, &RemoteProxyConnection::errorOccurred, this, &ProxyClient::onErrorOccurred);
|
||||
connect(m_connection, &RemoteProxyConnection::disconnected, this, &ProxyClient::onClientDisconnected);
|
||||
connect(m_connection, &RemoteProxyConnection::sslErrors, this, &ProxyClient::onSslErrors);
|
||||
}
|
||||
|
||||
void ProxyClient::setInsecure(bool insecure)
|
||||
{
|
||||
m_insecure = insecure;
|
||||
}
|
||||
|
||||
void ProxyClient::setPingpong(bool enable)
|
||||
{
|
||||
m_pingpong = enable;
|
||||
}
|
||||
|
||||
void ProxyClient::onErrorOccurred(QAbstractSocket::SocketError error)
|
||||
{
|
||||
qCWarning(dcProxyClient()) << "Error occurred" << error;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void ProxyClient::onClientReady()
|
||||
{
|
||||
qCDebug(dcProxyClient()) << "Connected to proxy server" << m_connection->serverUrl().toString();
|
||||
qCDebug(dcProxyClient()) << "Start authentication";
|
||||
m_connection->authenticate(m_token, m_nonce);
|
||||
}
|
||||
|
||||
void ProxyClient::onAuthenticationFinished()
|
||||
{
|
||||
qCDebug(dcProxyClient()) << "Authentication finished successfully.";
|
||||
}
|
||||
|
||||
void ProxyClient::onRemoteConnectionEstablished()
|
||||
{
|
||||
qCDebug(dcProxyClient()) << "----------------------------------------------------------------------------------";
|
||||
qCDebug(dcProxyClient()) << "Remote connection established with" << m_connection->tunnelPartnerName() << m_connection->tunnelPartnerUuid();
|
||||
qCDebug(dcProxyClient()) << "----------------------------------------------------------------------------------";
|
||||
if (m_pingpong) sendPing();
|
||||
}
|
||||
|
||||
void ProxyClient::onDataReady(const QByteArray &data)
|
||||
{
|
||||
qCDebug(dcProxyClient()) << "<--" << qUtf8Printable(data);
|
||||
if (m_pingpong) {
|
||||
QTimer::singleShot(1000, this, &ProxyClient::sendPing);
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyClient::onClientDisconnected()
|
||||
{
|
||||
qCDebug(dcProxyClient()) << "Disconnected from" << m_connection->serverUrl().toString();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void ProxyClient::onSslErrors(const QList<QSslError> errors)
|
||||
{
|
||||
if (m_insecure) {
|
||||
qCDebug(dcProxyClient()) << "SSL errors occurred. Ignoring because explicit specified.";
|
||||
m_connection->ignoreSslErrors();
|
||||
} else {
|
||||
qCWarning(dcProxyClient()) << "SSL errors occurred:";
|
||||
foreach (const QSslError &sslError, errors) {
|
||||
qCWarning(dcProxyClient()) << " --> " << sslError.errorString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyClient::sendPing()
|
||||
{
|
||||
QByteArray data(QString("Ping from " + m_name + "!").toUtf8());
|
||||
qCDebug(dcProxyClient()) << "-->" << qUtf8Printable(data);
|
||||
m_connection->sendData(data);
|
||||
}
|
||||
|
||||
void ProxyClient::start(const QUrl &url, const QString &token, const QString &nonce)
|
||||
{
|
||||
m_token = token;
|
||||
m_nonce = nonce;
|
||||
m_connection->connectServer(url);
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef PROXYCLIENT_H
|
||||
#define PROXYCLIENT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include "remoteproxyconnection.h"
|
||||
|
||||
using namespace remoteproxyclient;
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcProxyClient)
|
||||
|
||||
class ProxyClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ProxyClient(const QString &name, const QUuid &uuid, RemoteProxyConnection::ConnectionType connectionType, QObject *parent = nullptr);
|
||||
|
||||
void setInsecure(bool insecure);
|
||||
void setPingpong(bool enable);
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QUuid m_uuid;
|
||||
QString m_token;
|
||||
QString m_nonce;
|
||||
bool m_insecure = false;
|
||||
bool m_pingpong = false;
|
||||
|
||||
RemoteProxyConnection *m_connection = nullptr;
|
||||
|
||||
private slots:
|
||||
void onErrorOccurred(QAbstractSocket::SocketError error);
|
||||
void onClientReady();
|
||||
void onAuthenticationFinished();
|
||||
void onRemoteConnectionEstablished();
|
||||
void onDataReady(const QByteArray &data);
|
||||
void onClientDisconnected();
|
||||
void onSslErrors(const QList<QSslError> errors);
|
||||
|
||||
void sendPing();
|
||||
|
||||
public slots:
|
||||
void start(const QUrl &url, const QString &token, const QString &nonce);
|
||||
|
||||
};
|
||||
|
||||
#endif // PROXYCLIENT_H
|
||||
11
debian/control
vendored
11
debian/control
vendored
@ -20,7 +20,6 @@ Section: net
|
||||
Multi-Arch: same
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
awscli,
|
||||
libnymea-remoteproxy (= ${binary:Version}),
|
||||
Suggests: nymea-remoteproxy-monitor (= ${binary:Version})
|
||||
Description: The nymea remote proxy server
|
||||
@ -49,16 +48,6 @@ Description: The nymea remote proxy server lib - development files
|
||||
The nymea remote proxy server lib - development files
|
||||
|
||||
|
||||
Package: nymea-remoteproxy-client
|
||||
Architecture: any
|
||||
Section: utils
|
||||
Multi-Arch: same
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
Description: The nymea remote proxy client for testing
|
||||
The nymea remote proxy client for testing
|
||||
|
||||
|
||||
Package: nymea-remoteproxy-tunnelclient
|
||||
Architecture: any
|
||||
Section: utils
|
||||
|
||||
16
debian/copyright
vendored
16
debian/copyright
vendored
@ -1,7 +1,7 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: nymea-remoteproxy
|
||||
Upstream-Contact: Simon Stürz <simon.stuerz@nymea.io>
|
||||
Copyright: 2018 - 2022, nymea GmbH
|
||||
Copyright: 2018 - 2023, nymea GmbH
|
||||
Download: http://www.github.com/nymea/nymea-remoteproxy
|
||||
Source: https://github.com/nymea/nymea-remoteproxy.git
|
||||
|
||||
@ -16,24 +16,20 @@ License: LGPL-3
|
||||
|
||||
Files: libnymea-remoteproxyclient/*
|
||||
License: LGPL-3
|
||||
Copyright: 2018 - 2022, nymea GmbH <developer@nymea.io>
|
||||
Copyright: 2018 - 2023, nymea GmbH <developer@nymea.io>
|
||||
|
||||
Files: libnymea-remoteproxy/*
|
||||
License: GPL-3
|
||||
Copyright: 2018 - 2022, nymea GmbH <developer@nymea.io>
|
||||
|
||||
Files: client/*
|
||||
License: GPL-3
|
||||
Copyright: 2018 - 2022, nymea GmbH <developer@nymea.io>
|
||||
Copyright: 2018 - 2023, nymea GmbH <developer@nymea.io>
|
||||
|
||||
Files: monitor/*
|
||||
License: GPL-3
|
||||
Copyright: 2018 - 2022, nymea GmbH <developer@nymea.io>
|
||||
Copyright: 2018 - 2023, nymea GmbH <developer@nymea.io>
|
||||
|
||||
Files: server/*
|
||||
License: GPL-3
|
||||
Copyright: 2018 - 2022, nymea GmbH <developer@nymea.io>
|
||||
Copyright: 2018 - 2023, nymea GmbH <developer@nymea.io>
|
||||
|
||||
Files: tests/*
|
||||
License: GPL-3
|
||||
Copyright: 2018 - 2022, nymea GmbH <developer@nymea.io>
|
||||
Copyright: 2018 - 2023, nymea GmbH <developer@nymea.io>
|
||||
|
||||
1
debian/nymea-remoteproxy-client.install.in
vendored
1
debian/nymea-remoteproxy-client.install.in
vendored
@ -1 +0,0 @@
|
||||
usr/bin/nymea-remoteproxy-client
|
||||
1
debian/nymea-remoteproxy-tests.install
vendored
1
debian/nymea-remoteproxy-tests.install
vendored
@ -1,2 +1 @@
|
||||
usr/bin/nymea-remoteproxy-proxy-tests
|
||||
usr/bin/nymea-remoteproxy-tunnelproxy-tests
|
||||
|
||||
@ -7,6 +7,6 @@ HTML_RESULTS="${COV_DIR}/html"
|
||||
# Build code coverage html report
|
||||
mkdir -p ${HTML_RESULTS}
|
||||
lcov -d "${SRC_DIR}" -c -o "${COV_DIR}/coverage.info"
|
||||
lcov -r "${COV_DIR}/coverage.info" "*.h" "*/tests/*" "*.moc" "*moc_*.cpp" "*/test/*" "/usr/include/*" "*/build*/*" "*libnymea-remoteproxy/authentication/aws*" -o "${COV_DIR}/coverage-filtered.info"
|
||||
lcov -r "${COV_DIR}/coverage.info" "*.h" "*/tests/*" "*.moc" "*moc_*.cpp" "*/test/*" "/usr/include/*" "*/build*/*" -o "${COV_DIR}/coverage-filtered.info"
|
||||
genhtml -o "${HTML_RESULTS}" "${COV_DIR}/coverage-filtered.info"
|
||||
lcov -d "${COV_DIR}" -z
|
||||
|
||||
@ -1,98 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "engine.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "authenticationreply.h"
|
||||
#include "authentication/authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
AuthenticationReply::AuthenticationReply(ProxyClient *proxyClient, QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_proxyClient = proxyClient;
|
||||
|
||||
m_timer = new QTimer(this);
|
||||
m_timer->setSingleShot(true);
|
||||
connect(m_timer, &QTimer::timeout, this, &AuthenticationReply::onTimeout);
|
||||
qCDebug(dcAuthentication) << "Created authentication reply for" << proxyClient << "Timeout:" << Engine::instance()->configuration()->authenticationTimeout() << "[ms]";
|
||||
m_timer->start(Engine::instance()->configuration()->authenticationTimeout());
|
||||
}
|
||||
|
||||
AuthenticationReply::~AuthenticationReply()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QPointer<ProxyClient> AuthenticationReply::proxyClient() const
|
||||
{
|
||||
return m_proxyClient;
|
||||
}
|
||||
|
||||
bool AuthenticationReply::isTimedOut() const
|
||||
{
|
||||
return m_timedOut;
|
||||
}
|
||||
|
||||
bool AuthenticationReply::isFinished() const
|
||||
{
|
||||
return m_finished;
|
||||
}
|
||||
|
||||
Authenticator::AuthenticationError AuthenticationReply::error() const
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
void AuthenticationReply::setError(Authenticator::AuthenticationError error)
|
||||
{
|
||||
m_error = error;
|
||||
}
|
||||
|
||||
void AuthenticationReply::setFinished()
|
||||
{
|
||||
m_timer->stop();
|
||||
|
||||
// emit in next event loop
|
||||
QTimer::singleShot(0, this, &AuthenticationReply::finished);
|
||||
}
|
||||
|
||||
void AuthenticationReply::onTimeout()
|
||||
{
|
||||
m_timedOut = true;
|
||||
m_error = Authenticator::AuthenticationErrorTimeout;
|
||||
setFinished();
|
||||
}
|
||||
|
||||
void AuthenticationReply::abort()
|
||||
{
|
||||
m_error = Authenticator::AuthenticationErrorAborted;
|
||||
setFinished();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,83 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef AUTHENTICATIONREPLY_H
|
||||
#define AUTHENTICATIONREPLY_H
|
||||
|
||||
#include <QUuid>
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QProcess>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class AuthenticationReply : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
friend class Authenticator;
|
||||
|
||||
QPointer<ProxyClient> proxyClient() const;
|
||||
|
||||
bool isTimedOut() const;
|
||||
bool isFinished() const;
|
||||
|
||||
Authenticator::AuthenticationError error() const;
|
||||
|
||||
private:
|
||||
explicit AuthenticationReply(ProxyClient *proxyClient, QObject *parent = nullptr);
|
||||
~AuthenticationReply();
|
||||
|
||||
QPointer<ProxyClient> m_proxyClient;
|
||||
QTimer *m_timer = nullptr;
|
||||
|
||||
bool m_timedOut = false;
|
||||
bool m_finished = false;
|
||||
|
||||
Authenticator::AuthenticationError m_error = Authenticator::AuthenticationErrorUnknown;
|
||||
|
||||
void setError(Authenticator::AuthenticationError error);
|
||||
void setFinished();
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
private slots:
|
||||
void onTimeout();
|
||||
|
||||
public slots:
|
||||
void abort();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AUTHENTICATIONREPLY_H
|
||||
@ -1,60 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "proxy/proxyclient.h"
|
||||
#include "authenticator.h"
|
||||
#include "authenticationreply.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
Authenticator::Authenticator(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Authenticator::~Authenticator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Authenticator::setReplyError(AuthenticationReply *reply, Authenticator::AuthenticationError error)
|
||||
{
|
||||
reply->setError(error);
|
||||
}
|
||||
|
||||
void Authenticator::setReplyFinished(AuthenticationReply *reply)
|
||||
{
|
||||
reply->setFinished();
|
||||
}
|
||||
|
||||
AuthenticationReply *Authenticator::createAuthenticationReply(ProxyClient *proxyClient, QObject *parent)
|
||||
{
|
||||
return new AuthenticationReply(proxyClient, parent);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef AUTHENTICATOR_H
|
||||
#define AUTHENTICATOR_H
|
||||
|
||||
#include <QUuid>
|
||||
#include <QObject>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class ProxyClient;
|
||||
class AuthenticationReply;
|
||||
|
||||
class Authenticator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum AuthenticationError {
|
||||
AuthenticationErrorNoError,
|
||||
AuthenticationErrorUnknown,
|
||||
AuthenticationErrorTimeout,
|
||||
AuthenticationErrorAborted,
|
||||
AuthenticationErrorAuthenticationFailed,
|
||||
AuthenticationErrorProxyError
|
||||
};
|
||||
Q_ENUM(AuthenticationError)
|
||||
|
||||
explicit Authenticator(QObject *parent = nullptr);
|
||||
virtual ~Authenticator() = 0;
|
||||
|
||||
virtual QString name() const = 0;
|
||||
|
||||
public slots:
|
||||
virtual AuthenticationReply *authenticate(ProxyClient *proxyClient) = 0;
|
||||
|
||||
protected:
|
||||
void setReplyError(AuthenticationReply *reply, AuthenticationError error);
|
||||
void setReplyFinished(AuthenticationReply *reply);
|
||||
|
||||
AuthenticationReply *createAuthenticationReply(ProxyClient *proxyClient, QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AUTHENTICATOR_H
|
||||
@ -1,275 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "authenticationprocess.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
#include <QUrl>
|
||||
#include <QFile>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "engine.h"
|
||||
#include "sigv4utils.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
AuthenticationProcess::AuthenticationProcess(QNetworkAccessManager *manager, const QString &accessKey, const QString &secretAccessKey, const QString &sessionToken, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_manager(manager),
|
||||
m_accessKey(accessKey),
|
||||
m_secretAccessKey(secretAccessKey),
|
||||
m_sessionToken(sessionToken)
|
||||
{
|
||||
m_process = new QProcess(this);
|
||||
m_process->setProcessChannelMode(QProcess::MergedChannels);
|
||||
connect(m_process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &AuthenticationProcess::onProcessFinished);
|
||||
}
|
||||
|
||||
void AuthenticationProcess::invokeLambdaFunction()
|
||||
{
|
||||
// Known configurations
|
||||
QString region = Engine::instance()->configuration()->awsRegion();
|
||||
QString lambdaFunctionName = Engine::instance()->configuration()->awsAuthorizerLambdaFunctionName();
|
||||
|
||||
QString invocationType = "RequestResponse";
|
||||
QString service = "lambda";
|
||||
|
||||
QUrl requestUrl;
|
||||
requestUrl.setScheme("https");
|
||||
requestUrl.setHost(QString("lambda.%1.amazonaws.com").arg(region));
|
||||
requestUrl.setPath(QString("/2015-03-31/functions/%1/invocations").arg(lambdaFunctionName));
|
||||
|
||||
// Create request map
|
||||
QVariantMap requestMap;
|
||||
requestMap.insert("token", m_token);
|
||||
QByteArray payload = QJsonDocument::fromVariant(requestMap).toJson(QJsonDocument::Compact);
|
||||
|
||||
QNetworkRequest request(requestUrl);
|
||||
//request.setRawHeader("User-Agent", QString("%1/%2 JSON-RPC/%3").arg(SERVER_NAME_STRING).arg(SERVER_VERSION_STRING).arg(API_VERSION_STRING).toUtf8());
|
||||
//request.setRawHeader("Content-Type", "application/json");
|
||||
request.setRawHeader("host", requestUrl.host().toUtf8());
|
||||
SigV4Utils::signRequest(QNetworkAccessManager::PostOperation, request, region, service, invocationType, m_accessKey.toUtf8(), m_secretAccessKey.toUtf8(), m_sessionToken.toUtf8(), payload);
|
||||
|
||||
qCDebug(dcAuthenticationProcess()) << "Invoke lambda function" << lambdaFunctionName;
|
||||
|
||||
qCDebug(dcAuthenticationProcess()) << "--------------------------------------------";
|
||||
qCDebug(dcAuthenticationProcess()) << request.url().toString();
|
||||
|
||||
foreach (const QByteArray &rawHeader, request.rawHeaderList()) {
|
||||
qDebug(dcAuthenticationProcess()) << rawHeader << request.rawHeader(rawHeader);
|
||||
}
|
||||
qCDebug(dcAuthenticationProcess()) << payload;
|
||||
qCDebug(dcAuthenticationProcess()) << "--------------------------------------------";
|
||||
|
||||
m_lambdaTimer.start();
|
||||
|
||||
QNetworkReply *reply = m_manager->post(request, payload);
|
||||
connect(reply, &QNetworkReply::finished, this, &AuthenticationProcess::onLambdaInvokeFunctionFinished);
|
||||
|
||||
}
|
||||
|
||||
void AuthenticationProcess::startVerificationProcess()
|
||||
{
|
||||
if (m_process->state() != QProcess::NotRunning) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Authentication process already running. Killing the running process and restart.";
|
||||
m_process->kill();
|
||||
}
|
||||
|
||||
// Create request map
|
||||
QVariantMap request;
|
||||
request.insert("token", m_token);
|
||||
|
||||
// Set environment
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("AWS_DEFAULT_REGION", "eu-west-1");
|
||||
if (m_fallback) {
|
||||
qCDebug(dcAuthenticationProcess()) << "Using dynamic credentials" << m_accessKey << m_secretAccessKey << m_sessionToken;
|
||||
env.insert("AWS_ACCESS_KEY_ID", m_accessKey);
|
||||
env.insert("AWS_SECRET_ACCESS_KEY", m_secretAccessKey);
|
||||
env.insert("AWS_SESSION_TOKEN", m_sessionToken);
|
||||
}
|
||||
|
||||
m_process->setProcessEnvironment(env);
|
||||
|
||||
// FIXME: check how to clean this up properly
|
||||
m_resultFileName = "/tmp/" + QUuid::createUuid().toString().remove("{").remove("}").remove("-") + ".json";
|
||||
|
||||
QStringList processParams = { "lambda", "invoke",
|
||||
"--function-name", "system-services-authorizer-dev-checkToken",
|
||||
"--invocation-type", "RequestResponse",
|
||||
"--payload", QString::fromUtf8(QJsonDocument::fromVariant(request).toJson()),
|
||||
m_resultFileName };
|
||||
|
||||
qCDebug(dcAuthenticationProcess()) << "Process environment" << env.toStringList();
|
||||
qCDebug(dcAuthenticationProcess()) << "Process params" << processParams;
|
||||
|
||||
|
||||
qCDebug(dcAuthentication()) << "Start authenticator process and store result in" << m_resultFileName;
|
||||
m_processTimer.start();
|
||||
m_process->start("aws", processParams);
|
||||
}
|
||||
|
||||
void AuthenticationProcess::onLambdaInvokeFunctionFinished()
|
||||
{
|
||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||
reply->deleteLater();
|
||||
|
||||
qCDebug(dcAuthenticationProcess()) << "Lambda invoke request finished (" << m_lambdaTimer.elapsed() << "[ms] )";
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
|
||||
qCDebug(dcAuthenticationProcess()) << "--------------------------------------------";
|
||||
qCDebug(dcAuthenticationProcess()) << reply->request().url().toString();
|
||||
|
||||
foreach (const QByteArray &rawHeader, reply->rawHeaderList()) {
|
||||
qDebug(dcAuthenticationProcess()) << rawHeader << reply->rawHeader(rawHeader);
|
||||
}
|
||||
qCDebug(dcAuthenticationProcess()) << qUtf8Printable(data);
|
||||
qCDebug(dcAuthenticationProcess()) << "--------------------------------------------";
|
||||
|
||||
if (reply->error()) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Lambda invoke reply error: " << reply->errorString();
|
||||
m_fallback = true;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcAuthenticationProcess()) << "Lambda function result ready" << qUtf8Printable(data);
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||
if(error.error != QJsonParseError::NoError) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Failed to parse lambda invoke result data" << data << ":" << error.errorString();
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
qCDebug(dcAuthenticationProcess()) << "-->" << response;
|
||||
if (response.isEmpty()) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Received empty lambda result.";
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isValid = response.value("isValid").toBool();
|
||||
if (isValid) {
|
||||
QVariantMap verifiedDataMap = response.value("verifiedData").toMap();
|
||||
QString vendorId = verifiedDataMap.value("vendorId").toString();
|
||||
QString userPoolId = verifiedDataMap.value("userPoolId").toString();
|
||||
QVariantMap verifiedParsedTokenMap = verifiedDataMap.value("verifiedParsedToken").toMap();
|
||||
QString email = verifiedParsedTokenMap.value("email").toString();
|
||||
QString cognitoUsername = verifiedParsedTokenMap.value("cognito:username").toString();
|
||||
|
||||
UserInformation userInformation(email, cognitoUsername, vendorId, userPoolId);
|
||||
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorNoError, userInformation);
|
||||
} else {
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorAuthenticationFailed);
|
||||
}
|
||||
}
|
||||
|
||||
void AuthenticationProcess::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
qCDebug(dcAuthenticationProcess()) << "Authentication process finished (" << m_processTimer.elapsed() << "[ms] )";;
|
||||
if (exitStatus == QProcess::CrashExit) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Authentication process crashed:" << "\n" << qUtf8Printable(m_process->readAll());
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (exitCode != 0) {
|
||||
qCWarning(dcAuthenticationProcess()) << "The authentication process finished with error" << exitCode << "\n" << qUtf8Printable(m_process->readAll());
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
QFile resultFile(m_resultFileName);
|
||||
if (!resultFile.exists()) {
|
||||
qCWarning(dcAuthenticationProcess()) << "The process output file does not exist.";
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultFile.open(QIODevice::ReadWrite)) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Could not open result file from process:" << resultFile.errorString();
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray resultData = resultFile.readAll();
|
||||
|
||||
qCDebug(dcAuthenticationProcess()) << "Lambda function result ready" << qUtf8Printable(resultData);
|
||||
|
||||
resultFile.close();
|
||||
if (!resultFile.remove()) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Could not clean up result file from process:" << resultFile.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(resultData, &error);
|
||||
if(error.error != QJsonParseError::NoError) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Failed to parse lambda invoke result data" << resultData << ":" << error.errorString();
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
qCDebug(dcAuthenticationProcess()) << "-->" << response;
|
||||
if (response.isEmpty()) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Received empty lambda result.";
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isValid = response.value("isValid").toBool();
|
||||
if (isValid) {
|
||||
QVariantMap verifiedDataMap = response.value("verifiedData").toMap();
|
||||
QString vendorId = verifiedDataMap.value("vendorId").toString();
|
||||
QString userPoolId = verifiedDataMap.value("userPoolId").toString();
|
||||
QVariantMap verifiedParsedTokenMap = verifiedDataMap.value("verifiedParsedToken").toMap();
|
||||
QString email = verifiedParsedTokenMap.value("email").toString();
|
||||
QString cognitoUsername = verifiedParsedTokenMap.value("cognito:username").toString();
|
||||
|
||||
UserInformation userInformation(email, cognitoUsername, vendorId, userPoolId);
|
||||
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorNoError, userInformation);
|
||||
} else {
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorAuthenticationFailed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AuthenticationProcess::authenticate(const QString &token)
|
||||
{
|
||||
qCDebug(dcAuthenticationProcess()) << "Start authentication process for token" << token;
|
||||
m_token = token;
|
||||
invokeLambdaFunction();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,81 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef AUTHENTICATIONPROCESS_H
|
||||
#define AUTHENTICATIONPROCESS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QElapsedTimer>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include "userinformation.h"
|
||||
#include "authentication/authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class AuthenticationProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AuthenticationProcess(QNetworkAccessManager *manager, const QString &accessKey, const QString &secretAccessKey, const QString &sessionToken, QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *m_manager = nullptr;
|
||||
QString m_accessKey;
|
||||
QString m_secretAccessKey;
|
||||
QString m_sessionToken;
|
||||
|
||||
QString m_token;
|
||||
QString m_resultFileName;
|
||||
|
||||
bool m_fallback = false;
|
||||
|
||||
QProcess *m_process = nullptr;
|
||||
QElapsedTimer m_lambdaTimer;
|
||||
QElapsedTimer m_processTimer;
|
||||
|
||||
void invokeLambdaFunction();
|
||||
void startVerificationProcess();
|
||||
|
||||
void cleanUp();
|
||||
|
||||
signals:
|
||||
void authenticationFinished(Authenticator::AuthenticationError error, const UserInformation &userInformation = UserInformation());
|
||||
|
||||
private slots:
|
||||
void onLambdaInvokeFunctionFinished();
|
||||
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
public slots:
|
||||
void authenticate(const QString &token);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AUTHENTICATIONPROCESS_H
|
||||
@ -1,89 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "engine.h"
|
||||
#include "proxy/proxyclient.h"
|
||||
#include "awsauthenticator.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
AwsAuthenticator::AwsAuthenticator(const QUrl &awsCredentialsUrl, QObject *parent) :
|
||||
Authenticator(parent),
|
||||
m_manager(new QNetworkAccessManager(this))
|
||||
{
|
||||
m_credentialsProvider = new AwsCredentialProvider(m_manager, awsCredentialsUrl, this);
|
||||
QMetaObject::invokeMethod(m_credentialsProvider, QString("enable").toLatin1().data(), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
AwsAuthenticator::~AwsAuthenticator()
|
||||
{
|
||||
qCDebug(dcAuthentication()) << "Shutting down" << name();
|
||||
m_credentialsProvider->disable();
|
||||
}
|
||||
|
||||
QString AwsAuthenticator::name() const
|
||||
{
|
||||
return "AWS authenticator";
|
||||
}
|
||||
|
||||
AuthenticationReply *AwsAuthenticator::authenticate(ProxyClient *proxyClient)
|
||||
{
|
||||
qCDebug(dcAuthentication()) << name() << "Start authenticating" << proxyClient;
|
||||
AuthenticationReply *reply = createAuthenticationReply(proxyClient, proxyClient);
|
||||
if (!m_credentialsProvider->isValid()) {
|
||||
qCWarning(dcAuthentication()) << name() << "There are no credentials for authenticating.";
|
||||
setReplyError(reply, AuthenticationErrorProxyError);
|
||||
setReplyFinished(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
AuthenticationProcess *process = new AuthenticationProcess(m_manager,
|
||||
m_credentialsProvider->accessKey(),
|
||||
m_credentialsProvider->secretAccessKey(),
|
||||
m_credentialsProvider->sessionToken(), reply);
|
||||
|
||||
connect(process, &AuthenticationProcess::authenticationFinished, proxyClient, [=](Authenticator::AuthenticationError error, const UserInformation &userInformation = UserInformation()){
|
||||
if (error == AuthenticationErrorNoError) {
|
||||
qCDebug(dcAuthentication()) << name() << proxyClient << "finished successfully." << userInformation;
|
||||
} else {
|
||||
qCDebug(dcAuthentication()) << name() << proxyClient << "finished with error" << error;
|
||||
}
|
||||
|
||||
proxyClient->setUserName(userInformation.email());
|
||||
|
||||
setReplyError(reply, error);
|
||||
setReplyFinished(reply);
|
||||
});
|
||||
|
||||
|
||||
// Start authentication process
|
||||
process->authenticate(proxyClient->token());
|
||||
return reply;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef AWSAUTHENTICATOR_H
|
||||
#define AWSAUTHENTICATOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include "awscredentialprovider.h"
|
||||
#include "authenticationprocess.h"
|
||||
#include "authentication/authenticator.h"
|
||||
#include "authentication/authenticationreply.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class AwsAuthenticator : public Authenticator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AwsAuthenticator(const QUrl &awsCredentialsUrl, QObject *parent = nullptr);
|
||||
~AwsAuthenticator() override;
|
||||
|
||||
QString name() const override;
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *m_manager = nullptr;
|
||||
AwsCredentialProvider *m_credentialsProvider = nullptr;
|
||||
|
||||
public slots:
|
||||
AuthenticationReply *authenticate(ProxyClient *proxyClient) override;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AWSAUTHENTICATOR_H
|
||||
@ -1,154 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "loggingcategories.h"
|
||||
#include "awscredentialprovider.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonParseError>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
AwsCredentialProvider::AwsCredentialProvider(QNetworkAccessManager *networkManager, const QUrl &awsCredentialsUrl, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_networkManager(networkManager),
|
||||
m_requestUrl(awsCredentialsUrl)
|
||||
{
|
||||
m_timer = new QTimer(this);
|
||||
m_timer->setSingleShot(false);
|
||||
m_timer->setInterval(90000);
|
||||
|
||||
connect(m_timer, &QTimer::timeout, this, &AwsCredentialProvider::onTimeout);
|
||||
}
|
||||
|
||||
QString AwsCredentialProvider::accessKey() const
|
||||
{
|
||||
return m_accessKey;
|
||||
}
|
||||
|
||||
QString AwsCredentialProvider::secretAccessKey() const
|
||||
{
|
||||
return m_secretAccessKey;
|
||||
}
|
||||
|
||||
QString AwsCredentialProvider::sessionToken() const
|
||||
{
|
||||
return m_sessionToken;
|
||||
}
|
||||
|
||||
bool AwsCredentialProvider::isValid() const
|
||||
{
|
||||
return !m_accessKey.isEmpty() && !m_secretAccessKey.isEmpty() && !m_sessionToken.isEmpty();
|
||||
}
|
||||
|
||||
bool AwsCredentialProvider::enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void AwsCredentialProvider::refreshCredentials()
|
||||
{
|
||||
qCDebug(dcAwsCredentialsProvider()) << "Update dynamic credentials form" << m_requestUrl.toString();
|
||||
|
||||
m_requestTimer.start();
|
||||
QNetworkReply *reply = m_networkManager->get(QNetworkRequest(m_requestUrl));
|
||||
connect(reply, &QNetworkReply::finished, this, &AwsCredentialProvider::onReplyFinished);
|
||||
}
|
||||
|
||||
void AwsCredentialProvider::clear()
|
||||
{
|
||||
m_accessKey.clear();
|
||||
m_secretAccessKey.clear();
|
||||
m_sessionToken.clear();
|
||||
}
|
||||
|
||||
|
||||
void AwsCredentialProvider::onTimeout()
|
||||
{
|
||||
// TODO: check if we need to refresh
|
||||
refreshCredentials();
|
||||
}
|
||||
|
||||
void AwsCredentialProvider::onReplyFinished()
|
||||
{
|
||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||
reply->deleteLater();
|
||||
|
||||
qCDebug(dcAwsCredentialsProvider()) << "Dynamic credentials request finished (" << m_requestTimer.elapsed() << "[ms] )";
|
||||
if (reply->error()) {
|
||||
qCWarning(dcAwsCredentialsProvider()) << "Dynamic credentials reply error: " << reply->errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||
|
||||
if(error.error != QJsonParseError::NoError) {
|
||||
qCWarning(dcAwsCredentialsProviderTraffic()) << "Failed to parse dynamic credentials reply data" << data << ":" << error.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
|
||||
m_accessKey = response.value("AccessKeyId").toString();
|
||||
m_secretAccessKey = response.value("SecretAccessKey").toString();
|
||||
m_sessionToken = response.value("Token").toString();
|
||||
|
||||
qCDebug(dcAwsCredentialsProviderTraffic()) << "Dynamic credentials updated:" << response;
|
||||
|
||||
QDateTime expirationTime = QDateTime::fromString(response.value("Expiration").toString(), "yyyy-MM-ddThh:mm:ssZ");
|
||||
QDateTime lastUpdateTime = QDateTime::fromString(response.value("LastUpdated").toString(), "yyyy-MM-ddThh:mm:ssZ");
|
||||
qCDebug(dcAwsCredentialsProviderTraffic()) << "Exipration time" << expirationTime.toString("dd.MM.yyyy hh:mm:ss");
|
||||
qCDebug(dcAwsCredentialsProviderTraffic()) << "Last update time" << lastUpdateTime.toString("dd.MM.yyyy hh:mm:ss");
|
||||
}
|
||||
|
||||
void AwsCredentialProvider::enable()
|
||||
{
|
||||
if (!m_enabled) {
|
||||
clear();
|
||||
m_enabled = true;
|
||||
}
|
||||
|
||||
qCDebug(dcAwsCredentialsProvider()) << "Enable AWS dynamic credentials provider";
|
||||
m_timer->start();
|
||||
refreshCredentials();
|
||||
}
|
||||
|
||||
void AwsCredentialProvider::disable()
|
||||
{
|
||||
qCDebug(dcAwsCredentialsProvider()) << "Disable AWS dynamic credentials provider";
|
||||
m_enabled = false;
|
||||
m_timer->stop();
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,88 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef AWSCREDENTIALPROVIDER_H
|
||||
#define AWSCREDENTIALPROVIDER_H
|
||||
|
||||
#include <QUrl>
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
#include <QDateTime>
|
||||
#include <QElapsedTimer>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class AwsCredentialProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AwsCredentialProvider(QNetworkAccessManager *networkManager, const QUrl &awsCredentialsUrl, QObject *parent = nullptr);
|
||||
|
||||
QString accessKey() const;
|
||||
QString secretAccessKey() const;
|
||||
QString sessionToken() const;
|
||||
|
||||
bool isValid() const;
|
||||
bool enabled() const;
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *m_networkManager = nullptr;
|
||||
QTimer *m_timer = nullptr;
|
||||
|
||||
QElapsedTimer m_requestTimer;
|
||||
|
||||
bool m_enabled = false;
|
||||
|
||||
QUrl m_requestUrl;
|
||||
|
||||
QString m_accessKey;
|
||||
QString m_secretAccessKey;
|
||||
QString m_sessionToken;
|
||||
|
||||
QDateTime m_expirationTime;
|
||||
QDateTime m_lastUpdateTime;
|
||||
|
||||
void refreshCredentials();
|
||||
void clear();
|
||||
|
||||
private slots:
|
||||
void onTimeout();
|
||||
void onReplyFinished();
|
||||
|
||||
signals:
|
||||
void credentialsChanged();
|
||||
|
||||
public slots:
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AWSCREDENTIALPROVIDER_H
|
||||
@ -1,182 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "sigv4utils.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QCryptographicHash>
|
||||
#include <QMessageAuthenticationCode>
|
||||
#include <QtDebug>
|
||||
#include <QUrlQuery>
|
||||
#include <QList>
|
||||
|
||||
#include "loggingcategories.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
SigV4Utils::SigV4Utils()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SigV4Utils::signRequest(QNetworkAccessManager::Operation operation, QNetworkRequest &request, const QString ®ion, const QString &service, const QString &invocationType, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken, const QByteArray &payload)
|
||||
{
|
||||
QByteArray dateTime;
|
||||
if (request.rawHeaderList().contains("x-amz-date")) {
|
||||
dateTime = request.rawHeader("x-amz-date");
|
||||
} else {
|
||||
dateTime = SigV4Utils::getCurrentDateTime();
|
||||
request.setRawHeader("x-amz-date", dateTime);
|
||||
}
|
||||
|
||||
request.setRawHeader("x-amz-invocation-type", invocationType.toUtf8());
|
||||
|
||||
if (!sessionToken.isEmpty()) {
|
||||
request.setRawHeader("x-amz-security-token", sessionToken);
|
||||
}
|
||||
|
||||
QByteArray canonicalRequest = SigV4Utils::getCanonicalRequest(operation, request, payload);
|
||||
qCDebug(dcAuthenticationProcess()) << "canonical request:" << "\n" << qUtf8Printable(canonicalRequest);
|
||||
QByteArray stringToSign = SigV4Utils::getStringToSign(canonicalRequest, dateTime, region.toUtf8(), service.toUtf8());
|
||||
qCDebug(dcAuthenticationProcess()) << "string to sign:" << "\n" << qUtf8Printable(stringToSign);
|
||||
QByteArray signature = SigV4Utils::getSignature(stringToSign, secretAccessKey, dateTime, region, service);
|
||||
qCDebug(dcAuthenticationProcess()) << "signature:" << signature;
|
||||
QByteArray authorizeHeader = SigV4Utils::getAuthorizationHeader(accessKeyId, dateTime, region, service, request, signature);
|
||||
|
||||
request.setRawHeader("Authorization", authorizeHeader);
|
||||
}
|
||||
|
||||
QByteArray SigV4Utils::getCurrentDateTime()
|
||||
{
|
||||
return QDateTime::currentDateTime().toUTC().toString("yyyyMMddThhmmssZ").toUtf8();
|
||||
}
|
||||
|
||||
QByteArray SigV4Utils::getCanonicalQueryString(const QNetworkRequest &request, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken, const QByteArray ®ion, const QByteArray &service, const QByteArray &payload)
|
||||
{
|
||||
QByteArray algorithm = "AWS4-HMAC-SHA256";
|
||||
QByteArray dateTime = getCurrentDateTime();
|
||||
QByteArray credentialScope = getCredentialScope(algorithm, dateTime, region, service);
|
||||
|
||||
QByteArray canonicalQueryString;
|
||||
canonicalQueryString += "X-Amz-Algorithm=AWS4-HMAC-SHA256";
|
||||
canonicalQueryString += "&X-Amz-Credential=" + QByteArray(accessKeyId + '/' + credentialScope).toPercentEncoding();
|
||||
canonicalQueryString += "&X-Amz-Date=" + dateTime;
|
||||
if (request.rawHeaderList().count() > 0){
|
||||
canonicalQueryString += "&X-Amz-SignedHeaders=" + request.rawHeaderList().join(';').toLower();
|
||||
}
|
||||
|
||||
QByteArray canonicalRequest = getCanonicalRequest(QNetworkAccessManager::GetOperation, request, payload);
|
||||
|
||||
QByteArray stringToSign = getStringToSign(canonicalRequest, dateTime, region, service);
|
||||
QByteArray signature = getSignature(stringToSign, secretAccessKey, dateTime, region, service);
|
||||
|
||||
canonicalQueryString += "&X-Amz-Signature=" + signature;
|
||||
|
||||
if (!sessionToken.isEmpty()) {
|
||||
canonicalQueryString += "&X-Amz-Security-Token=" + sessionToken.toPercentEncoding();
|
||||
}
|
||||
|
||||
return canonicalQueryString;
|
||||
}
|
||||
|
||||
QByteArray SigV4Utils::getSignatureKey(const QByteArray &key, const QByteArray &date, const QByteArray ®ion, const QByteArray &service)
|
||||
{
|
||||
QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
|
||||
return QMessageAuthenticationCode::hash("aws4_request",
|
||||
QMessageAuthenticationCode::hash(service,
|
||||
QMessageAuthenticationCode::hash(region,
|
||||
QMessageAuthenticationCode::hash(date, "AWS4" + key,
|
||||
hashAlgorithm), hashAlgorithm), hashAlgorithm), hashAlgorithm);
|
||||
}
|
||||
|
||||
QByteArray SigV4Utils::getCanonicalRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, const QByteArray &payload)
|
||||
{
|
||||
QByteArray canonicalRequest;
|
||||
|
||||
QByteArray method;
|
||||
switch (operation) {
|
||||
case QNetworkAccessManager::GetOperation:
|
||||
method = "GET";
|
||||
break;
|
||||
case QNetworkAccessManager::PostOperation:
|
||||
method = "POST";
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT_X(false, "Network operation not implemented", "SigV4Utils");
|
||||
}
|
||||
QByteArray uri = request.url().path(QUrl::FullyEncoded).toUtf8();
|
||||
|
||||
QUrlQuery query(request.url());
|
||||
QList<QPair<QString, QString> > queryItems = query.queryItems();
|
||||
QStringList queryItemStrings;
|
||||
for (int i = 0; i < queryItems.count(); i++) {
|
||||
QPair<QString, QString> queryItem = queryItems.at(i);
|
||||
queryItemStrings.append(queryItem.first + '=' + queryItem.second);
|
||||
}
|
||||
queryItemStrings.sort(Qt::CaseInsensitive);
|
||||
|
||||
QByteArray canonicalQueryString = queryItemStrings.join('&').toUtf8();
|
||||
|
||||
QByteArray canonicalHeaders;
|
||||
foreach(const QByteArray &headerName, request.rawHeaderList()) {
|
||||
canonicalHeaders += headerName.toLower() + ':' + request.rawHeader(headerName) + '\n';
|
||||
}
|
||||
|
||||
QByteArray payloadHash = QCryptographicHash::hash(payload, QCryptographicHash::Sha256).toHex();
|
||||
|
||||
canonicalRequest = method + '\n' + uri + '\n' + canonicalQueryString + '\n' + canonicalHeaders + '\n' + request.rawHeaderList().join(';').toLower() + '\n' + payloadHash.toLower();
|
||||
return canonicalRequest;
|
||||
}
|
||||
|
||||
QByteArray SigV4Utils::getCredentialScope(const QByteArray &algorithm, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service)
|
||||
{
|
||||
Q_UNUSED(algorithm)
|
||||
QByteArray credentialScope = dateTime.left(8) + '/' + region + '/' + service + "/aws4_request";
|
||||
return credentialScope;
|
||||
}
|
||||
|
||||
QByteArray SigV4Utils::getStringToSign(const QByteArray &canonicalRequest, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service)
|
||||
{
|
||||
QByteArray algorithm = "AWS4-HMAC-SHA256";
|
||||
QByteArray credentialScope = getCredentialScope(algorithm, dateTime, region, service);
|
||||
QByteArray stringToSign = algorithm + '\n' + dateTime + '\n' + credentialScope + '\n' + QCryptographicHash::hash(canonicalRequest, QCryptographicHash::Sha256).toHex();
|
||||
return stringToSign;
|
||||
}
|
||||
|
||||
QByteArray SigV4Utils::getSignature(const QByteArray &stringToSign, const QByteArray &secretAccessKey, const QByteArray &dateTime, const QString ®ion, const QString &service)
|
||||
{
|
||||
QByteArray signingKey = getSignatureKey(secretAccessKey, dateTime.left(8), region.toUtf8(), service.toUtf8());
|
||||
QByteArray signature = QMessageAuthenticationCode::hash(stringToSign, signingKey, QCryptographicHash::Sha256).toHex();
|
||||
return signature;
|
||||
}
|
||||
|
||||
QByteArray SigV4Utils::getAuthorizationHeader(const QByteArray &accessKeyId, const QByteArray &dateTime, const QString ®ion, const QString &service, const QNetworkRequest &request, const QByteArray &signature)
|
||||
{
|
||||
QByteArray authHeader = "AWS4-HMAC-SHA256 Credential=" + accessKeyId + '/' + dateTime.left(8) + '/' + region.toUtf8() + '/' + service.toUtf8() + '/' + "aws4_request, SignedHeaders=" + request.rawHeaderList().join(';').toLower() + ", Signature=" + signature;
|
||||
return authHeader;
|
||||
}
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef SIGV4UTILS_H
|
||||
#define SIGV4UTILS_H
|
||||
|
||||
#include <QString>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class SigV4Utils
|
||||
{
|
||||
public:
|
||||
SigV4Utils();
|
||||
|
||||
// Signes a request by adding the "X-AMZ-Date" (if not present) and "X-AMZ-Signature" headers
|
||||
static void signRequest(QNetworkAccessManager::Operation operation, QNetworkRequest &request, const QString ®ion, const QString &service, const QString &invocationType, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken = QByteArray(), const QByteArray &payload = QByteArray());
|
||||
|
||||
static QByteArray getCurrentDateTime();
|
||||
|
||||
static QByteArray getCanonicalQueryString(const QNetworkRequest &request, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken, const QByteArray ®ion, const QByteArray &service, const QByteArray &payload);
|
||||
static QByteArray getCanonicalRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, const QByteArray &payload);
|
||||
static QByteArray getCanonicalHeaders(const QNetworkRequest &request);
|
||||
static QByteArray getCredentialScope(const QByteArray &algorithm, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service);
|
||||
static QByteArray getStringToSign(const QByteArray &canonicalRequest, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service);
|
||||
static QByteArray getSignatureKey(const QByteArray &key, const QByteArray &date, const QByteArray ®ion, const QByteArray &service);
|
||||
static QByteArray getSignature(const QByteArray &stringToSign, const QByteArray &secretAccessKey, const QByteArray &dateTime, const QString ®ion, const QString &service);
|
||||
static QByteArray getAuthorizationHeader(const QByteArray &accessKeyId, const QByteArray &dateTime, const QString ®ion, const QString &service, const QNetworkRequest &request, const QByteArray &signature);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SIGV4UTILS_H
|
||||
@ -1,79 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "userinformation.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
UserInformation::UserInformation(const QString &email, const QString &cognitoUsername, const QString &vendorId, const QString &userPoolId) :
|
||||
m_email(email),
|
||||
m_cognitoUsername(cognitoUsername),
|
||||
m_vendorId(vendorId),
|
||||
m_userPoolId(userPoolId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString UserInformation::email() const
|
||||
{
|
||||
return m_email;
|
||||
}
|
||||
|
||||
QString UserInformation::cognitoUsername() const
|
||||
{
|
||||
return m_cognitoUsername;
|
||||
}
|
||||
|
||||
QString UserInformation::vendorId() const
|
||||
{
|
||||
return m_vendorId;
|
||||
}
|
||||
|
||||
QString UserInformation::userPoolId() const
|
||||
{
|
||||
return m_userPoolId;
|
||||
}
|
||||
|
||||
bool UserInformation::isValid()
|
||||
{
|
||||
return !m_email.isEmpty()
|
||||
&& !m_cognitoUsername.isEmpty()
|
||||
&& !m_vendorId.isEmpty()
|
||||
&& !m_userPoolId.isEmpty();
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const UserInformation &userInformation)
|
||||
{
|
||||
QDebugStateSaver saver(debug);
|
||||
debug.nospace() << "UserInformation(" << userInformation.email();
|
||||
debug.nospace() << ", cognito:" << userInformation.cognitoUsername() << ") ";
|
||||
debug.nospace() << ", vendor" << userInformation.vendorId() << ") ";
|
||||
debug.nospace() << ", userpool" << userInformation.userPoolId() << ")";
|
||||
return debug;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef USERINFORMATION_H
|
||||
#define USERINFORMATION_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
|
||||
class UserInformation
|
||||
{
|
||||
public:
|
||||
UserInformation(const QString &email = QString(), const QString &cognitoUsername = QString(), const QString &vendorId = QString(), const QString &userPoolId = QString());
|
||||
|
||||
QString email() const;
|
||||
QString cognitoUsername() const;
|
||||
QString vendorId() const;
|
||||
QString userPoolId() const;
|
||||
|
||||
bool isValid();
|
||||
|
||||
private:
|
||||
QString m_email;
|
||||
QString m_cognitoUsername;
|
||||
QString m_vendorId;
|
||||
QString m_userPoolId;
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, const UserInformation &userInformation);
|
||||
|
||||
}
|
||||
|
||||
#endif // USERINFORMATION_H
|
||||
@ -1,59 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "dummyauthenticator.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
DummyAuthenticator::DummyAuthenticator(QObject *parent) :
|
||||
Authenticator(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString DummyAuthenticator::name() const
|
||||
{
|
||||
return "Dummy authenticator";
|
||||
}
|
||||
|
||||
AuthenticationReply *DummyAuthenticator::authenticate(ProxyClient *proxyClient)
|
||||
{
|
||||
qCDebug(dcAuthentication()) << name() << "validate" << proxyClient;
|
||||
qCWarning(dcAuthentication()) << "Attention: This authenticator will always succeed! This is a security risk and was explicitly enabled!";
|
||||
AuthenticationReply *reply = createAuthenticationReply(proxyClient, proxyClient);
|
||||
|
||||
proxyClient->setUserName("dummy@example.com");
|
||||
|
||||
setReplyError(reply, AuthenticationErrorNoError);
|
||||
setReplyFinished(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef DUMMYAUTHENTICATOR_H
|
||||
#define DUMMYAUTHENTICATOR_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "proxy/proxyclient.h"
|
||||
#include "authentication/authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class DummyAuthenticator : public Authenticator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DummyAuthenticator(QObject *parent = nullptr);
|
||||
~DummyAuthenticator() override = default;
|
||||
|
||||
QString name() const override;
|
||||
|
||||
public slots:
|
||||
AuthenticationReply *authenticate(ProxyClient *proxyClient) override;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DUMMYAUTHENTICATOR_H
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -69,49 +69,13 @@ void Engine::start(ProxyConfiguration *configuration)
|
||||
m_configuration = configuration;
|
||||
qCDebug(dcEngine()) << "Using configuration" << m_configuration;
|
||||
|
||||
// TODO: the old proxy server is deprecated. Will be removed in future releases
|
||||
if (configuration->proxyEnabled()) {
|
||||
// Make sure an authenticator was registered
|
||||
Q_ASSERT_X(m_authenticator != nullptr, "Engine", "There is no authenticator registerd.");
|
||||
|
||||
// Proxy
|
||||
// -------------------------------------
|
||||
m_proxyServer = new ProxyServer(this);
|
||||
m_webSocketServerProxy = new WebSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
|
||||
m_tcpSocketServerProxy = new TcpSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
|
||||
m_unixSocketServerProxy = new UnixSocketServer(m_configuration->unixSocketFileName(), this);
|
||||
|
||||
// Configure websocket server
|
||||
QUrl websocketServerUrl;
|
||||
websocketServerUrl.setScheme(m_configuration->sslEnabled() ? "wss" : "ws");
|
||||
websocketServerUrl.setHost(m_configuration->webSocketServerProxyHost().toString());
|
||||
websocketServerUrl.setPort(m_configuration->webSocketServerProxyPort());
|
||||
m_webSocketServerProxy->setServerUrl(websocketServerUrl);
|
||||
|
||||
// Configure tcp socket server
|
||||
QUrl tcpSocketServerProxyUrl;
|
||||
tcpSocketServerProxyUrl.setScheme(m_configuration->sslEnabled() ? "ssl" : "tcp");
|
||||
tcpSocketServerProxyUrl.setHost(m_configuration->tcpServerHost().toString());
|
||||
tcpSocketServerProxyUrl.setPort(m_configuration->tcpServerPort());
|
||||
m_tcpSocketServerProxy->setServerUrl(tcpSocketServerProxyUrl);
|
||||
|
||||
// Register the transport interfaces in the proxy server
|
||||
m_proxyServer->registerTransportInterface(m_webSocketServerProxy);
|
||||
m_proxyServer->registerTransportInterface(m_tcpSocketServerProxy);
|
||||
m_proxyServer->registerTransportInterface(m_unixSocketServerProxy);
|
||||
|
||||
// Start the server
|
||||
qCDebug(dcEngine()) << "Starting the proxy servers...";
|
||||
m_proxyServer->startServer();
|
||||
} else {
|
||||
qCDebug(dcEngine()) << "Proxy server disabled. Not starting proxy server.";
|
||||
}
|
||||
|
||||
// Tunnel proxy
|
||||
// -------------------------------------
|
||||
m_tunnelProxyServer = new TunnelProxyServer(this);
|
||||
m_webSocketServerTunnelProxy = new WebSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
|
||||
m_tcpSocketServerTunnelProxy = new TcpSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
|
||||
m_unixSocketServerTunnelProxy = new UnixSocketServer(m_configuration->unixSocketFileName(), this);
|
||||
|
||||
// Configure websocket server
|
||||
QUrl websocketServerTunnelProxyUrl;
|
||||
@ -130,6 +94,7 @@ void Engine::start(ProxyConfiguration *configuration)
|
||||
// Register the transport interfaces in the proxy server
|
||||
m_tunnelProxyServer->registerTransportInterface(m_webSocketServerTunnelProxy);
|
||||
m_tunnelProxyServer->registerTransportInterface(m_tcpSocketServerTunnelProxy);
|
||||
m_tunnelProxyServer->registerTransportInterface(m_unixSocketServerTunnelProxy);
|
||||
|
||||
// Start the server
|
||||
qCDebug(dcEngine()) << "Starting the tunnel proxy manager...";
|
||||
@ -161,67 +126,24 @@ bool Engine::running() const
|
||||
return m_running;
|
||||
}
|
||||
|
||||
bool Engine::developerMode() const
|
||||
{
|
||||
return m_developerMode;
|
||||
}
|
||||
|
||||
QString Engine::serverName() const
|
||||
{
|
||||
return m_configuration->serverName();
|
||||
}
|
||||
|
||||
void Engine::setAuthenticator(Authenticator *authenticator)
|
||||
{
|
||||
if (m_authenticator == authenticator)
|
||||
return;
|
||||
|
||||
if (m_authenticator) {
|
||||
qCDebug(dcEngine()) << "There is already an authenticator registered. Unregister default authenticator";
|
||||
m_authenticator = nullptr;
|
||||
}
|
||||
|
||||
m_authenticator = authenticator;
|
||||
}
|
||||
|
||||
void Engine::setDeveloperModeEnabled(bool enabled)
|
||||
{
|
||||
m_developerMode = enabled;
|
||||
}
|
||||
|
||||
ProxyConfiguration *Engine::configuration() const
|
||||
{
|
||||
return m_configuration;
|
||||
}
|
||||
|
||||
Authenticator *Engine::authenticator() const
|
||||
{
|
||||
return m_authenticator;
|
||||
}
|
||||
|
||||
ProxyServer *Engine::proxyServer() const
|
||||
{
|
||||
return m_proxyServer;
|
||||
}
|
||||
|
||||
TunnelProxyServer *Engine::tunnelProxyServer() const
|
||||
{
|
||||
return m_tunnelProxyServer;
|
||||
}
|
||||
|
||||
TcpSocketServer *Engine::tcpSocketServerProxy() const
|
||||
UnixSocketServer *Engine::unixSocketServerTunnelProxy() const
|
||||
{
|
||||
return m_tcpSocketServerProxy;
|
||||
}
|
||||
|
||||
WebSocketServer *Engine::webSocketServerProxy() const
|
||||
{
|
||||
return m_webSocketServerProxy;
|
||||
}
|
||||
|
||||
UnixSocketServer *Engine::unixSocketServerProxy() const
|
||||
{
|
||||
return m_unixSocketServerProxy;
|
||||
return m_unixSocketServerTunnelProxy;
|
||||
}
|
||||
|
||||
TcpSocketServer *Engine::tcpSocketServerTunnelProxy() const
|
||||
@ -250,9 +172,6 @@ QVariantMap Engine::buildMonitorData(bool printAll)
|
||||
monitorData.insert("serverName", m_configuration->serverName());
|
||||
monitorData.insert("serverVersion", SERVER_VERSION_STRING);
|
||||
monitorData.insert("apiVersion", API_VERSION_STRING);
|
||||
if (m_proxyServer) {
|
||||
monitorData.insert("proxyStatistic", m_proxyServer->currentStatistics());
|
||||
}
|
||||
monitorData.insert("tunnelProxyStatistic", tunnelProxyServer()->currentStatistics(printAll));
|
||||
return monitorData;
|
||||
}
|
||||
@ -285,21 +204,9 @@ void Engine::onTimerTick()
|
||||
if (m_currentTimeCounter >= 1000) {
|
||||
// One second passed, do second tick
|
||||
m_currentTimeCounter = 0;
|
||||
|
||||
if (m_proxyServer) {
|
||||
m_proxyServer->tick();
|
||||
}
|
||||
|
||||
if (m_tunnelProxyServer) {
|
||||
m_tunnelProxyServer->tick();
|
||||
}
|
||||
|
||||
// QVariantMap serverStatistics = buildMonitorData();
|
||||
// m_monitorServer->updateClients(serverStatistics);
|
||||
|
||||
// m_logEngine->logStatistics(serverStatistics.value("proxyStatistic").toMap().value("tunnelCount").toInt(),
|
||||
// serverStatistics.value("proxyStatistic").toMap().value("clientCount").toInt(),
|
||||
// serverStatistics.value("proxyStatistic").toMap().value("troughput").toInt());
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,28 +218,12 @@ void Engine::clean()
|
||||
m_monitorServer = nullptr;
|
||||
}
|
||||
|
||||
if (m_proxyServer) {
|
||||
m_proxyServer->stopServer();
|
||||
delete m_proxyServer;
|
||||
m_proxyServer = nullptr;
|
||||
}
|
||||
|
||||
if (m_tunnelProxyServer) {
|
||||
m_tunnelProxyServer->stopServer();
|
||||
delete m_tunnelProxyServer;
|
||||
m_tunnelProxyServer = nullptr;
|
||||
}
|
||||
|
||||
if (m_tcpSocketServerProxy) {
|
||||
delete m_tcpSocketServerProxy;
|
||||
m_tcpSocketServerProxy = nullptr;
|
||||
}
|
||||
|
||||
if (m_webSocketServerProxy) {
|
||||
delete m_webSocketServerProxy;
|
||||
m_webSocketServerProxy = nullptr;
|
||||
}
|
||||
|
||||
if (m_tcpSocketServerTunnelProxy) {
|
||||
delete m_tcpSocketServerTunnelProxy;
|
||||
m_tcpSocketServerTunnelProxy = nullptr;
|
||||
@ -343,6 +234,11 @@ void Engine::clean()
|
||||
m_webSocketServerTunnelProxy = nullptr;
|
||||
}
|
||||
|
||||
if (m_unixSocketServerTunnelProxy) {
|
||||
delete m_unixSocketServerTunnelProxy;
|
||||
m_unixSocketServerTunnelProxy = nullptr;
|
||||
}
|
||||
|
||||
if (m_configuration) {
|
||||
delete m_configuration;
|
||||
m_configuration = nullptr;
|
||||
@ -354,9 +250,6 @@ void Engine::setRunning(bool running)
|
||||
if (m_running == running)
|
||||
return;
|
||||
|
||||
if (m_proxyServer)
|
||||
m_proxyServer->setRunning(running);
|
||||
|
||||
if (m_tunnelProxyServer)
|
||||
m_tunnelProxyServer->setRunning(running);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -36,14 +36,12 @@
|
||||
#include <QSslConfiguration>
|
||||
|
||||
#include "logengine.h"
|
||||
#include "proxy/proxyserver.h"
|
||||
#include "proxyconfiguration.h"
|
||||
#include "server/monitorserver.h"
|
||||
#include "server/jsonrpcserver.h"
|
||||
#include "server/tcpsocketserver.h"
|
||||
#include "server/websocketserver.h"
|
||||
#include "server/unixsocketserver.h"
|
||||
#include "authentication/authenticator.h"
|
||||
#include "tunnelproxy/tunnelproxyserver.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
@ -61,23 +59,14 @@ public:
|
||||
void stop();
|
||||
|
||||
bool running() const;
|
||||
bool developerMode() const;
|
||||
|
||||
QString serverName() const;
|
||||
|
||||
void setAuthenticator(Authenticator *authenticator);
|
||||
void setDeveloperModeEnabled(bool enabled);
|
||||
|
||||
ProxyConfiguration *configuration() const;
|
||||
Authenticator *authenticator() const;
|
||||
|
||||
ProxyServer *proxyServer() const;
|
||||
TunnelProxyServer *tunnelProxyServer() const;
|
||||
|
||||
TcpSocketServer *tcpSocketServerProxy() const;
|
||||
WebSocketServer *webSocketServerProxy() const;
|
||||
UnixSocketServer *unixSocketServerProxy() const;
|
||||
|
||||
UnixSocketServer *unixSocketServerTunnelProxy() const;
|
||||
TcpSocketServer *tcpSocketServerTunnelProxy() const;
|
||||
WebSocketServer *webSocketServerTunnelProxy() const;
|
||||
|
||||
@ -97,18 +86,11 @@ private:
|
||||
qint64 m_runTime = 0;
|
||||
|
||||
bool m_running = false;
|
||||
bool m_developerMode = false;
|
||||
|
||||
ProxyConfiguration *m_configuration = nullptr;
|
||||
Authenticator *m_authenticator = nullptr;
|
||||
|
||||
ProxyServer *m_proxyServer = nullptr;
|
||||
TunnelProxyServer *m_tunnelProxyServer = nullptr;
|
||||
|
||||
TcpSocketServer *m_tcpSocketServerProxy = nullptr;
|
||||
WebSocketServer *m_webSocketServerProxy = nullptr;
|
||||
UnixSocketServer *m_unixSocketServerProxy = nullptr;
|
||||
|
||||
UnixSocketServer *m_unixSocketServerTunnelProxy = nullptr;
|
||||
TcpSocketServer *m_tcpSocketServerTunnelProxy = nullptr;
|
||||
WebSocketServer *m_webSocketServerTunnelProxy = nullptr;
|
||||
|
||||
|
||||
@ -1,106 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "jsontypes.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "authenticationhandler.h"
|
||||
#include "server/transportclient.h"
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
AuthenticationHandler::AuthenticationHandler(QObject *parent) :
|
||||
JsonHandler(parent)
|
||||
{
|
||||
// Methods
|
||||
QVariantMap params; QVariantMap returns;
|
||||
|
||||
setDescription("Authenticate", "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.insert("uuid", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
params.insert("token", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
params.insert("o:nonce", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
setParams("Authenticate", params);
|
||||
returns.insert("authenticationError", JsonTypes::authenticationErrorRef());
|
||||
setReturns("Authenticate", returns);
|
||||
}
|
||||
|
||||
QString AuthenticationHandler::name() const
|
||||
{
|
||||
return "Authentication";
|
||||
}
|
||||
|
||||
JsonReply *AuthenticationHandler::Authenticate(const QVariantMap ¶ms, TransportClient *transportClient)
|
||||
{
|
||||
QUuid uuid = params.value("uuid").toUuid();
|
||||
QString name = params.value("name").toString();
|
||||
QString token = params.value("token").toString();
|
||||
QString nonce = params.value("nonce").toString();
|
||||
|
||||
qCDebug(dcJsonRpc()) << "Authenticate:" << name << uuid << token << nonce;
|
||||
JsonReply *jsonReply = createAsyncReply("Authenticate");
|
||||
|
||||
// Set the token for this proxy client
|
||||
ProxyClient *proxyClient = qobject_cast<ProxyClient *>(transportClient);
|
||||
proxyClient->setUuid(uuid);
|
||||
proxyClient->setName(name);
|
||||
proxyClient->setToken(token);
|
||||
proxyClient->setNonce(nonce);
|
||||
|
||||
AuthenticationReply *authReply = Engine::instance()->authenticator()->authenticate(proxyClient);
|
||||
connect(authReply, &AuthenticationReply::finished, jsonReply, [=](){
|
||||
authReply->deleteLater();
|
||||
|
||||
qCDebug(dcJsonRpc()) << "Authentication reply finished";
|
||||
if (authReply->error() != Authenticator::AuthenticationErrorNoError) {
|
||||
qCWarning(dcJsonRpc()) << "Authentication error occurred" << authReply->error();
|
||||
jsonReply->setSuccess(false);
|
||||
} else {
|
||||
// Successfully authenticated
|
||||
jsonReply->setSuccess(true);
|
||||
}
|
||||
|
||||
// Set client authenticated if still there
|
||||
if (!authReply->proxyClient().isNull()) {
|
||||
authReply->proxyClient()->setAuthenticated(authReply->error() == Authenticator::AuthenticationErrorNoError);
|
||||
jsonReply->setData(errorToReply(authReply->error()));
|
||||
}
|
||||
|
||||
emit jsonReply->finished();
|
||||
});
|
||||
|
||||
return jsonReply;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef AUTHENTICATIONHANDLER_H
|
||||
#define AUTHENTICATIONHANDLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "jsonhandler.h"
|
||||
#include "authentication/authenticationreply.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class TransportClient;
|
||||
|
||||
class AuthenticationHandler : public JsonHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AuthenticationHandler(QObject *parent = nullptr);
|
||||
~AuthenticationHandler() override = default;
|
||||
|
||||
QString name() const override;
|
||||
|
||||
Q_INVOKABLE JsonReply *Authenticate(const QVariantMap ¶ms, TransportClient *transportClient);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AUTHENTICATIONHANDLER_H
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -135,12 +135,6 @@ void JsonHandler::setReturns(const QString &methodName, const QVariantMap &retur
|
||||
qCWarning(dcJsonRpc()) << "Cannot set returns. No such method:" << methodName;
|
||||
}
|
||||
|
||||
QVariantMap JsonHandler::errorToReply(Authenticator::AuthenticationError error) const
|
||||
{
|
||||
QVariantMap returns;
|
||||
returns.insert("authenticationError", JsonTypes::authenticationErrorToString(error));
|
||||
return returns;
|
||||
}
|
||||
|
||||
JsonReply *JsonHandler::createReply(const QString &method, const QVariantMap &data) const
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -34,8 +34,6 @@
|
||||
#include <QVariantMap>
|
||||
#include <QMetaMethod>
|
||||
|
||||
#include "authentication/authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class JsonReply;
|
||||
@ -67,8 +65,6 @@ protected:
|
||||
void setParams(const QString &methodName, const QVariantMap ¶ms);
|
||||
void setReturns(const QString &methodName, const QVariantMap &returns);
|
||||
|
||||
QVariantMap errorToReply(Authenticator::AuthenticationError error) const;
|
||||
|
||||
JsonReply *createReply(const QString &method, const QVariantMap &data) const;
|
||||
JsonReply *createAsyncReply(const QString &method) const;
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -39,7 +39,6 @@ QString JsonTypes::s_lastError;
|
||||
|
||||
// Types
|
||||
QVariantList JsonTypes::s_basicType;
|
||||
QVariantList JsonTypes::s_authenticationError;
|
||||
QVariantList JsonTypes::s_tunnelProxyError;
|
||||
|
||||
// Objects
|
||||
@ -51,7 +50,6 @@ QVariantMap JsonTypes::allTypes()
|
||||
|
||||
// Enums
|
||||
allTypes.insert("BasicType", basicType());
|
||||
allTypes.insert("AuthenticationError", authenticationError());
|
||||
allTypes.insert("TunnelProxyError", tunnelProxyError());
|
||||
|
||||
return allTypes;
|
||||
@ -61,7 +59,6 @@ void JsonTypes::init()
|
||||
{
|
||||
// Declare types
|
||||
s_basicType = enumToStrings(JsonTypes::staticMetaObject, "BasicType");
|
||||
s_authenticationError = enumToStrings(Authenticator::staticMetaObject, "AuthenticationError");
|
||||
s_tunnelProxyError = enumToStrings(TunnelProxyServer::staticMetaObject, "TunnelProxyError");
|
||||
|
||||
s_initialized = true;
|
||||
@ -118,12 +115,6 @@ QPair<bool, QString> JsonTypes::validateVariant(const QVariant &templateVariant,
|
||||
qCWarning(dcJsonRpc()) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(basicTypeRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == authenticationErrorRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_authenticationError, variant);
|
||||
if (!result.first) {
|
||||
qCWarning(dcJsonRpc()) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(authenticationErrorRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == tunnelProxyErrorRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_tunnelProxyError, variant);
|
||||
if (!result.first) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -34,7 +34,6 @@
|
||||
#include <QStringList>
|
||||
|
||||
#include "tunnelproxy/tunnelproxyserver.h"
|
||||
#include "authentication/authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
@ -90,7 +89,6 @@ public:
|
||||
|
||||
// Declare types
|
||||
DECLARE_TYPE(basicType, "BasicType", JsonTypes, BasicType)
|
||||
DECLARE_TYPE(authenticationError, "AuthenticationError", Authenticator, AuthenticationError)
|
||||
DECLARE_TYPE(tunnelProxyError, "TunnelProxyError", TunnelProxyServer, TunnelProxyError)
|
||||
|
||||
// Declare objects
|
||||
|
||||
@ -9,22 +9,10 @@ HEADERS += \
|
||||
logengine.h \
|
||||
loggingcategories.h \
|
||||
proxyconfiguration.h \
|
||||
authentication/authenticator.h \
|
||||
authentication/authenticationreply.h \
|
||||
authentication/aws/awsauthenticator.h \
|
||||
authentication/aws/userinformation.h \
|
||||
authentication/aws/authenticationprocess.h \
|
||||
authentication/aws/sigv4utils.h \
|
||||
authentication/aws/awscredentialprovider.h \
|
||||
authentication/dummy/dummyauthenticator.h \
|
||||
jsonrpc/jsonhandler.h \
|
||||
jsonrpc/jsonreply.h \
|
||||
jsonrpc/jsontypes.h \
|
||||
jsonrpc/authenticationhandler.h \
|
||||
jsonrpc/tunnelproxyhandler.h \
|
||||
proxy/proxyclient.h \
|
||||
proxy/proxyserver.h \
|
||||
proxy/tunnelconnection.h \
|
||||
server/tcpsocketserver.h \
|
||||
server/transportinterface.h \
|
||||
server/unixsocketserver.h \
|
||||
@ -42,22 +30,10 @@ SOURCES += \
|
||||
logengine.cpp \
|
||||
loggingcategories.cpp \
|
||||
proxyconfiguration.cpp \
|
||||
authentication/authenticator.cpp \
|
||||
authentication/authenticationreply.cpp \
|
||||
authentication/aws/awsauthenticator.cpp \
|
||||
authentication/aws/userinformation.cpp \
|
||||
authentication/aws/authenticationprocess.cpp \
|
||||
authentication/aws/sigv4utils.cpp \
|
||||
authentication/aws/awscredentialprovider.cpp \
|
||||
authentication/dummy/dummyauthenticator.cpp \
|
||||
jsonrpc/jsonhandler.cpp \
|
||||
jsonrpc/jsonreply.cpp \
|
||||
jsonrpc/jsontypes.cpp \
|
||||
jsonrpc/authenticationhandler.cpp \
|
||||
jsonrpc/tunnelproxyhandler.cpp \
|
||||
proxy/proxyclient.cpp \
|
||||
proxy/proxyserver.cpp \
|
||||
proxy/tunnelconnection.cpp \
|
||||
server/tcpsocketserver.cpp \
|
||||
server/transportinterface.cpp \
|
||||
server/transportclient.cpp \
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -44,25 +44,6 @@ LogEngine::~LogEngine()
|
||||
disable();
|
||||
}
|
||||
|
||||
void LogEngine::logTunnel(const TunnelConnection &tunnel)
|
||||
{
|
||||
if (!m_tunnelsFile.isOpen())
|
||||
return;
|
||||
|
||||
// <timestamp> <tunnel creation timestamp> <user name> <first client address> <second client addrees> <total tunnel traffic>
|
||||
|
||||
QStringList logString;
|
||||
logString << createTimestamp();
|
||||
logString << QString::number(tunnel.creationTime());
|
||||
logString << tunnel.clientOne()->userName();
|
||||
logString << tunnel.clientOne()->peerAddress().toString();
|
||||
logString << tunnel.clientTwo()->peerAddress().toString();
|
||||
logString << QString::number(tunnel.clientOne()->rxDataCount() + tunnel.clientOne()->txDataCount());
|
||||
|
||||
QTextStream textStream(&m_tunnelsFile);
|
||||
textStream << logString.join(" ") << "\n";
|
||||
}
|
||||
|
||||
void LogEngine::logStatistics(int tunnelCount, int connectionCount, int troughput)
|
||||
{
|
||||
if (!m_statisticsFile.isOpen())
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -31,8 +31,6 @@
|
||||
#include <QFile>
|
||||
#include <QObject>
|
||||
|
||||
#include "proxy/tunnelconnection.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class LogEngine : public QObject
|
||||
@ -42,7 +40,6 @@ public:
|
||||
explicit LogEngine(QObject *parent = nullptr);
|
||||
~LogEngine();
|
||||
|
||||
void logTunnel(const TunnelConnection &tunnel);
|
||||
void logStatistics(int tunnelCount, int connectionCount, int troughput);
|
||||
|
||||
private:
|
||||
|
||||
@ -30,20 +30,14 @@
|
||||
Q_LOGGING_CATEGORY(dcApplication, "Application")
|
||||
Q_LOGGING_CATEGORY(dcEngine, "Engine")
|
||||
Q_LOGGING_CATEGORY(dcJsonRpc, "JsonRpc")
|
||||
Q_LOGGING_CATEGORY(dcTunnel, "Tunnel")
|
||||
Q_LOGGING_CATEGORY(dcJsonRpcTraffic, "JsonRpcTraffic")
|
||||
Q_LOGGING_CATEGORY(dcTcpSocketServer, "TcpSocketServer")
|
||||
Q_LOGGING_CATEGORY(dcTcpSocketServerTraffic, "TcpSocketServerTraffic")
|
||||
Q_LOGGING_CATEGORY(dcWebSocketServer, "WebSocketServer")
|
||||
Q_LOGGING_CATEGORY(dcWebSocketServerTraffic, "WebSocketServerTraffic")
|
||||
Q_LOGGING_CATEGORY(dcAuthentication, "Authentication")
|
||||
Q_LOGGING_CATEGORY(dcAuthenticationProcess, "AuthenticationProcess")
|
||||
Q_LOGGING_CATEGORY(dcProxyServer, "ProxyServer")
|
||||
Q_LOGGING_CATEGORY(dcProxyServerTraffic, "ProxyServerTraffic")
|
||||
Q_LOGGING_CATEGORY(dcTunnelProxyServer, "TunnelProxyServer")
|
||||
Q_LOGGING_CATEGORY(dcTunnelProxyServerTraffic, "TunnelProxyServerTraffic")
|
||||
Q_LOGGING_CATEGORY(dcMonitorServer, "MonitorServer")
|
||||
Q_LOGGING_CATEGORY(dcUnixSocketServer, "UnixSocketServer")
|
||||
Q_LOGGING_CATEGORY(dcUnixSocketServerTraffic, "UnixSocketServerTraffic")
|
||||
Q_LOGGING_CATEGORY(dcAwsCredentialsProvider, "AwsCredentialsProvider")
|
||||
Q_LOGGING_CATEGORY(dcAwsCredentialsProviderTraffic, "AwsCredentialsProviderTraffic")
|
||||
|
||||
|
||||
@ -34,22 +34,15 @@
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcApplication)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcEngine)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcJsonRpc)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcTunnel)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcJsonRpcTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServerTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcTcpSocketServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcTcpSocketServerTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAuthentication)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAuthenticationProcess)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcProxyServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcProxyServerTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcTunnelProxyServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcTunnelProxyServerTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcMonitorServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcUnixSocketServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcUnixSocketServerTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAwsCredentialsProvider)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAwsCredentialsProviderTraffic)
|
||||
|
||||
#endif // LOGGINGCATEGORIES_H
|
||||
|
||||
@ -1,161 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "engine.h"
|
||||
#include "proxyclient.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
ProxyClient::ProxyClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent) :
|
||||
TransportClient(interface, clientId, address, parent)
|
||||
{
|
||||
m_timer = new QTimer(this);
|
||||
connect(m_timer, &QTimer::timeout, this, &ProxyClient::timeoutOccurred);
|
||||
m_timer->setSingleShot(true);
|
||||
resetTimer();
|
||||
}
|
||||
|
||||
bool ProxyClient::isAuthenticated() const
|
||||
{
|
||||
return m_authenticated;
|
||||
}
|
||||
|
||||
void ProxyClient::setAuthenticated(bool isAuthenticated)
|
||||
{
|
||||
m_authenticated = isAuthenticated;
|
||||
if (m_authenticated) {
|
||||
m_timerWaitState = TimerWaitStateAlone;
|
||||
resetTimer();
|
||||
emit authenticated();
|
||||
}
|
||||
}
|
||||
|
||||
bool ProxyClient::isTunnelConnected() const
|
||||
{
|
||||
return m_tunnelConnected;
|
||||
}
|
||||
|
||||
void ProxyClient::setTunnelConnected(bool isTunnelConnected)
|
||||
{
|
||||
m_tunnelConnected = isTunnelConnected;
|
||||
if (m_tunnelConnected) {
|
||||
m_timer->stop();
|
||||
emit tunnelConnected();
|
||||
}
|
||||
}
|
||||
|
||||
QString ProxyClient::userName() const
|
||||
{
|
||||
return m_userName;
|
||||
}
|
||||
|
||||
void ProxyClient::setUserName(const QString &userName)
|
||||
{
|
||||
m_userName = userName;
|
||||
}
|
||||
|
||||
QString ProxyClient::tunnelIdentifier() const
|
||||
{
|
||||
return m_token + m_nonce;
|
||||
}
|
||||
|
||||
QString ProxyClient::token() const
|
||||
{
|
||||
return m_token;
|
||||
}
|
||||
|
||||
void ProxyClient::setToken(const QString &token)
|
||||
{
|
||||
m_token = token;
|
||||
}
|
||||
|
||||
QString ProxyClient::nonce() const
|
||||
{
|
||||
return m_nonce;
|
||||
}
|
||||
|
||||
void ProxyClient::setNonce(const QString &nonce)
|
||||
{
|
||||
m_nonce = nonce;
|
||||
}
|
||||
|
||||
ProxyClient::TimerWaitState ProxyClient::timerWaitState() const
|
||||
{
|
||||
return m_timerWaitState;
|
||||
}
|
||||
|
||||
void ProxyClient::resetTimer()
|
||||
{
|
||||
switch (m_timerWaitState) {
|
||||
case TimerWaitStateInactive:
|
||||
m_timer->start(Engine::instance()->configuration()->inactiveTimeout());
|
||||
break;
|
||||
case TimerWaitStateAlone:
|
||||
m_timer->start(Engine::instance()->configuration()->aloneTimeout());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QList<QByteArray> ProxyClient::processData(const QByteArray &data)
|
||||
{
|
||||
QList<QByteArray> packets;
|
||||
|
||||
// Handle packet fragmentation
|
||||
m_dataBuffer.append(data);
|
||||
int splitIndex = m_dataBuffer.indexOf("}\n{");
|
||||
while (splitIndex > -1) {
|
||||
packets.append(m_dataBuffer.left(splitIndex + 1));
|
||||
m_dataBuffer = m_dataBuffer.right(m_dataBuffer.length() - splitIndex - 2);
|
||||
splitIndex = m_dataBuffer.indexOf("}\n{");
|
||||
}
|
||||
if (m_dataBuffer.endsWith("}\n") || m_dataBuffer.endsWith("}")) {
|
||||
packets.append(m_dataBuffer);
|
||||
m_dataBuffer.clear();
|
||||
}
|
||||
|
||||
return packets;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, ProxyClient *proxyClient)
|
||||
{
|
||||
QDebugStateSaver saver(debug);
|
||||
debug.nospace() << "ProxyClient(";
|
||||
if (!proxyClient->name().isEmpty()) {
|
||||
debug.nospace() << proxyClient->name() << ", ";
|
||||
}
|
||||
debug.nospace() << proxyClient->interface()->serverName();
|
||||
debug.nospace() << ", " << proxyClient->clientId().toString();
|
||||
debug.nospace() << ", " << proxyClient->userName();
|
||||
debug.nospace() << ", " << proxyClient->peerAddress().toString();
|
||||
debug.nospace() << ", " << proxyClient->creationTimeString() << ")";
|
||||
return debug;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef PROXYCLIENT_H
|
||||
#define PROXYCLIENT_H
|
||||
|
||||
#include <QUuid>
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QHostAddress>
|
||||
|
||||
#include "server/transportclient.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class ProxyClient : public TransportClient
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum TimerWaitState {
|
||||
TimerWaitStateInactive,
|
||||
TimerWaitStateAlone
|
||||
};
|
||||
Q_ENUM(TimerWaitState)
|
||||
|
||||
explicit ProxyClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent = nullptr);
|
||||
|
||||
bool isAuthenticated() const;
|
||||
void setAuthenticated(bool isAuthenticated);
|
||||
|
||||
bool isTunnelConnected() const;
|
||||
void setTunnelConnected(bool isTunnelConnected);
|
||||
|
||||
QString userName() const;
|
||||
void setUserName(const QString &userName);
|
||||
|
||||
QString tunnelIdentifier() const;
|
||||
|
||||
QString token() const;
|
||||
void setToken(const QString &token);
|
||||
|
||||
QString nonce() const;
|
||||
void setNonce(const QString &nonce);
|
||||
|
||||
// Actions for this client
|
||||
TimerWaitState timerWaitState() const;
|
||||
void resetTimer();
|
||||
|
||||
// Json server methods
|
||||
QList<QByteArray> processData(const QByteArray &data) override;
|
||||
|
||||
private:
|
||||
QTimer *m_timer = nullptr;
|
||||
TimerWaitState m_timerWaitState = TimerWaitStateInactive;
|
||||
|
||||
bool m_authenticated = false;
|
||||
bool m_tunnelConnected = false;
|
||||
|
||||
QString m_token;
|
||||
QString m_nonce;
|
||||
|
||||
QString m_userName;
|
||||
|
||||
signals:
|
||||
void authenticated();
|
||||
void tunnelConnected();
|
||||
void timeoutOccurred();
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<< (QDebug debug, ProxyClient *proxyClient);
|
||||
|
||||
}
|
||||
|
||||
#endif // PROXYCLIENT_H
|
||||
@ -1,420 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "engine.h"
|
||||
#include "proxyserver.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QMetaObject>
|
||||
#include <QVariantList>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
ProxyServer::ProxyServer(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
qRegisterMetaType<ProxyClient *>("ProxyClient *");
|
||||
m_jsonRpcServer = new JsonRpcServer(this);
|
||||
m_jsonRpcServer->registerHandler(m_jsonRpcServer);
|
||||
m_jsonRpcServer->registerHandler(new AuthenticationHandler(this));
|
||||
|
||||
loadStatistics();
|
||||
}
|
||||
|
||||
ProxyServer::~ProxyServer()
|
||||
{
|
||||
qCDebug(dcProxyServer()) << "Shutting down proxy server";
|
||||
}
|
||||
|
||||
bool ProxyServer::running() const
|
||||
{
|
||||
return m_running;
|
||||
}
|
||||
|
||||
void ProxyServer::registerTransportInterface(TransportInterface *interface)
|
||||
{
|
||||
qCDebug(dcProxyServer()) << "Register transport interface" << interface->serverName();
|
||||
|
||||
if (m_transportInterfaces.contains(interface)) {
|
||||
qCWarning(dcProxyServer()) << "Transport interface already registerd.";
|
||||
return;
|
||||
}
|
||||
|
||||
connect(interface, &TransportInterface::clientConnected, this, &ProxyServer::onClientConnected);
|
||||
connect(interface, &TransportInterface::clientDisconnected, this, &ProxyServer::onClientDisconnected);
|
||||
connect(interface, &TransportInterface::dataAvailable, this, &ProxyServer::onClientDataAvailable);
|
||||
|
||||
m_transportInterfaces.append(interface);
|
||||
}
|
||||
|
||||
QVariantMap ProxyServer::currentStatistics()
|
||||
{
|
||||
QVariantMap statisticsMap;
|
||||
statisticsMap.insert("clientCount", m_proxyClients.count());
|
||||
statisticsMap.insert("tunnelCount", m_tunnels.count());
|
||||
statisticsMap.insert("troughput", m_troughput);
|
||||
|
||||
QVariantMap totalStatisticsMap;
|
||||
totalStatisticsMap.insert("totalClientCount", m_totalClientCount);
|
||||
totalStatisticsMap.insert("totalTunnelCount", m_totalTunnelCount);
|
||||
totalStatisticsMap.insert("totalTraffic", m_totalTraffic);
|
||||
statisticsMap.insert("total", totalStatisticsMap);
|
||||
|
||||
// Create client list
|
||||
QVariantList clientList;
|
||||
foreach (ProxyClient *client, m_proxyClients) {
|
||||
QVariantMap clientMap;
|
||||
clientMap.insert("id", client->clientId().toString());
|
||||
clientMap.insert("address", client->peerAddress().toString());
|
||||
clientMap.insert("timestamp", client->creationTime());
|
||||
clientMap.insert("authenticated", client->isAuthenticated());
|
||||
clientMap.insert("tunnelConnected", client->isTunnelConnected());
|
||||
clientMap.insert("name", client->name());
|
||||
clientMap.insert("userName", client->userName());
|
||||
clientMap.insert("uuid", client->uuid());
|
||||
clientMap.insert("rxDataCount", client->rxDataCount());
|
||||
clientMap.insert("txDataCount", client->txDataCount());
|
||||
clientList.append(clientMap);
|
||||
}
|
||||
statisticsMap.insert("clients", clientList);
|
||||
|
||||
// Create tunnel list
|
||||
QVariantList tunnelList;
|
||||
foreach (const TunnelConnection &tunnel, m_tunnels) {
|
||||
QVariantMap tunnelMap;
|
||||
tunnelMap.insert("clientOne", tunnel.clientOne()->clientId().toString());
|
||||
tunnelMap.insert("clientTwo", tunnel.clientTwo()->clientId().toString());
|
||||
tunnelMap.insert("timestamp", tunnel.creationTime());
|
||||
tunnelList.append(tunnelMap);
|
||||
}
|
||||
statisticsMap.insert("tunnels", tunnelList);
|
||||
|
||||
return statisticsMap;
|
||||
}
|
||||
|
||||
void ProxyServer::setRunning(bool running)
|
||||
{
|
||||
if (m_running == running)
|
||||
return;
|
||||
|
||||
qCDebug(dcProxyServer()) << "The proxy server is" << (running ? "up and running." : "not running any more.");
|
||||
m_running = running;
|
||||
emit runningChanged();
|
||||
}
|
||||
|
||||
void ProxyServer::loadStatistics()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("Statistics");
|
||||
m_totalClientCount = settings.value("totalClientCount", 0).toInt();
|
||||
m_totalTunnelCount = settings.value("totalTunnelCount", 0).toInt();
|
||||
m_totalTraffic = settings.value("totalTraffic", 0).toInt();
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void ProxyServer::saveStatistics()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("Statistics");
|
||||
settings.setValue("totalClientCount", m_totalClientCount);
|
||||
settings.value("totalTunnelCount", m_totalTunnelCount);
|
||||
settings.value("totalTraffic", m_totalTraffic);
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
ProxyClient *ProxyServer::getRemoteClient(ProxyClient *proxyClient)
|
||||
{
|
||||
if (!m_tunnels.contains(proxyClient->tunnelIdentifier()))
|
||||
return nullptr;
|
||||
|
||||
if (proxyClient == m_tunnels.value(proxyClient->tunnelIdentifier()).clientOne()) {
|
||||
return m_tunnels.value(proxyClient->tunnelIdentifier()).clientTwo();
|
||||
} else if (proxyClient == m_tunnels.value(proxyClient->tunnelIdentifier()).clientTwo()) {
|
||||
return m_tunnels.value(proxyClient->tunnelIdentifier()).clientOne();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ProxyServer::establishTunnel(ProxyClient *firstClient, ProxyClient *secondClient)
|
||||
{
|
||||
qCDebug(dcProxyServer()) << "Create tunnel between authenticated clients " << firstClient << secondClient;
|
||||
|
||||
TunnelConnection tunnel(firstClient, secondClient);
|
||||
if (!tunnel.isValid()) {
|
||||
qCWarning(dcProxyServer()) << "Invalid tunnel. Could not establish connection.";
|
||||
//FIXME:
|
||||
}
|
||||
|
||||
m_tunnels.insert(tunnel.tunnelIdentifier(), tunnel);
|
||||
|
||||
// Tell both clients the tunnel has been established
|
||||
QVariantMap notificationParamsFirst;
|
||||
notificationParamsFirst.insert("name", tunnel.clientTwo()->name());
|
||||
notificationParamsFirst.insert("uuid", tunnel.clientTwo()->uuid());
|
||||
|
||||
QVariantMap notificationParamsSecond;
|
||||
notificationParamsSecond.insert("name", tunnel.clientOne()->name());
|
||||
notificationParamsSecond.insert("uuid", tunnel.clientOne()->uuid());
|
||||
|
||||
// Make sure the proxy is the first one who knows that the tunnel is connected
|
||||
firstClient->setTunnelConnected(true);
|
||||
secondClient->setTunnelConnected(true);
|
||||
|
||||
qCDebug(dcProxyServer()) << tunnel;
|
||||
qCDebug(dcTunnel()) << "Tunnel established between" << firstClient->peerAddress().toString() << firstClient->clientId()
|
||||
<< "<-->" << secondClient->peerAddress().toString() << secondClient->clientId();
|
||||
|
||||
m_totalTunnelCount += 1;
|
||||
saveStatistics();
|
||||
|
||||
// Notify the clients in the next event loop
|
||||
QMetaObject::invokeMethod(m_jsonRpcServer, QString("sendNotification").toLatin1().data(), Qt::QueuedConnection,
|
||||
Q_ARG(QString, m_jsonRpcServer->name()),
|
||||
Q_ARG(QString, "TunnelEstablished"),
|
||||
Q_ARG(QVariantMap, notificationParamsFirst),
|
||||
Q_ARG(TransportClient*, tunnel.clientOne()));
|
||||
|
||||
QMetaObject::invokeMethod(m_jsonRpcServer, QString("sendNotification").toLatin1().data(), Qt::QueuedConnection,
|
||||
Q_ARG(QString, m_jsonRpcServer->name()),
|
||||
Q_ARG(QString, "TunnelEstablished"),
|
||||
Q_ARG(QVariantMap, notificationParamsSecond),
|
||||
Q_ARG(TransportClient*, tunnel.clientTwo()));
|
||||
}
|
||||
|
||||
void ProxyServer::onClientConnected(const QUuid &clientId, const QHostAddress &address)
|
||||
{
|
||||
TransportInterface *interface = static_cast<TransportInterface *>(sender());
|
||||
|
||||
qCDebug(dcProxyServer()) << "New client connected" << interface->serverName() << clientId.toString() << address.toString();
|
||||
|
||||
ProxyClient *proxyClient = new ProxyClient(interface, clientId, address, this);
|
||||
connect(proxyClient, &ProxyClient::authenticated, this, &ProxyServer::onProxyClientAuthenticated);
|
||||
connect(proxyClient, &ProxyClient::timeoutOccurred, this, &ProxyServer::onProxyClientTimeoutOccurred);
|
||||
|
||||
m_totalClientCount += 1;
|
||||
saveStatistics();
|
||||
|
||||
m_proxyClients.insert(clientId, proxyClient);
|
||||
m_jsonRpcServer->registerClient(proxyClient);
|
||||
}
|
||||
|
||||
void ProxyServer::onClientDisconnected(const QUuid &clientId)
|
||||
{
|
||||
TransportInterface *interface = static_cast<TransportInterface *>(sender());
|
||||
qCDebug(dcProxyServer()) << "Client disconnected" << interface->serverName() << clientId.toString();
|
||||
|
||||
if (m_proxyClients.contains(clientId)) {
|
||||
ProxyClient *proxyClient = m_proxyClients.take(clientId);
|
||||
|
||||
// Clean up client tables
|
||||
if (m_authenticatedClients.values().contains(proxyClient)) {
|
||||
m_authenticatedClients.remove(proxyClient->token());
|
||||
}
|
||||
|
||||
if (m_authenticatedClientsNonce.values().contains(proxyClient)) {
|
||||
m_authenticatedClientsNonce.remove(proxyClient->nonce());
|
||||
}
|
||||
|
||||
// Unregister from json rpc server
|
||||
m_jsonRpcServer->unregisterClient(proxyClient);
|
||||
|
||||
// Check if
|
||||
if (m_tunnels.contains(proxyClient->tunnelIdentifier())) {
|
||||
// There is a tunnel connection for this client, remove the tunnel and disconnect also the other client
|
||||
ProxyClient *remoteClient = getRemoteClient(proxyClient);
|
||||
TunnelConnection tunnelConnection = m_tunnels.take(proxyClient->tunnelIdentifier());
|
||||
Engine::instance()->logEngine()->logTunnel(tunnelConnection);
|
||||
if (remoteClient) {
|
||||
qCDebug(dcTunnel()) << "Remove tunnel between" << proxyClient->peerAddress().toString() << proxyClient->clientId()
|
||||
<< "<-->" << remoteClient->peerAddress().toString() << remoteClient->clientId();
|
||||
remoteClient->killConnection("Tunnel client disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the proxy client
|
||||
proxyClient->deleteLater();
|
||||
} else {
|
||||
qCWarning(dcProxyServer()) << "Unknown client disconnected from proxy server." << clientId.toString();
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyServer::onClientDataAvailable(const QUuid &clientId, const QByteArray &data)
|
||||
{
|
||||
ProxyClient *proxyClient = m_proxyClients.value(clientId);
|
||||
if (!proxyClient) {
|
||||
qCWarning(dcProxyServer()) << "Could not find client for uuid" << clientId;
|
||||
return;
|
||||
}
|
||||
|
||||
// If this client is not authenticated yet, and not tunnel connected, pipe the traffic into the json rpc server
|
||||
if (!proxyClient->isAuthenticated() && !proxyClient->isTunnelConnected()) {
|
||||
qCDebug(dcProxyServerTraffic()) << "Client data available" << proxyClient << qUtf8Printable(data);
|
||||
m_jsonRpcServer->processData(proxyClient, data);
|
||||
// Reset the inactive timer
|
||||
proxyClient->resetTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the client is authenticated, but no tunnel created yet, kill the connection since no addition call is allowed until
|
||||
// the tunne is fully established.
|
||||
if (proxyClient->isAuthenticated() && !proxyClient->isTunnelConnected()) {
|
||||
qCWarning(dcProxyServer()) << "An authenticated client sent data without tunnel connection. This is not allowed.";
|
||||
m_jsonRpcServer->unregisterClient(proxyClient);
|
||||
// The client is authenticated and tries to send data, this is not allowed.
|
||||
proxyClient->killConnection("Data received while authenticated but not remote connected.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (proxyClient->isAuthenticated() && proxyClient->isTunnelConnected()) {
|
||||
ProxyClient *remoteClient = getRemoteClient(proxyClient);
|
||||
Q_ASSERT_X(remoteClient, "ProxyServer", "Tunnel existing but not tunnel client available");
|
||||
Q_ASSERT_X(m_tunnels.contains(proxyClient->tunnelIdentifier()), "ProxyServer", "Tunnel connect but not existing");
|
||||
|
||||
// Calculate server statisitcs
|
||||
m_troughputCounter += data.count();
|
||||
proxyClient->addRxDataCount(data.count());
|
||||
|
||||
if (!remoteClient)
|
||||
return;
|
||||
|
||||
remoteClient->addTxDataCount(data.count());
|
||||
|
||||
m_totalTraffic += data.count();
|
||||
saveStatistics();
|
||||
|
||||
qCDebug(dcProxyServerTraffic()) << "Pipe tunnel data:";
|
||||
qCDebug(dcProxyServerTraffic()) << " --> from" << proxyClient;
|
||||
qCDebug(dcProxyServerTraffic()) << " --> to" << remoteClient;
|
||||
qCDebug(dcProxyServerTraffic()) << " --> data:" << qUtf8Printable(data);
|
||||
|
||||
remoteClient->sendData(data);
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyServer::onProxyClientAuthenticated()
|
||||
{
|
||||
ProxyClient *proxyClient = static_cast<ProxyClient *>(sender());
|
||||
|
||||
qCDebug(dcProxyServer()) << "Client authenticated" << proxyClient;
|
||||
|
||||
//FIXME: limit the amount of connection with one token
|
||||
|
||||
// Check if we already have a tunnel with this identifier
|
||||
if (m_tunnels.contains(proxyClient->tunnelIdentifier())) {
|
||||
qCWarning(dcProxyServer()) << "There is already a tunnel with this token and nonce. The client has to take a new nonce or a new token.";
|
||||
// There is already a tunnel with this token and nonce. Reject the connection
|
||||
proxyClient->killConnection("Tunnel already exists for this token nonce combination.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: for backwards compatibility
|
||||
if (proxyClient->nonce().isEmpty()) {
|
||||
// Check if we have an other authenticated client with this token
|
||||
if (m_authenticatedClients.keys().contains(proxyClient->token())) {
|
||||
|
||||
// Found a client with this token
|
||||
ProxyClient *tunnelPartner = m_authenticatedClients.take(proxyClient->token());
|
||||
|
||||
// Check if the two clients show up with the same uuid to prevent connection loops
|
||||
if (tunnelPartner->uuid() == proxyClient->uuid()) {
|
||||
qCWarning(dcProxyServer()) << "The clients have the same uuid. This is not allowed.";
|
||||
proxyClient->killConnection("Duplicated client UUID.");
|
||||
tunnelPartner->killConnection("Duplicated client UUID.");
|
||||
return;
|
||||
}
|
||||
|
||||
// All ok so far. Create the tunnel
|
||||
establishTunnel(tunnelPartner, proxyClient);
|
||||
} else {
|
||||
// Append and wait for the other client
|
||||
m_authenticatedClients.insert(proxyClient->token(), proxyClient);
|
||||
}
|
||||
} else {
|
||||
// The client passed a nonce, let's hash with that to prevent cross connections
|
||||
if (m_authenticatedClientsNonce.keys().contains(proxyClient->nonce())) {
|
||||
// Found a client with this nonce
|
||||
ProxyClient *tunnelPartner = m_authenticatedClientsNonce.take(proxyClient->nonce());
|
||||
|
||||
// Check if the two clients show up with the same uuid to prevent connection loops
|
||||
if (tunnelPartner->uuid() == proxyClient->uuid()) {
|
||||
qCWarning(dcProxyServer()) << "The clients have the same uuid. This could cause a loop and is not allowed.";
|
||||
proxyClient->killConnection("Client loop detected.");
|
||||
tunnelPartner->killConnection("Client loop detected.");
|
||||
return;
|
||||
}
|
||||
|
||||
// All ok so far. Create the tunnel
|
||||
establishTunnel(tunnelPartner, proxyClient);
|
||||
} else {
|
||||
m_authenticatedClientsNonce.insert(proxyClient->nonce(), proxyClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyServer::onProxyClientTimeoutOccurred()
|
||||
{
|
||||
ProxyClient *proxyClient = static_cast<ProxyClient *>(sender());
|
||||
qCDebug(dcProxyServer()) << "Timeout occurred for" << proxyClient;
|
||||
switch (proxyClient->timerWaitState()) {
|
||||
case ProxyClient::TimerWaitStateInactive:
|
||||
proxyClient->killConnection("Proxy timeout occurred. The socket was inactive.");
|
||||
break;
|
||||
case ProxyClient::TimerWaitStateAlone:
|
||||
proxyClient->killConnection("Proxy timeout occurred. The tunnel partner did not show up.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyServer::startServer()
|
||||
{
|
||||
qCDebug(dcProxyServer()) << "Starting proxy server...";
|
||||
foreach (TransportInterface *interface, m_transportInterfaces) {
|
||||
interface->startServer();
|
||||
}
|
||||
setRunning(true);
|
||||
}
|
||||
|
||||
void ProxyServer::stopServer()
|
||||
{
|
||||
qCDebug(dcProxyServer()) << "Stopping proxy...";
|
||||
foreach (TransportInterface *interface, m_transportInterfaces) {
|
||||
interface->stopServer();
|
||||
}
|
||||
setRunning(false);
|
||||
}
|
||||
|
||||
void ProxyServer::tick()
|
||||
{
|
||||
m_troughput = m_troughputCounter;
|
||||
m_troughputCounter = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,111 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef PROXYSERVER_H
|
||||
#define PROXYSERVER_H
|
||||
|
||||
#include <QUuid>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
|
||||
#include "proxyclient.h"
|
||||
#include "tunnelconnection.h"
|
||||
#include "server/jsonrpcserver.h"
|
||||
#include "server/transportinterface.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class ProxyServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ProxyServer(QObject *parent = nullptr);
|
||||
~ProxyServer();
|
||||
|
||||
bool running() const;
|
||||
void setRunning(bool running);
|
||||
|
||||
void registerTransportInterface(TransportInterface *interface);
|
||||
|
||||
QVariantMap currentStatistics();
|
||||
|
||||
private:
|
||||
JsonRpcServer *m_jsonRpcServer = nullptr;
|
||||
QList<TransportInterface *> m_transportInterfaces;
|
||||
|
||||
bool m_running = false;
|
||||
|
||||
// Transport ClientId, ProxyClient
|
||||
QHash<QUuid, ProxyClient *> m_proxyClients;
|
||||
|
||||
// FIXME: Token, ProxyClient
|
||||
QHash<QString, ProxyClient *> m_authenticatedClients;
|
||||
|
||||
// TunnelIdentifier (token + nonce), ProxyClient
|
||||
QHash<QString, ProxyClient *> m_authenticatedClientsNonce;
|
||||
|
||||
// Token, Tunnel
|
||||
QHash<QString, TunnelConnection> m_tunnels;
|
||||
|
||||
// Statistic measurments
|
||||
int m_troughput = 0;
|
||||
int m_troughputCounter = 0;
|
||||
|
||||
// Persistent statistics
|
||||
int m_totalClientCount = 0;
|
||||
int m_totalTunnelCount = 0;
|
||||
int m_totalTraffic = 0;
|
||||
|
||||
void loadStatistics();
|
||||
void saveStatistics();
|
||||
|
||||
// Helper methods
|
||||
ProxyClient *getRemoteClient(ProxyClient *proxyClient);
|
||||
void establishTunnel(ProxyClient *firstClient, ProxyClient *secondClient);
|
||||
|
||||
signals:
|
||||
void runningChanged();
|
||||
|
||||
private slots:
|
||||
void onClientConnected(const QUuid &clientId, const QHostAddress &address);
|
||||
void onClientDisconnected(const QUuid &clientId);
|
||||
void onClientDataAvailable(const QUuid &clientId, const QByteArray &data);
|
||||
|
||||
void onProxyClientAuthenticated();
|
||||
void onProxyClientTimeoutOccurred();
|
||||
|
||||
public slots:
|
||||
void startServer();
|
||||
void stopServer();
|
||||
|
||||
void tick();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // PROXYSERVER_H
|
||||
@ -1,116 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "tunnelconnection.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
TunnelConnection::TunnelConnection(ProxyClient *clientOne, ProxyClient *clientTwo):
|
||||
m_clientOne(clientOne),
|
||||
m_clientTwo(clientTwo)
|
||||
{
|
||||
m_creationTimeStamp = QDateTime::currentDateTimeUtc().toTime_t();
|
||||
}
|
||||
|
||||
QString TunnelConnection::token() const
|
||||
{
|
||||
if (!isValid())
|
||||
return QString();
|
||||
|
||||
return m_clientOne->token();
|
||||
}
|
||||
|
||||
QString TunnelConnection::nonce() const
|
||||
{
|
||||
if (!isValid())
|
||||
return QString();
|
||||
|
||||
return m_clientOne->nonce();
|
||||
}
|
||||
|
||||
QString TunnelConnection::tunnelIdentifier() const
|
||||
{
|
||||
if (!isValid())
|
||||
return QString();
|
||||
|
||||
return m_clientOne->tunnelIdentifier();
|
||||
}
|
||||
|
||||
uint TunnelConnection::creationTime() const
|
||||
{
|
||||
return m_creationTimeStamp;
|
||||
}
|
||||
|
||||
QString TunnelConnection::creationTimeString() const
|
||||
{
|
||||
return QDateTime::fromTime_t(creationTime()).toString("dd.MM.yyyy hh:mm:ss");
|
||||
}
|
||||
|
||||
ProxyClient *TunnelConnection::clientOne() const
|
||||
{
|
||||
return m_clientOne;
|
||||
}
|
||||
|
||||
ProxyClient *TunnelConnection::clientTwo() const
|
||||
{
|
||||
return m_clientTwo;
|
||||
}
|
||||
|
||||
bool TunnelConnection::hasClient(ProxyClient *proxyClient) const
|
||||
{
|
||||
return m_clientOne == proxyClient || m_clientTwo == proxyClient;
|
||||
}
|
||||
|
||||
bool TunnelConnection::isValid() const
|
||||
{
|
||||
// Both clients have to be valid
|
||||
if (!m_clientOne || !m_clientTwo)
|
||||
return false;
|
||||
|
||||
// Both clients need the same token
|
||||
if (m_clientOne->token() != m_clientTwo->token())
|
||||
return false;
|
||||
|
||||
// The clients need to be different
|
||||
if (m_clientOne == m_clientTwo)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const TunnelConnection &tunnel)
|
||||
{
|
||||
QDebugStateSaver saver(debug);
|
||||
debug.nospace() << "TunnelConnection(" << tunnel.creationTimeString() << ")\n";
|
||||
debug.nospace() << " --> " << tunnel.clientOne() << "\n";
|
||||
debug.nospace() << " --> " << tunnel.clientTwo() << "\n";
|
||||
return debug;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef TUNNELCONNECTION_H
|
||||
#define TUNNELCONNECTION_H
|
||||
|
||||
#include "proxyclient.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class TunnelConnection
|
||||
{
|
||||
public:
|
||||
TunnelConnection(ProxyClient *clientOne = nullptr, ProxyClient *clientTwo = nullptr);
|
||||
|
||||
QString token() const;
|
||||
QString nonce() const;
|
||||
QString tunnelIdentifier() const;
|
||||
|
||||
uint creationTime() const;
|
||||
QString creationTimeString() const;
|
||||
|
||||
ProxyClient *clientOne() const;
|
||||
ProxyClient *clientTwo() const;
|
||||
|
||||
bool hasClient(ProxyClient *proxyClient) const;
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
private:
|
||||
uint m_creationTimeStamp = 0;
|
||||
|
||||
ProxyClient *m_clientOne = nullptr;
|
||||
ProxyClient *m_clientTwo = nullptr;
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<< (QDebug debug, const TunnelConnection &tunnel);
|
||||
|
||||
}
|
||||
|
||||
#endif // TUNNELCONNECTION_H
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -54,21 +54,12 @@ bool ProxyConfiguration::loadConfiguration(const QString &fileName)
|
||||
|
||||
settings.beginGroup("ProxyServer");
|
||||
setServerName(settings.value("name", "nymea-remoteproxy").toString());
|
||||
setProxyEnabled(settings.value("proxyEnabled", true).toBool());
|
||||
setWriteLogFile(settings.value("writeLogs", false).toBool());
|
||||
setLogFileName(settings.value("logFile", "/var/log/nymea-remoteproxy.log").toString());
|
||||
setLogEngineEnabled(settings.value("logEngineEnabled", false).toBool());
|
||||
setMonitorSocketFileName(settings.value("monitorSocket", "/tmp/nymea-remoteproxy.monitor").toString());
|
||||
setJsonRpcTimeout(settings.value("jsonRpcTimeout", 10000).toInt());
|
||||
setAuthenticationTimeout(settings.value("authenticationTimeout", 8000).toInt());
|
||||
setInactiveTimeout(settings.value("inactiveTimeout", 8000).toInt());
|
||||
setAloneTimeout(settings.value("aloneTimeout", 8000).toInt());
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup("AWS");
|
||||
setAwsRegion(settings.value("region", "eu-west-1").toString());
|
||||
setAwsAuthorizerLambdaFunctionName(settings.value("authorizerLambdaFunction", "system-services-authorizer-dev-checkToken").toString());
|
||||
setAwsCredentialsUrl(QUrl(settings.value("awsCredentialsUrl", "http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Remote-Connection-Proxy-Role").toString()));
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup("SSL");
|
||||
@ -78,17 +69,7 @@ bool ProxyConfiguration::loadConfiguration(const QString &fileName)
|
||||
setSslCertificateChainFileName(settings.value("certificateChain", "").toString());
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup("WebSocketServer");
|
||||
setWebSocketServerHost(QHostAddress(settings.value("host", "127.0.0.1").toString()));
|
||||
setWebSocketServerPort(static_cast<quint16>(settings.value("port", 1212).toInt()));
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup("TcpServer");
|
||||
setTcpServerHost(QHostAddress(settings.value("host", "127.0.0.1").toString()));
|
||||
setTcpServerPort(static_cast<quint16>(settings.value("port", 1213).toInt()));
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup("UnixSocketServer");
|
||||
settings.beginGroup("UnixSocketServerTunnelProxy");
|
||||
setUnixSocketFileName(settings.value("unixSocketFileName", "/run/nymea-remoteproxy.socket").toString());
|
||||
settings.endGroup();
|
||||
|
||||
@ -212,16 +193,6 @@ void ProxyConfiguration::setJsonRpcTimeout(int timeout)
|
||||
m_jsonRpcTimeout = timeout;
|
||||
}
|
||||
|
||||
int ProxyConfiguration::authenticationTimeout() const
|
||||
{
|
||||
return m_authenticationTimeout;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setAuthenticationTimeout(int timeout)
|
||||
{
|
||||
m_authenticationTimeout = timeout;
|
||||
}
|
||||
|
||||
int ProxyConfiguration::inactiveTimeout() const
|
||||
{
|
||||
return m_inactiveTimeout;
|
||||
@ -232,56 +203,6 @@ void ProxyConfiguration::setInactiveTimeout(int timeout)
|
||||
m_inactiveTimeout = timeout;
|
||||
}
|
||||
|
||||
int ProxyConfiguration::aloneTimeout() const
|
||||
{
|
||||
return m_aloneTimeout;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setAloneTimeout(int timeout)
|
||||
{
|
||||
m_aloneTimeout = timeout;
|
||||
}
|
||||
|
||||
bool ProxyConfiguration::proxyEnabled() const
|
||||
{
|
||||
return m_proxyEnabled;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setProxyEnabled(bool proxyEnabled)
|
||||
{
|
||||
m_proxyEnabled = proxyEnabled;
|
||||
}
|
||||
|
||||
QString ProxyConfiguration::awsRegion() const
|
||||
{
|
||||
return m_awsRegion;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setAwsRegion(const QString ®ion)
|
||||
{
|
||||
m_awsRegion = region;
|
||||
}
|
||||
|
||||
QString ProxyConfiguration::awsAuthorizerLambdaFunctionName() const
|
||||
{
|
||||
return m_awsAuthorizerLambdaFunctionName;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setAwsAuthorizerLambdaFunctionName(const QString &functionName)
|
||||
{
|
||||
m_awsAuthorizerLambdaFunctionName = functionName;
|
||||
}
|
||||
|
||||
QUrl ProxyConfiguration::awsCredentialsUrl() const
|
||||
{
|
||||
return m_awsCredentialsUrl;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setAwsCredentialsUrl(const QUrl &url)
|
||||
{
|
||||
m_awsCredentialsUrl = url;
|
||||
}
|
||||
|
||||
bool ProxyConfiguration::sslEnabled() const
|
||||
{
|
||||
return m_sslEnabled;
|
||||
@ -327,46 +248,6 @@ QSslConfiguration ProxyConfiguration::sslConfiguration() const
|
||||
return m_sslConfiguration;
|
||||
}
|
||||
|
||||
QHostAddress ProxyConfiguration::webSocketServerProxyHost() const
|
||||
{
|
||||
return m_webSocketServerProxyHost;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setWebSocketServerHost(const QHostAddress &address)
|
||||
{
|
||||
m_webSocketServerProxyHost = address;
|
||||
}
|
||||
|
||||
quint16 ProxyConfiguration::webSocketServerProxyPort() const
|
||||
{
|
||||
return m_webSocketServerProxyPort;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setWebSocketServerPort(quint16 port)
|
||||
{
|
||||
m_webSocketServerProxyPort = port;
|
||||
}
|
||||
|
||||
QHostAddress ProxyConfiguration::tcpServerHost() const
|
||||
{
|
||||
return m_tcpServerHost;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setTcpServerHost(const QHostAddress &address)
|
||||
{
|
||||
m_tcpServerHost = address;
|
||||
}
|
||||
|
||||
quint16 ProxyConfiguration::tcpServerPort() const
|
||||
{
|
||||
return m_tcpServerPort;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setTcpServerPort(quint16 port)
|
||||
{
|
||||
m_tcpServerPort = port;
|
||||
}
|
||||
|
||||
QString ProxyConfiguration::unixSocketFileName() const
|
||||
{
|
||||
return m_unixSocketFileName;
|
||||
@ -428,9 +309,7 @@ QDebug operator<<(QDebug debug, ProxyConfiguration *configuration)
|
||||
debug.nospace() << " - Logfile:" << configuration->logFileName() << "\n";
|
||||
debug.nospace() << " - Log engine enabled:" << configuration->logEngineEnabled() << "\n";
|
||||
debug.nospace() << " - JSON RPC timeout:" << configuration->jsonRpcTimeout() << " [ms]" << "\n";
|
||||
debug.nospace() << " - Authentication timeout:" << configuration->authenticationTimeout() << " [ms]" << "\n";
|
||||
debug.nospace() << " - Inactive timeout:" << configuration->inactiveTimeout() << " [ms]" << "\n";
|
||||
debug.nospace() << " - Alone timeout:" << configuration->aloneTimeout() << " [ms]" << "\n";
|
||||
debug.nospace() << "SSL configuration" << "\n";
|
||||
debug.nospace() << " - Enabled:" << configuration->sslEnabled() << "\n";
|
||||
debug.nospace() << " - Certificate:" << configuration->sslCertificateFileName() << "\n";
|
||||
@ -452,22 +331,8 @@ QDebug operator<<(QDebug debug, ProxyConfiguration *configuration)
|
||||
debug.nospace() << " Locality name:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::LocalityName) << "\n";
|
||||
debug.nospace() << " State/Province:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::StateOrProvinceName) << "\n";
|
||||
debug.nospace() << " Email address:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::EmailAddress) << "\n";
|
||||
if (configuration->proxyEnabled()) {
|
||||
debug.nospace() << "AWS configuration" << "\n";
|
||||
debug.nospace() << " - Region:" << configuration->awsRegion() << "\n";
|
||||
debug.nospace() << " - Authorizer lambda function:" << configuration->awsAuthorizerLambdaFunctionName() << "\n";
|
||||
debug.nospace() << " - Credentials URL:" << configuration->awsCredentialsUrl().toString() << "\n";
|
||||
debug.nospace() << "WebSocketServer Proxy" << "\n";
|
||||
debug.nospace() << " - Host:" << configuration->webSocketServerProxyHost().toString() << "\n";
|
||||
debug.nospace() << " - Port:" << configuration->webSocketServerProxyPort() << "\n";
|
||||
debug.nospace() << "TcpServer Proxy" << "\n";
|
||||
debug.nospace() << " - Host:" << configuration->tcpServerHost().toString() << "\n";
|
||||
debug.nospace() << " - Port:" << configuration->tcpServerPort() << "\n";
|
||||
debug.nospace() << "UnixSocketServer Proxy" << "\n";
|
||||
debug.nospace() << " - Filename:" << configuration->unixSocketFileName() << "\n";
|
||||
} else {
|
||||
debug.nospace() << "Proxy Server: disabled" << "\n";
|
||||
}
|
||||
debug.nospace() << "UnixSocketServer Proxy" << endl;
|
||||
debug.nospace() << " - Filename:" << configuration->unixSocketFileName() << "\n";
|
||||
debug.nospace() << "WebSocketServer TunnelProxy" << "\n";
|
||||
debug.nospace() << " - Host:" << configuration->webSocketServerTunnelProxyHost().toString() << "\n";
|
||||
debug.nospace() << " - Port:" << configuration->webSocketServerTunnelProxyPort() << "\n";
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -65,28 +65,9 @@ public:
|
||||
int jsonRpcTimeout() const;
|
||||
void setJsonRpcTimeout(int timeout);
|
||||
|
||||
int authenticationTimeout() const;
|
||||
void setAuthenticationTimeout(int timeout);
|
||||
|
||||
int inactiveTimeout() const;
|
||||
void setInactiveTimeout(int timeout);
|
||||
|
||||
int aloneTimeout() const;
|
||||
void setAloneTimeout(int timeout);
|
||||
|
||||
bool proxyEnabled() const;
|
||||
void setProxyEnabled(bool proxyEnabled);
|
||||
|
||||
// AWS
|
||||
QString awsRegion() const;
|
||||
void setAwsRegion(const QString ®ion);
|
||||
|
||||
QString awsAuthorizerLambdaFunctionName() const;
|
||||
void setAwsAuthorizerLambdaFunctionName( const QString &functionName);
|
||||
|
||||
QUrl awsCredentialsUrl() const;
|
||||
void setAwsCredentialsUrl(const QUrl &url);
|
||||
|
||||
// Ssl
|
||||
bool sslEnabled() const;
|
||||
void setSslEnabled(bool enabled);
|
||||
@ -102,21 +83,7 @@ public:
|
||||
|
||||
QSslConfiguration sslConfiguration() const;
|
||||
|
||||
// WebSocketServer
|
||||
QHostAddress webSocketServerProxyHost() const;
|
||||
void setWebSocketServerHost(const QHostAddress &address);
|
||||
|
||||
quint16 webSocketServerProxyPort() const;
|
||||
void setWebSocketServerPort(quint16 port);
|
||||
|
||||
// TcpServer
|
||||
QHostAddress tcpServerHost() const;
|
||||
void setTcpServerHost(const QHostAddress &address);
|
||||
|
||||
quint16 tcpServerPort() const;
|
||||
void setTcpServerPort(quint16 port);
|
||||
|
||||
// UnixSocketServer
|
||||
// UnixSocketServer (tunnel)
|
||||
QString unixSocketFileName() const;
|
||||
void setUnixSocketFileName(const QString &unixSocketFileName);
|
||||
|
||||
@ -144,16 +111,7 @@ private:
|
||||
QString m_monitorSocketFileName;
|
||||
|
||||
int m_jsonRpcTimeout = 10000;
|
||||
int m_authenticationTimeout = 8000;
|
||||
int m_inactiveTimeout = 8000;
|
||||
int m_aloneTimeout = 8000;
|
||||
|
||||
bool m_proxyEnabled = true;
|
||||
|
||||
// AWS
|
||||
QString m_awsRegion;
|
||||
QString m_awsAuthorizerLambdaFunctionName;
|
||||
QUrl m_awsCredentialsUrl;
|
||||
|
||||
// Ssl
|
||||
bool m_sslEnabled = true;
|
||||
@ -162,15 +120,7 @@ private:
|
||||
QString m_sslCertificateChainFileName;
|
||||
QSslConfiguration m_sslConfiguration;
|
||||
|
||||
// WebSocketServer (proxy)
|
||||
QHostAddress m_webSocketServerProxyHost = QHostAddress::LocalHost;
|
||||
quint16 m_webSocketServerProxyPort = 1212;
|
||||
|
||||
// TcpServer (proxy)
|
||||
QHostAddress m_tcpServerHost = QHostAddress::LocalHost;
|
||||
quint16 m_tcpServerPort = 1213;
|
||||
|
||||
// UnixSocketServer (proxy)
|
||||
// UnixSocketServer (tunnel)
|
||||
QString m_unixSocketFileName = "/run/nymea-remoteproxy.socket";
|
||||
|
||||
// WebSocketServer (tunnel)
|
||||
@ -181,7 +131,6 @@ private:
|
||||
QHostAddress m_tcpServerTunnelProxyHost = QHostAddress::LocalHost;
|
||||
quint16 m_tcpServerTunnelProxyPort = 2213;
|
||||
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<< (QDebug debug, ProxyConfiguration *configuration);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -31,11 +31,10 @@
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
|
||||
#include "proxy/proxyclient.h"
|
||||
#include "transportclient.h"
|
||||
#include "jsonrpc/jsonreply.h"
|
||||
#include "transportinterface.h"
|
||||
#include "jsonrpc/jsonhandler.h"
|
||||
#include "jsonrpc/authenticationhandler.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -317,11 +317,6 @@ void TunnelProxyServer::onClientConnected(const QUuid &clientId, const QHostAddr
|
||||
TunnelProxyClient *tunnelProxyClient = new TunnelProxyClient(interface, clientId, address, this);
|
||||
m_proxyClients.insert(clientId, tunnelProxyClient);
|
||||
m_jsonRpcServer->registerClient(tunnelProxyClient);
|
||||
|
||||
// // For debugging
|
||||
// qCDebug(dcTunnelProxyServer()) << "#### Total clients:" << m_proxyClients.count() << "JSON RPC clients:" << m_jsonRpcServer->registeredClientCount()
|
||||
// << "Interface connections:" << tunnelProxyClient->interface()->connectionsCount()
|
||||
// << "Servers:" << m_tunnelProxyServerConnections.count() << "Clients:" << m_tunnelProxyClientConnections.count();
|
||||
}
|
||||
|
||||
void TunnelProxyServer::onClientDisconnected(const QUuid &clientId)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -5,22 +5,20 @@ INCLUDEPATH += $$PWD
|
||||
HEADERS += \
|
||||
$$PWD/tunnelproxy/tunnelproxyremoteconnection.h \
|
||||
$$PWD/tunnelproxy/tunnelproxysocket.h \
|
||||
$$PWD/tunnelproxy/tunnelproxysocketserver.h \
|
||||
$$PWD/tcpsocketconnection.h \
|
||||
$$PWD/proxyjsonrpcclient.h \
|
||||
$$PWD/jsonreply.h \
|
||||
$$PWD/remoteproxyconnection.h \
|
||||
$$PWD/proxyconnection.h \
|
||||
$$PWD/tunnelproxy/tunnelproxysocketserver.h \
|
||||
$$PWD/websocketconnection.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/tunnelproxy/tunnelproxyremoteconnection.cpp \
|
||||
$$PWD/tunnelproxy/tunnelproxysocket.cpp \
|
||||
$$PWD/tunnelproxy/tunnelproxysocketserver.cpp \
|
||||
$$PWD/tcpsocketconnection.cpp \
|
||||
$$PWD/proxyjsonrpcclient.cpp \
|
||||
$$PWD/jsonreply.cpp \
|
||||
$$PWD/remoteproxyconnection.cpp \
|
||||
$$PWD/proxyconnection.cpp \
|
||||
$$PWD/tunnelproxy/tunnelproxysocketserver.cpp \
|
||||
$$PWD/websocketconnection.cpp
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@ installheaders.files = remoteproxyconnection.h
|
||||
installheaders.path = $$[QT_INSTALL_PREFIX]/include/nymea-remoteproxyclient/
|
||||
|
||||
installtunnelheaders.files = tunnelproxy/tunnelproxyremoteconnection.h \
|
||||
tunnelproxy/tunnelproxysocket.h \
|
||||
tunnelproxy/tunnelproxysocketserver.h
|
||||
tunnelproxy/tunnelproxysocket.h \
|
||||
tunnelproxy/tunnelproxysocketserver.h
|
||||
installtunnelheaders.path = $$[QT_INSTALL_PREFIX]/include/nymea-remoteproxyclient/tunnelproxy
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -52,21 +52,6 @@ JsonReply *JsonRpcClient::callHello()
|
||||
return reply;
|
||||
}
|
||||
|
||||
JsonReply *JsonRpcClient::callAuthenticate(const QUuid &clientUuid, const QString &clientName, const QString &token, const QString &nonce)
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("name", clientName);
|
||||
params.insert("uuid", clientUuid.toString());
|
||||
params.insert("token", token);
|
||||
if (!nonce.isEmpty()) params.insert("nonce", nonce);
|
||||
|
||||
JsonReply *reply = new JsonReply(m_commandId, "Authentication", "Authenticate", params, this);
|
||||
qCDebug(dcRemoteProxyClientJsonRpc()) << "Calling" << QString("%1.%2").arg(reply->nameSpace()).arg(reply->method());
|
||||
sendRequest(reply->requestMap());
|
||||
m_replies.insert(m_commandId, reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
JsonReply *JsonRpcClient::callRegisterServer(const QUuid &serverUuid, const QString &serverName)
|
||||
{
|
||||
QVariantMap params;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -50,9 +50,6 @@ public:
|
||||
// General
|
||||
JsonReply *callHello();
|
||||
|
||||
// Proxy
|
||||
JsonReply *callAuthenticate(const QUuid &clientUuid, const QString &clientName, const QString &token, const QString &nonce);
|
||||
|
||||
// Tunnel proxy
|
||||
JsonReply *callRegisterServer(const QUuid &serverUuid, const QString &serverName);
|
||||
JsonReply *callRegisterClient(const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid);
|
||||
|
||||
@ -1,393 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "proxyconnection.h"
|
||||
#include "proxyjsonrpcclient.h"
|
||||
#include "tcpsocketconnection.h"
|
||||
#include "websocketconnection.h"
|
||||
#include "remoteproxyconnection.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(dcRemoteProxyClientConnection, "RemoteProxyClientConnection")
|
||||
Q_LOGGING_CATEGORY(dcRemoteProxyClientConnectionTraffic, "RemoteProxyClientConnectionTraffic")
|
||||
|
||||
namespace remoteproxyclient {
|
||||
|
||||
RemoteProxyConnection::RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_clientUuid(clientUuid),
|
||||
m_clientName(clientName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
RemoteProxyConnection::RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, RemoteProxyConnection::ConnectionType connectionType, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_clientUuid(clientUuid),
|
||||
m_clientName(clientName),
|
||||
m_connectionType(connectionType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
RemoteProxyConnection::~RemoteProxyConnection()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
RemoteProxyConnection::State RemoteProxyConnection::state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
QAbstractSocket::SocketError RemoteProxyConnection::error() const
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::ignoreSslErrors()
|
||||
{
|
||||
m_connection->ignoreSslErrors();
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::ignoreSslErrors(const QList<QSslError> &errors)
|
||||
{
|
||||
m_connection->ignoreSslErrors(errors);
|
||||
}
|
||||
|
||||
bool RemoteProxyConnection::isConnected() const
|
||||
{
|
||||
return m_state == StateConnected
|
||||
|| m_state == StateInitializing
|
||||
|| m_state == StateReady
|
||||
|| m_state == StateAuthenticating
|
||||
|| m_state == StateAuthenticated
|
||||
|| m_state == StateRemoteConnected;
|
||||
}
|
||||
|
||||
bool RemoteProxyConnection::isAuthenticated() const
|
||||
{
|
||||
return m_state == StateAuthenticated || m_state == StateRemoteConnected;
|
||||
}
|
||||
|
||||
bool RemoteProxyConnection::isRemoteConnected() const
|
||||
{
|
||||
return m_state == StateRemoteConnected;
|
||||
}
|
||||
|
||||
RemoteProxyConnection::ConnectionType RemoteProxyConnection::connectionType() const
|
||||
{
|
||||
return m_connectionType;
|
||||
}
|
||||
|
||||
QUrl RemoteProxyConnection::serverUrl() const
|
||||
{
|
||||
return m_serverUrl;
|
||||
}
|
||||
|
||||
QString RemoteProxyConnection::serverName() const
|
||||
{
|
||||
return m_serverName;
|
||||
}
|
||||
|
||||
QString RemoteProxyConnection::proxyServerName() const
|
||||
{
|
||||
return m_proxyServerName;
|
||||
}
|
||||
|
||||
QString RemoteProxyConnection::proxyServerVersion() const
|
||||
{
|
||||
return m_proxyServerVersion;
|
||||
}
|
||||
|
||||
QString RemoteProxyConnection::proxyServerApiVersion() const
|
||||
{
|
||||
return m_proxyServerApiVersion;
|
||||
}
|
||||
|
||||
QString RemoteProxyConnection::tunnelPartnerName() const
|
||||
{
|
||||
return m_tunnelPartnerName;
|
||||
}
|
||||
|
||||
QString RemoteProxyConnection::tunnelPartnerUuid() const
|
||||
{
|
||||
return m_tunnelPartnerUuid;
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::cleanUp()
|
||||
{
|
||||
if (m_jsonClient) {
|
||||
m_jsonClient->deleteLater();
|
||||
m_jsonClient = nullptr;
|
||||
}
|
||||
|
||||
if (m_connection) {
|
||||
m_connection->deleteLater();
|
||||
m_connection = nullptr;
|
||||
}
|
||||
|
||||
m_serverName = QString();
|
||||
m_proxyServerName = QString();
|
||||
m_proxyServerVersion = QString();
|
||||
m_proxyServerApiVersion = QString();
|
||||
|
||||
setState(StateDisconnected);
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::setState(RemoteProxyConnection::State state)
|
||||
{
|
||||
if (m_state == state)
|
||||
return;
|
||||
|
||||
m_state = state;
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "State changed" << m_state;
|
||||
emit stateChanged(m_state);
|
||||
|
||||
switch (m_state) {
|
||||
case StateConnected:
|
||||
emit connected();
|
||||
break;
|
||||
case StateDisconnected:
|
||||
emit disconnected();
|
||||
break;
|
||||
case StateReady:
|
||||
emit ready();
|
||||
break;
|
||||
case StateRemoteConnected:
|
||||
emit remoteConnectionEstablished();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::setError(QAbstractSocket::SocketError error)
|
||||
{
|
||||
if (m_error == error)
|
||||
return;
|
||||
|
||||
m_error = error;
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Error occurred" << m_error;
|
||||
emit errorOccurred(m_error);
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::onConnectionChanged(bool isConnected)
|
||||
{
|
||||
if (isConnected) {
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Connected to proxy server.";
|
||||
setState(StateConnected);
|
||||
|
||||
setState(StateInitializing);
|
||||
JsonReply *reply = m_jsonClient->callHello();
|
||||
connect(reply, &JsonReply::finished, this, &RemoteProxyConnection::onHelloFinished);
|
||||
} else {
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Disconnected from proxy server.";
|
||||
setState(StateDisconnected);
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::onConnectionDataAvailable(const QByteArray &data)
|
||||
{
|
||||
switch (m_state) {
|
||||
case StateHostLookup:
|
||||
case StateConnecting:
|
||||
case StateConnected:
|
||||
case StateInitializing:
|
||||
case StateReady:
|
||||
case StateAuthenticating:
|
||||
case StateAuthenticated:
|
||||
m_jsonClient->processData(data);
|
||||
break;
|
||||
case StateRemoteConnected:
|
||||
// Remote data arrived
|
||||
emit dataReady(data);
|
||||
break;
|
||||
default:
|
||||
qCWarning(dcRemoteProxyClientConnection()) << "Unhandled: Data received" << data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::onConnectionSocketError(QAbstractSocket::SocketError error)
|
||||
{
|
||||
setError(error);
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::onConnectionStateChanged(QAbstractSocket::SocketState state)
|
||||
{
|
||||
switch (state) {
|
||||
case QAbstractSocket::UnconnectedState:
|
||||
setState(StateDisconnected);
|
||||
break;
|
||||
case QAbstractSocket::HostLookupState:
|
||||
setState(StateHostLookup);
|
||||
break;
|
||||
case QAbstractSocket::ConnectingState:
|
||||
setState(StateConnecting);
|
||||
break;
|
||||
case QAbstractSocket::ConnectedState:
|
||||
setState(StateConnected);
|
||||
break;
|
||||
case QAbstractSocket::ClosingState:
|
||||
setState(StateDiconnecting);
|
||||
break;
|
||||
case QAbstractSocket::BoundState:
|
||||
case QAbstractSocket::ListeningState:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::onHelloFinished()
|
||||
{
|
||||
JsonReply *reply = static_cast<JsonReply *>(sender());
|
||||
reply->deleteLater();
|
||||
|
||||
QVariantMap response = reply->response();
|
||||
qCDebug(dcRemoteProxyClientConnectionTraffic()) << "Hello response ready" << reply->commandId() << response;
|
||||
|
||||
if (response.value("status").toString() != "success") {
|
||||
qCWarning(dcRemoteProxyClientConnection()) << "Could not get initial information from proxy server.";
|
||||
m_connection->disconnectServer();
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap responseParams = response.value("params").toMap();
|
||||
|
||||
// TODO: verify success
|
||||
|
||||
m_serverName = responseParams.value("server").toString();
|
||||
m_proxyServerName = responseParams.value("name").toString();
|
||||
m_proxyServerVersion = responseParams.value("version").toString();
|
||||
m_proxyServerApiVersion = responseParams.value("apiVersion").toString();
|
||||
|
||||
setState(StateReady);
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::onAuthenticateFinished()
|
||||
{
|
||||
JsonReply *reply = static_cast<JsonReply *>(sender());
|
||||
reply->deleteLater();
|
||||
|
||||
QVariantMap response = reply->response();
|
||||
qCDebug(dcRemoteProxyClientConnectionTraffic()) << "Authentication response ready" << reply->commandId() << response;
|
||||
|
||||
QVariantMap responseParams = response.value("params").toMap();
|
||||
if (responseParams.value("authenticationError").toString() != "AuthenticationErrorNoError") {
|
||||
qCWarning(dcRemoteProxyClientConnection()) << "Authentication request finished with error" << responseParams.value("authenticationError").toString();
|
||||
setError(QAbstractSocket::ProxyConnectionRefusedError);
|
||||
m_connection->disconnectServer();
|
||||
} else {
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Successfully authenticated.";
|
||||
setState(StateAuthenticated);
|
||||
emit authenticated();
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::onTunnelEstablished(const QString &clientName, const QString &clientUuid)
|
||||
{
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Remote connection established successfully with" << clientName << clientUuid;
|
||||
m_tunnelPartnerName = clientName;
|
||||
m_tunnelPartnerUuid = clientUuid;
|
||||
setState(StateRemoteConnected);
|
||||
}
|
||||
|
||||
bool RemoteProxyConnection::connectServer(const QUrl &url)
|
||||
{
|
||||
m_serverUrl = url;
|
||||
m_error = QAbstractSocket::UnknownSocketError;
|
||||
|
||||
cleanUp();
|
||||
|
||||
switch (m_connectionType) {
|
||||
case ConnectionTypeWebSocket:
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Creating a web socket connection to" << url.toString();
|
||||
m_connection = qobject_cast<ProxyConnection *>(new WebSocketConnection(this));
|
||||
break;
|
||||
case ConnectionTypeTcpSocket:
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Creating a TCP socket connection to" << url.toString();
|
||||
m_connection = qobject_cast<ProxyConnection *>(new TcpSocketConnection(this));
|
||||
break;
|
||||
}
|
||||
|
||||
connect(m_connection, &ProxyConnection::connectedChanged, this, &RemoteProxyConnection::onConnectionChanged);
|
||||
connect(m_connection, &ProxyConnection::dataReceived, this, &RemoteProxyConnection::onConnectionDataAvailable);
|
||||
connect(m_connection, &ProxyConnection::errorOccurred, this, &RemoteProxyConnection::onConnectionSocketError);
|
||||
connect(m_connection, &ProxyConnection::stateChanged, this, &RemoteProxyConnection::onConnectionStateChanged);
|
||||
connect(m_connection, &ProxyConnection::sslErrors, this, &RemoteProxyConnection::sslErrors);
|
||||
|
||||
m_jsonClient = new JsonRpcClient(m_connection, this);
|
||||
connect(m_jsonClient, &JsonRpcClient::tunnelEstablished, this, &RemoteProxyConnection::onTunnelEstablished);
|
||||
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Connecting to" << m_serverUrl.toString();
|
||||
m_connection->connectServer(m_serverUrl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoteProxyConnection::authenticate(const QString &token, const QString &nonce)
|
||||
{
|
||||
if (m_state != StateReady) {
|
||||
qCWarning(dcRemoteProxyClientConnection()) << "Could not authenticate. The connection is not ready";
|
||||
return false;
|
||||
}
|
||||
|
||||
setState(StateAuthenticating);
|
||||
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Start authentication using token" << token << nonce;
|
||||
JsonReply *reply = m_jsonClient->callAuthenticate(m_clientUuid, m_clientName, token, nonce);
|
||||
connect(reply, &JsonReply::finished, this, &RemoteProxyConnection::onAuthenticateFinished);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoteProxyConnection::disconnectServer()
|
||||
{
|
||||
if (m_connection) {
|
||||
qCDebug(dcRemoteProxyClientConnection()) << "Disconnecting from" << m_connection->serverUrl().toString();
|
||||
m_connection->disconnectServer();
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteProxyConnection::sendData(const QByteArray &data)
|
||||
{
|
||||
if (!isConnected()) {
|
||||
qCWarning(dcRemoteProxyClientConnection()) << "Could not send data. Not connected.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isRemoteConnected()) {
|
||||
qCWarning(dcRemoteProxyClientConnection()) << "Could not send data. The remote client is not connected yet.";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_connection->sendData(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,164 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef REMOTEPROXYCONNECTOR_H
|
||||
#define REMOTEPROXYCONNECTOR_H
|
||||
|
||||
#include <QUuid>
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QHostInfo>
|
||||
#include <QWebSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcRemoteProxyClientConnection)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcRemoteProxyClientConnectionTraffic)
|
||||
|
||||
namespace remoteproxyclient {
|
||||
|
||||
class JsonRpcClient;
|
||||
class ProxyConnection;
|
||||
|
||||
class RemoteProxyConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ConnectionType {
|
||||
ConnectionTypeWebSocket,
|
||||
ConnectionTypeTcpSocket
|
||||
};
|
||||
Q_ENUM(ConnectionType)
|
||||
|
||||
enum State {
|
||||
StateHostLookup,
|
||||
StateConnecting,
|
||||
StateConnected,
|
||||
StateInitializing,
|
||||
StateReady,
|
||||
StateAuthenticating,
|
||||
StateAuthenticated,
|
||||
StateRemoteConnected,
|
||||
StateDiconnecting,
|
||||
StateDisconnected,
|
||||
};
|
||||
Q_ENUM(State)
|
||||
|
||||
explicit RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, QObject *parent = nullptr);
|
||||
RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, ConnectionType connectionType, QObject *parent = nullptr);
|
||||
~RemoteProxyConnection();
|
||||
|
||||
RemoteProxyConnection::State state() const;
|
||||
QAbstractSocket::SocketError error() const;
|
||||
|
||||
void ignoreSslErrors();
|
||||
void ignoreSslErrors(const QList<QSslError> &errors);
|
||||
|
||||
bool isConnected() const;
|
||||
bool isAuthenticated() const;
|
||||
bool isRemoteConnected() const;
|
||||
|
||||
RemoteProxyConnection::ConnectionType connectionType() const;
|
||||
|
||||
QUrl serverUrl() const;
|
||||
|
||||
QString serverName() const;
|
||||
QString proxyServerName() const;
|
||||
QString proxyServerVersion() const;
|
||||
QString proxyServerApiVersion() const;
|
||||
|
||||
QString tunnelPartnerName() const;
|
||||
QString tunnelPartnerUuid() const;
|
||||
|
||||
private:
|
||||
QUuid m_clientUuid;
|
||||
QString m_clientName;
|
||||
ConnectionType m_connectionType = ConnectionTypeTcpSocket;
|
||||
|
||||
QUrl m_serverUrl;
|
||||
|
||||
State m_state = StateDisconnected;
|
||||
QAbstractSocket::SocketError m_error = QAbstractSocket::UnknownSocketError;
|
||||
|
||||
bool m_insecureConnection = false;
|
||||
bool m_remoteConnected = false;
|
||||
|
||||
JsonRpcClient *m_jsonClient = nullptr;
|
||||
ProxyConnection *m_connection = nullptr;
|
||||
|
||||
// Server information
|
||||
QString m_serverName;
|
||||
QString m_proxyServerName;
|
||||
QString m_proxyServerVersion;
|
||||
QString m_proxyServerApiVersion;
|
||||
|
||||
// Tunnel
|
||||
QString m_tunnelPartnerName;
|
||||
QString m_tunnelPartnerUuid;
|
||||
|
||||
void cleanUp();
|
||||
|
||||
void setState(State state);
|
||||
void setError(QAbstractSocket::SocketError error);
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void ready();
|
||||
void authenticated();
|
||||
void remoteConnectionEstablished();
|
||||
void disconnected();
|
||||
|
||||
void stateChanged(RemoteProxyConnection::State state);
|
||||
void errorOccurred(QAbstractSocket::SocketError error);
|
||||
void sslErrors(const QList<QSslError> &errors);
|
||||
|
||||
void dataReady(const QByteArray &data);
|
||||
|
||||
private slots:
|
||||
void onConnectionChanged(bool isConnected);
|
||||
void onConnectionDataAvailable(const QByteArray &data);
|
||||
void onConnectionSocketError(QAbstractSocket::SocketError error);
|
||||
void onConnectionStateChanged(QAbstractSocket::SocketState state);
|
||||
|
||||
void onHelloFinished();
|
||||
void onAuthenticateFinished();
|
||||
void onTunnelEstablished(const QString &clientName, const QString &clientUuid);
|
||||
|
||||
public slots:
|
||||
bool connectServer(const QUrl &url);
|
||||
bool authenticate(const QString &token, const QString &nonce = QString());
|
||||
void disconnectServer();
|
||||
bool sendData(const QByteArray &data);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(remoteproxyclient::RemoteProxyConnection::State);
|
||||
Q_DECLARE_METATYPE(remoteproxyclient::RemoteProxyConnection::ConnectionType);
|
||||
|
||||
#endif // REMOTEPROXYCONNECTOR_H
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -37,7 +37,7 @@ TerminalWindow::TerminalWindow(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
// Init view tabs
|
||||
m_tabs << ViewClients << ViewTunnels << ViewTunnelProxy;
|
||||
m_tabs << ViewTunnelProxy;
|
||||
|
||||
// Create main window
|
||||
m_mainWindow = initscr();
|
||||
@ -160,34 +160,6 @@ void TerminalWindow::paintHeader()
|
||||
QString windowName;
|
||||
QString headerString;
|
||||
switch (m_view) {
|
||||
case ViewClients:
|
||||
windowName = "-- Clients --";
|
||||
headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10")
|
||||
.arg(m_dataMap.value("serverName", "-").toString())
|
||||
.arg(m_dataMap.value("serverVersion", "-").toString())
|
||||
.arg(m_dataMap.value("apiVersion", "-").toString())
|
||||
.arg(m_dataMap.value("proxyStatistic").toMap().value("clientCount", 0).toInt())
|
||||
.arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalClientCount").toInt())
|
||||
.arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount", 0).toInt())
|
||||
.arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTunnelCount").toInt())
|
||||
.arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13)
|
||||
.arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10)
|
||||
.arg(windowName);
|
||||
break;
|
||||
case ViewTunnels:
|
||||
windowName = "-- Tunnels --";
|
||||
headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10")
|
||||
.arg(m_dataMap.value("serverName", "-").toString())
|
||||
.arg(m_dataMap.value("serverVersion", "-").toString())
|
||||
.arg(m_dataMap.value("apiVersion", "-").toString())
|
||||
.arg(m_dataMap.value("proxyStatistic").toMap().value("clientCount", 0).toInt())
|
||||
.arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalClientCount").toInt())
|
||||
.arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount", 0).toInt())
|
||||
.arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTunnelCount").toInt())
|
||||
.arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13)
|
||||
.arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10)
|
||||
.arg(windowName);
|
||||
break;
|
||||
case ViewTunnelProxy:
|
||||
windowName = "-- TunnelProxy --";
|
||||
headerString = QString(" Server: %1 (%2) | API: %3 | Total: %4 | Servers: %5 | Clients: %6 | %7 | %8")
|
||||
@ -366,12 +338,6 @@ void TerminalWindow::eventLoop()
|
||||
|
||||
// Refresh content window
|
||||
switch (m_view) {
|
||||
case ViewClients:
|
||||
paintContentClients();
|
||||
break;
|
||||
case ViewTunnels:
|
||||
paintContentTunnels();
|
||||
break;
|
||||
case ViewTunnelProxy:
|
||||
paintContentTunnelProxy();
|
||||
break;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -40,8 +40,6 @@ class TerminalWindow : public QObject
|
||||
public:
|
||||
|
||||
enum View {
|
||||
ViewClients,
|
||||
ViewTunnels,
|
||||
ViewTunnelProxy
|
||||
};
|
||||
Q_ENUM(View)
|
||||
|
||||
@ -2,8 +2,7 @@
|
||||
*.debug=false
|
||||
Application.debug=true
|
||||
Engine.debug=true
|
||||
Tunnel.debug=true
|
||||
JsonRpc.debug=true
|
||||
JsonRpc.debug=false
|
||||
JsonRpcTraffic.debug=false
|
||||
WebSocketServer.debug=true
|
||||
WebSocketServerTraffic.debug=false
|
||||
@ -11,12 +10,6 @@ TcpSocketServer.debug=true
|
||||
TcpSocketServerTraffic.debug=false
|
||||
UnixSocketServer.debug=true
|
||||
UnixSocketServerTraffic.debug=false
|
||||
Authentication.debug=true
|
||||
AuthenticationProcess.debug=false
|
||||
ProxyServer.debug=true
|
||||
ProxyServerTraffic.debug=false
|
||||
TunnelProxyServer.debug=true
|
||||
TunnelProxyServerTraffic.debug=false
|
||||
MonitorServer.debug=true
|
||||
AwsCredentialsProvider.debug=false
|
||||
AwsCredentialsProviderTraffic.debug=false
|
||||
|
||||
@ -5,14 +5,7 @@ logFile=/var/log/nymea-remoteproxy.log
|
||||
logEngineEnabled=false
|
||||
monitorSocket=/tmp/nymea-remoteproxy-monitor.sock
|
||||
jsonRpcTimeout=10000
|
||||
authenticationTimeout=8000
|
||||
inactiveTimeout=8000
|
||||
aloneTimeout=8000
|
||||
|
||||
[AWS]
|
||||
region=eu-west-1
|
||||
authorizerLambdaFunction=system-services-authorizer-dev-checkToken
|
||||
awsCredentialsUrl=http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Remote-Connection-Proxy-Role
|
||||
|
||||
[SSL]
|
||||
enabled=false
|
||||
@ -20,15 +13,7 @@ certificate=/etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
certificateKey=/etc/ssl/private/ssl-cert-snakeoil.key
|
||||
certificateChain=
|
||||
|
||||
[WebSocketServer]
|
||||
host=127.0.0.1
|
||||
port=443
|
||||
|
||||
[TcpServer]
|
||||
host=127.0.0.1
|
||||
port=80
|
||||
|
||||
[UnixSocketServer]
|
||||
[UnixSocketServerTunnelProxy]
|
||||
unixSocketFileName=/run/nymea-remoteproxy.socket
|
||||
|
||||
[WebSocketServerTunnelProxy]
|
||||
|
||||
@ -3,7 +3,7 @@ include(nymea-remoteproxy.pri)
|
||||
# Define versions
|
||||
SERVER_NAME=nymea-remoteproxy
|
||||
API_VERSION_MAJOR=0
|
||||
API_VERSION_MINOR=5
|
||||
API_VERSION_MINOR=6
|
||||
COPYRIGHT_YEAR=2023
|
||||
|
||||
# Parse and export SERVER_VERSION
|
||||
@ -12,18 +12,13 @@ SERVER_VERSION=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"')
|
||||
QMAKE_SUBSTITUTES += version.h.in
|
||||
|
||||
TEMPLATE=subdirs
|
||||
SUBDIRS += server client tunnelclient libnymea-remoteproxy libnymea-remoteproxyclient
|
||||
SUBDIRS += server tunnelclient monitor libnymea-remoteproxy libnymea-remoteproxyclient
|
||||
|
||||
!disabletests {
|
||||
SUBDIRS += tests
|
||||
}
|
||||
|
||||
!disablemonitor {
|
||||
SUBDIRS += monitor
|
||||
}
|
||||
|
||||
server.depends = libnymea-remoteproxy
|
||||
client.depends = libnymea-remoteproxyclient
|
||||
tunnelclient.depends = libnymea-remoteproxyclient
|
||||
tests.depends = libnymea-remoteproxy libnymea-remoteproxyclient
|
||||
|
||||
@ -46,6 +41,3 @@ ccache {
|
||||
message("Building with ccache support")
|
||||
}
|
||||
|
||||
disablemonitor {
|
||||
message("Building without the monitor")
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -48,8 +48,6 @@
|
||||
#include "loggingcategories.h"
|
||||
#include "proxyconfiguration.h"
|
||||
#include "remoteproxyserverapplication.h"
|
||||
#include "authentication/aws/awsauthenticator.h"
|
||||
#include "authentication/dummy/dummyauthenticator.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
@ -114,8 +112,7 @@ int main(int argc, char *argv[])
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
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"
|
||||
parser.setApplicationDescription(QString("\nThe nymea remote proxy server. This server allowes nymea clients to establish a tunnel connection to nymea deamons.\n\n"
|
||||
"Version: %1\n"
|
||||
"API version: %2\n\n"
|
||||
"Copyright %3 %4 nymea GmbH <developer@nymea.io>\n")
|
||||
@ -128,13 +125,6 @@ int main(int argc, char *argv[])
|
||||
"logfile", "/var/log/nymea-remoteproxy.log");
|
||||
parser.addOption(logfileOption);
|
||||
|
||||
QCommandLineOption developmentOption(QStringList() << "d" << "development", "Enable the development mode. This enabled the server "
|
||||
"assumes there are static AWS credentials provided to aws-cli.");
|
||||
parser.addOption(developmentOption);
|
||||
|
||||
QCommandLineOption mockAuthenticatorOption(QStringList() << "m" << "mock-authenticator", "Start the server using a mock authenticator which returns always true.");
|
||||
parser.addOption(mockAuthenticatorOption);
|
||||
|
||||
QCommandLineOption configOption(QStringList() << "c" <<"configuration", "The path to the proxy server configuration file. The default is " + configFile, "configuration");
|
||||
configOption.setDefaultValue(configFile);
|
||||
parser.addOption(configOption);
|
||||
@ -152,7 +142,7 @@ int main(int argc, char *argv[])
|
||||
qCDebug(dcApplication()) << "Loading configuration file from" << configFile;
|
||||
if (!configuration->loadConfiguration(parser.value(configOption))) {
|
||||
qCCritical(dcApplication()) << "Invalid configuration file passed" << parser.value(configOption);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (parser.isSet(logfileOption)) {
|
||||
@ -167,31 +157,19 @@ int main(int argc, char *argv[])
|
||||
QDir dir(fi.absolutePath());
|
||||
if (!dir.exists() && !dir.mkpath(dir.absolutePath())) {
|
||||
qCWarning(dcApplication()) << "Error opening log file" << configuration->logFileName();
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
s_logFile.setFileName(configuration->logFileName());
|
||||
if (!s_logFile.open(QFile::WriteOnly | QFile::Append)) {
|
||||
qWarning() << "Error opening log file" << configuration->logFileName();
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify webserver configuration
|
||||
if (configuration->webSocketServerProxyHost().isNull()) {
|
||||
qCCritical(dcApplication()) << "Invalid web socket host address passed.";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Verify tcp server configuration
|
||||
if (configuration->tcpServerHost().isNull()) {
|
||||
qCCritical(dcApplication()) << "Invalid TCP server host address passed.";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Verify SSL configuration
|
||||
if (configuration->sslEnabled() && configuration->sslConfiguration().isNull()) {
|
||||
qCCritical(dcApplication()) << "SSL is enabled but no SSL configuration specified.";
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
qCDebug(dcApplication()) << "Using SSL version:" << QSslSocket::sslLibraryVersionString();
|
||||
}
|
||||
@ -199,28 +177,12 @@ int main(int argc, char *argv[])
|
||||
qCDebug(dcApplication()) << "==========================================================";
|
||||
qCDebug(dcApplication()) << "Starting" << application.applicationName() << application.applicationVersion();
|
||||
qCDebug(dcApplication()) << "==========================================================";
|
||||
if (parser.isSet(developmentOption)) {
|
||||
qCWarning(dcApplication()) << "##########################################################";
|
||||
qCWarning(dcApplication()) << "# DEVELOPMENT MODE #";
|
||||
qCWarning(dcApplication()) << "##########################################################";
|
||||
}
|
||||
|
||||
if (s_loggingEnabled)
|
||||
qCDebug(dcApplication()) << "Logging enabled. Writing logs to" << s_logFile.fileName();
|
||||
|
||||
Authenticator *authenticator = nullptr;
|
||||
if (parser.isSet(mockAuthenticatorOption)) {
|
||||
authenticator = qobject_cast<Authenticator *>(new DummyAuthenticator(nullptr));
|
||||
} else {
|
||||
if (configuration->proxyEnabled()) {
|
||||
// Create default authenticator
|
||||
authenticator = qobject_cast<Authenticator *>(new AwsAuthenticator(configuration->awsCredentialsUrl(), nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
// Configure and start the engines
|
||||
Engine::instance()->setAuthenticator(authenticator);
|
||||
Engine::instance()->setDeveloperModeEnabled(parser.isSet(developmentOption));
|
||||
Engine::instance()->start(configuration);
|
||||
|
||||
return application.exec();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
||||
@ -9,15 +9,7 @@ certificate=:/test-certificate.crt
|
||||
certificateKey=:/test-certificate.key
|
||||
certificateChain=:/test-certificate.crt
|
||||
|
||||
[WebSocketServer]
|
||||
host=127.0.0.1
|
||||
port=1212
|
||||
|
||||
[TcpServer]
|
||||
host=127.0.0.1
|
||||
port=1213
|
||||
|
||||
[UnixSocketServer]
|
||||
[UnixSocketServerTunnelProxy]
|
||||
unixSocketFileName=/tmp/nymea-remoteproxy.socket
|
||||
|
||||
[WebSocketServerTunnelProxy]
|
||||
|
||||
@ -9,15 +9,7 @@ certificate=:/not-existing-test-certificate.crt
|
||||
certificateKey=:/test-certificate.key
|
||||
certificateChain=
|
||||
|
||||
[WebSocketServer]
|
||||
host=127.0.0.1
|
||||
port=1212
|
||||
|
||||
[TcpServer]
|
||||
host=127.0.0.1
|
||||
port=1213
|
||||
|
||||
[UnixSocketServer]
|
||||
[UnixSocketServerTunnelProxy]
|
||||
unixSocketFileName=/tmp/nymea-remoteproxy.socket
|
||||
|
||||
[WebSocketServerTunnelProxy]
|
||||
|
||||
@ -9,15 +9,7 @@ certificate=:/test-certificate.crt
|
||||
certificateKey=:/test-certificate.key
|
||||
certificateChain=:/not-existing-test-certificate.crt
|
||||
|
||||
[WebSocketServer]
|
||||
host=127.0.0.1
|
||||
port=1212
|
||||
|
||||
[TcpServer]
|
||||
host=127.0.0.1
|
||||
port=1213
|
||||
|
||||
[UnixSocketServer]
|
||||
[UnixSocketServerTunnelProxy]
|
||||
unixSocketFileName=/tmp/nymea-remoteproxy.socket
|
||||
|
||||
[WebSocketServerTunnelProxy]
|
||||
|
||||
@ -9,15 +9,7 @@ certificate=:/test-certificate.crt
|
||||
certificateKey=:/not-existing-test-certificate.key
|
||||
certificateChain=
|
||||
|
||||
[WebSocketServer]
|
||||
host=127.0.0.1
|
||||
port=1212
|
||||
|
||||
[TcpServer]
|
||||
host=127.0.0.1
|
||||
port=1213
|
||||
|
||||
[UnixSocketServer]
|
||||
[UnixSocketServerTunnelProxy]
|
||||
unixSocketFileName=/tmp/nymea-remoteproxy.socket
|
||||
|
||||
[WebSocketServerTunnelProxy]
|
||||
|
||||
@ -4,24 +4,14 @@ writeLogs=false
|
||||
logFile=/var/log/nymea-remoteproxy.log
|
||||
monitorSocket=/tmp/nymea-remoteproxy-test.sock
|
||||
jsonRpcTimeout=10000
|
||||
authenticationTimeout=10000
|
||||
inactiveTimeout=5000
|
||||
aloneTimeout=10000
|
||||
|
||||
[SSL]
|
||||
certificate=:/test-certificate.crt
|
||||
certificateKey=:/test-certificate.key
|
||||
certificateChain=
|
||||
|
||||
[WebSocketServer]
|
||||
host=127.0.0.1
|
||||
port=1212
|
||||
|
||||
[TcpServer]
|
||||
host=127.0.0.1
|
||||
port=1213
|
||||
|
||||
[UnixSocketServer]
|
||||
[UnixSocketServerTunnelProxy]
|
||||
unixSocketFileName=/tmp/nymea-remoteproxy.socket
|
||||
|
||||
[WebSocketServerTunnelProxy]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,93 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef REMOTEPROXYTESTSPROXY_H
|
||||
#define REMOTEPROXYTESTSPROXY_H
|
||||
|
||||
#include "basetest.h"
|
||||
|
||||
using namespace remoteproxy;
|
||||
using namespace remoteproxyclient;
|
||||
|
||||
class RemoteProxyTestsProxy : public BaseTest
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RemoteProxyTestsProxy(QObject *parent = nullptr);
|
||||
~RemoteProxyTestsProxy() = default;
|
||||
|
||||
private slots:
|
||||
// Basic stuff
|
||||
void startStopServer();
|
||||
void dummyAuthenticator();
|
||||
void monitorServer();
|
||||
|
||||
void configuration_data();
|
||||
void configuration();
|
||||
|
||||
// WebSocket connection
|
||||
void serverPortBlocked();
|
||||
void websocketBinaryData();
|
||||
void websocketPing();
|
||||
|
||||
// WebSocket connection API
|
||||
void getIntrospect();
|
||||
void getHello();
|
||||
|
||||
void apiBasicCalls_data();
|
||||
void apiBasicCalls();
|
||||
|
||||
void apiBasicCallsTcp_data();
|
||||
void apiBasicCallsTcp();
|
||||
|
||||
void authenticate_data();
|
||||
void authenticate();
|
||||
|
||||
void authenticateNonce();
|
||||
void authenticateSendData();
|
||||
|
||||
// Client lib
|
||||
void clientConnectionTcpSocket();
|
||||
void clientConnectionWebSocket();
|
||||
void remoteConnection();
|
||||
void multipleRemoteConnection();
|
||||
void trippleConnection();
|
||||
void duplicateUuid();
|
||||
void sslConfigurations();
|
||||
|
||||
void inactiveTimeout();
|
||||
void jsonRpcTimeout();
|
||||
void authenticationReplyTimeout();
|
||||
void authenticationReplyConnection();
|
||||
|
||||
// TCP Websocket combinations
|
||||
void tcpRemoteConnection();
|
||||
void tcpWebsocketRemoteConnection();
|
||||
|
||||
};
|
||||
|
||||
#endif // REMOTEPROXYTESTSPROXY_H
|
||||
@ -1,14 +0,0 @@
|
||||
include(../../nymea-remoteproxy.pri)
|
||||
include(../testbase/testbase.pri)
|
||||
|
||||
CONFIG += testcase
|
||||
QT += testlib
|
||||
|
||||
TARGET = nymea-remoteproxy-proxy-tests
|
||||
|
||||
HEADERS += remoteproxytestsproxy.h
|
||||
|
||||
SOURCES += remoteproxytestsproxy.cpp
|
||||
|
||||
target.path = $$[QT_INSTALL_PREFIX]/bin
|
||||
INSTALLS += target
|
||||
@ -27,9 +27,9 @@
|
||||
|
||||
#include "remoteproxyteststunnelproxy.h"
|
||||
|
||||
|
||||
#include "engine.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "remoteproxyconnection.h"
|
||||
#include "../common/slipdataprocessor.h"
|
||||
#include "../../version.h"
|
||||
|
||||
@ -43,6 +43,8 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QWebSocketServer>
|
||||
|
||||
using namespace remoteproxyclient;
|
||||
|
||||
RemoteProxyTestsTunnelProxy::RemoteProxyTestsTunnelProxy(QObject *parent) :
|
||||
BaseTest(parent)
|
||||
{
|
||||
@ -51,6 +53,13 @@ RemoteProxyTestsTunnelProxy::RemoteProxyTestsTunnelProxy(QObject *parent) :
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::startStopServer()
|
||||
{
|
||||
resetDebugCategories();
|
||||
addDebugCategory("Engine.debug=true");
|
||||
addDebugCategory("JsonRpc.debug=true");
|
||||
addDebugCategory("TcpSocketServer.debug=true");
|
||||
addDebugCategory("WebSocketServer.debug=true");
|
||||
addDebugCategory("TunnelProxyServer.debug=true");
|
||||
|
||||
startServer();
|
||||
stopServer();
|
||||
}
|
||||
@ -74,6 +83,10 @@ void RemoteProxyTestsTunnelProxy::apiBasicCallsTcp_data()
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::apiBasicCallsTcp()
|
||||
{
|
||||
resetDebugCategories();
|
||||
addDebugCategory("Engine.debug=true");
|
||||
addDebugCategory("TcpSocketServer.debug=true");
|
||||
|
||||
QFETCH(QByteArray, data);
|
||||
QFETCH(int, responseId);
|
||||
QFETCH(QString, responseStatus);
|
||||
@ -81,7 +94,7 @@ void RemoteProxyTestsTunnelProxy::apiBasicCallsTcp()
|
||||
// Start the server
|
||||
startServer();
|
||||
|
||||
QVariant response = injectTcpSocketProxyData(data);
|
||||
QVariant response = injectTcpSocketTunnelProxyData(data);
|
||||
QVERIFY(!response.isNull());
|
||||
|
||||
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
||||
@ -156,6 +169,317 @@ void RemoteProxyTestsTunnelProxy::getHello()
|
||||
stopServer();
|
||||
}
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::monitorServer()
|
||||
{
|
||||
|
||||
// Start the server
|
||||
startServer();
|
||||
|
||||
|
||||
// ** Create the server **
|
||||
QString serverName = "nymea server";
|
||||
QUuid serverUuid = QUuid::createUuid();
|
||||
|
||||
TunnelProxySocketServer *tunnelProxyServer = new TunnelProxySocketServer(serverUuid, serverName, this);
|
||||
connect(tunnelProxyServer, &TunnelProxySocketServer::sslErrors, this, [=](const QList<QSslError> &errors){
|
||||
tunnelProxyServer->ignoreSslErrors(errors);
|
||||
});
|
||||
|
||||
tunnelProxyServer->startServer(m_serverUrlTunnelProxyTcp);
|
||||
|
||||
QSignalSpy serverRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
|
||||
serverRunningSpy.wait();
|
||||
QVERIFY(serverRunningSpy.count() == 1);
|
||||
QList<QVariant> arguments = serverRunningSpy.takeFirst();
|
||||
QVERIFY(arguments.at(0).toBool() == true);
|
||||
QVERIFY(tunnelProxyServer->running());
|
||||
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
|
||||
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
|
||||
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
|
||||
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
|
||||
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
|
||||
|
||||
|
||||
// ** Remote connection 1 **
|
||||
|
||||
QString clientOneName = "Client one";
|
||||
QUuid clientOneUuid = QUuid::createUuid();
|
||||
TunnelProxyRemoteConnection *remoteConnectionOne = new TunnelProxyRemoteConnection(clientOneUuid, clientOneName, this);
|
||||
connect(remoteConnectionOne, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
|
||||
remoteConnectionOne->ignoreSslErrors(errors);
|
||||
});
|
||||
|
||||
remoteConnectionOne->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
|
||||
|
||||
// ** Tunnel proxy server socket 1 **
|
||||
QSignalSpy remoteConnectedOneSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
|
||||
QVERIFY(remoteConnectedOneSpy.wait());
|
||||
QVERIFY(remoteConnectedOneSpy.count() == 1);
|
||||
arguments = remoteConnectedOneSpy.takeFirst();
|
||||
|
||||
TunnelProxySocket *tunnelProxySocketOne = arguments.at(0).value<TunnelProxySocket *>();
|
||||
QVERIFY(tunnelProxySocketOne->clientName() == clientOneName);
|
||||
QVERIFY(tunnelProxySocketOne->clientUuid() == clientOneUuid);
|
||||
QVERIFY(!tunnelProxySocketOne->clientPeerAddress().isNull());
|
||||
QVERIFY(tunnelProxySocketOne->socketAddress() != 0x0000 && tunnelProxySocketOne->socketAddress() != 0xFFFF);
|
||||
QVERIFY(tunnelProxySocketOne->connected());
|
||||
|
||||
qDebug() << "Have socket one" << tunnelProxySocketOne;
|
||||
|
||||
// ** Send data in both directions
|
||||
QByteArray testData("#sdföiabi23u4b34b598gvndafjibnföQIUH34982HRIPURBFÖWLKDÜOQw9h934utbf ljBiH9FBLAJF RF AF,A§uu)(\"§)§(u$)($=$(((($((!");
|
||||
|
||||
// Socket -> Remote connection
|
||||
QSignalSpy remoteConnectionOneDataSpy(remoteConnectionOne, &TunnelProxyRemoteConnection::dataReady);
|
||||
tunnelProxySocketOne->writeData(testData);
|
||||
QVERIFY(remoteConnectionOneDataSpy.wait());
|
||||
QVERIFY(remoteConnectionOneDataSpy.count() == 1);
|
||||
arguments = remoteConnectionOneDataSpy.takeFirst();
|
||||
QByteArray receivedTestData = arguments.at(0).toByteArray();
|
||||
QVERIFY(receivedTestData == testData);
|
||||
|
||||
|
||||
// Remote connection -> Socket
|
||||
QByteArray testData2("The biggest decision in life is about changing your life through changing your mind. – Albert Schweitzer");
|
||||
QSignalSpy tunnelProxySocketOneDataSpy(tunnelProxySocketOne, &TunnelProxySocket::dataReceived);
|
||||
remoteConnectionOne->sendData(testData2);
|
||||
QVERIFY(tunnelProxySocketOneDataSpy.wait());
|
||||
QVERIFY(tunnelProxySocketOneDataSpy.count() == 1);
|
||||
arguments = tunnelProxySocketOneDataSpy.takeFirst();
|
||||
QByteArray receivedTestData2 = arguments.at(0).toByteArray();
|
||||
QVERIFY(receivedTestData2 == testData2);
|
||||
|
||||
|
||||
// ** Remote connection 2 **
|
||||
|
||||
QString clientTwoName = "Client two";
|
||||
QUuid clientTwoUuid = QUuid::createUuid();
|
||||
TunnelProxyRemoteConnection *remoteConnectionTwo = new TunnelProxyRemoteConnection(clientTwoUuid, clientTwoName, this);
|
||||
connect(remoteConnectionTwo, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
|
||||
remoteConnectionTwo->ignoreSslErrors(errors);
|
||||
});
|
||||
|
||||
remoteConnectionTwo->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
|
||||
|
||||
// ** Tunnel proxy server socket 2 **
|
||||
QSignalSpy remoteConnectedTwoSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
|
||||
QVERIFY(remoteConnectedTwoSpy.wait());
|
||||
QVERIFY(remoteConnectedTwoSpy.count() == 1);
|
||||
arguments = remoteConnectedTwoSpy.takeFirst();
|
||||
|
||||
TunnelProxySocket *tunnelProxySocketTwo = arguments.at(0).value<TunnelProxySocket *>();
|
||||
QVERIFY(tunnelProxySocketTwo->clientName() == clientTwoName);
|
||||
QVERIFY(tunnelProxySocketTwo->clientUuid() == clientTwoUuid);
|
||||
QVERIFY(!tunnelProxySocketTwo->clientPeerAddress().isNull());
|
||||
QVERIFY(tunnelProxySocketTwo->socketAddress() != 0x0000 && tunnelProxySocketTwo->socketAddress() != 0xFFFF);
|
||||
QVERIFY(tunnelProxySocketTwo->connected());
|
||||
|
||||
qDebug() << "Have socket two" << tunnelProxySocketTwo;
|
||||
|
||||
// ** Send data in both directions
|
||||
|
||||
// Socket -> Remote connection
|
||||
QSignalSpy remoteConnectionTwoDataSpy(remoteConnectionTwo, &TunnelProxyRemoteConnection::dataReady);
|
||||
tunnelProxySocketTwo->writeData(testData);
|
||||
QVERIFY(remoteConnectionTwoDataSpy.wait());
|
||||
QVERIFY(remoteConnectionTwoDataSpy.count() == 1);
|
||||
arguments = remoteConnectionTwoDataSpy.takeFirst();
|
||||
receivedTestData = arguments.at(0).toByteArray();
|
||||
QVERIFY(receivedTestData == testData);
|
||||
|
||||
// Remote connection -> Socket
|
||||
QSignalSpy tunnelProxySocketTwoDataSpy(tunnelProxySocketTwo, &TunnelProxySocket::dataReceived);
|
||||
remoteConnectionTwo->sendData(testData2);
|
||||
QVERIFY(tunnelProxySocketTwoDataSpy.wait());
|
||||
QVERIFY(tunnelProxySocketTwoDataSpy.count() == 1);
|
||||
arguments = tunnelProxySocketTwoDataSpy.takeFirst();
|
||||
receivedTestData2 = arguments.at(0).toByteArray();
|
||||
QVERIFY(receivedTestData2 == testData2);
|
||||
|
||||
// Get monitor data
|
||||
QLocalSocket *monitor = new QLocalSocket(this);
|
||||
QSignalSpy connectedSpy(monitor, &QLocalSocket::connected);
|
||||
monitor->connectToServer(m_configuration->monitorSocketFileName());
|
||||
if (connectedSpy.count() < 1) connectedSpy.wait();
|
||||
QVERIFY(connectedSpy.count() == 1);
|
||||
|
||||
QSignalSpy dataSpy(monitor, &QLocalSocket::readyRead);
|
||||
|
||||
QVariantMap request;
|
||||
request.insert("method", "refresh");
|
||||
QVariantMap params;
|
||||
params.insert("printAll", true);
|
||||
request.insert("params", params);
|
||||
|
||||
monitor->write(QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact) + "\n");
|
||||
|
||||
if (dataSpy.count() < 1) dataSpy.wait();
|
||||
QVERIFY(dataSpy.count() == 1);
|
||||
QByteArray data = monitor->readAll();
|
||||
qDebug() << data;
|
||||
|
||||
// TODO: verify monitor data
|
||||
|
||||
QSignalSpy disconnectedSpy(monitor, &QLocalSocket::connected);
|
||||
monitor->disconnectFromServer();
|
||||
if (disconnectedSpy.count() < 1) disconnectedSpy.wait();
|
||||
|
||||
Engine::instance()->tunnelProxyServer()->stopServer();
|
||||
|
||||
QTest::qWait(100);
|
||||
|
||||
QVERIFY(!tunnelProxyServer->running());
|
||||
QVERIFY(!remoteConnectionOne->remoteConnected());
|
||||
QVERIFY(!remoteConnectionTwo->remoteConnected());
|
||||
|
||||
// Clean up
|
||||
tunnelProxyServer->deleteLater();
|
||||
remoteConnectionOne->deleteLater();
|
||||
remoteConnectionTwo->deleteLater();
|
||||
|
||||
resetDebugCategories();
|
||||
|
||||
stopServer();
|
||||
}
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::configuration_data()
|
||||
{
|
||||
QTest::addColumn<QString>("fileName");
|
||||
QTest::addColumn<bool>("success");
|
||||
|
||||
QTest::newRow("valid configuration") << ":/test-configuration.conf" << true;
|
||||
QTest::newRow("valid configuration chain") << ":/test-configuration-chain.conf" << true;
|
||||
QTest::newRow("faulty filename") << ":/not-exisitng-test-configuration.conf" << false;
|
||||
QTest::newRow("faulty certificate") << ":/test-configuration-faulty-certificate.conf" << false;
|
||||
QTest::newRow("faulty key") << ":/test-configuration-faulty-key.conf" << false;
|
||||
QTest::newRow("faulty chain") << ":/test-configuration-faulty-chain.conf" << false;
|
||||
}
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::configuration()
|
||||
{
|
||||
QFETCH(QString, fileName);
|
||||
QFETCH(bool, success);
|
||||
|
||||
ProxyConfiguration configuration;
|
||||
QCOMPARE(configuration.loadConfiguration(fileName), success);
|
||||
}
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::serverPortBlocked()
|
||||
{
|
||||
cleanUpEngine();
|
||||
|
||||
m_configuration = new ProxyConfiguration(this);
|
||||
loadConfiguration(":/test-configuration.conf");
|
||||
|
||||
// Create a dummy server which blocks the port
|
||||
QWebSocketServer dummyServer("dummy-server", QWebSocketServer::NonSecureMode);
|
||||
QVERIFY(dummyServer.listen(QHostAddress::LocalHost, m_configuration->webSocketServerTunnelProxyPort()));
|
||||
|
||||
// Start proxy webserver
|
||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||
Engine::instance()->start(m_configuration);
|
||||
runningSpy.wait();
|
||||
QVERIFY(runningSpy.count() == 1);
|
||||
|
||||
// Make sure the server is not running
|
||||
QVERIFY(Engine::instance()->running());
|
||||
|
||||
// Make sure the websocket server is not running
|
||||
QVERIFY(!Engine::instance()->webSocketServerTunnelProxy()->running());
|
||||
|
||||
QSignalSpy closedSpy(&dummyServer, &QWebSocketServer::closed);
|
||||
dummyServer.close();
|
||||
closedSpy.wait();
|
||||
QVERIFY(closedSpy.count() == 1);
|
||||
|
||||
// Try again
|
||||
startServer();
|
||||
|
||||
// Clean up
|
||||
stopServer();
|
||||
|
||||
// Do the same with the tcp server
|
||||
cleanUpEngine();
|
||||
|
||||
m_configuration = new ProxyConfiguration(this);
|
||||
loadConfiguration(":/test-configuration.conf");
|
||||
|
||||
// Create a dummy server which blocks the port
|
||||
QTcpServer *tcpDummyServer = new QTcpServer(this);
|
||||
QVERIFY(tcpDummyServer->listen(QHostAddress::LocalHost, m_configuration->tcpServerTunnelProxyPort()));
|
||||
|
||||
// Start proxy webserver
|
||||
QSignalSpy runningSpy2(Engine::instance(), &Engine::runningChanged);
|
||||
Engine::instance()->start(m_configuration);
|
||||
runningSpy2.wait();
|
||||
QVERIFY(runningSpy2.count() == 1);
|
||||
|
||||
// Make sure the engine is running
|
||||
QVERIFY(Engine::instance()->running());
|
||||
|
||||
// Make sure the TCP server is not running
|
||||
QVERIFY(!Engine::instance()->tcpSocketServerTunnelProxy()->running());
|
||||
|
||||
tcpDummyServer->close();
|
||||
delete tcpDummyServer;
|
||||
|
||||
// Try again
|
||||
startServer();
|
||||
|
||||
// Make sure the TCP server is not running
|
||||
QVERIFY(Engine::instance()->webSocketServerTunnelProxy()->running());
|
||||
QVERIFY(Engine::instance()->tcpSocketServerTunnelProxy()->running());
|
||||
|
||||
// Clean up
|
||||
stopServer();
|
||||
}
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::websocketBinaryData()
|
||||
{
|
||||
// Start the server
|
||||
startServer();
|
||||
|
||||
QWebSocket *client = new QWebSocket("bad-client", QWebSocketProtocol::Version13);
|
||||
connect(client, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
|
||||
QSignalSpy spyConnection(client, SIGNAL(connected()));
|
||||
client->open(Engine::instance()->webSocketServerTunnelProxy()->serverUrl());
|
||||
spyConnection.wait();
|
||||
|
||||
// Send binary data and make sure the server disconnects this socket
|
||||
QSignalSpy spyDisconnected(client, SIGNAL(disconnected()));
|
||||
client->sendBinaryMessage("trying to upload stuff...stuff...more stuff... other stuff");
|
||||
spyConnection.wait(1000);
|
||||
QVERIFY(spyConnection.count() == 1);
|
||||
|
||||
// Clean up
|
||||
stopServer();
|
||||
}
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::websocketPing()
|
||||
{
|
||||
// Start the server
|
||||
startServer();
|
||||
|
||||
QWebSocket *client = new QWebSocket("bad-client", QWebSocketProtocol::Version13);
|
||||
connect(client, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
|
||||
QSignalSpy spyConnection(client, SIGNAL(connected()));
|
||||
client->open(Engine::instance()->webSocketServerTunnelProxy()->serverUrl());
|
||||
spyConnection.wait();
|
||||
QVERIFY(spyConnection.count() == 1);
|
||||
|
||||
QByteArray pingMessage = QByteArray("ping!");
|
||||
QSignalSpy pongSpy(client, &QWebSocket::pong);
|
||||
client->ping(pingMessage);
|
||||
pongSpy.wait();
|
||||
QVERIFY(pongSpy.count() == 1);
|
||||
qDebug() << pongSpy.at(0).at(0) << pongSpy.at(0).at(1);
|
||||
|
||||
QVERIFY(pongSpy.at(0).at(1).toByteArray() == pingMessage);
|
||||
|
||||
// Clean up
|
||||
stopServer();
|
||||
}
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::apiBasicCalls_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("data");
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
#include "basetest.h"
|
||||
|
||||
using namespace remoteproxy;
|
||||
using namespace remoteproxyclient;
|
||||
|
||||
class RemoteProxyTestsTunnelProxy : public BaseTest
|
||||
{
|
||||
@ -48,6 +47,16 @@ private slots:
|
||||
void getIntrospect();
|
||||
void getHello();
|
||||
|
||||
void monitorServer();
|
||||
|
||||
void configuration_data();
|
||||
void configuration();
|
||||
|
||||
void serverPortBlocked();
|
||||
|
||||
void websocketBinaryData();
|
||||
void websocketPing();
|
||||
|
||||
void apiBasicCalls_data();
|
||||
void apiBasicCalls();
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -29,7 +29,6 @@
|
||||
|
||||
#include "engine.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "remoteproxyconnection.h"
|
||||
|
||||
#include "../common/slipdataprocessor.h"
|
||||
|
||||
@ -78,18 +77,6 @@ void BaseTest::cleanUpEngine()
|
||||
QVERIFY(!Engine::exists());
|
||||
}
|
||||
|
||||
if (m_mockAuthenticator) {
|
||||
delete m_mockAuthenticator;
|
||||
m_mockAuthenticator = nullptr;
|
||||
}
|
||||
|
||||
if (m_dummyAuthenticator) {
|
||||
delete m_dummyAuthenticator;
|
||||
m_dummyAuthenticator = nullptr;
|
||||
}
|
||||
|
||||
m_authenticator = nullptr;
|
||||
|
||||
if (m_configuration) {
|
||||
m_configuration = nullptr;
|
||||
}
|
||||
@ -103,39 +90,26 @@ void BaseTest::restartEngine()
|
||||
|
||||
void BaseTest::startEngine()
|
||||
{
|
||||
m_configuration = new ProxyConfiguration(this);
|
||||
if (!m_configuration)
|
||||
m_configuration = new ProxyConfiguration(Engine::instance());
|
||||
|
||||
loadConfiguration(":/test-configuration.conf");
|
||||
|
||||
m_dummyAuthenticator = new DummyAuthenticator(this);
|
||||
m_mockAuthenticator = new MockAuthenticator(this);
|
||||
m_authenticator = qobject_cast<Authenticator *>(m_mockAuthenticator);
|
||||
if (!Engine::exists()) {
|
||||
Engine::instance()->setAuthenticator(m_authenticator);
|
||||
Engine::instance()->setDeveloperModeEnabled(true);
|
||||
QVERIFY(Engine::exists());
|
||||
QVERIFY(!Engine::instance()->running());
|
||||
}
|
||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||
Engine::instance()->start(m_configuration);
|
||||
runningSpy.wait();
|
||||
QVERIFY(runningSpy.count() == 1);
|
||||
QVERIFY(Engine::instance()->running());
|
||||
}
|
||||
|
||||
void BaseTest::startServer()
|
||||
{
|
||||
restartEngine();
|
||||
|
||||
if (!Engine::instance()->running()) {
|
||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||
Engine::instance()->setDeveloperModeEnabled(true);
|
||||
Engine::instance()->start(m_configuration);
|
||||
runningSpy.wait();
|
||||
QVERIFY(runningSpy.count() == 1);
|
||||
}
|
||||
|
||||
QVERIFY(Engine::instance()->running());
|
||||
QVERIFY(Engine::instance()->developerMode());
|
||||
QVERIFY(Engine::instance()->webSocketServerProxy()->running());
|
||||
QVERIFY(Engine::instance()->tcpSocketServerProxy()->running());
|
||||
QVERIFY(Engine::instance()->webSocketServerTunnelProxy()->running());
|
||||
QVERIFY(Engine::instance()->tcpSocketServerTunnelProxy()->running());
|
||||
QVERIFY(Engine::instance()->proxyServer()->running());
|
||||
QVERIFY(Engine::instance()->unixSocketServerTunnelProxy()->running());
|
||||
QVERIFY(Engine::instance()->tunnelProxyServer()->running());
|
||||
QVERIFY(Engine::instance()->monitorServer()->running());
|
||||
}
|
||||
@ -151,316 +125,6 @@ void BaseTest::stopServer()
|
||||
cleanUpEngine();
|
||||
}
|
||||
|
||||
QVariant BaseTest::invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params)
|
||||
{
|
||||
QVariantMap request;
|
||||
request.insert("id", m_commandCounter);
|
||||
request.insert("method", method);
|
||||
request.insert("params", params);
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(request);
|
||||
|
||||
QWebSocket *socket = new QWebSocket("proxy-testclient", QWebSocketProtocol::Version13);
|
||||
connect(socket, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
|
||||
QSignalSpy spyConnection(socket, SIGNAL(connected()));
|
||||
socket->open(Engine::instance()->webSocketServerProxy()->serverUrl());
|
||||
spyConnection.wait();
|
||||
if (spyConnection.count() == 0) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QSignalSpy dataSpy(socket, SIGNAL(textMessageReceived(QString)));
|
||||
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
|
||||
dataSpy.wait();
|
||||
|
||||
socket->close();
|
||||
socket->deleteLater();
|
||||
|
||||
for (int i = 0; i < dataSpy.count(); i++) {
|
||||
// Make sure the response ends with '}\n'
|
||||
if (!dataSpy.at(i).last().toByteArray().endsWith("}\n")) {
|
||||
qWarning() << "JSON data does not end with \"}\n\"";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
// Make sure the response it a valid JSON string
|
||||
QJsonParseError error;
|
||||
jsonDoc = QJsonDocument::fromJson(dataSpy.at(i).last().toByteArray(), &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "JSON parser error" << error.errorString();
|
||||
return QVariant();
|
||||
}
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
|
||||
// skip notifications
|
||||
if (response.contains("notification"))
|
||||
continue;
|
||||
|
||||
if (response.value("id").toInt() == m_commandCounter) {
|
||||
m_commandCounter++;
|
||||
return jsonDoc.toVariant();
|
||||
}
|
||||
}
|
||||
|
||||
m_commandCounter++;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant BaseTest::injectWebSocketProxyData(const QByteArray &data)
|
||||
{
|
||||
QWebSocket *socket = new QWebSocket("proxy-testclient", QWebSocketProtocol::Version13);
|
||||
connect(socket, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
|
||||
|
||||
QSignalSpy spyConnection(socket, SIGNAL(connected()));
|
||||
socket->open(Engine::instance()->webSocketServerProxy()->serverUrl());
|
||||
spyConnection.wait();
|
||||
if (spyConnection.count() == 0) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QSignalSpy spy(socket, SIGNAL(textMessageReceived(QString)));
|
||||
socket->sendTextMessage(QString(data));
|
||||
spy.wait();
|
||||
|
||||
socket->close();
|
||||
socket->deleteLater();
|
||||
|
||||
for (int i = 0; i < spy.count(); i++) {
|
||||
// Make sure the response ends with '}\n'
|
||||
if (!spy.at(i).last().toByteArray().endsWith("}\n")) {
|
||||
qWarning() << "JSON data does not end with \"}\n\"";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
// Make sure the response it a valid JSON string
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(spy.at(i).last().toByteArray(), &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "JSON parser error" << error.errorString();
|
||||
return QVariant();
|
||||
}
|
||||
return jsonDoc.toVariant();
|
||||
}
|
||||
m_commandCounter++;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant BaseTest::invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params)
|
||||
{
|
||||
QVariantMap request;
|
||||
request.insert("id", m_commandCounter);
|
||||
request.insert("method", method);
|
||||
request.insert("params", params);
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(request);
|
||||
|
||||
QSslSocket *socket = new QSslSocket(this);
|
||||
typedef void (QSslSocket:: *sslErrorsSignal)(const QList<QSslError> &);
|
||||
QObject::connect(socket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &BaseTest::sslSocketSslErrors);
|
||||
|
||||
QSignalSpy spyConnection(socket, &QSslSocket::connected);
|
||||
socket->connectToHostEncrypted(Engine::instance()->tcpSocketServerProxy()->serverUrl().host(),
|
||||
static_cast<quint16>(Engine::instance()->tcpSocketServerProxy()->serverUrl().port()));
|
||||
spyConnection.wait();
|
||||
if (spyConnection.count() == 0) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QSignalSpy dataSpy(socket, &QSslSocket::readyRead);
|
||||
socket->write(jsonDoc.toJson(QJsonDocument::Compact) + '\n');
|
||||
dataSpy.wait();
|
||||
if (dataSpy.count() != 1) {
|
||||
qWarning() << "No data received";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QByteArray data = socket->readAll();
|
||||
socket->close();
|
||||
socket->deleteLater();
|
||||
|
||||
// Make sure the response ends with '}\n'
|
||||
if (!data.endsWith("}\n")) {
|
||||
qWarning() << "JSON data does not end with \"}\n\"";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
// Make sure the response it a valid JSON string
|
||||
QJsonParseError error;
|
||||
jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "JSON parser error" << error.errorString();
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
|
||||
if (response.value("id").toInt() == m_commandCounter) {
|
||||
m_commandCounter++;
|
||||
return jsonDoc.toVariant();
|
||||
}
|
||||
|
||||
m_commandCounter++;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool BaseTest::createRemoteConnection(const QString &token, const QString &nonce, QObject *parent)
|
||||
{
|
||||
// Configure mock authenticator
|
||||
m_mockAuthenticator->setTimeoutDuration(100);
|
||||
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||
|
||||
QString nameConnectionOne = "Test client one";
|
||||
QUuid uuidConnectionOne = QUuid::createUuid();
|
||||
|
||||
QString nameConnectionTwo = "Test client two";
|
||||
QUuid uuidConnectionTwo = QUuid::createUuid();
|
||||
|
||||
// QByteArray dataOne = "Hello from client one :-)";
|
||||
// QByteArray dataTwo = "Hello from client two :-)";
|
||||
|
||||
// Create two connection
|
||||
RemoteProxyConnection *connectionOne = new RemoteProxyConnection(uuidConnectionOne, nameConnectionOne, parent);
|
||||
connect(connectionOne, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
|
||||
|
||||
RemoteProxyConnection *connectionTwo = new RemoteProxyConnection(uuidConnectionTwo, nameConnectionTwo, parent);
|
||||
connect(connectionTwo, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
|
||||
|
||||
// Connect one
|
||||
QSignalSpy connectionOneReadySpy(connectionOne, &RemoteProxyConnection::ready);
|
||||
if (!connectionOne->connectServer(m_serverUrlProxyTcp)) {
|
||||
qWarning() << "Could not connect client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionOneReadySpy.wait();
|
||||
if (connectionOneReadySpy.count() != 1) {
|
||||
qWarning() << "Could not connect client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!connectionOne->isConnected()) {
|
||||
qWarning() << "Could not connect client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connect two
|
||||
QSignalSpy connectionTwoReadySpy(connectionTwo, &RemoteProxyConnection::ready);
|
||||
if (!connectionTwo->connectServer(m_serverUrlProxyTcp)) {
|
||||
qWarning() << "Could not connect client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionTwoReadySpy.wait();
|
||||
if (connectionTwoReadySpy.count() != 1) {
|
||||
qWarning() << "Could not connect client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!connectionTwo->isConnected()) {
|
||||
qWarning() << "Could not connect client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Authenticate one
|
||||
QSignalSpy remoteConnectionEstablishedOne(connectionOne, &RemoteProxyConnection::remoteConnectionEstablished);
|
||||
QSignalSpy connectionOneAuthenticatedSpy(connectionOne, &RemoteProxyConnection::authenticated);
|
||||
if (!connectionOne->authenticate(token, nonce)) {
|
||||
qWarning() << "Could not authenticate client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionOneAuthenticatedSpy.wait();
|
||||
if (connectionOneAuthenticatedSpy.count() != 1) {
|
||||
qWarning() << "Could not authenticate client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connectionOne->state() != RemoteProxyConnection::StateAuthenticated) {
|
||||
qWarning() << "Could not authenticate client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Authenticate two
|
||||
QSignalSpy remoteConnectionEstablishedTwo(connectionTwo, &RemoteProxyConnection::remoteConnectionEstablished);
|
||||
QSignalSpy connectionTwoAuthenticatedSpy(connectionTwo, &RemoteProxyConnection::authenticated);
|
||||
if (!connectionTwo->authenticate(token, nonce)) {
|
||||
qWarning() << "Could not authenticate client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionTwoAuthenticatedSpy.wait();
|
||||
if (connectionTwoAuthenticatedSpy.count() != 1) {
|
||||
qWarning() << "Could not authenticate client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connectionTwo->state() != RemoteProxyConnection::StateAuthenticated && connectionTwo->state() != RemoteProxyConnection::StateRemoteConnected) {
|
||||
qWarning() << "Could not authenticate client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for both to be connected
|
||||
if (remoteConnectionEstablishedOne.count() < 1)
|
||||
remoteConnectionEstablishedOne.wait();
|
||||
|
||||
if (remoteConnectionEstablishedTwo.count() < 1)
|
||||
remoteConnectionEstablishedTwo.wait();
|
||||
|
||||
if (remoteConnectionEstablishedOne.count() != 1 || remoteConnectionEstablishedTwo.count() != 1) {
|
||||
qWarning() << "Could not establish remote connection";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connectionOne->state() != RemoteProxyConnection::StateRemoteConnected || connectionTwo->state() != RemoteProxyConnection::StateRemoteConnected) {
|
||||
qWarning() << "Could not establish remote connection";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QVariant BaseTest::injectTcpSocketProxyData(const QByteArray &data)
|
||||
{
|
||||
QSslSocket *socket = new QSslSocket(this);
|
||||
typedef void (QSslSocket:: *sslErrorsSignal)(const QList<QSslError> &);
|
||||
QObject::connect(socket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &BaseTest::sslSocketSslErrors);
|
||||
|
||||
QSignalSpy spyConnection(socket, &QSslSocket::connected);
|
||||
socket->connectToHostEncrypted(Engine::instance()->tcpSocketServerProxy()->serverUrl().host(),
|
||||
static_cast<quint16>(Engine::instance()->tcpSocketServerProxy()->serverUrl().port()));
|
||||
spyConnection.wait();
|
||||
if (spyConnection.count() == 0) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QSignalSpy dataSpy(socket, &QSslSocket::readyRead);
|
||||
socket->write(data + '\n');
|
||||
dataSpy.wait();
|
||||
if (dataSpy.count() != 1) {
|
||||
qWarning() << "No data received";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QByteArray socketData = socket->readAll();
|
||||
socket->close();
|
||||
socket->deleteLater();
|
||||
|
||||
// Make sure the response ends with '}\n'
|
||||
if (!socketData.endsWith("}\n")) {
|
||||
qWarning() << "JSON data does not end with \"}\n\"";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
// Make sure the response it a valid JSON string
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(socketData, &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "JSON parser error" << error.errorString();
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
m_commandCounter++;
|
||||
return jsonDoc.toVariant();
|
||||
}
|
||||
|
||||
QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params)
|
||||
{
|
||||
@ -858,22 +522,6 @@ QPair<QVariant, QWebSocket *> BaseTest::invokeWebSocketTunnelProxyApiCallPersist
|
||||
|
||||
void BaseTest::initTestCase()
|
||||
{
|
||||
qRegisterMetaType<RemoteProxyConnection::State>();
|
||||
qRegisterMetaType<RemoteProxyConnection::ConnectionType>();
|
||||
|
||||
m_testToken = "eyJraWQiOiJXdnFFT3prVVh5VDlINzFyRUpoNWdxRnkxNFhnR2l3SFAzVEIzUFQ1V3ZrPSIsImFsZyI6IlJT"
|
||||
"MjU2In0.eyJzdWIiOiJmZTJmZDNlNC1hMGJhLTQ1OTUtOWRiZS00ZDkxYjRiMjFlMzUiLCJhdWQiOiI4cmpoZ"
|
||||
"mRsZjlqZjFzdW9rMmpjcmx0ZDZ2IiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImV2ZW50X2lkIjoiN2Y5NTRiNm"
|
||||
"ItOTYyZi0xMWU4LWI0ZjItMzU5NWRiZmRiODVmIiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE1MzM"
|
||||
"xOTkxMzgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5ldS13ZXN0LTEuYW1hem9uYXdzLmNvbVwvZXUt"
|
||||
"d2VzdC0xXzZlWDZZam1YciIsImNvZ25pdG86dXNlcm5hbWUiOiIyYzE3YzUwZC0xZDFlLTRhM2UtYmFjOS0zZ"
|
||||
"DI0YjQ1MTFiYWEiLCJleHAiOjE1MzMyMDI3MzgsImlhdCI6MTUzMzE5OTEzOCwiZW1haWwiOiJqZW5raW5zQG"
|
||||
"d1aC5pbyJ9.hMMSvZMx7pMvV70PaUmTZOZgdez5WGX5yagRFPZojBm8jNWZND1lUmi0RFkybeD4HonDiKHxTF"
|
||||
"_psyJoBVndgHbxYBBl3Np4gn0MxECWjvLxYzGxVBBkN24SqNUyAGkr0uFcZKkBecdtJlqNQnZN8Uk49twmODf"
|
||||
"raRaRmGmKmRBAK1qDITpUgP6AWqH9xoJWaoDzt0kwJ3EtPxS7vL1PHqOaN8ggXA8Eq4iTCSfXU1HAXhIWJH9Y"
|
||||
"pQbj58v1vktaAEATdmKmlzmcix-HJK9wWHRSuv3TsNa8DGxvcPOoeTu8Vql7krZ-y7Zu-s2WsgeP4VxyT80VE"
|
||||
"T_xh6pMkOhE6g";
|
||||
|
||||
qCDebug(dcApplication()) << "Init test case done.";
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -38,14 +38,9 @@
|
||||
#include <QSslConfiguration>
|
||||
|
||||
#include "jsonrpc/jsontypes.h"
|
||||
#include "mockauthenticator.h"
|
||||
#include "proxyconfiguration.h"
|
||||
#include "remoteproxyconnection.h"
|
||||
#include "authentication/aws/awsauthenticator.h"
|
||||
#include "authentication/dummy/dummyauthenticator.h"
|
||||
|
||||
using namespace remoteproxy;
|
||||
using namespace remoteproxyclient;
|
||||
|
||||
class BaseTest : public QObject
|
||||
{
|
||||
@ -56,25 +51,16 @@ public:
|
||||
protected:
|
||||
ProxyConfiguration *m_configuration = nullptr;
|
||||
|
||||
QUrl m_serverUrlProxyWebSocket = QUrl("wss://127.0.0.1:1212");
|
||||
QUrl m_serverUrlProxyTcp = QUrl("ssl://127.0.0.1:1213");
|
||||
|
||||
QUrl m_serverUrlTunnelProxyWebSocket = QUrl("wss://127.0.0.1:2212");
|
||||
QUrl m_serverUrlTunnelProxyTcp = QUrl("ssl://127.0.0.1:2213");
|
||||
|
||||
QSslConfiguration m_sslConfiguration;
|
||||
|
||||
Authenticator *m_authenticator = nullptr;
|
||||
MockAuthenticator *m_mockAuthenticator = nullptr;
|
||||
DummyAuthenticator *m_dummyAuthenticator = nullptr;
|
||||
AwsAuthenticator *m_awsAuthenticator = nullptr;
|
||||
|
||||
QString m_testToken;
|
||||
|
||||
int m_commandCounter = 0;
|
||||
|
||||
void loadConfiguration(const QString &fileName);
|
||||
void setAuthenticator(Authenticator *authenticator);
|
||||
|
||||
void resetDebugCategories();
|
||||
void addDebugCategory(const QString &debugCategory);
|
||||
@ -85,12 +71,6 @@ protected:
|
||||
void startServer();
|
||||
void stopServer();
|
||||
|
||||
QVariant invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap());
|
||||
QVariant injectWebSocketProxyData(const QByteArray &data);
|
||||
|
||||
QVariant invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap());
|
||||
QVariant injectTcpSocketProxyData(const QByteArray &data);
|
||||
|
||||
QVariant invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap());
|
||||
QVariant injectWebSocketTunnelProxyData(const QByteArray &data);
|
||||
|
||||
@ -118,12 +98,6 @@ public slots:
|
||||
socket->ignoreSslErrors();
|
||||
}
|
||||
|
||||
inline void ignoreConnectionSslError(const QList<QSslError> &errors) {
|
||||
RemoteProxyConnection *connection = static_cast<RemoteProxyConnection *>(sender());
|
||||
connection->ignoreSslErrors(errors);
|
||||
connection->ignoreSslErrors();
|
||||
}
|
||||
|
||||
inline void verifyError(const QVariant &response, const QString &fieldName, const QString &error) {
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(response);
|
||||
QVERIFY2(response.toMap().value("status").toString() == QString("success"),
|
||||
@ -139,10 +113,6 @@ public slots:
|
||||
.toLatin1().data());
|
||||
}
|
||||
|
||||
inline void verifyAuthenticationError(const QVariant &response, Authenticator::AuthenticationError error = Authenticator::AuthenticationErrorNoError) {
|
||||
verifyError(response, "authenticationError", JsonTypes::authenticationErrorToString(error));
|
||||
}
|
||||
|
||||
inline void verifyTunnelProxyError(const QVariant &response, TunnelProxyServer::TunnelProxyError error = TunnelProxyServer::TunnelProxyErrorNoError) {
|
||||
verifyError(response, "tunnelProxyError", JsonTypes::tunnelProxyErrorToString(error));
|
||||
}
|
||||
|
||||
@ -1,90 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "proxy/proxyclient.h"
|
||||
#include "mockauthenticator.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "authentication/authenticationreply.h"
|
||||
|
||||
MockAuthenticator::MockAuthenticator(QObject *parent) :
|
||||
Authenticator(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString MockAuthenticator::name() const
|
||||
{
|
||||
return "Mock authenticator";
|
||||
}
|
||||
|
||||
void MockAuthenticator::setTimeoutDuration(int timeout)
|
||||
{
|
||||
m_timeoutDuration = timeout;
|
||||
}
|
||||
|
||||
void MockAuthenticator::setExpectedAuthenticationError(Authenticator::AuthenticationError error)
|
||||
{
|
||||
m_expectedError = error;
|
||||
}
|
||||
|
||||
void MockAuthenticator::replyFinished()
|
||||
{
|
||||
MockAuthenticationReply *reply = static_cast<MockAuthenticationReply *>(sender());
|
||||
|
||||
qCDebug(dcAuthentication()) << name() << "Authentication finished" << reply << reply->authenticationReply();
|
||||
setReplyError(reply->authenticationReply(), reply->error());
|
||||
setReplyFinished(reply->authenticationReply());
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
AuthenticationReply *MockAuthenticator::authenticate(ProxyClient *proxyClient)
|
||||
{
|
||||
qCDebug(dcAuthentication()) << name() << "Start authentication for" << proxyClient << "using token" << proxyClient->token() << "Auth duration" << m_timeoutDuration << "[ms]";
|
||||
|
||||
AuthenticationReply *authenticationReply = createAuthenticationReply(proxyClient, proxyClient);
|
||||
|
||||
// Create mock authentication reply with the given configuration
|
||||
MockAuthenticationReply *reply = new MockAuthenticationReply(m_timeoutDuration, m_expectedError, authenticationReply, proxyClient);
|
||||
connect(reply, &MockAuthenticationReply::finished, this, &MockAuthenticator::replyFinished);
|
||||
|
||||
return authenticationReply;
|
||||
}
|
||||
|
||||
MockAuthenticationReply::MockAuthenticationReply(int timeout, Authenticator::AuthenticationError error, AuthenticationReply *authenticationReply, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_error(error),
|
||||
m_authenticationReply(authenticationReply)
|
||||
|
||||
{
|
||||
QTimer::singleShot(timeout, this, &MockAuthenticationReply::finished);
|
||||
}
|
||||
|
||||
MockAuthenticationReply::~MockAuthenticationReply()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -1,80 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by copyright law, and
|
||||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||
* of use of nymea GmbH, available under https://nymea.io/license
|
||||
*
|
||||
* GNU General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this project.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under contact@nymea.io
|
||||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef MOCKAUTHENTICATOR_H
|
||||
#define MOCKAUTHENTICATOR_H
|
||||
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
|
||||
#include "authentication/authenticator.h"
|
||||
|
||||
using namespace remoteproxy;
|
||||
|
||||
class MockAuthenticationReply : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MockAuthenticationReply(int timeout, Authenticator::AuthenticationError error, AuthenticationReply *authenticationReply, QObject *parent = nullptr);
|
||||
~MockAuthenticationReply();
|
||||
|
||||
AuthenticationReply *authenticationReply() const { return m_authenticationReply; }
|
||||
Authenticator::AuthenticationError error() const { return m_error; }
|
||||
|
||||
private:
|
||||
Authenticator::AuthenticationError m_error;
|
||||
AuthenticationReply *m_authenticationReply = nullptr;
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
};
|
||||
|
||||
|
||||
class MockAuthenticator : public Authenticator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MockAuthenticator(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
|
||||
void setTimeoutDuration(int timeout);
|
||||
void setExpectedAuthenticationError(Authenticator::AuthenticationError error = AuthenticationErrorNoError);
|
||||
|
||||
private:
|
||||
int m_timeoutDuration = 500;
|
||||
Authenticator::AuthenticationError m_expectedError;
|
||||
|
||||
private slots:
|
||||
void replyFinished();
|
||||
|
||||
public slots:
|
||||
AuthenticationReply *authenticate(ProxyClient *proxyClient) override;
|
||||
};
|
||||
|
||||
#endif // MOCKAUTHENTICATOR_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user