Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>xom</groupId>
<artifactId>xom</artifactId>
Expand Down Expand Up @@ -398,6 +403,19 @@
<version>${version.jmh}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.5.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>

Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing empty line at the end of the file should be removed for consistency with Java formatting conventions.

Suggested change

Copilot uses AI. Check for mistakes.
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.owasp.esapi.reference.validation.annotations;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;


@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Constraint(validatedBy = ValidCreditCardValidator.class)
@Documented
public @interface ValidCreditCard {

String message() default "";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

String context();

boolean allowNull();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.owasp.esapi.reference.validation.annotations;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.owasp.esapi.ValidationErrorList;
import org.owasp.esapi.ESAPI;


public class ValidCreditCardValidator implements ConstraintValidator<ValidCreditCard, String>{

private String context;
private boolean allowNull;

@Override
public void initialize(ValidCreditCard validCreditCard) {
context = validCreditCard.context();
allowNull = validCreditCard.allowNull();
}

@Override
public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
if (input == null) {
return true;
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The null check returns true even when allowNull is false. This means null values will always pass validation regardless of the allowNull setting. The validator should return allowNull when input is null to properly respect the allowNull configuration.

Suggested change
return true;
return allowNull;

Copilot uses AI. Check for mistakes.
}
ValidationErrorList errorList = new ValidationErrorList();
boolean valid = ESAPI.validator().isValidCreditCard(context, input, allowNull, errorList);

if(!valid){
ValidationUtil.addViolations(errorList, constraintValidatorContext);
}

return valid;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.owasp.esapi.reference.validation.annotations;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;


@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Constraint(validatedBy = ValidDateValidator.class)
@Documented
public @interface ValidDate {

String message() default "";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

String context();

//Invalid type DateFormat for the annotation attribute ValidDate.format;
//only primitive type, String, Class, annotation, enumeration are permitted or 1-dimensional arrays thereof
//DateFormat format();

int dateStyle();

String locale();

boolean allowNull();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.owasp.esapi.reference.validation.annotations;

import java.text.DateFormat;
import java.util.Locale;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.owasp.esapi.ValidationErrorList;
import org.owasp.esapi.ESAPI;


public class ValidDateValidator implements ConstraintValidator<ValidDate, String>{

private String context;
private int dateStyle;
private String localeString;
private boolean allowNull;

@Override
public void initialize(ValidDate validDate) {
context = validDate.context();
dateStyle = validDate.dateStyle();
localeString = validDate.locale();
allowNull = validDate.allowNull();
}

@Override
public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
if (input == null) {
return true;
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The null check returns true even when allowNull is false. This means null values will always pass validation regardless of the allowNull setting. The validator should return allowNull when input is null to properly respect the allowNull configuration.

Suggested change
return true;
return allowNull;

Copilot uses AI. Check for mistakes.
}
Locale locale = toLocale(localeString);
DateFormat dateFormat = DateFormat.getDateInstance(dateStyle, locale);

ValidationErrorList errorList = new ValidationErrorList();
boolean valid = ESAPI.validator().isValidDate(context, input, dateFormat, allowNull, errorList);

if(!valid){
ValidationUtil.addViolations(errorList, constraintValidatorContext);
}

return valid;
}

private static Locale toLocale(String localeValue) {
if (localeValue == null) {
return Locale.getDefault();
}
String normalized = localeValue.trim();
if (normalized.isEmpty()) {
return Locale.getDefault();
}
Locale locale = Locale.forLanguageTag(normalized.replace('_', '-'));
return Locale.ROOT.equals(locale) ? Locale.getDefault() : locale;
Comment on lines +54 to +55
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback to Locale.getDefault() when Locale.ROOT is returned may not work as intended. Locale.forLanguageTag() returns Locale.ROOT when the tag is unrecognized or invalid, not when it should return the default locale. This means invalid locale strings like "invalid-locale" will incorrectly fall back to the system default instead of being treated as an error. Consider validating the locale string format before parsing or documenting this fallback behavior.

Copilot uses AI. Check for mistakes.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.owasp.esapi.reference.validation.annotations;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;


@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Constraint(validatedBy = ValidDirectoryPathValidator.class)
@Documented
public @interface ValidDirectoryPath {

String message() default "";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

String context();

String parent();

boolean allowNull();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.owasp.esapi.reference.validation.annotations;

import java.io.File;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.owasp.esapi.ValidationErrorList;
import org.owasp.esapi.ESAPI;


public class ValidDirectoryPathValidator implements ConstraintValidator<ValidDirectoryPath, String>{

private String context;
private String parentString;
private boolean allowNull;

@Override
public void initialize(ValidDirectoryPath validDirectoryPath) {
context = validDirectoryPath.context();
parentString = validDirectoryPath.parent();
allowNull = validDirectoryPath.allowNull();
}

@Override
public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
if (input == null) {
return true;
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The null check returns true even when allowNull is false. This means null values will always pass validation regardless of the allowNull setting. The validator should return allowNull when input is null to properly respect the allowNull configuration.

Suggested change
return true;
return allowNull;

Copilot uses AI. Check for mistakes.
}
ValidationErrorList errorList = new ValidationErrorList();
File parent = new File(parentString);
boolean valid = ESAPI.validator().isValidDirectoryPath(context, input, parent, allowNull, errorList);

if(!valid){
ValidationUtil.addViolations(errorList, constraintValidatorContext);
}

return valid;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.owasp.esapi.reference.validation.annotations;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;


@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Constraint(validatedBy = ValidDoubleValidator.class)
@Documented
public @interface ValidDouble {

String message() default "";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

String context();

double minValue();

double maxValue();

boolean allowNull();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.owasp.esapi.reference.validation.annotations;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.owasp.esapi.ValidationErrorList;
import org.owasp.esapi.ESAPI;


public class ValidDoubleValidator implements ConstraintValidator<ValidDouble, String>{

private String context;
private double minValue;
private double maxValue;
private boolean allowNull;

@Override
public void initialize(ValidDouble validDouble) {
context = validDouble.context();
minValue = validDouble.minValue();
maxValue = validDouble.maxValue();
allowNull = validDouble.allowNull();
}

@Override
public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
if (input == null) {
return true;
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The null check returns true even when allowNull is false. This means null values will always pass validation regardless of the allowNull setting. The validator should return allowNull when input is null to properly respect the allowNull configuration.

Suggested change
return true;
return allowNull;

Copilot uses AI. Check for mistakes.
}
ValidationErrorList errorList = new ValidationErrorList();
boolean valid = ESAPI.validator().isValidDouble(context, input, minValue, maxValue, allowNull, errorList);

if(!valid){
ValidationUtil.addViolations(errorList, constraintValidatorContext);
}

return valid;
}
}
Loading