DEV Community

Cover image for How to validate uploaded files in Node JS
Eric O Okiti
Eric O Okiti

Posted on

How to validate uploaded files in Node JS

In this note, we'll look at how we can handle file validation and compression in Node JS.
If you have a better way of handling validation or compression, please drop it in the comment section.
In most cases, files are parsed in a Node JS server using either Multer, busboy, or Formidable.
While the content used in this writeup uses Multer, it can easily apply to any system.

File validation
Files in Node JS are usually in JSON format. The format for files is one of the two shown below.

// If memory storage is used
{
  fieldname: 'image',
  originalname: 'image.png',
  encoding: '7bit',
  mimetype: 'image/png',
  buffer: <Buffer bytes>,
  size: 25471
}

// If the file is stored locally
{
  fieldname: 'image',
  originalname: 'Meta1.png',
  encoding: '7bit',
  mimetype: 'image/png',
  destination: 'uploads/',
  filename: 'ed84692635f46d86c4be044f4acca667',
  path: 'uploads/ed84692635f46d86c4be044f4acca667',
  size: 25471
}
Enter fullscreen mode Exit fullscreen mode

The fields we will use for validation are originalname, mimetype, and size fields.

Checking the file extension.

We will use a bitwise right shift operator coupled with some inbuilt JS functions to get the file extension.

const file_extension = image.originalname.slice(
    ((image.originalname.lastIndexOf('.') - 1) >>> 0) + 2
);
Enter fullscreen mode Exit fullscreen mode

The above method has proven to work for 98% of cases, including misspelt filenames, i.e. image.png.png, photo.jpeg.jeg.

Since we now have the file extension, we can check to see if it's valid.

// Array of allowed files
const array_of_allowed_files = ['png', 'jpeg', 'jpg', 'gif'];

// Get the extension of the uploaded file
const file_extension = image.originalname.slice(
    ((image.originalname.lastIndexOf('.') - 1) >>> 0) + 2
);

// Check if the uploaded file is allowed
if (!array_of_allowed_files.includes(file_extension)) {
  throw Error('Invalid file');
}
Enter fullscreen mode Exit fullscreen mode

Checking only the file extension is not practical since anyone can edit a file name and change the extension, i.e. I can easily change a file name from todo-list.docx to todo-list.png.

For this reason, we will also need to check the mimetype of the file to ensure it's an image. We will follow a similar approach in doing this.

const array_of_allowed_file_types = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
if (!array_of_allowed_file_types.includes(image.memetype)) {
  throw Error('Invalid file');
}
Enter fullscreen mode Exit fullscreen mode

combining the two checks, we'll have;

// Array of allowed files
const array_of_allowed_files = ['png', 'jpeg', 'jpg', 'gif'];
const array_of_allowed_file_types = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];

// Get the extension of the uploaded file
const file_extension = image.originalname.slice(
    ((image.originalname.lastIndexOf('.') - 1) >>> 0) + 2
);

// Check if the uploaded file is allowed
if (!array_of_allowed_files.includes(file_extension) || !array_of_allowed_file_types.includes(image.memetype)) {
  throw Error('Invalid file');
}
Enter fullscreen mode Exit fullscreen mode

Checking file size

To check the file size, we use the size field. The size is usually given in bytes, so we have to convert it to the desired format for our evaluation. In our case, we converted it to MB.

// Allowed file size in mb
const allowed_file_size = 2;
if ((image.size / (1024 * 1024)) > allowed_file_size) {                  
  throw Error('File too large');
}
Enter fullscreen mode Exit fullscreen mode

Putting the above validations together, a typical middleware in express to validate uploaded files will look like the code below

export const auth = (req, res, next) => {
    const image = req.file;
    // Array of allowed files
    const array_of_allowed_files = ['png', 'jpeg', 'jpg', 'gif'];
    const array_of_allowed_file_types = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
    // Allowed file size in mb
    const allowed_file_size = 2;
    // Get the extension of the uploaded file
    const file_extension = image.originalname.slice(
        ((image.originalname.lastIndexOf('.') - 1) >>> 0) + 2
    );

    // Check if the uploaded file is allowed
    if (!array_of_allowed_files.includes(file_extension) || !array_of_allowed_file_types.includes(image.memetype)) {
        throw Error('Invalid file');
    }

    if ((image.size / (1024 * 1024)) > allowed_file_size) {                  
       throw Error('File too large');
    }
    return next();
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

File validation is very important. Although this writeup made use of images, and a single file upload, it can easily be modified to work for other file types. Adding it inside a loop, it can validate an array of files as well.
The codes has been bundled up into an NPM package that can easily be integrated. follow the link to find it. Fileguard.

Top comments (3)

Collapse
 
pop_pongpat profile image
Popz

file siganature also should be checked

Collapse
 
swapnilsoni1999 profile image
Swapnil Soni

Link to some guide for that please

Collapse
 
simoneth profile image
Simon

perhaps file-type