diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h index d1f95b8e..a7e2ec1f 100644 --- a/include/api/JsonAPI.h +++ b/include/api/JsonAPI.h @@ -37,6 +37,11 @@ public: /// void handleMessage(const QString & message, const QString& httpAuthHeader = ""); + /// + /// @brief Initialization steps + /// + void initialize(void); + public slots: /// /// @brief Is called whenever the current Hyperion instance pushes new led raw values (if enabled) @@ -117,6 +122,9 @@ private: /// Log instance Logger* _log; + /// Is this a local connection + bool _localConnection; + /// Hyperion instance manager HyperionIManager* _instanceManager; diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 8d4bbc9e..af364dc2 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -48,6 +48,7 @@ JsonAPI::JsonAPI(QString peerAddress, Logger* log, const bool& localConnection, , _noListener(noListener) , _peerAddress(peerAddress) , _log(log) + , _localConnection(localConnection) , _instanceManager(HyperionIManager::getInstance()) , _hyperion(nullptr) , _jsonCB(new JsonCB(this)) @@ -56,20 +57,22 @@ JsonAPI::JsonAPI(QString peerAddress, Logger* log, const bool& localConnection, , _ledStreamTimer(new QTimer(this)) { Q_INIT_RESOURCE(JSONRPC_schemas); +} +void JsonAPI::initialize(void) +{ // For security we block external connections if default PW is set - if(!localConnection && _authManager->hasHyperionDefaultPw()) + if(!_localConnection && _authManager->hasHyperionDefaultPw()) { emit forceClose(); } - // if this is localConnection and network allows unauth locals, set authorized flag - if(_apiAuthRequired && localConnection) + if(_apiAuthRequired && _localConnection) _authorized = !_authManager->isLocalAuthRequired(); // admin access is allowed, when the connection is local and the option for local admin isn't set. Con: All local connections get full access // authorization is also granted for api based on admin result. Pro: Admin should have full access. - if(localConnection) + if(_localConnection) { _userAuthorized = !_authManager->isLocalAdminAuthRequired(); _authorized = _userAuthorized; @@ -1646,6 +1649,9 @@ void JsonAPI::handleInstanceStateChange(const instanceState& state, const quint8 void JsonAPI::stopDataConnections(void) { LoggerManager::getInstance()->disconnect(); + _streaming_logging_activated = false; _jsonCB->resetSubscriptions(); + _imageStreamTimer->stop(); + _ledStreamTimer->stop(); } diff --git a/libsrc/jsonserver/JsonClientConnection.cpp b/libsrc/jsonserver/JsonClientConnection.cpp index 8ae4c372..959ec20a 100644 --- a/libsrc/jsonserver/JsonClientConnection.cpp +++ b/libsrc/jsonserver/JsonClientConnection.cpp @@ -17,7 +17,10 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket, const bool& local // create a new instance of JsonAPI _jsonAPI = new JsonAPI(socket->peerAddress().toString(), _log, localConnection, this); // get the callback messages from JsonAPI and send it to the client - connect(_jsonAPI,SIGNAL(callbackMessage(QJsonObject)),this,SLOT(sendMessage(QJsonObject))); + connect(_jsonAPI, &JsonAPI::callbackMessage, this , &JsonClientConnection::sendMessage); + connect(_jsonAPI, &JsonAPI::forceClose, this , [&](){ _socket->close(); } ); + + _jsonAPI->initialize(); } void JsonClientConnection::readRequest() diff --git a/libsrc/webserver/QtHttpClientWrapper.cpp b/libsrc/webserver/QtHttpClientWrapper.cpp index 41cf5403..de337078 100644 --- a/libsrc/webserver/QtHttpClientWrapper.cpp +++ b/libsrc/webserver/QtHttpClientWrapper.cpp @@ -300,8 +300,8 @@ void QtHttpClientWrapper::onReplySendDataRequested (void) void QtHttpClientWrapper::sendToClientWithReply(QtHttpReply * reply) { - connect (reply, &QtHttpReply::requestSendHeaders, this, &QtHttpClientWrapper::onReplySendHeadersRequested); - connect (reply, &QtHttpReply::requestSendData, this, &QtHttpClientWrapper::onReplySendDataRequested); + connect (reply, &QtHttpReply::requestSendHeaders, this, &QtHttpClientWrapper::onReplySendHeadersRequested, Qt::UniqueConnection); + connect (reply, &QtHttpReply::requestSendData, this, &QtHttpClientWrapper::onReplySendDataRequested, Qt::UniqueConnection); m_parsingStatus = sendReplyToClient (reply); } @@ -340,3 +340,19 @@ QtHttpClientWrapper::ParsingStatus QtHttpClientWrapper::sendReplyToClient (QtHtt return AwaitingRequest; } + +void QtHttpClientWrapper::closeConnection() +{ + // probably filter for request to follow http spec + if(m_currentRequest != Q_NULLPTR) + { + QtHttpReply reply(m_serverHandle); + reply.setStatusCode(QtHttpReply::StatusCode::Forbidden); + + connect (&reply, &QtHttpReply::requestSendHeaders, this, &QtHttpClientWrapper::onReplySendHeadersRequested, Qt::UniqueConnection); + connect (&reply, &QtHttpReply::requestSendData, this, &QtHttpClientWrapper::onReplySendDataRequested, Qt::UniqueConnection); + + m_parsingStatus = sendReplyToClient(&reply); + } + m_sockClient->close (); +} diff --git a/libsrc/webserver/QtHttpClientWrapper.h b/libsrc/webserver/QtHttpClientWrapper.h index e15797d0..5f3f31c6 100644 --- a/libsrc/webserver/QtHttpClientWrapper.h +++ b/libsrc/webserver/QtHttpClientWrapper.h @@ -34,6 +34,11 @@ public: /// @brief Wrapper for sendReplyToClient(), handles m_parsingStatus and signal connect void sendToClientWithReply (QtHttpReply * reply); + /// + /// @brief close a connection with FORBIDDEN header (used from JsonAPI over HTTP) + /// + void closeConnection(); + private slots: void onClientDataReceived (void); diff --git a/libsrc/webserver/WebJsonRpc.cpp b/libsrc/webserver/WebJsonRpc.cpp index 49c5932c..0b0c5d0d 100644 --- a/libsrc/webserver/WebJsonRpc.cpp +++ b/libsrc/webserver/WebJsonRpc.cpp @@ -15,14 +15,20 @@ WebJsonRpc::WebJsonRpc(QtHttpRequest* request, QtHttpServer* server, const bool& const QString client = request->getClientInfo().clientAddress.toString(); _jsonAPI = new JsonAPI(client, _log, localConnection, this, true); connect(_jsonAPI, &JsonAPI::callbackMessage, this, &WebJsonRpc::handleCallback); + connect(_jsonAPI, &JsonAPI::forceClose, [&]() { _wrapper->closeConnection(); _stopHandle = true; }); + _jsonAPI->initialize(); } void WebJsonRpc::handleMessage(QtHttpRequest* request) { - QByteArray header = request->getHeader("Authorization"); - QByteArray data = request->getRawData(); - _unlocked = true; - _jsonAPI->handleMessage(data,header); + // TODO better solution. If jsonAPI emits forceClose the request is deleted and the following call to this method results in segfault + if(!_stopHandle) + { + QByteArray header = request->getHeader("Authorization"); + QByteArray data = request->getRawData(); + _unlocked = true; + _jsonAPI->handleMessage(data,header); + } } void WebJsonRpc::handleCallback(QJsonObject obj) diff --git a/libsrc/webserver/WebJsonRpc.h b/libsrc/webserver/WebJsonRpc.h index 867c3bfa..a750817d 100644 --- a/libsrc/webserver/WebJsonRpc.h +++ b/libsrc/webserver/WebJsonRpc.h @@ -22,6 +22,7 @@ private: Logger* _log; JsonAPI* _jsonAPI; + bool _stopHandle = false; bool _unlocked = false; private slots: diff --git a/libsrc/webserver/WebSocketClient.cpp b/libsrc/webserver/WebSocketClient.cpp index a16ecf1e..0942a299 100644 --- a/libsrc/webserver/WebSocketClient.cpp +++ b/libsrc/webserver/WebSocketClient.cpp @@ -25,6 +25,7 @@ WebSocketClient::WebSocketClient(QtHttpRequest* request, QTcpSocket* sock, const // Json processor _jsonAPI = new JsonAPI(client, _log, localConnection, this); connect(_jsonAPI, &JsonAPI::callbackMessage, this, &WebSocketClient::sendMessage); + connect(_jsonAPI, &JsonAPI::forceClose, this,[this]() { this->sendClose(CLOSECODE::NORMAL); }); Debug(_log, "New connection from %s", QSTRING_CSTR(client)); @@ -40,6 +41,9 @@ WebSocketClient::WebSocketClient(QtHttpRequest* request, QTcpSocket* sock, const _socket->write(QSTRING_CSTR(data), data.size()); _socket->flush(); + + // Init JsonAPI + _jsonAPI->initialize(); } void WebSocketClient::handleWebSocketFrame(void) @@ -123,7 +127,7 @@ void WebSocketClient::handleWebSocketFrame(void) handleBinaryMessage(_wsReceiveBuffer); } _wsReceiveBuffer.clear(); - + } } break;