how to block uploading gif images in multer? - node.js

This multer configuration lets me upload images with '.gif' format. How to solve this ? I want it to only upload png, jpg, jpeg
This is my code:
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/public/images')
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.getExtension(file.mimetype));
});
}
});
let upload = multer({
limits: {
fileSize: 1000000
},
fileFilter: function(req, file, cb) {
if(!file.originalname.match(/\.(jpg|jpeg|png)$/)){
return cb('File must be an image.');
}
cb(undefined, true);
},
storage: storage
});
Route:
app.post('/upload-ad', upload.any(), recaptcha.middleware.verify, (req, res)

If I test your code like below, I get the correct response, e.g. "File must be an image." if I try to upload a .gif file.
const request = require("request");
const fs = require("fs");
const options = {
method: "POST",
url: "http://localhost:3300/upload-ad",
headers: {
"Content-Type": "multipart/form-data"
},
formData : {
"image" : fs.createReadStream("./test.gif")
}
};
request(options, function (err, res, body) {
if(err) console.log(err);
console.log(body);
});
This works because we're setting the Content-Disposition field in this case. I suspect that what's happening to you is that maybe the client is not setting this header, or it was set incorrectly. For example if we changed a filename from "test.gif" to "test.jpg" this would upload successfully despite the fact it is actually a GIF image.
In my case the start of the upload looks like so:
----------------------------321622124424983663382061
Content-Disposition: form-data; name="image"; filename="test.gif"
Content-Type: image/gif
And everything works as it is supposed to.
I'd recommend maybe not trusting the filename field in the POST and actually check what the image really is by looking at the uploaded buffer.

Related

How To Send Files From One Nodejs Server To Another Nodejs Server using POST request and save into folder?

I want to send some image file from one Nodejs server to another Nodejs server. And how to get the file in second server? Also how to save into a folder in second server?
How to do that any suggestion?
First server
uploadImage(req, callback) {
var formData = new FormData();
var body = {
"file": req.file,
}
var options = {
'method': 'POST',
'url': config.db_layer_endpointUpload,
'headers': {
'api_key': config.db_layer_access_key,
'content-type': 'application/json'
},
body: JSON.stringify(body),
}
request(options, function (error, response) {
return callback(response.body);
})
}
Second server
app.post(
"/upload",
multerObj.single("file"),
(req, res) => {
console.log(req.body);
}
);
When console.log i am getting following result in Second server file
But Image is not saved in the asset folder. Multer and storage are fine. When i uploaded Image to Second server directly its working fine.
The first thing you need to do is create an API using node/Express.js and create store using multer:
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'uploads/');
},
// By default, multer removes file extensions so let's add them back
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() +
path.extname(file.originalname));
}
});
Build the image filter function:
const imageFilter = function(req, file, cb) {
// Accept images only
if (!file.originalname.match(/\.(jpg|JPG|jpeg|JPEG|png|PNG|gif|GIF)$/)) {
req.fileValidationError = 'Only image files are allowed!';
return cb(new Error('Only image files are allowed!'), false);
}
cb(null, true);
};
exports.imageFilter = imageFilter;
Create an API to handle image get from request:
app.post('/upload-pic', (req, res) => {
let upload = multer({ storage: storage, fileFilter: helpers.imageFilter }).single('pic');
upload(req, res, function(err) {
// req.file contains information of uploaded file
// req.body contains information of text fields, if there were any
if (req.fileValidationError) {
return res.send(req.fileValidationError);
}
else if (!req.file) {
return res.send('Please select an image to upload');
}
else if (err instanceof multer.MulterError) {
return res.send(err);
}
else if (err) {
return res.send(err);
}
// Display uploaded image for user validation
res.send(`You have uploaded this image`);
});
});
Now you have the server side accept the image from request and save it on file. After that, let us go back to the other server. On other server it's like a client and we need create request to the API upload-pic . To do that you can use axios package and form-data package.
Handling File Uploads

How to receive req.file from request form-data in node

I have two apis, I want to send a file from the first api using request and formData.
How to receive req.file from request form-data ?
Receive side code
var storage = multer.diskStorage({
destination: function (req, file, cb) {
mkdirp(configServer.dataDir+ "/tmp", function(err){
cb(null, configServer.dataDir+ "/tmp/")
})
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage }).single('file');
exports.upload_in_server = function (req, res) {
upload(req, res, function (err) {
console.log("file : ", req.file)
console.log("body : ", req.body)
res.json({success: true})
})
}
router.post("/myurl/uploadInServer", UserController.upload_in_server);
Send side code
var storage2 = multer.diskStorage({
destination: function (req, file, cb) {
mkdirp(config.dataDir+ "/tmp", function(err){
cb(null, config.dataDir+ "/tmp/")
})
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload2 = multer({ storage: storage2 }).single('file');
exports.user_coffre_fort_create_file2 = function (req, res) {
upload2(req, res, function (err) {
var obj = {
'Nom': "Lagaf",
'Prénom': "Vincent",
'Date de naissance': "13/01/1960",
'file':new Buffer(fs.readFileSync(req.file.path)).toString("base64")
}
request({
url: "/myurl/uploadInServer",
method: 'POST',
formData: obj,
headers: {"Content-Type": "application/x-www-form-urlencoded", "Authorization": token}
}, function (err, stdout, body) {
res.json({success:true})
})
})
}
This is what I receive
the req.file is null, and i received the file in the body
How to recevie the file in the req.file ?
Thanks in advance
file : undefined
body : {
'Nom: 'Lagaf',
'Prénom': 'Vincent',
'Date de naissance': '13/01/1960',
file:/9j/4gIcSUNDX1BST0ZJTEUAAQEAAAIMbGNtcwIQAABtbnRyUkdCIFhZWiAH3AABABkAA
You need to use multipart/form-data as content type for uploading files and form feature from requests module. Take a look at this answer.

not able to upload file using multer

I have seen many answers on this and tried almost all of it but none seems to work for me. I can print the form data as ascii chars but I don't see the file stored in the public/uploads folder as expected. I can read and render stored files on react app using API but can't upload it. I get no errors, everything works fine but no file is uploaded in the folder. I'm trying to upload a file using multer and below are the code snippets :
routes/uploads.js
var storage = multer.diskStorage({
dest : function (req, file, cb) {
cb(null, path.join(__dirname, 'public/uploads/'))
}
});
var upload = multer({storage:storage}) ;
router.post('/upload', upload.single('mypic'), function (req, res, next) {
console.log("inside upload files");
console.log(req.body); //prints non-readable characters as I am uploading image as expected
console.log(req.file); //says undefined
return res.status(204).end();
});
API.js (React side):
export const uploadFile = (payload) => //payload is actually formdata
fetch(`${api}/files/upload`,
{
method: 'POST',
//headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: payload
}
)
.then(res => {
console.log(res);
return res.status;
})
.catch(error => {
console.log(error);
return error;
});
Try below IT contains multiple parts:
var storage = multer.diskStorage({
destination: function (req, file, cb) {
const extension = file.mimetype.split('/')[1];
//you can change destination runtime
if(file.fieldname == "covers[]")
{
cb(null, __dirname, '../public/uploads/cover');
return;
}
else
{
cb(null, '../public/uploads/image');
return;
}
},
filename: function (req, file, cb) {
//you can also change name
cb(null, filename)
}
});
var upload = multer({
storage: storage,
});
Try removing :
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'

Format issue while uploading Jpg file with NodeJS Multer module

I'm using Multer to upload jpg file from Postman to a node.js back-end.
I assume the "upload" goes well because the image is located at the right place with the right name and the right size after the POST request
Unfortunately, when I try to open the image file it doesn't open as a jpg image even though the extension is .jpg
I used checkFileType website and apparently, the file type becomes application/octet-stream after the upload.
I didn't specify any headers in the request.
Here is my Postman setup
Here is the response
Here is the code in the Node API side
var localWorkLocation = '/Users/noste/CarFixer/Pictures/';
exports.createBinary = function (req, res) {
var location = localWorkLocation + req.params.platenumber;
var storageOptions = multer.diskStorage({
destination: function (req, file, callback) {
mkdirp(location, err => callback(err, location));
callback(null, location);
},
filename: function (req, file, callback) {
//if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) {
// return callback(new Error('Only image files are allowed!'), false);
//}
callback(null, file.originalname);
},
});
var upload = multer({storage : storageOptions}).single('picture');
upload(req, res, function(err){
console.log(req.file);
if(err) {
return res.end(err.message);
}
res.send(req.file);
});
};
I've tried to upload a .txt file and it's still readable after upload.
Is there a place where I need to specify that I want to keep the jpg format ?
here's the storage configuration u need .. change the naming according to your code
var path = require('path');
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './uploads');
},
filename: function(req, file, callback) {
var fname = file.fieldname + '-' + Date.now() + path.extname(file.originalname);
callback(null, fname);
}
});
And here's another answer for multiple files upload

Transform upload with NodeJS Multer

I'm currently implementing a file/image upload service for my users. I want to transform these images (resize/optimize) before uploading to my s3 bucket.
What I'm currently doing: Using a multipart form on my frontend (I think the actual implementation doesn't matter here..) and the multer and multer-s3 packages on my backend.
Here my implementation stripped down to the important parts.
// SETUP
var multer = require('multer');
var s3 = require('multer-s3');
var storage = s3({
dirname: 'user/uploads',
bucket: auth.aws.s3.bucket,
secretAccessKey: auth.aws.s3.secretAccessKey,
accessKeyId: auth.aws.s3.accessKeyId,
region: auth.aws.s3.region,
filename: function (req, file, cb) {
cb(null, Date.now());
}
});
var upload = multer({storage: storage}).single('img');
// ROUTE
module.exports = Router()
.post('/', function (req, res, next) {
upload(req, res, function (err) {
if (err) {
return res.status(401).json({err: '...'});
}
return res.json({err:null,url: '..'});
});
});
What I want to do: transform the image before uploading it. I'm not sure if I need to use multer/busboy here or I can just do it with NodeJS (thus I've tagged NodeJS and express as well).
So my question is: where can I intercept the upload and transform it before uploading it to my S3 bucket?
Not sure if you're still looking for an answer to this, but I had the same problem. I decided to extend the multer-s3 package.
I've opened a pull request to the original repository, but for now, you can use my fork.
Here's an example of how to use the extended version:
var upload = multer({
storage: multerS3({
s3: s3,
bucket: 'some-bucket',
shouldTransform: function (req, file, cb) {
cb(null, /^image/i.test(file.mimetype))
},
transforms: [{
id: 'original',
key: function (req, file, cb) {
cb(null, 'image-original.jpg')
},
transform: function (req, file, cb) {
cb(null, sharp().jpg())
}
}, {
id: 'thumbnail',
key: function (req, file, cb) {
cb(null, 'image-thumbnail.jpg')
},
transform: function (req, file, cb) {
cb(null, sharp().resize(100, 100).jpg())
}
}]
})
})
EDIT: My fork is also now available via npm under the name multer-s3-transform.
I've tried using #ItsGreg's fork, but couldn't get it to work. I managed to get this behaviour working by using multer-s3 standard configuration, and inside my file upload endpoint, i.e.,
app.post('/files/upload', upload.single('file'), (req, res) => {...})
I am retrieving the file using request, and passing the Buffer to sharp. The following works (and assumes you are using ~/.aws/credentials):
let request = require('request').defaults({ encoding: null });
let dataURI = `https://s3.amazonaws.com/${process.env.AWS_S3_BUCKET}/${image.defaultUrl}`;
request.get(dataURI, function (error, response, body) {
if (! error && response.statusCode === 200) {
let buffer = new Buffer(body);
const sizes = ['thumbnail', 'medium', 'large'];
sizes.forEach(size => {
sharp(buffer)
.resize(image.sizes[size])
.toBuffer()
.then(data => {
// Upload the resized image Buffer to AWS S3.
let params = {
Body: data,
Bucket: process.env.AWS_S3_BUCKET,
Key: `${image.filePath}${image.names[size]}`,
ServerSideEncryption: "AES256",
};
s3.putObject(params, (err, data) => {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
})
})
}
});

Resources