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 a2dde88..27fee6a 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 @@ -44,6 +44,7 @@ import org.oneedtech.inspect.vc.probe.ExpirationProbe; import org.oneedtech.inspect.vc.probe.InlineJsonSchemaProbe; import org.oneedtech.inspect.vc.probe.IssuanceProbe; import org.oneedtech.inspect.vc.probe.EmbeddedProofProbe; +import org.oneedtech.inspect.vc.probe.EvidenceProbe; import org.oneedtech.inspect.vc.probe.RevocationListProbe; import org.oneedtech.inspect.vc.probe.ExternalProofProbe; import org.oneedtech.inspect.vc.probe.TypePropertyProbe; @@ -202,6 +203,11 @@ public class OB30Inspector extends VCInspector implements SubInspector { if(broken(accumulator)) return abort(ctx, accumulator, probeCount); } + // evidence + probeCount++; + accumulator.add(new EvidenceProbe().run(ob.getJson(), ctx)); + if(broken(accumulator)) return abort(ctx, accumulator, probeCount); + //embedded endorsements EndorsementInspector endorsementInspector = new EndorsementInspector.Builder().build(); diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EvidenceProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EvidenceProbe.java new file mode 100644 index 0000000..92f6c92 --- /dev/null +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EvidenceProbe.java @@ -0,0 +1,38 @@ +package org.oneedtech.inspect.vc.probe; + +import java.util.List; + +import org.oneedtech.inspect.core.probe.Probe; +import org.oneedtech.inspect.core.probe.RunContext; +import org.oneedtech.inspect.core.report.ReportItems; +import org.oneedtech.inspect.vc.util.JsonNodeUtil; + +import com.fasterxml.jackson.databind.JsonNode; + +public class EvidenceProbe extends Probe { + public EvidenceProbe() { + super(ID); + } + + @Override + public ReportItems run(JsonNode root, RunContext ctx) throws Exception { + + if (root.hasNonNull("evidence")) { + /* + * evidence is an array, so check type of each element + */ + List evidences = JsonNodeUtil.asNodeList(root.get("evidence")); + for (JsonNode evidence : evidences) { + // check that type contains "Evidence" + if (!JsonNodeUtil.asStringList(evidence.get("type")).contains("Evidence")) { + return error("evidence is not of type \"Evidence\"", ctx); + } + } + } + + return success(ctx); + } + + public static final String ID = EvidenceProbe.class.getSimpleName(); + +} diff --git a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java index e764640..9f8c07f 100644 --- a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java +++ b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java @@ -16,6 +16,7 @@ import org.oneedtech.inspect.vc.probe.ExpirationProbe; import org.oneedtech.inspect.vc.probe.InlineJsonSchemaProbe; import org.oneedtech.inspect.vc.probe.IssuanceProbe; import org.oneedtech.inspect.vc.probe.EmbeddedProofProbe; +import org.oneedtech.inspect.vc.probe.EvidenceProbe; import org.oneedtech.inspect.vc.probe.TypePropertyProbe; import com.google.common.collect.Iterables; @@ -252,6 +253,18 @@ public class OB30Tests { }); } + @Test + void testSimpleJsonInvalidEvidenceType() { + //add a dumb value to .type and remove the ob type + assertDoesNotThrow(()->{ + Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_UNKNOWN_EVIDENCE_TYPE.asFileResource()); + if(verbose) PrintHelper.print(report, true); + assertInvalid(report); + // assertFatalCount(report, 1); + assertHasProbeID(report, EvidenceProbe.ID, true); + }); + } + @Disabled //TODO IssuanceVerifierProbe is not run because FATAL: InvalidSignature terminates @Test void testSimpleJsonNotIssued() { diff --git a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java index 2b44942..1508d23 100644 --- a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java +++ b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java @@ -19,6 +19,7 @@ public class Samples { public final static Sample SIMPLE_JSON_UNKNOWN_CREDENTIAL_SUBJECT_RESULT_TYPE = new Sample("ob30/simple-err-credential-subject-result-type.json", false); public final static Sample SIMPLE_JSON_UNKNOWN_CREDENTIAL_SUBJECT_ACHIEVEMENT_RESULT_DESCRIPTION_TYPE = new Sample("ob30/simple-err-credential-subject-achievement-result-description-type.json", false); public final static Sample SIMPLE_JSON_UNKNOWN_CREDENTIAL_SUBJECT_PROFILE_TYPE = new Sample("ob30/simple-err-credential-subject-profile-type.json", false); + public final static Sample SIMPLE_JSON_UNKNOWN_EVIDENCE_TYPE = new Sample("ob30/simple-err-evidence-type.json", false); public final static Sample SIMPLE_JSON_PROOF_METHOD_ERROR = new Sample("ob30/simple-err-proof-method.json", false); public final static Sample SIMPLE_JSON_PROOF_METHOD_NO_SCHEME_ERROR = new Sample("ob30/simple-err-proof-method-no-scheme.json", false); public final static Sample SIMPLE_JSON_PROOF_METHOD_UNKNOWN_SCHEME_ERROR = new Sample("ob30/simple-err-proof-method-unknown-scheme.json", false); diff --git a/inspector-vc/src/test/resources/ob30/simple-err-evidence-type.json b/inspector-vc/src/test/resources/ob30/simple-err-evidence-type.json new file mode 100644 index 0000000..245cbd6 --- /dev/null +++ b/inspector-vc/src/test/resources/ob30/simple-err-evidence-type.json @@ -0,0 +1,66 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://purl.imsglobal.org/spec/ob/v3p0/context.json", + "https://w3id.org/security/suites/ed25519-2020/v1" + ], + "id": "http://example.com/credentials/3527", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "issuer": { + "id": "https://example.com/issuers/876543", + "type": [ + "Profile" + ], + "name": "Example Corp" + }, + "issuanceDate": "2010-01-01T00:00:00Z", + "name": "Teamwork Badge", + "credentialSubject": { + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", + "type": [ + "Achievement" + ], + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + }, + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork" + } + }, + "evidence": [ + { + "id": "https://1edtech.edu/credentials/3732/evidence/1", + "type": "Evidence", + "narrative": "# Final Project Report \n This project was ...", + "name": "Final Project Report", + "description": "This is the final project report.", + "genre": "Research", + "audience": "Department" + }, + { + "id": "https://github.com/somebody/project", + "type": "InvalidEvidence", + "name": "Final Project Code", + "description": "This is the source code for the final project app.", + "genre": "Research", + "audience": "Department" + } + ], + "proof": [ + { + "type": "Ed25519Signature2020", + "created": "2022-11-16T18:54:22Z", + "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", + "proofPurpose": "assertionMethod", + "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" + } + ] +} \ No newline at end of file