diff --git a/src/masonite/validation/Validator.py b/src/masonite/validation/Validator.py index 940bb8e3..c3de2284 100644 --- a/src/masonite/validation/Validator.py +++ b/src/masonite/validation/Validator.py @@ -759,10 +759,16 @@ def passes(self, attribute, key, dictionary): all_clear = False if self.special != 0: - special_chars = "[^A-Za-z0-9]" + # custom specials are just a string of characters + # and may contain regex meta chars. + # so we search for them differently if self.special_chars: - special_chars = f"[{self.special_chars}]" - if len(re.findall(special_chars, attribute)) < self.special: + special_count = sum(attribute.count(c) for c in self.special_chars) + else: + std_specials = "[^A-Za-z0-9]" + special_count = len(re.findall(std_specials, attribute)) + + if special_count < self.special: self.special_check = False all_clear = False diff --git a/tests/features/validation/test_validation.py b/tests/features/validation/test_validation.py index c43d5cf6..7737bab0 100644 --- a/tests/features/validation/test_validation.py +++ b/tests/features/validation/test_validation.py @@ -1677,14 +1677,26 @@ def test_strong(self): # test custom special characters validate = Validator().validate( { - "password": "secret&-", + "password": "$e]cret&-", }, - strong(["password"], length=5, uppercase=0, special=2, special_chars="*&^", numbers=0, lowercase=4), + strong( + ["password"], + length=5, + uppercase=0, + special=4, + special_chars="^$*&()[]", + numbers=0, + lowercase=4, + ), ) self.assertEqual( validate.all(), - {"password": ["The password field must contain at least 2 of these characters: '*&^'"]}, + { + "password": [ + "The password field must contain at least 4 of these characters: '^$*&()[]'" + ] + }, ) validate = Validator().validate(