DEV Community

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

Posted on

25 1 1

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.

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

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

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay