|
@@ -2,10 +2,17 @@
|
|
|
#include "logger.h"
|
|
#include "logger.h"
|
|
|
#include <fstream>
|
|
#include <fstream>
|
|
|
#include <QJsonObject>
|
|
#include <QJsonObject>
|
|
|
|
|
+#include <QJsonArray>
|
|
|
#include <QJsonDocument>
|
|
#include <QJsonDocument>
|
|
|
#include <QDir>
|
|
#include <QDir>
|
|
|
|
|
+#include <QCryptographicHash>
|
|
|
|
|
+#include <QMessageAuthenticationCode>
|
|
|
#include "appcontext.h"
|
|
#include "appcontext.h"
|
|
|
|
|
|
|
|
|
|
+#define FILE_SERVER_VERSION "1.0.0"
|
|
|
|
|
+#define FILE_SERVER_PASSWD "HGwP42vt65AgQyJa"
|
|
|
|
|
+#define FILE_SERVER_SECRIT_KEY "7R1mo2T7XJTrSgSJHBzRZYSydWybDD46"
|
|
|
|
|
+
|
|
|
HttpServer::HttpServer(QObject *parent)
|
|
HttpServer::HttpServer(QObject *parent)
|
|
|
: QObject{parent}
|
|
: QObject{parent}
|
|
|
{
|
|
{
|
|
@@ -156,81 +163,156 @@ void HttpServer::run_hhttp_sever()
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// 画面配置文件更新接口
|
|
// 画面配置文件更新接口
|
|
|
- m_server.Post("/update/monitor", [&](const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader) {
|
|
|
|
|
|
|
+ m_server.Post("/", [&](const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader) {
|
|
|
|
|
+
|
|
|
|
|
+ std::cout << "Headers:\n";
|
|
|
|
|
+ for (const auto &header : req.headers) {
|
|
|
|
|
+ std::cout << header.first << ": " << header.second << "\n";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
QJsonDocument doc;
|
|
QJsonDocument doc;
|
|
|
- if (req.is_multipart_form_data()) {
|
|
|
|
|
- // NOTE: `content_reader` is blocking until every form data field is read
|
|
|
|
|
- // This approach allows streaming processing of large files
|
|
|
|
|
- std::vector<httplib::FormData> items;
|
|
|
|
|
- content_reader(
|
|
|
|
|
- [&](const httplib::FormData &item) {
|
|
|
|
|
- items.push_back(item);
|
|
|
|
|
- return true;
|
|
|
|
|
- },
|
|
|
|
|
- [&](const char *data, size_t data_length) {
|
|
|
|
|
- items.back().content.append(data, data_length);
|
|
|
|
|
- return true;
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- // Process the received items
|
|
|
|
|
- for (const auto& item : items) {
|
|
|
|
|
- if (item.filename.empty()) {
|
|
|
|
|
- // Text field
|
|
|
|
|
- // std::cout << "Field: " << item.name << " = " << item.content << std::endl;
|
|
|
|
|
|
|
|
|
|
- QJsonObject obj = {
|
|
|
|
|
- {"message", QString("File error")}
|
|
|
|
|
- };
|
|
|
|
|
- doc.setObject(obj);
|
|
|
|
|
-
|
|
|
|
|
- res.status = httplib::StatusCode::BadRequest_400;
|
|
|
|
|
- res.set_content(doc.toJson(QJsonDocument::Compact).data(), "application/json");
|
|
|
|
|
- } else {
|
|
|
|
|
- // File
|
|
|
|
|
- QString currentPath = QDir::currentPath();
|
|
|
|
|
- QString savePath = QString("%1/%2").arg(currentPath, "update");
|
|
|
|
|
|
|
+ // 检查请求头中是否存在 Access-Token
|
|
|
|
|
+ auto it = req.headers.find("Access-Token");
|
|
|
|
|
+ if (it != req.headers.end() && !it->second.empty()) {
|
|
|
|
|
+ QString token = QString::fromStdString(it->second);
|
|
|
|
|
+ auto x = token.split(".");
|
|
|
|
|
+ QString h = x.first();
|
|
|
|
|
+ QString s = x.last();
|
|
|
|
|
|
|
|
- QDir dir(savePath);
|
|
|
|
|
- if(!dir.exists()) {
|
|
|
|
|
- dir.mkpath(savePath);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ auto header = QJsonDocument::fromJson(QByteArray::fromBase64(h.toUtf8())).array();
|
|
|
|
|
+ auto timestamp = header[0].toString();
|
|
|
|
|
+ auto type = header[2].toString();
|
|
|
|
|
|
|
|
- QString filename = QString("%1/%2").arg(savePath, "monitor.xml");
|
|
|
|
|
- std::ofstream ofs(filename.toStdString(), std::ios::binary);
|
|
|
|
|
- if (!ofs) {
|
|
|
|
|
- LOG_ERROR("open file failed: {}", filename.toStdString());
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ QJsonArray signature;
|
|
|
|
|
+ signature.push_back(timestamp);
|
|
|
|
|
+ signature.push_back(FILE_SERVER_VERSION);
|
|
|
|
|
+ signature.push_back(type);
|
|
|
|
|
+ signature.push_back(FILE_SERVER_PASSWD);
|
|
|
|
|
+ doc.setArray(signature);
|
|
|
|
|
+
|
|
|
|
|
+ QByteArray byteArray;
|
|
|
|
|
+ byteArray.push_back(h.toUtf8());
|
|
|
|
|
+ byteArray.push_back(".");
|
|
|
|
|
+ byteArray.push_back(QMessageAuthenticationCode::hash(QString(doc.toJson(QJsonDocument::Compact)).toUtf8(), FILE_SERVER_SECRIT_KEY, QCryptographicHash::Sha256).toBase64());
|
|
|
|
|
+ QString sign = QString(byteArray);
|
|
|
|
|
+ LOG_DEBUG("Access-Token: {} {}", token.toStdString(), sign.toStdString());
|
|
|
|
|
|
|
|
- ofs.write(item.content.data(), item.content.size());
|
|
|
|
|
- ofs.close();
|
|
|
|
|
- LOG_INFO("monitor configure file successfully update");
|
|
|
|
|
- emit monitorConfigureUpdate(filename);
|
|
|
|
|
|
|
+ if(sign == token) {
|
|
|
|
|
+ if (req.is_multipart_form_data()) {
|
|
|
|
|
+ // NOTE: `content_reader` is blocking until every form data field is read
|
|
|
|
|
+ // This approach allows streaming processing of large files
|
|
|
|
|
+ std::vector<httplib::FormData> items;
|
|
|
|
|
+ content_reader(
|
|
|
|
|
+ [&](const httplib::FormData &item) {
|
|
|
|
|
+ items.push_back(item);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ },
|
|
|
|
|
+ [&](const char *data, size_t data_length) {
|
|
|
|
|
+ items.back().content.append(data, data_length);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Process the received items
|
|
|
|
|
+ for (const auto& item : items) {
|
|
|
|
|
+ if (item.filename.empty()) {
|
|
|
|
|
+ // Text field
|
|
|
|
|
+ QJsonObject obj = {
|
|
|
|
|
+ {"message", QString("File error")}
|
|
|
|
|
+ };
|
|
|
|
|
+ doc.setObject(obj);
|
|
|
|
|
+
|
|
|
|
|
+ res.status = httplib::StatusCode::BadRequest_400;
|
|
|
|
|
+ res.set_content(doc.toJson(QJsonDocument::Compact).data(), "application/json");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // File
|
|
|
|
|
+ QString currentPath = QDir::currentPath();
|
|
|
|
|
+ QString savePath;
|
|
|
|
|
+ QString filename;
|
|
|
|
|
+
|
|
|
|
|
+ if(type == "monitor") {
|
|
|
|
|
+ savePath = QString("%1/%2").arg(currentPath, "storage/upload/monitor");
|
|
|
|
|
+ filename = QString("%1/%2").arg(savePath, "monitor.xml");
|
|
|
|
|
+ } else if(type == "netparse") {
|
|
|
|
|
+ savePath = QString("%1/%2").arg(currentPath, "storage/upload/netparse");
|
|
|
|
|
+ } else if(type == "formula") {
|
|
|
|
|
+ savePath = QString("%1/%2").arg(currentPath, "storage/upload/formula");
|
|
|
|
|
+ } else if(type == "pluginadd" || type == "pluginupgrade") {
|
|
|
|
|
+ savePath = QString("%1/%2").arg(currentPath, "storage/upload/plugins");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ res.status = httplib::StatusCode::BadRequest_400;
|
|
|
|
|
+ res.set_content(R"({"message": "Invalid file type"})", "application/json");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ filename = QString("%1/%2").arg(savePath, QString::fromStdString(item.filename));
|
|
|
|
|
+
|
|
|
|
|
+ QDir dir(savePath);
|
|
|
|
|
+ if(!dir.exists()) {
|
|
|
|
|
+ dir.mkpath(savePath);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ std::ofstream ofs(filename.toStdString(), std::ios::binary);
|
|
|
|
|
+ if (!ofs) {
|
|
|
|
|
+ LOG_ERROR("open file failed: {}", filename.toStdString());
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ofs.write(item.content.data(), item.content.size());
|
|
|
|
|
+ ofs.close();
|
|
|
|
|
+
|
|
|
|
|
+ if(type == "monitor") {
|
|
|
|
|
+ LOG_INFO("monitor configure file successfully update");
|
|
|
|
|
+ emit monitorConfigureUpdate(filename);
|
|
|
|
|
+ } else if(type == "formula") {
|
|
|
|
|
+ LOG_INFO("formula configure file successfully update");
|
|
|
|
|
+ emit formulaConfigureUpdate(filename);
|
|
|
|
|
+ } else if(type == "netparse") {
|
|
|
|
|
+ LOG_INFO("netparse configure file successfully update");
|
|
|
|
|
+ emit netparseConfigureUpdate(filename);
|
|
|
|
|
+ } else if(type == "pluginadd") {
|
|
|
|
|
+ LOG_INFO("add plugin: {}", item.filename);
|
|
|
|
|
+ } else if(type == "pluginupgrade") {
|
|
|
|
|
+ auto pluginName = header[3].toString();
|
|
|
|
|
+ LOG_INFO("upgrade plugin: {}", pluginName.toStdString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ QJsonObject obj = {
|
|
|
|
|
+ {"message", QString("'File successfully upload")}
|
|
|
|
|
+ };
|
|
|
|
|
+ doc.setObject(obj);
|
|
|
|
|
+
|
|
|
|
|
+ res.status = httplib::StatusCode::OK_200;
|
|
|
|
|
+ res.set_content(doc.toJson(QJsonDocument::Compact).data(), "application/json");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // std::string body;
|
|
|
|
|
+ // content_reader([&](const char *data, size_t data_length) {
|
|
|
|
|
+ // body.append(data, data_length);
|
|
|
|
|
+ // return true;
|
|
|
|
|
+ // });
|
|
|
|
|
|
|
|
QJsonObject obj = {
|
|
QJsonObject obj = {
|
|
|
- {"message", QString("'File successfully update")}
|
|
|
|
|
|
|
+ {"message", QString("File error")}
|
|
|
};
|
|
};
|
|
|
doc.setObject(obj);
|
|
doc.setObject(obj);
|
|
|
|
|
|
|
|
- res.status = httplib::StatusCode::OK_200;
|
|
|
|
|
|
|
+ res.status = httplib::StatusCode::BadRequest_400;
|
|
|
res.set_content(doc.toJson(QJsonDocument::Compact).data(), "application/json");
|
|
res.set_content(doc.toJson(QJsonDocument::Compact).data(), "application/json");
|
|
|
}
|
|
}
|
|
|
|
|
+ } else {
|
|
|
|
|
+ res.status = httplib::StatusCode::BadRequest_400; // error token
|
|
|
|
|
+ res.set_content(R"({"message": "Invalid access token"})", "application/json");
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- // std::string body;
|
|
|
|
|
- // content_reader([&](const char *data, size_t data_length) {
|
|
|
|
|
- // body.append(data, data_length);
|
|
|
|
|
- // return true;
|
|
|
|
|
- // });
|
|
|
|
|
-
|
|
|
|
|
- QJsonObject obj = {
|
|
|
|
|
- {"message", QString("File error")}
|
|
|
|
|
- };
|
|
|
|
|
- doc.setObject(obj);
|
|
|
|
|
-
|
|
|
|
|
- res.status = httplib::StatusCode::BadRequest_400;
|
|
|
|
|
- res.set_content(doc.toJson(QJsonDocument::Compact).data(), "application/json");
|
|
|
|
|
|
|
+ LOG_DEBUG("No Access-Token found");
|
|
|
|
|
+ res.status = httplib::StatusCode::Unauthorized_401; // 未授权
|
|
|
|
|
+ res.set_content(R"({"message": "Access token missing"})", "application/json");
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // return;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
m_server.listen(m_addr, m_port);
|
|
m_server.listen(m_addr, m_port);
|