diff --git a/src/main/kotlin/id/walt/credentials/jsonld/VerifiableCredentialContexts.kt b/src/main/kotlin/id/walt/credentials/jsonld/VerifiableCredentialContexts.kt new file mode 100644 index 00000000..005e1433 --- /dev/null +++ b/src/main/kotlin/id/walt/credentials/jsonld/VerifiableCredentialContexts.kt @@ -0,0 +1,32 @@ +package id.walt.credentials.jsonld + +import com.apicatalog.jsonld.document.JsonDocument +import com.apicatalog.jsonld.http.media.MediaType +import com.apicatalog.jsonld.loader.DocumentLoader +import foundation.identity.jsonld.ConfigurableDocumentLoader +import info.weboftrust.ldsignatures.jsonld.LDSecurityContexts +import java.net.URI +import java.util.* + +object VerifiableCredentialContexts { + val DOCUMENT_LOADER: DocumentLoader by lazy { ConfigurableDocumentLoader(CONTEXTS) } + private val CONTEXTS: Map by lazy { + val map = LDSecurityContexts.CONTEXTS + runCatching { loadContextFiles() }.onSuccess { + map.putAll(it) + } + for ((key, value) in map) { + value.documentUrl = key + } + map + } + private val JSONLD_CONTEXT_W3C_2018_CREDENTIALS_V1 = URI.create("https://www.w3.org/2018/credentials/v1") + + private fun loadContextFiles() = mapOf( + JSONLD_CONTEXT_W3C_2018_CREDENTIALS_V1 to JsonDocument.of( + MediaType.JSON_LD, Objects.requireNonNull( + VerifiableCredentialContexts::class.java.classLoader.getResourceAsStream("credentials-v1.jsonld") + ) + ) + ) +} diff --git a/src/main/kotlin/id/walt/services/vc/WaltIdJsonLdCredentialService.kt b/src/main/kotlin/id/walt/services/vc/WaltIdJsonLdCredentialService.kt index 162e9e1d..0f0b5093 100644 --- a/src/main/kotlin/id/walt/services/vc/WaltIdJsonLdCredentialService.kt +++ b/src/main/kotlin/id/walt/services/vc/WaltIdJsonLdCredentialService.kt @@ -7,6 +7,7 @@ import foundation.identity.jsonld.ConfigurableDocumentLoader import foundation.identity.jsonld.JsonLDException import foundation.identity.jsonld.JsonLDObject import id.walt.auditor.VerificationPolicyResult +import id.walt.credentials.jsonld.VerifiableCredentialContexts import id.walt.credentials.w3c.* import id.walt.credentials.w3c.schema.SchemaValidatorFactory import id.walt.crypto.Key @@ -109,13 +110,13 @@ open class WaltIdJsonLdCredentialService : JsonLdCredentialService() { log.debug { "Signing jsonLd object with: issuerDid (${config.issuerDid}), domain (${config.domain}), nonce (${config.nonce}" } val jsonLdObject: JsonLDObject = JsonLDObject.fromJson(jsonCred) - val confLoader = LDSecurityContexts.DOCUMENT_LOADER as ConfigurableDocumentLoader + val confLoader = VerifiableCredentialContexts.DOCUMENT_LOADER as ConfigurableDocumentLoader confLoader.isEnableHttp = true confLoader.isEnableHttps = true confLoader.isEnableFile = true confLoader.isEnableLocalCache = true - jsonLdObject.documentLoader = LDSecurityContexts.DOCUMENT_LOADER + jsonLdObject.documentLoader = VerifiableCredentialContexts.DOCUMENT_LOADER as ConfigurableDocumentLoader val vm = config.issuerVerificationMethod ?: config.issuerDid val key = keyStore.load(vm) diff --git a/src/main/resources/credentials-v1.jsonld b/src/main/resources/credentials-v1.jsonld new file mode 100644 index 00000000..0124a3c4 --- /dev/null +++ b/src/main/resources/credentials-v1.jsonld @@ -0,0 +1,237 @@ +{ + "@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"} + } +}