diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java index 9bfab9a..3ba06f8 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java @@ -1,5 +1,6 @@ package org.oneedtech.inspect.vc; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -64,9 +65,16 @@ public class Assertion extends Credential { } } - public enum Type { - Assertion, - Unknown; + public enum Type implements CredentialEnum { + Assertion(List.of("Assertion")), + BadgeClass(List.of("BadgeClass")), + Unknown(Collections.emptyList()); + + private final List allowedTypeValues; + + Type(List typeValues) { + this.allowedTypeValues = typeValues; + } public static Assertion.Type valueOf (JsonNode typeNode) { if(typeNode != null) { @@ -75,10 +83,23 @@ public class Assertion extends Credential { if(value.equals("Assertion")) { return Assertion; } + if(value.equals("BadgeClass")) { + return BadgeClass; + } } } return Unknown; } + + @Override + public List getRequiredTypeValues() { + return Collections.emptyList(); + } + + @Override + public List getAllowedTypeValues() { + return allowedTypeValues; + } } public static final String ID = Assertion.class.getCanonicalName(); diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Credential.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Credential.java index 3d74a87..e180ef5 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Credential.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Credential.java @@ -74,6 +74,11 @@ public abstract class Credential extends GeneratedObject { public static final List RECOGNIZED_PAYLOAD_TYPES = List.of(SVG, PNG, JSON, JWT); public static final String CREDENTIAL_KEY = "CREDENTIAL_KEY"; + public interface CredentialEnum { + List getRequiredTypeValues(); + List getAllowedTypeValues(); + } + public abstract static class Builder { private Resource resource; private JsonNode jsonData; diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java index b9443c6..c892844 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java @@ -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.VerifiablePresentation; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -72,14 +73,20 @@ public class VerifiableCredential extends Credential { .build(); - public enum Type { - AchievementCredential, - OpenBadgeCredential, //treated as an alias of AchievementCredential - ClrCredential, - EndorsementCredential, - VerifiablePresentation, - VerifiableCredential, //this is an underspecifier in our context - Unknown; + public enum Type implements CredentialEnum { + AchievementCredential(Collections.emptyList()), + OpenBadgeCredential(List.of("OpenBadgeCredential", "AchievementCredential")), //treated as an alias of AchievementCredential + ClrCredential(List.of("ClrCredential")), + EndorsementCredential(List.of("EndorsementCredential")), + VerifiablePresentation(Collections.emptyList()), + VerifiableCredential(List.of("VerifiableCredential")), //this is an underspecifier in our context + Unknown(Collections.emptyList()); + + private final List allowedTypeValues; + + Type(List allowedTypeValues) { + this.allowedTypeValues = allowedTypeValues; + } public static VerifiableCredential.Type valueOf (JsonNode typeNode) { if(typeNode != null) { @@ -98,6 +105,16 @@ public class VerifiableCredential extends Credential { } return Unknown; } + + @Override + public List getRequiredTypeValues() { + return List.of("VerifiableCredential"); + } + + @Override + public List getAllowedTypeValues() { + return allowedTypeValues; + } } public enum ProofType { diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/TypePropertyProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/TypePropertyProbe.java index c8e03f0..2c25d7d 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/TypePropertyProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/TypePropertyProbe.java @@ -3,10 +3,11 @@ package org.oneedtech.inspect.vc.probe; import static org.oneedtech.inspect.util.code.Defensives.checkNotNull; import java.util.List; +import java.util.stream.Collectors; import org.oneedtech.inspect.core.probe.RunContext; 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. @@ -14,38 +15,48 @@ import org.oneedtech.inspect.vc.VerifiableCredential; * @author mgylling */ 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"); this.expected = checkNotNull(expected); this.setValidations(this::validate); } public ReportItems validate(List values, RunContext ctx) { - if (!values.contains("VerifiableCredential")) { - return fatal("The type property does not contain the entry 'VerifiableCredential'", ctx); + List requiredTypeValues = expected.getRequiredTypeValues(); + if (!requiredTypeValues.isEmpty()) { + if (!requiredTypeValues.stream().allMatch(requiredValue -> values.contains(requiredValue))) { + return fatal(formatMessage(requiredTypeValues), ctx); + } } - if (expected == VerifiableCredential.Type.OpenBadgeCredential) { - if (!values.contains("OpenBadgeCredential") && !values.contains("AchievementCredential")) { - 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 { + List allowedValues = expected.getAllowedTypeValues(); + if (allowedValues.isEmpty()) { // TODO implement throw new IllegalStateException(); } + if (!values.stream().anyMatch(v -> allowedValues.contains(v))) { + return fatal(formatMessage(values), ctx); + } return success(ctx); } + private String formatMessage(List 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(); }