diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..63e9001 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8159baf..d2e2350 100644 --- a/pom.xml +++ b/pom.xml @@ -3,17 +3,56 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.2 + + + it.aboutbits spring-boot-toolbox BUILD-SNAPSHOT Utility library for Spring Boot projects. + jar 21 + + org.springframework.boot + spring-boot-starter-validation + + + + + org.projectlombok + lombok + true + + + + + + org.passay + passay + 1.6.5 + + + + + org.jetbrains + annotations + 24.1.0 + + + + org.springframework.boot + spring-boot-starter-test + diff --git a/src/main/java/it/aboutbits/springboot/toolbox/validation/enumeration/ValidEnum.java b/src/main/java/it/aboutbits/springboot/toolbox/validation/enumeration/ValidEnum.java new file mode 100644 index 0000000..3f53b46 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/validation/enumeration/ValidEnum.java @@ -0,0 +1,28 @@ +package it.aboutbits.springboot.toolbox.validation.enumeration; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Constraint(validatedBy = ValidEnumValidator.class) +@Target({FIELD, ANNOTATION_TYPE}) +@Retention(RUNTIME) +public @interface ValidEnum { + + String message() default "{shared.error.validation.invalidEnum}"; + + Class[] groups() default {}; + + Class[] payload() default {}; + + Class> enumClass(); + +} diff --git a/src/main/java/it/aboutbits/springboot/toolbox/validation/enumeration/ValidEnumValidator.java b/src/main/java/it/aboutbits/springboot/toolbox/validation/enumeration/ValidEnumValidator.java new file mode 100644 index 0000000..d90d53c --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/validation/enumeration/ValidEnumValidator.java @@ -0,0 +1,30 @@ +package it.aboutbits.springboot.toolbox.validation.enumeration; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +import java.util.HashSet; +import java.util.Set; + +public class ValidEnumValidator implements ConstraintValidator { + private Set enumValues; + + @Override + public void initialize(ValidEnum validEnum) { + var enumClass = validEnum.enumClass(); + + enumValues = new HashSet<>(); + for (Enum anEnum : enumClass.getEnumConstants()) { + enumValues.add(anEnum.name()); + } + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (value == null) { + return true; + } + + return enumValues.contains(value); + } +} diff --git a/src/main/java/it/aboutbits/springboot/toolbox/validation/password/ValidPassword.java b/src/main/java/it/aboutbits/springboot/toolbox/validation/password/ValidPassword.java new file mode 100644 index 0000000..f2097f4 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/validation/password/ValidPassword.java @@ -0,0 +1,26 @@ +package it.aboutbits.springboot.toolbox.validation.password; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Constraint(validatedBy = ValidPasswordValidator.class) +@Target({FIELD, ANNOTATION_TYPE}) +@Retention(RUNTIME) +public @interface ValidPassword { + String message() default "{shared.error.validation.invalidPassword}"; + + String lengthMessage() default "{shared.error.validation.invalidPassword.length}"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/src/main/java/it/aboutbits/springboot/toolbox/validation/password/ValidPasswordValidator.java b/src/main/java/it/aboutbits/springboot/toolbox/validation/password/ValidPasswordValidator.java new file mode 100644 index 0000000..1914a72 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/validation/password/ValidPasswordValidator.java @@ -0,0 +1,56 @@ +package it.aboutbits.springboot.toolbox.validation.password; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import org.passay.LengthRule; +import org.passay.PasswordData; +import org.passay.PasswordValidator; +import org.passay.RuleResultDetail; + +import java.util.List; + +public class ValidPasswordValidator implements ConstraintValidator { + private String message; + private String lengthMessage; + + @Override + public void initialize(ValidPassword constraintAnnotation) { + this.message = constraintAnnotation.message(); + this.lengthMessage = constraintAnnotation.lengthMessage(); + } + + @Override + public boolean isValid(String password, ConstraintValidatorContext context) { + if (password == null) { + return true; + } + + var validator = new PasswordValidator(List.of( + // at least 8 characters + new LengthRule(8, 50) + )); + + var result = validator.validate(new PasswordData(password)); + + if (!password.isBlank() && result.isValid()) { + return true; + } + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(getMessageTemplate(result.getDetails())) + .addConstraintViolation(); + + return false; + } + + private String getMessageTemplate(List ruleResultDetails) { + if (ruleResultDetails.isEmpty()) { + return message; + } + + return switch (ruleResultDetails.getFirst().getErrorCode()) { + case "TOO_SHORT" -> lengthMessage; + case "TOO_LONG" -> lengthMessage; + default -> message; + }; + } +}