How do I validate a password using Joi to ensure that it contains 2 numbers, 2 special characters, 2 uppercase letters, and 2 lowercase letters?

50 views Asked by At

Is there a way to do this using Joi?

For example:

    Joi.string()
      .required()
      .min(8)
      .max(16)
      .pattern(/(?=(?:.*[a-z]){2,16}).+/)
      .pattern(/(?=(?:.*[A-Z]){2,16}).+/)
      .pattern(/(?=(?:.*[0-9]){2,16}).+/)
      .pattern(/(?=(?:.*[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]){2,16}).+/)
      .messages({
        'string.base': 'Username must be of type string',
        'string.regex': 'Username must contain at least two lower-case letters',
        'string.regex2': 'Username must contain at least two upper-case letters',
        'string.regex3': 'Username must contain at least two numbers',
        'string.regex4': 'Username must contain at least two special characters',
        'string.min': 'Username must be at least 8 characters long',
        'string.max': 'Username must be no more than 16 characters long',
        'string.empty': 'Username is a required field',
      }),
    })
  });

The only problem I seem to be running into is getting back a good error message for the regular expressions. What should the keys be for messages? I would also like to see all failed validations, not just the first one that fails? Is there a better approach to this?

1

There are 1 answers

0
mkelley33 On BEST ANSWER
const passwordSchema: ObjectSchema = Joi.object().keys({
  password: Joi.string()
    .min(8)
    .max(16)
    .pattern(/(?=(?:.*[a-z]){2,16}).+/, 'lowercase')
    .pattern(/(?=(?:.*[A-Z]){2,16}).+/, 'uppercase')
    .pattern(/(?=(?:.*[0-9]){2,16}).+/, 'number')
    .pattern(/(?=(?:.*[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]){2,16}).+/, 'special')
    .required()
    .error((errors) => {
      errors.forEach((err) => {
        switch (err.code) {
          case 'string.base':
          case 'string.empty':
          case 'any.required':
          default:
            err.message = defaultErrorMessage;
            break;
          case 'string.min':
            err.message = minLengthMessage;
            break;
          case 'string.max':
            err.message = maxLengthMessage;
            break;
          case 'string.pattern.name':
            switch (err.local.name) {
              case 'lowercase':
                err.message = 'must contain at least two lower-case letters';
                break;
              case 'uppercase':
                err.message = 'must contain at least two lower-case letters';
                break;
              case 'number':
                err.message = 'must contain at least two numbers';
                break;
              case 'special':
                err.message = 'must contain at least two special characters';
                break;
            }
            break;
        }
      });

      return errors;
    }),

Then to get all messages:

passwordSchema.validate(data, { abortEarly: false });