160 lines
5.0 KiB
JavaScript
160 lines
5.0 KiB
JavaScript
import {
|
|
createBlob,
|
|
createRepBlob,
|
|
uploadSingleFile
|
|
} from "../../../actions/azurestorage";
|
|
|
|
import nextConnect from "next-connect";
|
|
import middleware from "../middleware/middleware";
|
|
import { consoleLogger } from "../../../actions/core/logger";
|
|
import { hashAPIPath } from "../../../actions/core/hash";
|
|
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
|
import { fileTypeFromBuffer } from "file-type";
|
|
import fs from "fs";
|
|
import path from "path";
|
|
|
|
const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-:()—']+$/;
|
|
|
|
function validateFilenameServer(originalFilename) {
|
|
const name = path.basename(originalFilename || "");
|
|
|
|
if (!name) return { ok: false, reason: "Empty filename" };
|
|
|
|
if (name.includes("#")) return { ok: false, reason: "Filename contains #" };
|
|
|
|
if (/[<>"/\\|?*]/.test(name))
|
|
return { ok: false, reason: "Filename contains reserved characters" };
|
|
|
|
if (!FILENAME_ALLOWED.test(name))
|
|
return { ok: false, reason: "Filename contains invalid characters" };
|
|
|
|
if (name === "." || name === "..")
|
|
return { ok: false, reason: "Invalid filename" };
|
|
|
|
return { ok: true, name };
|
|
}
|
|
const ApiProxy = nextConnect();
|
|
ApiProxy.use(middleware);
|
|
|
|
ApiProxy.post(async (req, res) => {
|
|
var checkHash = req.query.hash;
|
|
|
|
if (typeof checkHash === "undefined" || checkHash.length === 0) {
|
|
return respondError(res, {
|
|
status: 400,
|
|
code: "HASH_REQUIRED",
|
|
message: "hash is required"
|
|
});
|
|
}
|
|
|
|
var checkquerypath = "/api/file/uploadsinglefile";
|
|
|
|
if (hashAPIPath(checkquerypath) != "?hash=" + checkHash) {
|
|
return respondError(res, {
|
|
status: 400,
|
|
code: "INVALID_HASH",
|
|
message: "Invalid hash"
|
|
});
|
|
}
|
|
|
|
const containerID = req.body?.containerID?.[0];
|
|
const casefolderID = req.body?.casefolderID?.[0];
|
|
|
|
if (
|
|
typeof containerID === "undefined" ||
|
|
containerID.length === 0 ||
|
|
typeof casefolderID === "undefined" ||
|
|
casefolderID.length === 0
|
|
) {
|
|
return respondError(res, {
|
|
status: 400,
|
|
code: "MISSING_REQUIRED_BODY",
|
|
message: "containerID and casefolderID are required"
|
|
});
|
|
}
|
|
|
|
const uploadedFiles = req.files || {};
|
|
|
|
// Add other mimetypes here
|
|
const allowedMimeTypes = [
|
|
"application/pdf",
|
|
"application/msword",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
"image/tiff",
|
|
"image/jpeg",
|
|
"application/zip",
|
|
"image/png",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
];
|
|
|
|
var allowedFilesFormData = {};
|
|
var invalidFiles = []; // To store the names of invalid files
|
|
|
|
for (const [fileName, fileDetails] of Object.entries(uploadedFiles)) {
|
|
const file = fileDetails[0];
|
|
const filePath = file.path;
|
|
|
|
// validate ORIGINAL filename from upload
|
|
const fnCheck = validateFilenameServer(file.originalFilename);
|
|
|
|
if (!fnCheck.ok) {
|
|
invalidFiles.push(`${file.originalFilename} - Invalid filename`);
|
|
continue; // do not process further
|
|
}
|
|
|
|
// Check the MIME type from file headers
|
|
const fileMimeType = file.headers["content-type"];
|
|
if (allowedMimeTypes.includes(fileMimeType)) {
|
|
// Check file signature (magic number) using file-type
|
|
const buffer = fs.readFileSync(filePath);
|
|
|
|
try {
|
|
const type = await fileTypeFromBuffer(buffer); // Correct usage of fileTypeFromBuffer
|
|
if (type && allowedMimeTypes.includes(type.mime)) {
|
|
// If the MIME type from the file signature matches the allowed list
|
|
allowedFilesFormData[fileName] = fileDetails.map(
|
|
(file) => ({
|
|
fieldName: file.fieldName,
|
|
originalFilename: file.originalFilename,
|
|
path: file.path,
|
|
size: file.size,
|
|
headers: file.headers,
|
|
contentType: fileMimeType
|
|
})
|
|
);
|
|
} else {
|
|
invalidFiles.push(fileName); // Track invalid file
|
|
}
|
|
} catch (error) {
|
|
consoleLogger(error);
|
|
}
|
|
} else {
|
|
invalidFiles.push(fileName); // Track invalid file
|
|
}
|
|
}
|
|
|
|
try {
|
|
const data = await uploadSingleFile(
|
|
allowedFilesFormData,
|
|
containerID,
|
|
casefolderID
|
|
);
|
|
return respondSuccess(res, { data, invalidFiles });
|
|
} catch (error) {
|
|
consoleLogger(error);
|
|
return respondError(res, {
|
|
status: 500,
|
|
code: "UPLOAD_SINGLE_FILE_FAILED",
|
|
message: "Failed to upload files"
|
|
});
|
|
}
|
|
});
|
|
|
|
export const config = {
|
|
api: {
|
|
bodyParser: false
|
|
}
|
|
};
|
|
|
|
export default ApiProxy;
|