From ebcd653faeb28e74fef0375f0d7f2f55b120745f Mon Sep 17 00:00:00 2001 From: Markus Gylling Date: Tue, 5 Jul 2022 23:26:05 +0200 Subject: [PATCH] add a caching document loader --- .../oneedtech/inspect/vc/OB30Inspector.java | 1 - .../inspect/vc/probe/CredentialTypeProbe.java | 3 + .../vc/util/CachingDocumentLoader.java | 64 +++ .../2018-credentials-examples-v1.jsonld | 69 +++ .../contexts/2018-credentials-v1.jsonld | 315 +++++++++++++ .../src/main/resources/contexts/did-v1.jsonld | 58 +++ .../src/main/resources/contexts/obv3.jsonld | 440 ++++++++++++++++++ .../src/main/resources/contexts/odrl.jsonld | 301 ++++++++++++ .../security-suites-ed25519-2020-v1.jsonld | 93 ++++ .../vc/util/CachingDocumentLoaderTests.java | 24 + 10 files changed, 1367 insertions(+), 1 deletion(-) create mode 100644 inspector-vc/src/main/java/org/oneedtech/inspect/vc/util/CachingDocumentLoader.java create mode 100644 inspector-vc/src/main/resources/contexts/2018-credentials-examples-v1.jsonld create mode 100644 inspector-vc/src/main/resources/contexts/2018-credentials-v1.jsonld create mode 100644 inspector-vc/src/main/resources/contexts/did-v1.jsonld create mode 100644 inspector-vc/src/main/resources/contexts/obv3.jsonld create mode 100644 inspector-vc/src/main/resources/contexts/odrl.jsonld create mode 100644 inspector-vc/src/main/resources/contexts/security-suites-ed25519-2020-v1.jsonld create mode 100644 inspector-vc/src/test/java/org/oneedtech/inspect/vc/util/CachingDocumentLoaderTests.java diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/OB30Inspector.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/OB30Inspector.java index 88f007e..16de1ae 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/OB30Inspector.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/OB30Inspector.java @@ -22,7 +22,6 @@ import org.oneedtech.inspect.core.probe.json.JsonPredicates.JsonPredicateProbePa 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.core.report.ReportUtil; import org.oneedtech.inspect.schema.JsonSchemaCache; import org.oneedtech.inspect.schema.SchemaKey; import org.oneedtech.inspect.util.json.ObjectMapperCache; diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/CredentialTypeProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/CredentialTypeProbe.java index 1995c0d..1634a82 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/CredentialTypeProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/CredentialTypeProbe.java @@ -44,6 +44,9 @@ public class CredentialTypeProbe extends Probe { Credential crd = null; try { + + //TODO: this reads from a URIResource twice. Cache the resource on first call. + Optional type = TypeDetector.detect(resource, true); if(type.isPresent()) { diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/util/CachingDocumentLoader.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/util/CachingDocumentLoader.java new file mode 100644 index 0000000..7032fe2 --- /dev/null +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/util/CachingDocumentLoader.java @@ -0,0 +1,64 @@ +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.Closeables; +import org.oneedtech.inspect.util.code.Tuple; + +import com.apicatalog.jsonld.JsonLdError; +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 DocumentLoader with a threadsafe static cache. + * @author mgylling + */ +public class CachingDocumentLoader implements DocumentLoader { + + @Override + public Document loadDocument(URI url, DocumentLoaderOptions options) throws JsonLdError { + Tuple tpl = new Tuple<>(url.toASCIIString(), options); + try { + return documentCache.get(tpl); + } catch (Exception e) { + logger.error("contextCache not able to load {}", url); + } + return null; + } + + private static final ImmutableMap bundled = ImmutableMap.builder() + .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://imsglobal.github.io/openbadges-specification/context.json", Resources.getResource("contexts/obv3.jsonld")) + .build(); + + private static final LoadingCache, Document> documentCache = CacheBuilder.newBuilder() + .initialCapacity(32) + .maximumSize(64) + .expireAfterAccess(Duration.ofHours(24)) + .build(new CacheLoader, Document>() { + public Document load(final Tuple 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); + } + } + }); + + private static final Logger logger = LogManager.getLogger(); +} diff --git a/inspector-vc/src/main/resources/contexts/2018-credentials-examples-v1.jsonld b/inspector-vc/src/main/resources/contexts/2018-credentials-examples-v1.jsonld new file mode 100644 index 0000000..425199c --- /dev/null +++ b/inspector-vc/src/main/resources/contexts/2018-credentials-examples-v1.jsonld @@ -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" + } + ] +} \ No newline at end of file diff --git a/inspector-vc/src/main/resources/contexts/2018-credentials-v1.jsonld b/inspector-vc/src/main/resources/contexts/2018-credentials-v1.jsonld new file mode 100644 index 0000000..837104f --- /dev/null +++ b/inspector-vc/src/main/resources/contexts/2018-credentials-v1.jsonld @@ -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" + } + } +} \ No newline at end of file diff --git a/inspector-vc/src/main/resources/contexts/did-v1.jsonld b/inspector-vc/src/main/resources/contexts/did-v1.jsonld new file mode 100644 index 0000000..55ab11c --- /dev/null +++ b/inspector-vc/src/main/resources/contexts/did-v1.jsonld @@ -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" + } + } +} \ No newline at end of file diff --git a/inspector-vc/src/main/resources/contexts/obv3.jsonld b/inspector-vc/src/main/resources/contexts/obv3.jsonld new file mode 100644 index 0000000..301efa5 --- /dev/null +++ b/inspector-vc/src/main/resources/contexts/obv3.jsonld @@ -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" + } + } +} \ No newline at end of file diff --git a/inspector-vc/src/main/resources/contexts/odrl.jsonld b/inspector-vc/src/main/resources/contexts/odrl.jsonld new file mode 100644 index 0000000..1da5c13 --- /dev/null +++ b/inspector-vc/src/main/resources/contexts/odrl.jsonld @@ -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" + } +} \ No newline at end of file diff --git a/inspector-vc/src/main/resources/contexts/security-suites-ed25519-2020-v1.jsonld b/inspector-vc/src/main/resources/contexts/security-suites-ed25519-2020-v1.jsonld new file mode 100644 index 0000000..8500805 --- /dev/null +++ b/inspector-vc/src/main/resources/contexts/security-suites-ed25519-2020-v1.jsonld @@ -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" + } + } + } + } +} \ No newline at end of file diff --git a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/util/CachingDocumentLoaderTests.java b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/util/CachingDocumentLoaderTests.java new file mode 100644 index 0000000..e51222a --- /dev/null +++ b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/util/CachingDocumentLoaderTests.java @@ -0,0 +1,24 @@ +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; +import com.google.common.io.Resources; + +public class CachingDocumentLoaderTests { + + @Test + void testStaticCachedDocument() { + Assertions.assertDoesNotThrow(()->{ + DocumentLoader loader = new CachingDocumentLoader(); + URI uri = Resources.getResource("contexts/did-v1.jsonld").toURI(); + Document doc = loader.loadDocument(uri, new DocumentLoaderOptions()); + Assertions.assertNotNull(doc); + }); + } +}