Merge pull request #41 from imsglc/vc-ob-clr
add alpha implementations of ob3 and clr2 validators
This commit is contained in:
commit
c48bd72b2d
85
inspector-vc/pom.xml
Normal file
85
inspector-vc/pom.xml
Normal file
@ -0,0 +1,85 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.1edtech</groupId>
|
||||
<artifactId>inspector</artifactId>
|
||||
<version>0.9.2</version>
|
||||
</parent>
|
||||
<artifactId>inspector-vc</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.1edtech</groupId>
|
||||
<artifactId>inspector-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>auth0</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>jwks-rsa</artifactId>
|
||||
<version>0.21.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>3.19.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://repo.danubetech.com/#browse/browse:maven-public:com%2Fdanubetech%2Fverifiable-credentials-java%2F1.1-SNAPSHOT%2F1.1-20220818.090353-4 -->
|
||||
<dependency>
|
||||
<groupId>com.danubetech</groupId>
|
||||
<artifactId>verifiable-credentials-java</artifactId>
|
||||
<!-- <version>1.1-20220818.090353-4</version> -->
|
||||
<version>1.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://repo.danubetech.com/#browse/browse:maven-public:com%2Fdanubetech%2Fkey-formats-java%2F1.6-SNAPSHOT -->
|
||||
<dependency>
|
||||
<groupId>com.danubetech</groupId>
|
||||
<artifactId>key-formats-java</artifactId>
|
||||
<version>1.6-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://github.com/filip26/iron-verifiable-credentials -->
|
||||
<dependency>
|
||||
<groupId>com.apicatalog</groupId>
|
||||
<artifactId>iron-verifiable-credentials-jre8</artifactId>
|
||||
<version>0.7.0</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.apicatalog/titanium-json-ld -->
|
||||
<!-- https://github.com/filip26/titanium-json-ld -->
|
||||
<dependency>
|
||||
<groupId>com.apicatalog</groupId>
|
||||
<artifactId>titanium-json-ld</artifactId>
|
||||
<version>1.3.1</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.13</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/io.setl/rdf-urdna -->
|
||||
<!-- https://github.com/setl/rdf-urdna <dependency> <groupId>io.setl</groupId>
|
||||
<artifactId>rdf-urdna</artifactId> <version>1.1</version> <exclusions> <exclusion>
|
||||
<groupId>junit</groupId> <artifactId>junit</artifactId> </exclusion> <exclusion>
|
||||
<groupId>com.apicatalog</groupId> <artifactId>titanium-json-ld</artifactId>
|
||||
</exclusion> </exclusions> </dependency> -->
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>jakarta.json</artifactId>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>danubetech-maven-public</id>
|
||||
<url>https://repo.danubetech.com/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
@ -0,0 +1,133 @@
|
||||
package org.oneedtech.inspect.vc;
|
||||
|
||||
import static org.oneedtech.inspect.util.code.Defensives.*;
|
||||
import static org.oneedtech.inspect.util.resource.ResourceType.*;
|
||||
import static org.oneedtech.inspect.vc.Credential.Type.*;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.oneedtech.inspect.core.probe.GeneratedObject;
|
||||
import org.oneedtech.inspect.schema.Catalog;
|
||||
import org.oneedtech.inspect.schema.SchemaKey;
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* A wrapper object for a verifiable credential. This contains e.g. the origin resource
|
||||
* and the extracted JSON data plus any other stuff Probes need.
|
||||
* @author mgylling
|
||||
*/
|
||||
public class Credential extends GeneratedObject {
|
||||
final Resource resource;
|
||||
final JsonNode jsonData;
|
||||
final Credential.Type credentialType;
|
||||
final String jwt;
|
||||
|
||||
public Credential(Resource resource, JsonNode data, String jwt) {
|
||||
super(ID, GeneratedObject.Type.INTERNAL);
|
||||
this.resource = checkNotNull(resource);
|
||||
this.jsonData = checkNotNull(data);
|
||||
this.jwt = jwt; //may be null
|
||||
|
||||
checkTrue(RECOGNIZED_PAYLOAD_TYPES.contains(resource.getType()));
|
||||
|
||||
ArrayNode typeNode = (ArrayNode)jsonData.get("type");
|
||||
this.credentialType = Credential.Type.valueOf(typeNode);
|
||||
}
|
||||
|
||||
public Credential(Resource resource, JsonNode data) {
|
||||
this(resource, data, null);
|
||||
}
|
||||
|
||||
public Resource getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public JsonNode getJson() {
|
||||
return jsonData;
|
||||
}
|
||||
|
||||
public Credential.Type getCredentialType() {
|
||||
return credentialType;
|
||||
}
|
||||
|
||||
public Optional<String> getJwt() {
|
||||
return Optional.ofNullable(jwt);
|
||||
}
|
||||
|
||||
public ProofType getProofType() {
|
||||
return jwt == null ? ProofType.EMBEDDED : ProofType.EXTERNAL;
|
||||
}
|
||||
|
||||
|
||||
private static final Map<Credential.Type, SchemaKey> schemas = new ImmutableMap.Builder<Credential.Type, SchemaKey>()
|
||||
.put(AchievementCredential, Catalog.OB_30_ACHIEVEMENTCREDENTIAL_JSON)
|
||||
.put(ClrCredential, Catalog.CLR_20_CLRCREDENTIAL_JSON)
|
||||
.put(VerifiablePresentation, Catalog.CLR_20_CLRCREDENTIAL_JSON)
|
||||
.put(EndorsementCredential, Catalog.OB_30_ENDORSEMENTCREDENTIAL_JSON)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Get the canonical schema for this credential if such exists.
|
||||
*/
|
||||
public Optional<SchemaKey> getSchemaKey() {
|
||||
return Optional.ofNullable(schemas.get(credentialType));
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
AchievementCredential,
|
||||
OpenBadgeCredential, //treated as an alias of AchievementCredential
|
||||
ClrCredential,
|
||||
EndorsementCredential,
|
||||
VerifiablePresentation,
|
||||
VerifiableCredential, //this is an underspecifier in our context
|
||||
Unknown;
|
||||
|
||||
public static Credential.Type valueOf (ArrayNode typeArray) {
|
||||
if(typeArray != null) {
|
||||
Iterator<JsonNode> iter = typeArray.iterator();
|
||||
while(iter.hasNext()) {
|
||||
String value = iter.next().asText();
|
||||
if(value.equals("AchievementCredential") || value.equals("OpenBadgeCredential")) {
|
||||
return AchievementCredential;
|
||||
} else if(value.equals("ClrCredential")) {
|
||||
return ClrCredential;
|
||||
} else if(value.equals("VerifiablePresentation")) {
|
||||
return VerifiablePresentation;
|
||||
} else if(value.equals("EndorsementCredential")) {
|
||||
return EndorsementCredential;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ProofType {
|
||||
EXTERNAL,
|
||||
EMBEDDED
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("resource", resource.getID())
|
||||
.add("resourceType", resource.getType())
|
||||
.add("credentialType", credentialType)
|
||||
.add("json", jsonData)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public static final String ID = Credential.class.getCanonicalName();
|
||||
public static final List<ResourceType> RECOGNIZED_PAYLOAD_TYPES = List.of(SVG, PNG, JSON, JWT);
|
||||
public static final String CREDENTIAL_KEY = "CREDENTIAL_KEY";
|
||||
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
package org.oneedtech.inspect.vc;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static org.oneedtech.inspect.core.probe.RunContext.Key.*;
|
||||
import static org.oneedtech.inspect.core.report.ReportUtil.onProbeException;
|
||||
import static org.oneedtech.inspect.util.code.Defensives.checkNotNull;
|
||||
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
|
||||
import static org.oneedtech.inspect.vc.Credential.CREDENTIAL_KEY;
|
||||
import static org.oneedtech.inspect.vc.Credential.ProofType.EXTERNAL;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.oneedtech.inspect.core.SubInspector;
|
||||
import org.oneedtech.inspect.core.probe.GeneratedObject;
|
||||
import org.oneedtech.inspect.core.probe.Probe;
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.core.probe.json.JsonPathEvaluator;
|
||||
import org.oneedtech.inspect.core.report.Report;
|
||||
import org.oneedtech.inspect.core.report.ReportItems;
|
||||
import org.oneedtech.inspect.util.json.ObjectMapperCache;
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.UriResource;
|
||||
import org.oneedtech.inspect.util.resource.context.ResourceContext;
|
||||
import org.oneedtech.inspect.vc.Credential.Type;
|
||||
import org.oneedtech.inspect.vc.probe.ContextPropertyProbe;
|
||||
import org.oneedtech.inspect.vc.probe.EmbeddedProofProbe;
|
||||
import org.oneedtech.inspect.vc.probe.ExpirationProbe;
|
||||
import org.oneedtech.inspect.vc.probe.ExternalProofProbe;
|
||||
import org.oneedtech.inspect.vc.probe.InlineJsonSchemaProbe;
|
||||
import org.oneedtech.inspect.vc.probe.IssuanceProbe;
|
||||
import org.oneedtech.inspect.vc.probe.RevocationListProbe;
|
||||
import org.oneedtech.inspect.vc.probe.TypePropertyProbe;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* An inspector for EndorsementCredential objects.
|
||||
* @author mgylling
|
||||
*/
|
||||
public class EndorsementInspector extends VCInspector implements SubInspector {
|
||||
|
||||
protected <B extends VCInspector.Builder<?>> EndorsementInspector(B builder) {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Report run(Resource resource, Map<String, GeneratedObject> parentObjects) {
|
||||
|
||||
/*
|
||||
* The resource param is the top-level credential that embeds the endorsement, we
|
||||
* expect parentObjects to provide a pointer to the JsonNode we should check.
|
||||
*
|
||||
* The parent inspector is responsible to decode away possible jwt-ness, so that
|
||||
* what we get here is a verbatim json node.
|
||||
*
|
||||
*/
|
||||
|
||||
Credential endorsement = (Credential) checkNotNull(parentObjects.get(CREDENTIAL_KEY));
|
||||
|
||||
ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
|
||||
JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
|
||||
|
||||
RunContext ctx = new RunContext.Builder()
|
||||
.put(this)
|
||||
.put(JACKSON_OBJECTMAPPER, mapper)
|
||||
.put(JSONPATH_EVALUATOR, jsonPath)
|
||||
.build();
|
||||
|
||||
List<ReportItems> accumulator = new ArrayList<>();
|
||||
int probeCount = 0;
|
||||
try {
|
||||
|
||||
//context and type properties
|
||||
Credential.Type type = Type.EndorsementCredential;
|
||||
for(Probe<JsonNode> probe : List.of(new ContextPropertyProbe(type), new TypePropertyProbe(type))) {
|
||||
probeCount++;
|
||||
accumulator.add(probe.run(endorsement.getJson(), ctx));
|
||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||
}
|
||||
|
||||
//inline schema (parent inspector has already validated against canonical)
|
||||
accumulator.add(new InlineJsonSchemaProbe().run(endorsement.getJson(), ctx));
|
||||
|
||||
//signatures, proofs
|
||||
probeCount++;
|
||||
if(endorsement.getProofType() == EXTERNAL){
|
||||
//The credential originally contained in a JWT, validate the jwt and external proof.
|
||||
accumulator.add(new ExternalProofProbe().run(endorsement, ctx));
|
||||
} else {
|
||||
//The credential not contained in a jwt, must have an internal proof.
|
||||
accumulator.add(new EmbeddedProofProbe().run(endorsement, ctx));
|
||||
|
||||
}
|
||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||
|
||||
//check refresh service if we are not already refreshed (check just like in external CLR)
|
||||
probeCount++;
|
||||
if(resource.getContext().get(REFRESHED) != TRUE) {
|
||||
Optional<String> newID = checkRefreshService(endorsement, ctx);
|
||||
if(newID.isPresent()) {
|
||||
//TODO resource.type
|
||||
return this.run(
|
||||
new UriResource(new URI(newID.get()))
|
||||
.setContext(new ResourceContext(REFRESHED, TRUE)));
|
||||
}
|
||||
}
|
||||
|
||||
//revocation, expiration and issuance
|
||||
for(Probe<Credential> probe : List.of(new RevocationListProbe(),
|
||||
new ExpirationProbe(), new IssuanceProbe())) {
|
||||
probeCount++;
|
||||
accumulator.add(probe.run(endorsement, ctx));
|
||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
accumulator.add(onProbeException(Probe.ID.NO_UNCAUGHT_EXCEPTIONS, resource, e));
|
||||
}
|
||||
|
||||
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R extends Resource> Report run(R resource) {
|
||||
throw new IllegalStateException("must use #run(resource, map)");
|
||||
}
|
||||
|
||||
public static class Builder extends VCInspector.Builder<EndorsementInspector.Builder> {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public EndorsementInspector build() {
|
||||
return new EndorsementInspector(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,232 @@
|
||||
package org.oneedtech.inspect.vc;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static org.oneedtech.inspect.core.Inspector.Behavior.RESET_CACHES_ON_RUN;
|
||||
import static org.oneedtech.inspect.core.report.ReportUtil.onProbeException;
|
||||
import static org.oneedtech.inspect.util.code.Defensives.*;
|
||||
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
|
||||
import static org.oneedtech.inspect.vc.Credential.CREDENTIAL_KEY;
|
||||
import static org.oneedtech.inspect.vc.Credential.ProofType.EXTERNAL;
|
||||
import static org.oneedtech.inspect.vc.payload.PayloadParser.fromJwt;
|
||||
import static org.oneedtech.inspect.vc.util.JsonNodeUtil.asNodeList;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.oneedtech.inspect.core.SubInspector;
|
||||
import org.oneedtech.inspect.core.probe.GeneratedObject;
|
||||
import org.oneedtech.inspect.core.probe.Probe;
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.core.probe.RunContext.Key;
|
||||
import org.oneedtech.inspect.core.probe.json.JsonPathEvaluator;
|
||||
import org.oneedtech.inspect.core.probe.json.JsonSchemaProbe;
|
||||
import org.oneedtech.inspect.core.report.Report;
|
||||
import org.oneedtech.inspect.core.report.ReportItems;
|
||||
import org.oneedtech.inspect.schema.JsonSchemaCache;
|
||||
import org.oneedtech.inspect.schema.SchemaKey;
|
||||
import org.oneedtech.inspect.util.code.Defensives;
|
||||
import org.oneedtech.inspect.util.json.ObjectMapperCache;
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||
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.ContextPropertyProbe;
|
||||
import org.oneedtech.inspect.vc.probe.CredentialParseProbe;
|
||||
import org.oneedtech.inspect.vc.probe.CredentialSubjectProbe;
|
||||
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.RevocationListProbe;
|
||||
import org.oneedtech.inspect.vc.probe.ExternalProofProbe;
|
||||
import org.oneedtech.inspect.vc.probe.TypePropertyProbe;
|
||||
import org.oneedtech.inspect.vc.util.CachingDocumentLoader;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* A verifier for Open Badges 3.0.
|
||||
* @author mgylling
|
||||
*/
|
||||
public class OB30Inspector extends VCInspector implements SubInspector {
|
||||
protected final List<Probe<Credential>> userProbes;
|
||||
|
||||
protected OB30Inspector(OB30Inspector.Builder builder) {
|
||||
super(builder);
|
||||
this.userProbes = ImmutableList.copyOf(builder.probes);
|
||||
}
|
||||
|
||||
//https://docs.google.com/document/d/1_imUl2K-5tMib0AUxwA9CWb0Ap1b3qif0sXydih68J0/edit#
|
||||
//https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#verificaton-and-validation
|
||||
|
||||
/*
|
||||
* This inspector supports both standalone openbadge verification, as well as verification of
|
||||
* AchievementCredentials embedded in e.g. CLR.
|
||||
*
|
||||
* When verifying a standalone AchievementCredential, call the run(Resource) method. When verifying
|
||||
* an embedded AchievementCredential, call the run(Resource, Map) method.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Report run(Resource resource) {
|
||||
super.check(resource); //TODO because URIs, this should be a fetch and cache
|
||||
|
||||
if(getBehavior(RESET_CACHES_ON_RUN) == TRUE) {
|
||||
JsonSchemaCache.reset();
|
||||
CachingDocumentLoader.reset();
|
||||
}
|
||||
|
||||
ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
|
||||
JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
|
||||
|
||||
RunContext ctx = new RunContext.Builder()
|
||||
.put(this)
|
||||
.put(resource)
|
||||
.put(Key.JACKSON_OBJECTMAPPER, mapper)
|
||||
.put(Key.JSONPATH_EVALUATOR, jsonPath)
|
||||
.build();
|
||||
|
||||
List<ReportItems> accumulator = new ArrayList<>();
|
||||
int probeCount = 0;
|
||||
|
||||
try {
|
||||
//detect type (png, svg, json, jwt) and extract json data
|
||||
probeCount++;
|
||||
accumulator.add(new CredentialParseProbe().run(resource, ctx));
|
||||
if(broken(accumulator, true)) return abort(ctx, accumulator, probeCount);
|
||||
|
||||
//we expect the above to place a generated object in the context
|
||||
Credential ob = ctx.getGeneratedObject(Credential.ID);
|
||||
|
||||
//call the subinspector method of this
|
||||
Report subReport = this.run(resource, Map.of(Credential.CREDENTIAL_KEY, ob));
|
||||
probeCount += subReport.getSummary().getTotalRun();
|
||||
accumulator.add(subReport);
|
||||
|
||||
//finally, run any user-added probes
|
||||
for(Probe<Credential> probe : userProbes) {
|
||||
probeCount++;
|
||||
accumulator.add(probe.run(ob, ctx));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
accumulator.add(onProbeException(Probe.ID.NO_UNCAUGHT_EXCEPTIONS, resource, e));
|
||||
}
|
||||
|
||||
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Report run(Resource resource, Map<String, GeneratedObject> parentObjects) {
|
||||
|
||||
Credential ob = checkNotNull((Credential)parentObjects.get(CREDENTIAL_KEY));
|
||||
|
||||
ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
|
||||
JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
|
||||
RunContext ctx = new RunContext.Builder()
|
||||
.put(this)
|
||||
.put(resource)
|
||||
.put(Key.JACKSON_OBJECTMAPPER, mapper)
|
||||
.put(Key.JSONPATH_EVALUATOR, jsonPath)
|
||||
.build();
|
||||
|
||||
List<ReportItems> accumulator = new ArrayList<>();
|
||||
int probeCount = 0;
|
||||
|
||||
try {
|
||||
|
||||
//context and type properties
|
||||
Credential.Type type = Type.OpenBadgeCredential;
|
||||
for(Probe<JsonNode> probe : List.of(new ContextPropertyProbe(type), new TypePropertyProbe(type))) {
|
||||
probeCount++;
|
||||
accumulator.add(probe.run(ob.getJson(), ctx));
|
||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||
}
|
||||
|
||||
//canonical schema and inline schemata
|
||||
SchemaKey schema = ob.getSchemaKey().orElseThrow();
|
||||
for(Probe<JsonNode> probe : List.of(new JsonSchemaProbe(schema), new InlineJsonSchemaProbe(schema))) {
|
||||
probeCount++;
|
||||
accumulator.add(probe.run(ob.getJson(), ctx));
|
||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||
}
|
||||
|
||||
//credentialSubject
|
||||
probeCount++;
|
||||
accumulator.add(new CredentialSubjectProbe().run(ob.getJson(), ctx));
|
||||
|
||||
//signatures, proofs
|
||||
probeCount++;
|
||||
if(ob.getProofType() == EXTERNAL){
|
||||
//The credential originally contained in a JWT, validate the jwt and external proof.
|
||||
accumulator.add(new ExternalProofProbe().run(ob, ctx));
|
||||
} else {
|
||||
//The credential not contained in a jwt, must have an internal proof.
|
||||
accumulator.add(new EmbeddedProofProbe().run(ob, ctx));
|
||||
}
|
||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||
|
||||
//check refresh service if we are not already refreshed
|
||||
probeCount++;
|
||||
if(resource.getContext().get(REFRESHED) != TRUE) {
|
||||
Optional<String> newID = checkRefreshService(ob, ctx);
|
||||
if(newID.isPresent()) {
|
||||
return this.run(
|
||||
new UriResource(new URI(newID.get()))
|
||||
.setContext(new ResourceContext(REFRESHED, TRUE)));
|
||||
}
|
||||
}
|
||||
|
||||
//revocation, expiration and issuance
|
||||
for(Probe<Credential> probe : List.of(new RevocationListProbe(),
|
||||
new ExpirationProbe(), new IssuanceProbe())) {
|
||||
probeCount++;
|
||||
accumulator.add(probe.run(ob, ctx));
|
||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||
}
|
||||
|
||||
//embedded endorsements
|
||||
EndorsementInspector endorsementInspector = new EndorsementInspector.Builder().build();
|
||||
|
||||
List<JsonNode> endorsements = asNodeList(ob.getJson(), "$..endorsement", jsonPath);
|
||||
for(JsonNode node : endorsements) {
|
||||
probeCount++;
|
||||
Credential endorsement = new Credential(resource, node);
|
||||
accumulator.add(endorsementInspector.run(resource, Map.of(CREDENTIAL_KEY, endorsement)));
|
||||
}
|
||||
|
||||
//embedded jwt endorsements
|
||||
endorsements = asNodeList(ob.getJson(), "$..endorsementJwt", jsonPath);
|
||||
for(JsonNode node : endorsements) {
|
||||
probeCount++;
|
||||
String jwt = node.asText();
|
||||
JsonNode vcNode = fromJwt(jwt, ctx);
|
||||
Credential endorsement = new Credential(resource, vcNode, jwt);
|
||||
accumulator.add(endorsementInspector.run(resource, Map.of(CREDENTIAL_KEY, endorsement)));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
accumulator.add(onProbeException(Probe.ID.NO_UNCAUGHT_EXCEPTIONS, resource, e));
|
||||
}
|
||||
|
||||
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
||||
|
||||
}
|
||||
|
||||
public static class Builder extends VCInspector.Builder<OB30Inspector.Builder> {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public OB30Inspector build() {
|
||||
set(Specification.OB30);
|
||||
set(ResourceType.OPENBADGE);
|
||||
return new OB30Inspector(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package org.oneedtech.inspect.vc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.oneedtech.inspect.core.Inspector;
|
||||
import org.oneedtech.inspect.core.probe.Outcome;
|
||||
import org.oneedtech.inspect.core.probe.Probe;
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.core.report.Report;
|
||||
import org.oneedtech.inspect.core.report.ReportItems;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* Abstract base for verifiable credentials inspectors/verifiers.
|
||||
* @author mgylling
|
||||
*/
|
||||
public abstract class VCInspector extends Inspector {
|
||||
|
||||
protected <B extends VCInspector.Builder<?>> VCInspector(B builder) {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
protected Report abort(RunContext ctx, List<ReportItems> accumulator, int probeCount) {
|
||||
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
||||
}
|
||||
|
||||
protected boolean broken(List<ReportItems> accumulator) {
|
||||
return broken(accumulator, false);
|
||||
}
|
||||
|
||||
protected boolean broken(List<ReportItems> accumulator, boolean force) {
|
||||
if(!force && getBehavior(Inspector.Behavior.VALIDATOR_FAIL_FAST) == Boolean.FALSE) {
|
||||
return false;
|
||||
}
|
||||
for(ReportItems items : accumulator) {
|
||||
if(items.contains(Outcome.FATAL, Outcome.EXCEPTION)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the AchievementCredential or EndorsementCredential has a “refreshService” property and the type of the
|
||||
* RefreshService object is “1EdTechCredentialRefresh”, you should fetch the refreshed credential from the URL
|
||||
* provided, then start the verification process over using the response as input. If the request fails,
|
||||
* the credential is invalid.
|
||||
*/
|
||||
protected Optional<String> checkRefreshService(Credential crd, RunContext ctx) {
|
||||
JsonNode refreshServiceNode = crd.getJson().get("refreshService");
|
||||
if(refreshServiceNode != null) {
|
||||
JsonNode serviceTypeNode = refreshServiceNode.get("type");
|
||||
if(serviceTypeNode != null && serviceTypeNode.asText().equals("1EdTechCredentialRefresh")) {
|
||||
JsonNode serviceURINode = refreshServiceNode.get("id");
|
||||
if(serviceURINode != null) {
|
||||
return Optional.of(serviceURINode.asText());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
protected static final String REFRESHED = "is.refreshed.credential";
|
||||
|
||||
public abstract static class Builder<B extends VCInspector.Builder<B>> extends Inspector.Builder<B> {
|
||||
final List<Probe<Credential>> probes;
|
||||
|
||||
public Builder() {
|
||||
super();
|
||||
this.probes = new ArrayList<>();
|
||||
}
|
||||
|
||||
public VCInspector.Builder<B> add(Probe<Credential> probe) {
|
||||
probes.add(probe);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package org.oneedtech.inspect.vc.payload;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.oneedtech.inspect.util.code.Defensives.checkTrue;
|
||||
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||
import org.oneedtech.inspect.vc.Credential;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* A credential extractor for JSON files.
|
||||
* @author mgylling
|
||||
*/
|
||||
public final class JsonParser extends PayloadParser {
|
||||
|
||||
@Override
|
||||
public boolean supports(ResourceType type) {
|
||||
return type == ResourceType.JSON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credential parse(Resource resource, RunContext ctx) throws Exception {
|
||||
checkTrue(resource.getType() == ResourceType.JSON);
|
||||
String json = resource.asByteSource().asCharSource(UTF_8).read();
|
||||
JsonNode node = fromString(json, ctx);
|
||||
return new Credential(resource, node);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package org.oneedtech.inspect.vc.payload;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.oneedtech.inspect.util.code.Defensives.checkTrue;
|
||||
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||
import org.oneedtech.inspect.vc.Credential;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* A credential extractor for JWT files.
|
||||
* @author mgylling
|
||||
*/
|
||||
public final class JwtParser extends PayloadParser {
|
||||
|
||||
@Override
|
||||
public boolean supports(ResourceType type) {
|
||||
return type == ResourceType.JWT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credential parse(Resource resource, RunContext ctx) throws Exception {
|
||||
checkTrue(resource.getType() == ResourceType.JWT);
|
||||
String jwt = resource.asByteSource().asCharSource(UTF_8).read();
|
||||
JsonNode node = fromJwt(jwt, ctx);
|
||||
return new Credential(resource, node, jwt);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package org.oneedtech.inspect.vc.payload;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Base64.Decoder;
|
||||
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||
import org.oneedtech.inspect.vc.Credential;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
/**
|
||||
* Abstract base for extracting Credential instances from payloads.
|
||||
* @author mgylling
|
||||
*/
|
||||
public abstract class PayloadParser {
|
||||
|
||||
public abstract boolean supports(ResourceType type);
|
||||
|
||||
public abstract Credential parse(Resource source, RunContext ctx) throws Exception;
|
||||
|
||||
protected static JsonNode fromString(String json, RunContext context) throws Exception {
|
||||
return ((ObjectMapper)context.get(RunContext.Key.JACKSON_OBJECTMAPPER)).readTree(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode as per https://www.imsglobal.org/spec/ob/v3p0/#jwt-proof
|
||||
* @return The decoded JSON String
|
||||
*/
|
||||
public static JsonNode fromJwt(String jwt, RunContext context) throws Exception {
|
||||
List<String> parts = Splitter.on('.').splitToList(jwt);
|
||||
if(parts.size() != 3) throw new IllegalArgumentException("invalid jwt");
|
||||
|
||||
final Decoder decoder = Base64.getUrlDecoder();
|
||||
/*
|
||||
* For this step we are only deserializing the stored badge out of the payload.
|
||||
* The entire jwt is stored separately for signature verification later.
|
||||
*/
|
||||
String jwtPayload = new String(decoder.decode(parts.get(1)));
|
||||
|
||||
//Deserialize and fetch the 'vc' node from the object
|
||||
JsonNode outerPayload = fromString(jwtPayload, context);
|
||||
JsonNode vcNode = outerPayload.get("vc");
|
||||
|
||||
return vcNode;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.oneedtech.inspect.vc.payload;
|
||||
|
||||
import static org.oneedtech.inspect.util.code.Defensives.checkNotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
|
||||
/**
|
||||
* A factory to create PayloadParser instances for various resource types.
|
||||
* @author mgylling
|
||||
*/
|
||||
public class PayloadParserFactory {
|
||||
private static final Iterable<PayloadParser> parsers = List.of(
|
||||
new PngParser(), new SvgParser(),
|
||||
new JsonParser(), new JwtParser());
|
||||
|
||||
public static PayloadParser of(Resource resource) {
|
||||
checkNotNull(resource.getType());
|
||||
for(PayloadParser cex : parsers) {
|
||||
if(cex.supports(resource.getType())) return cex;
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package org.oneedtech.inspect.vc.payload;
|
||||
|
||||
import static org.oneedtech.inspect.util.code.Defensives.checkTrue;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||
import org.oneedtech.inspect.vc.Credential;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* A credential extractor for PNG images.
|
||||
* @author mgylling
|
||||
*/
|
||||
public final class PngParser extends PayloadParser {
|
||||
|
||||
@Override
|
||||
public boolean supports(ResourceType type) {
|
||||
return type == ResourceType.PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credential parse(Resource resource, RunContext ctx) throws Exception {
|
||||
|
||||
checkTrue(resource.getType() == ResourceType.PNG);
|
||||
|
||||
try(InputStream is = resource.asByteSource().openStream()) {
|
||||
|
||||
ImageReader imageReader = ImageIO.getImageReadersByFormatName("png").next();
|
||||
imageReader.setInput(ImageIO.createImageInputStream(is), true);
|
||||
IIOMetadata metadata = imageReader.getImageMetadata(0);
|
||||
|
||||
String vcString = null;
|
||||
String jwtString = null;
|
||||
String formatSearch = null;
|
||||
JsonNode vcNode = null;
|
||||
|
||||
String[] names = metadata.getMetadataFormatNames();
|
||||
int length = names.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
//Check all names rather than limiting to PNG format to remain malleable through any library changes. (Could limit to "javax_imageio_png_1.0")
|
||||
formatSearch = getOpenBadgeCredentialNodeText(metadata.getAsTree(names[i]));
|
||||
if(formatSearch != null) {
|
||||
vcString = formatSearch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(vcString == null) {
|
||||
throw new IllegalArgumentException("No credential inside PNG");
|
||||
}
|
||||
|
||||
vcString = vcString.trim();
|
||||
if(vcString.charAt(0) != '{'){
|
||||
//This is a jwt. Fetch either the 'vc' out of the payload and save the string for signature verification.
|
||||
jwtString = vcString;
|
||||
vcNode = fromJwt(vcString, ctx);
|
||||
}
|
||||
else {
|
||||
vcNode = fromString(vcString, ctx);
|
||||
}
|
||||
|
||||
return new Credential(resource, vcNode, jwtString);
|
||||
}
|
||||
}
|
||||
|
||||
private String getOpenBadgeCredentialNodeText(Node node){
|
||||
NamedNodeMap attributes = node.getAttributes();
|
||||
|
||||
//If this node is labeled with the attribute keyword: 'openbadgecredential' it is the right one.
|
||||
Node keyword = attributes.getNamedItem("keyword");
|
||||
if(keyword != null && keyword.getNodeValue().equals("openbadgecredential")){
|
||||
Node textAttribute = attributes.getNamedItem("text");
|
||||
if(textAttribute != null) {
|
||||
return textAttribute.getNodeValue();
|
||||
}
|
||||
}
|
||||
|
||||
//iterate over all children depth first and search for the credential node.
|
||||
Node child = node.getFirstChild();
|
||||
while (child != null) {
|
||||
String nodeValue = getOpenBadgeCredentialNodeText(child);
|
||||
if(nodeValue != null) {
|
||||
return nodeValue;
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
|
||||
//Return null if we haven't found anything at this recursive depth.
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package org.oneedtech.inspect.vc.payload;
|
||||
|
||||
import static org.oneedtech.inspect.util.code.Defensives.checkTrue;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.events.Attribute;
|
||||
import javax.xml.stream.events.Characters;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.util.code.Defensives;
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||
import org.oneedtech.inspect.util.xml.XMLInputFactoryCache;
|
||||
import org.oneedtech.inspect.vc.Credential;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* A credential extractor for SVG documents.
|
||||
* @author mgylling
|
||||
*/
|
||||
public final class SvgParser extends PayloadParser {
|
||||
|
||||
@Override
|
||||
public boolean supports(ResourceType type) {
|
||||
return type == ResourceType.SVG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credential parse(Resource resource, RunContext ctx) throws Exception {
|
||||
|
||||
checkTrue(resource.getType() == ResourceType.SVG);
|
||||
|
||||
try(InputStream is = resource.asByteSource().openStream()) {
|
||||
XMLEventReader reader = XMLInputFactoryCache.getInstance().createXMLEventReader(is);
|
||||
while(reader.hasNext()) {
|
||||
XMLEvent ev = reader.nextEvent();
|
||||
if(isEndElem(ev, OB_CRED_ELEM)) break;
|
||||
if(isStartElem(ev, OB_CRED_ELEM)) {
|
||||
Attribute verifyAttr = ev.asStartElement().getAttributeByName(OB_CRED_VERIFY_ATTR);
|
||||
if(verifyAttr != null) {
|
||||
String jwt = verifyAttr.getValue();
|
||||
JsonNode node = fromJwt(jwt, ctx);
|
||||
return new Credential(resource, node, jwt);
|
||||
} else {
|
||||
while(reader.hasNext()) {
|
||||
ev = reader.nextEvent();
|
||||
if(isEndElem(ev, OB_CRED_ELEM)) break;
|
||||
if(ev.getEventType() == XMLEvent.CHARACTERS) {
|
||||
Characters chars = ev.asCharacters();
|
||||
if(!chars.isWhiteSpace()) {
|
||||
JsonNode node = fromString(chars.getData(), ctx);
|
||||
return new Credential(resource, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} //while(reader.hasNext()) {
|
||||
}
|
||||
throw new IllegalArgumentException("No credential inside SVG");
|
||||
|
||||
}
|
||||
|
||||
private boolean isEndElem(XMLEvent ev, QName name) {
|
||||
return ev.isEndElement() && ev.asEndElement().getName().equals(name);
|
||||
}
|
||||
|
||||
private boolean isStartElem(XMLEvent ev, QName name) {
|
||||
return ev.isStartElement() && ev.asStartElement().getName().equals(name);
|
||||
}
|
||||
|
||||
private static final QName OB_CRED_ELEM = new QName("https://purl.imsglobal.org/ob/v3p0", "credential");
|
||||
private static final QName OB_CRED_VERIFY_ATTR = new QName("verify");
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import static org.oneedtech.inspect.vc.Credential.Type.*;
|
||||
|
||||
import static org.oneedtech.inspect.util.code.Defensives.checkNotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.Credential;
|
||||
|
||||
import org.oneedtech.inspect.vc.util.JsonNodeUtil;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* A Probe that verifies a credential's context property.
|
||||
*
|
||||
* @author mgylling
|
||||
*/
|
||||
public class ContextPropertyProbe extends Probe<JsonNode> {
|
||||
private final Credential.Type type;
|
||||
|
||||
public ContextPropertyProbe(Credential.Type type) {
|
||||
super(ID);
|
||||
this.type = checkNotNull(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReportItems run(JsonNode root, RunContext ctx) throws Exception {
|
||||
|
||||
ArrayNode contextNode = (ArrayNode) root.get("@context");
|
||||
if (contextNode == null) {
|
||||
return notRun("No @context property", ctx);
|
||||
}
|
||||
|
||||
List<String> expected = values.get(values.keySet()
|
||||
.stream()
|
||||
.filter(s->s.contains(type))
|
||||
.findFirst()
|
||||
.orElseThrow(()-> new IllegalArgumentException(type.name() + " not recognized")));
|
||||
|
||||
List<String> given = JsonNodeUtil.asStringList(contextNode);
|
||||
int pos = 0;
|
||||
for (String uri : expected) {
|
||||
if ((given.size() < pos + 1) || !given.get(pos).equals(uri)) {
|
||||
return error("missing required @context uri " + uri + " at position " + (pos + 1), ctx);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
return success(ctx);
|
||||
}
|
||||
|
||||
private final static Map<Set<Credential.Type>, List<String>> values = new ImmutableMap.Builder<Set<Credential.Type>, List<String>>()
|
||||
.put(Set.of(OpenBadgeCredential, AchievementCredential, EndorsementCredential),
|
||||
List.of("https://www.w3.org/2018/credentials/v1",
|
||||
//"https://imsglobal.github.io/openbadges-specification/context.json")) //dev legacy
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/context.json"))
|
||||
.put(Set.of(ClrCredential),
|
||||
List.of("https://www.w3.org/2018/credentials/v1",
|
||||
// "https://dc.imsglobal.org/draft/clr/v2p0/context", //dev legacy
|
||||
// "https://imsglobal.github.io/openbadges-specification/context.json")) //dev legacy
|
||||
"https://purl.imsglobal.org/spec/clr/v2p0/context.json",
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/context.json"))
|
||||
|
||||
.build();
|
||||
|
||||
public static final String ID = ContextPropertyProbe.class.getSimpleName();
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
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.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||
import org.oneedtech.inspect.util.resource.detect.TypeDetector;
|
||||
import org.oneedtech.inspect.vc.Credential;
|
||||
import org.oneedtech.inspect.vc.payload.PayloadParserFactory;
|
||||
|
||||
/**
|
||||
* A probe that verifies that the incoming credential resource is of a recognized payload type
|
||||
* and if so extracts and stores the VC json data (a 'Credential' instance)
|
||||
* in the RunContext.
|
||||
* @author mgylling
|
||||
*/
|
||||
public class CredentialParseProbe extends Probe<Resource> {
|
||||
|
||||
@Override
|
||||
public ReportItems run(Resource resource, RunContext context) throws Exception {
|
||||
|
||||
try {
|
||||
|
||||
//TODO if .detect reads from a URIResource twice. Cache the resource on first call.
|
||||
|
||||
Optional<ResourceType> type = Optional.ofNullable(resource.getType());
|
||||
if(type.isEmpty() || type.get() == ResourceType.UNKNOWN) {
|
||||
type = TypeDetector.detect(resource, true);
|
||||
if(type.isEmpty()) {
|
||||
//TODO if URI fetch, TypeDetector likely to fail
|
||||
System.err.println("typedetector fail: extend behavior here");
|
||||
return fatal("Could not detect credential payload type", context);
|
||||
} else {
|
||||
resource.setType(type.get());
|
||||
}
|
||||
}
|
||||
|
||||
if(!Credential.RECOGNIZED_PAYLOAD_TYPES.contains(type.get())) {
|
||||
return fatal("Payload type not supported: " + type.get().getName(), context);
|
||||
}
|
||||
|
||||
Credential crd = PayloadParserFactory.of(resource).parse(resource, context);
|
||||
context.addGeneratedObject(crd);
|
||||
return success(this, context);
|
||||
|
||||
} catch (Exception e) {
|
||||
return fatal("Error while parsing credential: " + e.getMessage(), context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<JsonNode> {
|
||||
|
||||
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();
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.net.URI;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
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.Credential;
|
||||
import org.oneedtech.inspect.vc.util.CachingDocumentLoader;
|
||||
|
||||
import com.apicatalog.ld.DocumentError;
|
||||
import com.apicatalog.multibase.Multibase;
|
||||
import com.apicatalog.vc.processor.StatusVerifier;
|
||||
import com.danubetech.verifiablecredentials.VerifiableCredential;
|
||||
|
||||
import info.weboftrust.ldsignatures.verifier.Ed25519Signature2020LdVerifier;
|
||||
|
||||
/**
|
||||
* A Probe that verifies a credential's embedded proof.
|
||||
* @author mgylling
|
||||
*/
|
||||
public class EmbeddedProofProbe extends Probe<Credential> {
|
||||
|
||||
public EmbeddedProofProbe() {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Using verifiable-credentials-java (https://github.com/danubetech/verifiable-credentials-java)
|
||||
*/
|
||||
@Override
|
||||
public ReportItems run(Credential crd, RunContext ctx) throws Exception {
|
||||
|
||||
//TODO check that proof is Ed25519 - issue error if not ("type": "Ed25519Signature2020",
|
||||
//TODO check value "proofPurpose": "assertionMethod", if not error
|
||||
|
||||
VerifiableCredential vc = VerifiableCredential.fromJson(new StringReader(crd.getJson().toString()));
|
||||
vc.setDocumentLoader(new CachingDocumentLoader());
|
||||
|
||||
URI method = vc.getLdProof().getVerificationMethod();
|
||||
|
||||
// The verification method must dereference to an Ed25519VerificationKey2020.
|
||||
// Danubetech's Ed25519Signature2020LdVerifier expects the decoded public key
|
||||
// from the Ed25519VerificationKey2020 (32 bytes).
|
||||
|
||||
String publicKeyMultibase = "";
|
||||
|
||||
// Formats accepted:
|
||||
//
|
||||
// [controller]#[publicKeyMultibase]
|
||||
// did:key:[publicKeyMultibase]
|
||||
// [publicKeyMultibase]
|
||||
|
||||
// TODO fourth format that we don't support yet: a URL that returns a Ed25519VerificationKey2020
|
||||
// if starts with http and does not have hashcode, try fetch and see if returns Ed25519VerificationKey2020
|
||||
// property is publicKeyMultibase
|
||||
|
||||
if (method.toString().contains("#")) {
|
||||
publicKeyMultibase = method.getFragment();
|
||||
} else {
|
||||
if (method.toString().startsWith("did")) {
|
||||
String didScheme = method.getSchemeSpecificPart();
|
||||
if (didScheme.startsWith("key:")) {
|
||||
publicKeyMultibase = didScheme.substring(4);
|
||||
} else {
|
||||
return error("Unknown verification method: " + method.toString(), ctx);
|
||||
}
|
||||
} else {
|
||||
publicKeyMultibase = method.toString();
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the Multibase to Multicodec and check that it is an Ed25519 public key
|
||||
byte[] publicKeyMulticodec;
|
||||
try {
|
||||
publicKeyMulticodec = Multibase.decode(publicKeyMultibase);
|
||||
if (publicKeyMulticodec[0] != -19 || publicKeyMulticodec[1] != 1) {
|
||||
return error("Verification method does not contain an Ed25519 public key", ctx);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return error("Verification method is invalid: " + e.getMessage(), ctx);
|
||||
}
|
||||
|
||||
// Extract the publicKey bytes from the Multicodec
|
||||
byte[] publicKey = Arrays.copyOfRange(publicKeyMulticodec, 2, publicKeyMulticodec.length);
|
||||
|
||||
Ed25519Signature2020LdVerifier verifier = new Ed25519Signature2020LdVerifier(publicKey);
|
||||
|
||||
//TODO find out whether we also should check that controller matches issuer ID:
|
||||
// if [controller]#[publicKeyMultibase] format - check [controller] segment
|
||||
// if did:key:[publicKeyMultibase] format: issuer ID must match the entire URI
|
||||
// if [publicKeyMultibase] -- don't check issuer ID. Maybe we should warn about this syntax.
|
||||
|
||||
try {
|
||||
boolean verify = verifier.verify(vc);
|
||||
if (!verify) {
|
||||
return error("Embedded proof verification failed.", ctx);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return fatal("Embedded proof verification failed:" + e.getMessage(), ctx);
|
||||
}
|
||||
|
||||
return success(ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Note: if using com.apicatalog Iron, we get a generic VC verifier that
|
||||
* will test other stuff than the Proof. So sometimes it may be that
|
||||
* Iron internally retests something that we're already testing out in the
|
||||
* Inspector class (e.g. expiration). But use this for now -- and remember
|
||||
* that this probe is only run if the given credential has internal proof
|
||||
* (aka is not a jwt).
|
||||
*/
|
||||
|
||||
// /*
|
||||
// * Using iron-verifiable-credentials (https://github.com/filip26/iron-verifiable-credentials)
|
||||
// */
|
||||
// @Override
|
||||
// public ReportItems run(Credential crd, RunContext ctx) throws Exception {
|
||||
// JsonDocument jsonDoc = JsonDocument.of(new StringReader(crd.getJson().toString()));
|
||||
// JsonObject json = jsonDoc.getJsonContent().get().asJsonObject();
|
||||
// try {
|
||||
// Vc.verify(json)
|
||||
// .loader(new CachingDocumentLoader())
|
||||
// .useBundledContexts(false) //we control the cache in the loader
|
||||
// .statusVerifier(new IronNoopStatusVerifier())
|
||||
// //.domain(...)
|
||||
// //.didResolver(...)
|
||||
// .isValid();
|
||||
// } catch (DocumentError e) {
|
||||
// return error(e.getType() + " " + e.getSubject(), ctx);
|
||||
// } catch (VerificationError e) {
|
||||
// //System.err.println(e.getCode() + " (ProofVerifierProbe)");
|
||||
// if(e.getCode() == Code.Internal) {
|
||||
// return exception(e.getMessage(), ctx.getResource());
|
||||
// } else if(e.getCode().equals(Code.Expired)) {
|
||||
// //handled by other probe
|
||||
// } else {
|
||||
// return fatal(e.getCode().name() + " " + e.getMessage(), ctx);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// return success(ctx);
|
||||
// }
|
||||
|
||||
private static final class IronNoopStatusVerifier implements StatusVerifier {
|
||||
@Override
|
||||
public void verify(Status status) throws DocumentError, VerifyError {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
public static final String ID = EmbeddedProofProbe.class.getSimpleName();
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
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.Credential;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* A Probe that verifies a credential's expiration status
|
||||
* @author mgylling
|
||||
*/
|
||||
public class ExpirationProbe extends Probe<Credential> {
|
||||
|
||||
public ExpirationProbe() {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReportItems run(Credential crd, RunContext ctx) throws Exception {
|
||||
/*
|
||||
* If the AchievementCredential or EndorsementCredential has an “expirationDate” property
|
||||
* and the expiration date is prior to the current date, the credential has expired.
|
||||
*/
|
||||
JsonNode node = crd.getJson().get("expirationDate");
|
||||
if(node != null) {
|
||||
try {
|
||||
ZonedDateTime expirationDate = ZonedDateTime.parse(node.textValue());
|
||||
if (ZonedDateTime.now().isAfter(expirationDate)) {
|
||||
return fatal("The credential has expired (expiration date was " + node.asText() + ").", ctx);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return exception("Error while checking expirationDate: " + e.getMessage(), ctx.getResource());
|
||||
}
|
||||
}
|
||||
return success(ctx);
|
||||
}
|
||||
|
||||
public static final String ID = ExpirationProbe.class.getSimpleName();
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import static org.oneedtech.inspect.util.code.Defensives.checkTrue;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.Base64.Decoder;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
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.Credential;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
|
||||
import com.auth0.jwt.exceptions.InvalidClaimException;
|
||||
import com.auth0.jwt.exceptions.SignatureVerificationException;
|
||||
import com.auth0.jwt.exceptions.TokenExpiredException;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
/**
|
||||
* A Probe that verifies credential external proof (jwt)
|
||||
* @author mlyon
|
||||
*/
|
||||
public class ExternalProofProbe extends Probe<Credential> {
|
||||
|
||||
public ExternalProofProbe() {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReportItems run(Credential crd, RunContext ctx) throws Exception {
|
||||
try {
|
||||
verifySignature(crd, ctx);
|
||||
} catch (Exception e) {
|
||||
return fatal("Error verifying jwt signature: " + e.getMessage(), ctx);
|
||||
}
|
||||
return success(ctx);
|
||||
}
|
||||
|
||||
private void verifySignature(Credential crd, RunContext ctx) throws Exception {
|
||||
checkTrue(crd.getJwt().isPresent(), "no jwt supplied");
|
||||
checkTrue(crd.getJwt().get().length() > 0, "no jwt supplied");
|
||||
|
||||
DecodedJWT decodedJwt = null;
|
||||
String jwt = crd.getJwt().get();
|
||||
|
||||
List<String> parts = Splitter.on('.').splitToList(jwt);
|
||||
if(parts.size() != 3) throw new IllegalArgumentException("invalid jwt");
|
||||
|
||||
final Decoder decoder = Base64.getUrlDecoder();
|
||||
String joseHeader = new String(decoder.decode(parts.get(0)));
|
||||
|
||||
ObjectMapper mapper = ((ObjectMapper)ctx.get(RunContext.Key.JACKSON_OBJECTMAPPER));
|
||||
JsonNode headerObj = mapper.readTree(joseHeader);
|
||||
|
||||
//MUST be "RS256"
|
||||
JsonNode alg = headerObj.get("alg");
|
||||
if(alg == null || !alg.textValue().equals("RS256")) { throw new Exception("alg must be present and must be 'RS256'"); }
|
||||
|
||||
//TODO: decoded jwt will check timestamps, but shall we explicitly break these out?
|
||||
|
||||
//Option 1, fetch directly from header
|
||||
JsonNode jwk = headerObj.get("jwk");
|
||||
|
||||
//Option 2, fetch from a hosting url
|
||||
JsonNode kid = headerObj.get("kid");
|
||||
|
||||
if(jwk == null && kid == null) { throw new Exception("Key must present in either jwk or kid value."); }
|
||||
if(kid != null){
|
||||
//Load jwk JsonNode from url and do the rest the same below.
|
||||
//TODO Consider additional testing.
|
||||
String kidUrl = kid.textValue();
|
||||
String jwkResponse = fetchJwk(kidUrl);
|
||||
if(jwkResponse == null) { throw new Exception("Unable to retrieve jwk value from url specified in kid."); }
|
||||
|
||||
jwk = mapper.readTree(jwkResponse);
|
||||
}
|
||||
|
||||
//Clean up may be required. Currently need to cleanse extra double quoting.
|
||||
String modulusString = jwk.get("n").textValue();
|
||||
String exponentString = jwk.get("e").textValue();
|
||||
|
||||
BigInteger modulus = new BigInteger(1, decoder.decode(modulusString));
|
||||
BigInteger exponent = new BigInteger(1, decoder.decode(exponentString));
|
||||
|
||||
PublicKey pub = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, exponent));
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey)pub, null);
|
||||
JWTVerifier verifier = JWT.require(algorithm)
|
||||
.build(); //Reusable verifier instance
|
||||
try {
|
||||
decodedJwt = verifier.verify(jwt);
|
||||
}
|
||||
catch(SignatureVerificationException ex){
|
||||
throw new Exception("JWT Invalid signature", ex);
|
||||
}
|
||||
catch(AlgorithmMismatchException ex){
|
||||
throw new Exception("JWT Algorithm mismatch", ex);
|
||||
}
|
||||
catch(TokenExpiredException ex){
|
||||
throw new Exception("JWT Token expired", ex);
|
||||
}
|
||||
catch(InvalidClaimException ex){
|
||||
throw new Exception("JWT, one or more claims are invalid", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String fetchJwk(String fetchUrl){
|
||||
String responseString = null;
|
||||
|
||||
try {
|
||||
CloseableHttpClient client = HttpClients.createDefault();
|
||||
HttpGet httpGet = new HttpGet(fetchUrl);
|
||||
|
||||
CloseableHttpResponse response = client.execute(httpGet);
|
||||
|
||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
||||
HttpEntity entity = response.getEntity();
|
||||
responseString = EntityUtils.toString(entity, "UTF-8");
|
||||
}
|
||||
|
||||
client.close();
|
||||
}
|
||||
catch(Exception ex){
|
||||
responseString = null;
|
||||
}
|
||||
|
||||
return responseString;
|
||||
}
|
||||
|
||||
public static final String ID = ExternalProofProbe.class.getSimpleName();
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.oneedtech.inspect.core.probe.Probe;
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.core.probe.json.JsonSchemaProbe;
|
||||
import org.oneedtech.inspect.core.report.ReportItems;
|
||||
import org.oneedtech.inspect.schema.SchemaKey;
|
||||
import org.oneedtech.inspect.vc.Credential;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
/**
|
||||
* Detect inline schemas in a credential and run them.
|
||||
* @author mgylling
|
||||
*/
|
||||
public class InlineJsonSchemaProbe extends Probe<JsonNode> {
|
||||
private static final Set<String> types = Set.of("1EdTechJsonSchemaValidator2019");
|
||||
private SchemaKey skip;
|
||||
|
||||
public InlineJsonSchemaProbe() {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
public InlineJsonSchemaProbe(SchemaKey skip) {
|
||||
super(ID);
|
||||
this.skip = skip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReportItems run(JsonNode root, RunContext ctx) throws Exception {
|
||||
List<ReportItems> accumulator = new ArrayList<>();
|
||||
Set<String> ioErrors = new HashSet<>();
|
||||
|
||||
//note - we don't get deep nested ones in e.g. EndorsementCredential
|
||||
JsonNode credentialSchemaNode = root.get("credentialSchema");
|
||||
if(credentialSchemaNode == null) return success(ctx);
|
||||
|
||||
ArrayNode schemas = (ArrayNode) credentialSchemaNode; //TODO guard this cast
|
||||
|
||||
for(JsonNode schemaNode : schemas) {
|
||||
JsonNode typeNode = schemaNode.get("type");
|
||||
if(typeNode == null || !types.contains(typeNode.asText())) continue;
|
||||
JsonNode idNode = schemaNode.get("id");
|
||||
if(idNode == null) continue;
|
||||
String id = idNode.asText().strip();
|
||||
if(ioErrors.contains(id)) continue;
|
||||
if(equals(skip, id)) continue;
|
||||
try {
|
||||
accumulator.add(new JsonSchemaProbe(id).run(root, ctx));
|
||||
} catch (Exception e) {
|
||||
if(!ioErrors.contains(id)) {
|
||||
ioErrors.add(id);
|
||||
accumulator.add(error("Could not read schema resource " + id, ctx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ReportItems(accumulator);
|
||||
}
|
||||
|
||||
private boolean equals(SchemaKey key, String id) {
|
||||
if(key == null) return false;
|
||||
return key.getCanonicalURI().equals(id);
|
||||
}
|
||||
|
||||
public static final String ID = InlineJsonSchemaProbe.class.getSimpleName();
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
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.Credential;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* A Probe that verifies a credential's issuance status
|
||||
* @author mgylling
|
||||
*/
|
||||
public class IssuanceProbe extends Probe<Credential> {
|
||||
|
||||
public IssuanceProbe() {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReportItems run(Credential crd, RunContext ctx) throws Exception {
|
||||
/*
|
||||
* If the AchievementCredential or EndorsementCredential “issuanceDate”
|
||||
* property after the current date, the credential is not yet valid.
|
||||
*/
|
||||
JsonNode node = crd.getJson().get("issuanceDate");
|
||||
if(node != null) {
|
||||
try {
|
||||
ZonedDateTime issuanceDate = ZonedDateTime.parse(node.textValue());
|
||||
if (issuanceDate.isAfter(ZonedDateTime.now())) {
|
||||
return fatal("The credential is not yet issued (issuance date is " + node.asText() + ").", ctx);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return exception("Error while checking issuanceDate: " + e.getMessage(), ctx.getResource());
|
||||
}
|
||||
}
|
||||
return success(ctx);
|
||||
}
|
||||
|
||||
public static final String ID = IssuanceProbe.class.getSimpleName();
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import static org.oneedtech.inspect.core.probe.RunContext.Key.JACKSON_OBJECTMAPPER;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
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.Credential;
|
||||
import org.oneedtech.inspect.vc.util.JsonNodeUtil;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* A Probe that verifies a credential's revocation status.
|
||||
* @author mgylling
|
||||
*/
|
||||
public class RevocationListProbe extends Probe<Credential> {
|
||||
|
||||
public RevocationListProbe() {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReportItems run(Credential crd, RunContext ctx) throws Exception {
|
||||
|
||||
/*
|
||||
* If the AchievementCredential or EndorsementCredential has a “credentialStatus” property
|
||||
* and the type of the CredentialStatus object is “1EdTechRevocationList”, fetch the
|
||||
* credential status from the URL provided. If the request is unsuccessful,
|
||||
* report a warning, not an error.
|
||||
*/
|
||||
|
||||
JsonNode credentialStatus = crd.getJson().get("credentialStatus");
|
||||
if(credentialStatus != null) {
|
||||
JsonNode type = credentialStatus.get("type");
|
||||
if(type != null && type.asText().strip().equals("1EdTechRevocationList")) {
|
||||
JsonNode listID = credentialStatus.get("id");
|
||||
if(listID != null) {
|
||||
try {
|
||||
URL url = new URI(listID.asText().strip()).toURL();
|
||||
try (InputStream is = url.openStream()) {
|
||||
JsonNode revocList = ((ObjectMapper)ctx.get(JACKSON_OBJECTMAPPER)).readTree(is.readAllBytes());
|
||||
|
||||
/* To check if a credential has been revoked, the verifier issues a GET request
|
||||
* to the URL of the issuer's 1EdTech Revocation List Status Method. If the
|
||||
* credential's id is in the list of revokedCredentials and the value of
|
||||
* revoked is true or ommitted, the issuer has revoked the credential. */
|
||||
|
||||
JsonNode crdID = crd.getJson().get("id"); //TODO these != checks sb removed (trigger warning)
|
||||
if(crdID != null) {
|
||||
List<JsonNode> list = JsonNodeUtil.asNodeList(revocList.get("revokedCredentials"));
|
||||
if(list != null) {
|
||||
for(JsonNode item : list) {
|
||||
JsonNode revID = item.get("id");
|
||||
JsonNode revoked = item.get("revoked");
|
||||
if(revID != null && revID.equals(crdID) && (revoked == null || revoked.asBoolean())) {
|
||||
return fatal("Credential has been revoked", ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return warning("Error when fetching credentialStatus resource " + e.getMessage(), ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return success(ctx);
|
||||
}
|
||||
|
||||
public static final String ID = RevocationListProbe.class.getSimpleName();
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import static org.oneedtech.inspect.util.code.Defensives.checkNotNull;
|
||||
|
||||
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.Credential;
|
||||
import org.oneedtech.inspect.vc.Credential.Type;
|
||||
import org.oneedtech.inspect.vc.util.JsonNodeUtil;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
/**
|
||||
* A Probe that verifies a credential's type property.
|
||||
*
|
||||
* @author mgylling
|
||||
*/
|
||||
public class TypePropertyProbe extends Probe<JsonNode> {
|
||||
private final Credential.Type expected;
|
||||
|
||||
public TypePropertyProbe(Credential.Type expected) {
|
||||
super(ID);
|
||||
this.expected = checkNotNull(expected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReportItems run(JsonNode root, RunContext ctx) throws Exception {
|
||||
|
||||
ArrayNode typeNode = (ArrayNode) root.get("type");
|
||||
if (typeNode == null)
|
||||
return fatal("No type property", ctx);
|
||||
|
||||
List<String> values = JsonNodeUtil.asStringList(typeNode);
|
||||
|
||||
if (!values.contains("VerifiableCredential")) {
|
||||
return fatal("The type property does not contain the entry 'VerifiableCredential'", ctx);
|
||||
}
|
||||
|
||||
if (expected == Credential.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 == Credential.Type.ClrCredential) {
|
||||
if (!values.contains("ClrCredential")) {
|
||||
return fatal("The type property does not contain the entry 'ClrCredential'", ctx);
|
||||
}
|
||||
} else if (expected == Credential.Type.EndorsementCredential) {
|
||||
if (!values.contains("EndorsementCredential")) {
|
||||
return fatal("The type property does not contain the entry 'EndorsementCredential'", ctx);
|
||||
}
|
||||
} else {
|
||||
// TODO implement
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
return success(ctx);
|
||||
}
|
||||
|
||||
public static final String ID = TypePropertyProbe.class.getSimpleName();
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package org.oneedtech.inspect.vc.util;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.oneedtech.inspect.util.code.Tuple;
|
||||
|
||||
import com.apicatalog.jsonld.JsonLdError;
|
||||
import com.apicatalog.jsonld.JsonLdErrorCode;
|
||||
import com.apicatalog.jsonld.document.Document;
|
||||
import com.apicatalog.jsonld.document.JsonDocument;
|
||||
import com.apicatalog.jsonld.loader.DocumentLoader;
|
||||
import com.apicatalog.jsonld.loader.DocumentLoaderOptions;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.Resources;
|
||||
|
||||
/**
|
||||
* A com.apicatalog DocumentLoader with a threadsafe static cache.
|
||||
*
|
||||
* @author mgylling
|
||||
*/
|
||||
public class CachingDocumentLoader implements DocumentLoader {
|
||||
|
||||
@Override
|
||||
public Document loadDocument(URI url, DocumentLoaderOptions options) throws JsonLdError {
|
||||
Tuple<String, DocumentLoaderOptions> tpl = new Tuple<>(url.toASCIIString(), options);
|
||||
try {
|
||||
return documentCache.get(tpl);
|
||||
} catch (Exception e) {
|
||||
logger.error("documentCache not able to load {}", url);
|
||||
throw new JsonLdError(JsonLdErrorCode.INVALID_REMOTE_CONTEXT, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static final ImmutableMap<String, URL> bundled = ImmutableMap.<String, URL>builder()
|
||||
.put("https://purl.imsglobal.org/spec/clr/v2p0/context.json",Resources.getResource("contexts/clr-v2p0.json"))
|
||||
.put("https://purl.imsglobal.org/spec/ob/v3p0/context.json",Resources.getResource("contexts/ob-v3p0.json"))
|
||||
.put("https://imsglobal.github.io/openbadges-specification/context.json",Resources.getResource("contexts/obv3x.jsonld"))
|
||||
.put("https://www.w3.org/ns/did/v1", Resources.getResource("contexts/did-v1.jsonld"))
|
||||
.put("https://www.w3.org/ns/odrl.jsonld", Resources.getResource("contexts/odrl.jsonld"))
|
||||
.put("https://w3id.org/security/suites/ed25519-2020/v1",Resources.getResource("contexts/security-suites-ed25519-2020-v1.jsonld"))
|
||||
.put("https://www.w3.org/2018/credentials/v1", Resources.getResource("contexts/2018-credentials-v1.jsonld"))
|
||||
.put("https://w3id.org/security/v1", Resources.getResource("contexts/security-v1.jsonld"))
|
||||
.put("https://w3id.org/security/v2", Resources.getResource("contexts/security-v2.jsonld"))
|
||||
.put("https://w3id.org/security/v3", Resources.getResource("contexts/security-v3-unstable.jsonld"))
|
||||
.put("https://w3id.org/security/bbs/v1", Resources.getResource("contexts/security-bbs-v1.jsonld"))
|
||||
.put("https://w3id.org/security/suites/secp256k1-2019/v1", Resources.getResource("contexts/suites-secp256k1-2019.jsonld"))
|
||||
.put("https://w3id.org/security/suites/ed25519-2018/v1", Resources.getResource("contexts/suites-ed25519-2018.jsonld"))
|
||||
.put("https://w3id.org/security/suites/x25519-2019/v1", Resources.getResource("contexts/suites-x25519-2019.jsonld"))
|
||||
.put("https://w3id.org/security/suites/jws-2020/v1", Resources.getResource("contexts/suites-jws-2020.jsonld"))
|
||||
|
||||
.build();
|
||||
|
||||
static final LoadingCache<Tuple<String, DocumentLoaderOptions>, Document> documentCache = CacheBuilder.newBuilder()
|
||||
.initialCapacity(32).maximumSize(64).expireAfterAccess(Duration.ofHours(24))
|
||||
.build(new CacheLoader<Tuple<String, DocumentLoaderOptions>, Document>() {
|
||||
public Document load(final Tuple<String, DocumentLoaderOptions> id) throws Exception {
|
||||
try (InputStream is = bundled.keySet().contains(id.t1)
|
||||
? bundled.get(id.t1).openStream()
|
||||
: new URI(id.t1).toURL().openStream();) {
|
||||
return JsonDocument.of(is);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public static void reset() {
|
||||
documentCache.invalidateAll();
|
||||
}
|
||||
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package org.oneedtech.inspect.vc.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.oneedtech.inspect.core.probe.json.JsonPathEvaluator;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
/**
|
||||
* Json node utilities.
|
||||
* @author mgylling
|
||||
*/
|
||||
public class JsonNodeUtil {
|
||||
|
||||
public static List<JsonNode> asNodeList(JsonNode root, String jsonPath, JsonPathEvaluator evaluator) {
|
||||
List<JsonNode> list = new ArrayList<>();
|
||||
ArrayNode array = evaluator.eval(jsonPath, root);
|
||||
for(JsonNode node : array) {
|
||||
if(!(node instanceof ArrayNode)) {
|
||||
list.add(node);
|
||||
} else {
|
||||
ArrayNode values = (ArrayNode) node;
|
||||
for(JsonNode value : values) {
|
||||
list.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<String> asStringList(JsonNode node) {
|
||||
if(!(node instanceof ArrayNode)) {
|
||||
return List.of(node.asText());
|
||||
} else {
|
||||
ArrayNode arrayNode = (ArrayNode)node;
|
||||
return StreamSupport
|
||||
.stream(arrayNode.spliterator(), false)
|
||||
.map(n->n.asText().strip())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
public static List<JsonNode> asNodeList(JsonNode node) {
|
||||
if(node == null) return null;
|
||||
if(!(node instanceof ArrayNode)) {
|
||||
return List.of(node);
|
||||
} else {
|
||||
ArrayNode arrayNode = (ArrayNode)node;
|
||||
return StreamSupport
|
||||
.stream(arrayNode.spliterator(), false)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
{
|
||||
"@context": [
|
||||
{
|
||||
"@version": 1.1
|
||||
},
|
||||
"https://www.w3.org/ns/odrl.jsonld",
|
||||
{
|
||||
"ex": "https://example.org/examples#",
|
||||
"schema": "http://schema.org/",
|
||||
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
||||
"3rdPartyCorrelation": "ex:3rdPartyCorrelation",
|
||||
"AllVerifiers": "ex:AllVerifiers",
|
||||
"Archival": "ex:Archival",
|
||||
"BachelorDegree": "ex:BachelorDegree",
|
||||
"Child": "ex:Child",
|
||||
"CLCredentialDefinition2019": "ex:CLCredentialDefinition2019",
|
||||
"CLSignature2019": "ex:CLSignature2019",
|
||||
"IssuerPolicy": "ex:IssuerPolicy",
|
||||
"HolderPolicy": "ex:HolderPolicy",
|
||||
"Mother": "ex:Mother",
|
||||
"RelationshipCredential": "ex:RelationshipCredential",
|
||||
"UniversityDegreeCredential": "ex:UniversityDegreeCredential",
|
||||
"AlumniCredential": "ex:AlumniCredential",
|
||||
"DisputeCredential": "ex:DisputeCredential",
|
||||
"PrescriptionCredential": "ex:PrescriptionCredential",
|
||||
"ZkpExampleSchema2018": "ex:ZkpExampleSchema2018",
|
||||
"issuerData": "ex:issuerData",
|
||||
"attributes": "ex:attributes",
|
||||
"signature": "ex:signature",
|
||||
"signatureCorrectnessProof": "ex:signatureCorrectnessProof",
|
||||
"primaryProof": "ex:primaryProof",
|
||||
"nonRevocationProof": "ex:nonRevocationProof",
|
||||
"alumniOf": {
|
||||
"@id": "schema:alumniOf",
|
||||
"@type": "rdf:HTML"
|
||||
},
|
||||
"child": {
|
||||
"@id": "ex:child",
|
||||
"@type": "@id"
|
||||
},
|
||||
"degree": "ex:degree",
|
||||
"degreeType": "ex:degreeType",
|
||||
"degreeSchool": "ex:degreeSchool",
|
||||
"college": "ex:college",
|
||||
"name": {
|
||||
"@id": "schema:name",
|
||||
"@type": "rdf:HTML"
|
||||
},
|
||||
"givenName": "schema:givenName",
|
||||
"familyName": "schema:familyName",
|
||||
"parent": {
|
||||
"@id": "ex:parent",
|
||||
"@type": "@id"
|
||||
},
|
||||
"referenceId": "ex:referenceId",
|
||||
"documentPresence": "ex:documentPresence",
|
||||
"evidenceDocument": "ex:evidenceDocument",
|
||||
"spouse": "schema:spouse",
|
||||
"subjectPresence": "ex:subjectPresence",
|
||||
"verifier": {
|
||||
"@id": "ex:verifier",
|
||||
"@type": "@id"
|
||||
},
|
||||
"currentStatus": "ex:currentStatus",
|
||||
"statusReason": "ex:statusReason",
|
||||
"prescription": "ex:prescription"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,315 @@
|
||||
{
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"VerifiableCredential": {
|
||||
"@id": "https://www.w3.org/2018/credentials#VerifiableCredential",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"cred": "https://www.w3.org/2018/credentials#",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
||||
"credentialSchema": {
|
||||
"@id": "cred:credentialSchema",
|
||||
"@type": "@id",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"cred": "https://www.w3.org/2018/credentials#",
|
||||
"JsonSchemaValidator2018": "cred:JsonSchemaValidator2018"
|
||||
}
|
||||
},
|
||||
"credentialStatus": {
|
||||
"@id": "cred:credentialStatus",
|
||||
"@type": "@id"
|
||||
},
|
||||
"credentialSubject": {
|
||||
"@id": "cred:credentialSubject",
|
||||
"@type": "@id"
|
||||
},
|
||||
"evidence": {
|
||||
"@id": "cred:evidence",
|
||||
"@type": "@id"
|
||||
},
|
||||
"expirationDate": {
|
||||
"@id": "cred:expirationDate",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"holder": {
|
||||
"@id": "cred:holder",
|
||||
"@type": "@id"
|
||||
},
|
||||
"issued": {
|
||||
"@id": "cred:issued",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"issuer": {
|
||||
"@id": "cred:issuer",
|
||||
"@type": "@id"
|
||||
},
|
||||
"issuanceDate": {
|
||||
"@id": "cred:issuanceDate",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"proof": {
|
||||
"@id": "sec:proof",
|
||||
"@type": "@id",
|
||||
"@container": "@graph"
|
||||
},
|
||||
"refreshService": {
|
||||
"@id": "cred:refreshService",
|
||||
"@type": "@id",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"cred": "https://www.w3.org/2018/credentials#",
|
||||
"ManualRefreshService2018": "cred:ManualRefreshService2018"
|
||||
}
|
||||
},
|
||||
"termsOfUse": {
|
||||
"@id": "cred:termsOfUse",
|
||||
"@type": "@id"
|
||||
},
|
||||
"validFrom": {
|
||||
"@id": "cred:validFrom",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"validUntil": {
|
||||
"@id": "cred:validUntil",
|
||||
"@type": "xsd:dateTime"
|
||||
}
|
||||
}
|
||||
},
|
||||
"VerifiablePresentation": {
|
||||
"@id": "https://www.w3.org/2018/credentials#VerifiablePresentation",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"cred": "https://www.w3.org/2018/credentials#",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"holder": {
|
||||
"@id": "cred:holder",
|
||||
"@type": "@id"
|
||||
},
|
||||
"proof": {
|
||||
"@id": "sec:proof",
|
||||
"@type": "@id",
|
||||
"@container": "@graph"
|
||||
},
|
||||
"verifiableCredential": {
|
||||
"@id": "cred:verifiableCredential",
|
||||
"@type": "@id",
|
||||
"@container": "@graph"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EcdsaSecp256k1Signature2019": {
|
||||
"@id": "https://w3id.org/security#EcdsaSecp256k1Signature2019",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
||||
"challenge": "sec:challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"domain": "sec:domain",
|
||||
"expires": {
|
||||
"@id": "sec:expiration",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"jws": "sec:jws",
|
||||
"nonce": "sec:nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "sec:proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"assertionMethod": {
|
||||
"@id": "sec:assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "sec:authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "sec:proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "sec:verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EcdsaSecp256r1Signature2019": {
|
||||
"@id": "https://w3id.org/security#EcdsaSecp256r1Signature2019",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
||||
"challenge": "sec:challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"domain": "sec:domain",
|
||||
"expires": {
|
||||
"@id": "sec:expiration",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"jws": "sec:jws",
|
||||
"nonce": "sec:nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "sec:proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"assertionMethod": {
|
||||
"@id": "sec:assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "sec:authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "sec:proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "sec:verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Ed25519Signature2018": {
|
||||
"@id": "https://w3id.org/security#Ed25519Signature2018",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
||||
"challenge": "sec:challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"domain": "sec:domain",
|
||||
"expires": {
|
||||
"@id": "sec:expiration",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"jws": "sec:jws",
|
||||
"nonce": "sec:nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "sec:proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"assertionMethod": {
|
||||
"@id": "sec:assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "sec:authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "sec:proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "sec:verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RsaSignature2018": {
|
||||
"@id": "https://w3id.org/security#RsaSignature2018",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"challenge": "sec:challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"domain": "sec:domain",
|
||||
"expires": {
|
||||
"@id": "sec:expiration",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"jws": "sec:jws",
|
||||
"nonce": "sec:nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "sec:proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"assertionMethod": {
|
||||
"@id": "sec:assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "sec:authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "sec:proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "sec:verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proof": {
|
||||
"@id": "https://w3id.org/security#proof",
|
||||
"@type": "@id",
|
||||
"@container": "@graph"
|
||||
}
|
||||
}
|
||||
}
|
53
inspector-vc/src/main/resources/contexts/clr-v2p0.json
Normal file
53
inspector-vc/src/main/resources/contexts/clr-v2p0.json
Normal file
@ -0,0 +1,53 @@
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"ClrCredential": {
|
||||
"@id": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#ClrCredential",
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type"
|
||||
}
|
||||
},
|
||||
"ClrSubject": {
|
||||
"@id": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#ClrSubject",
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"cred": "https://www.w3.org/2018/credentials#",
|
||||
"obi": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#",
|
||||
"achievement": {
|
||||
"@id": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#achievement",
|
||||
"@type": "obi:Achievement",
|
||||
"@container": "@set"
|
||||
},
|
||||
"association": {
|
||||
"@id": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#association",
|
||||
"@type": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#Association",
|
||||
"@container": "@set"
|
||||
},
|
||||
"verifiableCredential": {
|
||||
"@id": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#verifiableCredential",
|
||||
"@type": "cred:verifiableCredential",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Association": {
|
||||
"@id": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#Association",
|
||||
"@context": {
|
||||
"associationType": {
|
||||
"@id": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#AssociationType"
|
||||
},
|
||||
"sourceId": {
|
||||
"@id": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#sourceId",
|
||||
"@type": "xsd:anyURI"
|
||||
},
|
||||
"targetId": {
|
||||
"@id": "https://purl.imsglobal.org/spec/clr/v2p0/vocab.html#targetId",
|
||||
"@type": "xsd:anyURI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
58
inspector-vc/src/main/resources/contexts/did-v1.jsonld
Normal file
58
inspector-vc/src/main/resources/contexts/did-v1.jsonld
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"alsoKnownAs": {
|
||||
"@id": "https://www.w3.org/ns/activitystreams#alsoKnownAs",
|
||||
"@type": "@id"
|
||||
},
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"controller": {
|
||||
"@id": "https://w3id.org/security#controller",
|
||||
"@type": "@id"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"service": {
|
||||
"@id": "https://www.w3.org/ns/did#service",
|
||||
"@type": "@id",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"serviceEndpoint": {
|
||||
"@id": "https://www.w3.org/ns/did#serviceEndpoint",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
}
|
440
inspector-vc/src/main/resources/contexts/ob-v3p0.json
Normal file
440
inspector-vc/src/main/resources/contexts/ob-v3p0.json
Normal file
@ -0,0 +1,440 @@
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"xsd": "https://www.w3.org/2001/XMLSchema#",
|
||||
|
||||
"OpenBadgeCredential": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#OpenBadgeCredential"
|
||||
},
|
||||
"Achievement": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Achievement",
|
||||
"@context": {
|
||||
"achievementType": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#achievementType",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"alignment": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#alignment",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Alignment",
|
||||
"@container": "@set"
|
||||
},
|
||||
"creator": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Profile"
|
||||
},
|
||||
"creditsAvailable": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#creditsAvailable",
|
||||
"@type": "xsd:float"
|
||||
},
|
||||
"criteria": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Criteria",
|
||||
"@type": "@id"
|
||||
},
|
||||
"fieldOfStudy": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#fieldOfStudy",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"humanCode": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#humanCode",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"otherIdentifier": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#otherIdentifier",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#IdentifierEntry",
|
||||
"@container": "@set"
|
||||
},
|
||||
"related": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#related",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Related",
|
||||
"@container": "@set"
|
||||
},
|
||||
"resultDescription": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#resultDescription",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#ResultDescription",
|
||||
"@container": "@set"
|
||||
},
|
||||
"specialization": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#specialization",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"tag": {
|
||||
"@id": "https://schema.org/keywords",
|
||||
"@type": "xsd:string",
|
||||
"@container": "@set"
|
||||
},
|
||||
"version": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#version",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AchievementCredential": {
|
||||
"@id": "OpenBadgeCredential"
|
||||
},
|
||||
"AchievementSubject": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#AchievementSubject",
|
||||
"@context": {
|
||||
"achievement": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Achievement"
|
||||
},
|
||||
"activityEndDate": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#activityEndDate",
|
||||
"@type": "xsd:date"
|
||||
},
|
||||
"activityStartDate": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#activityStartDate",
|
||||
"@type": "xsd:date"
|
||||
},
|
||||
"creditsEarned": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#creditsEarned",
|
||||
"@type": "xsd:float"
|
||||
},
|
||||
"identifier": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#identifier",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#IdentityObject",
|
||||
"@container": "@set"
|
||||
},
|
||||
"licenseNumber": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#licenseNumber",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"result": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#result",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Result",
|
||||
"@container": "@set"
|
||||
},
|
||||
"role": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#role",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"source": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#source",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Profile"
|
||||
},
|
||||
"term": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#term",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Address": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Address",
|
||||
"@context": {
|
||||
"addressCountry": {
|
||||
"@id": "https://schema.org/addressCountry",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"addressCountryCode": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#CountryCode",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"addressLocality": {
|
||||
"@id": "https://schema.org/addressLocality",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"addressRegion": {
|
||||
"@id": "https://schema.org/addressRegion",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"geo": {
|
||||
"@id" : "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#GeoCoordinates"
|
||||
},
|
||||
"postOfficeBoxNumber": {
|
||||
"@id": "https://schema.org/postOfficeBoxNumber",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"postalCode": {
|
||||
"@id": "https://schema.org/postalCode",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"streetAddress": {
|
||||
"@id": "https://schema.org/streetAddress",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Alignment": {
|
||||
"@id": "https://schema.org/Alignment",
|
||||
"@context": {
|
||||
"targetCode": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#targetCode",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetDescription": {
|
||||
"@id": "https://schema.org/targetDescription",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetFramework": {
|
||||
"@id": "https://schema.org/targetFramework",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetName": {
|
||||
"@id": "https://schema.org/targetName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetType": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#targetType",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetUrl": {
|
||||
"@id": "https://schema.org/targetUrl",
|
||||
"@type": "xsd:anyURI"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Criteria": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Criteria"
|
||||
},
|
||||
"EndorsementCredential": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#EndorsementCredential"
|
||||
},
|
||||
"EndorsementSubject": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#EndorsementSubject",
|
||||
"@context": {
|
||||
"endorsementComment": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#endorsementComment",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Evidence": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Evidence",
|
||||
"@context": {
|
||||
"audience": {
|
||||
"@id": "https://schema.org/audience",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"genre": {
|
||||
"@id": "https://schema.org/genre",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GeoCoordinates": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#GeoCoordinates",
|
||||
"@context": {
|
||||
"latitude": {
|
||||
"@id": "https://schema.org/latitude",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"longitude": {
|
||||
"@id": "https://schema.org/longitude",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"IdentifierEntry": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#IdentifierEntry",
|
||||
"@context": {
|
||||
"identifier": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#identifier",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"identifierType": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#identifierType",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"IdentityObject": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#IdentityObject",
|
||||
"@context": {
|
||||
"hashed": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#hashed",
|
||||
"@type": "xsd:boolean"
|
||||
},
|
||||
"identityHash": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#identityHash",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"identityType": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#identityType",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"salt": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#salt",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Image": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Image",
|
||||
"@context": {
|
||||
"caption": {
|
||||
"@id": "https://schema.org/caption",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Profile": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Profile",
|
||||
"@context": {
|
||||
"additionalName": {
|
||||
"@id": "https://schema.org/additionalName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"address": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Address"
|
||||
},
|
||||
"dateOfBirth": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#dateOfBirth",
|
||||
"@type": "xsd:date"
|
||||
},
|
||||
"email": {
|
||||
"@id": "https://schema.org/email",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"familyName": {
|
||||
"@id": "https://schema.org/familyName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"familyNamePrefix": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#familyNamePrefix",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"givenName": {
|
||||
"@id": "https://schema.org/givenName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"honorificPrefix": {
|
||||
"@id": "https://schema.org/honorificPrefix",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"honorificSuffix": {
|
||||
"@id": "https://schema.org/honorificSuffix",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"otherIdentifier": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#otherIdentifier",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#IdentifierEntry",
|
||||
"@container": "@set"
|
||||
},
|
||||
"parentOrg": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#parentOrg",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"patronymicName": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#patronymicName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"phone": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#PhoneNumber",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"official": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#official",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Related": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Related",
|
||||
"@context": {
|
||||
"version": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#version",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Result": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Result",
|
||||
"@context": {
|
||||
"achievedLevel": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#achievedLevel",
|
||||
"@type": "xsd:anyURI"
|
||||
},
|
||||
"resultDescription": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#resultDescription",
|
||||
"@type": "xsd:anyURI"
|
||||
},
|
||||
"status": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#status",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"value": {
|
||||
"@id": "https://schema.org/value",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ResultDescription": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#ResultDescription",
|
||||
"@context": {
|
||||
"allowedValue": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#allowedValue",
|
||||
"@type": "xsd:string",
|
||||
"@container": "@set"
|
||||
},
|
||||
"requiredLevel": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#requiredLevel",
|
||||
"@type": "xsd:anyURI"
|
||||
},
|
||||
"requiredValue": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#requiredValue",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"resultType": {
|
||||
"@id":"https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#resultType",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"rubricCriterionLevel": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#rubricCriterionLevel",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#RubricCriterionLevel",
|
||||
"@container": "@set"
|
||||
},
|
||||
"valueMax": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#valueMax",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"valueMin": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#valueMin",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RubricCriterionLevel": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#RubricCriterionLevel",
|
||||
"@context": {
|
||||
"level": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#level",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"points": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#points",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"alignment": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#alignment",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Alignment",
|
||||
"@container": "@set"
|
||||
},
|
||||
"description": {
|
||||
"@id": "https://schema.org/description",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"endorsement": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#endorsement",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#EndorsementCredential",
|
||||
"@container": "@set"
|
||||
},
|
||||
"image": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#image",
|
||||
"@type": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#Image"
|
||||
},
|
||||
"name": {
|
||||
"@id": "https://schema.org/name",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"narrative": {
|
||||
"@id": "https://purl.imsglobal.org/spec/ob/v3p0/vocab.html#narrative",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"url": {
|
||||
"@id": "https://schema.org/url",
|
||||
"@type": "xsd:anyURI"
|
||||
}
|
||||
}
|
||||
}
|
440
inspector-vc/src/main/resources/contexts/obv3x.jsonld
Normal file
440
inspector-vc/src/main/resources/contexts/obv3x.jsonld
Normal file
@ -0,0 +1,440 @@
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"xsd": "https://www.w3.org/2001/XMLSchema#",
|
||||
|
||||
"OpenBadgeCredential": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#OpenBadgeCredential"
|
||||
},
|
||||
"Achievement": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Achievement",
|
||||
"@context": {
|
||||
"achievementType": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#achievementType",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"alignment": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#alignment",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Alignment",
|
||||
"@container": "@set"
|
||||
},
|
||||
"creator": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Profile"
|
||||
},
|
||||
"creditsAvailable": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#creditsAvailable",
|
||||
"@type": "xsd:float"
|
||||
},
|
||||
"criteria": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Criteria",
|
||||
"@type": "@id"
|
||||
},
|
||||
"fieldOfStudy": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#fieldOfStudy",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"humanCode": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#humanCode",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"otherIdentifier": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#otherIdentifier",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#IdentifierEntry",
|
||||
"@container": "@set"
|
||||
},
|
||||
"related": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#related",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Related",
|
||||
"@container": "@set"
|
||||
},
|
||||
"resultDescription": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#resultDescription",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#ResultDescription",
|
||||
"@container": "@set"
|
||||
},
|
||||
"specialization": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#specialization",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"tag": {
|
||||
"@id": "https://schema.org/keywords",
|
||||
"@type": "xsd:string",
|
||||
"@container": "@set"
|
||||
},
|
||||
"version": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#version",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AchievementCredential": {
|
||||
"@id": "OpenBadgeCredential"
|
||||
},
|
||||
"AchievementSubject": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#AchievementSubject",
|
||||
"@context": {
|
||||
"achievement": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Achievement"
|
||||
},
|
||||
"activityEndDate": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#activityEndDate",
|
||||
"@type": "xsd:date"
|
||||
},
|
||||
"activityStartDate": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#activityStartDate",
|
||||
"@type": "xsd:date"
|
||||
},
|
||||
"creditsEarned": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#creditsEarned",
|
||||
"@type": "xsd:float"
|
||||
},
|
||||
"identifier": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#identifier",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#IdentityObject",
|
||||
"@container": "@set"
|
||||
},
|
||||
"licenseNumber": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#licenseNumber",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"result": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#result",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Result",
|
||||
"@container": "@set"
|
||||
},
|
||||
"role": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#role",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"source": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#source",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Profile"
|
||||
},
|
||||
"term": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#term",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Address": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Address",
|
||||
"@context": {
|
||||
"addressCountry": {
|
||||
"@id": "https://schema.org/addressCountry",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"addressCountryCode": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#CountryCode",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"addressLocality": {
|
||||
"@id": "https://schema.org/addresLocality",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"addressRegion": {
|
||||
"@id": "https://schema.org/addressRegion",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"geo": {
|
||||
"@id" : "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#GeoCoordinates"
|
||||
},
|
||||
"postOfficeBoxNumber": {
|
||||
"@id": "https://schema.org/postOfficeBoxNumber",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"postalCode": {
|
||||
"@id": "https://schema.org/postalCode",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"streetAddress": {
|
||||
"@id": "https://schema.org/streetAddress",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Alignment": {
|
||||
"@id": "https://schema.org/Alignment",
|
||||
"@context": {
|
||||
"targetCode": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#targetCode",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetDescription": {
|
||||
"@id": "https://schema.org/targetDescription",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetFramework": {
|
||||
"@id": "https://schema.org/targetFramework",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetName": {
|
||||
"@id": "https://schema.org/targetName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetType": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#targetType",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"targetUrl": {
|
||||
"@id": "https://schema.org/targetUrl",
|
||||
"@type": "xsd:anyURI"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Criteria": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Criteria"
|
||||
},
|
||||
"EndorsementCredential": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#EndorsementCredential"
|
||||
},
|
||||
"EndorsementSubject": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#EndorsementSubject",
|
||||
"@context": {
|
||||
"endorsementComment": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#endorsementComment",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Evidence": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Evidence",
|
||||
"@context": {
|
||||
"audience": {
|
||||
"@id": "https://schema.org/audience",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"genre": {
|
||||
"@id": "https://schema.org/genre",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GeoCoordinates": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#GeoCoordinates",
|
||||
"@context": {
|
||||
"latitude": {
|
||||
"@id": "https://schema.org/latitude",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"longitude": {
|
||||
"@id": "https://schema.org/longitude",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"IdentifierEntry": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#IdentifierEntry",
|
||||
"@context": {
|
||||
"identifier": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#identifier",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"identifierType": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#identifierType",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"IdentityObject": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#IdentityObject",
|
||||
"@context": {
|
||||
"hashed": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#hashed",
|
||||
"@type": "xsd:boolean"
|
||||
},
|
||||
"identityHash": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#identityHash",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"identityType": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#identityType",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"salt": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#salt",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Image": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Image",
|
||||
"@context": {
|
||||
"caption": {
|
||||
"@id": "https://schema.org/caption",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Profile": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Profile",
|
||||
"@context": {
|
||||
"additionalName": {
|
||||
"@id": "https://schema.org/additionalName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"address": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Address"
|
||||
},
|
||||
"dateOfBirth": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#dateOfBirth",
|
||||
"@type": "xsd:date"
|
||||
},
|
||||
"email": {
|
||||
"@id": "https://schema.org/email",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"familyName": {
|
||||
"@id": "https://schema.org/familyName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"familyNamePrefix": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#familyNamePrefix",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"givenName": {
|
||||
"@id": "https://schema.org/givenName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"honorificPrefix": {
|
||||
"@id": "https://schema.org/honorificPrefix",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"honorificSuffix": {
|
||||
"@id": "https://schema.org/honorificSuffix",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"otherIdentifier": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#otherIdentifier",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#IdentifierEntry",
|
||||
"@container": "@set"
|
||||
},
|
||||
"parentOrg": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#parentOrg",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"patronymicName": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#patronymicName",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"phone": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#PhoneNumber",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"official": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#official",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Related": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Related",
|
||||
"@context": {
|
||||
"version": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#version",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Result": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Result",
|
||||
"@context": {
|
||||
"achievedLevel": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#achievedLevel",
|
||||
"@type": "xsd:anyURI"
|
||||
},
|
||||
"resultDescription": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#resultDescription",
|
||||
"@type": "xsd:anyURI"
|
||||
},
|
||||
"status": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#status",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"value": {
|
||||
"@id": "https://schema.org/value",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ResultDescription": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#ResultDescription",
|
||||
"@context": {
|
||||
"allowedValue": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#allowedValue",
|
||||
"@type": "xsd:string",
|
||||
"@container": "@set"
|
||||
},
|
||||
"requiredLevel": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#requiredLevel",
|
||||
"@type": "xsd:anyURI"
|
||||
},
|
||||
"requiredValue": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#requiredValue",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"resultType": {
|
||||
"@id":"https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#resultType",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"rubricCriterionLevel": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#rubricCriterionLevel",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#RubricCriterionLevel",
|
||||
"@container": "@set"
|
||||
},
|
||||
"valueMax": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#valueMax",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"valueMin": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#valueMin",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RubricCriterionLevel": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#RubricCriterionLevel",
|
||||
"@context": {
|
||||
"level": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#level",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"points": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#points",
|
||||
"@type": "xsd:string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"alignment": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#alignment",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Alignment",
|
||||
"@container": "@set"
|
||||
},
|
||||
"description": {
|
||||
"@id": "https://schema.org/description",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"endorsement": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#endorsement",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#EndorsementCredential",
|
||||
"@container": "@set"
|
||||
},
|
||||
"image": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#image",
|
||||
"@type": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#Image"
|
||||
},
|
||||
"name": {
|
||||
"@id": "https://schema.org/name",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"narrative": {
|
||||
"@id": "https://imsglobal.github.io/openbadges-specification/ob_v3p0.html#narrative",
|
||||
"@type": "xsd:string"
|
||||
},
|
||||
"url": {
|
||||
"@id": "https://schema.org/url",
|
||||
"@type": "xsd:anyURI"
|
||||
}
|
||||
}
|
||||
}
|
301
inspector-vc/src/main/resources/contexts/odrl.jsonld
Normal file
301
inspector-vc/src/main/resources/contexts/odrl.jsonld
Normal file
@ -0,0 +1,301 @@
|
||||
{
|
||||
"@context": {
|
||||
"odrl": "http://www.w3.org/ns/odrl/2/",
|
||||
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
||||
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
||||
"owl": "http://www.w3.org/2002/07/owl#",
|
||||
"skos": "http://www.w3.org/2004/02/skos/core#",
|
||||
"dct": "http://purl.org/dc/terms/",
|
||||
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
||||
"vcard": "http://www.w3.org/2006/vcard/ns#",
|
||||
"foaf": "http://xmlns.com/foaf/0.1/",
|
||||
"schema": "http://schema.org/",
|
||||
"cc": "http://creativecommons.org/ns#",
|
||||
"uid": "@id",
|
||||
"type": "@type",
|
||||
"Policy": "odrl:Policy",
|
||||
"Rule": "odrl:Rule",
|
||||
"profile": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:profile"
|
||||
},
|
||||
"inheritFrom": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:inheritFrom"
|
||||
},
|
||||
"ConflictTerm": "odrl:ConflictTerm",
|
||||
"conflict": {
|
||||
"@type": "@vocab",
|
||||
"@id": "odrl:conflict"
|
||||
},
|
||||
"perm": "odrl:perm",
|
||||
"prohibit": "odrl:prohibit",
|
||||
"invalid": "odrl:invalid",
|
||||
"Agreement": "odrl:Agreement",
|
||||
"Assertion": "odrl:Assertion",
|
||||
"Offer": "odrl:Offer",
|
||||
"Privacy": "odrl:Privacy",
|
||||
"Request": "odrl:Request",
|
||||
"Set": "odrl:Set",
|
||||
"Ticket": "odrl:Ticket",
|
||||
"Asset": "odrl:Asset",
|
||||
"AssetCollection": "odrl:AssetCollection",
|
||||
"relation": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:relation"
|
||||
},
|
||||
"hasPolicy": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:hasPolicy"
|
||||
},
|
||||
"target": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:target"
|
||||
},
|
||||
"output": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:output"
|
||||
},
|
||||
"partOf": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:partOf"
|
||||
},
|
||||
"source": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:source"
|
||||
},
|
||||
"Party": "odrl:Party",
|
||||
"PartyCollection": "odrl:PartyCollection",
|
||||
"function": {
|
||||
"@type": "@vocab",
|
||||
"@id": "odrl:function"
|
||||
},
|
||||
"PartyScope": "odrl:PartyScope",
|
||||
"assignee": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:assignee"
|
||||
},
|
||||
"assigner": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:assigner"
|
||||
},
|
||||
"assigneeOf": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:assigneeOf"
|
||||
},
|
||||
"assignerOf": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:assignerOf"
|
||||
},
|
||||
"attributedParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:attributedParty"
|
||||
},
|
||||
"attributingParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:attributingParty"
|
||||
},
|
||||
"compensatedParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:compensatedParty"
|
||||
},
|
||||
"compensatingParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:compensatingParty"
|
||||
},
|
||||
"consentingParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:consentingParty"
|
||||
},
|
||||
"consentedParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:consentedParty"
|
||||
},
|
||||
"informedParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:informedParty"
|
||||
},
|
||||
"informingParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:informingParty"
|
||||
},
|
||||
"trackingParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:trackingParty"
|
||||
},
|
||||
"trackedParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:trackedParty"
|
||||
},
|
||||
"contractingParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:contractingParty"
|
||||
},
|
||||
"contractedParty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:contractedParty"
|
||||
},
|
||||
"Action": "odrl:Action",
|
||||
"action": {
|
||||
"@type": "@vocab",
|
||||
"@id": "odrl:action"
|
||||
},
|
||||
"includedIn": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:includedIn"
|
||||
},
|
||||
"implies": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:implies"
|
||||
},
|
||||
"Permission": "odrl:Permission",
|
||||
"permission": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:permission"
|
||||
},
|
||||
"Prohibition": "odrl:Prohibition",
|
||||
"prohibition": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:prohibition"
|
||||
},
|
||||
"obligation": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:obligation"
|
||||
},
|
||||
"use": "odrl:use",
|
||||
"grantUse": "odrl:grantUse",
|
||||
"aggregate": "odrl:aggregate",
|
||||
"annotate": "odrl:annotate",
|
||||
"anonymize": "odrl:anonymize",
|
||||
"archive": "odrl:archive",
|
||||
"concurrentUse": "odrl:concurrentUse",
|
||||
"derive": "odrl:derive",
|
||||
"digitize": "odrl:digitize",
|
||||
"display": "odrl:display",
|
||||
"distribute": "odrl:distribute",
|
||||
"execute": "odrl:execute",
|
||||
"extract": "odrl:extract",
|
||||
"give": "odrl:give",
|
||||
"index": "odrl:index",
|
||||
"install": "odrl:install",
|
||||
"modify": "odrl:modify",
|
||||
"move": "odrl:move",
|
||||
"play": "odrl:play",
|
||||
"present": "odrl:present",
|
||||
"print": "odrl:print",
|
||||
"read": "odrl:read",
|
||||
"reproduce": "odrl:reproduce",
|
||||
"sell": "odrl:sell",
|
||||
"stream": "odrl:stream",
|
||||
"textToSpeech": "odrl:textToSpeech",
|
||||
"transfer": "odrl:transfer",
|
||||
"transform": "odrl:transform",
|
||||
"translate": "odrl:translate",
|
||||
"Duty": "odrl:Duty",
|
||||
"duty": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:duty"
|
||||
},
|
||||
"consequence": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:consequence"
|
||||
},
|
||||
"remedy": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:remedy"
|
||||
},
|
||||
"acceptTracking": "odrl:acceptTracking",
|
||||
"attribute": "odrl:attribute",
|
||||
"compensate": "odrl:compensate",
|
||||
"delete": "odrl:delete",
|
||||
"ensureExclusivity": "odrl:ensureExclusivity",
|
||||
"include": "odrl:include",
|
||||
"inform": "odrl:inform",
|
||||
"nextPolicy": "odrl:nextPolicy",
|
||||
"obtainConsent": "odrl:obtainConsent",
|
||||
"reviewPolicy": "odrl:reviewPolicy",
|
||||
"uninstall": "odrl:uninstall",
|
||||
"watermark": "odrl:watermark",
|
||||
"Constraint": "odrl:Constraint",
|
||||
"LogicalConstraint": "odrl:LogicalConstraint",
|
||||
"constraint": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:constraint"
|
||||
},
|
||||
"refinement": {
|
||||
"@type": "@id",
|
||||
"@id": "odrl:refinement"
|
||||
},
|
||||
"Operator": "odrl:Operator",
|
||||
"operator": {
|
||||
"@type": "@vocab",
|
||||
"@id": "odrl:operator"
|
||||
},
|
||||
"RightOperand": "odrl:RightOperand",
|
||||
"rightOperand": "odrl:rightOperand",
|
||||
"rightOperandReference": {
|
||||
"@type": "xsd:anyURI",
|
||||
"@id": "odrl:rightOperandReference"
|
||||
},
|
||||
"LeftOperand": "odrl:LeftOperand",
|
||||
"leftOperand": {
|
||||
"@type": "@vocab",
|
||||
"@id": "odrl:leftOperand"
|
||||
},
|
||||
"unit": "odrl:unit",
|
||||
"dataType": {
|
||||
"@type": "xsd:anyType",
|
||||
"@id": "odrl:datatype"
|
||||
},
|
||||
"status": "odrl:status",
|
||||
"absolutePosition": "odrl:absolutePosition",
|
||||
"absoluteSpatialPosition": "odrl:absoluteSpatialPosition",
|
||||
"absoluteTemporalPosition": "odrl:absoluteTemporalPosition",
|
||||
"absoluteSize": "odrl:absoluteSize",
|
||||
"count": "odrl:count",
|
||||
"dateTime": "odrl:dateTime",
|
||||
"delayPeriod": "odrl:delayPeriod",
|
||||
"deliveryChannel": "odrl:deliveryChannel",
|
||||
"elapsedTime": "odrl:elapsedTime",
|
||||
"event": "odrl:event",
|
||||
"fileFormat": "odrl:fileFormat",
|
||||
"industry": "odrl:industry:",
|
||||
"language": "odrl:language",
|
||||
"media": "odrl:media",
|
||||
"meteredTime": "odrl:meteredTime",
|
||||
"payAmount": "odrl:payAmount",
|
||||
"percentage": "odrl:percentage",
|
||||
"product": "odrl:product",
|
||||
"purpose": "odrl:purpose",
|
||||
"recipient": "odrl:recipient",
|
||||
"relativePosition": "odrl:relativePosition",
|
||||
"relativeSpatialPosition": "odrl:relativeSpatialPosition",
|
||||
"relativeTemporalPosition": "odrl:relativeTemporalPosition",
|
||||
"relativeSize": "odrl:relativeSize",
|
||||
"resolution": "odrl:resolution",
|
||||
"spatial": "odrl:spatial",
|
||||
"spatialCoordinates": "odrl:spatialCoordinates",
|
||||
"systemDevice": "odrl:systemDevice",
|
||||
"timeInterval": "odrl:timeInterval",
|
||||
"unitOfCount": "odrl:unitOfCount",
|
||||
"version": "odrl:version",
|
||||
"virtualLocation": "odrl:virtualLocation",
|
||||
"eq": "odrl:eq",
|
||||
"gt": "odrl:gt",
|
||||
"gteq": "odrl:gteq",
|
||||
"lt": "odrl:lt",
|
||||
"lteq": "odrl:lteq",
|
||||
"neq": "odrl:neg",
|
||||
"isA": "odrl:isA",
|
||||
"hasPart": "odrl:hasPart",
|
||||
"isPartOf": "odrl:isPartOf",
|
||||
"isAllOf": "odrl:isAllOf",
|
||||
"isAnyOf": "odrl:isAnyOf",
|
||||
"isNoneOf": "odrl:isNoneOf",
|
||||
"or": "odrl:or",
|
||||
"xone": "odrl:xone",
|
||||
"and": "odrl:and",
|
||||
"andSequence": "odrl:andSequence",
|
||||
"policyUsage": "odrl:policyUsage"
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
{
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"BbsBlsSignature2020": {
|
||||
"@id": "https://w3id.org/security#BbsBlsSignature2020",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"proofValue": "https://w3id.org/security#proofValue",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BbsBlsSignatureProof2020": {
|
||||
"@id": "https://w3id.org/security#BbsBlsSignatureProof2020",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "https://w3id.org/security#proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Bls12381G2Key2020": "https://w3id.org/security#Bls12381G2Key2020"
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"@protected": true,
|
||||
"proof": {
|
||||
"@id": "https://w3id.org/security#proof",
|
||||
"@type": "@id",
|
||||
"@container": "@graph"
|
||||
},
|
||||
"Ed25519VerificationKey2020": {
|
||||
"@id": "https://w3id.org/security#Ed25519VerificationKey2020",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"controller": {
|
||||
"@id": "https://w3id.org/security#controller",
|
||||
"@type": "@id"
|
||||
},
|
||||
"revoked": {
|
||||
"@id": "https://w3id.org/security#revoked",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"publicKeyMultibase": {
|
||||
"@id": "https://w3id.org/security#publicKeyMultibase",
|
||||
"@type": "https://w3id.org/security#multibase"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Ed25519Signature2020": {
|
||||
"@id": "https://w3id.org/security#Ed25519Signature2020",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": {
|
||||
"@id": "https://w3id.org/security#proofValue",
|
||||
"@type": "https://w3id.org/security#multibase"
|
||||
},
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
inspector-vc/src/main/resources/contexts/security-v1.jsonld
Normal file
50
inspector-vc/src/main/resources/contexts/security-v1.jsonld
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"dc": "http://purl.org/dc/terms/",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
||||
|
||||
"EcdsaKoblitzSignature2016": "sec:EcdsaKoblitzSignature2016",
|
||||
"Ed25519Signature2018": "sec:Ed25519Signature2018",
|
||||
"EncryptedMessage": "sec:EncryptedMessage",
|
||||
"GraphSignature2012": "sec:GraphSignature2012",
|
||||
"LinkedDataSignature2015": "sec:LinkedDataSignature2015",
|
||||
"LinkedDataSignature2016": "sec:LinkedDataSignature2016",
|
||||
"CryptographicKey": "sec:Key",
|
||||
|
||||
"authenticationTag": "sec:authenticationTag",
|
||||
"canonicalizationAlgorithm": "sec:canonicalizationAlgorithm",
|
||||
"cipherAlgorithm": "sec:cipherAlgorithm",
|
||||
"cipherData": "sec:cipherData",
|
||||
"cipherKey": "sec:cipherKey",
|
||||
"created": {"@id": "dc:created", "@type": "xsd:dateTime"},
|
||||
"creator": {"@id": "dc:creator", "@type": "@id"},
|
||||
"digestAlgorithm": "sec:digestAlgorithm",
|
||||
"digestValue": "sec:digestValue",
|
||||
"domain": "sec:domain",
|
||||
"encryptionKey": "sec:encryptionKey",
|
||||
"expiration": {"@id": "sec:expiration", "@type": "xsd:dateTime"},
|
||||
"expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"},
|
||||
"initializationVector": "sec:initializationVector",
|
||||
"iterationCount": "sec:iterationCount",
|
||||
"nonce": "sec:nonce",
|
||||
"normalizationAlgorithm": "sec:normalizationAlgorithm",
|
||||
"owner": {"@id": "sec:owner", "@type": "@id"},
|
||||
"password": "sec:password",
|
||||
"privateKey": {"@id": "sec:privateKey", "@type": "@id"},
|
||||
"privateKeyPem": "sec:privateKeyPem",
|
||||
"publicKey": {"@id": "sec:publicKey", "@type": "@id"},
|
||||
"publicKeyBase58": "sec:publicKeyBase58",
|
||||
"publicKeyPem": "sec:publicKeyPem",
|
||||
"publicKeyWif": "sec:publicKeyWif",
|
||||
"publicKeyService": {"@id": "sec:publicKeyService", "@type": "@id"},
|
||||
"revoked": {"@id": "sec:revoked", "@type": "xsd:dateTime"},
|
||||
"salt": "sec:salt",
|
||||
"signature": "sec:signature",
|
||||
"signatureAlgorithm": "sec:signingAlgorithm",
|
||||
"signatureValue": "sec:signatureValue"
|
||||
}
|
||||
}
|
59
inspector-vc/src/main/resources/contexts/security-v2.jsonld
Normal file
59
inspector-vc/src/main/resources/contexts/security-v2.jsonld
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"@context": [{
|
||||
"@version": 1.1
|
||||
}, "https://w3id.org/security/v1", {
|
||||
"AesKeyWrappingKey2019": "sec:AesKeyWrappingKey2019",
|
||||
"DeleteKeyOperation": "sec:DeleteKeyOperation",
|
||||
"DeriveSecretOperation": "sec:DeriveSecretOperation",
|
||||
"EcdsaSecp256k1Signature2019": "sec:EcdsaSecp256k1Signature2019",
|
||||
"EcdsaSecp256r1Signature2019": "sec:EcdsaSecp256r1Signature2019",
|
||||
"EcdsaSecp256k1VerificationKey2019": "sec:EcdsaSecp256k1VerificationKey2019",
|
||||
"EcdsaSecp256r1VerificationKey2019": "sec:EcdsaSecp256r1VerificationKey2019",
|
||||
"Ed25519Signature2018": "sec:Ed25519Signature2018",
|
||||
"Ed25519VerificationKey2018": "sec:Ed25519VerificationKey2018",
|
||||
"EquihashProof2018": "sec:EquihashProof2018",
|
||||
"ExportKeyOperation": "sec:ExportKeyOperation",
|
||||
"GenerateKeyOperation": "sec:GenerateKeyOperation",
|
||||
"KmsOperation": "sec:KmsOperation",
|
||||
"RevokeKeyOperation": "sec:RevokeKeyOperation",
|
||||
"RsaSignature2018": "sec:RsaSignature2018",
|
||||
"RsaVerificationKey2018": "sec:RsaVerificationKey2018",
|
||||
"Sha256HmacKey2019": "sec:Sha256HmacKey2019",
|
||||
"SignOperation": "sec:SignOperation",
|
||||
"UnwrapKeyOperation": "sec:UnwrapKeyOperation",
|
||||
"VerifyOperation": "sec:VerifyOperation",
|
||||
"WrapKeyOperation": "sec:WrapKeyOperation",
|
||||
"X25519KeyAgreementKey2019": "sec:X25519KeyAgreementKey2019",
|
||||
|
||||
"allowedAction": "sec:allowedAction",
|
||||
"assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"},
|
||||
"authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"},
|
||||
"capability": {"@id": "sec:capability", "@type": "@id"},
|
||||
"capabilityAction": "sec:capabilityAction",
|
||||
"capabilityChain": {"@id": "sec:capabilityChain", "@type": "@id", "@container": "@list"},
|
||||
"capabilityDelegation": {"@id": "sec:capabilityDelegationMethod", "@type": "@id", "@container": "@set"},
|
||||
"capabilityInvocation": {"@id": "sec:capabilityInvocationMethod", "@type": "@id", "@container": "@set"},
|
||||
"caveat": {"@id": "sec:caveat", "@type": "@id", "@container": "@set"},
|
||||
"challenge": "sec:challenge",
|
||||
"ciphertext": "sec:ciphertext",
|
||||
"controller": {"@id": "sec:controller", "@type": "@id"},
|
||||
"delegator": {"@id": "sec:delegator", "@type": "@id"},
|
||||
"equihashParameterK": {"@id": "sec:equihashParameterK", "@type": "xsd:integer"},
|
||||
"equihashParameterN": {"@id": "sec:equihashParameterN", "@type": "xsd:integer"},
|
||||
"invocationTarget": {"@id": "sec:invocationTarget", "@type": "@id"},
|
||||
"invoker": {"@id": "sec:invoker", "@type": "@id"},
|
||||
"jws": "sec:jws",
|
||||
"keyAgreement": {"@id": "sec:keyAgreementMethod", "@type": "@id", "@container": "@set"},
|
||||
"kmsModule": {"@id": "sec:kmsModule"},
|
||||
"parentCapability": {"@id": "sec:parentCapability", "@type": "@id"},
|
||||
"plaintext": "sec:plaintext",
|
||||
"proof": {"@id": "sec:proof", "@type": "@id", "@container": "@graph"},
|
||||
"proofPurpose": {"@id": "sec:proofPurpose", "@type": "@vocab"},
|
||||
"proofValue": "sec:proofValue",
|
||||
"referenceId": "sec:referenceId",
|
||||
"unwrappedKey": "sec:unwrappedKey",
|
||||
"verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"},
|
||||
"verifyData": "sec:verifyData",
|
||||
"wrappedKey": "sec:wrappedKey"
|
||||
}]
|
||||
}
|
@ -0,0 +1,710 @@
|
||||
{
|
||||
"@context": [{
|
||||
"@version": 1.1,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"@protected": true,
|
||||
"JsonWebKey2020": {
|
||||
"@id": "https://w3id.org/security#JsonWebKey2020"
|
||||
},
|
||||
"JsonWebSignature2020": {
|
||||
"@id": "https://w3id.org/security#JsonWebSignature2020",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"@protected": true,
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"jws": "https://w3id.org/security#jws",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Ed25519VerificationKey2020": {
|
||||
"@id": "https://w3id.org/security#Ed25519VerificationKey2020"
|
||||
},
|
||||
"Ed25519Signature2020": {
|
||||
"@id": "https://w3id.org/security#Ed25519Signature2020",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": {
|
||||
"@id": "https://w3id.org/security#proofValue"
|
||||
},
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"publicKeyJwk": {
|
||||
"@id": "https://w3id.org/security#publicKeyJwk",
|
||||
"@type": "@json"
|
||||
},
|
||||
"ethereumAddress": {
|
||||
"@id": "https://w3id.org/security#ethereumAddress"
|
||||
},
|
||||
"publicKeyHex": {
|
||||
"@id": "https://w3id.org/security#publicKeyHex"
|
||||
},
|
||||
"blockchainAccountId": {
|
||||
"@id": "https://w3id.org/security#blockchainAccountId"
|
||||
},
|
||||
"MerkleProof2019": {
|
||||
"@id": "https://w3id.org/security#MerkleProof2019"
|
||||
},
|
||||
"Bls12381G1Key2020": {
|
||||
"@id": "https://w3id.org/security#Bls12381G1Key2020"
|
||||
},
|
||||
"Bls12381G2Key2020": {
|
||||
"@id": "https://w3id.org/security#Bls12381G2Key2020"
|
||||
},
|
||||
"BbsBlsSignature2020": {
|
||||
"@id": "https://w3id.org/security#BbsBlsSignature2020",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "https://w3id.org/security#proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BbsBlsSignatureProof2020": {
|
||||
"@id": "https://w3id.org/security#BbsBlsSignatureProof2020",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "https://w3id.org/security#proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"EcdsaKoblitzSignature2016": "https://w3id.org/security#EcdsaKoblitzSignature2016",
|
||||
"Ed25519Signature2018": {
|
||||
"@id": "https://w3id.org/security#Ed25519Signature2018",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"jws": "https://w3id.org/security#jws",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "https://w3id.org/security#proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EncryptedMessage": "https://w3id.org/security#EncryptedMessage",
|
||||
"GraphSignature2012": "https://w3id.org/security#GraphSignature2012",
|
||||
"LinkedDataSignature2015": "https://w3id.org/security#LinkedDataSignature2015",
|
||||
"LinkedDataSignature2016": "https://w3id.org/security#LinkedDataSignature2016",
|
||||
"CryptographicKey": "https://w3id.org/security#Key",
|
||||
"authenticationTag": "https://w3id.org/security#authenticationTag",
|
||||
"canonicalizationAlgorithm": "https://w3id.org/security#canonicalizationAlgorithm",
|
||||
"cipherAlgorithm": "https://w3id.org/security#cipherAlgorithm",
|
||||
"cipherData": "https://w3id.org/security#cipherData",
|
||||
"cipherKey": "https://w3id.org/security#cipherKey",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"creator": {
|
||||
"@id": "http://purl.org/dc/terms/creator",
|
||||
"@type": "@id"
|
||||
},
|
||||
"digestAlgorithm": "https://w3id.org/security#digestAlgorithm",
|
||||
"digestValue": "https://w3id.org/security#digestValue",
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"encryptionKey": "https://w3id.org/security#encryptionKey",
|
||||
"expiration": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"initializationVector": "https://w3id.org/security#initializationVector",
|
||||
"iterationCount": "https://w3id.org/security#iterationCount",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"normalizationAlgorithm": "https://w3id.org/security#normalizationAlgorithm",
|
||||
"owner": "https://w3id.org/security#owner",
|
||||
"password": "https://w3id.org/security#password",
|
||||
"privateKey": "https://w3id.org/security#privateKey",
|
||||
"privateKeyPem": "https://w3id.org/security#privateKeyPem",
|
||||
"publicKey": "https://w3id.org/security#publicKey",
|
||||
"publicKeyBase58": "https://w3id.org/security#publicKeyBase58",
|
||||
"publicKeyPem": "https://w3id.org/security#publicKeyPem",
|
||||
"publicKeyWif": "https://w3id.org/security#publicKeyWif",
|
||||
"publicKeyService": "https://w3id.org/security#publicKeyService",
|
||||
"revoked": {
|
||||
"@id": "https://w3id.org/security#revoked",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"salt": "https://w3id.org/security#salt",
|
||||
"signature": "https://w3id.org/security#signature",
|
||||
"signatureAlgorithm": "https://w3id.org/security#signingAlgorithm",
|
||||
"signatureValue": "https://w3id.org/security#signatureValue",
|
||||
"proofValue": "https://w3id.org/security#proofValue",
|
||||
|
||||
"AesKeyWrappingKey2019": "https://w3id.org/security#AesKeyWrappingKey2019",
|
||||
"DeleteKeyOperation": "https://w3id.org/security#DeleteKeyOperation",
|
||||
"DeriveSecretOperation": "https://w3id.org/security#DeriveSecretOperation",
|
||||
"EcdsaSecp256k1Signature2019": {
|
||||
"@id": "https://w3id.org/security#EcdsaSecp256k1Signature2019",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"jws": "https://w3id.org/security#jws",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "https://w3id.org/security#proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EcdsaSecp256r1Signature2019": {
|
||||
"@id": "https://w3id.org/security#EcdsaSecp256r1Signature2019",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"jws": "https://w3id.org/security#jws",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "https://w3id.org/security#proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EcdsaSecp256k1VerificationKey2019": "https://w3id.org/security#EcdsaSecp256k1VerificationKey2019",
|
||||
"EcdsaSecp256r1VerificationKey2019": "https://w3id.org/security#EcdsaSecp256r1VerificationKey2019",
|
||||
"Ed25519VerificationKey2018": "https://w3id.org/security#Ed25519VerificationKey2018",
|
||||
"EquihashProof2018": "https://w3id.org/security#EquihashProof2018",
|
||||
"ExportKeyOperation": "https://w3id.org/security#ExportKeyOperation",
|
||||
"GenerateKeyOperation": "https://w3id.org/security#GenerateKeyOperation",
|
||||
"KmsOperation": "https://w3id.org/security#KmsOperation",
|
||||
"RevokeKeyOperation": "https://w3id.org/security#RevokeKeyOperation",
|
||||
"RsaSignature2018": {
|
||||
"@id": "https://w3id.org/security#RsaSignature2018",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"jws": "https://w3id.org/security#jws",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": "https://w3id.org/security#proofValue",
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RsaVerificationKey2018": "https://w3id.org/security#RsaVerificationKey2018",
|
||||
"Sha256HmacKey2019": "https://w3id.org/security#Sha256HmacKey2019",
|
||||
"SignOperation": "https://w3id.org/security#SignOperation",
|
||||
"UnwrapKeyOperation": "https://w3id.org/security#UnwrapKeyOperation",
|
||||
"VerifyOperation": "https://w3id.org/security#VerifyOperation",
|
||||
"WrapKeyOperation": "https://w3id.org/security#WrapKeyOperation",
|
||||
"X25519KeyAgreementKey2019": "https://w3id.org/security#X25519KeyAgreementKey2019",
|
||||
|
||||
"allowedAction": "https://w3id.org/security#allowedAction",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capability": {
|
||||
"@id": "https://w3id.org/security#capability",
|
||||
"@type": "@id"
|
||||
},
|
||||
"capabilityAction": "https://w3id.org/security#capabilityAction",
|
||||
"capabilityChain": {
|
||||
"@id": "https://w3id.org/security#capabilityChain",
|
||||
"@type": "@id",
|
||||
"@container": "@list"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"caveat": {
|
||||
"@id": "https://w3id.org/security#caveat",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"ciphertext": "https://w3id.org/security#ciphertext",
|
||||
"controller": {
|
||||
"@id": "https://w3id.org/security#controller",
|
||||
"@type": "@id"
|
||||
},
|
||||
"delegator": {
|
||||
"@id": "https://w3id.org/security#delegator",
|
||||
"@type": "@id"
|
||||
},
|
||||
"equihashParameterK": {
|
||||
"@id": "https://w3id.org/security#equihashParameterK",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#:integer"
|
||||
},
|
||||
"equihashParameterN": {
|
||||
"@id": "https://w3id.org/security#equihashParameterN",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#:integer"
|
||||
},
|
||||
"invocationTarget": {
|
||||
"@id": "https://w3id.org/security#invocationTarget",
|
||||
"@type": "@id"
|
||||
},
|
||||
"invoker": {
|
||||
"@id": "https://w3id.org/security#invoker",
|
||||
"@type": "@id"
|
||||
},
|
||||
"jws": "https://w3id.org/security#jws",
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"kmsModule": {
|
||||
"@id": "https://w3id.org/security#kmsModule"
|
||||
},
|
||||
"parentCapability": {
|
||||
"@id": "https://w3id.org/security#parentCapability",
|
||||
"@type": "@id"
|
||||
},
|
||||
"plaintext": "https://w3id.org/security#plaintext",
|
||||
"proof": {
|
||||
"@id": "https://w3id.org/security#proof",
|
||||
"@type": "@id",
|
||||
"@container": "@graph"
|
||||
},
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@version": 1.1,
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"referenceId": "https://w3id.org/security#referenceId",
|
||||
"unwrappedKey": "https://w3id.org/security#unwrappedKey",
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
},
|
||||
"verifyData": "https://w3id.org/security#verifyData",
|
||||
"wrappedKey": "https://w3id.org/security#wrappedKey"
|
||||
}]
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"@protected": true,
|
||||
"proof": {
|
||||
"@id": "https://w3id.org/security#proof",
|
||||
"@type": "@id",
|
||||
"@container": "@graph"
|
||||
},
|
||||
"Ed25519VerificationKey2018": {
|
||||
"@id": "https://w3id.org/security#Ed25519VerificationKey2018",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"controller": {
|
||||
"@id": "https://w3id.org/security#controller",
|
||||
"@type": "@id"
|
||||
},
|
||||
"revoked": {
|
||||
"@id": "https://w3id.org/security#revoked",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"publicKeyBase58": {
|
||||
"@id": "https://w3id.org/security#publicKeyBase58"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Ed25519Signature2018": {
|
||||
"@id": "https://w3id.org/security#Ed25519Signature2018",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jws": {
|
||||
"@id": "https://w3id.org/security#jws"
|
||||
},
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"@protected": true,
|
||||
"proof": {
|
||||
"@id": "https://w3id.org/security#proof",
|
||||
"@type": "@id",
|
||||
"@container": "@graph"
|
||||
},
|
||||
"Ed25519VerificationKey2020": {
|
||||
"@id": "https://w3id.org/security#Ed25519VerificationKey2020",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"controller": {
|
||||
"@id": "https://w3id.org/security#controller",
|
||||
"@type": "@id"
|
||||
},
|
||||
"revoked": {
|
||||
"@id": "https://w3id.org/security#revoked",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"publicKeyMultibase": {
|
||||
"@id": "https://w3id.org/security#publicKeyMultibase",
|
||||
"@type": "https://w3id.org/security#multibase"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Ed25519Signature2020": {
|
||||
"@id": "https://w3id.org/security#Ed25519Signature2020",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proofValue": {
|
||||
"@id": "https://w3id.org/security#proofValue",
|
||||
"@type": "https://w3id.org/security#multibase"
|
||||
},
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
{
|
||||
"@context": {
|
||||
"privateKeyJwk": {
|
||||
"@id": "https://w3id.org/security#privateKeyJwk",
|
||||
"@type": "@json"
|
||||
},
|
||||
"JsonWebKey2020": {
|
||||
"@id": "https://w3id.org/security#JsonWebKey2020",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"publicKeyJwk": {
|
||||
"@id": "https://w3id.org/security#publicKeyJwk",
|
||||
"@type": "@json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonWebSignature2020": {
|
||||
"@id": "https://w3id.org/security#JsonWebSignature2020",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"jws": "https://w3id.org/security#jws",
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"@protected": true,
|
||||
"proof": {
|
||||
"@id": "https://w3id.org/security#proof",
|
||||
"@type": "@id",
|
||||
"@container": "@graph"
|
||||
},
|
||||
"EcdsaSecp256k1VerificationKey2019": {
|
||||
"@id": "https://w3id.org/security#EcdsaSecp256k1VerificationKey2019",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"controller": {
|
||||
"@id": "https://w3id.org/security#controller",
|
||||
"@type": "@id"
|
||||
},
|
||||
"revoked": {
|
||||
"@id": "https://w3id.org/security#revoked",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"blockchainAccountId": {
|
||||
"@id": "https://w3id.org/security#blockchainAccountId"
|
||||
},
|
||||
"publicKeyJwk": {
|
||||
"@id": "https://w3id.org/security#publicKeyJwk",
|
||||
"@type": "@json"
|
||||
},
|
||||
"publicKeyBase58": {
|
||||
"@id": "https://w3id.org/security#publicKeyBase58"
|
||||
},
|
||||
"publicKeyMultibase": {
|
||||
"@id": "https://w3id.org/security#publicKeyMultibase",
|
||||
"@type": "https://w3id.org/security#multibase"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EcdsaSecp256k1Signature2019": {
|
||||
"@id": "https://w3id.org/security#EcdsaSecp256k1Signature2019",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"challenge": "https://w3id.org/security#challenge",
|
||||
"created": {
|
||||
"@id": "http://purl.org/dc/terms/created",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"domain": "https://w3id.org/security#domain",
|
||||
"expires": {
|
||||
"@id": "https://w3id.org/security#expiration",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"nonce": "https://w3id.org/security#nonce",
|
||||
"proofPurpose": {
|
||||
"@id": "https://w3id.org/security#proofPurpose",
|
||||
"@type": "@vocab",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"assertionMethod": {
|
||||
"@id": "https://w3id.org/security#assertionMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"authentication": {
|
||||
"@id": "https://w3id.org/security#authenticationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityInvocation": {
|
||||
"@id": "https://w3id.org/security#capabilityInvocationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"capabilityDelegation": {
|
||||
"@id": "https://w3id.org/security#capabilityDelegationMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
},
|
||||
"keyAgreement": {
|
||||
"@id": "https://w3id.org/security#keyAgreementMethod",
|
||||
"@type": "@id",
|
||||
"@container": "@set"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jws": {
|
||||
"@id": "https://w3id.org/security#jws"
|
||||
},
|
||||
"verificationMethod": {
|
||||
"@id": "https://w3id.org/security#verificationMethod",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"@protected": true,
|
||||
"X25519KeyAgreementKey2019": {
|
||||
"@id": "https://w3id.org/security#X25519KeyAgreementKey2019",
|
||||
"@context": {
|
||||
"@protected": true,
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"controller": {
|
||||
"@id": "https://w3id.org/security#controller",
|
||||
"@type": "@id"
|
||||
},
|
||||
"revoked": {
|
||||
"@id": "https://w3id.org/security#revoked",
|
||||
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
|
||||
},
|
||||
"publicKeyBase58": {
|
||||
"@id": "https://w3id.org/security#publicKeyBase58"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package org.oneedtech.inspect.vc;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.apicatalog.did.key.DidKey;
|
||||
import com.apicatalog.ld.signature.ed25519.Ed25519Proof2020Adapter;
|
||||
import com.apicatalog.ld.signature.key.KeyPair;
|
||||
import com.apicatalog.ld.signature.proof.ProofOptions;
|
||||
import com.apicatalog.ld.signature.proof.VerificationMethod;
|
||||
import com.apicatalog.vc.Vc;
|
||||
import com.apicatalog.vc.processor.Issuer;
|
||||
|
||||
import jakarta.json.Json;
|
||||
import jakarta.json.JsonObject;
|
||||
import jakarta.json.JsonWriter;
|
||||
import jakarta.json.JsonWriterFactory;
|
||||
import jakarta.json.stream.JsonGenerator;
|
||||
|
||||
public class IronTests {
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
void testOb_01() {
|
||||
Assertions.assertDoesNotThrow(()->{
|
||||
|
||||
|
||||
final DidKey didKey = DidKey.from(URI.create("did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"));
|
||||
|
||||
//https://w3id.org/security#Ed25519KeyPair2020
|
||||
//https://w3id.org/security#Ed25519Signature2020
|
||||
URI unsigned = Samples.OB30.JSON.SIMPLE_JSON_NOPROOF.asURL().toURI();
|
||||
KeyPair kp = Vc.generateKeys("https://w3id.org/security#Ed25519Signature2020").get(URI.create("urn:1"), 256);
|
||||
ProofOptions options = ProofOptions.create(
|
||||
Ed25519Proof2020Adapter.TYPE,
|
||||
//new VerificationMethod(URI.create("did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj")),
|
||||
new VerificationMethod(didKey.toUri()),
|
||||
URI.create("https://w3id.org/security#assertionMethod")).created(Instant.now().truncatedTo(ChronoUnit.SECONDS));
|
||||
|
||||
Issuer issuer = Vc.sign(unsigned, kp, options);
|
||||
System.err.println(pretty(issuer.getCompacted()));
|
||||
JsonObject signed = issuer.getCompacted();
|
||||
JsonObject proof = signed.getJsonObject("sec:proof");
|
||||
Assertions.assertNotNull(proof);
|
||||
|
||||
Vc.verify(issuer.getCompacted()).isValid();
|
||||
});
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
void testClr_01() {
|
||||
Assertions.assertDoesNotThrow(()->{
|
||||
URI unsigned = Samples.CLR20.JSON.SIMPLE_JSON_NOPROOF.asURL().toURI();
|
||||
KeyPair kp = Vc.generateKeys("https://w3id.org/security#Ed25519Signature2020").get(URI.create("urn:1"), 256);
|
||||
ProofOptions options = ProofOptions.create(
|
||||
Ed25519Proof2020Adapter.TYPE,
|
||||
new VerificationMethod(URI.create("did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj")),
|
||||
URI.create("https://w3id.org/security#assertionMethod"));
|
||||
|
||||
Issuer issuer = Vc.sign(unsigned, kp, options);
|
||||
JsonObject job = issuer.getCompacted().getJsonObject("sec:proof");
|
||||
|
||||
//System.err.println (pretty(issuer.getCompacted().toString()));
|
||||
Assertions.assertNotNull(job);
|
||||
Vc.verify(issuer.getCompacted()).isValid();
|
||||
});
|
||||
}
|
||||
|
||||
String pretty(JsonObject jobj) {
|
||||
Map<String, Object> properties = new HashMap<>(1);
|
||||
properties.put(JsonGenerator.PRETTY_PRINTING, true);
|
||||
StringWriter sw = new StringWriter();
|
||||
JsonWriterFactory writerFactory = Json.createWriterFactory(properties);
|
||||
JsonWriter jsonWriter = writerFactory.createWriter(sw);
|
||||
jsonWriter.writeObject(jobj);
|
||||
jsonWriter.close();
|
||||
return sw.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
package org.oneedtech.inspect.vc;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.oneedtech.inspect.test.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.oneedtech.inspect.core.Inspector.Behavior;
|
||||
import org.oneedtech.inspect.core.probe.json.JsonSchemaProbe;
|
||||
import org.oneedtech.inspect.core.report.Report;
|
||||
import org.oneedtech.inspect.test.PrintHelper;
|
||||
import org.oneedtech.inspect.vc.probe.ContextPropertyProbe;
|
||||
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.TypePropertyProbe;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
public class OB30Tests {
|
||||
private static OB30Inspector validator;
|
||||
private static boolean verbose = true;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
validator = new OB30Inspector.Builder()
|
||||
.set(Behavior.TEST_INCLUDE_SUCCESS, true)
|
||||
.set(Behavior.VALIDATOR_FAIL_FAST, true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleJsonValid() {
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertValid(report);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimplePNGPlainValid() {
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.PNG.SIMPLE_JSON_PNG.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertValid(report);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimplePNGJWTValid() {
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.PNG.SIMPLE_JWT_PNG.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertValid(report);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleJsonSVGPlainValid() {
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.SVG.SIMPLE_JSON_SVG.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertValid(report);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleJsonSVGJWTValid() {
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.SVG.SIMPLE_JWT_SVG.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertValid(report);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleJsonInvalidUnknownType() {
|
||||
//add a dumb value to .type and remove the ob type
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_UNKNOWN_TYPE.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertInvalid(report);
|
||||
assertFatalCount(report, 1);
|
||||
assertHasProbeID(report, TypePropertyProbe.ID, true);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleJsonInvalidProofMethod() {
|
||||
//add some garbage chars to proofValue
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_PROOF_METHOD_ERROR.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertInvalid(report);
|
||||
assertErrorCount(report, 1);
|
||||
assertHasProbeID(report, EmbeddedProofProbe.ID, true);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleJsonInvalidProofValue() {
|
||||
//add some garbage chars to proofValue
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_PROOF_VALUE_ERROR.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertInvalid(report);
|
||||
assertErrorCount(report, 1);
|
||||
assertHasProbeID(report, EmbeddedProofProbe.ID, true);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleJsonExpired() {
|
||||
//"expirationDate": "2020-01-20T00:00:00Z",
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_EXPIRED.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertInvalid(report);
|
||||
assertHasProbeID(report, ExpirationProbe.ID, true);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleJsonContextError() {
|
||||
//removed one of the reqd context uris
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_ERR_CONTEXT.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertInvalid(report);
|
||||
assertHasProbeID(report, ContextPropertyProbe.ID, true);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleJsonSchemaError() throws Exception {
|
||||
//issuer removed
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_ISSUER.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertInvalid(report);
|
||||
assertHasProbeID(report, JsonSchemaProbe.ID, true);
|
||||
});
|
||||
}
|
||||
|
||||
@Disabled //TODO IssuanceVerifierProbe is not run because FATAL: InvalidSignature terminates
|
||||
@Test
|
||||
void testSimpleJsonNotIssued() {
|
||||
//"issuanceDate": "2040-01-01T00:00:00Z",
|
||||
//this breaks the proof too
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_ISSUED.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertInvalid(report);
|
||||
assertHasProbeID(report, IssuanceProbe.ID, true);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCompleteJsonInvalidInlineSchemaRef() throws Exception {
|
||||
//404 inline schema ref, and 404 refresh uri
|
||||
assertDoesNotThrow(()->{
|
||||
Report report = validator.run(Samples.OB30.JSON.COMPLETE_JSON.asFileResource());
|
||||
if(verbose) PrintHelper.print(report, true);
|
||||
assertFalse(report.asBoolean());
|
||||
assertTrue(Iterables.size(report.getErrors()) > 0);
|
||||
assertTrue(Iterables.size(report.getExceptions()) > 0);
|
||||
assertHasProbeID(report, InlineJsonSchemaProbe.ID, true);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.oneedtech.inspect.vc;
|
||||
|
||||
import org.oneedtech.inspect.test.Sample;
|
||||
|
||||
public class Samples {
|
||||
public static final class OB30 {
|
||||
public static final class SVG {
|
||||
public final static Sample SIMPLE_JSON_SVG = new Sample("ob30/simple-json.svg", true);
|
||||
public final static Sample SIMPLE_JWT_SVG = new Sample("ob30/simple-jwt.svg", true);
|
||||
}
|
||||
public static final class JSON {
|
||||
public final static Sample COMPLETE_JSON = new Sample("ob30/complete.json", false);
|
||||
public final static Sample SIMPLE_JSON = new Sample("ob30/simple.json", true);
|
||||
public final static Sample SIMPLE_JSON_NOPROOF = new Sample("ob30/simple-noproof.json", false);
|
||||
public final static Sample SIMPLE_JSON_UNKNOWN_TYPE = new Sample("ob30/simple-err-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_VALUE_ERROR = new Sample("ob30/simple-err-proof-value.json", false);
|
||||
public final static Sample SIMPLE_JSON_EXPIRED = new Sample("ob30/simple-err-expired.json", false);
|
||||
public final static Sample SIMPLE_JSON_ISSUED = new Sample("ob30/simple-err-issued.json", false);
|
||||
public final static Sample SIMPLE_JSON_ISSUER = new Sample("ob30/simple-err-issuer.json", false);
|
||||
public final static Sample SIMPLE_JSON_ERR_CONTEXT = new Sample("ob30/simple-err-context.json", false);
|
||||
}
|
||||
public static final class PNG {
|
||||
public final static Sample SIMPLE_JWT_PNG = new Sample("ob30/simple-jwt.png", true);
|
||||
public final static Sample SIMPLE_JSON_PNG = new Sample("ob30/simple-json.png", true);
|
||||
}
|
||||
public static final class JWT {
|
||||
public final static Sample SIMPLE_JWT = new Sample("ob30/simple.jwt", true);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class CLR20 {
|
||||
public static final class JSON {
|
||||
public final static Sample SIMPLE_JSON = new Sample("clr20/simple.json", true);
|
||||
public final static Sample SIMPLE_JSON_NOPROOF = new Sample("clr20/simple-noproof.json", true);
|
||||
public final static Sample SIMPLE_JWT = new Sample("clr20/simple.jwt", true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
package org.oneedtech.inspect.vc.credential;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.core.probe.RunContext.Key;
|
||||
import org.oneedtech.inspect.core.probe.json.JsonPathEvaluator;
|
||||
import org.oneedtech.inspect.util.json.ObjectMapperCache;
|
||||
import org.oneedtech.inspect.util.resource.Resource;
|
||||
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||
import org.oneedtech.inspect.vc.Credential;
|
||||
import org.oneedtech.inspect.vc.OB30Inspector;
|
||||
import org.oneedtech.inspect.vc.Samples;
|
||||
import org.oneedtech.inspect.vc.payload.PayloadParser;
|
||||
import org.oneedtech.inspect.vc.payload.PayloadParserFactory;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class PayloadParserTests {
|
||||
|
||||
@Test
|
||||
void testSvgStringExtract() {
|
||||
assertDoesNotThrow(()->{
|
||||
Resource res = Samples.OB30.SVG.SIMPLE_JSON_SVG.asFileResource(ResourceType.SVG);
|
||||
PayloadParser ext = PayloadParserFactory.of(res);
|
||||
assertNotNull(ext);
|
||||
Credential crd = ext.parse(res, mockOB30Context(res));
|
||||
//System.out.println(crd.getJson().toPrettyString());
|
||||
assertNotNull(crd);
|
||||
assertNotNull(crd.getJson());
|
||||
assertNotNull(crd.getJson().get("@context"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSvgJwtExtract() {
|
||||
assertDoesNotThrow(()->{
|
||||
Resource res = Samples.OB30.SVG.SIMPLE_JWT_SVG.asFileResource(ResourceType.SVG);
|
||||
PayloadParser ext = PayloadParserFactory.of(res);
|
||||
assertNotNull(ext);
|
||||
Credential crd = ext.parse(res, mockOB30Context(res));
|
||||
//System.out.println(crd.getJson().toPrettyString());
|
||||
assertNotNull(crd);
|
||||
assertNotNull(crd.getJson());
|
||||
assertNotNull(crd.getJson().get("@context"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPngStringExtract() {
|
||||
assertDoesNotThrow(()->{
|
||||
Resource res = Samples.OB30.PNG.SIMPLE_JSON_PNG.asFileResource(ResourceType.PNG);
|
||||
PayloadParser ext = PayloadParserFactory.of(res);
|
||||
assertNotNull(ext);
|
||||
Credential crd = ext.parse(res, mockOB30Context(res));
|
||||
//System.out.println(crd.getJson().toPrettyString());
|
||||
assertNotNull(crd);
|
||||
assertNotNull(crd.getJson());
|
||||
assertNotNull(crd.getJson().get("@context"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPngJwtExtract() {
|
||||
assertDoesNotThrow(()->{
|
||||
Resource res = Samples.OB30.PNG.SIMPLE_JWT_PNG.asFileResource(ResourceType.PNG);
|
||||
PayloadParser ext = PayloadParserFactory.of(res);
|
||||
assertNotNull(ext);
|
||||
Credential crd = ext.parse(res, mockOB30Context(res));
|
||||
//System.out.println(crd.getJson().toPrettyString());
|
||||
assertNotNull(crd);
|
||||
assertNotNull(crd.getJson());
|
||||
assertNotNull(crd.getJson().get("@context"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJwtExtract() {
|
||||
assertDoesNotThrow(()->{
|
||||
Resource res = Samples.OB30.JWT.SIMPLE_JWT.asFileResource(ResourceType.JWT);
|
||||
PayloadParser ext = PayloadParserFactory.of(res);
|
||||
assertNotNull(ext);
|
||||
Credential crd = ext.parse(res, mockOB30Context(res));
|
||||
//System.out.println(crd.getJson().toPrettyString());
|
||||
assertNotNull(crd);
|
||||
assertNotNull(crd.getJson());
|
||||
assertNotNull(crd.getJson().get("@context"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJsonExtract() {
|
||||
assertDoesNotThrow(()->{
|
||||
Resource res = Samples.OB30.JSON.SIMPLE_JSON.asFileResource(ResourceType.JSON);
|
||||
PayloadParser ext = PayloadParserFactory.of(res);
|
||||
assertNotNull(ext);
|
||||
Credential crd = ext.parse(res, mockOB30Context(res));
|
||||
//System.out.println(crd.getJson().toPrettyString());
|
||||
assertNotNull(crd);
|
||||
assertNotNull(crd.getJson());
|
||||
assertNotNull(crd.getJson().get("@context"));
|
||||
});
|
||||
}
|
||||
|
||||
private RunContext mockOB30Context(Resource res) {
|
||||
ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
|
||||
JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
|
||||
return new RunContext.Builder()
|
||||
.put(new OB30Inspector.Builder().build())
|
||||
.put(res)
|
||||
.put(Key.JACKSON_OBJECTMAPPER, mapper)
|
||||
.put(Key.JSONPATH_EVALUATOR, jsonPath)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.oneedtech.inspect.vc.util;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.apicatalog.jsonld.document.Document;
|
||||
import com.apicatalog.jsonld.loader.DocumentLoader;
|
||||
import com.apicatalog.jsonld.loader.DocumentLoaderOptions;
|
||||
|
||||
public class CachingDocumentLoaderTests {
|
||||
|
||||
@Test
|
||||
void testStaticCachedDocumentBundled() {
|
||||
Assertions.assertDoesNotThrow(()->{
|
||||
DocumentLoader loader = new CachingDocumentLoader();
|
||||
for(String id : CachingDocumentLoader.bundled.keySet()) {
|
||||
Document doc = loader.loadDocument(new URI(id), new DocumentLoaderOptions());
|
||||
Assertions.assertNotNull(doc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStaticCachedDocumentKey() {
|
||||
Assertions.assertDoesNotThrow(()->{
|
||||
DocumentLoader loader = new CachingDocumentLoader();
|
||||
URI uri = new URI("https://www.w3.org/ns/did/v1");
|
||||
Document doc = loader.loadDocument(uri, new DocumentLoaderOptions());
|
||||
Assertions.assertNotNull(doc);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package org.oneedtech.inspect.vc.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.oneedtech.inspect.core.probe.json.JsonPathEvaluator;
|
||||
import org.oneedtech.inspect.util.json.ObjectMapperCache;
|
||||
import org.oneedtech.inspect.vc.Samples;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
public class JsonNodeUtilTests {
|
||||
static final ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
|
||||
static final JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
|
||||
|
||||
@Test
|
||||
void testFlattenNodeList() {
|
||||
Assertions.assertDoesNotThrow(()->{
|
||||
String json = Samples.OB30.JSON.COMPLETE_JSON.asString();
|
||||
JsonNode root = mapper.readTree(json);
|
||||
List<JsonNode> list = JsonNodeUtil.asNodeList(root, "$..endorsement", jsonPath);
|
||||
Assertions.assertEquals(5, list.size());
|
||||
for(JsonNode node : list) {
|
||||
ArrayNode types = (ArrayNode) node.get("type");
|
||||
boolean found = false;
|
||||
for(JsonNode val : types) {
|
||||
if(val.asText().equals("EndorsementCredential")) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
assertTrue(found);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
712
inspector-vc/src/test/resources/ob30/complete.json
Normal file
712
inspector-vc/src/test/resources/ob30/complete.json
Normal file
@ -0,0 +1,712 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://1edtech.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"name": "1EdTech University Degree for Example Student",
|
||||
"description": "1EdTech University Degree Description",
|
||||
"image": {
|
||||
"id": "https://1edtech.edu/credentials/3732/image",
|
||||
"type": "Image",
|
||||
"caption": "1EdTech University Degree for Example Student"
|
||||
},
|
||||
"credentialSubject": {
|
||||
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
|
||||
"type": [
|
||||
"AchievementSubject"
|
||||
],
|
||||
"activityEndDate": "2010-01-02T00:00:00Z",
|
||||
"activityStartDate": "2010-01-01T00:00:00Z",
|
||||
"creditsEarned": 42,
|
||||
"licenseNumber": "A-9320041",
|
||||
"role": "Major Domo",
|
||||
"source": {
|
||||
"id": "https://school.edu/issuers/201234",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "1EdTech College of Arts"
|
||||
},
|
||||
"term": "Fall",
|
||||
"identifier": [
|
||||
{
|
||||
"type": "IdentityObject",
|
||||
"identityHash": "student@1edtech.edu",
|
||||
"identityType": "email",
|
||||
"hashed": false,
|
||||
"salt": "not-used"
|
||||
},
|
||||
{
|
||||
"type": "IdentityObject",
|
||||
"identityHash": "somebody@gmail.com",
|
||||
"identityType": "email",
|
||||
"hashed": false,
|
||||
"salt": "not-used"
|
||||
}
|
||||
],
|
||||
"achievement": {
|
||||
"id": "https://1edtech.edu/achievements/degree",
|
||||
"type": [
|
||||
"Achievement"
|
||||
],
|
||||
"alignment": [
|
||||
{
|
||||
"type": [
|
||||
"Alignment"
|
||||
],
|
||||
"targetCode": "degree",
|
||||
"targetDescription": "1EdTech University Degree programs.",
|
||||
"targetName": "1EdTech University Degree",
|
||||
"targetFramework": "1EdTech University Program and Course Catalog",
|
||||
"targetType": "CFItem",
|
||||
"targetUrl": "https://1edtech.edu/catalog/degree"
|
||||
},
|
||||
{
|
||||
"type": [
|
||||
"Alignment"
|
||||
],
|
||||
"targetCode": "degree",
|
||||
"targetDescription": "1EdTech University Degree programs.",
|
||||
"targetName": "1EdTech University Degree",
|
||||
"targetFramework": "1EdTech University Program and Course Catalog",
|
||||
"targetType": "CTDL",
|
||||
"targetUrl": "https://credentialengineregistry.org/resources/ce-98cb027b-95ef-4494-908d-6f7790ec6b6b"
|
||||
}
|
||||
],
|
||||
"achievementType": "Degree",
|
||||
"creator": {
|
||||
"id": "https://1edtech.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "1EdTech University",
|
||||
"url": "https://1edtech.edu",
|
||||
"phone": "1-222-333-4444",
|
||||
"description": "1EdTech University provides online degree programs.",
|
||||
"endorsement": [
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"EndorsementCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://accrediter.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example Accrediting Agency"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"expirationDate": "2020-01-01T00:00:00Z",
|
||||
"credentialSubject": {
|
||||
"id": "https://1edtech.edu/issuers/565049",
|
||||
"type": [
|
||||
"EndorsementSubject"
|
||||
],
|
||||
"endorsementComment": "1EdTech University is in good standing"
|
||||
},
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/endorsementcredential.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
},
|
||||
{
|
||||
"id": "https://accrediter.edu/schema/endorsementcredential.json",
|
||||
"type": "JsonSchemaValidator2018"
|
||||
}
|
||||
],
|
||||
"credentialStatus": {
|
||||
"id": "https://1edtech.edu/credentials/3732/revocations",
|
||||
"type": "1EdTechRevocationList"
|
||||
},
|
||||
"refreshService": {
|
||||
"id": "http://1edtech.edu/credentials/3732",
|
||||
"type": "1EdTechCredentialRefresh"
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-05-26T18:17:08Z",
|
||||
"verificationMethod": "https://accrediter.edu/issuers/565049#key-1",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"EndorsementCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://state.gov/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "State Department of Education"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"expirationDate": "2020-01-01T00:00:00Z",
|
||||
"credentialSubject": {
|
||||
"id": "https://1edtech.edu/issuers/565049",
|
||||
"type": [
|
||||
"EndorsementSubject"
|
||||
],
|
||||
"endorsementComment": "1EdTech University is in good standing"
|
||||
},
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/endorsementcredential.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
},
|
||||
{
|
||||
"id": "https://state.gov/schema/endorsementcredential.json",
|
||||
"type": "JsonSchemaValidator2018"
|
||||
}
|
||||
],
|
||||
"credentialStatus": {
|
||||
"id": "https://state.gov/credentials/3732/revocations",
|
||||
"type": "1EdTechRevocationList"
|
||||
},
|
||||
"refreshService": {
|
||||
"id": "http://state.gov/credentials/3732",
|
||||
"type": "1EdTechCredentialRefresh"
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-05-26T18:25:59Z",
|
||||
"verificationMethod": "https://accrediter.edu/issuers/565049#key-1",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z5bDnmSgDczXwZGya6ZjxKaxkdKxzsCMiVSsgEVWxnaWK7ZqbKnzcCd7mUKE9DQaAL2QMXP5AquPeW6W2CWrZ7jNC"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"image": {
|
||||
"id": "https://1edtech.edu/logo.png",
|
||||
"type": "Image",
|
||||
"caption": "1EdTech University logo"
|
||||
},
|
||||
"email": "registrar@1edtech.edu",
|
||||
"address": {
|
||||
"type": [
|
||||
"Address"
|
||||
],
|
||||
"addressCountry": "USA",
|
||||
"addressCountryCode": "US",
|
||||
"addressRegion": "TX",
|
||||
"addressLocality": "Austin",
|
||||
"streetAddress": "123 First St",
|
||||
"postOfficeBoxNumber": "1",
|
||||
"postalCode": "12345",
|
||||
"geo": {
|
||||
"type": "GeoCoordinates",
|
||||
"latitude": 1,
|
||||
"longitude": 1
|
||||
}
|
||||
},
|
||||
"otherIdentifier": [
|
||||
{
|
||||
"type": "IdentifierEntry",
|
||||
"identifier": "12345",
|
||||
"identifierType": "sourcedId"
|
||||
},
|
||||
{
|
||||
"type": "IdentifierEntry",
|
||||
"identifier": "67890",
|
||||
"identifierType": "nationalIdentityNumber"
|
||||
}
|
||||
],
|
||||
"official": "Horace Mann",
|
||||
"parentOrg": {
|
||||
"id": "did:example:123456789",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Universal Universities"
|
||||
}
|
||||
},
|
||||
"creditsAvailable": 36,
|
||||
"criteria": {
|
||||
"id": "https://1edtech.edu/achievements/degree",
|
||||
"narrative": "# Degree Requirements\nStudents must complete..."
|
||||
},
|
||||
"description": "1EdTech University Degree Description",
|
||||
"endorsement": [
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"EndorsementCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://accrediter.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example Accrediting Agency"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"expirationDate": "2020-01-01T00:00:00Z",
|
||||
"credentialSubject": {
|
||||
"id": "https://1edtech.edu/issuers/565049",
|
||||
"type": [
|
||||
"EndorsementSubject"
|
||||
],
|
||||
"endorsementComment": "1EdTech University is in good standing"
|
||||
},
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/endorsementcredential.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
},
|
||||
{
|
||||
"id": "https://accrediter.edu/schema/endorsementcredential.json",
|
||||
"type": "JsonSchemaValidator2018"
|
||||
}
|
||||
],
|
||||
"credentialStatus": {
|
||||
"id": "https://1edtech.edu/credentials/3732/revocations",
|
||||
"type": "1EdTechRevocationList"
|
||||
},
|
||||
"refreshService": {
|
||||
"id": "http://1edtech.edu/credentials/3732",
|
||||
"type": "1EdTechCredentialRefresh"
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-05-26T18:17:08Z",
|
||||
"verificationMethod": "https://accrediter.edu/issuers/565049#key-1",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"fieldOfStudy": "Research",
|
||||
"humanCode": "R1",
|
||||
"image": {
|
||||
"id": "https://1edtech.edu/achievements/degree/image",
|
||||
"type": "Image",
|
||||
"caption": "1EdTech University Degree"
|
||||
},
|
||||
"name": "1EdTech University Degree",
|
||||
"otherIdentifier": [
|
||||
{
|
||||
"type": "IdentifierEntry",
|
||||
"identifier": "abde",
|
||||
"identifierType": "identifier"
|
||||
}
|
||||
],
|
||||
"resultDescription": [
|
||||
{
|
||||
"id": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c",
|
||||
"type": [
|
||||
"ResultDescription"
|
||||
],
|
||||
"alignment": [
|
||||
{
|
||||
"type": [
|
||||
"Alignment"
|
||||
],
|
||||
"targetCode": "project",
|
||||
"targetDescription": "Project description",
|
||||
"targetName": "Final Project",
|
||||
"targetFramework": "1EdTech University Program and Course Catalog",
|
||||
"targetType": "CFItem",
|
||||
"targetUrl": "https://1edtech.edu/catalog/degree/project"
|
||||
}
|
||||
],
|
||||
"allowedValue": [
|
||||
"D",
|
||||
"C",
|
||||
"B",
|
||||
"A"
|
||||
],
|
||||
"name": "Final Project Grade",
|
||||
"requiredValue": "C",
|
||||
"resultType": "LetterGrade"
|
||||
},
|
||||
{
|
||||
"id": "urn:uuid:a70ddc6a-4c4a-4bd8-8277-cb97c79f40c5",
|
||||
"type": [
|
||||
"ResultDescription"
|
||||
],
|
||||
"alignment": [
|
||||
{
|
||||
"type": [
|
||||
"Alignment"
|
||||
],
|
||||
"targetCode": "project",
|
||||
"targetDescription": "Project description",
|
||||
"targetName": "Final Project",
|
||||
"targetFramework": "1EdTech University Program and Course Catalog",
|
||||
"targetType": "CFItem",
|
||||
"targetUrl": "https://1edtech.edu/catalog/degree/project"
|
||||
}
|
||||
],
|
||||
"allowedValue": [
|
||||
"D",
|
||||
"C",
|
||||
"B",
|
||||
"A"
|
||||
],
|
||||
"name": "Final Project Grade",
|
||||
"requiredLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a",
|
||||
"resultType": "RubricCriterionLevel",
|
||||
"rubricCriterionLevel": [
|
||||
{
|
||||
"id": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a",
|
||||
"type": [
|
||||
"RubricCriterionLevel"
|
||||
],
|
||||
"alignment": [
|
||||
{
|
||||
"type": [
|
||||
"Alignment"
|
||||
],
|
||||
"targetCode": "project",
|
||||
"targetDescription": "Project description",
|
||||
"targetName": "Final Project",
|
||||
"targetFramework": "1EdTech University Program and Course Catalog",
|
||||
"targetType": "CFRubricCriterionLevel",
|
||||
"targetUrl": "https://1edtech.edu/catalog/degree/project/rubric/levels/mastered"
|
||||
}
|
||||
],
|
||||
"description": "The author demonstrated...",
|
||||
"level": "Mastered",
|
||||
"name": "Mastery",
|
||||
"points": "4"
|
||||
},
|
||||
{
|
||||
"id": "urn:uuid:6b84b429-31ee-4dac-9d20-e5c55881f80e",
|
||||
"type": [
|
||||
"RubricCriterionLevel"
|
||||
],
|
||||
"alignment": [
|
||||
{
|
||||
"type": [
|
||||
"Alignment"
|
||||
],
|
||||
"targetCode": "project",
|
||||
"targetDescription": "Project description",
|
||||
"targetName": "Final Project",
|
||||
"targetFramework": "1EdTech University Program and Course Catalog",
|
||||
"targetType": "CFRubricCriterionLevel",
|
||||
"targetUrl": "https://1edtech.edu/catalog/degree/project/rubric/levels/basic"
|
||||
}
|
||||
],
|
||||
"description": "The author demonstrated...",
|
||||
"level": "Basic",
|
||||
"name": "Basic",
|
||||
"points": "4"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "urn:uuid:b07c0387-f2d6-4b65-a3f4-f4e4302ea8f7",
|
||||
"type": [
|
||||
"ResultDescription"
|
||||
],
|
||||
"name": "Project Status",
|
||||
"resultType": "Status"
|
||||
}
|
||||
],
|
||||
"specialization": "Computer Science Research",
|
||||
"tag": [
|
||||
"research",
|
||||
"computer science"
|
||||
]
|
||||
},
|
||||
"image": {
|
||||
"id": "https://1edtech.edu/credentials/3732/image",
|
||||
"type": "Image",
|
||||
"caption": "1EdTech University Degree for Example Student"
|
||||
},
|
||||
"narrative": "There is a final project report and source code evidence.",
|
||||
"result": [
|
||||
{
|
||||
"type": [
|
||||
"Result"
|
||||
],
|
||||
"alignment": [
|
||||
{
|
||||
"type": [
|
||||
"Alignment"
|
||||
],
|
||||
"targetCode": "project",
|
||||
"targetDescription": "Project description",
|
||||
"targetName": "Final Project",
|
||||
"targetFramework": "1EdTech University Program and Course Catalog",
|
||||
"targetType": "CFItem",
|
||||
"targetUrl": "https://1edtech.edu/catalog/degree/project/result/1"
|
||||
}
|
||||
],
|
||||
"resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c",
|
||||
"value": "A"
|
||||
},
|
||||
{
|
||||
"type": [
|
||||
"Result"
|
||||
],
|
||||
"achievedLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a",
|
||||
"alignment": [
|
||||
{
|
||||
"type": [
|
||||
"Alignment"
|
||||
],
|
||||
"targetCode": "project",
|
||||
"targetDescription": "Project description",
|
||||
"targetName": "Final Project",
|
||||
"targetFramework": "1EdTech University Program and Course Catalog",
|
||||
"targetType": "CFItem",
|
||||
"targetUrl": "https://1edtech.edu/catalog/degree/project/result/1"
|
||||
}
|
||||
],
|
||||
"resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c"
|
||||
},
|
||||
{
|
||||
"type": [
|
||||
"Result"
|
||||
],
|
||||
"resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c",
|
||||
"status": "Completed"
|
||||
}
|
||||
]
|
||||
},
|
||||
"endorsement": [
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"EndorsementCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://accrediter.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example Accrediting Agency"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"expirationDate": "2020-01-01T00:00:00Z",
|
||||
"credentialSubject": {
|
||||
"id": "https://1edtech.edu/issuers/565049",
|
||||
"type": [
|
||||
"EndorsementSubject"
|
||||
],
|
||||
"endorsementComment": "1EdTech University is in good standing"
|
||||
},
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/endorsementcredential.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
},
|
||||
{
|
||||
"id": "https://accrediter.edu/schema/endorsementcredential.json",
|
||||
"type": "JsonSchemaValidator2018"
|
||||
}
|
||||
],
|
||||
"credentialStatus": {
|
||||
"id": "https://1edtech.edu/credentials/3732/revocations",
|
||||
"type": "1EdTechRevocationList"
|
||||
},
|
||||
"refreshService": {
|
||||
"id": "http://1edtech.edu/credentials/3732",
|
||||
"type": "1EdTechCredentialRefresh"
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-05-26T18:17:08Z",
|
||||
"verificationMethod": "https://accrediter.edu/issuers/565049#key-1",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"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": [
|
||||
"Evidence"
|
||||
],
|
||||
"name": "Final Project Code",
|
||||
"description": "This is the source code for the final project app.",
|
||||
"genre": "Research",
|
||||
"audience": "Department"
|
||||
}
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://1edtech.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "1EdTech University",
|
||||
"url": "https://1edtech.edu",
|
||||
"phone": "1-222-333-4444",
|
||||
"description": "1EdTech University provides online degree programs.",
|
||||
"endorsement": [
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"EndorsementCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://accrediter.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example Accrediting Agency"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"expirationDate": "2020-01-01T00:00:00Z",
|
||||
"credentialSubject": {
|
||||
"id": "https://1edtech.edu/issuers/565049",
|
||||
"type": [
|
||||
"EndorsementSubject"
|
||||
],
|
||||
"endorsementComment": "1EdTech University is in good standing"
|
||||
},
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/endorsementcredential.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
},
|
||||
{
|
||||
"id": "https://accrediter.edu/schema/endorsementcredential.json",
|
||||
"type": "JsonSchemaValidator2018"
|
||||
}
|
||||
],
|
||||
"credentialStatus": {
|
||||
"id": "https://1edtech.edu/credentials/3732/revocations",
|
||||
"type": "1EdTechRevocationList"
|
||||
},
|
||||
"refreshService": {
|
||||
"id": "http://1edtech.edu/credentials/3732",
|
||||
"type": "1EdTechCredentialRefresh"
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-05-26T18:17:08Z",
|
||||
"verificationMethod": "https://accrediter.edu/issuers/565049#key-1",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"image": {
|
||||
"id": "https://1edtech.edu/logo.png",
|
||||
"type": "Image",
|
||||
"caption": "1EdTech University logo"
|
||||
},
|
||||
"email": "registrar@1edtech.edu",
|
||||
"address": {
|
||||
"type": [
|
||||
"Address"
|
||||
],
|
||||
"addressCountry": "USA",
|
||||
"addressCountryCode": "US",
|
||||
"addressRegion": "TX",
|
||||
"addressLocality": "Austin",
|
||||
"streetAddress": "123 First St",
|
||||
"postOfficeBoxNumber": "1",
|
||||
"postalCode": "12345",
|
||||
"geo": {
|
||||
"type": "GeoCoordinates",
|
||||
"latitude": 1,
|
||||
"longitude": 1
|
||||
}
|
||||
},
|
||||
"otherIdentifier": [
|
||||
{
|
||||
"type": "IdentifierEntry",
|
||||
"identifier": "12345",
|
||||
"identifierType": "sourcedId"
|
||||
},
|
||||
{
|
||||
"type": "IdentifierEntry",
|
||||
"identifier": "67890",
|
||||
"identifierType": "nationalIdentityNumber"
|
||||
}
|
||||
],
|
||||
"official": "Horace Mann",
|
||||
"parentOrg": {
|
||||
"id": "did:example:123456789",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Universal Universities"
|
||||
}
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"expirationDate": "2020-01-01T00:00:00Z",
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/achievementcredential.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
}
|
||||
],
|
||||
"credentialStatus": {
|
||||
"id": "https://1edtech.edu/credentials/3732/revocations",
|
||||
"type": "1EdTechRevocationList"
|
||||
},
|
||||
"refreshService": {
|
||||
"id": "http://1edtech.edu/credentials/3732",
|
||||
"type": "1EdTechCredentialRefresh"
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-06-09T22:56:28Z",
|
||||
"verificationMethod": "https://1edtech.edu/issuers/565049#key-1",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "zPpg92pBBEqRMxAqHMFQJ6Kmwf1thF9GdzqCofyWTLE6AhuahQixBNuG9BLgk6vb8K3NoqzanajYYYJbEcEhvQtM"
|
||||
}
|
||||
]
|
||||
}
|
35
inspector-vc/src/test/resources/ob30/simple-err-context.json
Normal file
35
inspector-vc/src/test/resources/ob30/simple-err-context.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://example.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example University"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"credentialSubject": {
|
||||
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
|
||||
"type": [
|
||||
"AchievementSubject"
|
||||
]
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-06-28T16:28:36Z",
|
||||
"verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnM"
|
||||
}
|
||||
]
|
||||
}
|
37
inspector-vc/src/test/resources/ob30/simple-err-expired.json
Normal file
37
inspector-vc/src/test/resources/ob30/simple-err-expired.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://example.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example University"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"expirationDate": "2020-01-20T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"credentialSubject": {
|
||||
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
|
||||
"type": [
|
||||
"AchievementSubject"
|
||||
]
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-06-28T16:28:36Z",
|
||||
"verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnM"
|
||||
}
|
||||
]
|
||||
}
|
37
inspector-vc/src/test/resources/ob30/simple-err-issued.json
Normal file
37
inspector-vc/src/test/resources/ob30/simple-err-issued.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://example.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example University"
|
||||
},
|
||||
"issuanceDate": "2040-01-01T00:00:00Z",
|
||||
"expirationDate": "2050-01-20T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"credentialSubject": {
|
||||
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
|
||||
"type": [
|
||||
"AchievementSubject"
|
||||
]
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-06-28T16:28:36Z",
|
||||
"verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnM"
|
||||
}
|
||||
]
|
||||
}
|
29
inspector-vc/src/test/resources/ob30/simple-err-issuer.json
Normal file
29
inspector-vc/src/test/resources/ob30/simple-err-issuer.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"credentialSubject": {
|
||||
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
|
||||
"type": [
|
||||
"AchievementSubject"
|
||||
]
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-06-28T16:28:36Z",
|
||||
"verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnM"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/context.json",
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/extensions.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://example.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example University"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
}
|
||||
],
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-09-15T15:48:32Z",
|
||||
"verificationMethod": "https://example.edu/issuers/565049#xxMkmY1R6tG2NEdRHzphdRT6JqxeYpHwLAHwbrDfQULpkMAj",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z3yUuWbFsLUp2CUrSZRaRbTk1UnkhpoJgJYu1SdMqd3AEMotpY41sKky7VzavnSfjApggtWJg1tcREvs5H4ZNnBRH"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/context.json",
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/extensions.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://example.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example University"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
}
|
||||
],
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-09-15T15:48:32Z",
|
||||
"verificationMethod": "https://example.edu/issuers/565049#z6MkmY1R6tG2NEdRHzphdRT6JqxeYpHwLAHwbrDfQULpkMAj",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z3fQCWGpz7b1HSH6DTwYiH5vutqtpJb5SHiP1VFK22xeBEW2D61tC9j3SktwPLNxPnTNZnPt4GeAZJPdVYserRqs4"
|
||||
}
|
||||
]
|
||||
}
|
36
inspector-vc/src/test/resources/ob30/simple-err-type.json
Normal file
36
inspector-vc/src/test/resources/ob30/simple-err-type.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OtherCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://example.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example University"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"credentialSubject": {
|
||||
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
|
||||
"type": [
|
||||
"AchievementSubject"
|
||||
]
|
||||
},
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-06-09T22:56:28Z",
|
||||
"verificationMethod": "https://example.edu/issuers/565049#key-1",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z58ieJCh4kN6eE2Vq4TyYURKSC4hWWEK7b75NNUL2taZMhKqwTteuByG1wRoGDdCqqNLW5Gq1diUi4qyZ63tQRtyN"
|
||||
}
|
||||
]
|
||||
}
|
BIN
inspector-vc/src/test/resources/ob30/simple-json.png
Normal file
BIN
inspector-vc/src/test/resources/ob30/simple-json.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
74
inspector-vc/src/test/resources/ob30/simple-json.svg
Normal file
74
inspector-vc/src/test/resources/ob30/simple-json.svg
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:openbadges="https://purl.imsglobal.org/ob/v3p0" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<openbadges:credential>
|
||||
<![CDATA[
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/context.json",
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/extensions.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://example.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example University"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
}
|
||||
],
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-09-15T15:48:32Z",
|
||||
"verificationMethod": "https://example.edu/issuers/565049#z6MkmY1R6tG2NEdRHzphdRT6JqxeYpHwLAHwbrDfQULpkMAj",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z3yUuWbFsLUp2CUrSZRaRbTk1UnkhpoJgJYu1SdMqd3AEMotpY41sKky7VzavnSfjApggtWJg1tcREvs5H4ZNnBRH"
|
||||
}
|
||||
]
|
||||
}
|
||||
]]>
|
||||
</openbadges:credential>
|
||||
<g>
|
||||
<path fill="none" stroke="#040000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M500,928.8c0,0,0,40.8,245,40.8" />
|
||||
<path fill="none" stroke="#040000" stroke-width="1.9215" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M500,928.8c0,0,40.8,0,285.8,0" />
|
||||
<path fill="none" stroke="#040000" stroke-width="1.9215" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M214.2,928.8c0,0,40.8,0,285.8,0" />
|
||||
<path fill="none" stroke="#040000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M500,928.8c0,0,0,40.8-245,40.8" />
|
||||
<path d="M581.7,316.2c22.6,0,40.8,18.3,40.8,40.8s-18.3,40.8-40.8,40.8c-22.6,0-40.8-18.3-40.8-40.8S559.1,316.2,581.7,316.2z" />
|
||||
<circle cx="418.3" cy="357.1" r="40.8" />
|
||||
<path d="M500,403.6c0,0-34.8,25.3-81.7,38.9c24.2,63.1,81.7,77.9,81.7,77.9s57.5-14.7,81.7-77.9C534.8,429,500,403.6,500,403.6z" />
|
||||
<path d="M856.6,689.6c0,0-3.3-89,16.6-196.2c39.4,104.7,119.7,164.3,116.8,203.3C930.9,739.3,856.6,689.6,856.6,689.6z" />
|
||||
<path d="M143.4,689.6c0,0,3.3-89-16.6-196.2C87.5,598.1,7.1,657.7,10.1,696.7C69.1,739.3,143.4,689.6,143.4,689.6z" />
|
||||
<path d="M835.4,367.4c0-232.1-184.3-337-335.4-337s-335.4,104.8-335.4,337c-3,24.9-42.3,125.5-42.3,151.4c0,269.7,109.3,450.8,377.8,450.8c268.5,0,377.8-181.1,377.8-450.8C877.8,492.9,838.4,392.2,835.4,367.4z M500,856.9c-119.1,0-264.4-56.5-264.4-265c0-100.2,37.8-148.3,37.8-148.3s-72.5-271.8,132.2-271.8c50.9,0,77.3,48.4,94.4,48.4s50.8-48.4,94.4-48.4c204.7,0,132.2,271.8,132.2,271.8s37.8,48.1,37.8,148.3C764.5,800.4,619.1,856.9,500,856.9z" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
BIN
inspector-vc/src/test/resources/ob30/simple-jwt.png
Normal file
BIN
inspector-vc/src/test/resources/ob30/simple-jwt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
17
inspector-vc/src/test/resources/ob30/simple-jwt.svg
Normal file
17
inspector-vc/src/test/resources/ob30/simple-jwt.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:openbadges="https://purl.imsglobal.org/ob/v3p0" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<openbadges:credential verify="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6IlJTQSIsIm4iOiI2dGM1dnJnQ2JzbGNrRzdPTTJoWkxJMnNxSHZabTdLS2FPTTItck1WczdyVjBRMEFiZk1ia1pXRzlfTENfM3RaelRld0tiblY1ZXZycFlVVGI4V09TVzk3dXNwZFFFMG5wR1pKdFdFWWgxaFJoM1hEVFBPVFRLa1ZwR2lJQWVocTdIRHJsYmxUZE41TUlqRWpPNnFhWTRhRzlIYXBMeXZHVUY2a2xGb2ctODZOWktOUXR0dVJvZWtlb3ZBdWhxZFhMd0RVZnJuOWlZTEowNmtWQkNKa1ZHdS1RYVlBbUFBcElfTFJGUWV4SF9BNXJQZnhZWEhReHctWmpBaVZNdkhwYmVtYkExWm9HUU5XOW92ZS1ZNWRQSm5CcWlDNEtSTzViMUctQU1KaVdHZDEwSFVkTEFDZ3FHX2FkWGktcmdHUFJINmpGRG9ZQzc2eDROQzBvVG9NS3cifX0.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9jb250ZXh0Lmpzb24iLCJodHRwczovL3B1cmwuaW1zZ2xvYmFsLm9yZy9zcGVjL29iL3YzcDAvZXh0ZW5zaW9ucy5qc29uIl0sImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiT3BlbkJhZGdlQ3JlZGVudGlhbCJdLCJpc3N1ZXIiOnsiaWQiOiJodHRwczovL2V4YW1wbGUuZWR1L2lzc3VlcnMvNTY1MDQ5IiwidHlwZSI6WyJQcm9maWxlIl0sIm5hbWUiOiJFeGFtcGxlIFVuaXZlcnNpdHkifSwiaXNzdWFuY2VEYXRlIjoiMjAxMC0wMS0wMVQwMDowMDowMFoiLCJuYW1lIjoiRXhhbXBsZSBVbml2ZXJzaXR5IERlZ3JlZSIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwidHlwZSI6WyJBY2hpZXZlbWVudFN1YmplY3QiXSwiYWNoaWV2ZW1lbnQiOnsiaWQiOiJodHRwczovL2V4YW1wbGUuY29tL2FjaGlldmVtZW50cy8yMXN0LWNlbnR1cnktc2tpbGxzL3RlYW13b3JrIiwidHlwZSI6WyJBY2hpZXZlbWVudCJdLCJjcml0ZXJpYSI6eyJuYXJyYXRpdmUiOiJUZWFtIG1lbWJlcnMgYXJlIG5vbWluYXRlZCBmb3IgdGhpcyBiYWRnZSBieSB0aGVpciBwZWVycyBhbmQgcmVjb2duaXplZCB1cG9uIHJldmlldyBieSBFeGFtcGxlIENvcnAgbWFuYWdlbWVudC4ifSwiZGVzY3JpcHRpb24iOiJUaGlzIGJhZGdlIHJlY29nbml6ZXMgdGhlIGRldmVsb3BtZW50IG9mIHRoZSBjYXBhY2l0eSB0byBjb2xsYWJvcmF0ZSB3aXRoaW4gYSBncm91cCBlbnZpcm9ubWVudC4iLCJuYW1lIjoiVGVhbXdvcmsifX0sImNyZWRlbnRpYWxTY2hlbWEiOlt7ImlkIjoiaHR0cHM6Ly9wdXJsLmltc2dsb2JhbC5vcmcvc3BlYy9vYi92M3AwL3NjaGVtYS9qc29uL29iX3YzcDBfYWNoaWV2ZW1lbnRjcmVkZW50aWFsX3NjaGVtYS5qc29uIiwidHlwZSI6IjFFZFRlY2hKc29uU2NoZW1hVmFsaWRhdG9yMjAxOSJ9XX0sImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5lZHUvaXNzdWVycy81NjUwNDkiLCJuYmYiOjEyNjIzMDQwMDAsImp0aSI6Imh0dHA6Ly9leGFtcGxlLmVkdS9jcmVkZW50aWFscy8zNzMyIiwic3ViIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIn0.ryVxvKHEQFu2b0Cu1L64A90ogiq4Ggkqv5i2ZN7phUt9AOlJfqKQIGrzl46CfmcaFqOBxwEJR_xtpaFRUrarwBnl81CSyHwVfSE1z9gQVLXgSRLNrh0UBMM53O4aVoJO-nYbr1f5YcS_d762o6TDlj9gAoCa3Y5j0vhwZPeRJD9cEONeYgpRhndYAD1SrFNvOopSQrY8l48p02oyYBdn1wSi0JOYAyn5MkvsfN6gL3P7GdOqoPYS-CoP3mtYrngUn9IwjpZUK7ZRnEzBgW_cvYwojZv5iYAtG56VN51JryxHeFL65rEchrCOnPNsQncx6M1UCx3RqOFgt_KE2pSKyw"></openbadges:credential>
|
||||
<g>
|
||||
<path fill="none" stroke="#040000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M500,928.8c0,0,0,40.8,245,40.8" />
|
||||
<path fill="none" stroke="#040000" stroke-width="1.9215" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M500,928.8c0,0,40.8,0,285.8,0" />
|
||||
<path fill="none" stroke="#040000" stroke-width="1.9215" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M214.2,928.8c0,0,40.8,0,285.8,0" />
|
||||
<path fill="none" stroke="#040000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M500,928.8c0,0,0,40.8-245,40.8" />
|
||||
<path d="M581.7,316.2c22.6,0,40.8,18.3,40.8,40.8s-18.3,40.8-40.8,40.8c-22.6,0-40.8-18.3-40.8-40.8S559.1,316.2,581.7,316.2z" />
|
||||
<circle cx="418.3" cy="357.1" r="40.8" />
|
||||
<path d="M500,403.6c0,0-34.8,25.3-81.7,38.9c24.2,63.1,81.7,77.9,81.7,77.9s57.5-14.7,81.7-77.9C534.8,429,500,403.6,500,403.6z" />
|
||||
<path d="M856.6,689.6c0,0-3.3-89,16.6-196.2c39.4,104.7,119.7,164.3,116.8,203.3C930.9,739.3,856.6,689.6,856.6,689.6z" />
|
||||
<path d="M143.4,689.6c0,0,3.3-89-16.6-196.2C87.5,598.1,7.1,657.7,10.1,696.7C69.1,739.3,143.4,689.6,143.4,689.6z" />
|
||||
<path d="M835.4,367.4c0-232.1-184.3-337-335.4-337s-335.4,104.8-335.4,337c-3,24.9-42.3,125.5-42.3,151.4c0,269.7,109.3,450.8,377.8,450.8c268.5,0,377.8-181.1,377.8-450.8C877.8,492.9,838.4,392.2,835.4,367.4z M500,856.9c-119.1,0-264.4-56.5-264.4-265c0-100.2,37.8-148.3,37.8-148.3s-72.5-271.8,132.2-271.8c50.9,0,77.3,48.4,94.4,48.4s50.8-48.4,94.4-48.4c204.7,0,132.2,271.8,132.2,271.8s37.8,48.1,37.8,148.3C764.5,800.4,619.1,856.9,500,856.9z" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.6 KiB |
27
inspector-vc/src/test/resources/ob30/simple-noproof.json
Normal file
27
inspector-vc/src/test/resources/ob30/simple-noproof.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://imsglobal.github.io/openbadges-specification/context.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://example.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example University"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"credentialSubject": {
|
||||
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
|
||||
"type": [
|
||||
"AchievementSubject"
|
||||
]
|
||||
}
|
||||
}
|
54
inspector-vc/src/test/resources/ob30/simple.json
Normal file
54
inspector-vc/src/test/resources/ob30/simple.json
Normal file
@ -0,0 +1,54 @@
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1",
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/context.json",
|
||||
"https://purl.imsglobal.org/spec/ob/v3p0/extensions.json",
|
||||
"https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
],
|
||||
"id": "http://example.edu/credentials/3732",
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"OpenBadgeCredential"
|
||||
],
|
||||
"issuer": {
|
||||
"id": "https://example.edu/issuers/565049",
|
||||
"type": [
|
||||
"Profile"
|
||||
],
|
||||
"name": "Example University"
|
||||
},
|
||||
"issuanceDate": "2010-01-01T00:00:00Z",
|
||||
"name": "Example University Degree",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"credentialSchema": [
|
||||
{
|
||||
"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json",
|
||||
"type": "1EdTechJsonSchemaValidator2019"
|
||||
}
|
||||
],
|
||||
"proof": [
|
||||
{
|
||||
"type": "Ed25519Signature2020",
|
||||
"created": "2022-09-15T15:48:32Z",
|
||||
"verificationMethod": "https://example.edu/issuers/565049#z6MkmY1R6tG2NEdRHzphdRT6JqxeYpHwLAHwbrDfQULpkMAj",
|
||||
"proofPurpose": "assertionMethod",
|
||||
"proofValue": "z3yUuWbFsLUp2CUrSZRaRbTk1UnkhpoJgJYu1SdMqd3AEMotpY41sKky7VzavnSfjApggtWJg1tcREvs5H4ZNnBRH"
|
||||
}
|
||||
]
|
||||
}
|
1
inspector-vc/src/test/resources/ob30/simple.jwt
Normal file
1
inspector-vc/src/test/resources/ob30/simple.jwt
Normal file
@ -0,0 +1 @@
|
||||
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vaW1zZ2xvYmFsLmdpdGh1Yi5pby9vcGVuYmFkZ2VzLXNwZWNpZmljYXRpb24vY29udGV4dC5qc29uIl0sImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiT3BlbkJhZGdlQ3JlZGVudGlhbCJdLCJpc3N1ZXIiOnsiaWQiOiJodHRwczovL2V4YW1wbGUuZWR1L2lzc3VlcnMvNTY1MDQ5IiwidHlwZSI6WyJQcm9maWxlIl0sIm5hbWUiOiJFeGFtcGxlIFVuaXZlcnNpdHkifSwiaXNzdWFuY2VEYXRlIjoiMjAxMC0wMS0wMVQwMDowMDowMFoiLCJuYW1lIjoiRXhhbXBsZSBVbml2ZXJzaXR5IERlZ3JlZSIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwidHlwZSI6WyJBY2hpZXZlbWVudFN1YmplY3QiXX19LCJpc3MiOiJodHRwczovL2V4YW1wbGUuZWR1L2lzc3VlcnMvNTY1MDQ5IiwibmJmIjoxMjYyMzA0MDAwLCJqdGkiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMzczMiIsInN1YiI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSJ9.G7W8od9rSZRsVyk26rXjg_fH2CyUihwNpepd6tWgLt_UHC1vUU0Clox8IicnOSkMyYEqAuNZAdCC9_35i1oUcyj1c076Aa0dsVQ2fFVuQPqXBlyZWcBmo5jqOK6R9NHzRAYXwLRXgrB8gz3lSK55cnHTnMtkpXXcUcHkS5ylWbXCLeOWKoygOCuxRN3N6kP-0HOyuk15PWlnkJ2zEKz2pBtVPaNEydcT0kEtoHFMEWVwqo6rnGV-Ea3M7ssDt3145mcl-DVYLXmBVdT8KoO47QAOBaVMR6k-hgrHNBcdhpI-o6IvLIFsGLgrNvWN67i8Z7Baum1mP-HBpsAigdmIpA
|
Loading…
Reference in New Issue
Block a user