Merge PR #642: Add tunnel proxy remote connection

This commit is contained in:
Jenkins nymea 2022-01-21 22:31:38 +01:00
commit 98a51afc6d
24 changed files with 670 additions and 58 deletions

View File

@ -49,17 +49,27 @@ NymeaConfiguration::NymeaConfiguration(JsonRpcClient *client, QObject *parent):
m_tcpServerConfigurations(new ServerConfigurations(this)),
m_webSocketServerConfigurations(new ServerConfigurations(this)),
m_webServerConfigurations(new WebServerConfigurations(this)),
m_tunnelProxyServerConfigurations(new TunnelProxyServerConfigurations(this)),
m_mqttServerConfigurations(new ServerConfigurations(this)),
m_mqttPolicies(new MqttPolicies(this))
{
client->registerNotificationHandler(this, "Configuration", "notificationReceived");
}
bool NymeaConfiguration::fetchingData() const
{
return m_fetchingData;
}
void NymeaConfiguration::init()
{
m_fetchingData = true;
emit fetchingDataChanged();
m_tcpServerConfigurations->clear();
m_webSocketServerConfigurations->clear();
m_mqttServerConfigurations->clear();
m_tunnelProxyServerConfigurations->clear();
m_client->sendCommand("Configuration.GetConfigurations", this, "getConfigurationsResponse");
m_client->sendCommand("Configuration.GetMqttServerConfigurations", this, "getMqttServerConfigsReply");
m_client->sendCommand("Configuration.GetMqttPolicies", this, "getMqttPoliciesReply");
@ -123,6 +133,11 @@ WebServerConfigurations *NymeaConfiguration::webServerConfigurations() const
return m_webServerConfigurations;
}
TunnelProxyServerConfigurations *NymeaConfiguration::tunnelProxyServerConfigurations() const
{
return m_tunnelProxyServerConfigurations;
}
ServerConfigurations *NymeaConfiguration::mqttServerConfigurations() const
{
return m_mqttServerConfigurations;
@ -135,16 +150,21 @@ MqttPolicies *NymeaConfiguration::mqttPolicies() const
ServerConfiguration *NymeaConfiguration::createServerConfiguration(const QString &address, int port, bool authEnabled, bool sslEnabled)
{
return new ServerConfiguration(QUuid::createUuid().toString(), QHostAddress(address), port, authEnabled, sslEnabled);
return new ServerConfiguration(QUuid::createUuid().toString(), address, port, authEnabled, sslEnabled);
}
WebServerConfiguration *NymeaConfiguration::createWebServerConfiguration(const QString &address, int port, bool authEnabled, bool sslEnabled, const QString &publicFolder)
{
auto ret = new WebServerConfiguration(QUuid::createUuid().toString(), QHostAddress(address), port, authEnabled, sslEnabled);
auto ret = new WebServerConfiguration(QUuid::createUuid().toString(), address, port, authEnabled, sslEnabled);
ret->setPublicFolder(publicFolder);
return ret;
}
TunnelProxyServerConfiguration *NymeaConfiguration::createTunnelProxyServerConfiguration(const QString &address, int port, bool authEnabled, bool sslEnabled, bool ignoreSslErrors)
{
return new TunnelProxyServerConfiguration(QUuid::createUuid().toString(), address, port, authEnabled, sslEnabled, ignoreSslErrors);
}
MqttPolicy *NymeaConfiguration::createMqttPolicy() const
{
return new MqttPolicy(QString(), QString(), QString(), {"#"}, {"#"});
@ -190,6 +210,20 @@ void NymeaConfiguration::setWebServerConfiguration(WebServerConfiguration *confi
m_client->sendCommand("Configuration.SetWebServerConfiguration", params, this, "setWebConfigReply");
}
void NymeaConfiguration::setTunnelProxyServerConfiguration(TunnelProxyServerConfiguration *configuration)
{
QVariantMap params;
QVariantMap configurationMap;
configurationMap.insert("id", configuration->id());
configurationMap.insert("address", configuration->address());
configurationMap.insert("port", configuration->port());
configurationMap.insert("authenticationEnabled", configuration->authenticationEnabled());
configurationMap.insert("sslEnabled", configuration->sslEnabled());
configurationMap.insert("ignoreSslErrors", configuration->ignoreSslErrors());
params.insert("configuration", configurationMap);
m_client->sendCommand("Configuration.SetTunnelProxyServerConfiguration", params, this, "setTunnelProxyServerConfigReply");
}
void NymeaConfiguration::setMqttServerConfiguration(ServerConfiguration *configuration)
{
QVariantMap params;
@ -224,6 +258,13 @@ void NymeaConfiguration::deleteWebServerConfiguration(const QString &id)
m_client->sendCommand("Configuration.DeleteWebServerConfiguration", params, this, "deleteWebConfigReply");
}
void NymeaConfiguration::deleteTunnelProxyServerConfiguration(const QString &id)
{
QVariantMap params;
params.insert("id", id);
m_client->sendCommand("Configuration.DeleteTunnelProxyServerConfiguration", params, this, "deleteTunnelProxyServerConfigReply");
}
void NymeaConfiguration::deleteMqttServerConfiguration(const QString &id)
{
QVariantMap params;
@ -268,23 +309,32 @@ void NymeaConfiguration::getConfigurationsResponse(int commandId, const QVariant
foreach (const QVariant &tcpServerVariant, params.value("tcpServerConfigurations").toList()) {
// qDebug() << "tcp server config:" << tcpServerVariant;
QVariantMap tcpConfigMap = tcpServerVariant.toMap();
ServerConfiguration *config = new ServerConfiguration(tcpConfigMap.value("id").toString(), QHostAddress(tcpConfigMap.value("address").toString()), tcpConfigMap.value("port").toInt(), tcpConfigMap.value("authenticationEnabled").toBool(), tcpConfigMap.value("sslEnabled").toBool());
ServerConfiguration *config = new ServerConfiguration(tcpConfigMap.value("id").toString(), tcpConfigMap.value("address").toString(), tcpConfigMap.value("port").toInt(), tcpConfigMap.value("authenticationEnabled").toBool(), tcpConfigMap.value("sslEnabled").toBool());
m_tcpServerConfigurations->addConfiguration(config);
}
webSocketServerConfigurations()->clear();
foreach (const QVariant &websocketServerVariant, params.value("webSocketServerConfigurations").toList()) {
QVariantMap websocketConfigMap = websocketServerVariant.toMap();
ServerConfiguration *config = new ServerConfiguration(websocketConfigMap.value("id").toString(), QHostAddress(websocketConfigMap.value("address").toString()), websocketConfigMap.value("port").toInt(), websocketConfigMap.value("authenticationEnabled").toBool(), websocketConfigMap.value("sslEnabled").toBool());
ServerConfiguration *config = new ServerConfiguration(websocketConfigMap.value("id").toString(), websocketConfigMap.value("address").toString(), websocketConfigMap.value("port").toInt(), websocketConfigMap.value("authenticationEnabled").toBool(), websocketConfigMap.value("sslEnabled").toBool());
m_webSocketServerConfigurations->addConfiguration(config);
}
webServerConfigurations()->clear();
foreach (const QVariant &webServerVariant, params.value("webServerConfigurations").toList()) {
QVariantMap webServerConfigMap = webServerVariant.toMap();
WebServerConfiguration* config = new WebServerConfiguration(webServerConfigMap.value("id").toString(), QHostAddress(webServerConfigMap.value("address").toString()), webServerConfigMap.value("port").toInt(), webServerConfigMap.value("authenticationEnabled").toBool(), webServerConfigMap.value("sslEnabled").toBool());
WebServerConfiguration* config = new WebServerConfiguration(webServerConfigMap.value("id").toString(), webServerConfigMap.value("address").toString(), webServerConfigMap.value("port").toInt(), webServerConfigMap.value("authenticationEnabled").toBool(), webServerConfigMap.value("sslEnabled").toBool());
config->setPublicFolder(webServerConfigMap.value("publicFolder").toString());
m_webServerConfigurations->addConfiguration(config);
}
foreach (const QVariant &tunnelProxyServerVariant, params.value("tunnelProxyServerConfigurations").toList()) {
QVariantMap tunnelProxyServerConfigMap = tunnelProxyServerVariant.toMap();
TunnelProxyServerConfiguration *config = new TunnelProxyServerConfiguration(tunnelProxyServerConfigMap.value("id").toString(), tunnelProxyServerConfigMap.value("address").toString(), tunnelProxyServerConfigMap.value("port").toInt(), tunnelProxyServerConfigMap.value("authenticationEnabled").toBool(), tunnelProxyServerConfigMap.value("sslEnabled").toBool(), tunnelProxyServerConfigMap.value("ignoreSslErrors").toBool());
m_tunnelProxyServerConfigurations->addConfiguration(config);
}
m_fetchingData = false;
emit fetchingDataChanged();
}
void NymeaConfiguration::setServerNameResponse(int commandId, const QVariantMap &params)
@ -342,13 +392,23 @@ void NymeaConfiguration::deleteWebSocketConfigReply(int commandId, const QVarian
qDebug() << "Delete web socket server config reply" << commandId << params;
}
void NymeaConfiguration::setTunnelProxyServerConfigReply(int commandId, const QVariantMap &params)
{
qDebug() << "Set tunnel proxy server config reply" << commandId << params;
}
void NymeaConfiguration::deleteTunnelProxyServerConfigReply(int commandId, const QVariantMap &params)
{
qDebug() << "Delete tunnel proxy server config reply" << commandId << params;
}
void NymeaConfiguration::getMqttServerConfigsReply(int commandId, const QVariantMap &params)
{
Q_UNUSED(commandId)
m_mqttServerConfigurations->clear();
foreach (const QVariant &mqttServerVariant, params.value("mqttServerConfigurations").toList()) {
QVariantMap mqttConfigMap = mqttServerVariant.toMap();
ServerConfiguration *config = new ServerConfiguration(mqttConfigMap.value("id").toString(), QHostAddress(mqttConfigMap.value("address").toString()), mqttConfigMap.value("port").toInt(), mqttConfigMap.value("authenticationEnabled").toBool(), mqttConfigMap.value("sslEnabled").toBool());
ServerConfiguration *config = new ServerConfiguration(mqttConfigMap.value("id").toString(), mqttConfigMap.value("address").toString(), mqttConfigMap.value("port").toInt(), mqttConfigMap.value("authenticationEnabled").toBool(), mqttConfigMap.value("sslEnabled").toBool());
m_mqttServerConfigurations->addConfiguration(config);
}
}
@ -393,6 +453,7 @@ void NymeaConfiguration::deleteMqttPolicyReply(int commandId, const QVariantMap
void NymeaConfiguration::notificationReceived(const QVariantMap &notification)
{
QString notif = notification.value("notification").toString();
qWarning() << "Config notification received" << notif;
if (notif == "Configuration.BasicConfigurationChanged") {
QVariantMap params = notification.value("params").toMap().value("basicConfiguration").toMap();
m_debugServerEnabled = params.value("debugServerEnabled").toBool();
@ -422,6 +483,10 @@ void NymeaConfiguration::notificationReceived(const QVariantMap &notification)
configModel = m_webSocketServerConfigurations;
params = notification.value("params").toMap().value("webSocketServerConfiguration").toMap();
}
if (notif == "Configuration.TunnelProxyServerConfigurationChanged") {
configModel = m_tunnelProxyServerConfigurations;
params = notification.value("params").toMap().value("tunnelProxyServerConfiguration").toMap();
}
if (notif == "Configuration.WebServerConfigurationChanged") {
configModel = m_webServerConfigurations;
params = notification.value("params").toMap().value("webServerConfiguration").toMap();
@ -444,6 +509,8 @@ void NymeaConfiguration::notificationReceived(const QVariantMap &notification)
if (!serverConfig) {
if (notif == "Configuration.WebServerConfigurationChanged") {
serverConfig = new WebServerConfiguration(params.value("id").toString());
} else if (notif == "Configuration.TunnelProxyServerConfigurationChanged") {
serverConfig = new TunnelProxyServerConfiguration(params.value("id").toString());
} else {
serverConfig = new ServerConfiguration(params.value("id").toString());
}
@ -467,6 +534,10 @@ void NymeaConfiguration::notificationReceived(const QVariantMap &notification)
m_webSocketServerConfigurations->removeConfiguration(notification.value("params").toMap().value("id").toString());
return;
}
if (notif == "Configuration.TunnelProxyServerConfigurationRemoved") {
m_tunnelProxyServerConfigurations->removeConfiguration(notification.value("params").toMap().value("id").toString());
return;
}
if (notif == "Configuration.WebServerConfigurationRemoved") {
m_webServerConfigurations->removeConfiguration(notification.value("params").toMap().value("id").toString());
return;

View File

@ -38,6 +38,8 @@ class ServerConfiguration;
class ServerConfigurations;
class WebServerConfiguration;
class WebServerConfigurations;
class TunnelProxyServerConfiguration;
class TunnelProxyServerConfigurations;
class MqttPolicy;
class MqttPolicies;
@ -45,6 +47,8 @@ class NymeaConfiguration : public QObject
{
Q_OBJECT
Q_PROPERTY(bool fetchingData READ fetchingData NOTIFY fetchingDataChanged)
Q_PROPERTY(QString serverName READ serverName WRITE setServerName NOTIFY serverNameChanged)
Q_PROPERTY(bool cloudEnabled READ cloudEnabled WRITE setCloudEnabled NOTIFY cloudEnabledChanged)
@ -53,6 +57,7 @@ class NymeaConfiguration : public QObject
Q_PROPERTY(ServerConfigurations* tcpServerConfigurations READ tcpServerConfigurations CONSTANT)
Q_PROPERTY(ServerConfigurations* webSocketServerConfigurations READ webSocketServerConfigurations CONSTANT)
Q_PROPERTY(WebServerConfigurations* webServerConfigurations READ webServerConfigurations CONSTANT)
Q_PROPERTY(TunnelProxyServerConfigurations* tunnelProxyServerConfigurations READ tunnelProxyServerConfigurations CONSTANT)
Q_PROPERTY(ServerConfigurations* mqttServerConfigurations READ mqttServerConfigurations CONSTANT)
Q_PROPERTY(MqttPolicies* mqttPolicies READ mqttPolicies CONSTANT)
@ -60,6 +65,8 @@ class NymeaConfiguration : public QObject
public:
explicit NymeaConfiguration(JsonRpcClient* client, QObject *parent = nullptr);
bool fetchingData() const;
QString serverName() const;
void setServerName(const QString &serverName);
@ -80,21 +87,25 @@ public:
ServerConfigurations *tcpServerConfigurations() const;
ServerConfigurations *webSocketServerConfigurations() const;
WebServerConfigurations *webServerConfigurations() const;
TunnelProxyServerConfigurations *tunnelProxyServerConfigurations() const;
ServerConfigurations *mqttServerConfigurations() const;
MqttPolicies *mqttPolicies() const;
Q_INVOKABLE ServerConfiguration* createServerConfiguration(const QString &address = "0.0.0.0", int port = 0, bool authEnabled = false, bool sslEnabled = false);
Q_INVOKABLE WebServerConfiguration* createWebServerConfiguration(const QString &address = "0.0.0.0", int port = 0, bool authEnabled = false, bool sslEnabled = false, const QString &publicFolder = QString());
Q_INVOKABLE TunnelProxyServerConfiguration* createTunnelProxyServerConfiguration(const QString &address, int port, bool authEnabled = true, bool sslEnabled = true, bool ignoreSslErrors = false);
Q_INVOKABLE MqttPolicy* createMqttPolicy() const;
Q_INVOKABLE void setTcpServerConfiguration(ServerConfiguration *configuration);
Q_INVOKABLE void setWebSocketServerConfiguration(ServerConfiguration *configuration);
Q_INVOKABLE void setWebServerConfiguration(WebServerConfiguration *configuration);
Q_INVOKABLE void setTunnelProxyServerConfiguration(TunnelProxyServerConfiguration *configuration);
Q_INVOKABLE void setMqttServerConfiguration(ServerConfiguration *configuration);
Q_INVOKABLE void deleteTcpServerConfiguration(const QString &id);
Q_INVOKABLE void deleteWebSocketServerConfiguration(const QString &id);
Q_INVOKABLE void deleteWebServerConfiguration(const QString &id);
Q_INVOKABLE void deleteTunnelProxyServerConfiguration(const QString &id);
Q_INVOKABLE void deleteMqttServerConfiguration(const QString &id);
Q_INVOKABLE void updateMqttPolicy(MqttPolicy* policy);
@ -112,6 +123,8 @@ private:
Q_INVOKABLE void deleteTcpConfigReply(int commandId, const QVariantMap &params);
Q_INVOKABLE void setWebSocketConfigReply(int commandId, const QVariantMap &params);
Q_INVOKABLE void deleteWebSocketConfigReply(int commandId, const QVariantMap &params);
Q_INVOKABLE void setTunnelProxyServerConfigReply(int commandId, const QVariantMap &params);
Q_INVOKABLE void deleteTunnelProxyServerConfigReply(int commandId, const QVariantMap &params);
Q_INVOKABLE void setWebConfigReply(int commandId, const QVariantMap &params);
Q_INVOKABLE void deleteWebConfigReply(int commandId, const QVariantMap &params);
Q_INVOKABLE void getMqttServerConfigsReply(int commandId, const QVariantMap &params);
@ -124,6 +137,7 @@ private:
Q_INVOKABLE void notificationReceived(const QVariantMap &notification);
signals:
void fetchingDataChanged();
void debugServerEnabledChanged();
void serverNameChanged();
void cloudEnabledChanged();
@ -131,6 +145,7 @@ signals:
private:
JsonRpcClient* m_client = nullptr;
bool m_fetchingData = false;
bool m_debugServerEnabled = false;
QString m_serverName;
bool m_cloudEnabled = false;
@ -138,6 +153,7 @@ private:
ServerConfigurations *m_tcpServerConfigurations = nullptr;
ServerConfigurations *m_webSocketServerConfigurations = nullptr;
WebServerConfigurations* m_webServerConfigurations = nullptr;
TunnelProxyServerConfigurations *m_tunnelProxyServerConfigurations = nullptr;
ServerConfigurations *m_mqttServerConfigurations = nullptr;
MqttPolicies *m_mqttPolicies = nullptr;

View File

@ -30,7 +30,7 @@
#include "serverconfiguration.h"
ServerConfiguration::ServerConfiguration(const QString &id, const QHostAddress &address, int port, bool authEnabled, bool sslEnabled, QObject *parent):
ServerConfiguration::ServerConfiguration(const QString &id, const QString &address, int port, bool authEnabled, bool sslEnabled, QObject *parent):
QObject(parent),
m_id(id),
m_hostAddress(address),
@ -48,13 +48,13 @@ QString ServerConfiguration::id() const
QString ServerConfiguration::address() const
{
return m_hostAddress.toString();
return m_hostAddress;
}
void ServerConfiguration::setAddress(const QString &address)
{
if (m_hostAddress != QHostAddress(address)) {
m_hostAddress = QHostAddress(address);
if (m_hostAddress != address) {
m_hostAddress = address;
emit addressChanged();
}
}
@ -119,7 +119,26 @@ void WebServerConfiguration::setPublicFolder(const QString &publicFolder)
ServerConfiguration *WebServerConfiguration::clone() const
{
WebServerConfiguration *ret = new WebServerConfiguration(id(), QHostAddress(address()), port(), authenticationEnabled(), sslEnabled());
WebServerConfiguration *ret = new WebServerConfiguration(id(), address(), port(), authenticationEnabled(), sslEnabled());
ret->setPublicFolder(m_publicFolder);
return ret;
}
bool TunnelProxyServerConfiguration::ignoreSslErrors() const
{
return m_ignoreSslErrors;
}
void TunnelProxyServerConfiguration::setIgnoreSslErrors(bool ignoreSslErrors)
{
if (m_ignoreSslErrors != ignoreSslErrors) {
m_ignoreSslErrors = ignoreSslErrors;
emit ignoreSslErrorsChanged();
}
}
ServerConfiguration *TunnelProxyServerConfiguration::clone() const
{
TunnelProxyServerConfiguration *ret = new TunnelProxyServerConfiguration(id(), address(), port(), authenticationEnabled(), ignoreSslErrors());
return ret;
}

View File

@ -45,7 +45,7 @@ class ServerConfiguration : public QObject
Q_PROPERTY(bool sslEnabled READ sslEnabled WRITE setSslEnabled NOTIFY sslEnabledChanged)
public:
explicit ServerConfiguration(const QString &id, const QHostAddress &address = QHostAddress(), int port = 0, bool authEnabled = false, bool sslEnabled = false, QObject *parent = nullptr);
explicit ServerConfiguration(const QString &id, const QString &address = QString(), int port = 0, bool authEnabled = false, bool sslEnabled = false, QObject *parent = nullptr);
QString id() const;
@ -71,7 +71,7 @@ signals:
private:
QString m_id;
QHostAddress m_hostAddress;
QString m_hostAddress;
int m_port;
bool m_authEnabled;
bool m_sslEnabled;
@ -82,7 +82,7 @@ class WebServerConfiguration: public ServerConfiguration
Q_OBJECT
Q_PROPERTY(QString publicFolder READ publicFolder WRITE setPublicFolder NOTIFY publicFolderChanged)
public:
explicit WebServerConfiguration(const QString &id, const QHostAddress &address = QHostAddress(), int port = 0, bool authEnabled = false, bool sslEnabled = false, QObject *parent = nullptr)
explicit WebServerConfiguration(const QString &id, const QString &address = QString(), int port = 0, bool authEnabled = false, bool sslEnabled = false, QObject *parent = nullptr)
: ServerConfiguration(id, address, port, authEnabled, sslEnabled, parent) {}
QString publicFolder() const;
@ -97,4 +97,25 @@ private:
QString m_publicFolder;
};
class TunnelProxyServerConfiguration: public ServerConfiguration
{
Q_OBJECT
Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors NOTIFY ignoreSslErrorsChanged)
public:
explicit TunnelProxyServerConfiguration(const QString &id, const QString &address = QString(), int port = 0, bool authenticationEnabled = false, bool sslEnabled = false, bool ignoreSslErrors = false, QObject *parent = nullptr)
: ServerConfiguration(id, address, port, authenticationEnabled, sslEnabled, parent),
m_ignoreSslErrors(ignoreSslErrors) {}
bool ignoreSslErrors() const;
void setIgnoreSslErrors(bool ignoreSslErrors);
Q_INVOKABLE ServerConfiguration* clone() const override;
signals:
void ignoreSslErrorsChanged();
private:
bool m_ignoreSslErrors = false;
};
#endif // SERVERCONFIGURATION_H

View File

@ -84,4 +84,15 @@ public:
}
};
class TunnelProxyServerConfigurations: public ServerConfigurations
{
Q_OBJECT
public:
TunnelProxyServerConfigurations(QObject *parent = nullptr): ServerConfigurations(parent) {}
Q_INVOKABLE TunnelProxyServerConfiguration* getTunnelProxyServerConfiguration(int index) const {
return dynamic_cast<TunnelProxyServerConfiguration*>(m_list.at(index));
}
};
#endif // SERVERCONFIGURATIONS_H

View File

@ -66,7 +66,7 @@ CloudTransport::CloudTransport(AWSClient *awsClient, QObject *parent):
QObject::connect(m_remoteproxyConnection, &RemoteProxyConnection::dataReady, this, [this](const QByteArray &data) {
emit dataReady(data);
});
QObject::connect(m_remoteproxyConnection, &RemoteProxyConnection::errorOccured, this, [] (QAbstractSocket::SocketError error) {
QObject::connect(m_remoteproxyConnection, &RemoteProxyConnection::errorOccurred, this, [] (QAbstractSocket::SocketError error) {
qDebug() << "Remote proxy Error:" << error;
// emit NymeaTransportInterface::error(QAbstractSocket::ConnectionRefusedError);
});

View File

@ -101,6 +101,21 @@ bool NymeaHost::online() const
return m_online;
}
void NymeaHost::addTunnelConnection()
{
for (int i = 0; i < m_connections->rowCount(); i++) {
if (m_connections->get(i)->url().scheme() == "tunnel") {
return;
}
}
QUrl url;
url.setScheme("tunnel");
url.setHost(m_uuid.toString().remove(QRegExp("[{}]")));
qCritical() << "Adding tunnel connection" << url << m_uuid;
Connection *connection = new Connection(url, Connection::BearerTypeCloud, true, "foooobaaaar", this);
m_connections->addConnection(connection);
}
void NymeaHost::syncOnlineState()
{
for (int i = 0; i < m_connections->rowCount(); i++) {
@ -217,7 +232,7 @@ Connection *Connections::bestMatch(Connection::BearerTypes bearerTypes) const
{
Connection *best = nullptr;
foreach (Connection *c, m_connections) {
// qDebug() << "have connection:" << bearerTypes << c->url() << c->bearerType() << bearerTypes.testFlag(c->bearerType());
// qWarning() << "have connection:" << bearerTypes << c->url() << c->bearerType() << bearerTypes.testFlag(c->bearerType());
if ((bearerTypes & c->bearerType()) == Connection::BearerTypeNone) {
continue;
}
@ -232,6 +247,12 @@ Connection *Connections::bestMatch(Connection::BearerTypes bearerTypes) const
return best;
}
void Connections::addConnection(const QUrl &url, Connection::BearerType bearerType, bool secure, const QString &displayName)
{
Connection *connection = new Connection(url, bearerType, secure, displayName);
addConnection(connection);
}
QHash<int, QByteArray> Connections::roleNames() const
{
QHash<int, QByteArray> roles;
@ -250,7 +271,7 @@ Connection::Connection(const QUrl &url, Connection::BearerType bearerType, bool
m_secure(secure),
m_displayName(displayName)
{
qRegisterMetaType<Connection::BearerType>("Connection.BearerType");
}
Connection::~Connection()
@ -320,6 +341,9 @@ int Connection::priority() const
break;
case BearerTypeCloud:
prio += 200;
if (m_url.scheme().startsWith("tunnel")) {
prio += 1;
}
break;
case BearerTypeBluetooth:
prio += 100;

View File

@ -109,14 +109,16 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
void addConnection(Connection *connection);
void removeConnection(Connection *connection);
void removeConnection(int index);
Q_INVOKABLE Connection* find(const QUrl &url) const;
Q_INVOKABLE Connection* get(int index) const;
Q_INVOKABLE Connection* bestMatch(Connection::BearerTypes bearerTypes = Connection::BearerTypeAll) const;
void addConnection(Connection *connection);
Q_INVOKABLE void addConnection(const QUrl &url, Connection::BearerType bearerType, bool secure, const QString &displayName);
Q_INVOKABLE void removeConnection(Connection *connection);
Q_INVOKABLE void removeConnection(int index);
signals:
void countChanged();
void connectionAdded(Connection *connection);
@ -156,6 +158,8 @@ public:
bool online() const;
Q_INVOKABLE void addTunnelConnection();
signals:
void nameChanged();
void versionChanged();

View File

@ -0,0 +1,151 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, 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 "tunnelproxytransport.h"
#include <QCoreApplication>
#include <QUrlQuery>
using namespace remoteproxyclient;
#include "logging.h"
// Note: Re-registering the same category as the proxy lib offers, so we can control it in the app
// However, as we can't link the same category twice, let's just create a dummy here with the category string matching the lib
NYMEA_LOGGING_CATEGORY(dcTunnelProxyRemoteConnectionDummy, "TunnelProxyRemoteConnection")
TunnelProxyTransport::TunnelProxyTransport(QObject *parent) :
NymeaTransportInterface(parent)
{
m_remoteConnection = new TunnelProxyRemoteConnection(QUuid::createUuid(), qApp->applicationName(), this);
QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::stateChanged, this, &TunnelProxyTransport::onRemoteConnectionStateChanged);
QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::dataReady, this, &TunnelProxyTransport::dataReady);
QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::errorOccurred, this, &TunnelProxyTransport::onRemoteConnectionErrorOccurred);
QObject::connect(m_remoteConnection, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
qWarning() << "Remote tunnel proxy server SSL errors occurred:";
foreach (const QSslError &sslError, errors) {
qWarning() << " --> " << sslError.errorString();
}
});
}
bool TunnelProxyTransport::connect(const QUrl &url)
{
m_url = url;
QUrl serverUrl;
serverUrl.setScheme(url.scheme() == "tunnels" ? "ssl" : "tcp");
serverUrl.setHost(url.host());
serverUrl.setPort(url.port());
QUuid serverUuid = QUrlQuery(url).queryItemValue("uuid");
qCritical() << "Calling connect on" << serverUrl << serverUuid;
return m_remoteConnection->connectServer(serverUrl, serverUuid);
}
QUrl TunnelProxyTransport::url() const
{
return m_url;
}
NymeaTransportInterface::ConnectionState TunnelProxyTransport::connectionState() const
{
switch (m_remoteConnection->state()) {
case TunnelProxyRemoteConnection::StateRemoteConnected:
return NymeaTransportInterface::ConnectionStateConnected;
case TunnelProxyRemoteConnection::StateConnecting:
case TunnelProxyRemoteConnection::StateHostLookup:
case TunnelProxyRemoteConnection::StateConnected:
case TunnelProxyRemoteConnection::StateInitializing:
case TunnelProxyRemoteConnection::StateRegister:
return NymeaTransportInterface::ConnectionStateConnecting;
case TunnelProxyRemoteConnection::StateDiconnecting:
case TunnelProxyRemoteConnection::StateDisconnected:
return NymeaTransportInterface::ConnectionStateDisconnected;
}
}
void TunnelProxyTransport::disconnect()
{
m_remoteConnection->disconnectServer();
}
void TunnelProxyTransport::sendData(const QByteArray &data)
{
m_remoteConnection->sendData(data);
}
void TunnelProxyTransport::ignoreSslErrors(const QList<QSslError> &errors)
{
// FIXME: once the tunnel connection implements SSL connection trought the tunnel proxy, we need to implement this
Q_UNUSED(errors)
}
bool TunnelProxyTransport::isEncrypted() const
{
return false;
}
QSslCertificate TunnelProxyTransport::serverCertificate() const
{
// FIXME: once the tunnel connection implements SSL connection trought the tunnel proxy, we need to implement this
return QSslCertificate();
}
void TunnelProxyTransport::onRemoteConnectionStateChanged(remoteproxyclient::TunnelProxyRemoteConnection::State state)
{
switch (state) {
case remoteproxyclient::TunnelProxyRemoteConnection::StateRemoteConnected:
emit connected();
break;
case remoteproxyclient::TunnelProxyRemoteConnection::StateDisconnected:
emit disconnected();
break;
default:
break;
}
}
void TunnelProxyTransport::onRemoteConnectionErrorOccurred(QAbstractSocket::SocketError error)
{
qWarning() << "Tunnel proxy socket error occurred" << error;
}
NymeaTransportInterface *TunnelProxyTransportFactory::createTransport(QObject *parent) const
{
return new TunnelProxyTransport(parent);
}
QStringList TunnelProxyTransportFactory::supportedSchemes() const
{
return { "tunnel", "tunnels" };
}

View File

@ -0,0 +1,74 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, 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 TUNNELPROXYTRANSPORT_H
#define TUNNELPROXYTRANSPORT_H
#include <QUrl>
#include <QObject>
#include "nymeatransportinterface.h"
#include "tunnelproxy/tunnelproxyremoteconnection.h"
class TunnelProxyTransportFactory: public NymeaTransportInterfaceFactory
{
public:
NymeaTransportInterface* createTransport(QObject *parent = nullptr) const override;
QStringList supportedSchemes() const override;
};
class TunnelProxyTransport : public NymeaTransportInterface
{
Q_OBJECT
public:
explicit TunnelProxyTransport(QObject *parent = nullptr);
bool connect(const QUrl &url) override;
QUrl url() const override;
ConnectionState connectionState() const override;
void disconnect() override;
void sendData(const QByteArray &data) override;
void ignoreSslErrors(const QList<QSslError> &errors) override;
bool isEncrypted() const override;
QSslCertificate serverCertificate() const override;
private slots:
void onRemoteConnectionStateChanged(remoteproxyclient::TunnelProxyRemoteConnection::State state);
void onRemoteConnectionErrorOccurred(QAbstractSocket::SocketError error);
private:
QUrl m_url;
remoteproxyclient::TunnelProxyRemoteConnection *m_remoteConnection = nullptr;
};
#endif // TUNNELPROXYTRANSPORT_H

View File

@ -37,6 +37,7 @@
#include "connection/websockettransport.h"
#include "connection/bluetoothtransport.h"
#include "connection/cloudtransport.h"
#include "connection/tunnelproxytransport.h"
#include <QJsonDocument>
#include <QVariantMap>
@ -61,6 +62,7 @@ JsonRpcClient::JsonRpcClient(QObject *parent) :
m_connection->registerTransport(new WebsocketTransportFactory());
m_connection->registerTransport(new BluetoothTransportFactoy());
m_connection->registerTransport(new CloudTransportFactory());
m_connection->registerTransport(new TunnelProxyTransportFactory());
connect(m_connection, &NymeaConnection::availableBearerTypesChanged, this, &JsonRpcClient::availableBearerTypesChanged);
connect(m_connection, &NymeaConnection::connectionStatusChanged, this, &JsonRpcClient::connectionStatusChanged);
@ -443,6 +445,7 @@ void JsonRpcClient::processAuthenticate(int /*commandId*/, const QVariantMap &da
} else {
m_permissionScopes = UserInfo::PermissionScopeAdmin;
}
emit permissionsChanged();
QSettings settings;
settings.beginGroup("jsonTokens");
settings.setValue(m_serverUuid, m_token);
@ -643,7 +646,7 @@ void JsonRpcClient::dataReceived(const QByteArray &data)
JsonRpcReply *reply = m_replies.take(commandId);
if (reply) {
reply->deleteLater();
qWarning() << QString("JsonRpc: got response for %1.%2: %3").arg(reply->nameSpace(), reply->method(), QString::fromUtf8(jsonDoc.toJson(QJsonDocument::Indented))) << reply->callback() << reply->callback();
// qWarning() << QString("JsonRpc: got response for %1.%2: %3").arg(reply->nameSpace(), reply->method(), QString::fromUtf8(jsonDoc.toJson(QJsonDocument::Indented))) << reply->callback() << reply->callback();
if (dataMap.value("status").toString() == "unauthorized") {
qWarning() << "Something's off with the token";
@ -718,6 +721,11 @@ void JsonRpcClient::helloReply(int /*commandId*/, const QVariantMap &params)
qCInfo(dcJsonRpc()) << "Handshake reply:" << "Protocol version:" << protoVersionString << "InitRequired:" << m_initialSetupRequired << "AuthRequired:" << m_authenticationRequired << "PushButtonAvailable:" << m_pushButtonAuthAvailable;
if (m_connection->currentHost()->uuid().isNull()) {
qCDebug(dcJsonRpc()) << "Updating Server UUID in connection:" << m_connection->currentHost()->uuid().toString() << "->" << m_serverUuid;
m_connection->currentHost()->setUuid(m_serverUuid);
}
QVersionNumber minimumRequiredVersion = QVersionNumber(5, 0);
QVersionNumber maximumMajorVersion = QVersionNumber(6);
if (m_jsonRpcVersion < minimumRequiredVersion) {
@ -793,11 +801,6 @@ void JsonRpcClient::helloReply(int /*commandId*/, const QVariantMap &params)
emit handshakeReceived();
if (m_connection->currentHost()->uuid().isNull()) {
qCDebug(dcJsonRpc()) << "Updating Server UUID in connection:" << m_connection->currentHost()->uuid().toString() << "->" << m_serverUuid;
m_connection->currentHost()->setUuid(m_serverUuid);
}
if (m_initialSetupRequired) {
qCInfo(dcJsonRpc()) << "Initial setup is required for this nymea instance!";
emit initialSetupRequiredChanged();

View File

@ -256,6 +256,8 @@ void registerQmlTypes() {
qmlRegisterUncreatableType<ServerConfigurations>(uri, 1, 0, "ServerConfigurations", "Get it from NymeaConfiguration");
qmlRegisterUncreatableType<WebServerConfiguration>(uri, 1, 0, "WebServerConfiguration", "Get it from NymeaConfiguration");
qmlRegisterUncreatableType<WebServerConfigurations>(uri, 1, 0, "WebServerConfigurations", "Get it from NymeaConfiguration");
qmlRegisterUncreatableType<TunnelProxyServerConfiguration>(uri, 1, 0, "TunnelProxyServerConfiguration", "Get it from NymeaConfiguration");
qmlRegisterUncreatableType<TunnelProxyServerConfigurations>(uri, 1, 0, "TunnelProxyServerConfigurations", "Get it from NymeaConfiguration");
qmlRegisterUncreatableType<MqttPolicy>(uri, 1, 0, "MqttPolicy", "Get it from NymeaConfiguration");
qmlRegisterUncreatableType<MqttPolicies>(uri, 1, 0, "MqttPolicies", "Get it from NymeaConfiguration");

View File

@ -25,6 +25,7 @@ SOURCES += \
$$PWD/energy/energymanager.cpp \
$$PWD/energy/powerbalancelogs.cpp \
$$PWD/energy/thingpowerlogs.cpp \
$$PWD/connection/tunnelproxytransport.cpp \
$$PWD/models/scriptsproxymodel.cpp \
$$PWD/tagwatcher.cpp \
$$PWD/zigbee/zigbeenode.cpp \
@ -185,6 +186,7 @@ HEADERS += \
$$PWD/energy/energymanager.h \
$$PWD/energy/powerbalancelogs.h \
$$PWD/energy/thingpowerlogs.h \
$$PWD/connection/tunnelproxytransport.h \
$$PWD/models/scriptsproxymodel.h \
$$PWD/tagwatcher.h \
$$PWD/zigbee/zigbeenode.h \

View File

@ -279,6 +279,10 @@ QVariant Users::data(const QModelIndex &index, int role) const
switch (role) {
case RoleUsername:
return m_users.at(index.row())->username();
case RoleDisplayName:
return m_users.at(index.row())->displayName();
case RoleEmail:
return m_users.at(index.row())->email();
case RoleScopes:
return static_cast<int>(m_users.at(index.row())->scopes());
}
@ -289,6 +293,8 @@ QHash<int, QByteArray> Users::roleNames() const
{
QHash<int, QByteArray> roles;
roles.insert(RoleUsername, "username");
roles.insert(RoleDisplayName, "displayName");
roles.insert(RoleEmail, "email");
roles.insert(RoleScopes, "scopes");
return roles;
}
@ -296,6 +302,18 @@ QHash<int, QByteArray> Users::roleNames() const
void Users::insertUser(UserInfo *userInfo)
{
userInfo->setParent(this);
connect(userInfo, &UserInfo::displayNameChanged, this, [=](){
int idx = m_users.indexOf(userInfo);
if (idx >= 0) {
emit dataChanged(index(idx), index(idx), {RoleDisplayName});
}
});
connect(userInfo, &UserInfo::emailChanged, this, [=](){
int idx = m_users.indexOf(userInfo);
if (idx >= 0) {
emit dataChanged(index(idx), index(idx), {RoleEmail});
}
});
connect(userInfo, &UserInfo::scopesChanged, this, [=](){
int idx = m_users.indexOf(userInfo);
if (idx >= 0) {

View File

@ -97,6 +97,8 @@ class Users: public QAbstractListModel {
public:
enum Roles {
RoleUsername,
RoleDisplayName,
RoleEmail,
RoleScopes
};
Q_ENUM(Roles)

View File

@ -21,23 +21,6 @@ ConfiguredHostsModel::ConfiguredHostsModel(QObject *parent) : QAbstractListModel
m_currentIndex = settings.value("currentIndex", 0).toInt();
settings.endGroup();
// If there aren't any in the config, try migrating settings from old tab model
if (m_list.isEmpty() && settings.contains("tabCount")) {
qCInfo(dcApplication()) << "Migrating tab settings to mainmenumodel";
int tabCount = settings.value("tabCount", 0).toInt();
qCDebug(dcApplication()) << "Tab count:" << tabCount;
for (int i = 0; i < tabCount; i++) {
settings.beginGroup(QString("tabSettings%1").arg(i));
QUuid uuid = settings.value("lastConnectedHost").toUuid();
ConfiguredHost *host = new ConfiguredHost(uuid, this);
addHost(host);
settings.endGroup();
}
settings.remove("tabCount");
}
// There must be always 1 at least
if (m_list.isEmpty()) {
createHost();

View File

@ -12,7 +12,6 @@
<file>ui/mainviews/FavoritesView.qml</file>
<file>ui/mainviews/ThingsView.qml</file>
<file>ui/connection/ConnectPage.qml</file>
<file>ui/connection/ManualConnectPage.qml</file>
<file>ui/connection/ConnectingPage.qml</file>
<file>ui/connection/wifisetup/BluetoothDiscoveryPage.qml</file>
<file>ui/connection/wifisetup/WirelessSetupPage.qml</file>
@ -274,5 +273,6 @@
<file>ui/components/NymeaToolTip.qml</file>
<file>ui/components/SettingsTile.qml</file>
<file>ui/components/NymeaTextField.qml</file>
<file>ui/system/TunnelProxyServerConfigurationDialog.qml</file>
</qresource>
</RCC>

View File

@ -721,7 +721,6 @@ Page {
text: qsTr("Disconnect")
Layout.preferredWidth: Math.max(cancelButton.implicitWidth, disconnectButton.implicitWidth)
onClicked: {
tabSettings.lastConnectedHost = "";
engine.jsonRpcClient.disconnectFromHost();
}
}

View File

@ -173,7 +173,6 @@ Item {
print("opening push button auth")
var page = pageStack.push(Qt.resolvedUrl("PushButtonAuthPage.qml"))
page.backPressed.connect(function() {
// tabSettings.lastConnectedHost = "";
engine.jsonRpcClient.disconnectFromHost();
init();
})
@ -182,7 +181,6 @@ Item {
if (engine.jsonRpcClient.initialSetupRequired) {
var page = pageStack.push(Qt.resolvedUrl("connection/SetupWizard.qml"));
page.backPressed.connect(function() {
// tabSettings.lastConnectedHost = "";
engine.jsonRpcClient.disconnectFromHost()
init();
})
@ -191,7 +189,6 @@ Item {
var page = pageStack.push(Qt.resolvedUrl("connection/LoginPage.qml"));
page.backPressed.connect(function() {
// tabSettings.lastConnectedHost = "";
engine.jsonRpcClient.disconnectFromHost()
init();
})
@ -314,7 +311,6 @@ Item {
if (engine.jsonRpcClient.connected) {
nymeaDiscovery.cacheHost(engine.jsonRpcClient.currentHost)
configuredHost.uuid = engine.jsonRpcClient.serverUuid
// tabSettings.lastConnectedHost = engine.jsonRpcClient.serverUuid
}
init();
}
@ -333,17 +329,47 @@ Item {
popup.actualVersion = actualVersion;
popup.minVersion = minVersion;
popup.open()
// tabSettings.lastConnectedHost = ""
}
onInvalidMaximumVersion: {
var popup = invalidVersionComponent.createObject(app.contentItem);
popup.actualVersion = actualVersion;
popup.maxVersion = maxVersion;
popup.open()
// tabSettings.lastConnectedHost = ""
}
}
Connections {
target: engine.nymeaConfiguration
onFetchingDataChanged: {
if (!engine.nymeaConfiguration.fetchingData) {
syncRemoteConnection()
}
}
}
Connections {
target: engine.nymeaConfiguration.tunnelProxyServerConfigurations
onCountChanged: syncRemoteConnection();
}
function syncRemoteConnection() {
for (var i = 0; i < engine.jsonRpcClient.currentHost.connections.count; i++) {
var connection = engine.jsonRpcClient.currentHost.connections.get(i)
if (connection.url.toString().startsWith("tunnel")) {
engine.jsonRpcClient.currentHost.connections.removeConnection(i--);
}
}
for (var i = 0; i < engine.nymeaConfiguration.tunnelProxyServerConfigurations.count; i++) {
var tunnelProxyConfig = engine.nymeaConfiguration.tunnelProxyServerConfigurations.get(i);
var url = tunnelProxyConfig.sslEnabled ? "tunnels://" : "tunnel://";
url += tunnelProxyConfig.address
url += ":" + tunnelProxyConfig.port
url += "?uuid=" + engine.jsonRpcClient.currentHost.uuid
engine.jsonRpcClient.currentHost.connections.addConnection(url, Connection.BearerTypeCloud, tunnelProxyConfig.sslEnabled, "Remote proxy connection");
}
nymeaDiscovery.cacheHost(engine.jsonRpcClient.currentHost)
}
Connections {
target: Qt.application
enabled: engine.jsonRpcClient.connected && settings.returnToHome

View File

@ -308,6 +308,12 @@ WizardPageBase {
} else {
rpcUrl = "ws://" + hostAddress + ":" + port
}
} else if (connectionTypeComboBox.currentIndex == 2) {
if (secureCheckBox.checked) {
rpcUrl = "tunnels://" + hostAddress + ":" + port + "?uuid=" + serverUuidTextInput.text
} else {
rpcUrl = "tunnel://" + hostAddress + ":" + port + "?uuid=" + serverUuidTextInput.text
}
}
print("Try to connect ", rpcUrl)
@ -331,28 +337,43 @@ WizardPageBase {
ComboBox {
id: connectionTypeComboBox
Layout.fillWidth: true
model: [ qsTr("TCP"), qsTr("Websocket") ]
model: [ qsTr("TCP"), qsTr("Websocket"), qsTr("Remote proxy") ]
}
Label { text: qsTr("Address:") }
Label {
text: connectionTypeComboBox.currentIndex < 2 ? qsTr("Address:") : qsTr("Proxy address:")
}
TextField {
id: addressTextInput
objectName: "addressTextInput"
Layout.fillWidth: true
placeholderText: "127.0.0.1"
placeholderText: connectionTypeComboBox.currentIndex < 2 ? "127.0.0.1" : "dev-remoteproxy.nymea.io"
}
Label {
text: qsTr("%1 UUID:").arg(Configuration.systemName)
visible: connectionTypeComboBox.currentIndex == 2
}
TextField {
id: serverUuidTextInput
Layout.fillWidth: true
visible: connectionTypeComboBox.currentIndex == 2
}
Label { text: qsTr("Port:") }
TextField {
id: portTextInput
Layout.fillWidth: true
placeholderText: connectionTypeComboBox.currentIndex === 0 ? "2222" : "4444"
placeholderText: connectionTypeComboBox.currentIndex === 0
? "2222"
: connectionTypeComboBox.currentIndex == 1
? "4444"
: "2213"
validator: IntValidator{bottom: 1; top: 65535;}
}
Label {
Layout.fillWidth: true
text: qsTr("Encrypted connection:")
text: qsTr("SSL:")
}
CheckBox {
id: secureCheckBox

View File

@ -136,4 +136,55 @@ SettingsPageBase {
popup.open()
}
}
SettingsPageSectionHeader {
text: qsTr("Remote connection server interfaces")
visible: engine.jsonRpcClient.ensureServerVersion("6.0")
}
Repeater {
model: engine.nymeaConfiguration.tunnelProxyServerConfigurations
delegate: ConnectionInterfaceDelegate {
Layout.fillWidth: true
text: qsTr("Server: %1").arg(model.address)
iconColor: inUse ? Style.accentColor : Style.iconColor
readonly property bool inUse: (engine.jsonRpcClient.currentConnection.hostAddress === model.address || model.address === "0.0.0.0")
&& engine.jsonRpcClient.currentConnection.port === model.port
canDelete: !inUse
onClicked: {
var component = Qt.createComponent(Qt.resolvedUrl("TunnelProxyServerConfigurationDialog.qml"));
var popup = component.createObject(root, { serverConfiguration: engine.nymeaConfiguration.tunnelProxyServerConfigurations.get(index).clone() });
popup.accepted.connect(function() {
print("configuring:", popup.serverConfiguration.port)
engine.nymeaConfiguration.setTunnelProxyServerConfiguration(popup.serverConfiguration)
popup.serverConfiguration.destroy();
})
popup.rejected.connect(function() {
popup.serverConfiguration.destroy();
})
popup.open()
}
onDeleteClicked: {
engine.nymeaConfiguration.deleteTunnelProxyServerConfiguration(model.id)
}
}
}
Button {
Layout.fillWidth: true
Layout.margins: app.margins
text: qsTr("Add")
visible: engine.jsonRpcClient.ensureServerVersion("6.0")
onClicked: {
var config = engine.nymeaConfiguration.createTunnelProxyServerConfiguration("dev-remoteproxy.nymea.io", 2213, true, true, false);
var component = Qt.createComponent(Qt.resolvedUrl("TunnelProxyServerConfigurationDialog.qml"));
var popup = component.createObject(root, { serverConfiguration: config });
popup.accepted.connect(function() {
engine.nymeaConfiguration.setTunnelProxyServerConfiguration(popup.serverConfiguration)
popup.serverConfiguration.destroy();
})
popup.rejected.connect(function() {
popup.serverConfiguration.destroy();
})
popup.open()
}
}
}

View File

@ -0,0 +1,114 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
import QtQuick 2.9
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
Dialog {
id: root
title: qsTr("Proxy server configuration")
width: parent.width * .8
x: (parent.width - width) / 2
y: (parent.height - height) / 2
property ServerConfiguration serverConfiguration: null
standardButtons: Dialog.Ok | Dialog.Cancel
ColumnLayout {
anchors { left: parent.left; top: parent.top; right: parent.right }
RowLayout {
Label {
text: qsTr("Proxy server address:")
Layout.fillWidth: true
}
TextField {
id: addressTextField
Layout.fillWidth: true
text: root.serverConfiguration ? root.serverConfiguration.address : ""
onEditingFinished: root.serverConfiguration.address = text
}
}
RowLayout {
Label {
text: qsTr("Port:")
Layout.fillWidth: true
}
TextField {
inputMethodHints: Qt.ImhDigitsOnly
text: root.serverConfiguration ? root.serverConfiguration.port : 0
validator: IntValidator { bottom: 0; top: 65535 }
onEditingFinished: root.serverConfiguration.port = text
}
}
RowLayout {
Label {
Layout.fillWidth: true
text: qsTr("Require login")
}
CheckBox {
checkState: root.serverConfiguration && root.serverConfiguration.authenticationEnabled ? Qt.Checked : Qt.Unchecked
onClicked: root.serverConfiguration.authenticationEnabled = checked
}
}
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: qsTr("Not requiring a login for the remote connection will allow anyone on the internet to connect to your %1 system.").arg(Configuration.systemName)
color: Style.red
visible: root.serverConfiguration && !root.serverConfiguration.authenticationEnabled
}
RowLayout {
Label {
Layout.fillWidth: true
text: qsTr("SSL enabled")
}
CheckBox {
checkState: root.serverConfiguration && root.serverConfiguration.sslEnabled ? Qt.Checked : Qt.Unchecked
onClicked: root.serverConfiguration.sslEnabled = checked
}
}
RowLayout {
Label {
Layout.fillWidth: true
text: qsTr("Ignore SSL errors")
}
CheckBox {
checkState: root.serverConfiguration && root.serverConfiguration.ignoreSslErrors ? Qt.Checked : Qt.Unchecked
onClicked: root.serverConfiguration.ignoreSslErrors = checked
}
}
}
}

View File

@ -278,7 +278,7 @@ SettingsPageBase {
model: userManager.users
delegate: NymeaItemDelegate {
Layout.fillWidth: true
text: engine.jsonRpcClient.ensureServerVersion("6.0") && model.displayName ? model.displayName : model.username
text: engine.jsonRpcClient.ensureServerVersion("6.0") && model.displayName !== "" ? model.displayName : model.username
subText: engine.jsonRpcClient.ensureServerVersion("6.0") && model.displayName ? model.username : ""
iconName: "/ui/images/account.svg"
iconColor: userManager.userInfo.scopes & UserInfo.PermissionScopeAdmin ? Style.accentColor : Style.iconColor

@ -1 +1 @@
Subproject commit 9c7075192b2b799feb302b48618eb4ef4d942172
Subproject commit 32c33ec23f975a457017b3eb7744a040bb4bd257