typestack / class-validator

Decorator-based property validation for classes.
MIT License
11.07k stars 803 forks source link

feature: Add `IsFilename` to determine whether input field is a valid filename #1254

Open mnixry opened 3 years ago

mnixry commented 3 years ago

Description

In production practices, we may create a file upload form, which is possible contains filename. To validate if filename correct is a important step to avoid hacker attacks. (e.g. CVE-2021-21972 is caused by file upload without filename validation)

Proposed solution

Fortunately, sindresorhus/valid-filename has provided a simple solution, so current workaround is simple:

import { registerDecorator, ValidationOptions } from 'class-validator';
import isFilename from 'valid-filename';

export function IsFilename(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      name: 'isFilename',
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      validator: {
        validate(value: any) {
          return typeof value === 'string' && isFilename(value);
        },
      },
    });
  };
}
geekyayush commented 1 year ago

Thanks for this. Gonna use it in my project.

braaar commented 1 year ago

Is this a typical enough use case to warrant adding a dependency just for this validator? It's a tough call for me, personally. Would like to hear some more opinions about this. After all, it is pretty easy to implement this in a custom decorator if you do need it.

braaar commented 1 year ago

Perhaps we should have a library of useful custom validators somewhere. That would be a good home for this code. Like a readme file or something

mnixry commented 1 year ago

Is this a typical enough use case to warrant adding a dependency just for this validator? It's a tough call for me, personally. Would like to hear some more opinions about this. After all, it is pretty easy to implement this in a custom decorator if you do need it.

If we look through this package, the package are only have few lines of valid code, and it doesn't seems need to be frequently updated or maintained:

import filenameReservedRegex, {windowsReservedNameRegex} from 'filename-reserved-regex';

export default function isValidFilename(string) {
    if (!string || string.length > 255) {
        return false;
    }

    if (filenameReservedRegex().test(string) || windowsReservedNameRegex().test(string)) {
        return false;
    }

    if (string === '.' || string === '..') {
        return false;
    }

    return true;
}
/* eslint-disable no-control-regex */

export default function filenameReservedRegex() {
    return /[<>:"/\\|?*\u0000-\u001F]/g;
}

export function windowsReservedNameRegex() {
    return /^(con|prn|aux|nul|com\d|lpt\d)$/i;
}

I think it is acceptable if directly adopt these code into the repository (just same as IsEmail or IsFQDN etc.), without declaring the extra dependencies.