diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/DIDDoc.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/DIDDoc.kt index fee1d19..8d9e680 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/DIDDoc.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/DIDDoc.kt @@ -14,6 +14,14 @@ const val SERVICE_DIDCOMM_MESSAGING = "DIDCommMessaging" const val SERVICE_ROUTING_KEYS = "routingKeys" const val SERVICE_ACCEPT = "accept" +/** + * Represents a PeerDID DID Document. + * + * @property did The DID identifier. + * @property authentication The list of authentication verification methods. + * @property keyAgreement The list of key agreement verification methods. + * @property service The list of service endpoints. + */ @Serializable data class DIDDocPeerDID @JvmOverloads @@ -23,11 +31,27 @@ constructor( val keyAgreement: List = emptyList(), val service: List? = null ) { + /** + * Retrieves a list of IDs from the authentication list. + * + * @return The list of authentication kid IDs. + */ val authenticationKids get() = authentication.map { it.id } + + /** + * Represents the agreementKids property in the DIDDocPeerDID class. + * It is a read-only property that returns a list of IDs of key agreements in the DID document. + * + * @return The list of IDs of key agreements. + */ val agreementKids get() = keyAgreement.map { it.id } + /** + * Converts the DID document to a dictionary representation. + * @return The dictionary representation of the DID document. + */ fun toDict(): Map { val res = mutableMapOf( @@ -49,6 +73,11 @@ constructor( return res } + /** + * Converts the object to its JSON representation as a String. + * + * @return The JSON representation of the object as a String. + */ fun toJson(): String { return toDict().toJsonElement().toString() } @@ -61,6 +90,7 @@ constructor( * @throws MalformedPeerDIDDOcException if the input DID Doc JSON is not a valid peerdid DID Doc * @return [DIDDocPeerDID] instance */ + @Throws(MalformedPeerDIDDOcException::class) fun fromJson(value: JSON): DIDDocPeerDID { try { // Two ways @@ -72,12 +102,24 @@ constructor( } } +/** + * Represents a verification method used in PeerDID. + * + * @property id The ID of the verification method. + * @property controller The controller of the verification method. + * @property verMaterial The verification material of the verification method. + */ @Serializable data class VerificationMethodPeerDID( val id: String, val controller: String, val verMaterial: VerificationMaterialPeerDID ) { + /** + * Returns the appropriate public key field based on the verification material format. + * + * @return The public key field. + */ private fun publicKeyField() = when (verMaterial.format) { VerificationMaterialFormatPeerDID.BASE58 -> PublicKeyField.BASE58 @@ -85,6 +127,11 @@ data class VerificationMethodPeerDID( VerificationMaterialFormatPeerDID.MULTIBASE -> PublicKeyField.MULTIBASE } + /** + * Converts the VerificationMethodPeerDID to a dictionary representation. + * + * @return The dictionary representation of the VerificationMethodPeerDID. + */ fun toDict() = mapOf( "id" to id, @@ -94,10 +141,26 @@ data class VerificationMethodPeerDID( ) } +/** + * Represents a service. + */ sealed interface Service +/** + * Represents a service provided by a DID document. + * + * @property data The data of the service. + */ data class OtherService(val data: Map) : Service +/** + * Represents a DIDComm service peer DID. + * @property id The ID of the service. + * @property type The type of the service. + * @property serviceEndpoint The service endpoint. + * @property routingKeys The list of routing keys. + * @property accept The list of accepted message types. + */ data class DIDCommServicePeerDID( val id: String, val type: String, @@ -105,6 +168,11 @@ data class DIDCommServicePeerDID( val routingKeys: List, val accept: List ) : Service { + /** + * Converts the DIDCommServicePeerDID object to a mutable map representation. + * + * @return The mutable map representation of the DIDCommServicePeerDID object. + */ fun toDict(): MutableMap { val res = mutableMapOf( @@ -118,6 +186,11 @@ data class DIDCommServicePeerDID( } } +/** + * Represents the different types of public key fields. + * + * @property value The string value of the public key field. + */ enum class PublicKeyField(val value: String) { BASE58("publicKeyBase58"), MULTIBASE("publicKeyMultibase"), diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/PeerDIDCreator.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/PeerDIDCreator.kt index 3c3f8c6..814544a 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/PeerDIDCreator.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/PeerDIDCreator.kt @@ -62,14 +62,10 @@ fun createPeerDIDNumalgo2( val encodedEncryptionKeysStr = encryptionKeys - .map { createMultibaseEncnumbasis(it) } - .map { ".${Numalgo2Prefix.KEY_AGREEMENT.prefix}$it" } - .joinToString("") + .map { createMultibaseEncnumbasis(it) }.joinToString("") { ".${Numalgo2Prefix.KEY_AGREEMENT.prefix}$it" } val encodedSigningKeysStr = signingKeys - .map { createMultibaseEncnumbasis(it) } - .map { ".${Numalgo2Prefix.AUTHENTICATION.prefix}$it" } - .joinToString("") + .map { createMultibaseEncnumbasis(it) }.joinToString("") { ".${Numalgo2Prefix.AUTHENTICATION.prefix}$it" } val encodedService = if (service.isNullOrEmpty()) "" else encodeService(service) return "did:peer:2$encodedEncryptionKeysStr$encodedSigningKeysStr$encodedService" diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/PeerDIDResolver.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/PeerDIDResolver.kt index 29fbd59..c114ddc 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/PeerDIDResolver.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/PeerDIDResolver.kt @@ -21,6 +21,7 @@ import kotlin.jvm.JvmOverloads * @return resolved [DIDDocPeerDID] as JSON string */ @JvmOverloads +@Throws(IllegalArgumentException::class) fun resolvePeerDID( peerDID: PeerDID, format: VerificationMaterialFormatPeerDID = VerificationMaterialFormatPeerDID.MULTIBASE @@ -37,6 +38,13 @@ fun resolvePeerDID( return didDoc.toJson() } +/** + * Builds a PeerDID DID Document for the numalgo0 format. + * + * @param peerDID The PeerDID. + * @param format The format of verification material in the DID Document. + * @return The built DID Document. + */ private fun buildDIDDocNumalgo0(peerDID: PeerDID, format: VerificationMaterialFormatPeerDID): DIDDocPeerDID { val inceptionKey = peerDID.substring(10) val decodedEncumbasis = decodeMultibaseEncnumbasisAuth(inceptionKey, format) @@ -46,6 +54,15 @@ private fun buildDIDDocNumalgo0(peerDID: PeerDID, format: VerificationMaterialFo ) } +/** + * Builds a PeerDID DID Document using the Numalgo2 algorithm. + * + * @param peerDID The PeerDID identifier. + * @param format The format of the verification material. + * @return The built PeerDID DID Document. + * @throws IllegalArgumentException if the transform part of the PeerDID is unsupported. + */ +@Throws(IllegalArgumentException::class) private fun buildDIDDocNumalgo2(peerDID: PeerDID, format: VerificationMaterialFormatPeerDID): DIDDocPeerDID { val keys = peerDID.drop(11) @@ -87,6 +104,15 @@ private fun buildDIDDocNumalgo2(peerDID: PeerDID, format: VerificationMaterialFo ) } +/** + * Decodes a multibase-encoded encnumbasis with a given verification material format. + * + * @param multibase The multibase-encoded encnumbasis to decode. + * @param format The verification material format. + * @throws MalformedPeerDIDException if the multibase is invalid. + * @return The decoded encnumbasis as verification material. + */ +@Throws(MalformedPeerDIDException::class) private fun decodeMultibaseEncnumbasisAuth( multibase: String, format: VerificationMaterialFormatPeerDID @@ -100,6 +126,15 @@ private fun decodeMultibaseEncnumbasisAuth( } } +/** + * Decodes a multibase encoded number basis agreement to a verification material for DID DOC. + * + * @param multibase The multibase string to decode. + * @param format The format of public keys in the DID DOC. + * @throws MalformedPeerDIDException If the multibase string is invalid. + * @return The decoded encnumbasis as verification material for DID DOC. + */ +@Throws(MalformedPeerDIDException::class) private fun decodeMultibaseEncnumbasisAgreement( multibase: String, format: VerificationMaterialFormatPeerDID @@ -113,6 +148,15 @@ private fun decodeMultibaseEncnumbasisAgreement( } } +/** + * Decodes the provided list of service JSON objects according to the PeerDID spec. + * + * @param service The list of JSON objects representing services. + * @param peerDID The PeerDID used as an ID. + * @return The decoded list of services. + * @throws MalformedPeerDIDException If the service is not correctly decoded. + */ +@Throws(MalformedPeerDIDException::class) private fun doDecodeService(service: List, peerDID: String): List? { try { return decodeService(service, peerDID) diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/Types.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/Types.kt index 9ce71a6..f61c263 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/Types.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/Types.kt @@ -3,15 +3,28 @@ package io.iohk.atala.prism.didcomm.didpeer import kotlinx.serialization.Contextual import kotlinx.serialization.Serializable +/** + * An enumeration that represents the format of verification material in a PeerDID. + */ enum class VerificationMaterialFormatPeerDID { JWK, BASE58, MULTIBASE } +/** + * Represents the types of verification methods for PeerDID. + * + * @param value The string value associated with the verification method type. + */ @Serializable sealed class VerificationMethodTypePeerDID(val value: String) +/** + * A sealed class representing the types of verification methods for agreements. + * + * @property value The value associated with the verification method type. + */ sealed class VerificationMethodTypeAgreement(value: String) : VerificationMethodTypePeerDID(value) { object JsonWebKey2020 : VerificationMethodTypeAgreement("JsonWebKey2020") @@ -20,6 +33,11 @@ sealed class VerificationMethodTypeAgreement(value: String) : VerificationMethod object X25519KeyAgreementKey2020 : VerificationMethodTypeAgreement("X25519KeyAgreementKey2020") } +/** + * Represents the different types of authentication methods for verification. + * + * @param value The string value representing the authentication method type. + */ sealed class VerificationMethodTypeAuthentication(value: String) : VerificationMethodTypePeerDID(value) { object JsonWebKey2020 : VerificationMethodTypeAuthentication("JsonWebKey2020") @@ -28,6 +46,14 @@ sealed class VerificationMethodTypeAuthentication(value: String) : VerificationM object ED25519VerificationKey2020 : VerificationMethodTypeAuthentication("Ed25519VerificationKey2020") } +/** + * Represents the verification material used in a PeerDID. + * + * @param T The type of the verification method. + * @property format The format of the verification material. + * @property value The value of the verification material. + * @property type The type of the verification method. + */ @Serializable data class VerificationMaterialPeerDID( val format: VerificationMaterialFormatPeerDID, @@ -35,8 +61,22 @@ data class VerificationMaterialPeerDID( val type: T ) +/** + * Alias for [VerificationMaterialPeerDID] with [VerificationMethodTypeAgreement] type parameter. + */ typealias VerificationMaterialAgreement = VerificationMaterialPeerDID + +/** + * Alias for [VerificationMaterialPeerDID] with [VerificationMethodTypeAuthentication] type parameter. + */ typealias VerificationMaterialAuthentication = VerificationMaterialPeerDID +/** + * Type alias for JSON strings. + */ typealias JSON = String + +/** + * Defines the type PeerDID, which is an alias for a String. + */ typealias PeerDID = String diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/DIDDocHelper.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/DIDDocHelper.kt index 43c336c..f112f46 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/DIDDocHelper.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/DIDDocHelper.kt @@ -24,6 +24,9 @@ import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive +/** + * Maps verification method types to corresponding public key fields. + */ private val verTypeToField = mapOf( VerificationMethodTypeAgreement.X25519KeyAgreementKey2019 to PublicKeyField.BASE58, @@ -34,6 +37,9 @@ private val verTypeToField = VerificationMethodTypeAuthentication.JsonWebKey2020 to PublicKeyField.JWK ) +/** + * Mapping from verification method type to verification material format. + */ private val verTypeToFormat = mapOf( VerificationMethodTypeAgreement.X25519KeyAgreementKey2019 to VerificationMaterialFormatPeerDID.BASE58, @@ -44,6 +50,14 @@ private val verTypeToFormat = VerificationMethodTypeAuthentication.JsonWebKey2020 to VerificationMaterialFormatPeerDID.JWK ) +/** + * Creates a [DIDDocPeerDID] instance from a JSON object. + * + * @param jsonObject The JSON object representing the DID Doc. + * @return [DIDDocPeerDID] instance. + * @throws IllegalArgumentException if the JSON object is missing required fields. + */ +@Throws(IllegalArgumentException::class) internal fun didDocFromJson(jsonObject: JsonObject): DIDDocPeerDID { val did = jsonObject["id"]?.jsonPrimitive?.content @@ -70,7 +84,15 @@ internal fun didDocFromJson(jsonObject: JsonObject): DIDDocPeerDID { ) } +/** + * Converts a JSON object to a VerificationMethodPeerDID object. + * + * @param jsonObject The JSON object representing the verification method. + * @return A VerificationMethodPeerDID object. + * @throws IllegalArgumentException if the required fields are missing in the JSON object. + */ @Suppress("IMPLICIT_CAST_TO_ANY") +@Throws(IllegalArgumentException::class) internal fun verificationMethodFromJson(jsonObject: JsonObject): VerificationMethodPeerDID { val id = jsonObject["id"]?.jsonPrimitive?.content @@ -90,9 +112,6 @@ internal fun verificationMethodFromJson(jsonObject: JsonObject): VerificationMet jsonObject[field.value]?.jsonObject ?: throw IllegalArgumentException("No 'field' field in method $jsonObject") jwkJson.toMap() -// val jwkJson = jsonObject[field.value]?.jsonObject?.toString() -// ?: throw IllegalArgumentException("No 'field' field in method $jsonObject") -// fromJsonToMap(jwkJson) } else { jsonObject[field.value]?.jsonPrimitive?.content ?: throw IllegalArgumentException("No 'field' field in method $jsonObject") @@ -110,8 +129,16 @@ internal fun verificationMethodFromJson(jsonObject: JsonObject): VerificationMet ) } +/** + * Parses a JSON object into a Service object. + * + * @param jsonObject The JSON object to parse. + * @return The parsed Service object. + * @throws IllegalArgumentException if the 'id' or 'type' field is missing in the JSON object. + */ +@Throws(IllegalArgumentException::class) internal fun serviceFromJson(jsonObject: JsonObject): Service { - val serviceMap = jsonObject.toMap() // fromJsonToMap(jsonObject.toString()) + val serviceMap = jsonObject.toMap() val id = jsonObject[SERVICE_ID]?.jsonPrimitive?.content @@ -137,6 +164,15 @@ internal fun serviceFromJson(jsonObject: JsonObject): Service { ) } +/** + * Retrieves the verification method type from the given JSON object. + * + * @param jsonObject The JSON object representing the verification method. + * @return The corresponding VerificationMethodTypePeerDID. + * @throws IllegalArgumentException If the 'type' field is missing in the method or if the verification + * method type is unknown. + */ +@Throws(IllegalArgumentException::class) private fun getVerMethodType(jsonObject: JsonObject): VerificationMethodTypePeerDID { val type = (jsonObject["type"] as JsonPrimitive).contentOrNull diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/JWKOKP.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/JWKOKP.kt index fec6035..bbfe2c6 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/JWKOKP.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/JWKOKP.kt @@ -7,6 +7,15 @@ import io.iohk.atala.prism.didcomm.didpeer.VerificationMethodTypeAgreement import io.iohk.atala.prism.didcomm.didpeer.VerificationMethodTypeAuthentication import io.iohk.atala.prism.didcomm.didpeer.VerificationMethodTypePeerDID +/** + * Converts a public key to a JSON Web Key (JWK). + * + * @param publicKey The public key to convert as a byte array. + * @param verMethodType The type of verification method. + * @return The public key converted to a JWK. + * @throws IllegalArgumentException if the JWK type is unsupported. + */ +@Throws(IllegalArgumentException::class) fun toJwk(publicKey: ByteArray, verMethodType: VerificationMethodTypePeerDID): Map { val x = publicKey.base64UrlEncoded val crv = @@ -22,6 +31,13 @@ fun toJwk(publicKey: ByteArray, verMethodType: VerificationMethodTypePeerDID): M ) } +/** + * Converts a given JWK object to a byte array. + * @param verMaterial the VerificationMaterialPeerDID object representing the JWK + * @throws IllegalArgumentException if the JWK key is invalid + * @return the JWK key as a byte array + */ +@Throws(IllegalArgumentException::class) fun fromJwk(verMaterial: VerificationMaterialPeerDID): ByteArray { val jwkDict = if (verMaterial.value is Map<*, *>) verMaterial.value else fromJsonToMap(verMaterial.value.toString()) diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Multibase.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Multibase.kt index 1030f0c..c6564f4 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Multibase.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Multibase.kt @@ -4,11 +4,32 @@ import io.iohk.atala.prism.apollo.base58.base58BtcDecodedBytes import io.iohk.atala.prism.apollo.base58.base58BtcEncoded import io.iohk.atala.prism.apollo.multibase.MultiBase +/** + * Converts a byte array to a base58 multibase encoding. + * + * @param value The byte array to be encoded. + * @return The base58 multibase encoding of the byte array. + * @throws IllegalArgumentException If the byte array is invalid. + */ fun toBase58Multibase(value: ByteArray) = MultiBase.encode(MultiBase.Base.BASE58_BTC, value) +/** + * Converts a byte array to a Base58 encoded string. + * + * @param value The byte array to encode. + * @return The Base58 encoded string. + */ fun toBase58(value: ByteArray) = value.base58BtcEncoded +/** + * Decodes a multibase string to a pair of the transform and the encoded number basis. + * + * @param multibase The multibase string to decode. + * @throws IllegalArgumentException if the multibase string is invalid. + * @return A pair of the encoded number basis and the decoded transform. + */ +@Throws(IllegalArgumentException::class) fun fromBase58Multibase(multibase: String): Pair { if (multibase.isEmpty()) { throw IllegalArgumentException("Invalid key: No transform part in multibase encoding") @@ -22,6 +43,14 @@ fun fromBase58Multibase(multibase: String): Pair { return Pair(encnumbasis, decodedEncnumbasis) } +/** + * Converts a base58-encoded string to a byte array. + * + * @param value The base58-encoded string. + * @throws IllegalArgumentException if the input string is not a valid base58 encoding. + * @return The decoded byte array. + */ +@Throws(IllegalArgumentException::class) fun fromBase58(value: String): ByteArray { if (!isBase58(value)) { throw IllegalArgumentException("Invalid key: Invalid base58 encoding: $value") @@ -29,6 +58,12 @@ fun fromBase58(value: String): ByteArray { return value.base58BtcDecodedBytes } +/** + * Checks whether a given string is base58 encoded. + * + * @param value the string to be checked + * @return true if the string is base58 encoded, false otherwise + */ fun isBase58(value: String): Boolean { val alphabet = Regex("[1-9a-km-zA-HJ-NP-Z]+") return alphabet.matches(value) diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Multicodec.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Multicodec.kt index df51af8..0a0aab1 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Multicodec.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Multicodec.kt @@ -6,11 +6,23 @@ import io.iohk.atala.prism.didcomm.didpeer.VerificationMethodTypeAuthentication import io.iohk.atala.prism.didcomm.didpeer.VerificationMethodTypePeerDID import okio.Buffer +/** + * Enum class representing different codecs. + * + * @property prefix The prefix value of the codec. + */ enum class Codec(val prefix: Int) { X25519(0xEC), ED25519(0xED) } +/** + * Converts the given value to a multicodec byte array using the specified keyType. + * + * @param value The value to convert. + * @param keyType The keyType representing the verification method type. + * @return The multicodec byte array. + */ fun toMulticodec(value: ByteArray, keyType: VerificationMethodTypePeerDID): ByteArray { val prefix = getCodec(keyType).prefix val byteBuffer = Buffer() @@ -18,6 +30,12 @@ fun toMulticodec(value: ByteArray, keyType: VerificationMethodTypePeerDID): Byte return byteBuffer.readByteArray().plus(value) } +/** + * Decodes a multicodec value to a pair of Codec and the remaining bytes. + * + * @param value The multicodec value to decode. + * @return A pair of Codec and the remaining bytes. + */ fun fromMulticodec(value: ByteArray): Pair { val prefix = VarInt.read(Buffer().write(value)) val codec = getCodec(prefix) @@ -26,12 +44,26 @@ fun fromMulticodec(value: ByteArray): Pair { return Pair(codec, value.drop(2).toByteArray()) } +/** + * Returns the corresponding Codec for the given [VerificationMethodTypePeerDID]. + * + * @param keyType the key type for which to retrieve the Codec + * @return the Codec corresponding to the given key type + */ private fun getCodec(keyType: VerificationMethodTypePeerDID) = when (keyType) { is VerificationMethodTypeAuthentication -> Codec.ED25519 is VerificationMethodTypeAgreement -> Codec.X25519 } +/** + * Retrieves the Codec based on the provided prefix. + * + * @param prefix The prefix value to search for. + * @return The matching Codec entry. + * @throws IllegalArgumentException If the prefix is not supported. + */ +@Throws(IllegalArgumentException::class) private fun getCodec(prefix: Int) = - Codec.values().find { it.prefix == prefix } + Codec.entries.find { it.prefix == prefix } ?: throw IllegalArgumentException("Invalid key: Prefix $prefix not supported") diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/PeerDIDHelper.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/PeerDIDHelper.kt index 19ac376..84b5b82 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/PeerDIDHelper.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/PeerDIDHelper.kt @@ -25,12 +25,22 @@ import io.iohk.atala.prism.didcomm.didpeer.VerificationMethodTypePeerDID import kotlinx.serialization.SerializationException import kotlin.jvm.JvmName +/** + * Enum class representing prefixes used in the Numalgo2 algorithm. + * Each prefix is associated with a character value. + * + * @property prefix The character value of the prefix + */ internal enum class Numalgo2Prefix(val prefix: Char) { AUTHENTICATION('V'), KEY_AGREEMENT('E'), SERVICE('S') } +/** + * Prefix values used for encoding and decoding services. + * Each prefix corresponds to a specific service type. + */ private val ServicePrefix = mapOf( SERVICE_TYPE to "t", @@ -61,14 +71,15 @@ internal fun encodeService(service: JSON): String { } /** - * Decodes [encodedService] according to PeerDID spec + * Decodes [encodedServices] according to PeerDID spec * @see * Specification - * @param [encodedService] service to decode + * @param [encodedServices] service to decode * @param [peerDID] PeerDID which will be used as an ID * @throws IllegalArgumentException if service is not correctly decoded * @return decoded service */ +@Throws(IllegalArgumentException::class) internal fun decodeService(encodedServices: List, peerDID: PeerDID): List? { if (encodedServices.isEmpty()) { return null @@ -134,6 +145,12 @@ internal fun createMultibaseEncnumbasis(key: VerificationMaterialPeerDID @@ -222,6 +239,13 @@ internal fun decodeMultibaseEncnumbasis( return DecodedEncumbasis(encnumbasis, verMaterial) } +/** + * Gets a verification method for a given DID and decoded encumbasis. + * + * @param did The DID string. + * @param decodedEncumbasis The decoded encumbasis object containing the encnumbasis and verification material. + * @return The verification method for the given DID and decoded encumbasis. + */ internal fun getVerificationMethod(did: String, decodedEncumbasis: DecodedEncumbasis) = VerificationMethodPeerDID( id = "$did#${decodedEncumbasis.encnumbasis}", diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Utils.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Utils.kt index 1566e8f..7a38e04 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Utils.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Utils.kt @@ -11,6 +11,11 @@ import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive +/** + * Converts an object to its JSON representation as a [JsonElement]. + * + * @return The JSON representation of the object as a [JsonElement]. + */ fun Any?.toJsonElement(): JsonElement { return when (this) { is Number -> JsonPrimitive(this) @@ -24,18 +29,57 @@ fun Any?.toJsonElement(): JsonElement { } } +/** + * Converts an array to a JSON array. + * + * @return The JSON array representation of the array. + */ fun Array<*>.toJsonArray() = JsonArray(map { it.toJsonElement() }) +/** + * Converts an Iterable of any type to a JSON array. + * + * @return The JSON array representation of the Iterable. + */ fun Iterable<*>.toJsonArray() = JsonArray(map { it.toJsonElement() }) +/** + * Converts the given [Map] object to a [JsonObject]. + * Each key-value pair in the map is converted to a corresponding key-value pair in the JsonObject. + * The keys are converted to string representation using the [toString] method. + * The values are converted to [JsonElement] using the [toJsonElement] method. + * + * @return the converted JsonObject. + * + * @see toJsonElement + */ fun Map<*, *>.toJsonObject() = JsonObject(mapKeys { it.key.toString() }.mapValues { it.value.toJsonElement() }) +/** + * Encodes the given pairs of key-value data into a JSON string representation. + * + * @param pairs the key-value pairs to encode + * @return the JSON string representation of the encoded data + */ fun Json.encodeToString(vararg pairs: Pair<*, *>) = encodeToString(pairs.toMap().toJsonElement()) +/** + * Converts the given [value] to its JSON representation as a string. + * + * @param value the value to convert to JSON + * @return the JSON representation of the value as a string + */ fun toJson(value: Any?): String { return Json.encodeToString(value.toJsonElement()) } +/** + * Extracts the key-value pairs from a given JsonObject and returns them as a Map. + * + * @param jsonObject the JsonObject from which to extract key-value pairs + * @return a Map containing the extracted key-value pairs + * @throws Exception if the value of any key in the JsonObject is not of type JsonPrimitive or JsonArray + */ private fun extractFromJsonObject(jsonObject: JsonObject): Map { val currentMap = mutableMapOf() jsonObject.forEach { @@ -63,24 +107,39 @@ private fun extractFromJsonObject(jsonObject: JsonObject): Map { } /** - * I'm expecting the value to be a JSON array + * Converts a JSON string to a List of Maps. + * + * @param value The JSON string to convert. + * @return The converted List of Maps. + * @throws Exception if the JSON string is not valid. */ fun fromJsonToList(value: String): List> { val list: MutableList> = mutableListOf() - val element = Json.parseToJsonElement(value) + when (val element = Json.parseToJsonElement(value)) { + is JsonArray -> { + for (jsonElement in element.jsonArray) { + list.add(extractFromJsonObject(jsonElement.jsonObject)) + } + } - if (element is JsonArray) { - for (jsonElement in element.jsonArray) { - list.add(extractFromJsonObject(jsonElement.jsonObject)) + is JsonObject -> { + list.add(extractFromJsonObject(element.jsonObject)) + } + + else -> { + throw Exception("") } - } else if (element is JsonObject) { - list.add(extractFromJsonObject(element.jsonObject)) - } else { - throw Exception("") } return list } +/** + * Converts a JSON string to a Map object. + * + * @param value The JSON string to convert. + * @return The converted Map object. + * @throws Exception if the JSON string is not valid or if the value of any key in the JSON object is not of type JsonPrimitive or JsonArray. + */ fun fromJsonToMap(value: String): Map { val element = Json.parseToJsonElement(value) diff --git a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Validation.kt b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Validation.kt index 370cd4d..f7a06f2 100644 --- a/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Validation.kt +++ b/didpeer/src/commonMain/kotlin/io/iohk/atala/prism/didcomm/didpeer/core/Validation.kt @@ -7,6 +7,14 @@ import io.iohk.atala.prism.didcomm.didpeer.VerificationMethodTypePeerDID import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json +/** + * Validates the type of authentication material. + * + * @param verificationMaterial The verification material to validate. + * @Throws IllegalArgumentException if the verification material type is not + * VerificationMethodTypeAuthentication. + */ +@Throws(IllegalArgumentException::class) internal fun validateAuthenticationMaterialType(verificationMaterial: VerificationMaterialPeerDID) { if (verificationMaterial.type !is VerificationMethodTypeAuthentication) { throw IllegalArgumentException( @@ -15,6 +23,13 @@ internal fun validateAuthenticationMaterialType(verificationMaterial: Verificati } } +/** + * Validates the agreement material type of the verification material. + * + * @param verificationMaterial The verification material to be validated. + * @throws IllegalArgumentException If the verification material type is not a subclass of VerificationMethodTypeAgreement. + */ +@Throws(IllegalArgumentException::class) internal fun validateAgreementMaterialType(verificationMaterial: VerificationMaterialPeerDID) { if (verificationMaterial.type !is VerificationMethodTypeAgreement) { throw IllegalArgumentException( @@ -23,6 +38,13 @@ internal fun validateAgreementMaterialType(verificationMaterial: VerificationMat } } +/** + * Validates a JSON string. + * + * @param value The JSON string to validate + * @throws IllegalArgumentException If the JSON string is invalid + */ +@Throws(IllegalArgumentException::class) internal fun validateJson(value: String) { try { Json.parseToJsonElement(value) @@ -32,6 +54,13 @@ internal fun validateJson(value: String) { if (!value.contains("{")) throw IllegalArgumentException("Invalid JSON $value") } +/** + * Validates the length of a raw key byte array. + * + * @param key The raw key byte array. + * @throws IllegalArgumentException If the length of the raw key is not equal to 32. + */ +@Throws(IllegalArgumentException::class) internal fun validateRawKeyLength(key: ByteArray) { // for all supported key types now (ED25519 and X25510) the expected size is 32 if (key.size != 32) { diff --git a/package.json b/package.json index ba58a24..19fe51a 100644 --- a/package.json +++ b/package.json @@ -16,11 +16,10 @@ }, "homepage": "https://github.com/input-output-hk/atala-prism-didcomm-kmm#readme", "devDependencies": { - "@semantic-release/changelog": "^6.0.2", - "@semantic-release/exec": "^6.0.3", + "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", - "gradle-semantic-release-plugin": "^1.7.4", - "semantic-release": "^19.0.5", - "semantic-release-slack-bot": "^3.5.3" + "gradle-semantic-release-plugin": "^1.9.0", + "semantic-release": "^22.0.12", + "semantic-release-slack-bot": "^4.0.2" } }