Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove danubech dependency from credential package 1/2 #249

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,14 @@
val idNode = node.get("id")
val id = idNode?.asText()?.takeIf { it.isNotBlank() }?.let { URI.create(it) }

require(id.toString().isNotBlank()) {"Credential Subject id cannot be blank"}

// Remove the "id" field and treat the rest as additionalClaims
val additionalClaims = node.fields().asSequence().filterNot { it.key == "id" }
.associate { it.key to it.value.asText() } // Assuming all values are stored as text

return CredentialSubject.Builder()
.id(id)
.id(id!!)
.additionalClaims(additionalClaims)
.build()
}
Expand Down Expand Up @@ -107,9 +109,9 @@
* Builder class for creating [VcDataModel] instances.
*/
public class Builder {
private var id: URI? = null
private var context: MutableList<URI> = mutableListOf()
private var type: MutableList<String> = mutableListOf()
private lateinit var id: URI
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could u explain why lateinit was added?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea it was a kotlin thing giving me compile time errors, it wont allow non nullable properties to be left uninitialized. I could be using Kotlin feature wrong? but it seems like this is the only way to use the builder this way

private var context: List<URI> = listOf()
private var type: List<String> = listOf()
private lateinit var issuer: URI
private lateinit var issuanceDate: Date
private var expirationDate: Date? = null
Expand All @@ -122,21 +124,21 @@
* @param id The unique identifier URI of the credential.
* @return Returns this builder to allow for chaining.
*/
public fun id(id: URI?): Builder = apply { this.id = id }
public fun id(id: URI): Builder = apply { this.id = id }

/**
* Sets the context URIs for the [VcDataModel].
* @param context A list of context URIs.
* @return Returns this builder to allow for chaining.
*/
public fun context(context: MutableList<URI>): Builder = apply { this.context = context }
public fun context(context: List<URI>): Builder = apply { this.context = context }

/**
* Sets the type(s) for the [VcDataModel].
* @param type A list of types.
* @return Returns this builder to allow for chaining.
*/
public fun type(type: MutableList<String>): Builder = apply { this.type = type }
public fun type(type: List<String>): Builder = apply { this.type = type }

/**
* Sets the issuer URI for the [VcDataModel].
Expand Down Expand Up @@ -173,7 +175,7 @@
* @return Returns this builder to allow for chaining.
*/
public fun credentialSchema(credentialSchema: CredentialSchema?): Builder =
apply { this.credentialSchema = credentialSchema }

Check warning on line 178 in credentials/src/main/kotlin/web5/sdk/credentials/model/VcDataModel.kt

View check run for this annotation

Codecov / codecov/patch

credentials/src/main/kotlin/web5/sdk/credentials/model/VcDataModel.kt#L178

Added line #L178 was not covered by tests

/**
* Sets the credential status for the [VcDataModel].
Expand All @@ -189,23 +191,17 @@
* @throws IllegalStateException If the issuer or issuance date are not set, or other validation fails.
*/
public fun build(): VcDataModel {

require(context.contains(URI.create(DEFAULT_VC_CONTEXT))) { "context must include at least: $DEFAULT_VC_CONTEXT" }
require(id.toString().isNotBlank()) { "ID URI cannot be blank" }
require(type.contains(DEFAULT_VC_TYPE)) { "type must include at least: $DEFAULT_VC_TYPE" }
require(issuer.toString().isNotBlank()) { "Issuer URI cannot be blank" }
require(id == null || id.toString().isNotBlank()) { "ID URI cannot be blank" }

if (expirationDate != null) {
require(issuanceDate.before(expirationDate)) { "Issuance date must be before expiration date" }
}

// Default context and type handling
if (context.isEmpty() || context[0].toString() != DEFAULT_VC_CONTEXT) {
context.add(0, URI.create(DEFAULT_VC_CONTEXT))
}

if (type.isEmpty() || type[0] != DEFAULT_VC_TYPE) {
type.add(0, DEFAULT_VC_TYPE)
}

return VcDataModel(id, context.toList(), type.toList(), issuer, issuanceDate, expirationDate,
return VcDataModel(id, context, type, issuer, issuanceDate, expirationDate,
credentialSubject, credentialSchema, credentialStatus)
}
}
Expand Down Expand Up @@ -263,22 +259,22 @@
* properties related to the subject of the verifiable credential.
*/
public class CredentialSubject(
public val id: URI?,
public val id: URI,
public val additionalClaims: Map<String, Any>
) {
/**
* Builder class for creating [CredentialSubject] instances.
*/
public class Builder {
nitro-neal marked this conversation as resolved.
Show resolved Hide resolved
private var id: URI? = null
private lateinit var id: URI
private var additionalClaims: Map<String, Any> = emptyMap()

/**
* Sets the ID URI for the credential subject.
* @param id The unique identifier URI of the credential subject.
* @return Returns this builder to allow for chaining.
*/
public fun id(id: URI?): Builder = apply { this.id = id }
public fun id(id: URI): Builder = apply { this.id = id }

/**
* Sets the additional claims for the credential subject.
Expand All @@ -295,7 +291,7 @@
* @throws IllegalStateException If the ID URI is not valid.
*/
public fun build(): CredentialSubject {
require(id == null || id.toString().isNotBlank()) { "ID URI cannot be blank" }
require(id.toString().isNotBlank()) { "ID URI cannot be blank" }

return CredentialSubject(id, additionalClaims)
}
Expand All @@ -306,16 +302,16 @@
/**
* The [CredentialSchema] Represents the schema defining the structure of a credential.
*/
public class CredentialSchema(
public val id: String,
public val type: String?
public val type: String

Check warning on line 307 in credentials/src/main/kotlin/web5/sdk/credentials/model/VcDataModel.kt

View check run for this annotation

Codecov / codecov/patch

credentials/src/main/kotlin/web5/sdk/credentials/model/VcDataModel.kt#L305-L307

Added lines #L305 - L307 were not covered by tests
) {
/**
* Builder class for creating [CredentialSchema] instances.
*/
public class Builder {
private var id: String? = null
private var type: String? = null
private lateinit var id: String
private lateinit var type: String

/**
* Sets the ID for the credential schema.
Expand All @@ -329,18 +325,18 @@
* @param type The type of the credential schema.
* @return Returns this builder to allow for chaining.
*/
public fun type(type: String?): Builder = apply { this.type = type }
public fun type(type: String): Builder = apply { this.type = type }

/**
* Builds and returns the [CredentialSchema] object.
* @return The constructed [CredentialSchema] object.
* @throws IllegalStateException If the id is not set.
*/
public fun build(): CredentialSchema {
require(!id.isNullOrBlank()) { "ID cannot be blank" }
require(type == null || type!!.isNotBlank()) { "Type cannot be blank" }
require(id.toString().isNotBlank()) { "ID cannot be blank" }
require(type == "JsonSchema") { "Type must be: JsonSchema" }

return CredentialSchema(id!!, type)
return CredentialSchema(id, type)

Check warning on line 339 in credentials/src/main/kotlin/web5/sdk/credentials/model/VcDataModel.kt

View check run for this annotation

Codecov / codecov/patch

credentials/src/main/kotlin/web5/sdk/credentials/model/VcDataModel.kt#L339

Added line #L339 was not covered by tests
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -299,24 +299,49 @@ class VerifiableCredentialTest {
}

@Test
fun `vcDataModel should add default context and type`() {

val vcDataModel = VcDataModel.Builder()
.id(URI.create("123"))
.context(mutableListOf()) // Assuming default context is handled by the Builder if necessary
.type(mutableListOf()) // Assuming default type is handled by the Builder if necessary
.issuer(URI.create("http://example.com/issuer"))
.issuanceDate(Date())
.credentialSubject(
CredentialSubject.Builder()
.id(URI.create("http://example.com/subject"))
.additionalClaims(mapOf("claimKey" to "claimValue"))
fun `vcDataModel should add default context`() {

val exception =
assertThrows(IllegalArgumentException::class.java) {
VcDataModel.Builder()
.id(URI.create("123"))
.context(mutableListOf())
.type(mutableListOf())
.issuer(URI.create("http://example.com/issuer"))
.issuanceDate(Date())
.credentialSubject(
CredentialSubject.Builder()
.id(URI.create("http://example.com/subject"))
.additionalClaims(mapOf("claimKey" to "claimValue"))
.build()
)
.build()
)
.build()
}

assertTrue(exception.message!!.contains("context must include at least: https://www.w3.org/2018/credentials/v1" ))
}

@Test
fun `vcDataModel should add default type`() {

val exception =
assertThrows(IllegalArgumentException::class.java) {
VcDataModel.Builder()
.id(URI.create("123"))
.context(mutableListOf(URI.create("https://www.w3.org/2018/credentials/v1")))
.type(mutableListOf())
.issuer(URI.create("http://example.com/issuer"))
.issuanceDate(Date())
.credentialSubject(
CredentialSubject.Builder()
.id(URI.create("http://example.com/subject"))
.additionalClaims(mapOf("claimKey" to "claimValue"))
.build()
)
.build()
}

assertEquals("https://www.w3.org/2018/credentials/v1", vcDataModel.context[0].toString())
assertEquals("VerifiableCredential", vcDataModel.type[0])
assertTrue(exception.message!!.contains("type must include at least: VerifiableCredential" ))
}

@Test
Expand Down Expand Up @@ -350,15 +375,15 @@ class VerifiableCredentialTest {
}

@Test
fun `vcDataModel credentialSchema should fail with empty type`() {
fun `vcDataModel credentialSchema should fail with wrong type`() {
val exception = assertThrows(IllegalArgumentException::class.java) {
CredentialSchema.Builder()
.id("did:example:123")
.type("")
.type("otherType")
.build()
}

assertTrue(exception.message!!.contains("Type cannot be blank"))
assertTrue(exception.message!!.contains("Type must be: JsonSchema"))
}
}

Expand All @@ -382,7 +407,6 @@ class Web5TestVectorsCredentials {
val testVectors = mapper.readValue(File("../web5-spec/test-vectors/credentials/create.json"), typeRef)

testVectors.vectors.filterNot { it.errors ?: false }.forEach { vector ->
println(vector.description)
val vc = VerifiableCredential.fromJson(mapper.writeValueAsString(vector.input.credential))

val keyManager = InMemoryKeyManager()
Expand All @@ -409,7 +433,6 @@ class Web5TestVectorsCredentials {
val testVectors = mapper.readValue(File("../web5-spec/test-vectors/credentials/verify.json"), typeRef)

testVectors.vectors.filterNot { it.errors ?: false }.forEach { vector ->
println(vector.description)
assertDoesNotThrow {
VerifiableCredential.verify(vector.input.vcJwt)
}
Expand Down
Loading