fix: image upload proxy, compression, and JSON parse safety
- Add /api/v1/ and /files/ rewrite rules in next.config.ts so frontend can call backend without /admin139 prefix - Fix upload using MultiPartParser instead of req->getUploadedFiles() - Add client-side image compression (canvas resize to 1920px, quality 0.8) for photos >500KB before upload - Safe JSON parsing: catch HTML error responses instead of throwing SyntaxError on non-JSON backend responses - Fix backslash escape in delete filename validation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
这个提交包含在:
@@ -12,7 +12,11 @@
|
||||
#include "csp/services/learning_note_scoring_service.h"
|
||||
#include "http_auth.h"
|
||||
|
||||
#include <drogon/MultiPart.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
@@ -363,7 +367,12 @@ void MeController::uploadWrongBookNoteImages(
|
||||
const auto user_id = RequireAuth(req, cb);
|
||||
if (!user_id.has_value()) return;
|
||||
|
||||
const auto files = req->getUploadedFiles();
|
||||
drogon::MultiPartParser parser;
|
||||
if (parser.parse(req) != 0) {
|
||||
cb(JsonError(drogon::k400BadRequest, "bad multipart"));
|
||||
return;
|
||||
}
|
||||
const auto& files = parser.getFiles();
|
||||
if (files.empty()) {
|
||||
cb(JsonError(drogon::k400BadRequest, "no files"));
|
||||
return;
|
||||
@@ -398,8 +407,12 @@ void MeController::uploadWrongBookNoteImages(
|
||||
for (const auto &f : files) {
|
||||
if ((int)arr.size() >= kMaxImages) break;
|
||||
|
||||
const auto ct_hdr = f.getFileType();
|
||||
if (ct_hdr.rfind("image/", 0) != 0) {
|
||||
// Allow common image extensions only (frontend also restricts accept=image/*)
|
||||
std::string name_for_ext = f.getFileName();
|
||||
auto dot = name_for_ext.find_last_of('.');
|
||||
std::string ext_check = (dot == std::string::npos) ? std::string("") : name_for_ext.substr(dot);
|
||||
for (auto &c : ext_check) c = (char)std::tolower((unsigned char)c);
|
||||
if (!(ext_check==".png" || ext_check==".jpg" || ext_check==".jpeg" || ext_check==".gif" || ext_check==".webp")) {
|
||||
continue;
|
||||
}
|
||||
if (f.fileLength() > 5 * 1024 * 1024) {
|
||||
@@ -456,7 +469,7 @@ void MeController::deleteWrongBookNoteImage(
|
||||
}
|
||||
|
||||
const std::string filename = (*json).get("filename", "").asString();
|
||||
if (filename.empty() || filename.find("..") != std::string::npos || filename.find('/') != std::string::npos || filename.find('\\\\') != std::string::npos) {
|
||||
if (filename.empty() || filename.find("..") != std::string::npos || filename.find('/') != std::string::npos || filename.find('\\') != std::string::npos) {
|
||||
cb(JsonError(drogon::k400BadRequest, "bad filename"));
|
||||
return;
|
||||
}
|
||||
|
||||
在新工单中引用
屏蔽一个用户