diff --git a/README.md b/README.md index 7eeb99d3..4f2bff7f 100644 --- a/README.md +++ b/README.md @@ -63,13 +63,13 @@ fun main() { val issuerDid = DidService.create(DidMethod.ebsi) val holderDid = DidService.create(DidMethod.key) - // Issue VC in JSON-LD and JWT format (for show-casing both formats) + // Issue VC with LD_PROOF and JWT format (for show-casing both formats) val vcJson = Signatory.getService().issue( - templateId = "VerifiableId", + templateIdOrFilename = "VerifiableId", config = ProofConfig(issuerDid = issuerDid, subjectDid = holderDid, proofType = ProofType.LD_PROOF) ) val vcJwt = Signatory.getService().issue( - templateId = "Europass", + templateIdOrFilename = "Europass", config = ProofConfig(issuerDid = issuerDid, subjectDid = holderDid, proofType = ProofType.JWT) ) diff --git a/build.gradle.kts b/build.gradle.kts index ce6c3de7..a3b619b7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,8 +35,8 @@ dependencies { implementation("com.github.multiformats:java-multibase:v1.1.0") implementation("com.microsoft.azure:azure-keyvault:1.2.6") implementation("com.microsoft.azure:azure-client-authentication:1.7.14") - implementation("com.nimbusds:nimbus-jose-jwt:9.30.1") - implementation("com.nimbusds:oauth2-oidc-sdk:10.5.1") + implementation("com.nimbusds:nimbus-jose-jwt:9.30.2") + implementation("com.nimbusds:oauth2-oidc-sdk:10.7") implementation("org.bouncycastle:bcprov-jdk15to18:1.72") implementation("org.bouncycastle:bcpkix-jdk15to18:1.72") @@ -52,22 +52,23 @@ dependencies { implementation("com.beust:klaxon:5.6") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.0") implementation("com.jayway.jsonpath:json-path:2.7.0") - implementation("com.networknt:json-schema-validator:1.0.77") + implementation("com.networknt:json-schema-validator:1.0.78") implementation("net.pwall.json:json-kotlin-schema:0.39") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") // DB - implementation("org.xerial:sqlite-jdbc:3.39.4.1") + implementation("org.xerial:sqlite-jdbc:3.40.1.0") implementation("com.zaxxer:HikariCP:5.0.1") // CLI - implementation("com.github.ajalt.clikt:clikt-jvm:3.5.0") + implementation("com.github.ajalt.clikt:clikt-jvm:3.5.2") implementation("com.github.ajalt.clikt:clikt:3.5.0") // Misc implementation("commons-io:commons-io:2.11.0") implementation("io.minio:minio:8.4.6") + implementation("com.github.ben-manes.caffeine:caffeine:3.1.5") // HTTP implementation("io.ktor:ktor-client-jackson-jvm:2.2.4") @@ -107,9 +108,9 @@ dependencies { //testImplementation(kotlin("test-junit")) testImplementation("io.mockk:mockk:1.13.2") - testImplementation("io.kotest:kotest-runner-junit5:5.5.4") - testImplementation("io.kotest:kotest-assertions-core:5.5.4") - testImplementation("io.kotest:kotest-assertions-json:5.5.4") + testImplementation("io.kotest:kotest-runner-junit5:5.5.5") + testImplementation("io.kotest:kotest-assertions-core:5.5.5") + testImplementation("io.kotest:kotest-assertions-json:5.5.5") } diff --git a/src/main/kotlin/id/walt/DidCheqdTest.kt b/src/main/kotlin/id/walt/DidCheqdTest.kt deleted file mode 100644 index ab0ae478..00000000 --- a/src/main/kotlin/id/walt/DidCheqdTest.kt +++ /dev/null @@ -1,12 +0,0 @@ -package id.walt - -import id.walt.servicematrix.ServiceMatrix -import id.walt.services.did.DidService -import java.io.File - -fun main() { - ServiceMatrix("service-matrix.properties") - val did = DidService.importDidFromFile(File("did-cheqd.json")) - - println("DID imported: $did") -} diff --git a/src/main/kotlin/id/walt/PerformanceRun.kt b/src/main/kotlin/id/walt/PerformanceRun.kt new file mode 100644 index 00000000..93f06fd8 --- /dev/null +++ b/src/main/kotlin/id/walt/PerformanceRun.kt @@ -0,0 +1,43 @@ +package id.walt + +import id.walt.credentials.w3c.VerifiableCredential +import id.walt.credentials.w3c.W3CIssuer +import id.walt.model.DidMethod +import id.walt.servicematrix.ServiceMatrix +import id.walt.services.did.DidService +import id.walt.signatory.ProofConfig +import id.walt.signatory.ProofType +import id.walt.signatory.Signatory +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import java.io.File +import kotlin.system.measureTimeMillis + +val RESOURCES_PATH: String = "src/test/resources" + +fun getTemplate(name: String): VerifiableCredential = + VerifiableCredential.fromString(File("$RESOURCES_PATH/verifiable-credentials/vc-template-default.json").readText(Charsets.UTF_8)) + +suspend fun main() { + ServiceMatrix("service-matrix.properties") + val issuerWebDid: String = DidService.create(DidMethod.web) + + //val credentialService: JwtCredentialService = JwtCredentialService.getService() + val signatory = Signatory.getService() + val template = getTemplate("ebsi-attestation") + + template.issuer = W3CIssuer(issuerWebDid) + template.credentialSubject!!.id = issuerWebDid // self signed + + println("" + measureTimeMillis { + val jobs = ArrayList() + repeat(500000) { + jobs.add(GlobalScope.launch { + signatory.issue("VerifiableId", ProofConfig(issuerDid = issuerWebDid, proofType = ProofType.JWT)) + }) + } + + jobs.forEach { it.join() } + } + " ms overall") +} diff --git a/src/main/kotlin/id/walt/credentials/w3c/JsonConverter.kt b/src/main/kotlin/id/walt/credentials/w3c/JsonConverter.kt index 1c64218d..a919b3c0 100644 --- a/src/main/kotlin/id/walt/credentials/w3c/JsonConverter.kt +++ b/src/main/kotlin/id/walt/credentials/w3c/JsonConverter.kt @@ -1,6 +1,7 @@ package id.walt.credentials.w3c import kotlinx.serialization.json.* +import kotlin.reflect.jvm.jvmName object JsonConverter { @@ -9,34 +10,30 @@ object JsonConverter { is Number -> JsonPrimitive(value) is String -> JsonPrimitive(value) is Boolean -> JsonPrimitive(value) - is List<*> -> buildJsonArray { - value.forEach { add(toJsonElement(it)) } - } + null -> JsonNull - is Map<*, *> -> buildJsonObject { - value.keys.forEach { key -> - put(key.toString(), toJsonElement(value[key])) - } - } + is List<*> -> buildJsonArray { value.forEach { add(toJsonElement(it)) } } + is Map<*, *> -> buildJsonObject { value.keys.forEach { put(it.toString(), toJsonElement(value[it])) } } is JsonElement -> value - null -> JsonNull - else -> throw Exception("Json values can only be Number, String, List or Map") + + //else -> JsonNull + else -> throw Exception("Json values can only be Number, String, Boolean, Null, List or Map, not \"${value::class.jvmName}\": toString = $value") } } fun fromJsonElement(element: JsonElement): Any? { return when (element) { - is JsonPrimitive -> if (element.isString) { - element.contentOrNull - } else { - element.booleanOrNull ?: element.longOrNull ?: element.doubleOrNull + is JsonPrimitive -> when { + element.isString -> element.contentOrNull + else -> element.booleanOrNull ?: element.longOrNull ?: element.doubleOrNull } is JsonArray -> element.map { fromJsonElement(it) }.toList() is JsonObject -> element.keys.associateWith { - fromJsonElement(element[it] ?: JsonNull) - } + fromJsonElement(element[it] ?: JsonNull) + } + else -> throw IllegalArgumentException("Invalid JSON element \"${element::class.jvmName}\": $element") } } diff --git a/src/main/kotlin/id/walt/credentials/w3c/VerifiableCredential.kt b/src/main/kotlin/id/walt/credentials/w3c/VerifiableCredential.kt index e1feb193..129f46ef 100644 --- a/src/main/kotlin/id/walt/credentials/w3c/VerifiableCredential.kt +++ b/src/main/kotlin/id/walt/credentials/w3c/VerifiableCredential.kt @@ -74,7 +74,10 @@ open class VerifiableCredential internal constructor( } } - fun toJson() = toJsonObject().toString() + fun toJson(): String { + println("To JSON Object: $type $id") + return toJsonObject().toString() + } fun toJsonElement() = jwt?.let { JsonPrimitive(it) } ?: toJsonObject() override fun toString(): String { diff --git a/src/main/kotlin/id/walt/credentials/w3c/W3CCredentialSubject.kt b/src/main/kotlin/id/walt/credentials/w3c/W3CCredentialSubject.kt index 3aec3d85..23f66e5b 100644 --- a/src/main/kotlin/id/walt/credentials/w3c/W3CCredentialSubject.kt +++ b/src/main/kotlin/id/walt/credentials/w3c/W3CCredentialSubject.kt @@ -9,6 +9,7 @@ open class W3CCredentialSubject(var id: String? = null, override val properties: id?.let { put("id", it) } properties.let { props -> props.keys.forEach { key -> + println("Properties key: $key => ${props[key]}") put(key, JsonConverter.toJsonElement(props[key])) } } diff --git a/src/main/kotlin/id/walt/credentials/w3c/templates/VcTemplate.kt b/src/main/kotlin/id/walt/credentials/w3c/templates/VcTemplate.kt index 04508cce..b49b0492 100644 --- a/src/main/kotlin/id/walt/credentials/w3c/templates/VcTemplate.kt +++ b/src/main/kotlin/id/walt/credentials/w3c/templates/VcTemplate.kt @@ -1,9 +1,10 @@ package id.walt.credentials.w3c.templates +import id.walt.common.SingleVCObject import id.walt.credentials.w3c.VerifiableCredential data class VcTemplate( val name: String, - val template: VerifiableCredential? = null, + @SingleVCObject val template: VerifiableCredential? = null, val mutable: Boolean ) diff --git a/src/main/kotlin/id/walt/credentials/w3c/templates/VcTemplateManager.kt b/src/main/kotlin/id/walt/credentials/w3c/templates/VcTemplateManager.kt index c0b7be7d..096040a9 100644 --- a/src/main/kotlin/id/walt/credentials/w3c/templates/VcTemplateManager.kt +++ b/src/main/kotlin/id/walt/credentials/w3c/templates/VcTemplateManager.kt @@ -1,5 +1,6 @@ package id.walt.credentials.w3c.templates +import com.github.benmanes.caffeine.cache.Caffeine import id.walt.credentials.w3c.VerifiableCredential import id.walt.credentials.w3c.W3CIssuer import id.walt.credentials.w3c.toVerifiableCredential @@ -9,6 +10,7 @@ import mu.KotlinLogging import java.io.File import java.nio.file.FileSystems import java.nio.file.Files +import java.time.Duration import kotlin.io.path.isRegularFile import kotlin.io.path.nameWithoutExtension @@ -25,19 +27,60 @@ object VcTemplateManager { return VcTemplate(name, template, true) } + val templateCache = Caffeine.newBuilder() + .maximumSize(1000) + .expireAfterWrite(Duration.ofMinutes(10)) + .build() + + private fun String?.toVcTemplate(name: String, populateTemplate: Boolean, isMutable: Boolean) = + this?.let { VcTemplate(name, if (populateTemplate && it.isNotBlank()) it.toVerifiableCredential() else null, isMutable) } + + fun loadTemplateFromHkvStore(name: String, loadTemplate: Boolean) = + ContextManager.hkvStore.getAsString(HKVKey(SAVED_VC_TEMPLATES_KEY, name)) + .toVcTemplate(name, loadTemplate, true) + + fun loadTemplateFromResources(name: String, populateTemplate: Boolean) = + object {}.javaClass.getResource("/vc-templates/$name.json")?.readText() + .toVcTemplate(name, populateTemplate, false) + + fun loadTemplateFromFile(name: String, populateTemplate: Boolean, runtimeTemplateFolder: String) = + File("$runtimeTemplateFolder/$name.json").let { + if (it.exists()) it.readText() else null + }.toVcTemplate(name, populateTemplate, false) + + fun loadTemplate(name: String, populateTemplate: Boolean, runtimeTemplateFolder: String) = loadTemplateFromHkvStore(name, populateTemplate) + ?: loadTemplateFromResources(name, populateTemplate) + ?: loadTemplateFromFile(name, populateTemplate, runtimeTemplateFolder) + ?: throw IllegalArgumentException("No template found with name: $name") + + fun retrieveOrLoadCachedTemplate( + name: String, + populateTemplate: Boolean = true, + runtimeTemplateFolder: String = "/vc-templates-runtime" + ) = if(populateTemplate) { + // only add to cache, if template is populated + templateCache.get(name) { + loadTemplate(name, true, runtimeTemplateFolder) + } + } else { + // try to get from cache or load unpopulated template + (templateCache.getIfPresent(name) ?: loadTemplate(name, false, runtimeTemplateFolder)).let { + // reset populated template, in case it was loaded from cache + VcTemplate(it.name, null, it.mutable) + } + } + fun getTemplate( name: String, - loadTemplate: Boolean = true, + populateTemplate: Boolean = true, runtimeTemplateFolder: String = "/vc-templates-runtime" ): VcTemplate { - return ContextManager.hkvStore.getAsString(HKVKey(SAVED_VC_TEMPLATES_KEY, name)) - ?.let { VcTemplate(name, if (loadTemplate) it.toVerifiableCredential() else null, true) } - ?: object {}.javaClass.getResource("/vc-templates/$name.json")?.readText() - ?.let { VcTemplate(name, if (loadTemplate) it.toVerifiableCredential() else null, false) } - ?: File("$runtimeTemplateFolder/$name.json").let { - if (it.exists()) it.readText() else null - }?.let { VcTemplate(name, if (loadTemplate) it.toVerifiableCredential() else null, false) } - ?: throw IllegalArgumentException("No template found, with name $name") + val cachedTemplate = retrieveOrLoadCachedTemplate(name, populateTemplate, runtimeTemplateFolder) + + return if (cachedTemplate.template == null && populateTemplate) { + templateCache.invalidate(name) + retrieveOrLoadCachedTemplate(name, true, runtimeTemplateFolder) + } else cachedTemplate } private val resourceWalk = lazy { diff --git a/src/main/kotlin/id/walt/services/did/DidService.kt b/src/main/kotlin/id/walt/services/did/DidService.kt index b72c5313..057a0701 100644 --- a/src/main/kotlin/id/walt/services/did/DidService.kt +++ b/src/main/kotlin/id/walt/services/did/DidService.kt @@ -1,6 +1,7 @@ package id.walt.services.did import com.beust.klaxon.Klaxon +import com.github.benmanes.caffeine.cache.Caffeine import com.nimbusds.jose.jwk.Curve import com.nimbusds.jose.jwk.JWK import com.nimbusds.jose.util.Base64URL @@ -39,6 +40,7 @@ import java.nio.charset.StandardCharsets import java.security.KeyFactory import java.security.KeyPair import java.security.spec.X509EncodedKeySpec +import java.time.Duration import java.util.* @@ -116,10 +118,18 @@ object DidService { } } + private val didCache = Caffeine.newBuilder() + .maximumSize(1000) + .expireAfterWrite(Duration.ofMinutes(10)) + .build() + fun load(did: String): Did = load(DidUrl.from(did)) - fun load(didUrl: DidUrl): Did = Did.decode( - loadDid(didUrl.did) ?: throw IllegalArgumentException("DID $didUrl not found.") - ) ?: throw IllegalArgumentException("DID $didUrl not found.") + fun load(didUrl: DidUrl): Did = + didCache.get(didUrl) { + Did.decode( + loadDid(didUrl.did) ?: throw IllegalArgumentException("DID $didUrl could not be loaded/found.") + ) ?: throw IllegalArgumentException("DID $didUrl could not be decoded.") + } fun resolveDidEbsiRaw(did: String): String = runBlocking { log.debug { "Resolving DID $did" } @@ -192,7 +202,7 @@ object DidService { } fun loadDidEbsi(did: String): DidEbsi = loadDidEbsi(DidUrl.from(did)) - fun loadDidEbsi(didUrl: DidUrl): DidEbsi = Did.decode(loadDid(didUrl.did)!!)!! as DidEbsi + fun loadDidEbsi(didUrl: DidUrl): DidEbsi = load(didUrl.did) as DidEbsi fun updateDidEbsi(did: DidEbsi) = storeDid(did.id, did.encode()) @@ -648,6 +658,7 @@ object DidService { fun deleteDid(didUrl: String) { loadOrResolveAnyDid(didUrl)?.let { did -> + didCache.invalidate(DidUrl.from(didUrl)) ContextManager.hkvStore.delete(HKVKey("did", "created", didUrl), recursive = true) did.verificationMethod?.forEach { ContextManager.keyStore.delete(it.id) diff --git a/src/main/kotlin/id/walt/services/jwt/WaltIdJwtService.kt b/src/main/kotlin/id/walt/services/jwt/WaltIdJwtService.kt index f77b061f..cdec53df 100644 --- a/src/main/kotlin/id/walt/services/jwt/WaltIdJwtService.kt +++ b/src/main/kotlin/id/walt/services/jwt/WaltIdJwtService.kt @@ -67,17 +67,17 @@ open class WaltIdJwtService : JwtService() { private fun createSignedJwt(jwsAlgorithm: JWSAlgorithm, keyAlias: String, claimsSet: JWTClaimsSet, includeJwk: JWK?) = SignedJWT( - /* header = */ JWSHeader + JWSHeader .Builder(jwsAlgorithm) .keyID(keyAlias) .type(JOSEObjectType.JWT) .apply { includeJwk?.let { jwk(it) } }.build(), - /* claimsSet = */ claimsSet - ).also { + claimsSet + )/*.also { // log.debug { "Created signable JWT object: $it." } - } + }*/ override fun sign( diff --git a/src/main/kotlin/id/walt/signatory/Signatory.kt b/src/main/kotlin/id/walt/signatory/Signatory.kt index 364f6cfa..d3583703 100644 --- a/src/main/kotlin/id/walt/signatory/Signatory.kt +++ b/src/main/kotlin/id/walt/signatory/Signatory.kt @@ -42,7 +42,7 @@ data class ProofConfig( @Json(serializeNull = false) val subjectDid: String? = null, @Json(serializeNull = false) val verifierDid: String? = null, @Json(serializeNull = false) val issuerVerificationMethod: String? = null, // DID URL that defines key ID; if null the issuers' default key is used - val proofType: ProofType = ProofType.LD_PROOF, + val proofType: ProofType = ProofType.JWT, @Json(serializeNull = false) val domain: String? = null, @Json(serializeNull = false) val nonce: String? = null, @Json(serializeNull = false) val proofPurpose: String? = null, @@ -90,6 +90,7 @@ abstract class Signatory : WaltIdService() { open fun importTemplate(templateId: String, template: String): Unit = implementation.importTemplate(templateId, template) open fun removeTemplate(templateId: String): Unit = implementation.removeTemplate(templateId) + open fun hasTemplateId(templateId: String): Boolean = implementation.hasTemplateId(templateId) } class WaltIdSignatory(configurationPath: String) : Signatory() { @@ -149,7 +150,8 @@ class WaltIdSignatory(configurationPath: String) : Signatory() { val credentialBuilder = when (Files.exists(Path.of(templateIdOrFilename))) { true -> Files.readString(Path.of(templateIdOrFilename)).toVerifiableCredential() else -> VcTemplateManager.getTemplate(templateIdOrFilename, true, configuration.templatesFolder).template - }?.let { W3CCredentialBuilder.fromPartial(it) } ?: throw Exception("Template not found") + }?.let { W3CCredentialBuilder.fromPartial(it) } + ?: throw Exception("Template could not be loaded: $templateIdOrFilename") return issue(dataProvider?.populate(credentialBuilder, config) ?: credentialBuilder, config, issuer, storeCredential) } @@ -173,7 +175,7 @@ class WaltIdSignatory(configurationPath: String) : Signatory() { fullProofConfig.expirationDate?.let { setExpirationDate(it) } }.build() - log.info { "Signing credential with proof using ${fullProofConfig.proofType.name}..." } + log.debug { "Signing credential with proof using ${fullProofConfig.proofType.name}..." } log.debug { "Signing credential with proof using ${fullProofConfig.proofType.name}, credential is: $vcRequest" } val signedVc = when (fullProofConfig.proofType) { ProofType.LD_PROOF -> JsonLdCredentialService.getService().sign(vcRequest.toJson(), fullProofConfig) @@ -188,10 +190,14 @@ class WaltIdSignatory(configurationPath: String) : Signatory() { return signedVc } + override fun hasTemplateId(templateId: String) = + runCatching { VcTemplateManager.getTemplate(templateId, false) }.getOrNull() != null + override fun listTemplates(): List = VcTemplateManager.listTemplates(configuration.templatesFolder) override fun listTemplateIds() = VcTemplateManager.listTemplates(configuration.templatesFolder).map { it.name } override fun loadTemplate(templateId: String): VerifiableCredential = - VcTemplateManager.getTemplate(templateId, true, configuration.templatesFolder).template!! + VcTemplateManager.getTemplate(templateId, true, configuration.templatesFolder).template + ?: throw IllegalArgumentException("Could not load template \"$templateId\" into WaltSignatory") override fun importTemplate(templateId: String, template: String) { val vc = VerifiableCredential.fromJson(template) diff --git a/src/main/kotlin/id/walt/signatory/rest/SignatoryController.kt b/src/main/kotlin/id/walt/signatory/rest/SignatoryController.kt index f2f4d0c2..51924c8b 100644 --- a/src/main/kotlin/id/walt/signatory/rest/SignatoryController.kt +++ b/src/main/kotlin/id/walt/signatory/rest/SignatoryController.kt @@ -1,5 +1,6 @@ package id.walt.signatory.rest +import id.walt.common.KlaxonWithConverters import id.walt.credentials.w3c.JsonConverter import id.walt.credentials.w3c.VerifiableCredential import id.walt.credentials.w3c.builder.W3CCredentialBuilder @@ -24,7 +25,7 @@ object SignatoryController { val signatory = Signatory.getService() fun listTemplates(ctx: Context) { - ctx.json(signatory.listTemplates()) + ctx.contentType(ContentType.APPLICATION_JSON).result(KlaxonWithConverters().toJsonString(signatory.listTemplates())) } fun listTemplatesDocs() = document().operation { @@ -68,7 +69,7 @@ object SignatoryController { fun issueCredential(ctx: Context) { val req = ctx.bodyAsClass() - if (req.templateId != null && !signatory.listTemplateIds().contains(req.templateId)) { + if (req.templateId != null && !signatory.hasTemplateId(req.templateId)) { throw BadRequestResponse("Template with supplied id does not exist.") } if (req.templateId == null && req.credentialData == null) { diff --git a/src/test/kotlin/id/walt/Performance.kt b/src/test/kotlin/id/walt/Performance.kt index 406e2cb0..8f315bce 100644 --- a/src/test/kotlin/id/walt/Performance.kt +++ b/src/test/kotlin/id/walt/Performance.kt @@ -1,12 +1,20 @@ package id.walt - +/* import id.walt.credentials.w3c.W3CIssuer import id.walt.model.DidMethod import id.walt.servicematrix.ServiceMatrix import id.walt.services.did.DidService +import id.walt.signatory.ProofConfig +import id.walt.signatory.ProofType import id.walt.signatory.Signatory import id.walt.test.getTemplate import io.kotest.core.spec.style.StringSpec +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlin.system.measureTimeMillis + class Performance : StringSpec({ @@ -20,12 +28,9 @@ class Performance : StringSpec({ template.issuer = W3CIssuer(issuerWebDid) template.credentialSubject!!.id = issuerWebDid // self signed - val credOffer: String = template.toJson() - - /* "Issue 1" { val jobs = ArrayList() - repeat(10000) { + repeat(100000) { jobs.add(GlobalScope.launch { println("" + measureTimeMillis { signatory.issue("VerifiableId", ProofConfig(issuerDid = issuerWebDid, proofType = ProofType.JWT)) @@ -36,37 +41,5 @@ class Performance : StringSpec({ jobs.forEach { it.join() } } - "Issue 2" { - val jobs = ArrayList() - - measureTimeMillis { - - repeat(50000) { - launch(Dispatchers.Default) { - signatory.issue("VerifiableId", ProofConfig(issuerDid = issuerWebDid, proofType = ProofType.JWT)) - }.let { jobs.add(it) } - } - - jobs.forEach { it.join() } - }.let { println("=> Full issuance: $it ms") } - } - - "Issue 3" { - val offers = ArrayList().apply { - repeat(10000) { - add(credOffer) - } - } - - measureTimeMillis { - offers - .map { /*launch(Dispatchers.Default) {*/ - measureTimeMillis { - signatory.issue("VerifiableId", ProofConfig(issuerDid = issuerWebDid, proofType = ProofType.JWT)) - }.let { println("Single issuance: $it ms") } - /*}*/} - //.forEach { it.join() } - }.let { println("=> Full issuance: $it ms") } - } - */ }) +*/ diff --git a/src/test/kotlin/id/walt/services/ReadmeTest.kt b/src/test/kotlin/id/walt/services/ReadmeTest.kt index 20c12831..f626aed9 100644 --- a/src/test/kotlin/id/walt/services/ReadmeTest.kt +++ b/src/test/kotlin/id/walt/services/ReadmeTest.kt @@ -28,7 +28,7 @@ class ReadmeTest : StringSpec({ val issuerDid = DidService.create(DidMethod.ebsi) val holderDid = DidService.create(DidMethod.key) - // Issue VC in JSON-LD and JWT format (for show-casing both formats) + // Issue VC with LD_PROOF and JWT format (for show-casing both formats) val vcJson = Signatory.getService().issue( templateIdOrFilename = "VerifiableId", config = ProofConfig(issuerDid = issuerDid, subjectDid = holderDid, proofType = ProofType.LD_PROOF) diff --git a/src/test/kotlin/id/walt/services/oidc/OIDC4VCTest.kt b/src/test/kotlin/id/walt/services/oidc/OIDC4VCTest.kt index 40ffb784..48785ee2 100644 --- a/src/test/kotlin/id/walt/services/oidc/OIDC4VCTest.kt +++ b/src/test/kotlin/id/walt/services/oidc/OIDC4VCTest.kt @@ -183,7 +183,7 @@ class OIDC4VCTest : AnnotationSpec() { @Test fun testVerifyPresentation() { - val credential = Signatory.getService().issue("VerifiableId", ProofConfig(OIDCTestProvider.ISSUER_DID, SUBJECT_DID)) + val credential = Signatory.getService().issue("VerifiableId", ProofConfig(OIDCTestProvider.ISSUER_DID, SUBJECT_DID, proofType = ProofType.LD_PROOF)) val presentation = Custodian.getService().createPresentation(listOf(credential), SUBJECT_DID) .toVerifiablePresentation() val req = OIDC4VPService.createOIDC4VPRequest( @@ -230,7 +230,7 @@ class OIDC4VCTest : AnnotationSpec() { @Test fun testVerifyMultiplePresentations() { - val credential = Signatory.getService().issue("VerifiableId", ProofConfig(OIDCTestProvider.ISSUER_DID, SUBJECT_DID)) + val credential = Signatory.getService().issue("VerifiableId", ProofConfig(OIDCTestProvider.ISSUER_DID, SUBJECT_DID, proofType = ProofType.LD_PROOF)) val presentation = Custodian.getService().createPresentation(listOf(credential), SUBJECT_DID) .toVerifiablePresentation() val req = OIDC4VPService.createOIDC4VPRequest( diff --git a/src/test/kotlin/id/walt/signatory/SignatoryApiTest.kt b/src/test/kotlin/id/walt/signatory/SignatoryApiTest.kt index 343447ae..b67f6c76 100644 --- a/src/test/kotlin/id/walt/signatory/SignatoryApiTest.kt +++ b/src/test/kotlin/id/walt/signatory/SignatoryApiTest.kt @@ -13,6 +13,7 @@ import id.walt.signatory.rest.IssueCredentialRequest import id.walt.signatory.rest.SignatoryRestAPI import id.walt.test.RESOURCES_PATH import io.kotest.core.spec.style.AnnotationSpec +import io.kotest.inspectors.shouldForAll import io.kotest.matchers.collections.shouldContain import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe @@ -64,13 +65,20 @@ class SignatoryApiTest : AnnotationSpec() { fun testListVcTemplates() = runBlocking { val templates = client.get("$SIGNATORY_API_URL/v1/templates").bodyAsText() + .also { println("BODY: $it") } .let { KlaxonWithConverters().parseArray(it) }!! - .map { it.name } + // make sure templates are not populated + templates.forEach { + it.template shouldBe null + } + val templateNames = templates.map { it.name } + + templateNames shouldContain "Europass" + templateNames shouldContain "VerifiablePresentation" - VcTemplateManager.listTemplates().map { it.name }.forEach { templateName -> templates shouldContain templateName } + VcTemplateManager.listTemplates().map { it.name }.forEach { templateName -> templateNames shouldContain templateName } - templates shouldContain "Europass" - templates shouldContain "VerifiablePresentation" + println(templates) } diff --git a/src/test/kotlin/id/walt/signatory/SignatoryServiceTest.kt b/src/test/kotlin/id/walt/signatory/SignatoryServiceTest.kt index 26352a81..01a33e07 100644 --- a/src/test/kotlin/id/walt/signatory/SignatoryServiceTest.kt +++ b/src/test/kotlin/id/walt/signatory/SignatoryServiceTest.kt @@ -39,7 +39,8 @@ class SignatoryServiceTest : StringSpec({ subjectDid = did, issuerDid = did, issueDate = LocalDateTime.of(2020, 11, 3, 0, 0).toInstant(ZoneOffset.UTC), - issuerVerificationMethod = vm + issuerVerificationMethod = vm, + proofType = ProofType.LD_PROOF ) ) @@ -59,9 +60,7 @@ class SignatoryServiceTest : StringSpec({ println("ISSUING CREDENTIAL...") val jwtStr = signatory.issue( "VerifiableId", ProofConfig( - subjectDid = did, - issuerDid = did, - proofType = ProofType.JWT + subjectDid = did, issuerDid = did, proofType = ProofType.JWT ) ) @@ -89,7 +88,8 @@ class SignatoryServiceTest : StringSpec({ subjectDid = did, issuerDid = did, issueDate = LocalDateTime.of(2020, 11, 3, 0, 0).toInstant(ZoneOffset.UTC), - issuerVerificationMethod = vm + issuerVerificationMethod = vm, + proofType = ProofType.LD_PROOF ) ) @@ -108,7 +108,8 @@ class SignatoryServiceTest : StringSpec({ "Issue and verify: VerifiableDiploma (JWT-Proof)" { println("ISSUING CREDENTIAL...") val jwtStr = signatory.issue( - "VerifiableDiploma", ProofConfig(subjectDid = did, issuerDid = did, proofType = ProofType.JWT) + "VerifiableDiploma", + ProofConfig(subjectDid = did, issuerDid = did, proofType = ProofType.JWT) ) println("VC:") @@ -145,8 +146,7 @@ class SignatoryServiceTest : StringSpec({ val builder = W3CCredentialBuilder() val data = mapOf(Pair("credentialSubject", mapOf(Pair("firstName", "Yves")))) val populated = MergingDataProvider(data).populate( - builder, - ProofConfig(subjectDid = did, issuerDid = did, proofType = ProofType.LD_PROOF) + builder, ProofConfig(subjectDid = did, issuerDid = did, proofType = ProofType.LD_PROOF) ).build() populated.credentialSubject?.properties?.get("firstName") shouldBe "Yves" @@ -168,9 +168,7 @@ class SignatoryServiceTest : StringSpec({ """.trimIndent() val signedVC = Signatory.getService().issue( - W3CCredentialBuilder - .fromPartial(template) - .setFromJson(userData), + W3CCredentialBuilder.fromPartial(template).setFromJson(userData), ProofConfig(subjectDid = did, issuerDid = did, proofType = ProofType.LD_PROOF) ) @@ -189,11 +187,10 @@ class SignatoryServiceTest : StringSpec({ "sign any credential with user data from subject builder" { val signedVC = Signatory.getService().issue( - W3CCredentialBuilder() - .buildSubject { - setProperty("firstName", "Inco") - setProperty("familyName", "GNITO") - }, + W3CCredentialBuilder().buildSubject { + setProperty("firstName", "Inco") + setProperty("familyName", "GNITO") + }, ProofConfig(subjectDid = did, issuerDid = did, proofType = ProofType.LD_PROOF), W3CIssuer(did, mapOf("name" to "Test Issuer")) ) diff --git a/src/test/resources/vc-templates/AmletCredential.json b/src/test/resources/vc-templates/AmletCredential.json new file mode 100644 index 00000000..c7488d35 --- /dev/null +++ b/src/test/resources/vc-templates/AmletCredential.json @@ -0,0 +1,44 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/schemas/AmletCredential.json", + "type": "JsonSchemaValidator2018" + }, + "credentialSubject": { + "birthDate": "1995-05-03", + "birthPlace": "Milan", + "company": { + "address": "VLE. BACCHIGLIONE 20, MILANO", + "email": "info@mopso.it", + "foundingDate": "2021-01-01", + "hasInternationalActivity": true, + "isRecipientOfPublicFunds": true, + "isRiskSector": false, + "name": "Mopso", + "revenue": "10000", + "ultimateBeneficialOwners": [{ + "address": "Milan, Italy", + "birthDate": "1995-05-03", + "birthPlace": "Milan", + "citizenship": "Italian", + "familyName": "Doe", + "givenName": "Jane", + "isPep": false, + "taxID": "DOEJNA95M43Z330V" + }], + "vatId": "11717750969" + }, + "execRappr": "LEGAL REPRESENTATIVE", + "familyName": "Doe", + "givenName": "Jane", + "id": "did:ebsi:zukSNRQ7Umb2TzbRLNkTGX4#3bf09a67ac1348f4bfe35b7c7fc54fba", + "taxID": "DOEJNA95M43Z330V" + }, + "expirationDate": "2023-03-21T00:00:00Z", + "id": "", + "issued": "2022-03-21T00:00:00Z", + "issuer": "did:ebsi:zkttgPyjddU8JqrkQ9aV5MW#6462224517f04e9d84ba1ea09c82e01c", + "validFrom": "2022-03-21T00:00:00Z", + "issuanceDate": "2022-03-21T00:00:00Z", + "type": ["VerifiableCredential", "AmletCredential"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/DataConsortium.json b/src/test/resources/vc-templates/DataConsortium.json new file mode 100644 index 00000000..1d20af23 --- /dev/null +++ b/src/test/resources/vc-templates/DataConsortium.json @@ -0,0 +1,18 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "id": "1234" + }, + "dataspace": [{ + "id": "Gaia-X AISBL", + "serviceEndpoint": "https://endpoint1.io" + }, { + "id": "Gaia-X XYZ", + "serviceEndpoint": "https://endpoint2.io" + }], + "expirationDate": "2022-01-06T20:38:38Z", + "id": "1234", + "issued": "2022-01-03T20:38:38Z", + "issuer": "did:web:vc.gaia-x.eu:issuer", + "type": ["VerifiableCredential", "DataConsortiumCredential"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/DataSelfDescription.json b/src/test/resources/vc-templates/DataSelfDescription.json new file mode 100644 index 00000000..356056d2 --- /dev/null +++ b/src/test/resources/vc-templates/DataSelfDescription.json @@ -0,0 +1,19 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "dependsOn": ["Pilot004DataService"], + "description": "AIS demonstrates machine learning application use case.", + "hasCertifications": ["ISO_27001", "GDPR_Compliance"], + "hasMarketingImage": "https://www.data-infrastructure.eu/GAIAX/Redaktion/EN/Bilder/UseCases/ai-marketplace-for-product-development.jpg?__blob=normal", + "hasName": "AIS", + "hasVersion": "0.1.0", + "id": "Pilot004AIService", + "providedBy": "GAIA-X", + "type": "Service", + "utilizes": ["ExampleKubernetesService"] + }, + "id": "did:ebsi-eth:00000001/credentials/1872", + "issued": "2020-08-24T14:13:44Z", + "issuer": "did:example:456", + "type": ["VerifiableCredential", "DataSelfDescription"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/DataServiceOffering.json b/src/test/resources/vc-templates/DataServiceOffering.json new file mode 100644 index 00000000..fc60de79 --- /dev/null +++ b/src/test/resources/vc-templates/DataServiceOffering.json @@ -0,0 +1,37 @@ +{ + "billing": { + "paymentModel": { + "frequenceOfPayment": "daily", + "unit": "EUR", + "value": "0.0" + }, + "price": "0.0", + "unit": "EUR" + }, + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "dependsOn": ["Pilot004DataService"], + "description": "AIS demonstrates machine learning application use case.", + "hasCertifications": ["ISO_27001", "GDPR_Compliance"], + "hasMarketingImage": "https://www.data-infrastructure.eu/Data/Redaktion/EN/Bilder/UseCases/ai-marketplace-for-product-development.jpg?__blob=normal", + "hasName": "AIS", + "hasVersion": "0.1.0", + "id": "Pilot004AIService", + "providedBy": "GAIA-X", + "type": "Service", + "utilizes": ["ExampleKubernetesService"] + }, + "description": "he data contains the basic information to build a transaction graph for later analysis by the safeFBDC algorithm. Is is one of multiple data sources to be analyzed.", + "id": "did:ebsi-eth:00000001/credentials/1872", + "issued": "2020-08-24T14:13:44Z", + "issuer": "did:example:456", + "keywords": ["Analytics", "AML", "safeFBDC", "finance", "dataset", "graph"], + "modified": "2020-12-02T23:00:00+01:00", + "providedBy": "did:key:z6Mktqg13w3KRBdcqhyjU99ZhHF8FR6tRJACuQzmVcXNiH25", + "provisionType": "E.g., Hybrid", + "serviceModel": "E.g., DaaS", + "serviceTitle": "safeFBDC - Dataset A for safeFBDC AML analysis", + "version": "0.1", + "webAddress": "https://safefbdc.portal.minimal-gaia-x.eu/asset/did:op:348e1a938dB25221031Ed6b465782efCAcBB214E", + "type": ["VerifiableCredential", "DataServiceOffering"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/EbsiAccreditedVerifiableAttestation.json b/src/test/resources/vc-templates/EbsiAccreditedVerifiableAttestation.json new file mode 100644 index 00000000..1ae4443d --- /dev/null +++ b/src/test/resources/vc-templates/EbsiAccreditedVerifiableAttestation.json @@ -0,0 +1,31 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "id": "urn:uuid:58afcb57-81f9-4e8c-817b-01f0597d6801", + "type": [ + "VerifiableCredential", + "VerifiableAttestation", + "AccreditedVerifiableAttestation" + ], + "issuer": "did:ebsi:00001234", + "issuanceDate": "2021-11-01T00:00:00Z", + "validFrom": "2021-11-01T00:00:00Z", + "expirationDate": "2024-06-22T14:11:44Z", + "issued": "2020-06-22T14:11:44Z", + "termsOfUse": [ + { + "id": "https://essif.europa.eu/accreditation/45", + "type": "VerifiableAccreditation" + } + ], + "credentialSubject": { + "id": "did:ebsi:00001235" + }, + "credentialStatus": { + "id": "https://essif.europa.eu/status/45", + "type": "CredentialsStatusList2020" + }, + "credentialSchema": { + "id": "https://api-test.ebsi.eu/trusted-schemas-registry/v2/schemas/0x4a131e78474b35ca4c93d4904cae9f2013cd53794ce521f6fcfac17ac460c6e5", + "type": "FullJsonSchemaValidator2021" + } +} diff --git a/src/test/resources/vc-templates/EbsiDiplomaVerifiableAccreditation.json b/src/test/resources/vc-templates/EbsiDiplomaVerifiableAccreditation.json new file mode 100644 index 00000000..beb8e83b --- /dev/null +++ b/src/test/resources/vc-templates/EbsiDiplomaVerifiableAccreditation.json @@ -0,0 +1,51 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://essif.europa.eu/schemas/vc/2020/v1" + ], + "id": "https://essif.europa.eu/tsr/53", + "type": [ + "VerifiableCredential", + "VerifiableAttestation", + "VerifiableAccreditation", + "DiplomaVerifiableAccreditation" + ], + "issuer": "did:ebsi:00001234", + "issuanceDate": "2020-06-22T14:11:44Z", + "issued": "2020-06-22T14:11:44Z", + "credentialSubject": { + "id": "did:ebsi:00001235", + "authorizationClaims": { + "accreditationType": "http://data.europa.eu/snb/accreditation/003293d2ce", + "decision": "fully compliant", + "report": ["https://www.example.com/URLtoreport.pdf"], + "limitQFLevel": [ + "http://data.europa.eu/snb/eqf/6", + "http://data.europa.eu/snb/eqf/7" + ], + "limitField": ["http://data.europa.eu/snb/isced-f/0419"], + "limitJurisdiction": [ + "http://publications.europa.eu/resource/authority/atu/NLD" + ], + "reviewDate": "2024-04-22T14:11:44Z" + } + }, + "expirationDate": "2024-06-22T14:11:44Z", + "validFrom": "2021-11-01T00:00:00Z", + "credentialStatus": { + "id": "https://essif.europa.eu/status/45", + "type": "CredentialsStatusList2020" + }, + "credentialSchema": { + "id": "https://essif.europa.eu/tsr-123/verifiableattestation.json", + "type": "FullJsonSchemaValidator2021" + }, + "proof": { + "type": "EidasSeal2019", + "created": "2019-06-22T14:11:44Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "http://uri-to-verification-method", + "jws": "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5X", + "proofValue": "BD21J4fdlnBvBA+y6D...fnC8Y=" + } +} diff --git a/src/test/resources/vc-templates/EbsiEuropass.json b/src/test/resources/vc-templates/EbsiEuropass.json new file mode 100644 index 00000000..e69de29b diff --git a/src/test/resources/vc-templates/EbsiVerifiableAccreditationToAccredit.json b/src/test/resources/vc-templates/EbsiVerifiableAccreditationToAccredit.json new file mode 100644 index 00000000..8b9c7450 --- /dev/null +++ b/src/test/resources/vc-templates/EbsiVerifiableAccreditationToAccredit.json @@ -0,0 +1,40 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "id": "urn:uuid:8568b525-a24e-4bc0-9d97-6a8459ec0130", + "type": [ + "VerifiableCredential", + "VerifiableAttestation", + "VerifiableAccreditation", + "VerifiableAccreditationToAccredit" + ], + "issuer": "did:ebsi:00001234", + "issuanceDate": "2021-11-01T00:00:00Z", + "validFrom": "2021-11-01T00:00:00Z", + "expirationDate": "2024-06-22T14:11:44Z", + "issued": "2020-06-22T14:11:44Z", + "credentialSubject": { + "id": "did:ebsi:00001235", + "accreditedFor": [ + { + "schemaId": "https://api-test.ebsi.eu/trusted-schemas-registry/v2/schemas/0x010110", + "types": [ + "VerifiableCredential", + "VerifiableAttestation", + "DiplomaCredential" + ], + "limitJurisdiction": "https://publications.europa.eu/resource/authority/atu/FIN" + } + ] + }, + "termsOfUse": [ + { + "id": "https://api-test.ebsi.eu/trusted-issuers-registry/../..xyz", + "type": "IssuanceCertificate" + } + ], + "credentialSchema": + { + "id": "https://api-test.ebsi.eu/trusted-schemas-registry/v2/schemas/0x1d7146f8897aa6cd5c59321ea0756ec61277028e4a8b3c13ec1b310ec47e6495", + "type": "FullJsonSchemaValidator2021" + } +} diff --git a/src/test/resources/vc-templates/EbsiVerifiableAttestationGeneric.json b/src/test/resources/vc-templates/EbsiVerifiableAttestationGeneric.json new file mode 100644 index 00000000..dc37148b --- /dev/null +++ b/src/test/resources/vc-templates/EbsiVerifiableAttestationGeneric.json @@ -0,0 +1,26 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "id": "urn:uuid:003a1dd8-a5d2-42ef-8182-e921c0a9f2cd", + "type": ["VerifiableCredential", "VerifiableAttestation"], + "issuer": "did:ebsi:00001234", + "issuanceDate": "2021-11-01T00:00:00Z", + "validFrom": "2021-11-01T00:00:00Z", + "validUntil": "2050-11-01T00:00:00Z", + "expirationDate": "2024-06-22T14:11:44Z", + "issued": "2020-06-22T14:11:44Z", + "credentialSubject": { + "id": "did:ebsi:00001235" + }, + "credentialStatus": { + "id": "https://essif.europa.eu/status/45", + "type": "AnyExtension" + }, + "credentialSchema": { + "id": "https://api-test.ebsi.eu/trusted-schemas-registry/v2/schemas/0x23039e6356ea6b703ce672e7cfac0b42765b150f63df78e2bd18ae785787f6a2", + "type": "FullJsonSchemaValidator2021" + }, + "termsOfUse": { + "id": "https://essif.europa.eu/accreditation/45", + "type": "AnyExtension" + } +} diff --git a/src/test/resources/vc-templates/EbsiVerifiableAttestationLegal.json b/src/test/resources/vc-templates/EbsiVerifiableAttestationLegal.json new file mode 100644 index 00000000..cd6137ba --- /dev/null +++ b/src/test/resources/vc-templates/EbsiVerifiableAttestationLegal.json @@ -0,0 +1,49 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https:/.europa.eu/schemas/v-id/2020/v1", + "https:/.europa.eu/schemas/eidas/2020/v1" + ], + "id": "urn:did:123456", + "type": ["VerifiableCredential", "VerifiableAttestation"], + "issuer": "did:ebsi:2757945549477fc571663bee12042873fe555b674bd294a3", + "issuanceDate": "2019-06-22T14:11:44Z", + "validFrom": "2019-06-22T14:11:44Z", + "issued": "2019-06-22T14:11:44Z", + "credentialSubject": { + "id": "did:ebsi:2659b154a445434a39d91149ead3bd993cb99fd5e78281b7", + "identifier": [ + { + "schemeID": "SHACL", + "value": "SHACL ID 1", + "id": "http://student.id/41231232" + } + ], + "legalName": "Example Company" + }, + "credentialStatus": { + "id": "https:/europa.eu/status/identity#1dee355d-0432-4910-ac9c-70d89e8d674e", + "type": "CredentialStatusList2020" + }, + "credentialSchema": { + "id": "https:/.europa.eu/tsr-vid/verifiableid1.json", + "type": "FullJsonSchemaValidator2021" + }, + "evidence": [ + { + "id": "https:/.europa.eu/tsr-vid/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d4231", + "type": ["DocumentVerification"], + "verifier": "did:ebsi:2e81454f76775c687694ee6772a17796436768a30e289555", + "evidenceDocument": ["Passport"], + "subjectPresence": "Physical", + "documentPresence": ["Physical"] + } + ], + "proof": { + "type": "EidasSeal2021", + "created": "2019-06-22T14:11:44Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:ebsi:2757945549477fc571663bee12042873fe555b674bd294a3#2368332668", + "jws": "HG21J4fdlnBvBA+y6D...amP7O=" + } +} diff --git a/src/test/resources/vc-templates/EbsiVerifiableAttestationPerson.json b/src/test/resources/vc-templates/EbsiVerifiableAttestationPerson.json new file mode 100644 index 00000000..dc37148b --- /dev/null +++ b/src/test/resources/vc-templates/EbsiVerifiableAttestationPerson.json @@ -0,0 +1,26 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "id": "urn:uuid:003a1dd8-a5d2-42ef-8182-e921c0a9f2cd", + "type": ["VerifiableCredential", "VerifiableAttestation"], + "issuer": "did:ebsi:00001234", + "issuanceDate": "2021-11-01T00:00:00Z", + "validFrom": "2021-11-01T00:00:00Z", + "validUntil": "2050-11-01T00:00:00Z", + "expirationDate": "2024-06-22T14:11:44Z", + "issued": "2020-06-22T14:11:44Z", + "credentialSubject": { + "id": "did:ebsi:00001235" + }, + "credentialStatus": { + "id": "https://essif.europa.eu/status/45", + "type": "AnyExtension" + }, + "credentialSchema": { + "id": "https://api-test.ebsi.eu/trusted-schemas-registry/v2/schemas/0x23039e6356ea6b703ce672e7cfac0b42765b150f63df78e2bd18ae785787f6a2", + "type": "FullJsonSchemaValidator2021" + }, + "termsOfUse": { + "id": "https://essif.europa.eu/accreditation/45", + "type": "AnyExtension" + } +} diff --git a/src/test/resources/vc-templates/Email.json b/src/test/resources/vc-templates/Email.json new file mode 100644 index 00000000..14310c5f --- /dev/null +++ b/src/test/resources/vc-templates/Email.json @@ -0,0 +1,11 @@ +{ + "context": ["https://www.w3.org/2018/credentials/v1"], + "credentialStatus": { + "id": "https://credentialstatus.velocitycareerlabs.io", + "type": "VelocityRevocationRegistry" + }, + "credentialSubject": { + "email": "adam.smith@example.com" + }, + "type": ["VerifiableCredential", "Email"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/Europass.json b/src/test/resources/vc-templates/Europass.json new file mode 100644 index 00000000..5db9f2ed --- /dev/null +++ b/src/test/resources/vc-templates/Europass.json @@ -0,0 +1,153 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/schemas/Europass.json", + "type": "JsonSchemaValidator2018" + }, + "credentialStatus": { + "id": "https://essif.europa.eu/status/education#higherEducation#51e42fda-cb0a-4333-b6a6-35cb147e1a88", + "type": "TrustedCredentialStatus2021" + }, + "credentialSubject": { + "achieved": [{ + "entitlesTo": { + "definition": "Competences the student acquires after the completion of Graduate university study are sufficient conditions for attending the programme of Postgraduate doctoral study at the Faculty of Civil Engineering, Architecture and Geodesy in Split, as well as for attending the same or similar programmes and Postgraduate specialist studies at other faculties of Civil Engineering in Croatia. The acquired learning outcomes enable the student to attend other postgraduate study programmes in the field of technical sciences. ", + "id": "urn:epass:entitlement:1", + "issuedDate": "2019-09-20", + "specifiedBy": { + "entitlementType": "http://data.europa.eu/snb/entitlement/64aad92881", + "id": "urn:epass:entitlementspec:1", + "limitJurisdiction": ["http://publications.europa.eu/resource/authority/country/HRV"], + "limitOrganisation": ["did:ebsi:zsSgDXeYPhZ3AuKhTFneDf1"], + "status": "http://data.europa.eu/snb/entitlement-status/5b8d6b34fb", + "title": "Postgraduate doctoral study" + }, + "title": "Postgraduate doctoral study" + }, + "hasPart": { + "learningAchievements": [{ + "id": "", + "identifier": [{ + "schemeID": "Achievement ID", + "value": "GAB701" + }], + "specifiedBy": [{ + "eCTSCreditPoints": 5, + "eqflLevel": "http://data.europa.eu/snb/eqf/4", + "id": "urn:epass:qualification:1", + "isPartialQualification": true, + "maximumDuration": "P6M", + "nqflLevel": "http://data.europa.eu/snb/qdr/c_49672c5a", + "title": "Applied mathematics", + "volumeOfLearning": "PT60H" + }], + "title": "", + "wasAwardedBy": { + "awardingBody": ["did:ebsi:zsSgDXeYPhZ3AuKhTFneDf1"], + "awardingDate": "2019-09-20T00:00:00+02:00", + "id": "urn:epass:awardingProcess:2" + }, + "wasDerivedFrom": [{ + "assessedBy": ["did:ebsi:zsSgDXeYPhZ3AuKhTFneDf1"], + "grade": "good (3)", + "id": "urn:epass:asssessmentspec:2", + "specifiedBy": { + "gradingScheme": { + "definition": "The Croatian national grading scheme consists of five grades with numerical equivalents: izvrstan \u2013 5 (outstanding); vrlo dobar \u2013 4 (very good); dobar \u2013 3 (good); dovoljan \u2013 2 (sufficient); nedovoljan \u2013 1 (insufficient - fail). The minimum passing grade is dovoljan \u2013 2.", + "id": "urn:epass:scoringschemespec:2", + "title": "General grading scheme in Croatia" + }, + "id": "urn:epass:asssessmentspec:2", + "title": "Applied mathematics" + }, + "title": "Applied mathematics" + }], + "wasInfluencedBy": [{ + "directedBy": ["did:ebsi:zsSgDXeYPhZ3AuKhTFneDf1"], + "endedAtTime": "2018-01-14T00:00:00+01:00", + "id": "urn:epass:activity:1", + "identifier": [{ + "schemeID": "Activity ID", + "value": "GAB701" + }], + "location": ["urn:epass:location:4"], + "specifiedBy": { + "id": "urn:epass:learningactivityspec:1", + "language": ["http://publications.europa.eu/resource/authority/language/HRV"], + "learningActivityType": ["http://data.europa.eu/snb/learning-activity/fd33e234ae"], + "title": "Applied mathematics", + "workload": "PT60H" + }, + "startedAtTime": "2017-09-04T00:00:00+02:00", + "title": "Applied mathematics", + "workload": "PT60H" + }] + }] + }, + "id": "urn:epass:learningAchievement:1", + "specifiedBy": [{ + "eCTSCreditPoints": 120, + "entryRequirementsNote": "The minimum educational requirement for enrolment into graduate university programmes is the completion of an undergraduate university programme. The university can allow students who have completed a professional programme to also enrol graduate university programmes, but they are allowed to set special requirements in these cases.\nThe minimum educational requirement for enrolment into specialist graduate professional programmes is the completion of an undergraduate university programme or a professional programme (first cycle).", + "eqflLevel": "http://data.europa.eu/snb/eqf/5", + "id": "urn:epass:qualification:20", + "isPartialQualification": false, + "maximumDuration": "P21M", + "nqflLevel": "http://data.europa.eu/snb/qdr/c_dcc9aca1", + "title": "Master of Science in Civil Engineering", + "volumeOfLearning": "PT1440H" + }], + "title": "Master of Science in Civil Engineering", + "wasAwardedBy": { + "awardingBody": ["did:ebsi:zsSgDXeYPhZ3AuKhTFneDf1"], + "awardingDate": "2019-09-20T00:00:00+02:00", + "id": "urn:epass:awardingProcess:1" + }, + "wasDerivedFrom": [{ + "assessedBy": ["did:ebsi:zsSgDXeYPhZ3AuKhTFneDf1"], + "grade": "excellent (5)", + "id": "urn:epass:assessment:1", + "specifiedBy": { + "gradingScheme": { + "definition": "The Croatian national grading scheme consists of five grades with numerical equivalents: izvrstan \u2013 5 (outstanding); vrlo dobar \u2013 4 (very good); dobar \u2013 3 (good); dovoljan \u2013 2 (sufficient); nedovoljan \u2013 1 (insufficient - fail). The minimum passing grade is dovoljan \u2013 2.", + "id": "urn:epass:scoringschemespec:1", + "title": "General grading scheme in Croatia" + }, + "id": "urn:epass:asssessmentspec:1", + "title": "Overall Diploma Assessment" + }, + "title": "Overall Diploma Assessment" + }], + "wasInfluencedBy": [{ + "directedBy": ["did:ebsi:zsSgDXeYPhZ3AuKhTFneDf1"], + "endedAtTime": "2018-01-14T00:00:00+01:00", + "id": "urn:epass:learningAchievement:1", + "identifier": [{ + "schemeID": "Activity ID", + "value": "GAB701" + }], + "location": ["urn:epass:location:4"], + "specifiedBy": { + "id": "urn:epass:learningactivityspec:1", + "language": ["http://publications.europa.eu/resource/authority/language/HRV"], + "learningActivityType": ["http://data.europa.eu/snb/learning-activity/fd33e234ae"], + "title": "Applied mathematics", + "workload": "PT60H" + }, + "startedAtTime": "2017-09-04T00:00:00+02:00", + "title": "Master of Science in Civil Engineering", + "workload": "PT60H" + }] + }], + "id": "did:epass:person:1", + "identifier": { + "schemeID": "Student identification number", + "value": "99009900" + } + }, + "id": "urn:credential:5a4d5412-27e3-4540-a5e5-f1aa4d55b20c", + "issued": "2020-07-20T13:58:53+02:00", + "issuer": "did:epass:org:1", + "validFrom": "2019-09-20T00:00:00+02:00", + "issuanceDate": "2019-09-20T00:00:00+02:00", + "type": ["VerifiableCredential", "VerifiableAttestation", "Europass"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/EuropeanBankIdentity.json b/src/test/resources/vc-templates/EuropeanBankIdentity.json new file mode 100644 index 00000000..44b19019 --- /dev/null +++ b/src/test/resources/vc-templates/EuropeanBankIdentity.json @@ -0,0 +1,23 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/schemas/EuropeanBankIdentity.json", + "type": "JsonSchemaValidator2018" + }, + "credentialSubject": { + "birthDate": "1958-08-17", + "familyName": "DOE", + "givenName": "JOHN", + "id": "identity#verifiableID", + "placeOfBirth": { + "country": "DE", + "locality": "Berlin" + } + }, + "id": "identity#EuropeanBankIdentity#3add94f4-28ec-42a1-8704-4e4aa51006b4", + "issued": "2021-08-31T00:00:00Z", + "issuer": "did:example:456", + "validFrom": "2021-08-31T00:00:00Z", + "issuanceDate": "2021-08-31T00:00:00Z", + "type": ["VerifiableCredential", "EuropeanBankIdentity"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/GaiaxCredential.json b/src/test/resources/vc-templates/GaiaxCredential.json new file mode 100644 index 00000000..c0be4a1e --- /dev/null +++ b/src/test/resources/vc-templates/GaiaxCredential.json @@ -0,0 +1,40 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "DNSpublicKey": "04:8B:CA:33:B1:A1:3A:69:E6:A2:1E:BE:CB:4E:DF:75:A9:70:8B:AA:51:83:AB:A1:B0:5A:35:20:3D:B4:29:09:AD:67:B4:12:19:3B:6A:B5:7C:12:3D:C4:CA:DD:A5:E0:DA:05:1E:5E:1A:4B:D1:F2:BA:8F:07:4D:C7:B6:AA:23:46", + "brandName": "deltaDAO", + "commercialRegister": { + "countryName": "Germany", + "locality": "Hamburg", + "organizationName": "Amtsgericht Hamburg (-Mitte)", + "organizationUnit": "Registergericht", + "postalCode": "20355", + "streetAddress": "Caffamacherreihe 20" + }, + "corporateEmailAddress": "contact@delta-dao.com", + "ethereumAddress": { + "id": "0x4C84a36fCDb7Bc750294A7f3B5ad5CA8F74C4A52" + }, + "id": "did:key:dummy", + "individualContactLegal": "legal@delta-dao.com", + "individualContactTechnical": "support@delta-dao.com", + "jurisdiction": "Germany", + "legalForm": "Stock Company", + "legalRegistrationNumber": "HRB 170364", + "legallyBindingAddress": { + "countryName": "Germany", + "locality": "Hamburg", + "postalCode": "22303", + "streetAddress": "Geibelstr. 46B" + }, + "legallyBindingName": "deltaDAO AG", + "trustState": "trusted", + "webAddress": { + "url": "https://www.delta-dao.com/" + } + }, + "id": "did:ebsi-eth:00000001/credentials/1872", + "issued": "2020-08-24T14:13:44Z", + "issuer": "did:example:456", + "type": ["VerifiableCredential", "GaiaxCredential"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/Iso27001Certificate.json b/src/test/resources/vc-templates/Iso27001Certificate.json new file mode 100644 index 00000000..f8d1ea60 --- /dev/null +++ b/src/test/resources/vc-templates/Iso27001Certificate.json @@ -0,0 +1,30 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "brandName": "deltaDAO", + "corporateEmailAddress": "contact@delta-dao.com", + "id": "did:key:dummy", + "individualContactLegal": "legal@delta-dao.com", + "individualContactTechnical": "support@delta-dao.com", + "jurisdiction": "Germany", + "legalForm": "Stock Company", + "legalRegistrationNumber": "HRB 170364", + "legallyBindingAddress": { + "countryName": "Germany", + "locality": "Hamburg", + "postalCode": "22303", + "streetAddress": "Geibelstr. 46B" + }, + "legallyBindingName": "deltaDAO AG", + "webAddress": "https://www.delta-dao.com/" + }, + "id": "did:ebsi-eth:00000001/credentials/1872", + "iso2700Criteria": { + "certifcateName": "IOS/IEC 27001:2022", + "certificateNr": "123", + "scope": ["consulting service", "software development", "IT operations"] + }, + "issued": "2020-08-24T14:13:44Z", + "issuer": "did:example:456", + "type": ["VerifiableCredential", "VerifiableAttestation", "Iso27001Certificate"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/KybCredential.json b/src/test/resources/vc-templates/KybCredential.json new file mode 100644 index 00000000..9cfc5919 --- /dev/null +++ b/src/test/resources/vc-templates/KybCredential.json @@ -0,0 +1,33 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "brandName": "deltaDAO", + "commercialRegister": { + "countryName": "Germany", + "locality": "Hamburg", + "organizationName": "Amtsgericht Hamburg (-Mitte)", + "organizationUnit": "Registergericht", + "postalCode": "20355", + "streetAddress": "Caffamacherreihe 20" + }, + "corporateEmailAddress": "contact@delta-dao.com", + "id": "did:key:dummy", + "individualContactLegal": "legal@delta-dao.com", + "individualContactTechnical": "support@delta-dao.com", + "jurisdiction": "Germany", + "legalForm": "Stock Company", + "legalRegistrationNumber": "HRB 170364", + "legallyBindingAddress": { + "countryName": "Germany", + "locality": "Hamburg", + "postalCode": "22303", + "streetAddress": "Geibelstr. 46B" + }, + "legallyBindingName": "deltaDAO AG", + "webAddress": "https://www.delta-dao.com/" + }, + "id": "did:ebsi-eth:00000001/credentials/1872", + "issued": "2020-08-24T14:13:44Z", + "issuer": "did:example:456", + "type": ["VerifiableCredential", "VerifiableAttestation", "KybCredential"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/KybMonoCredential.json b/src/test/resources/vc-templates/KybMonoCredential.json new file mode 100644 index 00000000..c254eca9 --- /dev/null +++ b/src/test/resources/vc-templates/KybMonoCredential.json @@ -0,0 +1,11 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "id": "did:key:dummy", + "kybValidationPassed": true + }, + "id": "did:ebsi-eth:00000001/credentials/1872", + "issued": "2020-08-24T14:13:44Z", + "issuer": "did:example:456", + "type": ["VerifiableCredential", "VerifiableAttestation", "KybMonoCredential"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/KycCredential.json b/src/test/resources/vc-templates/KycCredential.json new file mode 100644 index 00000000..f95cfee4 --- /dev/null +++ b/src/test/resources/vc-templates/KycCredential.json @@ -0,0 +1,20 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "currentAddress": "1 Boulevard de la Liberté, 59800 Lille", + "dateOfBirth": "1993-04-08", + "familyName": "DOE", + "firstName": "Jane", + "gender": "FEMALE", + "id": "did:ebsi:2AEMAqXWKYMu1JHPAgGcga4dxu7ThgfgN95VyJBJGZbSJUtp", + "nameAndFamilyNameAtBirth": "Jane DOE", + "personalIdentifier": "0904008084H", + "placeOfBirth": "LILLE, FRANCE" + }, + "id": "identity#KycCredential#3add94f4-28ec-42a1-8704-4e4aa51006b4", + "issued": "2021-08-31T00:00:00Z", + "issuer": "did:ebsi:2A9BZ9SUe6BatacSpvs1V5CdjHvLpQ7bEsi2Jb6LdHKnQxaN", + "validFrom": "2021-08-31T00:00:00Z", + "issuanceDate": "2021-08-31T00:00:00Z", + "type": ["VerifiableCredential", "VerifiableAttestation", "KycCredential"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/LegalPerson.json b/src/test/resources/vc-templates/LegalPerson.json new file mode 100644 index 00000000..0e34bfea --- /dev/null +++ b/src/test/resources/vc-templates/LegalPerson.json @@ -0,0 +1,29 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "gx-participant:blockchainAccountId": "0x4C84a36fCDb7Bc750294A7f3B5ad5CA8F74C4A52", + "gx-participant:headquarterAddress": { + "gx-participant:addressCode": "DE-HH", + "gx-participant:addressCountryCode": "DE", + "gx-participant:postal-code": "22303", + "gx-participant:street-address": "Geibelstraße 46b" + }, + "gx-participant:legalAddress": { + "gx-participant:addressCode": "DE-HH", + "gx-participant:addressCountryCode": "DE", + "gx-participant:postal-code": "22303", + "gx-participant:street-address": "Geibelstraße 46b" + }, + "gx-participant:legalName": "deltaDAO AG", + "gx-participant:registrationNumber": { + "gx-participant:registrationNumberNumber": "391200FJBNU0YW987L26", + "gx-participant:registrationNumberType": "leiCode" + }, + "gx-participant:termsAndConditions": "70c1d713215f95191a11d38fe2341faed27d19e083917bc8732ca4fea4976700", + "id": "did:web:delta-dao.com" + }, + "id": "https://delta-dao.com/.well-known/participant.json", + "issuanceDate": "2022-09-15T20:05:20.997Z", + "issuer": "did:web:delta-dao.com", + "type": ["VerifiableCredential", "LegalPerson"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/OpenBadgeCredential.json b/src/test/resources/vc-templates/OpenBadgeCredential.json new file mode 100644 index 00000000..eb4caf35 --- /dev/null +++ b/src/test/resources/vc-templates/OpenBadgeCredential.json @@ -0,0 +1,40 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1", "https://purl.imsglobal.org/spec/ob/v3p0/context.json"], + "credentialSchema": [{ + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json", + "type": "https://json-schema.org/draft/2019-09/schema" + }], + "credentialSubject": { + "achievement": { + "criteria": { + "narrative": "The cohort of the JFF Plugfest 2 in August-November of 2022 collaborated to push interoperability of VCs in education forward.", + "type": "Criteria" + }, + "description": "This wallet can display this Open Badge 3.0", + "id": "0", + "image": { + "id": "https://w3c-ccg.github.io/vc-ed/plugfest-2-2022/images/JFF-VC-EDU-PLUGFEST2-badge-image.png", + "type": "Image" + }, + "name": "Our Wallet Passed JFF Plugfest #2 2022", + "type": "Achievement" + }, + "id": "did:jwk:1235667890", + "type": "AchievementSubject" + }, + "id": "urn:uuid:01af1ece-4279-4c1e-b952-469bc5b5bab2", + "issuanceDate": "2020-03-10T04:24:12.164Z", + "issued": "2020-03-10T04:24:12.164Z", + "issuer": { + "id": "did:key:z6MkrHKzgsahxBLyNAbLQyB1pcWNYC9GmywiWPgkrvntAZcj", + "image": { + "id": "https://w3c-ccg.github.io/vc-ed/plugfest-2-2022/images/JFF-VC-EDU-PLUGFEST2-badge-image.png", + "type": "Image" + }, + "name": "Jobs for the Future (JFF)", + "type": "Profile", + "url": "https://w3c-ccg.github.io/vc-ed/plugfest-2-2022/images/JFF-VC-EDU-PLUGFEST2-badge-image.png" + }, + "name": "Achievement Credential", + "type": ["VerifiableCredential", "OpenBadgeCredential"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/ParticipantCredential.json b/src/test/resources/vc-templates/ParticipantCredential.json new file mode 100644 index 00000000..55895f51 --- /dev/null +++ b/src/test/resources/vc-templates/ParticipantCredential.json @@ -0,0 +1,28 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/ed25519-2020/v1", "https://w3id.org/security/suites/jws-2020/v1"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/schemas/ParticipantCredential.json", + "type": "JsonSchemaValidator2018" + }, + "credentialStatus": { + "id": "https://gaiax.europa.eu/status/participant-credential#392ac7f6-399a-437b-a268-4691ead8f176", + "type": "CredentialStatusList2020" + }, + "credentialSubject": { + "ethereumAddress": "0x4C84a36fCDb7Bc750294A7f3B5ad5CA8F74C4A52", + "hasCountry": "GER", + "hasJurisdiction": "GER", + "hasLegallyBindingName": "deltaDAO AG", + "hasRegistrationNumber": "DEK1101R.HRB170364", + "hash": "9ecf754ffdad0c6de238f60728a90511780b2f7dbe2f0ea015115515f3f389cd", + "id": "did:web:delta-dao.com", + "leiCode": "391200FJBNU0YW987L26", + "parentOrganisation": "", + "subOrganisation": "" + }, + "expirationDate": "2022-01-06T20:38:38Z", + "id": "vc.gaia-x.eu/participant-credential#392ac7f6-399a-437b-a268-4691ead8f176", + "issued": "2022-01-03T20:38:38Z", + "issuer": "did:web:vc.gaia-x.eu:issuer", + "type": ["VerifiableCredential", "ParticipantCredential"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/PeerReview.json b/src/test/resources/vc-templates/PeerReview.json new file mode 100644 index 00000000..88c0dabe --- /dev/null +++ b/src/test/resources/vc-templates/PeerReview.json @@ -0,0 +1,32 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/serialized/PeerReview.json", + "type": "JsonSchemaValidator2018" + }, + "credentialSubject": { + "completedDate": "2021-08-31T00:00:00Z", + "groupingKey": "c4235de3-e35b-4a53-ac46-f62c2b222441", + "id": "identity#verifiableID", + "measurements": [{ + "indicators": [{ + "category": "SKILL", + "name": "Coaching", + "type": "People Skills" + }], + "name": "Coaching", + "numberValue": 87, + "scale": "PERCENTAGE", + "type": "People Skills" + }], + "name": "WorkPi Peer Review", + "providerName": "WorkPi", + "type": "Assessment" + }, + "id": "identity#PeerReview#3add94f4-28ec-42a1-8704-4e4aa51006b4", + "issued": "2021-08-31T00:00:00Z", + "issuer": "did:example:456", + "validFrom": "2021-08-31T00:00:00Z", + "issuanceDate": "2021-08-31T00:00:00Z", + "type": ["VerifiableCredential", "PeerReview"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/PermanentResidentCard.json b/src/test/resources/vc-templates/PermanentResidentCard.json new file mode 100644 index 00000000..3de9b456 --- /dev/null +++ b/src/test/resources/vc-templates/PermanentResidentCard.json @@ -0,0 +1,11 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1", "https://w3id.org/citizenship/v1"], + "credentialSubject": { + "birthDate": "1958-08-17", + "givenName": "JOHN", + "id": "did:example:123", + "type": ["PermanentResident", "Person"] + }, + "issuer": "did:example:456", + "type": ["VerifiableCredential", "PermanentResidentCard"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/ProofOfResidence.json b/src/test/resources/vc-templates/ProofOfResidence.json new file mode 100644 index 00000000..ed98aa65 --- /dev/null +++ b/src/test/resources/vc-templates/ProofOfResidence.json @@ -0,0 +1,43 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/schemas/ProofOfResidence.json", + "type": "JsonSchemaValidator2018" + }, + "credentialStatus": { + "id": "https://essif.europa.eu/status/identity#verifiableID#1dee355d-0432-4910-ac9c-70d89e8d674e", + "type": "CredentialStatusList2020" + }, + "credentialSubject": { + "address": { + "countryName": "LU", + "locality": "Steinfort", + "postalCode": "L-8410", + "streetAddress": "16 Route D' Arlon" + }, + "dateOfBirth": "1993-04-08", + "familyName": "Beron", + "familyStatus": "Single", + "firstNames": "Domink", + "gender": "Male", + "id": "id123", + "identificationNumber": "123456789", + "nationality": "AT" + }, + "evidence": [{ + "documentPresence": "Physical", + "evidenceDocument": "Passport", + "id": "https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678", + "subjectPresence": "Physical", + "type": ["DocumentVerification"], + "verifier": "did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a" + }], + "expirationDate": "2022-06-22T14:11:44Z", + "id": "residence#3fea53a4-0432-4910-ac9c-69ah8da3c37f", + "issued": "2019-06-22T14:11:44Z", + "issuer": "did:ebsi:2757945549477fc571663bee12042873fe555b674bd294a3", + "title": "Proof of Residence", + "validFrom": "2019-06-22T14:11:44Z", + "issuanceDate": "2019-06-22T14:11:44Z", + "type": ["VerifiableCredential", "VerifiableAttestation", "ProofOfResidence"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/ServiceOfferingCredential.json b/src/test/resources/vc-templates/ServiceOfferingCredential.json new file mode 100644 index 00000000..7ab35790 --- /dev/null +++ b/src/test/resources/vc-templates/ServiceOfferingCredential.json @@ -0,0 +1,27 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "gx-service-offering:dataExport": [{ + "gx-service-offering:accessType": "digital", + "gx-service-offering:formatType": "mime/png", + "gx-service-offering:requestType": "emails" + }], + "gx-service-offering:dataProtectionRegime": ["GDPR2016"], + "gx-service-offering:dependsOn": ["https://compliance.gaia-x.eu/.well-known/serviceManagedPostgreSQLOVH.json", "https://compliance.gaia-x.eu/.well-known/serviceManagedK8sOVH.json"], + "gx-service-offering:description": "The Compliance Service will validate the shape and content of Self Descriptions. Required fields and consistency rules are defined in the Gaia-X Trust Framework.", + "gx-service-offering:gdpr": [{ + "gx-service-offering:imprint": "https://gaia-x.eu/imprint/", + "gx-service-offering:privacyPolicy": "https://gaia-x.eu/privacy-policy/" + }], + "gx-service-offering:name": "Gaia-X Lab Compliance Service", + "gx-service-offering:providedBy": "https://compliance.gaia-x.eu/.well-known/participant.json", + "gx-service-offering:termsAndConditions": [{ + "gx-service-offering:hash": "myrandomhash", + "gx-service-offering:url": "https://compliance.gaia-x.eu/terms" + }], + "gx-service-offering:webAddress": "https://compliance.gaia-x.eu/", + "id": "https://compliance.gaia-x.eu/.well-known/serviceComplianceService.json" + }, + "id": "https://compliance.gaia-x.eu/.well-known/serviceComplianceService.json", + "type": ["VerifiableCredential", "ServiceOfferingExperimental"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/UniversityDegree.json b/src/test/resources/vc-templates/UniversityDegree.json new file mode 100644 index 00000000..0a3f5358 --- /dev/null +++ b/src/test/resources/vc-templates/UniversityDegree.json @@ -0,0 +1,16 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"], + "credentialSubject": { + "degree": { + "name": "Bachelor of Science and Arts", + "type": "BachelorDegree" + }, + "id": "did:example:123" + }, + "id": "http://example.gov/credentials/3732", + "issued": "2020-03-10T04:24:12.164Z", + "issuer": { + "id": "did:example:456" + }, + "type": ["VerifiableCredential", "UniversityDegreeCredential"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/VerifiableAttestation.json b/src/test/resources/vc-templates/VerifiableAttestation.json new file mode 100644 index 00000000..0a8aefbb --- /dev/null +++ b/src/test/resources/vc-templates/VerifiableAttestation.json @@ -0,0 +1,29 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/schemas/VerifiableAttestation.json", + "type": "JsonSchemaValidator2018" + }, + "credentialStatus": { + "id": "https://essif.europa.eu/status/identity#verifiableID#1dee355d-0432-4910-ac9c-70d89e8d674e", + "type": "CredentialStatusList2020" + }, + "credentialSubject": { + "id": "id123" + }, + "evidence": [{ + "documentPresence": "Physical", + "evidenceDocument": "Passport", + "id": "https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678", + "subjectPresence": "Physical", + "type": ["DocumentVerification"], + "verifier": "did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a" + }], + "expirationDate": "2022-06-22T14:11:44Z", + "id": "education#higherEducation#3fea53a4-0432-4910-ac9c-69ah8da3c37f", + "issued": "2019-06-22T14:11:44Z", + "issuer": "did:ebsi:2757945549477fc571663bee12042873fe555b674bd294a3", + "validFrom": "2019-06-22T14:11:44Z", + "issuanceDate": "2019-06-22T14:11:44Z", + "type": ["VerifiableCredential", "VerifiableAttestation"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/VerifiableAuthorization.json b/src/test/resources/vc-templates/VerifiableAuthorization.json new file mode 100644 index 00000000..f0ac6370 --- /dev/null +++ b/src/test/resources/vc-templates/VerifiableAuthorization.json @@ -0,0 +1,13 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "id": "did:ebsi:00000004321", + "naturalPerson": { + "did": "did:example:00001111" + } + }, + "id": "did:ebsi-eth:00000001/credentials/1872", + "issued": "2020-08-24T14:13:44Z", + "issuer": "did:ebsi:000001234", + "type": ["VerifiableCredential", "VerifiableAuthorization"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/VerifiableDiploma.json b/src/test/resources/vc-templates/VerifiableDiploma.json new file mode 100644 index 00000000..619ed77d --- /dev/null +++ b/src/test/resources/vc-templates/VerifiableDiploma.json @@ -0,0 +1,64 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/schemas/VerifiableDiploma.json", + "type": "JsonSchemaValidator2018" + }, + "credentialStatus": { + "id": "https://essif.europa.eu/status/education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176", + "type": "CredentialStatusList2020" + }, + "credentialSubject": { + "awardingOpportunity": { + "awardingBody": { + "eidasLegalIdentifier": "Unknown", + "homepage": "https://leaston.bcdiploma.com/", + "id": "did:ebsi:2A9BZ9SUe6BatacSpvs1V5CdjHvLpQ7bEsi2Jb6LdHKnQxaN", + "preferredName": "Leaston University", + "registration": "0597065J" + }, + "endedAtTime": "2020-06-26T00:00:00Z", + "id": "https://leaston.bcdiploma.com/law-economics-management#AwardingOpportunity", + "identifier": "https://certificate-demo.bcdiploma.com/check/87ED2F2270E6C41456E94B86B9D9115B4E35BCCAD200A49B846592C14F79C86BV1Fnbllta0NZTnJkR3lDWlRmTDlSRUJEVFZISmNmYzJhUU5sZUJ5Z2FJSHpWbmZZ", + "location": "FRANCE", + "startedAtTime": "2019-09-02T00:00:00Z" + }, + "dateOfBirth": "1993-04-08", + "familyName": "DOE", + "givenNames": "Jane", + "gradingScheme": { + "id": "https://leaston.bcdiploma.com/law-economics-management#GradingScheme", + "title": "Lower Second-Class Honours" + }, + "id": "did:ebsi:2AEMAqXWKYMu1JHPAgGcga4dxu7ThgfgN95VyJBJGZbSJUtp", + "identifier": "0904008084H", + "learningAchievement": { + "additionalNote": ["DISTRIBUTION MANAGEMENT"], + "description": "MARKETING AND SALES", + "id": "https://leaston.bcdiploma.com/law-economics-management#LearningAchievment", + "title": "MASTERS LAW, ECONOMICS AND MANAGEMENT" + }, + "learningSpecification": { + "ectsCreditPoints": 120, + "eqfLevel": 7, + "id": "https://leaston.bcdiploma.com/law-economics-management#LearningSpecification", + "iscedfCode": ["7"], + "nqfLevel": ["7"] + } + }, + "evidence": { + "documentPresence": ["Physical"], + "evidenceDocument": ["Passport"], + "id": "https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678", + "subjectPresence": "Physical", + "type": ["DocumentVerification"], + "verifier": "did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a" + }, + "expirationDate": "2022-08-31T00:00:00Z", + "id": "education#higherEducation#392ac7f6-399a-437b-a268-4691ead8f176", + "issued": "2021-08-31T00:00:00Z", + "issuer": "did:ebsi:2A9BZ9SUe6BatacSpvs1V5CdjHvLpQ7bEsi2Jb6LdHKnQxaN", + "validFrom": "2021-08-31T00:00:00Z", + "issuanceDate": "2021-08-31T00:00:00Z", + "type": ["VerifiableCredential", "VerifiableAttestation", "VerifiableDiploma"] +} diff --git a/src/test/resources/vc-templates/VerifiableId.json b/src/test/resources/vc-templates/VerifiableId.json new file mode 100644 index 00000000..b8b4aa04 --- /dev/null +++ b/src/test/resources/vc-templates/VerifiableId.json @@ -0,0 +1,31 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/schemas/VerifiableId.json", + "type": "FullJsonSchemaValidator2021" + }, + "credentialSubject": { + "currentAddress": ["1 Boulevard de la Liberté, 59800 Lille"], + "dateOfBirth": "1993-04-08", + "familyName": "DOE", + "firstName": "Jane", + "gender": "FEMALE", + "id": "did:ebsi:2AEMAqXWKYMu1JHPAgGcga4dxu7ThgfgN95VyJBJGZbSJUtp", + "nameAndFamilyNameAtBirth": "Jane DOE", + "personalIdentifier": "0904008084H", + "placeOfBirth": "LILLE, FRANCE" + }, + "evidence": [{ + "documentPresence": ["Physical"], + "evidenceDocument": ["Passport"], + "subjectPresence": "Physical", + "type": ["DocumentVerification"], + "verifier": "did:ebsi:2A9BZ9SUe6BatacSpvs1V5CdjHvLpQ7bEsi2Jb6LdHKnQxaN" + }], + "id": "urn:uuid:3add94f4-28ec-42a1-8704-4e4aa51006b4", + "issued": "2021-08-31T00:00:00Z", + "issuer": "did:ebsi:2A9BZ9SUe6BatacSpvs1V5CdjHvLpQ7bEsi2Jb6LdHKnQxaN", + "validFrom": "2021-08-31T00:00:00Z", + "issuanceDate": "2021-08-31T00:00:00Z", + "type": ["VerifiableCredential", "VerifiableAttestation", "VerifiableId"] +} diff --git a/src/test/resources/vc-templates/VerifiableMandate.json b/src/test/resources/vc-templates/VerifiableMandate.json new file mode 100644 index 00000000..0bffcb4c --- /dev/null +++ b/src/test/resources/vc-templates/VerifiableMandate.json @@ -0,0 +1,28 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSchema": { + "id": "https://api.preprod.ebsi.eu/trusted-schemas-registry/v1/schemas/0xb77f8516a965631b4f197ad54c65a9e2f9936ebfb76bae4906d33744dbcc60ba", + "type": "FullJsonSchemaValidator2021" + }, + "credentialSubject": { + "holder": { + "constraints": {}, + "grant": "apply_to_masters", + "id": "", + "role": "family" + }, + "id": "", + "policySchemaURI": "https://raw.githubusercontent.com/walt-id/waltid-ssikit/master/src/test/resources/verifiable-mandates/test-policy.rego" + }, + "evidence": [{ + "evidenceValue": "", + "id": "https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678", + "type": ["VerifiableMandatePresentation"] + }], + "id": "urn:uuid:3add94f4-28ec-42a1-8704-4e4aa51006b4", + "issued": "2021-08-31T00:00:00Z", + "issuer": "did:ebsi:2A9BZ9SUe6BatacSpvs1V5CdjHvLpQ7bEsi2Jb6LdHKnQxaN", + "validFrom": "2021-08-31T00:00:00Z", + "issuanceDate": "2021-08-31T00:00:00Z", + "type": ["VerifiableCredential", "VerifiableMandate"] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/VerifiablePresentation.json b/src/test/resources/vc-templates/VerifiablePresentation.json new file mode 100644 index 00000000..db95674d --- /dev/null +++ b/src/test/resources/vc-templates/VerifiablePresentation.json @@ -0,0 +1,43 @@ +{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "holder": "did:ebsi:00000004321", + "id": "id", + "type": ["VerifiablePresentation"], + "verifiableCredential": [{ + "@context": ["https://www.w3.org/2018/credentials/v1"], + "credentialSubject": { + "id": "did:ebsi:00000004321", + "naturalPerson": { + "did": "did:example:00001111" + } + }, + "id": "did:ebsi-eth:00000001/credentials/1872", + "issued": "2020-08-24T14:13:44Z", + "issuer": "did:ebsi:000001234", + "proof": { + "created": "assertionMethod", + "creator": "2020-08-24T14:13:44Z", + "domain": "did:ebsi-eth:000001234#key-1", + "proofPurpose": "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19.", + "type": "EcdsaSecp256k1Signature2019" + }, + "type": ["VerifiableCredential", "VerifiableAuthorization"] + }, { + "@context": ["https://www.w3.org/2018/credentials/v1", "https://w3id.org/citizenship/v1"], + "credentialSubject": { + "birthDate": "1958-08-17", + "givenName": "JOHN", + "id": "did:example:123", + "type": ["PermanentResident", "Person"] + }, + "issuer": "did:example:456", + "proof": { + "created": "assertionMethod", + "creator": "2020-04-22T10:37:22Z", + "domain": "did:example:456#key-1", + "proofPurpose": "eyJjcml0IjpbImI2NCJdLCJiNjQiOmZhbHNlLCJhbGciOiJFZERTQSJ9..BhWew0x-txcroGjgdtK-yBCqoetg9DD9SgV4245TmXJi-PmqFzux6Cwaph0r-mbqzlE17yLebjfqbRT275U1AA", + "type": "Ed25519Signature2018" + }, + "type": ["VerifiableCredential", "PermanentResidentCard"] + }] +} \ No newline at end of file diff --git a/src/test/resources/vc-templates/VerifiableVaccinationCertificate.json b/src/test/resources/vc-templates/VerifiableVaccinationCertificate.json new file mode 100644 index 00000000..ddc88964 --- /dev/null +++ b/src/test/resources/vc-templates/VerifiableVaccinationCertificate.json @@ -0,0 +1 @@ +{"@context" : ["https://www.w3.org/2018/credentials/v1"], "credentialSchema" : {"id" : "https://raw.githubusercontent.com/walt-id/waltid-ssikit-vclib/master/src/test/resources/schemas/VerifiableVaccinationCertificate.json", "type" : "JsonSchemaValidator2018"}, "credentialStatus" : {"id" : "https://essif.europa.eu/status/covidvaccination#392ac7f6-399a-437b-a268-4691ead8f176", "type" : "CredentialStatusList2020"}, "credentialSubject" : {"dateOfBirth" : "1993-04-08", "familyName" : "DOE", "givenNames" : "Jane", "id" : "asdf", "personIdentifier" : "optional The type of identifier and identifier of the person, according to the policies applicable in each country. Examples are citizen ID and/or document number (ID- card/passport) or identifier within the health system/IIS/e-registry.", "personSex" : "optional", "uniqueCertificateIdentifier" : "UVCI0904008084H", "vaccinationProphylaxisInformation" : [{"administeringCentre" : "Name/code of administering centre or a health authority responsible for the vaccination event", "batchNumber" : "optional 1234", "countryOfVaccination" : "DE", "dateOfVaccination" : "2021-02-12", "diseaseOrAgentTargeted" : {"code" : "840539006", "system" : "2.16.840.1.113883. 6.96", "version" : "2021-01-31"}, "doseNumber" : "1", "marketingAuthorizationHolder" : "Example Vaccine Manufacturing Company", "nextVaccinationDate" : "optional - 2021-03-28", "totalSeriesOfDoses" : "2", "vaccineMedicinalProduct" : "VACCINE concentrate for dispersion for injection", "vaccineOrProphylaxis" : "1119349007 COVID-19 example vaccine"}]}, "evidence" : {"documentPresence" : ["Physical"], "evidenceDocument" : ["Passport"], "id" : "https://essif.europa.eu/tsr-va/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d5678", "subjectPresence" : "Physical", "type" : ["DocumentVerification"], "verifier" : "did:ebsi:2962fb784df61baa267c8132497539f8c674b37c1244a7a"}, "expirationDate" : "2022-08-31T00:00:00Z", "id" : "covidvaccination#392ac7f6-399a-437b-a268-4691ead8f176", "issued" : "2021-08-31T00:00:00Z", "issuer" : "qwer", "validFrom" : "2021-08-31T00:00:00Z", "issuanceDate" : "2021-08-31T00:00:00Z", "type" : ["VerifiableCredential", "VerifiableAttestation", "VerifiableVaccinationCertificate"]} \ No newline at end of file