add-unix-user-hosting-asset-validation #66
@ -29,7 +29,7 @@ class HsUnixUserHostingAssetValidator extends HsHostingAssetEntityValidator {
|
|||||||
.values("/bin/false", "/bin/bash", "/bin/csh", "/bin/dash", "/usr/bin/tcsh", "/usr/bin/zsh", "/usr/bin/passwd")
|
.values("/bin/false", "/bin/bash", "/bin/csh", "/bin/dash", "/usr/bin/tcsh", "/usr/bin/zsh", "/usr/bin/passwd")
|
||||||
.withDefault("/bin/false"),
|
.withDefault("/bin/false"),
|
||||||
stringProperty("homedir").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeHomedir),
|
stringProperty("homedir").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeHomedir),
|
||||||
stringProperty("totpKey").matchesRegEx("^0x([0-9A-Fa-f]{2})+$").minLength(20).maxLength(256).hidden().writeOnly().optional(),
|
stringProperty("totpKey").matchesRegEx("^0x([0-9A-Fa-f]{2})+$").minLength(20).maxLength(256).undisclosed().writeOnly().optional(),
|
||||||
passwordProperty("password").minLength(8).maxLength(40).writeOnly());
|
passwordProperty("password").minLength(8).maxLength(40).writeOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,20 +32,20 @@ public class EnumerationProperty extends ValidatableProperty<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void deferredInit(final ValidatableProperty<?>[] allProperties) {
|
public void deferredInit(final ValidatableProperty<?>[] allProperties) {
|
||||||
if (deferredInit != null) {
|
if (hasDeferredInit()) {
|
||||||
if (this.values != null) {
|
if (this.values != null) {
|
||||||
throw new IllegalStateException("property " + this + " already has values");
|
throw new IllegalStateException("property " + this + " already has values");
|
||||||
}
|
}
|
||||||
this.values = deferredInit.apply(allProperties);
|
this.values = doDeferredInit(allProperties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValidatableProperty<String> valuesFromProperties(final String propertyNamePrefix) {
|
public ValidatableProperty<String> valuesFromProperties(final String propertyNamePrefix) {
|
||||||
this.deferredInit = (ValidatableProperty<?>[] allProperties) -> stream(allProperties)
|
this.setDeferredInit( (ValidatableProperty<?>[] allProperties) -> stream(allProperties)
|
||||||
.map(ValidatableProperty::propertyName)
|
.map(ValidatableProperty::propertyName)
|
||||||
.filter(name -> name.startsWith(propertyNamePrefix))
|
.filter(name -> name.startsWith(propertyNamePrefix))
|
||||||
.map(name -> name.substring(propertyNamePrefix.length()))
|
.map(name -> name.substring(propertyNamePrefix.length()))
|
||||||
.toArray(String[]::new);
|
.toArray(String[]::new));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ public abstract class HsEntityValidator<E extends PropertiesProvider> {
|
|||||||
public Map<String, Object> postProcess(final E entity, final Map<String, Object> config) {
|
public Map<String, Object> postProcess(final E entity, final Map<String, Object> config) {
|
||||||
final var copy = new HashMap<>(config);
|
final var copy = new HashMap<>(config);
|
||||||
stream(propertyValidators).forEach(p -> {
|
stream(propertyValidators).forEach(p -> {
|
||||||
if ( p.writeOnly) {
|
if ( p.isWriteOnly()) {
|
||||||
hsh-michaelhoennig marked this conversation as resolved
Outdated
|
|||||||
copy.remove(p.propertyName);
|
copy.remove(p.propertyName);
|
||||||
}
|
}
|
||||||
if (p.isComputed()) {
|
if (p.isComputed()) {
|
||||||
|
@ -10,7 +10,7 @@ public class PasswordProperty extends StringProperty {
|
|||||||
|
|
||||||
private PasswordProperty(final String propertyName) {
|
private PasswordProperty(final String propertyName) {
|
||||||
super(propertyName);
|
super(propertyName);
|
||||||
hidden();
|
undisclosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PasswordProperty passwordProperty(final String propertyName) {
|
public static PasswordProperty passwordProperty(final String propertyName) {
|
||||||
|
@ -6,7 +6,6 @@ import net.hostsharing.hsadminng.mapper.Array;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
public class StringProperty extends ValidatableProperty<String> {
|
public class StringProperty extends ValidatableProperty<String> {
|
||||||
|
|
||||||
@ -14,11 +13,11 @@ public class StringProperty extends ValidatableProperty<String> {
|
|||||||
ValidatableProperty.KEY_ORDER_HEAD,
|
ValidatableProperty.KEY_ORDER_HEAD,
|
||||||
Array.of("matchesRegEx", "minLength", "maxLength"),
|
Array.of("matchesRegEx", "minLength", "maxLength"),
|
||||||
ValidatableProperty.KEY_ORDER_TAIL,
|
ValidatableProperty.KEY_ORDER_TAIL,
|
||||||
Array.of("hidden"));
|
Array.of("undisclosed"));
|
||||||
private Pattern matchesRegEx;
|
private Pattern matchesRegEx;
|
||||||
private Integer minLength;
|
private Integer minLength;
|
||||||
private Integer maxLength;
|
private Integer maxLength;
|
||||||
private boolean hidden;
|
private boolean undisclosed;
|
||||||
|
|
||||||
protected StringProperty(final String propertyName) {
|
protected StringProperty(final String propertyName) {
|
||||||
super(String.class, propertyName, KEY_ORDER);
|
super(String.class, propertyName, KEY_ORDER);
|
||||||
@ -43,8 +42,13 @@ public class StringProperty extends ValidatableProperty<String> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringProperty hidden() {
|
/**
|
||||||
this.hidden = true;
|
* The property value is not disclosed in error messages.
|
||||||
hsh-michaelhoennig marked this conversation as resolved
Outdated
hsh-marcsandlus
commented
doku doku
|
|||||||
|
*
|
||||||
|
* @return this;
|
||||||
|
*/
|
||||||
|
public StringProperty undisclosed() {
|
||||||
|
this.undisclosed = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,13 +63,13 @@ public class StringProperty extends ValidatableProperty<String> {
|
|||||||
if (matchesRegEx != null && !matchesRegEx.matcher(propValue).matches()) {
|
if (matchesRegEx != null && !matchesRegEx.matcher(propValue).matches()) {
|
||||||
result.add(propertyName + "' is expected to be match " + matchesRegEx + " but " + display(propValue) + " does not match");
|
result.add(propertyName + "' is expected to be match " + matchesRegEx + " but " + display(propValue) + " does not match");
|
||||||
}
|
}
|
||||||
if (readOnly && propValue != null) {
|
if (isReadOnly() && propValue != null) {
|
||||||
result.add(propertyName + "' is readonly but given as " + display(propValue));
|
result.add(propertyName + "' is readonly but given as " + display(propValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String display(final String propValue) {
|
private String display(final String propValue) {
|
||||||
return hidden ? "provided value" : ("'" + propValue + "'");
|
return undisclosed ? "provided value" : ("'" + propValue + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package net.hostsharing.hsadminng.hs.validation;
|
package net.hostsharing.hsadminng.hs.validation;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
|
||||||
@ -21,6 +23,7 @@ import static java.lang.Boolean.TRUE;
|
|||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public abstract class ValidatableProperty<T> {
|
public abstract class ValidatableProperty<T> {
|
||||||
|
|
||||||
@ -29,16 +32,28 @@ public abstract class ValidatableProperty<T> {
|
|||||||
|
|
||||||
final Class<T> type;
|
final Class<T> type;
|
||||||
final String propertyName;
|
final String propertyName;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
hsh-michaelhoennig marked this conversation as resolved
Outdated
hsh-marcsandlus
commented
private private
|
|||||||
private final String[] keyOrder;
|
private final String[] keyOrder;
|
||||||
|
|
||||||
private Boolean required;
|
private Boolean required;
|
||||||
private T defaultValue;
|
private T defaultValue;
|
||||||
protected Function<PropertiesProvider, T> computedBy;
|
|
||||||
protected boolean computed; // used in descriptor, because computedBy cannot be rendered to a text string
|
|
||||||
protected boolean readOnly;
|
|
||||||
protected boolean writeOnly;
|
|
||||||
|
|
||||||
protected Function<ValidatableProperty<?>[], T[]> deferredInit;
|
@JsonIgnore
|
||||||
|
private Function<PropertiesProvider, T> computedBy;
|
||||||
|
|
||||||
|
@Accessors(makeFinal = true, chain = true, fluent = false)
|
||||||
|
private boolean computed; // used in descriptor, because computedBy cannot be rendered to a text string
|
||||||
|
|
||||||
|
@Accessors(makeFinal = true, chain = true, fluent = false)
|
||||||
|
private boolean readOnly;
|
||||||
|
|
||||||
|
@Accessors(makeFinal = true, chain = true, fluent = false)
|
||||||
|
private boolean writeOnly;
|
||||||
|
|
||||||
|
private Function<ValidatableProperty<?>[], T[]> deferredInit;
|
||||||
private boolean isTotalsValidator = false;
|
private boolean isTotalsValidator = false;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private List<Function<HsBookingItemEntity, List<String>>> asTotalLimitValidators; // TODO.impl: move to BookingItemIntegerProperty
|
private List<Function<HsBookingItemEntity, List<String>>> asTotalLimitValidators; // TODO.impl: move to BookingItemIntegerProperty
|
||||||
|
|
||||||
@ -48,6 +63,17 @@ public abstract class ValidatableProperty<T> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setDeferredInit(final Function<ValidatableProperty<?>[], T[]> function) {
|
||||||
|
this.deferredInit = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasDeferredInit() {
|
||||||
|
return deferredInit != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T[] doDeferredInit(final ValidatableProperty<?>[] allProperties) {
|
||||||
|
return deferredInit.apply(allProperties);
|
||||||
|
}
|
||||||
|
|
||||||
public ValidatableProperty<T> writeOnly() {
|
public ValidatableProperty<T> writeOnly() {
|
||||||
this.writeOnly = true;
|
this.writeOnly = true;
|
||||||
@ -61,7 +87,6 @@ public abstract class ValidatableProperty<T> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ValidatableProperty<T> required() {
|
public ValidatableProperty<T> required() {
|
||||||
required = TRUE;
|
required = TRUE;
|
||||||
return this;
|
return this;
|
||||||
@ -231,10 +256,6 @@ public abstract class ValidatableProperty<T> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isComputed() {
|
|
||||||
return computedBy != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <E extends PropertiesProvider> T compute(final E entity) {
|
public <E extends PropertiesProvider> T compute(final E entity) {
|
||||||
return computedBy.apply(entity);
|
return computedBy.apply(entity);
|
||||||
}
|
}
|
||||||
|
@ -124,8 +124,8 @@ class HsUnixUserHostingAssetValidatorUnitTest {
|
|||||||
"{type=integer, propertyName=HDD soft quota, unit=GB, maxFrom=HDD hard quota}",
|
"{type=integer, propertyName=HDD soft quota, unit=GB, maxFrom=HDD hard quota}",
|
||||||
"{type=enumeration, propertyName=shell, values=[/bin/false, /bin/bash, /bin/csh, /bin/dash, /usr/bin/tcsh, /usr/bin/zsh, /usr/bin/passwd], defaultValue=/bin/false}",
|
"{type=enumeration, propertyName=shell, values=[/bin/false, /bin/bash, /bin/csh, /bin/dash, /usr/bin/tcsh, /usr/bin/zsh, /usr/bin/passwd], defaultValue=/bin/false}",
|
||||||
"{type=string, propertyName=homedir, readOnly=true, computed=true}",
|
"{type=string, propertyName=homedir, readOnly=true, computed=true}",
|
||||||
"{type=string, propertyName=totpKey, matchesRegEx=^0x([0-9A-Fa-f]{2})+$, minLength=20, maxLength=256, writeOnly=true, hidden=true}",
|
"{type=string, propertyName=totpKey, matchesRegEx=^0x([0-9A-Fa-f]{2})+$, minLength=20, maxLength=256, writeOnly=true, undisclosed=true}",
|
||||||
"{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, hidden=true}"
|
"{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, undisclosed=true}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user
isWriteOnly()