Generic TypePropertyProbe

This commit is contained in:
Xavi Aracil 2022-11-25 12:48:11 +01:00
parent a46fcbff9a
commit cc33dd4068
4 changed files with 83 additions and 29 deletions

View File

@ -1,5 +1,6 @@
package org.oneedtech.inspect.vc; package org.oneedtech.inspect.vc;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -64,9 +65,16 @@ public class Assertion extends Credential {
} }
} }
public enum Type { public enum Type implements CredentialEnum {
Assertion, Assertion(List.of("Assertion")),
Unknown; BadgeClass(List.of("BadgeClass")),
Unknown(Collections.emptyList());
private final List<String> allowedTypeValues;
Type(List<String> typeValues) {
this.allowedTypeValues = typeValues;
}
public static Assertion.Type valueOf (JsonNode typeNode) { public static Assertion.Type valueOf (JsonNode typeNode) {
if(typeNode != null) { if(typeNode != null) {
@ -75,10 +83,23 @@ public class Assertion extends Credential {
if(value.equals("Assertion")) { if(value.equals("Assertion")) {
return Assertion; return Assertion;
} }
if(value.equals("BadgeClass")) {
return BadgeClass;
}
} }
} }
return Unknown; return Unknown;
} }
@Override
public List<String> getRequiredTypeValues() {
return Collections.emptyList();
}
@Override
public List<String> getAllowedTypeValues() {
return allowedTypeValues;
}
} }
public static final String ID = Assertion.class.getCanonicalName(); public static final String ID = Assertion.class.getCanonicalName();

View File

@ -74,6 +74,11 @@ public abstract class Credential extends GeneratedObject {
public static final List<ResourceType> RECOGNIZED_PAYLOAD_TYPES = List.of(SVG, PNG, JSON, JWT); public static final List<ResourceType> RECOGNIZED_PAYLOAD_TYPES = List.of(SVG, PNG, JSON, JWT);
public static final String CREDENTIAL_KEY = "CREDENTIAL_KEY"; public static final String CREDENTIAL_KEY = "CREDENTIAL_KEY";
public interface CredentialEnum {
List<String> getRequiredTypeValues();
List<String> getAllowedTypeValues();
}
public abstract static class Builder<B extends Credential> { public abstract static class Builder<B extends Credential> {
private Resource resource; private Resource resource;
private JsonNode jsonData; private JsonNode jsonData;

View File

@ -5,6 +5,7 @@ import static org.oneedtech.inspect.vc.VerifiableCredential.Type.ClrCredential;
import static org.oneedtech.inspect.vc.VerifiableCredential.Type.EndorsementCredential; import static org.oneedtech.inspect.vc.VerifiableCredential.Type.EndorsementCredential;
import static org.oneedtech.inspect.vc.VerifiableCredential.Type.VerifiablePresentation; import static org.oneedtech.inspect.vc.VerifiableCredential.Type.VerifiablePresentation;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -72,14 +73,20 @@ public class VerifiableCredential extends Credential {
.build(); .build();
public enum Type { public enum Type implements CredentialEnum {
AchievementCredential, AchievementCredential(Collections.emptyList()),
OpenBadgeCredential, //treated as an alias of AchievementCredential OpenBadgeCredential(List.of("OpenBadgeCredential", "AchievementCredential")), //treated as an alias of AchievementCredential
ClrCredential, ClrCredential(List.of("ClrCredential")),
EndorsementCredential, EndorsementCredential(List.of("EndorsementCredential")),
VerifiablePresentation, VerifiablePresentation(Collections.emptyList()),
VerifiableCredential, //this is an underspecifier in our context VerifiableCredential(List.of("VerifiableCredential")), //this is an underspecifier in our context
Unknown; Unknown(Collections.emptyList());
private final List<String> allowedTypeValues;
Type(List<String> allowedTypeValues) {
this.allowedTypeValues = allowedTypeValues;
}
public static VerifiableCredential.Type valueOf (JsonNode typeNode) { public static VerifiableCredential.Type valueOf (JsonNode typeNode) {
if(typeNode != null) { if(typeNode != null) {
@ -98,6 +105,16 @@ public class VerifiableCredential extends Credential {
} }
return Unknown; return Unknown;
} }
@Override
public List<String> getRequiredTypeValues() {
return List.of("VerifiableCredential");
}
@Override
public List<String> getAllowedTypeValues() {
return allowedTypeValues;
}
} }
public enum ProofType { public enum ProofType {

View File

@ -3,10 +3,11 @@ package org.oneedtech.inspect.vc.probe;
import static org.oneedtech.inspect.util.code.Defensives.checkNotNull; import static org.oneedtech.inspect.util.code.Defensives.checkNotNull;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.oneedtech.inspect.core.probe.RunContext; import org.oneedtech.inspect.core.probe.RunContext;
import org.oneedtech.inspect.core.report.ReportItems; import org.oneedtech.inspect.core.report.ReportItems;
import org.oneedtech.inspect.vc.VerifiableCredential; import org.oneedtech.inspect.vc.Credential.CredentialEnum;
/** /**
* A Probe that verifies a credential's type property. * A Probe that verifies a credential's type property.
@ -14,38 +15,48 @@ import org.oneedtech.inspect.vc.VerifiableCredential;
* @author mgylling * @author mgylling
*/ */
public class TypePropertyProbe extends PropertyProbe { public class TypePropertyProbe extends PropertyProbe {
private final VerifiableCredential.Type expected; private final CredentialEnum expected;
public TypePropertyProbe(VerifiableCredential.Type expected) { public TypePropertyProbe(CredentialEnum expected) {
super(ID, "type"); super(ID, "type");
this.expected = checkNotNull(expected); this.expected = checkNotNull(expected);
this.setValidations(this::validate); this.setValidations(this::validate);
} }
public ReportItems validate(List<String> values, RunContext ctx) { public ReportItems validate(List<String> values, RunContext ctx) {
if (!values.contains("VerifiableCredential")) { List<String> requiredTypeValues = expected.getRequiredTypeValues();
return fatal("The type property does not contain the entry 'VerifiableCredential'", ctx); if (!requiredTypeValues.isEmpty()) {
if (!requiredTypeValues.stream().allMatch(requiredValue -> values.contains(requiredValue))) {
return fatal(formatMessage(requiredTypeValues), ctx);
}
} }
if (expected == VerifiableCredential.Type.OpenBadgeCredential) { List<String> allowedValues = expected.getAllowedTypeValues();
if (!values.contains("OpenBadgeCredential") && !values.contains("AchievementCredential")) { if (allowedValues.isEmpty()) {
return fatal("The type property does not contain one of 'OpenBadgeCredential' or 'AchievementCredential'", ctx);
}
} else if (expected == VerifiableCredential.Type.ClrCredential) {
if (!values.contains("ClrCredential")) {
return fatal("The type property does not contain the entry 'ClrCredential'", ctx);
}
} else if (expected == VerifiableCredential.Type.EndorsementCredential) {
if (!values.contains("EndorsementCredential")) {
return fatal("The type property does not contain the entry 'EndorsementCredential'", ctx);
}
} else {
// TODO implement // TODO implement
throw new IllegalStateException(); throw new IllegalStateException();
} }
if (!values.stream().anyMatch(v -> allowedValues.contains(v))) {
return fatal(formatMessage(values), ctx);
}
return success(ctx); return success(ctx);
} }
private String formatMessage(List<String> values) {
StringBuffer buffer = new StringBuffer("The type property does not contain ");
if (values.size() > 1) {
buffer.append("one of");
buffer.append(values.stream()
.map(value -> "'" + value + "'")
.collect(Collectors.joining(" or "))
);
} else {
buffer.append("the entry '" + values.get(0) + "'");
}
return buffer.toString();
}
public static final String ID = TypePropertyProbe.class.getSimpleName(); public static final String ID = TypePropertyProbe.class.getSimpleName();
} }