diff --git a/3rdparty/libshv b/3rdparty/libshv index 834da05db..43c7fbb90 160000 --- a/3rdparty/libshv +++ b/3rdparty/libshv @@ -1 +1 @@ -Subproject commit 834da05db3c1fc199b6ad62a6d60c969a14d0f4a +Subproject commit 43c7fbb905d67d4b9d4034c0f72e91ac34090a60 diff --git a/3rdparty/necrolog b/3rdparty/necrolog index 87ed76143..428aa4038 160000 --- a/3rdparty/necrolog +++ b/3rdparty/necrolog @@ -1 +1 @@ -Subproject commit 87ed76143e10a5d07d881795eac11a1429a09012 +Subproject commit 428aa4038c472a5680079f0d2b464c3a6b828212 diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index dd1c4cc6c..0678de17a 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -128,8 +128,8 @@ add_executable(quickevent if(WITH_QE_SHVAPI) target_compile_definitions(quickevent PRIVATE WITH_QE_SHVAPI) target_sources(quickevent PRIVATE - plugins/Event/src/services/shvapi/client.cpp - plugins/Event/src/services/shvapi/clientwidget.cpp + plugins/Event/src/services/shvapi/shvclientservice.cpp plugins/Event/src/services/shvapi/shvclientservice.h + plugins/Event/src/services/shvapi/shvclientservicewidget.cpp plugins/Event/src/services/shvapi/shvclientservicewidget.h plugins/Event/src/services/shvapi/shvclientservicewidget.ui plugins/Event/src/services/shvapi/shvnode.cpp plugins/Event/src/services/shvapi/sqlapinode.cpp plugins/Event/src/services/shvapi/nodes.cpp diff --git a/quickevent/app/quickevent/plugins/Core/src/coreplugin.cpp b/quickevent/app/quickevent/plugins/Core/src/coreplugin.cpp index f75749c0d..785b20378 100644 --- a/quickevent/app/quickevent/plugins/Core/src/coreplugin.cpp +++ b/quickevent/app/quickevent/plugins/Core/src/coreplugin.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -44,6 +45,20 @@ const QString CorePlugin::SETTINGS_PREFIX_APPLICATION_LOCALE_LANGUAGE() return s; } +namespace { +qf::core::utils::Crypt s_crypt(qf::core::utils::Crypt::createGenerator(16808, 11, 2147483647)); +} + +QByteArray CorePlugin::encrypt(const QByteArray &data, int min_length) +{ + return s_crypt.encrypt(data, min_length); +} + +QByteArray CorePlugin::decrypt(const QByteArray &data) +{ + return s_crypt.decrypt(data); +} + void CorePlugin::onInstalled() { qff::MainWindow *fwk = qff::MainWindow::frameWork(); diff --git a/quickevent/app/quickevent/plugins/Core/src/coreplugin.h b/quickevent/app/quickevent/plugins/Core/src/coreplugin.h index fd5fea7d5..bf260dd48 100644 --- a/quickevent/app/quickevent/plugins/Core/src/coreplugin.h +++ b/quickevent/app/quickevent/plugins/Core/src/coreplugin.h @@ -23,6 +23,9 @@ class CorePlugin : public qf::qmlwidgets::framework::Plugin static const QString SETTINGS_PREFIX_APPLICATION_LOCALE_LANGUAGE(); + Q_REQUIRED_RESULT static QByteArray encrypt(const QByteArray &data, int min_length = 16); + Q_REQUIRED_RESULT static QByteArray decrypt(const QByteArray &data); + void onInstalled(); private: SettingsDialog *m_settingsDialog = nullptr; diff --git a/quickevent/app/quickevent/plugins/Event/src/connectionsettings.cpp b/quickevent/app/quickevent/plugins/Event/src/connectionsettings.cpp index 155bc8704..04d3ff9b5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/connectionsettings.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/connectionsettings.cpp @@ -1,6 +1,7 @@ #include "connectionsettings.h" -#include +#include + #include #include @@ -17,8 +18,6 @@ static const auto USER = QStringLiteral("user"); static const auto PASSWORD = QStringLiteral("password"); static const auto WORKING_DIR = QStringLiteral("workingDir"); static const auto EVENT_NAME = QStringLiteral("eventName"); - -qf::core::utils::Crypt s_crypt(qf::core::utils::Crypt::createGenerator(16808, 11, 2147483647)); } ConnectionSettings::ConnectionSettings(QObject *parent) @@ -55,7 +54,7 @@ void ConnectionSettings::setServerUser(const QString &s) void ConnectionSettings::setServerPassword(const QString &s) { - QByteArray ba = s_crypt.encrypt(s.toUtf8(), 32); + QByteArray ba = Core::CorePlugin::encrypt(s.toUtf8(), 32); setValue(EVENT + '/' + DATA_STORAGE + '/' + SQL_SERVER + '/' + PASSWORD, QString::fromLatin1(ba)); } @@ -95,7 +94,7 @@ QString ConnectionSettings::serverUser() QString ConnectionSettings::serverPassword() { QByteArray ba = value(EVENT + '/' + DATA_STORAGE + '/' + SQL_SERVER + '/' + PASSWORD).toString().toLatin1(); - return QString::fromUtf8(s_crypt.decrypt(ba)); + return QString::fromUtf8(Core::CorePlugin::decrypt(ba)); } QString ConnectionSettings::singleWorkingDir() diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 24539aff5..3a4a94749 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -5,12 +5,13 @@ #include "dbschema.h" #include "stagedocument.h" #include "stagewidget.h" +#include "../../Core/src/coreplugin.h" #include "../../Core/src/widgets/appstatusbar.h" #include "services/serviceswidget.h" #include "services/emmaclient.h" #ifdef WITH_QE_SHVAPI -#include "services/shvapi/client.h" +#include "services/shvapi/shvclientservice.h" #endif #include @@ -52,6 +53,7 @@ #include #include #include +#include #include @@ -378,7 +380,7 @@ void EventPlugin::onInstalled() services::Service::addService(emma_client); #ifdef WITH_QE_SHVAPI - auto shvapi_client = new services::shvapi::Client(this); + auto shvapi_client = new services::shvapi::ShvClientService(this); services::Service::addService(shvapi_client); #endif @@ -501,6 +503,25 @@ QString EventPlugin::classNameById(int class_id) return m_classNameCache.value(class_id); } +QString EventPlugin::shvApiEventId() const +{ + return eventName() + "-" + QString::number(m_eventConfig->importId()); +} + +QString EventPlugin::createShvApiKey() +{ + QString key; + QList cc; + for (auto i = 'a'; i <= 'z'; i++) { cc << i; } + for (auto i = 'A'; i <= 'Z'; i++) { cc << i; } + for (auto i = '0'; i <= '9'; i++) { cc << i; } + for (int i = 0; i < 16; i++) { + quint32 ix = QRandomGenerator::global()->generate() % cc.size(); + key += cc[ix]; + } + return key; +} + DbSchema *EventPlugin::dbSchema() { return new DbSchema(this); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index 7d1ccd634..0c5e3c9e6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -93,6 +93,9 @@ class EventPlugin : public qf::qmlwidgets::framework::Plugin Q_INVOKABLE QString classNameById(int class_id); + QString shvApiEventId() const; + static QString createShvApiKey(); + DbSchema* dbSchema(); static int dbVersion(); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/clientwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/clientwidget.cpp deleted file mode 100644 index a6aae94e6..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/clientwidget.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "clientwidget.h" -#include "ui_clientwidget.h" -#include "client.h" - -#include -#include -#include - -#include - -#include -using qf::qmlwidgets::framework::getPlugin; - -namespace Event::services::shvapi { - -ClientWidget::ClientWidget(QWidget *parent) - : Super(parent) - , ui(new Ui::ClientWidget) -{ - setPersistentSettingsId("ClientWidget"); - ui->setupUi(this); - - Client *svc = service(); - if(svc) { - ClientSettings ss = svc->settings(); - ui->shvUrl->setText(ss.shvConnectionUrl()); - } -} - -ClientWidget::~ClientWidget() -{ - delete ui; -} - -bool ClientWidget::acceptDialogDone(int result) -{ - if(result == QDialog::Accepted) { - if(!saveSettings()) { - return false; - } - } - return true; -} - -Client *ClientWidget::service() -{ - Client *svc = qobject_cast(Service::serviceByName(Client::serviceName())); - QF_ASSERT(svc, Client::serviceName() + " doesn't exist", return nullptr); - return svc; -} - -bool ClientWidget::saveSettings() -{ - Client *svc = service(); - if(svc) { - ClientSettings ss = svc->settings(); - ss.setShvConnectionUrl(ui->shvUrl->text()); - //svc->setApiKey(ui->edApiKey->text().trimmed()); - svc->setSettings(ss); - } - return true; -} - -} - diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/clientwidget.h b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/clientwidget.h deleted file mode 100644 index 027bbc130..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/clientwidget.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -namespace Event::services::shvapi { - -namespace Ui { -class ClientWidget; -} - -class Client; - -class ClientWidget : public qf::qmlwidgets::framework::DialogWidget -{ - Q_OBJECT - - using Super = qf::qmlwidgets::framework::DialogWidget; -public: - explicit ClientWidget(QWidget *parent = nullptr); - ~ClientWidget(); -private: - Client* service(); - bool saveSettings(); -private: - Ui::ClientWidget *ui; - bool acceptDialogDone(int result); -}; - -} - diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/clientwidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/clientwidget.ui deleted file mode 100644 index 252a4e115..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/clientwidget.ui +++ /dev/null @@ -1,34 +0,0 @@ - - - Event::services::shvapi::ClientWidget - - - - 0 - 0 - 298 - 97 - - - - SHV API service - - - - - - SHV URL - - - - - - - - - - shvUrl - - - - diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.cpp b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservice.cpp similarity index 69% rename from quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.cpp rename to quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservice.cpp index 688154cf3..7dca66c1c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservice.cpp @@ -1,5 +1,5 @@ -#include "client.h" -#include "clientwidget.h" +#include "shvclientservice.h" +#include "shvclientservicewidget.h" #include "nodes.h" #include "sqlapinode.h" @@ -43,8 +43,8 @@ using Runs::RunsPlugin; namespace Event::services::shvapi { -Client::Client(QObject *parent) - : Super(Client::serviceName(), parent) +ShvClientService::ShvClientService(QObject *parent) + : Super(ShvClientService::serviceName(), parent) , m_rpcConnection(nullptr) , m_rootNode(new shv::iotqt::node::ShvRootNode(this)) { @@ -66,20 +66,20 @@ Client::Client(QObject *parent) } }); - connect(event_plugin, &Event::EventPlugin::dbEventNotify, this, &Client::onDbEventNotify, Qt::QueuedConnection); - connect(m_rootNode, &shv::iotqt::node::ShvNode::sendRpcMessage, this, &Client::sendRpcMessage); + connect(event_plugin, &Event::EventPlugin::dbEventNotify, this, &ShvClientService::onDbEventNotify, Qt::QueuedConnection); + connect(m_rootNode, &shv::iotqt::node::ShvNode::sendRpcMessage, this, &ShvClientService::sendRpcMessage); } -QString Client::serviceName() +QString ShvClientService::serviceName() { return QStringLiteral("ShvApi"); } -void Client::run() { +void ShvClientService::run() { QF_SAFE_DELETE(m_rpcConnection); auto ss = settings(); m_rpcConnection = new DeviceConnection(this); - connect(m_rpcConnection, &DeviceConnection::rpcMessageReceived, this, &Client::onRpcMessageReceived); + connect(m_rpcConnection, &DeviceConnection::rpcMessageReceived, this, &ShvClientService::onRpcMessageReceived); connect(m_rpcConnection, &DeviceConnection::brokerConnectedChanged, this, [this](bool is_connected) { if (is_connected) { setStatus(Status::Running); @@ -91,24 +91,24 @@ void Client::run() { m_rpcConnection->setConnectionString(ss.shvConnectionUrl()); RpcValue::Map opts; RpcValue::Map device; - device["mountPoint"] = "test/QE"; + device["mountPoint"] = ss.eventPath().toStdString(); opts["device"] = device; m_rpcConnection->setConnectionOptions(opts); m_rpcConnection->open(); } -void Client::stop() { +void ShvClientService::stop() { QF_SAFE_DELETE(m_rpcConnection); Super::stop(); } -qf::qmlwidgets::framework::DialogWidget *Client::createDetailWidget() +qf::qmlwidgets::framework::DialogWidget *ShvClientService::createDetailWidget() { - auto *w = new ClientWidget(); + auto *w = new ShvClientServiceWidget(); return w; } -void Client::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) +void ShvClientService::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) { qfDebug() << "client RPC request:" << msg.toCpon(); if(msg.isSignal()) { @@ -116,27 +116,47 @@ void Client::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) } if(msg.isRequest()) { RpcRequest rq(msg); - m_rootNode->handleRpcRequest(rq); + auto api_key = settings().apiKey(); + auto user_id = rq.userId().asString(); + auto correct_user_id = QStringLiteral("api_key=%1").arg(api_key).toStdString(); + if (user_id == correct_user_id) { + RpcResponse resp = RpcResponse::forRequest(rq); + resp.setError(RpcResponse::Error("Invalid API key", RpcResponse::Error::MethodNotFound)); + m_rootNode->emitSendRpcMessage(resp); + } + else { + m_rootNode->handleRpcRequest(rq); + } + return; } - else if(msg.isResponse()) { + if(msg.isResponse()) { //shvInfo() << "==> NTF method:" << method.toString(); return; } } -void Client::sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) +void ShvClientService::sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) { if(m_rpcConnection && m_rpcConnection->isBrokerConnected()) { m_rpcConnection->sendRpcMessage(rpc_msg); } } -void Client::loadSettings() +void ShvClientService::loadSettings() { Super::loadSettings(); + auto ss = settings(); + auto *event_plugin = getPlugin(); + if (ss.eventPath().isEmpty()) { + ss.setEventPath("test/qe/" + event_plugin->shvApiEventId()); + } + if (ss.apiKey().isEmpty()) { + ss.setApiKey(event_plugin->createShvApiKey()); + } + m_settings = ss; } -void Client::onDbEventNotify(const QString &domain, int connection_id, const QVariant &data) +void ShvClientService::onDbEventNotify(const QString &domain, int connection_id, const QVariant &data) { if (status() != Status::Running) return; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.h b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservice.h similarity index 70% rename from quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.h rename to quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservice.h index 76564aefa..9cbd394c5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservice.h @@ -13,26 +13,28 @@ namespace Event::services::shvapi { class RootNode; -class ClientSettings : public ServiceSettings +class ShvClientServiceSettings : public ServiceSettings { using Super = ServiceSettings; QF_VARIANTMAP_FIELD(QString, s, setS, hvConnectionUrl) + QF_VARIANTMAP_FIELD(QString, e, setE, ventPath) + QF_VARIANTMAP_FIELD(QString, a, setA, piKey) public: - ClientSettings(const QVariantMap &o = QVariantMap()) : Super(o) {} + ShvClientServiceSettings(const QVariantMap &o = QVariantMap()) : Super(o) {} }; -class Client : public Service +class ShvClientService : public Service { Q_OBJECT using Super = Service; public: - Client(QObject *parent); + ShvClientService(QObject *parent); void run() override; void stop() override; - ClientSettings settings() const {return ClientSettings(m_settings);} + ShvClientServiceSettings settings() const {return ShvClientServiceSettings(m_settings);} static QString serviceName(); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservicewidget.cpp new file mode 100644 index 000000000..5172fc59b --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservicewidget.cpp @@ -0,0 +1,86 @@ +#include "shvclientservicewidget.h" +#include "ui_shvclientservicewidget.h" +#include "shvclientservice.h" + +#include +#include +#include + +#include +#include + +#include +using qf::qmlwidgets::framework::getPlugin; + +namespace Event::services::shvapi { + +ShvClientServiceWidget::ShvClientServiceWidget(QWidget *parent) + : Super(parent) + , ui(new Ui::ShvClientServiceWidget) +{ + setPersistentSettingsId("ShvClientServiceWidget"); + ui->setupUi(this); + + auto *svc = service(); + if(svc) { + auto ss = svc->settings(); + ui->shvUrl->setText(ss.shvConnectionUrl()); + ui->shvEventPath->setText(ss.eventPath()); + ui->shvApiKey->setText(ss.apiKey()); + } + updateQrCodeUrl(); + connect(ui->shvUrl, &QLineEdit::textChanged, this, &ShvClientServiceWidget::updateQrCodeUrl); + connect(ui->shvApiKey, &QLineEdit::textChanged, this, &ShvClientServiceWidget::updateQrCodeUrl); + connect(ui->shvEventPath, &QLineEdit::textChanged, this, &ShvClientServiceWidget::updateQrCodeUrl); +} + +ShvClientServiceWidget::~ShvClientServiceWidget() +{ + delete ui; +} + +bool ShvClientServiceWidget::acceptDialogDone(int result) +{ + if(result == QDialog::Accepted) { + if(!saveSettings()) { + return false; + } + } + return true; +} + +ShvClientService *ShvClientServiceWidget::service() +{ + ShvClientService *svc = qobject_cast(Service::serviceByName(ShvClientService::serviceName())); + QF_ASSERT(svc, ShvClientService::serviceName() + " doesn't exist", return nullptr); + return svc; +} + +bool ShvClientServiceWidget::saveSettings() +{ + auto *svc = service(); + if(svc) { + auto ss = svc->settings(); + ss.setShvConnectionUrl(ui->shvUrl->text()); + //svc->setApiKey(ui->edApiKey->text().trimmed()); + svc->setSettings(ss); + } + return true; +} + +void ShvClientServiceWidget::updateQrCodeUrl() +{ + QUrl url(ui->shvUrl->text()); + url.setPath("/" + ui->shvEventPath->text()); + auto query = QUrlQuery(url); + url.setQuery(QString()); + query.addQueryItem("api_key", ui->shvApiKey->text()); + url.setQuery(query); + bool b = url.isValid(); + auto es = url.errorString(); + auto s = url.toString(); + ui->qrCodeUrl->setText(s); +} + +} + diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservicewidget.h b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservicewidget.h new file mode 100644 index 000000000..e7d0808d5 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservicewidget.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +namespace Event::services::shvapi { + +namespace Ui { +class ShvClientServiceWidget; +} + +class ShvClientService; + +class ShvClientServiceWidget : public qf::qmlwidgets::framework::DialogWidget +{ + Q_OBJECT + + using Super = qf::qmlwidgets::framework::DialogWidget; +public: + explicit ShvClientServiceWidget(QWidget *parent = nullptr); + ~ShvClientServiceWidget(); +private: + ShvClientService* service(); + bool saveSettings(); + void updateQrCodeUrl(); +private: + Ui::ShvClientServiceWidget *ui; + bool acceptDialogDone(int result); +}; + +} + diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservicewidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservicewidget.ui new file mode 100644 index 000000000..016cd0389 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/shvclientservicewidget.ui @@ -0,0 +1,78 @@ + + + Event::services::shvapi::ShvClientServiceWidget + + + + 0 + 0 + 298 + 201 + + + + SHV API service + + + + + + SHV url + + + + + + + + + + API key + + + + + + + true + + + + + + + Event path + + + + + + + true + + + + + + + QR code url + + + + + + + true + + + + + + + shvUrl + shvEventPath + shvApiKey + + + +