Skip to content

Commit

Permalink
[#73] Add @context, alsoKnownAs, controller to DIDDoc
Browse files Browse the repository at this point in the history
  • Loading branch information
tdiesler committed Mar 4, 2023
1 parent d11199b commit 4f2d769
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 29 deletions.
8 changes: 5 additions & 3 deletions lib/src/main/kotlin/org/didcommx/didcomm/common/Types.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ data class VerificationMaterial(
* https://www.w3.org/TR/did-spec-registries/#verification-method-properties
*/
enum class VerificationMaterialFormat {
@Deprecated("publicKeyBase58 is deprecated by spec. Use publicKeyMultibase or publicKeyJwk",
ReplaceWith("publicKeyMultibase or publicKeyJwk"))
BASE58, // https://www.w3.org/TR/did-spec-registries/#publickeybase58
@Deprecated(
"publicKeyBase58 is deprecated by spec. Use publicKeyMultibase or publicKeyJwk",
ReplaceWith("publicKeyMultibase or publicKeyJwk")
)
BASE58, // https://www.w3.org/TR/did-spec-registries/#publickeybase58
MULTIBASE,
JWK,
OTHER
Expand Down
106 changes: 81 additions & 25 deletions lib/src/main/kotlin/org/didcommx/didcomm/diddoc/DIDDoc.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,19 @@ import org.didcommx.didcomm.common.VerificationMethodType
import org.didcommx.didcomm.exceptions.DIDDocException
import org.didcommx.didcomm.exceptions.DIDUrlNotFoundException

const val DID_CONTEXT_URL: String = "https://www.w3.org/ns/did/v1"

/**
* DID DOC (https://www.w3.org/TR/did-core/#dfn-did-documents)
* @property did a DID for the given DID Doc
* @property context The JSON-LD Context is either a string or a list containing any combination of strings and/or ordered maps.
* See https://www.w3.org/TR/did-core/#json-ld
* @property alsoKnownAs The alsoKnownAs property is OPTIONAL. If present, the value MUST be a set where each item in the set is a URI.
* See https://www.w3.org/TR/did-core/#also-known-as
* @property controller The controller property is OPTIONAL. If present, the value MUST be a string or a set of strings that conform to the rules in 3.1 DID Syntax.
* See https://www.w3.org/TR/did-core/#did-controller
* @property authentications The authentication property is OPTIONAL. If present, the associated value MUST be a set of one or more verification methods. Each verification method MAY be embedded or referenced.
* See https://www.w3.org/TR/did-core/#authentication.
* See https://www.w3.org/TR/did-core/#authentication
* @property assertionMethods The assertionMethod property is OPTIONAL. If present, the associated value MUST be a set of one or more verification methods. Each verification method MAY be embedded or referenced.
* See https://www.w3.org/TR/did-core/#assertion
* @property keyAgreements The keyAgreement property is OPTIONAL. If present, the associated value MUST be a set of one or more verification methods. Each verification method MAY be embedded or referenced.
Expand All @@ -26,13 +34,16 @@ import org.didcommx.didcomm.exceptions.DIDUrlNotFoundException
* @property verificationMethods The verificationMethod property is OPTIONAL. If present, the value MUST be a set of verification methods, where each verification method is expressed using a map.
* The verification method map MUST include the id, type, controller, and specific verification material properties that are determined by the value of type and are defined in 5.2.1 Verification Material.
* A verification method MAY include additional properties.
* See https://www.w3.org/TR/did-core/#verification-methods.
* See https://www.w3.org/TR/did-core/#verification-methods
* @property didCommServices The service property is OPTIONAL. If present, the associated value MUST be a set of services, where each service is described by a map.
* Each service map MUST contain id, type, and serviceEndpoint properties. Each service extension MAY include additional properties and MAY further restrict the properties associated with the extension.
* See https://www.w3.org/TR/did-core/#services and https://identity.foundation/didcomm-messaging/spec/#did-document-service-endpoint.
* See https://www.w3.org/TR/did-core/#services and https://identity.foundation/didcomm-messaging/spec/#did-document-service-endpoint
*/
data class DIDDoc(
val did: String,
val context: List<String>,
val alsoKnownAs: List<String>,
val controller: List<String>,
val authentications: List<String>,
val assertionMethods: List<String>,
val keyAgreements: List<String>,
Expand All @@ -48,13 +59,17 @@ data class DIDDoc(
keyAgreements: List<String>,
authentications: List<String>,
verificationMethods: List<VerificationMethod>,
didCommServices: List<DIDCommService>) : this(
didCommServices: List<DIDCommService>
) : this(
did = did,
context = listOf(DID_CONTEXT_URL),
alsoKnownAs = listOf(),
controller = listOf(),
authentications = authentications,
assertionMethods = listOf(), // empty assertionMethods
assertionMethods = listOf(),
keyAgreements = keyAgreements,
capabilityInvocations = listOf(), // empty capabilityInvocations
capabilityDelegations = listOf(), // empty capabilityDelegations
capabilityInvocations = listOf(),
capabilityDelegations = listOf(),
verificationMethods = verificationMethods,
didCommServices = didCommServices
)
Expand Down Expand Up @@ -119,6 +134,24 @@ object DIDDocEncoder {
// id
jsonObj.addProperty("id", doc.did)

// context
if (doc.context.isNotEmpty()) {
val context = doc.context.fold(JsonArray()) { arr, el -> arr.add(el); arr }
jsonObj.add("@context", context)
}

// alsoKnownAs
if (doc.alsoKnownAs.isNotEmpty()) {
val alsoKnownAs = doc.alsoKnownAs.fold(JsonArray()) { arr, el -> arr.add(el); arr }
jsonObj.add("alsoKnownAs", alsoKnownAs)
}

// controller
if (doc.controller.isNotEmpty()) {
val controller = doc.controller.fold(JsonArray()) { arr, el -> arr.add(el); arr }
jsonObj.add("controller", controller)
}

// authentication
if (doc.authentications.isNotEmpty()) {
val authentication = doc.authentications.fold(JsonArray()) { arr, el -> arr.add(el); arr }
Expand Down Expand Up @@ -174,22 +207,25 @@ object DIDDocEncoder {
jsonObj.addProperty("id", vm.id)

// type
jsonObj.addProperty("type", when(vm.type) {
VerificationMethodType.ED25519_VERIFICATION_KEY_2018 -> "Ed25519VerificationKey2018"
VerificationMethodType.ED25519_VERIFICATION_KEY_2020 -> "Ed25519VerificationKey2020"
VerificationMethodType.X25519_KEY_AGREEMENT_KEY_2019 -> "X25519KeyAgreementKey2019"
VerificationMethodType.X25519_KEY_AGREEMENT_KEY_2020 -> "X25519KeyAgreementKey2020"
VerificationMethodType.JSON_WEB_KEY_2020 -> "JsonWebKey2020"
else -> throw IllegalStateException("Unsupported verification type: ${vm.type}")
})
jsonObj.addProperty(
"type",
when (vm.type) {
VerificationMethodType.ED25519_VERIFICATION_KEY_2018 -> "Ed25519VerificationKey2018"
VerificationMethodType.ED25519_VERIFICATION_KEY_2020 -> "Ed25519VerificationKey2020"
VerificationMethodType.X25519_KEY_AGREEMENT_KEY_2019 -> "X25519KeyAgreementKey2019"
VerificationMethodType.X25519_KEY_AGREEMENT_KEY_2020 -> "X25519KeyAgreementKey2020"
VerificationMethodType.JSON_WEB_KEY_2020 -> "JsonWebKey2020"
else -> throw IllegalStateException("Unsupported verification type: ${vm.type}")
}
)

// controller
jsonObj.addProperty("controller", vm.controller)

// verification material
val materialFormat = vm.verificationMaterial.format
val materialValue = vm.verificationMaterial.value
when(materialFormat) {
when (materialFormat) {
VerificationMaterialFormat.JWK -> {
jsonObj.add("publicKeyJwk", gson.fromJson(materialValue, JsonObject::class.java))
}
Expand Down Expand Up @@ -261,43 +297,63 @@ object DIDDocDecoder {
// id
val id = jsonObj["id"].asString

// context
val context = jsonObj.get("@context")
?.let { it.asJsonArray.map { el -> el.asString } }
?: listOf(DID_CONTEXT_URL)

// alsoKnownAs
// [TODO] verify that these are URIs (needs logging)
val alsoKnownAs = jsonObj.get("alsoKnownAs")
?.let { it.asJsonArray.map { el -> el.asString } }
?: listOf()

// controller
// [TODO] verify that these are DIDs (needs logging)
val controller = jsonObj.get("controller")
?.let { it.asJsonArray.map { el -> el.asString } }
?: listOf()

// verificationMethod
jsonObj.get("verificationMethod")?.also {
it.asJsonArray.forEach { el -> asVerificationMethod(el) }
}

// authentication
val authentications = jsonObj.get("authentication")
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) }}
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) } }
?: listOf()

// assertionMethod
val assertionMethods = jsonObj.get("assertionMethod")
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) }}
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) } }
?: listOf()

// keyAgreement
val keyAgreements = jsonObj.get("keyAgreement")
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) }}
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) } }
?: listOf()

// capabilityInvocations
val capabilityInvocations = jsonObj.get("capabilityInvocation")
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) }}
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) } }
?: listOf()

// capabilityDelegation
val capabilityDelegations = jsonObj.get("capabilityDelegation")
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) }}
?.let { it.asJsonArray.map { el -> asVerificationMethod(el) } }
?: listOf()

// service
val didCommServices = jsonObj.get("service")
?.let { it.asJsonArray.map { el -> decodeDIDCommService(el.asJsonObject) }}
?.let { it.asJsonArray.map { el -> decodeDIDCommService(el.asJsonObject) } }
?: listOf()

return DIDDoc(
did = id,
context = context,
alsoKnownAs = alsoKnownAs,
controller = controller,
authentications = authentications,
assertionMethods = assertionMethods,
keyAgreements = keyAgreements,
Expand All @@ -310,7 +366,7 @@ object DIDDocDecoder {

private fun decodeVerificationMethod(obj: JsonObject): VerificationMethod {
val id = obj["id"].asString
val methodType = when(val type = obj["type"].asString) {
val methodType = when (val type = obj["type"].asString) {
"Ed25519VerificationKey2018" -> VerificationMethodType.ED25519_VERIFICATION_KEY_2018
"Ed25519VerificationKey2020" -> VerificationMethodType.ED25519_VERIFICATION_KEY_2020
"X25519KeyAgreementKey2019" -> VerificationMethodType.X25519_KEY_AGREEMENT_KEY_2019
Expand All @@ -331,8 +387,8 @@ object DIDDocDecoder {
private fun decodeDIDCommService(obj: JsonObject): DIDCommService {
val id = obj["id"].asString
val serviceEndpoint = obj["serviceEndpoint"].asString
val accept = obj["accept"]?.let { it.asJsonArray.map { el -> el.asString }} ?: listOf()
val routingKeys = obj["routingKeys"]?.let { it.asJsonArray.map { el -> el.asString }} ?: listOf()
val accept = obj["accept"]?.let { it.asJsonArray.map { el -> el.asString } } ?: listOf()
val routingKeys = obj["routingKeys"]?.let { it.asJsonArray.map { el -> el.asString } } ?: listOf()
return DIDCommService(id, serviceEndpoint, routingKeys, accept)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class DIDDocEncodingTest {
DID_DOC_MEDIATOR1_SPEC_TEST_VECTORS,
DID_DOC_MEDIATOR1,
DID_DOC_MEDIATOR2_SPEC_TEST_VECTORS,
DID_DOC_MEDIATOR2).forEach { doc ->
DID_DOC_MEDIATOR2
).forEach { doc ->

val encoded = doc.encodeJson(true)
println { encoded }
Expand Down

0 comments on commit 4f2d769

Please sign in to comment.