diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/OB30Inspector.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/OB30Inspector.java index 02d532f..c49bd80 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/OB30Inspector.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/OB30Inspector.java @@ -31,6 +31,7 @@ import org.oneedtech.inspect.util.resource.UriResource; import org.oneedtech.inspect.util.resource.context.ResourceContext; import org.oneedtech.inspect.util.spec.Specification; import org.oneedtech.inspect.vc.Credential.Type; +import org.oneedtech.inspect.vc.probe.CredentialSubjectProbe; import org.oneedtech.inspect.vc.probe.ContextPropertyProbe; import org.oneedtech.inspect.vc.probe.CredentialParseProbe; import org.oneedtech.inspect.vc.probe.ExpirationVerifierProbe; @@ -91,9 +92,7 @@ public class OB30Inspector extends VCInspector { //we expect the above to place a generated object in the context Credential crd = ctx.getGeneratedObject(Credential.ID); - - //TODO new check: that subject @id or IdentityObject is available (at least one is the req) - + //context and type properties Credential.Type type = Type.OpenBadgeCredential; for(Probe probe : List.of(new ContextPropertyProbe(type), new TypePropertyProbe(type))) { @@ -110,6 +109,8 @@ public class OB30Inspector extends VCInspector { if(broken(accumulator)) return abort(ctx, accumulator, probeCount); } + accumulator.add(new CredentialSubjectProbe().run(crd.getJson(), ctx)); + //signatures, proofs probeCount++; if(crd.getJwt().isPresent()){ diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/CredentialSubjectProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/CredentialSubjectProbe.java new file mode 100644 index 0000000..2932563 --- /dev/null +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/CredentialSubjectProbe.java @@ -0,0 +1,42 @@ +package org.oneedtech.inspect.vc.probe; + +import org.oneedtech.inspect.core.probe.Probe; +import org.oneedtech.inspect.core.probe.RunContext; +import org.oneedtech.inspect.core.report.ReportItems; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; + +/** + * A Probe that checks credential subject specifics not capturable by schemata. + * + * @author mgylling + */ +public class CredentialSubjectProbe extends Probe { + + public CredentialSubjectProbe() { + super(ID); + } + + @Override + public ReportItems run(JsonNode root, RunContext ctx) throws Exception { + + JsonNode subject = root.get("credentialSubject"); + if(subject == null) return notRun("no credentialSubject node found", ctx); //error reported by schema + + /* + * Check that we have either .id or .identifier populated + */ + JsonNode id = root.get("id"); + if (id != null && id.textValue().strip().length() > 0) return success(ctx); + + JsonNode identifier = root.get("identifier"); + if(identifier != null && identifier instanceof ArrayNode + && ((ArrayNode)identifier).size() > 0) return success(ctx); + + return error("no id in credentialSubject", ctx); + + } + + public static final String ID = CredentialSubjectProbe.class.getSimpleName(); +}