您可以使用 multer 软件包和内置的加密模块来上传文件并在存储到磁盘之前对其进行加密。然后可以通过 get 路由对其进行解密和读回。
文件将保存到 ./uploads,名称为 [originalfile]_encrypted.[ext]。
可以通过对 /file/:fileName 的 GET 请求来检索上传的文件。
我正在使用 AES-256-CBC 加密文件,但您可以选择任何您想要的算法。显然,您必须更改密钥和/或 iv 长度。
有一些改进可以使它成为更好的解决方案,例如确保加密的文件名是唯一的。
例如:
const express = require("express");
const port = 8080;
const app = express();
const bodyParser = require("body-parser");
const multer = require("multer");
const crypto = require("crypto");
const fs = require("fs");
const path = require("path");
const stream = require("stream");
const CryptoAlgorithm = "aes-256-cbc";
// Obviously keys should not be kept in code, these should be populated with environmental variables or key store
const secret = {
iv: Buffer.from('efb2da92cff888c9c295dc4ee682789c', 'hex'),
key: Buffer.from('6245cb9b8dab1c1630bb3283063f963574d612ca6ec60bc8a5d1e07ddd3f7c53', 'hex')
}
app.use(express.static("./public"));
app.use(bodyParser.json());
const storage = multer.memoryStorage()
const upload = multer({ storage });
function encrypt(algorithm, buffer, key, iv) {
const cipher = crypto.createCipheriv(algorithm, key, iv);
const encrypted = Buffer.concat([cipher.update(buffer),cipher.final()]);
return encrypted;
};
function decrypt(algorithm, buffer, key, iv) {
const decipher = crypto.createDecipheriv(algorithm, key, iv);
const decrypted = Buffer.concat([decipher.update(buffer), decipher.final()]);
return decrypted;
}
function getEncryptedFilePath(filePath) {
return path.join(path.dirname(filePath), path.basename(filePath, path.extname(filePath)) + "_encrypted" + path.extname(filePath))
}
function saveEncryptedFile(buffer, filePath, key, iv) {
const encrypted = encrypt(CryptoAlgorithm, buffer, key, iv);
filePath = getEncryptedFilePath(filePath);
if (!fs.existsSync(path.dirname(filePath))) {
fs.mkdirSync(path.dirname(filePath))
}
fs.writeFileSync(filePath, encrypted);
}
function getEncryptedFile(filePath, key, iv) {
filePath = getEncryptedFilePath(filePath);
const encrypted = fs.readFileSync(filePath);
const buffer = decrypt(CryptoAlgorithm, encrypted, key, iv);
return buffer;
}
app.post("/upload", upload.single("file"), (req, res, next) => {
console.log("file upload: ", req.file.originalname);
saveEncryptedFile(req.file.buffer, path.join("./uploads", req.file.originalname), secret.key, secret.iv);
res.status(201).json( { status: "ok" });
});
app.get("/file/:fileName", (req, res, next) => {
console.log("Getting file:", req.params.fileName);
const buffer = getEncryptedFile(path.join("./uploads", req.params.fileName), secret.key, secret.iv);
const readStream = new stream.PassThrough();
readStream.end(buffer);
res.writeHead(200, {
"Content-disposition": "attachment; filename=" + req.params.fileName,
"Content-Type": "application/octet-stream",
"Content-Length": buffer.length
});
res.end(buffer);
});
app.listen(port);
console.log(`Serving at http://localhost:${port}`);