Skip to content

Commit

Permalink
test: different dids supported on credential issuance
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeplotean committed Nov 8, 2023
1 parent d0af856 commit 50f3972
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ class W3CCredentialBuilderWithCredentialStatus<C : VerifiableCredential, B : Abs
issuer = proofConfig.issuerDid,
type = proofConfig.statusType!!,
purpose = proofConfig.statusPurpose,
credentialUrl = proofConfig.credentialsEndpoint ?: signatoryConfig?.proofConfig?.credentialsEndpoint ?: ""
credentialUrl = proofConfig.credentialsEndpoint ?: signatoryConfig?.proofConfig?.credentialsEndpoint
?: proofConfig.statusPurpose
)?.let { this.setProperty("credentialStatus", it) }
}.build()

Expand All @@ -48,7 +49,7 @@ class W3CCredentialBuilderWithCredentialStatus<C : VerifiableCredential, B : Abs
)).asMap()
CredentialStatus.Types.StatusList2021Entry -> statusListEntryFactory.create(StatusListEntryFactoryParameter(
purpose = purpose,
credentialUrl = URLBuilder().takeFrom(credentialUrl).appendPathSegments("status", purpose).buildString(),
credentialUrl = credentialUrl,
issuer = issuer,
)).asMap()
}.takeIf {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class StatusListEntryFactory(
// verify status-credential exists and create one
storageService.fetch(statusParameter.credentialUrl) ?: run {
storageService.store(
parameter.issuer,
statusParameter.issuer,
statusParameter.credentialUrl,
statusParameter.purpose,
String(createEncodedBitString(BitSet(16 * 1024 * 8)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import id.walt.signatory.ProofConfig
import id.walt.signatory.ProofType
import id.walt.signatory.Signatory
import java.io.File
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import kotlin.io.path.Path
import kotlin.io.path.pathString

open class StatusListCredentialStorageService : WaltIdService() {
override val implementation get() = serviceImplementation<StatusListCredentialStorageService>()

open fun fetch(id: String): VerifiableCredential? = implementation.fetch(id)
open fun fetch(url: String): VerifiableCredential? = implementation.fetch(url)
open fun store(issuer: String, id: String, purpose: String, bitString: String): Unit =
implementation.store(issuer, id, purpose, bitString)

Expand All @@ -31,12 +33,12 @@ open class StatusListCredentialStorageService : WaltIdService() {


class WaltIdStatusListCredentialStorageService : StatusListCredentialStorageService() {
private val templatePath = "StatusList2021Credential"
private val templateId = "StatusList2021Credential"
private val signatoryService = Signatory.getService()
private val templateService = VcTemplateService.getService()

override fun fetch(id: String): VerifiableCredential? = let {
val path = getCredentialPath(id.substringAfterLast("/"))
override fun fetch(url: String): VerifiableCredential? = let {
val path = getCredentialPath(url)
resolveContent(path).takeIf { it != path }?.let {
VerifiableCredential.fromJson(it)
}
Expand All @@ -61,7 +63,7 @@ class WaltIdStatusListCredentialStorageService : StatusListCredentialStorageServ
)
)
}.let {
W3CCredentialBuilder.fromPartial(templateService.getTemplate(templatePath).template!!).apply {
W3CCredentialBuilder.fromPartial(templateService.getTemplate(templateId).template!!).apply {
setId(it.id ?: id)
buildSubject {
setFromJson(it.toJson())
Expand All @@ -76,10 +78,11 @@ class WaltIdStatusListCredentialStorageService : StatusListCredentialStorageServ
proofType = ProofType.LD_PROOF,
)
).toVerifiableCredential()
getCredentialPath(credential.id!!.substringAfterLast("/")).let {
getCredentialPath(credential.id!!).let {
File(it).writeText(credential.encode())
}
}

private fun getCredentialPath(name: String) = Path(WaltIdServices.revocationDir, "$name.cred").pathString
private fun getCredentialPath(name: String) =
Path(WaltIdServices.revocationDir, "${URLEncoder.encode(name, StandardCharsets.UTF_8)}.cred").pathString
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,52 @@ package id.walt.signatory.revocation

import com.beust.klaxon.Klaxon
import id.walt.common.resolveContent
import id.walt.credentials.w3c.VerifiableCredential
import id.walt.credentials.w3c.builder.W3CCredentialBuilder
import id.walt.credentials.w3c.templates.VcTemplateService
import id.walt.crypto.KeyAlgorithm
import id.walt.model.DidMethod
import id.walt.model.credential.status.CredentialStatus
import id.walt.model.credential.status.StatusList2021EntryCredentialStatus
import id.walt.servicematrix.ServiceMatrix
import id.walt.services.WaltIdServices
import id.walt.services.did.DidService
import id.walt.services.did.DidWebCreateOptions
import id.walt.services.key.KeyService
import id.walt.signatory.ProofConfig
import id.walt.signatory.ProofType
import id.walt.signatory.Signatory
import id.walt.signatory.revocation.statuslist2021.StatusList2021EntryClientService
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.StringSpec
import io.kotest.data.blocking.forAll
import io.kotest.data.row
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
import io.mockk.every
import io.mockk.mockkStatic
import io.mockk.unmockkStatic
import java.io.File
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import kotlin.io.path.Path
import kotlin.io.path.pathString
import kotlin.random.Random

internal class StatusList2021ServiceTest : StringSpec({
val sut = StatusList2021EntryClientService()
val rootPath = "src/test/resources/credential-status/"
val statusLisCredential = resolveContent(rootPath + "status-list-credential.json")
lateinit var keyId: String

beforeSpec {
ServiceMatrix("service-matrix.properties")
keyId = KeyService.getService().generate(KeyAlgorithm.EdDSA_Ed25519).id
}

afterSpec {
KeyService.getService().delete(keyId)
}

"test result" {
forAll(
Expand Down Expand Up @@ -53,4 +84,43 @@ internal class StatusList2021ServiceTest : StringSpec({
unmockkStatic(::resolveContent)
}
}

"given issuer, when issuing a credential with status then the status-list credential has the issuer's did".config(
blockingTest = true
) {
forAll(
row(DidService.create(DidMethod.web, keyId, DidWebCreateOptions("example.com"))),
row(DidService.create(DidMethod.key, keyId)),
row(DidService.create(DidMethod.ebsi, keyId)),
row(DidService.create(DidMethod.jwk, keyId)),
row(DidService.create(DidMethod.cheqd, keyId)),
) { issuer ->
// given
val credentialUrl = "http://localhost:7001/credentials/status/#${Random.nextInt()}"
val path = Path(WaltIdServices.revocationDir, "${URLEncoder.encode(credentialUrl, StandardCharsets.UTF_8)}.cred").pathString
val template = VcTemplateService.getService().getTemplate("VerifiableId").template!!
// when
Signatory.getService().issue(
W3CCredentialBuilder.fromPartial(template), ProofConfig(
subjectDid = issuer,
issuerDid = issuer,
proofType = ProofType.LD_PROOF,
statusPurpose = "revocation",
statusType = CredentialStatus.Types.StatusList2021Entry,
credentialsEndpoint = credentialUrl
)
)
// then
val statusListVcStr = resolveContent(path)
val statusListVc = VerifiableCredential.fromString(statusListVcStr)
statusListVc.shouldNotBeNull()
statusListVc.issuerId.shouldNotBeNull()
statusListVc.issuerId shouldBe issuer

//cleanup TODO: dids
File(path).takeIf { it.exists() }?.run {
this.delete()
}
}
}
})

0 comments on commit 50f3972

Please sign in to comment.