diff --git a/atala-prism-sdk/build.gradle.kts b/atala-prism-sdk/build.gradle.kts index 454e26a06..34b4bcaed 100644 --- a/atala-prism-sdk/build.gradle.kts +++ b/atala-prism-sdk/build.gradle.kts @@ -223,7 +223,7 @@ tasks.withType().configureEach { } } -val buildProtoLibsGen by tasks.creating { +val buildProtoLibsGen: Task by tasks.creating { group = "build" this.dependsOn(":protosLib:generateProto") } diff --git a/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpClient.kt b/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpClient.kt index c6ff00ce2..d9dd7d2e9 100644 --- a/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpClient.kt +++ b/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpClient.kt @@ -3,6 +3,12 @@ package io.iohk.atala.prism.walletsdk.domain.models import io.ktor.client.HttpClientConfig import io.ktor.client.engine.okhttp.OkHttp +/** + * Creates an HTTP client with the specified configuration. + * + * @param config The configuration block for the HTTP client. + * @return The created HTTP client. + */ actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = io.ktor.client.HttpClient(OkHttp) { config(this) } diff --git a/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt b/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt index f7f5c6e49..a6c7404e7 100644 --- a/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt +++ b/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt @@ -1,8 +1,35 @@ package io.iohk.atala.prism.walletsdk.domain.models +/** + * The `Platform` object represents the platform on which the code is running. + */ actual object Platform { + /** + * This variable represents the operating system on which the code is currently running. + * + * On Android, it returns a string with the Android version followed by the SDK level. + * For example: "Android 10" + * + * @return The operating system of the device. + */ actual val OS: String - get() = "Android" + get() = "Android ${android.os.Build.VERSION.SDK_INT}" + + /** + * Represents the platform type. + * + * This actual property represents the current platform type. It is used to determine the type of the platform on which + * the application is being executed. The possible platform types are JVM, ANDROID, IOS, and WEB. + * + * This property is read-only and can be accessed using the `type` property of the `PlatformType` class. + * + * Example usage: + * ``` + * val platformType = PlatformType.ANDROID + * ``` + * + * @see PlatformType + */ actual val type: PlatformType get() = PlatformType.ANDROID } diff --git a/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/data/DbConnection.kt b/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/data/DbConnection.kt index e864f6093..9cc058c23 100644 --- a/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/data/DbConnection.kt +++ b/atala-prism-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/data/DbConnection.kt @@ -6,6 +6,9 @@ import com.squareup.sqldelight.db.SqlDriver import io.iohk.atala.prism.walletsdk.PrismPlutoDb import io.iohk.atala.prism.walletsdk.domain.models.PlutoError +/** + * DbConnection class represents a connection to the database. + */ actual class DbConnection actual constructor() { actual var driver: SqlDriver? = null actual suspend fun connectDb(context: Any?): PrismPlutoDb { @@ -16,5 +19,14 @@ actual class DbConnection actual constructor() { } } +/** + * Represents the connection status of an SQL driver. + */ actual val SqlDriver.isConnected: Boolean - get() = true + get() { + try { + return this.executeQuery(null, "SELECT 1", 0).next() + } catch (ex: Exception) { + return false + } + } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/ApolloImpl.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/ApolloImpl.kt index e768d361c..0f18dd181 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/ApolloImpl.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/ApolloImpl.kt @@ -74,12 +74,32 @@ class ApolloImpl : Apollo { ) } + /** + * Creates a private key based on the provided properties. + * + * @param properties A map of properties used to create the private key. The map should contain the following keys: + * - "type" (String): The type of the key ("EC" or "Curve25519"). + * - "curve" (String): The curve of the key. + * - "rawKey" (ByteArray): The raw key data (optional). + * - "index" (Int): The index for the key (only applicable for EC keys with curve "secp256k1"). + * - "derivationPath" (String): The derivation path for the key (only applicable for EC keys with curve "secp256k1"). + * - "seed" (String): The seed for the key (only applicable for EC keys with curve "secp256k1"). + * + * @return The created private key. + * + * @throws ApolloError.InvalidKeyType If the provided key type is invalid. + * @throws ApolloError.InvalidKeyCurve If the provided key curve is invalid. + * @throws ApolloError.InvalidRawData If the provided raw key data is invalid. + * @throws ApolloError.InvalidIndex If the provided index is invalid. + * @throws ApolloError.InvalidDerivationPath If the provided derivation path is invalid. + * @throws ApolloError.InvalidSeed If the provided seed is invalid. + */ override fun createPrivateKey(properties: Map): PrivateKey { if (!properties.containsKey(TypeKey().property)) { - throw ApolloError.InvalidKeyType(TypeKey().property, KeyTypes.values().map { it.type }.toTypedArray()) + throw ApolloError.InvalidKeyType(TypeKey().property) } if (!properties.containsKey(CurveKey().property)) { - throw ApolloError.InvalidKeyCurve(CurveKey().property, Curve.values().map { it.value }.toTypedArray()) + throw ApolloError.InvalidKeyCurve(CurveKey().property) } val keyType = properties[TypeKey().property] @@ -148,17 +168,38 @@ class ApolloImpl : Apollo { return keyPair.privateKey } } - throw ApolloError.InvalidKeyType(TypeKey().property, KeyTypes.values().map { it.type }.toTypedArray()) + throw ApolloError.InvalidKeyType(TypeKey().property) } + /** + * Checks if the provided data is associated with a private key identified by the given identifier. + * + * @param identifier The identifier for the private key. + * @param data The data to check. + * @return True if the data is associated with a private key, false otherwise. + */ override fun isPrivateKeyData(identifier: String, data: ByteArray): Boolean { return identifier.endsWith("priv") } + /** + * Checks if the provided data is associated with a public key identified by the given identifier. + * + * @param identifier The identifier for the public key. + * @param data The data to check. + * @return True if the data is associated with a public key, false otherwise. + */ override fun isPublicKeyData(identifier: String, data: ByteArray): Boolean { return identifier.endsWith("pub") } + /** + * Restores a private key based on the provided storable key. + * + * @param key The storable key to restore the private key from. + * @return The restored private key. + * @throws ApolloError.RestorationFailedNoIdentifierOrInvalid If the restoration identifier is missing or invalid. + */ override fun restorePrivateKey(key: StorableKey): PrivateKey { return when (key.restorationIdentifier) { "secp256k1+priv" -> { @@ -179,6 +220,13 @@ class ApolloImpl : Apollo { } } + /** + * Restores a public key based on the provided storable key. + * + * @param key The storable key to restore the public key from. + * @return The restored public key. + * @throws ApolloError.RestorationFailedNoIdentifierOrInvalid If the restoration identifier is missing or invalid. + */ override fun restorePublicKey(key: StorableKey): PublicKey { return when (key.restorationIdentifier) { "secp256k1+pub" -> { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/config/ECConfig.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/config/ECConfig.kt index 114852b9e..f331ee744 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/config/ECConfig.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/config/ECConfig.kt @@ -2,12 +2,15 @@ package io.iohk.atala.prism.walletsdk.apollo.config import com.ionspin.kotlin.bignum.integer.BigInteger +/** + * The ECConfig object provides configuration properties and constants related to elliptic curve cryptography (ECC). + */ object ECConfig { - val PRIVATE_KEY_BYTE_SIZE: Int = 32 - internal val PUBLIC_KEY_COORDINATE_BYTE_SIZE: Int = 32 - internal val PUBLIC_KEY_COMPRESSED_BYTE_SIZE: Int = PUBLIC_KEY_COORDINATE_BYTE_SIZE + 1 - val SIGNATURE_MAX_BYTE_SIZE: Int = 72 - val PUBLIC_KEY_BYTE_SIZE: Int = PUBLIC_KEY_COORDINATE_BYTE_SIZE * 2 + 1 + const val PRIVATE_KEY_BYTE_SIZE: Int = 32 + internal const val PUBLIC_KEY_COORDINATE_BYTE_SIZE: Int = 32 + internal const val PUBLIC_KEY_COMPRESSED_BYTE_SIZE: Int = PUBLIC_KEY_COORDINATE_BYTE_SIZE + 1 + const val SIGNATURE_MAX_BYTE_SIZE: Int = 72 + const val PUBLIC_KEY_BYTE_SIZE: Int = PUBLIC_KEY_COORDINATE_BYTE_SIZE * 2 + 1 // Field characteristic p (prime) is equal to 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 internal val p = BigInteger.parseString("115792089237316195423570985008687907853269984665640564039457584007908834671663", 10) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/helpers/ByteArrayExt.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/helpers/ByteArrayExt.kt index 11ce5d58f..4cc2f8d08 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/helpers/ByteArrayExt.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/helpers/ByteArrayExt.kt @@ -1,5 +1,13 @@ package io.iohk.atala.prism.walletsdk.apollo.helpers +/** + * Pads the current ByteArray with the specified padValue at the beginning, + * making it equal to or larger than the specified length. + * + * @param length The desired length for the new ByteArray. + * @param padValue The value used to pad the ByteArray. + * @return The padded ByteArray with the specified length. + */ fun ByteArray.padStart(length: Int, padValue: Byte): ByteArray { return if (size >= length) { this diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/helpers/JVMBigIntegerExt.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/helpers/JVMBigIntegerExt.kt index fa197eca6..c718dfeeb 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/helpers/JVMBigIntegerExt.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/helpers/JVMBigIntegerExt.kt @@ -2,6 +2,11 @@ package io.iohk.atala.prism.walletsdk.apollo.helpers import java.math.BigInteger +/** + * Converts a Kotlin BigInteger to a Java BigInteger. + * + * @return the converted Java BigInteger. + */ fun com.ionspin.kotlin.bignum.integer.BigInteger.toJavaBigInteger(): BigInteger { return BigInteger(this.signum(), this.toByteArray()) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519KeyPair.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519KeyPair.kt index dddab644a..005aa4167 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519KeyPair.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519KeyPair.kt @@ -5,12 +5,21 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.KeyPair import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PrivateKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PublicKey +/** + * Represents a pair of Ed25519 private and public keys. + */ class Ed25519KeyPair( override var privateKey: PrivateKey, override var publicKey: PublicKey ) : KeyPair() { companion object { + /** + * Generates a pair of Ed25519 private and public keys. + * + * @return The generated Ed25519KeyPair. + */ + @JvmStatic fun generateKeyPair(): Ed25519KeyPair { val pair = KMMEdKeyPair.generateKeyPair() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519PrivateKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519PrivateKey.kt index 8cb5136cf..423f9758e 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519PrivateKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519PrivateKey.kt @@ -14,6 +14,21 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PublicKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.SignableKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.StorableKey +/** + * Represents a private key for the Ed25519 algorithm. + * + * This class extends the abstract class PrivateKey and implements the interfaces SignableKey, StorableKey, and ExportableKey. + * + * @param nativeValue The raw byte array representing the private key. + * @property size The size of the private key in bytes. + * @property raw The raw byte array representing the private key. + * @property type The type of the key. Always set to KeyTypes.EC. + * @property keySpecification A mutable map representing the key specification. + * + * @constructor Creates an instance of Ed25519PrivateKey and initializes its properties. + * + * @param nativeValue The raw byte array representing the private key. + */ class Ed25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), SignableKey, StorableKey, ExportableKey { override val type: KeyTypes = KeyTypes.EC @@ -26,16 +41,32 @@ class Ed25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), SignableKey, Sto keySpecification[CurveKey().property] = Curve.ED25519.value } + /** + * Returns the public key corresponding to this private key. + * @return the public key as a PublicKey object + */ override fun publicKey(): PublicKey { val public = KMMEdPrivateKey(raw).publicKey() return Ed25519PublicKey(public.raw) } + /** + * Signs a byte array message using the private key. + * + * @param message The message to be signed. + * @return The signature as a byte array. + */ override fun sign(message: ByteArray): ByteArray { val private = KMMEdPrivateKey(raw) return private.sign(message) } + /** + * Returns the PEM (Privacy-Enhanced Mail) representation of the private key. + * The key is encoded in base64 and wrapped with "BEGIN" and "END" markers. + * + * @return the PEM representation of the private key as a String + */ override fun getPem(): String { return PEMKey( keyType = PEMKeyType.EC_PRIVATE_KEY, @@ -43,6 +74,11 @@ class Ed25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), SignableKey, Sto ).pemEncoded() } + /** + * Retrieves the JWK (JSON Web Key) representation of the private key. + * + * @return The JWK instance representing the private key. + */ override fun getJwk(): JWK { return JWK( kty = "OKP", @@ -51,6 +87,12 @@ class Ed25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), SignableKey, Sto ) } + /** + * Retrieves the JWK (JSON Web Key) representation of the private key with the specified key identifier (kid). + * + * @param kid The key identifier to be associated with the JWK. + * @return The JWK object representing the private key. + */ override fun jwkWithKid(kid: String): JWK { return JWK( kty = "OKP", @@ -60,8 +102,22 @@ class Ed25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), SignableKey, Sto ) } + /** + * Represents the storable data of a key. + * + * @property storableData The byte array representing the storable data. + * @see StorableKey + */ override val storableData: ByteArray get() = raw + + /** + * This variable represents the restoration identifier for a key. + * It is a unique identifier used for restoring the key from storage. + * + * @property restorationIdentifier The restoration identifier for the key. + * @see StorableKey + */ override val restorationIdentifier: String get() = "ed25519+priv" } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519PublicKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519PublicKey.kt index e4ffcd981..afa7f5e39 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519PublicKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Ed25519PublicKey.kt @@ -13,6 +13,17 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PublicKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.StorableKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.VerifiableKey +/** + * Represents an Ed25519 public key. + * + * This class implements the [PublicKey], [VerifiableKey], [StorableKey], and [ExportableKey] interfaces. + * + * @param nativeValue The native value of the public key. + * @property type The type of the key, which is [KeyTypes.EC]. + * @property keySpecification The specification of the key. + * @property size The size of the key. + * @property raw The raw bytes of the key. + */ class Ed25519PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, StorableKey, ExportableKey { override val type: KeyTypes = KeyTypes.EC override val keySpecification: MutableMap = mutableMapOf() @@ -24,11 +35,24 @@ class Ed25519PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, Sto keySpecification[CurveKey().property] = Curve.ED25519.value } + /** + * Verifies the authenticity of a signature using a given message and signature. + * + * @param message The message to verify. + * @param signature The signature data to verify. + * @return A boolean value indicating whether the signature is valid or not. + */ override fun verify(message: ByteArray, signature: ByteArray): Boolean { val public = KMMEdPublicKey(raw) return public.verify(message, signature) } + /** + * Returns the PEM (Privacy-Enhanced Mail) representation of the public key. + * The key is encoded in base64 and wrapped with "BEGIN" and "END" markers. + * + * @return the PEM representation of the private key as a String + */ override fun getPem(): String { return PEMKey( keyType = PEMKeyType.EC_PUBLIC_KEY, @@ -36,6 +60,11 @@ class Ed25519PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, Sto ).pemEncoded() } + /** + * Retrieves the JWK (JSON Web Key) representation of the public key. + * + * @return The JWK instance representing the private key. + */ override fun getJwk(): JWK { return JWK( kty = "OKP", @@ -44,6 +73,12 @@ class Ed25519PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, Sto ) } + /** + * Retrieves the JWK (JSON Web Key) representation of the private key with the specified key identifier (kid). + * + * @param kid The key identifier to be associated with the JWK. + * @return The JWK object representing the private key. + */ override fun jwkWithKid(kid: String): JWK { return JWK( kty = "OKP", @@ -53,8 +88,22 @@ class Ed25519PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, Sto ) } + /** + * Represents the storable data of a key. + * + * @property storableData The byte array representing the storable data. + * @see StorableKey + */ override val storableData: ByteArray get() = raw + + /** + * This variable represents the restoration identifier for a key. + * It is a unique identifier used for restoring the key from storage. + * + * @property restorationIdentifier The restoration identifier for the key. + * @see StorableKey + */ override val restorationIdentifier: String get() = "ed25519+pub" } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/JVMBigIntegerExt.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/JVMBigIntegerExt.kt index 53c6c2557..935b22cc1 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/JVMBigIntegerExt.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/JVMBigIntegerExt.kt @@ -3,11 +3,22 @@ package io.iohk.atala.prism.walletsdk.apollo.utils import com.ionspin.kotlin.bignum.integer.Sign import java.math.BigInteger +/** + * Converts a `BigInteger` to an unsigned byte array. + * + * @return The unsigned byte array representation of the `BigInteger`. + */ fun BigInteger.toUnsignedByteArray(): ByteArray { val comparedValue = 0.toByte() return toByteArray().dropWhile { it == comparedValue }.toByteArray() } +/** + * Converts a `java.math.BigInteger` to a `com.ionspin.kotlin.bignum.integer.BigInteger` object. + * + * @return The converted `com.ionspin.kotlin.bignum.integer.BigInteger` object. + * @throws IllegalStateException if the sign of the original `java.math.BigInteger` is invalid. + */ fun BigInteger.toKotlinBigInteger(): com.ionspin.kotlin.bignum.integer.BigInteger { val sign = when (this.signum()) { -1 -> Sign.NEGATIVE diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1KeyPair.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1KeyPair.kt index b83fc73c8..90c421714 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1KeyPair.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1KeyPair.kt @@ -7,8 +7,22 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.KeyPair import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PrivateKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PublicKey +/** + * Represents a key pair consisting of a private key and public key. + * + * @property privateKey The private key of the key pair. + * @property publicKey The public key of the key pair. + */ class Secp256k1KeyPair(override var privateKey: PrivateKey, override var publicKey: PublicKey) : KeyPair() { companion object { + /** + * Generates a key pair using a given seed and key curve. + * + * @param seed The seed used for key generation. + * @param curve The key curve to use for key generation. + * @return A key pair consisting of a private key and public key. + */ + @JvmStatic fun generateKeyPair(seed: Seed, curve: KeyCurve): Secp256k1KeyPair { val path = "m/${curve.index}'/0'/0'" val hdKey = HDKey(seed.value, 0, 0) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1PrivateKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1PrivateKey.kt index c01400900..b0e02c8e5 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1PrivateKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1PrivateKey.kt @@ -21,6 +21,27 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.SeedKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.SignableKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.StorableKey +/** + * The `Secp256k1PrivateKey` class represents a private key that uses the secp256k1 elliptic curve. + * It extends the `PrivateKey` class and implements the `SignableKey`, `StorableKey`, `ExportableKey`, and `DerivableKey` interfaces. + * + * @param nativeValue The raw byte array value of the private key. + * @property type The type of the key, which is set to `KeyTypes.EC`. + * @property keySpecification A mutable map that contains additional key specifications. + * @property size The size of the private key in bytes. + * @property raw The raw byte array value of the private key. + * + * @constructor Creates a `Secp256k1PrivateKey` object with the specified `nativeValue`. + * + * @param nativeValue The raw byte array value of the private key. + * + * + * @see PrivateKey + * @see SignableKey + * @see StorableKey + * @see ExportableKey + * @see DerivableKey + */ class Secp256k1PrivateKey(nativeValue: ByteArray) : PrivateKey(), SignableKey, @@ -37,15 +58,31 @@ class Secp256k1PrivateKey(nativeValue: ByteArray) : keySpecification[CurveKey().property] = Curve.SECP256K1.value } + /** + * Returns the public key corresponding to this private key. + * @return the public key as a PublicKey object + */ override fun publicKey(): PublicKey { return Secp256k1PublicKey(KMMECSecp256k1PrivateKey.secp256k1FromByteArray(raw).getPublicKey().raw) } + /** + * Signs a byte array message using the private key. + * + * @param message The message to be signed. + * @return The signature as a byte array. + */ override fun sign(message: ByteArray): ByteArray { val kmmPrivateKey = KMMECSecp256k1PrivateKey.secp256k1FromByteArray(raw) return kmmPrivateKey.sign(data = message) } + /** + * Returns the PEM (Privacy-Enhanced Mail) representation of the private key. + * The key is encoded in base64 and wrapped with "BEGIN" and "END" markers. + * + * @return the PEM representation of the private key as a String + */ override fun getPem(): String { return PEMKey( keyType = PEMKeyType.EC_PRIVATE_KEY, @@ -53,6 +90,11 @@ class Secp256k1PrivateKey(nativeValue: ByteArray) : ).pemEncoded() } + /** + * Retrieves the JWK (JSON Web Key) representation of the private key. + * + * @return The JWK instance representing the private key. + */ override fun getJwk(): JWK { return JWK( kty = "OKP", @@ -61,6 +103,13 @@ class Secp256k1PrivateKey(nativeValue: ByteArray) : y = getProperty(CurvePointYKey().property).base64UrlEncoded ) } + + /** + * Retrieves the JWK (JSON Web Key) representation of the private key with the specified key identifier (kid). + * + * @param kid The key identifier to be associated with the JWK. + * @return The JWK object representing the private key. + */ override fun jwkWithKid(kid: String): JWK { return JWK( kty = "OKP", @@ -71,11 +120,32 @@ class Secp256k1PrivateKey(nativeValue: ByteArray) : ) } + /** + * Represents the storable data of a key. + * + * @property storableData The byte array representing the storable data. + * @see StorableKey + */ override val storableData: ByteArray get() = raw + + /** + * This variable represents the restoration identifier for a key. + * It is a unique identifier used for restoring the key from storage. + * + * @property restorationIdentifier The restoration identifier for the key. + * @see StorableKey + */ override val restorationIdentifier: String get() = "secp256k1+priv" + /** + * Derives a private key using the given derivation path. + * + * @param derivationPath the derivation path used to derive the key + * @return the derived private key + * @throws Exception if the key specification does not contain the required properties + */ override fun derive(derivationPath: DerivationPath): PrivateKey { val seed = getProperty(SeedKey().property) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1PublicKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1PublicKey.kt index 87219667e..b0cf69069 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1PublicKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/Secp256k1PublicKey.kt @@ -17,6 +17,11 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PublicKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.StorableKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.VerifiableKey +/** + * Represents a public key in the Secp256k1 elliptic curve algorithm. + * + * @param nativeValue The raw byte array representing the public key. + */ class Secp256k1PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, StorableKey, ExportableKey { override val type: KeyTypes = KeyTypes.EC override val keySpecification: MutableMap = mutableMapOf() @@ -33,6 +38,13 @@ class Secp256k1PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, S keySpecification[CurveKey().property] = Curve.SECP256K1.value } + /** + * Verifies the authenticity of a signature using a given message and signature. + * + * @param message The message to verify. + * @param signature The signature data to verify. + * @return A boolean value indicating whether the signature is valid or not. + */ override fun verify(message: ByteArray, signature: ByteArray): Boolean { val kmmPublicKey = KMMECSecp256k1PublicKey.secp256k1FromBytes(raw) return kmmPublicKey.verify( @@ -41,6 +53,12 @@ class Secp256k1PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, S ) } + /** + * Returns the PEM (Privacy-Enhanced Mail) representation of the public key. + * The key is encoded in base64 and wrapped with "BEGIN" and "END" markers. + * + * @return the PEM representation of the private key as a String + */ override fun getPem(): String { return PEMKey( keyType = PEMKeyType.EC_PUBLIC_KEY, @@ -48,6 +66,11 @@ class Secp256k1PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, S ).pemEncoded() } + /** + * Retrieves the JWK (JSON Web Key) representation of the public key. + * + * @return The JWK instance representing the private key. + */ override fun getJwk(): JWK { return JWK( kty = "OKP", @@ -57,6 +80,12 @@ class Secp256k1PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, S ) } + /** + * Retrieves the JWK (JSON Web Key) representation of the private key with the specified key identifier (kid). + * + * @param kid The key identifier to be associated with the JWK. + * @return The JWK object representing the private key. + */ override fun jwkWithKid(kid: String): JWK { return JWK( kty = "OKP", @@ -67,11 +96,30 @@ class Secp256k1PublicKey(nativeValue: ByteArray) : PublicKey(), VerifiableKey, S ) } + /** + * Represents the storable data of a key. + * + * @property storableData The byte array representing the storable data. + * @see StorableKey + */ override val storableData: ByteArray get() = raw + + /** + * This variable represents the restoration identifier for a key. + * It is a unique identifier used for restoring the key from storage. + * + * @property restorationIdentifier The restoration identifier for the key. + * @see StorableKey + */ override val restorationIdentifier: String get() = "secp256k1+pub" + /** + * Retrieves the encoded and compressed representation of the public key. + * + * @return The encoded and compressed public key as a ByteArray. + */ fun getEncodedCompressed(): ByteArray { return KMMECSecp256k1PublicKey(raw).getCompressed() } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519KeyPair.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519KeyPair.kt index 92f50d572..b1dbe9153 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519KeyPair.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519KeyPair.kt @@ -5,9 +5,21 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.KeyPair import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PrivateKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PublicKey +/** + * Represents a pair of X25519 private and public keys. + * + * @property privateKey The X25519 private key. + * @property publicKey The X25519 public key. + */ class X25519KeyPair(override var privateKey: PrivateKey, override var publicKey: PublicKey) : KeyPair() { companion object { + /** + * Generates a pair of X25519 private and public keys. + * + * @return The generated X25519 key pair. + */ + @JvmStatic fun generateKeyPair(): X25519KeyPair { val pair = KMMX25519KeyPair.generateKeyPair() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519PrivateKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519PrivateKey.kt index 32af0c0a9..885eb7d57 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519PrivateKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519PrivateKey.kt @@ -13,6 +13,11 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PrivateKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PublicKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.StorableKey +/** + * Represents a private key for the X25519 elliptic curve. + * + * @param nativeValue The raw private key value in byte array format. + */ class X25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), StorableKey, ExportableKey { override val type: KeyTypes = KeyTypes.EC override val keySpecification: MutableMap = mutableMapOf() @@ -24,11 +29,21 @@ class X25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), StorableKey, Expo keySpecification[CurveKey().property] = Curve.X25519.value } + /** + * Returns the public key corresponding to this private key. + * @return the public key as a PublicKey object + */ override fun publicKey(): PublicKey { val private = KMMX25519PrivateKey(raw) return X25519PublicKey(private.publicKey().raw) } + /** + * Returns the PEM (Privacy-Enhanced Mail) representation of the private key. + * The key is encoded in base64 and wrapped with "BEGIN" and "END" markers. + * + * @return the PEM representation of the private key as a String + */ override fun getPem(): String { return PEMKey( keyType = PEMKeyType.EC_PRIVATE_KEY, @@ -36,6 +51,11 @@ class X25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), StorableKey, Expo ).pemEncoded() } + /** + * Retrieves the JWK (JSON Web Key) representation of the private key. + * + * @return The JWK instance representing the private key. + */ override fun getJwk(): JWK { return JWK( kty = "OKP", @@ -44,6 +64,12 @@ class X25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), StorableKey, Expo ) } + /** + * Retrieves the JWK (JSON Web Key) representation of the private key with the specified key identifier (kid). + * + * @param kid The key identifier to be associated with the JWK. + * @return The JWK object representing the private key. + */ override fun jwkWithKid(kid: String): JWK { return JWK( kty = "OKP", @@ -53,8 +79,22 @@ class X25519PrivateKey(nativeValue: ByteArray) : PrivateKey(), StorableKey, Expo ) } + /** + * Represents the storable data of a key. + * + * @property storableData The byte array representing the storable data. + * @see StorableKey + */ override val storableData: ByteArray get() = raw + + /** + * This variable represents the restoration identifier for a key. + * It is a unique identifier used for restoring the key from storage. + * + * @property restorationIdentifier The restoration identifier for the key. + * @see StorableKey + */ override val restorationIdentifier: String get() = "x25519+priv" } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519PublicKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519PublicKey.kt index 789d8c581..8603e0f9f 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519PublicKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/X25519PublicKey.kt @@ -11,6 +11,11 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PEMKeyType import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PublicKey import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.StorableKey +/** + * Class representing a public key for the X25519 curve. + * + * @param nativeValue The raw byte array representing the public key + */ class X25519PublicKey(nativeValue: ByteArray) : PublicKey(), ExportableKey, StorableKey { override val type: KeyTypes = KeyTypes.EC override val keySpecification: MutableMap = mutableMapOf() @@ -22,6 +27,12 @@ class X25519PublicKey(nativeValue: ByteArray) : PublicKey(), ExportableKey, Stor keySpecification[CurveKey().property] = Curve.X25519.value } + /** + * Returns the PEM (Privacy-Enhanced Mail) representation of the public key. + * The key is encoded in base64 and wrapped with "BEGIN" and "END" markers. + * + * @return the PEM representation of the private key as a String + */ override fun getPem(): String { return PEMKey( keyType = PEMKeyType.EC_PUBLIC_KEY, @@ -29,6 +40,11 @@ class X25519PublicKey(nativeValue: ByteArray) : PublicKey(), ExportableKey, Stor ).pemEncoded() } + /** + * Retrieves the JWK (JSON Web Key) representation of the public key. + * + * @return The JWK instance representing the private key. + */ override fun getJwk(): JWK { return JWK( kty = "OKP", @@ -37,6 +53,12 @@ class X25519PublicKey(nativeValue: ByteArray) : PublicKey(), ExportableKey, Stor ) } + /** + * Retrieves the JWK (JSON Web Key) representation of the private key with the specified key identifier (kid). + * + * @param kid The key identifier to be associated with the JWK. + * @return The JWK object representing the private key. + */ override fun jwkWithKid(kid: String): JWK { return JWK( kty = "OKP", @@ -46,8 +68,22 @@ class X25519PublicKey(nativeValue: ByteArray) : PublicKey(), ExportableKey, Stor ) } + /** + * Represents the storable data of a key. + * + * @property storableData The byte array representing the storable data. + * @see StorableKey + */ override val storableData: ByteArray get() = raw + + /** + * This variable represents the restoration identifier for a key. + * It is a unique identifier used for restoring the key from storage. + * + * @property restorationIdentifier The restoration identifier for the key. + * @see StorableKey + */ override val restorationIdentifier: String get() = "x25519+pub" } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/ec/KMMECCoordinate.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/ec/KMMECCoordinate.kt index 385f8a666..bbd25e1a8 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/ec/KMMECCoordinate.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/ec/KMMECCoordinate.kt @@ -3,11 +3,23 @@ package io.iohk.atala.prism.walletsdk.apollo.utils.ec import com.ionspin.kotlin.bignum.integer.BigInteger import io.iohk.atala.prism.walletsdk.apollo.helpers.padStart +/** + * Represents a coordinate in the elliptic curve cryptography (ECC) system. + * + * @property coordinate The coordinate value represented as a BigInteger. + */ class KMMECCoordinate(val coordinate: BigInteger) { + /** + * Returns a ByteArray representation of the coordinate. + * The returned ByteArray will be padded with zeroes at the beginning if necessary + * to match the specified length. + * + * @return The ByteArray representation of the coordinate. + */ fun bytes(): ByteArray = coordinate.toByteArray().padStart(PRIVATE_KEY_BYTE_SIZE, 0) companion object { - internal val PRIVATE_KEY_BYTE_SIZE: Int = 32 + internal const val PRIVATE_KEY_BYTE_SIZE: Int = 32 } } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/ec/KMMECPoint.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/ec/KMMECPoint.kt index c0cb2a251..c5630ab42 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/ec/KMMECPoint.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/apollo/utils/ec/KMMECPoint.kt @@ -2,12 +2,34 @@ package io.iohk.atala.prism.walletsdk.apollo.utils.ec import com.ionspin.kotlin.bignum.integer.BigInteger +/** + * Represents a point in the elliptic curve cryptography (ECC) system. + * + * @property x The x-coordinate of the point. + * @property y The y-coordinate of the point. + */ class KMMECPoint(val x: KMMECCoordinate, val y: KMMECCoordinate) { + /** + * Represents a point in the elliptic curve cryptography (ECC) system. + * + * @property x The x-coordinate of the point. + * @property y The y-coordinate of the point. + */ constructor(x: String, y: String) : this( KMMECCoordinate(BigInteger.parseString(x)), KMMECCoordinate(BigInteger.parseString(y)) ) + /** + * Represents a point in the elliptic curve cryptography (ECC) system. + * + * @property x The x-coordinate of the point. + * @property y The y-coordinate of the point. + * + * @constructor Creates a new instance of KMMECPoint with the provided x and y coordinates. + * @param x The x-coordinate as a BigInteger. + * @param y The y-coordinate as a BigInteger. + */ constructor(x: BigInteger, y: BigInteger) : this( KMMECCoordinate(x), KMMECCoordinate(y) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/CastorImpl.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/CastorImpl.kt index 989c66ec3..c5e26d5c2 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/CastorImpl.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/CastorImpl.kt @@ -28,17 +28,11 @@ import kotlin.jvm.Throws * or a more traditional system requiring secure and private identity management, Castor provides the tools and features * you need to easily create, manage, and resolve DIDs. */ -class CastorImpl(apollo: Apollo, private val logger: PrismLogger = PrismLoggerImpl(LogComponent.CASTOR)) : Castor { - val apollo: Apollo - var resolvers: Array - - init { - this.apollo = apollo - this.resolvers = arrayOf( - PeerDIDResolver(), - LongFormPrismDIDResolver(this.apollo) - ) - } +class CastorImpl(val apollo: Apollo, private val logger: PrismLogger = PrismLoggerImpl(LogComponent.CASTOR)) : Castor { + var resolvers: Array = arrayOf( + PeerDIDResolver(), + LongFormPrismDIDResolver(this.apollo) + ) /** * Parses a string representation of a Decentralized Identifier (DID) into a DID object. @@ -127,7 +121,7 @@ class CastorImpl(apollo: Apollo, private val logger: PrismLogger = PrismLoggerIm CastorShared.getKeyPairFromCoreProperties(document.coreProperties) if (keyPairs.isEmpty()) { - throw CastorError.InvalidKeyError() + throw CastorError.InvalidKeyError("KeyPairs is empty") } for (keyPair in keyPairs) { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/DIDParser.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/DIDParser.kt index 9492abaac..b3e818e77 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/DIDParser.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/DIDParser.kt @@ -4,8 +4,18 @@ import io.iohk.atala.prism.walletsdk.domain.models.CastorError import io.iohk.atala.prism.walletsdk.domain.models.DID import kotlin.jvm.Throws +/** + * The DIDParser class provides methods for parsing a string representation of a Decentralized Identifier (DID) into a DID object. + */ object DIDParser { + /** + * Parses a string representation of a Decentralized Identifier (DID) into a DID object. + * + * @param didString The string representation of the DID. + * @return The [DID] object. + * @throws [CastorError.InvalidDIDString] if the string is not a valid DID. + */ @Throws(CastorError.InvalidDIDString::class) fun parse(didString: String): DID { val regex = diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/DIDUrlParser.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/DIDUrlParser.kt index 62e6167ee..8ed8a7fa1 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/DIDUrlParser.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/DIDUrlParser.kt @@ -4,7 +4,17 @@ import io.iohk.atala.prism.walletsdk.domain.models.CastorError import io.iohk.atala.prism.walletsdk.domain.models.DID import io.iohk.atala.prism.walletsdk.domain.models.DIDUrl +/** + * Class responsible for parsing a DID URL string and returning a parsed [DIDUrl] object. + */ object DIDUrlParser { + /** + * Parses a DID URL string and returns a `DIDUrl` object. + * + * @param didUrlString The input DID URL string to parse. + * @return A `DIDUrl` object representing the parsed DID URL. + * @throws CastorError.InvalidDIDString if the input DID string does not match the expected structure. + */ @Throws(CastorError.InvalidDIDString::class) fun parse(didUrlString: String): DIDUrl { val regex = @@ -26,7 +36,7 @@ object DIDUrlParser { query.removePrefix("?").split("&") .associate { val (key, value) = it.split("=") - key to (value ?: "") + key to value } } else { mapOf() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/LongFormPrismDID.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/LongFormPrismDID.kt index c3c0d5ae6..740f66106 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/LongFormPrismDID.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/LongFormPrismDID.kt @@ -4,6 +4,15 @@ import io.iohk.atala.prism.walletsdk.domain.models.CastorError import io.iohk.atala.prism.walletsdk.domain.models.DID import kotlin.jvm.Throws +/** + * Represents a LongFormPrismDID. + * + * @property did The DID associated with the LongFormPrismDID. + * @property prismMethodId The PrismDIDMethodId instance associated with the LongFormPrismDID. + * @property stateHash The state hash of the LongFormPrismDID. + * @property encodedState The encoded state of the LongFormPrismDID. + * @throws CastorError.InvalidLongFormDID if the methodId of the DID does not have 2 sections. + */ data class LongFormPrismDID @Throws(CastorError.InvalidLongFormDID::class) constructor(val did: DID) { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/PrismDIDMethodId.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/PrismDIDMethodId.kt index 1bdb7a317..f6b24195b 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/PrismDIDMethodId.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/PrismDIDMethodId.kt @@ -4,10 +4,20 @@ import io.iohk.atala.prism.walletsdk.castor.DID_SEPARATOR import io.iohk.atala.prism.walletsdk.domain.models.CastorError import kotlin.jvm.Throws +/** + * Represents a Prism DID Method ID. + * + * @property value The string value of the Prism DID Method ID. + */ data class PrismDIDMethodId(private val value: String) { val sections: List get() = value.split(DID_SEPARATOR).map { it } + /** + * Represents a Prism DID Method ID. + * + * @property value The string value of the Prism DID Method ID. + */ @Throws(CastorError.MethodIdIsDoesNotSatisfyRegex::class) constructor(sections: List) : this(sections.joinToString(DID_SEPARATOR)) { val sectionRegex = Regex("^[A-Za-z0-9_-]+$") @@ -20,6 +30,11 @@ data class PrismDIDMethodId(private val value: String) { } } + /** + * Returns a string representation of the Prism DID Method ID. + * + * @return The string representation of the Prism DID Method ID. + */ override fun toString(): String { return value } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/PrismDIDPublicKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/PrismDIDPublicKey.kt index bc6c4ec92..d7c85f93e 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/PrismDIDPublicKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/did/prismdid/PrismDIDPublicKey.kt @@ -11,12 +11,28 @@ import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PublicKey import pbandk.ByteArr import kotlin.jvm.Throws +/** + * Represents a public key for the Atala PRISM system. + * + * @property apollo The instance of [Apollo] used for cryptographic operations. + * @property id The ID of the public key. + * @property usage The intended usage of the public key. + * @property keyData The actual public key data. + */ class PrismDIDPublicKey { private val apollo: Apollo val id: String val usage: Usage val keyData: PublicKey + /** + * Represents a PrismDIDPublicKey. + * + * @param apollo The cryptography suite representation. + * @param id The ID of the public key. + * @param usage The usage of the public key. + * @param keyData The actual public key data. + */ constructor(apollo: Apollo, id: String, usage: Usage, keyData: PublicKey) { this.apollo = apollo this.id = id @@ -24,6 +40,13 @@ class PrismDIDPublicKey { this.keyData = keyData } + /** + * Constructs a PrismDIDPublicKey object. + * + * @param apollo The Apollo object used for cryptographic operations in the Atala PRISM. + * @param proto The protobuf representation of the public key. + * @throws CastorError.InvalidPublicKeyEncoding if the encoding of the key is invalid. + */ @Throws(CastorError.InvalidPublicKeyEncoding::class) constructor(apollo: Apollo, proto: io.iohk.atala.prism.protos.PublicKey) { this.apollo = apollo @@ -40,6 +63,11 @@ class PrismDIDPublicKey { } } + /** + * Converts the PublicKey object to a Protobuf PublicKey object. + * + * @return the converted Protobuf PublicKey object + */ fun toProto(): io.iohk.atala.prism.protos.PublicKey { val compressedPublicKey = Secp256k1PublicKey(Secp256k1Lib().compressPublicKey(keyData.getValue())) return io.iohk.atala.prism.protos.PublicKey( @@ -51,6 +79,12 @@ class PrismDIDPublicKey { ) } + /** + * Enumeration representing the possible usages of a public key. + * + * @property value The string representation of the usage. + * @constructor Creates an instance of the Usage enum with the given value. + */ enum class Usage(val value: String) { MASTER_KEY("masterKey"), ISSUING_KEY("issuingKey"), @@ -63,6 +97,11 @@ class PrismDIDPublicKey { } } +/** + * Converts a `KeyUsage` object to a `PrismDIDPublicKey.Usage` object. + * + * @return The corresponding `PrismDIDPublicKey.Usage` object. + */ fun KeyUsage.fromProto(): PrismDIDPublicKey.Usage { return when (this) { is KeyUsage.MASTER_KEY -> PrismDIDPublicKey.Usage.MASTER_KEY @@ -77,6 +116,11 @@ fun KeyUsage.fromProto(): PrismDIDPublicKey.Usage { } } +/** + * Converts a Secp256k1PublicKey object to a CompressedECKeyData object. + * + * @return the converted CompressedECKeyData object. + */ fun Secp256k1PublicKey.toProto(): CompressedECKeyData { return CompressedECKeyData( curve = Curve.SECP256K1.value, @@ -84,6 +128,12 @@ fun Secp256k1PublicKey.toProto(): CompressedECKeyData { ) } +/** + * Generates the identifier for a PrismDIDPublicKey.Usage based on the given index. + * + * @param index The index used to generate the identifier. + * @return The generated identifier. + */ fun PrismDIDPublicKey.Usage.id(index: Int): String { return when (this) { PrismDIDPublicKey.Usage.MASTER_KEY -> "master$index" @@ -97,6 +147,11 @@ fun PrismDIDPublicKey.Usage.id(index: Int): String { } } +/** + * Converts the Usage value of a PrismDIDPublicKey to the corresponding KeyUsage enum value. + * + * @return The KeyUsage enum value corresponding to the Usage value of the PrismDIDPublicKey. + */ fun PrismDIDPublicKey.Usage.toProto(): KeyUsage { return when (this) { PrismDIDPublicKey.Usage.MASTER_KEY -> KeyUsage.MASTER_KEY @@ -110,6 +165,12 @@ fun PrismDIDPublicKey.Usage.toProto(): KeyUsage { } } +/** + * Returns the default ID for the current usage of the PrismDIDPublicKey. + * This method generates an ID based on the usage enum value. + * + * @return The default ID for the current usage. + */ fun PrismDIDPublicKey.Usage.defaultId(): String { return this.id(0) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/resolvers/LongFormPrismDIDResolver.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/resolvers/LongFormPrismDIDResolver.kt index 7e71cbb43..6622478d8 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/resolvers/LongFormPrismDIDResolver.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/resolvers/LongFormPrismDIDResolver.kt @@ -6,11 +6,25 @@ import io.iohk.atala.prism.walletsdk.domain.buildingblocks.Apollo import io.iohk.atala.prism.walletsdk.domain.models.DIDDocument import io.iohk.atala.prism.walletsdk.domain.models.DIDResolver +/** + * The LongFormPrismDIDResolver class is an implementation of the DIDResolver interface + * for resolving DID document using the LongForm PRISM method. + * + * @param apollo The Apollo instance used for cryptographic operations. + * + * @see Apollo + */ class LongFormPrismDIDResolver( private val apollo: Apollo ) : DIDResolver { override val method: String = PRISM + /** + * Resolves a DID document using the LongForm PRISM method. + * + * @param didString The string representation of the DID. + * @return The resolved DID document. + */ override suspend fun resolve(didString: String): DIDDocument { return CastorShared.resolveLongFormPrismDID( apollo = apollo, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/resolvers/PeerDIDResolver.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/resolvers/PeerDIDResolver.kt index cb6aa8d7c..4c9f7f7ed 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/resolvers/PeerDIDResolver.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/resolvers/PeerDIDResolver.kt @@ -5,8 +5,20 @@ import io.iohk.atala.prism.walletsdk.castor.shared.CastorShared import io.iohk.atala.prism.walletsdk.domain.models.DIDDocument import io.iohk.atala.prism.walletsdk.domain.models.DIDResolver +/** + * The [PeerDIDResolver] class is an implementation of the [DIDResolver] interface for resolving DID document using the Peer DID method. + * + * @see DIDResolver + */ class PeerDIDResolver : DIDResolver { override val method: String = PEER + + /** + * Resolves a DID document using the Peer DID method. + * + * @param didString the string representation of the DID + * @return the resolved DID document + */ override suspend fun resolve(didString: String): DIDDocument { return CastorShared.resolvePeerDID(didString) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/shared/CastorShared.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/shared/CastorShared.kt index da4af1b09..62ffc2b01 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/shared/CastorShared.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/castor/shared/CastorShared.kt @@ -56,9 +56,18 @@ import pbandk.encodeToByteArray import kotlin.jvm.Throws import io.iohk.atala.prism.didcomm.didpeer.resolvePeerDID as mercuryPeerDIDResolve +/** + * The `CastorShared` class provides a set of logging methods for the Castor module. + */ internal class CastorShared { companion object { + /** + * The logger property is a PrismLoggerImpl instance for logging purposes. + * It is used to log debug, info, warning, and error messages, along with the associated metadata. + * + * @property logger The logger instance. + */ private val logger = PrismLoggerImpl(LogComponent.CASTOR) /** @@ -150,11 +159,12 @@ internal class CastorShared { val peerDIDDocument = try { DIDDocPeerDID.fromJson(mercuryPeerDIDResolve(didString)) } catch (e: MalformedPeerDIDException) { - throw CastorError.InvalidPeerDIDError() + throw CastorError.InvalidPeerDIDError(e.message, e.cause) } catch (e: Throwable) { throw CastorError.NotPossibleToResolveDID( did = didString, - reason = "Method or method id are invalid" + reason = "Method or method id are invalid", + e ) } @@ -465,6 +475,7 @@ internal class CastorShared { * @param keyPair keyPair to be used in creating [OctetPublicKey]. * @return [OctetPublicKey]. */ + @JvmStatic private fun octetPublicKey(keyPair: KeyPair): OctetPublicKey { val curve = when (keyPair::class) { Secp256k1KeyPair::class -> { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Apollo.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Apollo.kt index 7ef9d8294..a969e69e8 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Apollo.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Apollo.kt @@ -39,5 +39,15 @@ interface Apollo : KeyRestoration { */ fun createRandomSeed(passphrase: String? = ""): SeedWords + /** + * Creates a private key using the provided properties. + * + * @param properties A map containing the properties of the private key. + * The supported properties are: + * - "type": The type of the private key. Use KeyTypes.EC for elliptic curve keys. + * - "seed": The seed used for key generation. Must be a byte array. + * - "curve": The key curve. Use Curve.SECP256K1 for secp256k1 curve. + * @return A PrivateKey object representing the created private key. + */ fun createPrivateKey(properties: Map): PrivateKey } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Pluto.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Pluto.kt index f2390755f..f69f56e18 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Pluto.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Pluto.kt @@ -14,8 +14,19 @@ import io.iohk.atala.prism.walletsdk.pollux.models.CredentialRequestMeta import ioiohkatalaprismwalletsdkpluto.data.AvailableClaims import kotlinx.coroutines.flow.Flow +/** + * The `Pluto` interface defines the contract for storing and retrieving various data related to Atala PRISM architecture. + */ interface Pluto { + /** + * Stores the Prism DID, key path index, alias, and private keys. + * + * @param did The Prism DID to store. + * @param keyPathIndex The key path index. + * @param alias The optional alias for the Prism DID. + * @param privateKeys The list of private keys to store. + */ fun storePrismDIDAndPrivateKeys( did: DID, keyPathIndex: Int, @@ -23,80 +34,297 @@ interface Pluto { privateKeys: List ) + /** + * Stores the PeerDID in the system. + * + * @param did The PeerDID to store. + */ fun storePeerDID(did: DID) + /** + * Stores a pair of Distributed Identifier (DID) and a receiver DID with a given name. + * + * @param host The host DID to store. + * @param receiver The receiver DID to store. + * @param name The name of the stored pair. + */ fun storeDIDPair(host: DID, receiver: DID, name: String) + /** + * Stores a message in the system. + * + * @param message The message to store. + */ fun storeMessage(message: Message) + /** + * Stores a list of messages in the system. + * + * @param messages The list of messages to store. + */ fun storeMessages(messages: List) + /** + * Stores the private key along with additional information. + * + * @param privateKey The private key to store. Must implement the [StorableKey] interface. + * @param did The DID associated with the private key. + * @param keyPathIndex The key path index. + * @param metaId The optional metadata ID. + */ fun storePrivateKeys(privateKey: StorableKey, did: DID, keyPathIndex: Int, metaId: String? = null) + /** + * Stores a mediator in the system. + * + * @param mediator The mediator DID to store. + * @param host The host DID associated with the mediator. + * @param routing The routing DID for the mediator. + */ fun storeMediator(mediator: DID, host: DID, routing: DID) + /** + * Stores a credential in the system. + * + * @param credential The credential to store. It must implement the [StorableCredential] interface. + */ fun storeCredential(credential: StorableCredential) + /** + * Stores a link secret in the system. + * + * @param linkSecret The link secret to store. + */ fun storeLinkSecret(linkSecret: String) + /** + * Stores the metadata associated with a credential request. + * + * @param metadata The metadata to store. It must be an instance of [CredentialRequestMeta]. + */ fun storeCredentialMetadata(metadata: CredentialRequestMeta) + /** + * Retrieves all PrismDIDs and their associated information. + * + * @return A flow of lists of [PrismDIDInfo] objects representing the PrismDIDs and their information. + */ fun getAllPrismDIDs(): Flow> + /** + * Retrieves the [PrismDIDInfo] associated with a given [DID]. + * + * @param did The [DID] for which to retrieve the [PrismDIDInfo]. + * @return A [Flow] that emits a nullable [PrismDIDInfo] object representing the [PrismDIDInfo] associated + * with the specified [DID]. If no [PrismDIDInfo] is found, null is emitted. + */ fun getDIDInfoByDID(did: DID): Flow + /** + * Retrieves the [PrismDIDInfo] objects associated with a given alias. + * + * @param alias The alias for which to retrieve the [PrismDIDInfo] objects. + * @return A [Flow] that emits a list of [PrismDIDInfo] objects representing the + * [PrismDIDInfo] associated with the specified alias. + */ fun getDIDInfoByAlias(alias: String): Flow> + /** + * Retrieves the key path index associated with a given Prism DID. + * + * @param did The Prism DID for which to retrieve the key path index. + * @return A [Flow] that emits a nullable [Int] representing the key path index associated with the specified Prism DID. + * If no key path index is found, null is emitted. + */ fun getPrismDIDKeyPathIndex(did: DID): Flow + /** + * Retrieves the last key path index associated with the Prism DID. + * + * @return A [Flow] that emits an [Int] representing the last key path index associated with the Prism DID. + */ fun getPrismLastKeyPathIndex(): Flow + /** + * Retrieves all PeerDIDs. + * + * @return A flow of lists of PeerDIDs. + */ fun getAllPeerDIDs(): Flow> + /** + * Retrieves a list of private keys associated with a given DID. + * + * @param did The DID for which to retrieve private keys. + * @return A flow that emits a list of nullable [PrivateKey] objects. In case a private key is not found, null is emitted. + */ fun getDIDPrivateKeysByDID(did: DID): Flow> + /** + * Retrieves the private key associated with a given ID. + * + * @param id The ID of the private key. + * @return A [Flow] that emits the private key as a nullable [PrivateKey] object. If no private key is found, + * null is emitted. + */ fun getDIDPrivateKeyByID(id: String): Flow + /** + * Retrieves all the pairs of DIDs stored in the system. + * + * @return a [Flow] emitting a list of [DIDPair] objects representing the pairs of DIDs. + */ fun getAllDidPairs(): Flow> + /** + * Retrieves a DIDPair object using the provided DID. + * + * @param did The DID to search for. + * @return A Flow of DIDPair objects. If a match is found, the flow emits the matching DIDPair. + * If no match is found, the flow emits null. + */ fun getPairByDID(did: DID): Flow + /** + * Retrieve a [DIDPair] from a flow by its name. + * + * @param name The name of the [DIDPair] to retrieve. + * @return A [Flow] emitting the [DIDPair] object that matches the given name, + * or `null` if no matching [DIDPair] is found. + */ fun getPairByName(name: String): Flow - // @JsName("getAllMessages") + /** + * Retrieves all the messages. + * + * @return a Flow of List of Message objects representing all the messages. + */ fun getAllMessages(): Flow> - // @JsName("getAllMessagesByDID") + /** + * Retrieves all messages based on the provided DID. + * + * @param did The DID (Direct Inward Dialing) to filter messages by. + * @return A flow of list of messages. + */ fun getAllMessages(did: DID): Flow> + /** + * Retrieves all the messages that have been sent. + * + * @return A [Flow] of type [List] containing the sent messages. + */ fun getAllMessagesSent(): Flow> + /** + * Retrieves all messages received by the user. + * + * @return A [Flow] emitting a list of [Message] objects representing all the messages received. + */ fun getAllMessagesReceived(): Flow> + /** + * Retrieves all messages sent to the specified DID. + * + * @param did the destination DID to filter the messages by + * @return a [Flow] of [List] of [Message] objects containing all the messages sent to the specified DID + */ fun getAllMessagesSentTo(did: DID): Flow> + /** + * Returns a Flow of lists of all messages received from the specified DID. + * + * @param did the DID (Decentralized Identifier) to get the received messages from + * @return a Flow of lists of messages received from the specified DID + */ fun getAllMessagesReceivedFrom(did: DID): Flow> + /** + * Retrieves all messages of a specific type that are related to a given DID. + * + * @param type The type of the messages to retrieve. + * @param relatedWithDID The optional DID to which the messages are related. + * @return A [Flow] emitting a list of [Message] objects that match the given type and are related to the specified DID. + */ fun getAllMessagesOfType(type: String, relatedWithDID: DID?): Flow> - // @JsName("getAllMessagesByFromToDID") + /** + * Retrieves all messages exchanged between the specified 'from' and 'to' DIDs. + * + * @param from the sender DID + * @param to the receiver DID + * @return a Flow emitting a list of messages exchanged between the 'from' and 'to' DIDs + */ fun getAllMessages(from: DID, to: DID): Flow> + /** + * Retrieves the message with the specified ID. + * + * @param id The unique ID of the message. + * @return A [Flow] that emits the message with the specified ID, or null if no such message exists. + * The [Flow] completes when the message is successfully retrieved, or when an error occurs. + */ fun getMessage(id: String): Flow + /** + * Returns a Flow of lists of [Mediator] objects representing all the available mediators. + * + * @return a Flow of lists of [Mediator] objects. + */ fun getAllMediators(): Flow> + /** + * Retrieves all credentials for credential recovery. + * + * @return A flow of a list of [CredentialRecovery] objects representing the credentials for recovery. + */ fun getAllCredentials(): Flow> + /** + * Inserts an available claim for a specific credential. + * + * @param credentialId The ID of the credential. + * @param claim The claim to insert. + */ fun insertAvailableClaim(credentialId: String, claim: String) + /** + * Inserts the available claims for a given credential ID. + * + * @param credentialId the ID of the credential + * @param claims an array of available claims to be inserted + */ fun insertAvailableClaims(credentialId: String, claims: Array) + /** + * Retrieves the available claims for a given credential ID. + * + * @param credentialId The ID of the credential. + * @return A flow that emits an array of AvailableClaims. + */ fun getAvailableClaimsByCredentialId(credentialId: String): Flow> + /** + * Retrieves the available claims for a given claim. + * + * @param claim The claim for which the available claims are to be retrieved. + * @return A flow of arrays of AvailableClaims representing the available claims for the given claim. + */ fun getAvailableClaimsByClaim(claim: String): Flow> + /** + * Retrieves the secret link associated with the current instance. + * + * @return A [Flow] emitting the secret link as a nullable [String]. + */ fun getLinkSecret(): Flow + /** + * Retrieves the metadata associated with a credential request. + * + * @param linkSecretName The name of the link secret used for the credential request. + * @return A [Flow] emitting the [CredentialRequestMeta] object for the specified link secret name, + * or null if no metadata is found. + */ fun getCredentialMetadata(linkSecretName: String): Flow } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Pollux.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Pollux.kt index 35a19dcc7..09cb401f9 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Pollux.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/buildingblocks/Pollux.kt @@ -13,20 +13,50 @@ import io.iohk.atala.prism.walletsdk.domain.models.StorableCredential import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PrivateKey import kotlinx.serialization.json.JsonObject +/** + * The `Pollux` interface represents a set of operations for working with verifiable credentials. + */ interface Pollux { + + /** + * Parses the given JSON data into a verifiable credential of the specified type. + * + * @param jsonData The JSON data representing the verifiable credential. + * @param type The type of the verifiable credential. + * @param linkSecret The optional link secret for the credential. + * @param credentialMetadata The metadata for the credential request. + * @return The parsed credential. + */ suspend fun parseCredential( - data: String, + jsonData: String, type: CredentialType, linkSecret: LinkSecret? = null, credentialMetadata: CredentialRequestMetadata? ): Credential + /** + * Processes the JWT credential request and returns a string representation of the processed result. + * + * @param subjectDID The DID of the subject for whom the request is being processed. + * @param privateKey The private key used for signing the JWT. + * @param offerJson The JSON object representing the credential offer. + * @return The string representation of the processed result. + */ fun processCredentialRequestJWT( subjectDID: DID, privateKey: PrivateKey, offerJson: JsonObject ): String + /** + * Processes a credential request for anonymous credentials. + * + * @param did The DID of the subject requesting the credential. + * @param offer The credential offer. + * @param linkSecret The link secret for the credential. + * @param linkSecretName The name of the link secret. + * @return A pair containing the credential request and its metadata. + */ suspend fun processCredentialRequestAnoncreds( did: DID, offer: CredentialOffer, @@ -34,6 +64,15 @@ interface Pollux { linkSecretName: String ): Pair + /** + * Creates a verifiable presentation JSON Web Token (JWT) for the given subjectDID, privateKey, credential, and requestPresentationJson. + * + * @param subjectDID The DID of the subject for whom the presentation is being created. + * @param privateKey The private key used to sign the JWT. + * @param credential The credential to be included in the presentation. + * @param requestPresentationJson The JSON object representing the request presentation. + * @return The created verifiable presentation JWT. + */ fun createVerifiablePresentationJWT( subjectDID: DID, privateKey: PrivateKey, @@ -41,11 +80,37 @@ interface Pollux { requestPresentationJson: JsonObject ): String + /** + * Restores a credential using the provided restoration identifier and credential data. + * + * @param restorationIdentifier The restoration identifier of the credential. + * @param credentialData The byte array containing the credential data. + * @return The restored credential. + */ fun restoreCredential(restorationIdentifier: String, credentialData: ByteArray): Credential + /** + * Converts a [Credential] object to a [StorableCredential] object of the specified [CredentialType]. + * + * @param type The type of the [StorableCredential]. + * @param credential The [Credential] object to be converted. + * @return The converted [StorableCredential]. + */ fun credentialToStorableCredential(type: CredentialType, credential: Credential): StorableCredential + /** + * Extracts the credential format from the given array of attachment descriptors. + * + * @param formats The array of attachment descriptors. + * @return The credential format as a CredentialType enum value. + */ fun extractCredentialFormatFromMessage(formats: Array): CredentialType + /** + * Retrieves the credential definition for the specified ID. + * + * @param id The ID of the credential definition. + * @return The credential definition. + */ suspend fun getCredentialDefinition(id: String): CredentialDefinition } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Api.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Api.kt index 893f35b06..7dbb1c56c 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Api.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Api.kt @@ -8,6 +8,17 @@ import io.ktor.client.HttpClient as KtorClient */ interface Api { var client: KtorClient + + /** + * Makes an HTTP request using the specified HTTP method, URL, URL parameters, HTTP headers, and request body. + * + * @param httpMethod the HTTP method to be used for the request (e.g., "GET", "POST", "PUT", "DELETE", etc.) + * @param url the URL to send the request to + * @param urlParameters the array of URL parameters to be included in the request (default is an empty array) + * @param httpHeaders the array of HTTP headers to be included in the request (default is an empty array) + * @param body the request body to be sent with the request (default is null) + * @return the HttpResponse object representing the response received from the server + */ suspend fun request( httpMethod: String, url: String, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/ApiImpl.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/ApiImpl.kt index b8d471756..e5e5e9912 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/ApiImpl.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/ApiImpl.kt @@ -12,6 +12,17 @@ import io.ktor.http.Url * Implementation of API interface for http requests. */ open class ApiImpl(override var client: HttpClient) : Api { + + /** + * Makes an HTTP request using the specified HTTP method, URL, URL parameters, HTTP headers, and request body. + * + * @param httpMethod the HTTP method to be used for the request (e.g., "GET", "POST", "PUT", "DELETE", etc.) + * @param url the URL to send the request to + * @param urlParameters the array of URL parameters to be included in the request (default is an empty array) + * @param httpHeaders the array of HTTP headers to be included in the request (default is an empty array) + * @param body the request body to be sent with the request (default is null) + * @return the HttpResponse object representing the response received from the server + */ override suspend fun request( httpMethod: String, url: String, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Claim.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Claim.kt index 53b175a65..e86b40760 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Claim.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Claim.kt @@ -2,19 +2,91 @@ package io.iohk.atala.prism.walletsdk.domain.models import kotlinx.serialization.Serializable +/** + * Represents a claim in a verifiable credential. + * + * @property key The key of the claim. + * @property value The value of the claim. + */ @Serializable class Claim( val key: String, val value: ClaimType ) +/** + * A sealed class representing different types of claims. + */ @Serializable sealed class ClaimType : Comparable { + /** + * A data class representing a string value. + * + * @property value The string value. + */ data class StringValue(val value: String) : ClaimType() + + /** + * Represents a boolean value as a claim type. + * + * @property value The boolean value. + */ data class BoolValue(val value: Boolean) : ClaimType() - data class DataValue(val value: ByteArray) : ClaimType() + + /** + * Represents a data value with a byte array. + * + * @property value the byte array value of the data + * @constructor Creates a [DataValue] instance with the specified byte array value. + */ + data class DataValue(val value: ByteArray) : ClaimType() { + + /** + * Compares this [DataValue] object with the specified object for equality. Returns `true` if the objects are the same, + * have the same runtime class, and their values are equal. + * + * @param other the object to compare for equality + * @return `true` if the objects are the same, have the same runtime class, and their values are equal, `false` otherwise + */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as DataValue + + return value.contentEquals(other.value) + } + + /** + * Generates a hash code value for the [DataValue] object. + * + * The hash code value is calculated by invoking the [contentHashCode] method on the [value] property. + * + * @return the hash code value for the [DataValue] object + */ + override fun hashCode(): Int { + return value.contentHashCode() + } + } + + /** + * Represents a numeric value for a claim. + * + * @property value The numeric value. + * @constructor Creates a new NumberValue instance with the specified value. + */ data class NumberValue(val value: Double) : ClaimType() + /** + * Compares this [ClaimType] object with the specified [other] object for order. + * + * @param other the object to compare with + * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the + * specified object + * + * @throws IllegalArgumentException if [other] is not of the same type as this object + * @throws IllegalArgumentException if [this] and [other] are not comparable + */ override fun compareTo(other: ClaimType): Int { return when (this) { is StringValue -> { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Credential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Credential.kt index f52889d01..f833789d8 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Credential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Credential.kt @@ -1,5 +1,10 @@ package io.iohk.atala.prism.walletsdk.domain.models +/** + * Represents a verifiable credential that contains information about an entity or identity. + * + * Implementing classes are expected to provide implementation for all properties and functions defined in this interface. + */ interface Credential { val id: String val issuer: String diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/CredentialIssueOptions.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/CredentialIssueOptions.kt index 5b0099d32..5c706eaed 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/CredentialIssueOptions.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/CredentialIssueOptions.kt @@ -1,5 +1,11 @@ package io.iohk.atala.prism.walletsdk.domain.models +/** + * Represents the options for issuing credentials. + * + * @property type The type of verifiable credential to issue. + * @property linkSecret The optional link secret used for linking credentials to a specific issuer. + */ data class CredentialIssueOptions( val type: CredentialType, val linkSecret: String? = null diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DID.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DID.kt index be146093d..fc0193d23 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DID.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DID.kt @@ -19,32 +19,59 @@ data class DID @JvmOverloads constructor( val method: String, val methodId: String ) { - - // @JsName("fromString") + /** + * Constructor overload for creating a [DID] object based on a [String]. + * + * @param string The input [String] from which the [DID] object will be created. + * The [String] should have the format "schema:method:methodId". + */ constructor( string: String ) : this(getSchemaFromString(string), getMethodFromString(string), getMethodIdFromString(string)) + /** + * Returns a string representation of the DID object. + * + * @return The string representation of the DID in the format "schema:method:methodId". + */ override fun toString(): String { return "$schema:$method:$methodId" } companion object { + /** + * Extracts the schema from the given string representation of a DID. + * + * @param string The input string in the format "schema:method:methodId". + * @return The extracted schema from the input string. + */ @JvmStatic fun getSchemaFromString(string: String): String { val split = string.split(DID_SEPARATOR) return split[0] } + /** + * Retrieves the method component from a given string representation of a DID. + * + * @param string The input string in the format "schema:method:methodId". + * @return The extracted method component from the input string. + */ @JvmStatic fun getMethodFromString(string: String): String { val split = string.split(DID_SEPARATOR) return split[1] } + /** + * Retrieves the methodId component from a given string representation of a DID. + * + * @param string The input string in the format "schema:method:methodId". + * @return The extracted methodId component from the input string. + */ @JvmStatic fun getMethodIdFromString(string: String): String { - var split = string.split(DID_SEPARATOR).toMutableList() + val split = string.split(DID_SEPARATOR).toMutableList() split.removeFirst() split.removeFirst() return split.joinToString(DID_SEPARATOR) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DIDDocument.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DIDDocument.kt index a87052d85..a6807d137 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DIDDocument.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DIDDocument.kt @@ -27,6 +27,12 @@ data class DIDDocument( if (property is DIDDocument.Services) acc.plus(property.values) else acc } + /** + * Overrides the equals method to compare two instances of DIDDocument. + * + * @param other The object to compare with. + * @return true if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -39,6 +45,13 @@ data class DIDDocument( return true } + /** + * Calculates the hash code for the DIDDocument object. + * + * The hash code is calculated based on the id field and the content hash code of the coreProperties array. + * + * @return The hash code of the DIDDocument object. + */ override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + coreProperties.contentHashCode() @@ -60,6 +73,13 @@ data class DIDDocument( val publicKeyMultibase: String? = null ) { companion object { + /** + * Returns the Curve value based on the given type. + * + * @param type The type of the curve. + * @return The Curve object corresponding to the given type. + * @throws CastorError.InvalidKeyError if the given type is not supported. + */ @JvmStatic fun getCurveByType(type: String): Curve { return when (type) { @@ -94,6 +114,12 @@ data class DIDDocument( val type: Array, val serviceEndpoint: ServiceEndpoint ) : DIDDocumentCoreProperty { + /** + * Determines whether the current object is equal to another object. + * + * @param other The object to compare with the current object. + * @return true if the current object is equal to the other object, otherwise false. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -107,6 +133,12 @@ data class DIDDocument( return true } + /** + * Calculates the hash code for the Service object. + * The hash code is calculated based on the id, type, and serviceEndpoint properties. + * + * @return The hash code of the Service object. + */ override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + (type.contentHashCode()) @@ -124,6 +156,12 @@ data class DIDDocument( val accept: Array? = arrayOf(), val routingKeys: Array? = arrayOf() ) { + /** + * Determines whether the current object is equal to another object. + * + * @param other The object to compare with the current object. + * @return true if the current object is equal to the other object, otherwise false. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -143,6 +181,12 @@ data class DIDDocument( return true } + /** + * Calculates the hash code for the ServiceEndpoint object. + * The hash code is calculated based on the uri, accept, and routingKeys properties. + * + * @return The hash code of the ServiceEndpoint object. + */ override fun hashCode(): Int { var result = uri.hashCode() result = 31 * result + (accept?.contentHashCode() ?: 0) @@ -160,17 +204,33 @@ data class DIDDocument( data class AlsoKnownAs( val values: Array ) : DIDDocumentCoreProperty { + /** + * Checks if the current object is equal to the given object. + * + * The current object is considered equal to the given object if and only if: + * - They refer to the same instance + * - The given object is not null and belongs to the same class as the current object + * - The values of the `values` property of both objects are equal + * + * @param other The object to compare with the current object + * + * @return `true` if the objects are equal, `false` otherwise + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false other as AlsoKnownAs - if (!values.contentEquals(other.values)) return false - - return true + return values.contentEquals(other.values) } + /** + * Generates the hash code value for the current object. + * The hash code is computed based on the values of the `values` property. + * + * @return The hash code value for the object + */ override fun hashCode(): Int { return values.contentHashCode() } @@ -183,17 +243,26 @@ data class DIDDocument( * to update or deactivate the DID or subject or object. */ data class Controller(val values: Array) : DIDDocumentCoreProperty { + /** + * Compares this Controller object with the specified object for equality. + * + * @param other The object to compare for equality. + * @return true if the given object is equal to this Controller object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false other as Controller - if (!values.contentEquals(other.values)) return false - - return true + return values.contentEquals(other.values) } + /** + * Calculates the hash code for the Controller object. + * + * @return The hash code value for the Controller object. + */ override fun hashCode(): Int { return values.contentHashCode() } @@ -206,17 +275,33 @@ data class DIDDocument( * identity of the DID or subject or object. */ data class VerificationMethods(val values: Array) : DIDDocumentCoreProperty { + /** + * Compares this `VerificationMethods` object with the specified object for equality. + * + * The comparison is based on the `values` property of the `VerificationMethods` object. If the specified object is + * `null`, or is not an instance of `VerificationMethods`, or the `values` arrays are not equal, then the method + * returns `false`. Otherwise, it returns `true`. + * + * @param other The object to compare for equality. + * @return `true` if this `VerificationMethods` object is equal to the specified object, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false other as VerificationMethods - if (!values.contentEquals(other.values)) return false - - return true + return values.contentEquals(other.values) } + /** + * Calculates the hash code for the VerificationMethods object. + * + * This method calculates the hash code based on the content of the values array in the VerificationMethods object. + * If two VerificationMethods objects have the same values array, their hash codes will be equal. + * + * @return The hash code for the VerificationMethods object. + */ override fun hashCode(): Int { return values.contentHashCode() } @@ -229,17 +314,27 @@ data class DIDDocument( * associated DID or subject or object. */ data class Services(val values: Array) : DIDDocumentCoreProperty { + /** + * Determines whether the current object is equal to another object. + * + * @param other The object to compare with the current object. + * @return true if the current object is equal to the other object, otherwise false. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false other as Services - if (!values.contentEquals(other.values)) return false - - return true + return values.contentEquals(other.values) } + /** + * Calculates the hash code for the Services object. + * The hash code is calculated based on the content of the values array property. + * + * @return The hash code of the Services object. + */ override fun hashCode(): Int { return values.contentHashCode() } @@ -255,6 +350,12 @@ data class DIDDocument( val urls: Array, val verificationMethods: Array ) : DIDDocumentCoreProperty { + /** + * Checks if the current instance of [Authentication] is equal to the provided [other] object. + * + * @param other The object to compare with. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -267,6 +368,9 @@ data class DIDDocument( return true } + /** + * + */ override fun hashCode(): Int { var result = urls.contentHashCode() result = 31 * result + verificationMethods.contentHashCode() @@ -284,6 +388,12 @@ data class DIDDocument( val urls: Array, val verificationMethods: Array ) : DIDDocumentCoreProperty { + /** + * Checks if the current AssertionMethod object is equal to the provided object. + * + * @param other The object to compare with the current AssertionMethod. + * @return true if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -296,6 +406,11 @@ data class DIDDocument( return true } + /** + * Calculates the hash code for the AssertionMethod object. + * + * @return The hash code value for the AssertionMethod object. + */ override fun hashCode(): Int { var result = urls.contentHashCode() result = 31 * result + verificationMethods.contentHashCode() @@ -313,6 +428,12 @@ data class DIDDocument( val urls: Array, val verificationMethods: Array ) : DIDDocumentCoreProperty { + /** + * Checks whether the current instance is equal to the given object. + * + * @param other The object to compare with the current instance. + * @return Returns true if the current instance is equal to the given object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -325,6 +446,11 @@ data class DIDDocument( return true } + /** + * Calculates the hash code for the `KeyAgreement` instance. + * + * @return The hash code value calculated based on the `urls` and `verificationMethods` properties. + */ override fun hashCode(): Int { var result = urls.contentHashCode() result = 31 * result + verificationMethods.contentHashCode() @@ -342,6 +468,13 @@ data class DIDDocument( val urls: Array, val verificationMethods: Array ) : DIDDocumentCoreProperty { + /** + * Compares this object with the specified object for equality. + * Returns true if the specified object is also a [CapabilityInvocation] and has the same values for the `urls` and `verificationMethods` properties. + * + * @param other The object to compare for equality. + * @return True if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -354,6 +487,11 @@ data class DIDDocument( return true } + /** + * Calculates the hash code for a CapabilityInvocation object. + * + * @return The calculated hash code. + */ override fun hashCode(): Int { var result = urls.contentHashCode() result = 31 * result + verificationMethods.contentHashCode() @@ -371,6 +509,12 @@ data class DIDDocument( val urls: Array, val verificationMethods: Array ) : DIDDocumentCoreProperty { + /** + * Determines whether the current `CapabilityDelegation` object is equal to the provided object. + * + * @param other The object to compare with the current `CapabilityDelegation` object. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -383,6 +527,15 @@ data class DIDDocument( return true } + /** + * Calculates the hash code value for the `CapabilityDelegation` object. + * + * The hash code is calculated based on the `urls` and `verificationMethods` properties of the `CapabilityDelegation`. + * Both properties are used to calculate the hash code by invoking the `contentHashCode()` method on the corresponding arrays. + * The resulting hash codes are combined using the formula: `result = 31 * result + secondHashCode`. + * + * @return The hash code value for the `CapabilityDelegation` object. + */ override fun hashCode(): Int { var result = urls.contentHashCode() result = 31 * result + verificationMethods.contentHashCode() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DIDUrl.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DIDUrl.kt index c1f3edd98..ab9f88e19 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DIDUrl.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/DIDUrl.kt @@ -14,22 +14,49 @@ data class DIDUrl @JvmOverloads constructor( val fragment: String? = null ) { + /** + * Returns a string representation of the DID URL. + * + * @return The string representation of the DID URL. + */ fun string(): String { return "${did}${fragmentString()}" } + /** + * Returns the path portion of a DID URL as a string. + * If the path is null, an empty string is returned. + * + * @return The path portion of a DID URL. + */ fun pathString(): String { return "/${path?.joinToString(DID_URL_SEPARATOR)}" } + /** + * Generates a query string based on the provided parameters. + * + * @return The query string in the format "?key1=value1&key2=value2&..." + */ fun queryString(): String { return "?${parameters?.map { "${it.key}=${it.value}" }?.joinToString("&")}" } + /** + * Returns the fragment portion of a DID URL as a string. + * + * @return The fragment portion of a DID URL. + */ fun fragmentString(): String { return "#$fragment" } + /** + * Checks if the current [DIDUrl] instance is equal to the specified [other] object. + * + * @param other The object to compare with the current [DIDUrl]. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -47,6 +74,11 @@ data class DIDUrl @JvmOverloads constructor( return true } + /** + * Calculates the hash code for the current [DIDUrl] instance. + * + * @return The hash code value for the [DIDUrl] object. + */ override fun hashCode(): Int { var result = did.hashCode() result = 31 * result + (path?.contentHashCode() ?: 0) @@ -55,6 +87,11 @@ data class DIDUrl @JvmOverloads constructor( return result } + /** + * Returns a string representation of the current [DIDUrl] instance. + * + * @return The string representation of the DID URL. + */ override fun toString(): String { return string() } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Errors.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Errors.kt index 9eb5e38f4..b1ada7378 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Errors.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Errors.kt @@ -1,5 +1,7 @@ package io.iohk.atala.prism.walletsdk.domain.models +import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.KeyTypes + /** * An interface that represents a base error in the Prism SDK. */ @@ -10,496 +12,755 @@ abstract interface Error { } /** - * A class representing an unknown error in a Prism API response. + * A class representing an unknown error in a PRISM. * - * Note: When an error occurs during an API request/response cycle, the server may return an error object in the response. - * This object may include an error code, an error message, and possibly an array of underlying errors. If the error - * received does not conform to the [Error] interface, it will be classified as an [UnknownPrismError]. + * @see Error + * @see Throwable */ -abstract class UnknownPrismError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : Error, - Throwable(message, cause) { - +abstract class UnknownPrismError +@JvmOverloads +constructor( + message: String? = null, + cause: Throwable? = null +) : Error, Throwable(message, cause) { override val code: Int? get() = null - override val message: String? - get() = null override val underlyingErrors: Array? get() = emptyArray() + override val errorDescription: String? get() = null } /** - * A class representing a known error in a Prism API response. + * A class representing a known error in a PRISM. * - * Note: When an error occurs during an API request/response cycle, the server may return an error object in the response. - * This object may include an error code and an error message. If the error received conforms to the [KnownPrismError], - * it will be classified as a known error. + * @see Error + * @see Throwable */ -abstract class KnownPrismError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : Error, - Throwable(message, cause) { +abstract class KnownPrismError +@JvmOverloads +constructor( + message: String? = null, + cause: Throwable? = null +) : Error, Throwable(message, cause) { override val code: Int? get() = null - override val message: String? - get() = null + override val underlyingErrors: Array? get() = emptyArray() + override val errorDescription: String? get() = null } /** - * A class representing an unknown error in a Prism API response. + * A class representing an unknown error if the error received does not conform to the [KnownPrismError], it will be + * classified as an [UnknownPrismError]. * - * Note: When an error occurs during an API request/response cycle, the server may return an error object in the response. - * This object may include an error code, an error message, and possibly an array of underlying errors. - * If the error received does not conform to the [KnownPrismError], it will be classified as an [UnknownPrismError]. + * @see UnknownPrismError */ -abstract class UnknownError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : - UnknownPrismError(message, cause) { - - class SomethingWentWrongError( +abstract class UnknownError +@JvmOverloads +constructor( + message: String? = null, + cause: Throwable? = null +) : UnknownPrismError(message, cause) { + + /** + * A class representing an error that occurs when something goes wrong in the SDK. + * + * @param message The error message. + * @param cause The underlying cause of the error. + * + * @see UnknownError + */ + class SomethingWentWrongError + @JvmOverloads + constructor( message: String? = null, - cause: Throwable? = null, - private val customMessage: String? = null, - private val customUnderlyingErrors: Array = emptyArray() + cause: Throwable? = null ) : UnknownError(message, cause) { - override val code: Int? = -1 - override val message: String? - get() { - val errorsMessages = customUnderlyingErrors.joinToString(separator = "\n") { it.errorDescription ?: "" } - return "$customMessage $errorsMessages" - } + override val code: Int + get() = -1 } } /** - * A class representing a known error in a Prism API response. + * A class representing a common error in a PRISM. * - * Note: When an error occurs during an API request/response cycle, the server may return an error object in the response. - * This object may include an error code and an error message. If the error received conforms to the [KnownPrismError], - * it will be classified as a known error. + * @see KnownPrismError */ -sealed class CommonError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : - KnownPrismError(message, cause) { - class InvalidURLError(val url: String) : CommonError() { +sealed class CommonError +@JvmOverloads +constructor( + message: String? = null, + cause: Throwable? = null +) : KnownPrismError(message, cause) { + + /** + * A class representing an error that occurs when an invalid URL is encountered while trying to send a message. + * + * @param url The invalid URL that caused the error. + * + * @see CommonError + */ + class InvalidURLError(url: String) : CommonError("Invalid url while trying to send message: $url") { override val code: Int get() = -2 - override val message: String - get() = "Invalid url while trying to send message: $url" } - class HttpError(private val customCode: Int, private val customMessage: String? = null) : CommonError() { - override val code: Int - get() = customCode - override val message: String - get() = "HTTP Request Error $customCode: $customMessage" + /** + * Represents an HTTP error encountered during an API request. + * + * @param code The HTTP status code of the error. + * @param message The error message. + * + * @see CommonError + */ + class HttpError + @JvmOverloads + constructor( + override val code: Int, + message: String? = null + ) : CommonError("HTTP Request Error $code: $message") { override val errorDescription: String get() = "Code $code: $message" } } /** - * A class representing a known error in an Apollo API response. + * A class representing a known error in an Apollo. * - * Note: When an error occurs during an API request/response cycle, the server may return an error object in the response. - * This object may include an error code and an error message. If the error received conforms to the [KnownPrismError], - * it will be classified as a known error. + * @see KnownPrismError */ -sealed class ApolloError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : - KnownPrismError(message, cause) { - class InvalidMnemonicWord(private val invalidWords: Array? = null) : ApolloError() { +sealed class ApolloError +@JvmOverloads +constructor( + message: String? = null, + cause: Throwable? = null +) : KnownPrismError(message, cause) { + + /** + * An implementation of the [ApolloError] class that represents an error caused by invalid mnemonic words. + * This error occurs when one or more mnemonic words are invalid in a PRISM API response. + * + * @param invalidWords The array of invalid mnemonic words. + * @property message The error message for this error, which is determined based on the presence of invalid words. + * If `invalidWords` is not null, the message will be "The following mnemonic words are invalid: [invalidWords]". + * If `invalidWords` is null, the message will be "The seed cannot be null". + * + * @see ApolloError + */ + class InvalidMnemonicWord + @JvmOverloads + constructor( + invalidWords: Array? = null + ) : ApolloError( + if (invalidWords.isNullOrEmpty()) { + "The following mnemonic words are invalid: $invalidWords" + } else { + "The seed cannot be null" + } + ) { override val code: Int get() = 11 - override val message: String - get() { - return if (invalidWords != null) { - "The following mnemonic words are invalid: $invalidWords" - } else { - "The seed cannot be null" - } - } } - class CouldNotParseMessageString : ApolloError() { + /** + * Class representing an error when the message string cannot be parsed to UTF8 data. + * + * @property code The error code for CouldNotParseMessageString, which is 12. + * + * @see ApolloError + */ + class CouldNotParseMessageString : ApolloError("Could not get UTF8 Data from message string") { override val code: Int get() = 12 - - override val message: String - get() = "Could not get UTF8 Data from message string" } - class InvalidJWKError : ApolloError() { - + /** + * A class representing an invalid JSON Web Key (JWK) error in the PRISM SDK. + * + * This error indicates that the JWK provided is not in a valid format. + * + * @property code The error + * + * @see ApolloError + */ + class InvalidJWKError : ApolloError("JWK is not in a valid format") { override val code: Int get() = 13 - override val message: String - get() = "JWK is not in a valid format" } - class InvalidKeyCurve(val invalidCurve: String, val validCurves: Array) : ApolloError() { - + /** + * Represents an error that occurs when an invalid key curve is provided. + * + * @param invalidCurve The invalid key curve that was provided. + * + * @see ApolloError + */ + class InvalidKeyCurve( + invalidCurve: String + ) : ApolloError( + "Invalid key curve $invalidCurve. Valid options are: ${ + Curve.values().map { it.value }.toTypedArray().joinToString(", ") + }" + ) { override val code: Int get() = 14 - override val message: String - get() = "Invalid key curve $invalidCurve. Valid options are: ${validCurves.joinToString(", ")}" } - class InvalidKeyType(val invalidType: String, val validTypes: Array) : ApolloError() { + /** + * Represents an error indicating that a specific key curve is invalid. + * + * @param invalidCurve The invalid key curve. + * @param validCurves An array of valid key curves. + * + * @see ApolloError + */ + class InvalidSpecificKeyCurve( + invalidCurve: String, + validCurves: Array + ) : ApolloError( + "Invalid key curve $invalidCurve. Valid options are: ${validCurves.joinToString(", ")}" + ) { + override val code: Int + get() = 14 + } + /** + * Represents an error that occurs when an invalid key type is used. + * + * @param invalidType The invalid key type. + * + * @see ApolloError + */ + class InvalidKeyType( + invalidType: String + ) : ApolloError( + "Invalid key type $invalidType. Valid options are: ${ + KeyTypes.values().map { it.type }.toTypedArray().joinToString(", ") + }" + ) { override val code: Int get() = 15 - override val message: String - get() = "Invalid key type $invalidType. Valid options are: ${validTypes.joinToString(", ")}" } - class InvalidIndex(val invalidMessage: String) : ApolloError() { - + /** + * Represents an error that occurs when an invalid index is provided. + * + * @param message The error message associated with the exception. + * + * @see ApolloError + */ + class InvalidIndex(message: String) : ApolloError(message) { override val code: Int get() = 16 - override val message: String - get() = invalidMessage } - class InvalidDerivationPath(val invalidMessage: String) : ApolloError() { - + /** + * A class representing an invalid derivation path error. + * + * @property message The error message. + * + * @see ApolloError + */ + class InvalidDerivationPath(message: String) : ApolloError(message) { override val code: Int get() = 17 - override val message: String - get() = invalidMessage } - class InvalidSeed(val invalidMessage: String) : ApolloError() { - + /** + * A class representing an error that occurs when an invalid seed is used. + * + * @param message The error message. + * + * @see ApolloError + */ + class InvalidSeed(message: String) : ApolloError(message) { override val code: Int get() = 18 - override val message: String - get() = invalidMessage } - class InvalidRawData(val invalidMessage: String) : ApolloError() { - + /** + * Represents an error that occurs due to invalid raw data. + * + * @param message A detailed error message. + * + * @see ApolloError + */ + class InvalidRawData(message: String) : ApolloError(message) { override val code: Int get() = 19 - override val message: String - get() = invalidMessage } - class RestorationFailedNoIdentifierOrInvalid() : ApolloError() { - + /** + * Represents an error that occurs when restoration fails due to no identifier or invalid identifier. + * + * @see ApolloError + */ + class RestorationFailedNoIdentifierOrInvalid : ApolloError("Restoration failed: no identifier or invalid") { override val code: Int get() = 20 - override val message: String - get() = "Restoration failed: no identifier or invalid" } } /** - * A class representing a known error in a Castor API response. + * A class representing a known error in a Castor. * - * Note: When an error occurs during an API request/response cycle, the server may return an error object in the response. - * This object may include an error code and an error message. If the error received conforms to the [KnownPrismError], - * it will be classified as a known error. + * @see KnownPrismError */ -sealed class CastorError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : - KnownPrismError(message, cause) { - class KeyCurveNotSupported(val curve: String) : CastorError() { +sealed class CastorError +@JvmOverloads +constructor( + message: String? = null, + cause: Throwable? = null +) : KnownPrismError(message, cause) { + + /** + * An error that indicates that the given key curve is not supported for a specific functionality. + * + * @param curve The unsupported key curve. + * + * @see CastorError + */ + class KeyCurveNotSupported(curve: String) : CastorError( + "Key curve $curve is not supported for this functionality" + ) { override val code: Int get() = 21 - - override val message: String - get() = "Key curve $curve is not supported for this functionality" } - class InvalidLongFormDID : CastorError() { + /** + * Represents an error that occurs when the long form PRISM DID is invalid or changed. + * + * @property code The error code associated with the InvalidLongFormDID error. + * + * @see CastorError + */ + class InvalidLongFormDID : CastorError("Long form prism DID is invalid or changed") { override val code: Int get() = 22 - - override val message: String - get() = "Long form prism DID is invalid or changed" } - class MethodIdIsDoesNotSatisfyRegex(private val regex: String) : CastorError() { + /** + * Represents an error that occurs when the provided method ID does not satisfy a given regex pattern. + * + * @param regex The regex pattern that the method ID should satisfy. + * + * @see CastorError + */ + class MethodIdIsDoesNotSatisfyRegex(regex: String) : CastorError( + "The Prism DID provided is not passing the regex validation: $regex" + ) { override val code: Int get() = 23 - - override val message: String - get() = "The Prism DID provided is not passing the regex validation: $regex" } - class InvalidPublicKeyEncoding(private val didMethod: String, val curve: String) : - CastorError() { + /** + * Represents an error that occurs when there is an invalid encoding or decoding + * of a public key. + * + * @param didMethod The DID method being used when the error occurred. + * @param curve The curve of the key when the error occurred. + * + * @see CastorError + */ + class InvalidPublicKeyEncoding( + didMethod: String, + curve: String + ) : CastorError("Invalid encoding/decoding of key $curve while trying to compute $didMethod") { override val code: Int get() = 24 - - override val message: String - get() = "Invalid encoding/decoding of key $curve while trying to compute $didMethod" } - class InvalidDIDString(val did: String) : CastorError() { + /** + * Represents an error that occurs when trying to parse an invalid DID string. + * + * @param did The invalid DID string. + * + * @see CastorError + */ + class InvalidDIDString(did: String) : CastorError("Trying to parse invalid DID String: $did") { override val code: Int get() = 25 - - override val message: String - get() = "Trying to parse invalid DID String: $did" } - class InitialStateOfDIDChanged : CastorError() { + /** + * Represents an error that occurs when the initial state of a PRISM DID changes, + * making it invalid. + * + * @see CastorError + */ + class InitialStateOfDIDChanged : CastorError( + "While trying to resolve Prism DID state changed making it invalid" + ) { override val code: Int get() = 26 - - override val message: String - get() = "While trying to resolve Prism DID state changed making it invalid" } - class NotPossibleToResolveDID(val did: String, private val reason: String) : - CastorError() { + /** + * Represents an error that occurs when it is not possible to resolve a Decentralized Identifier (DID) due to a specific reason. + * + * @param did The DID that could not be resolved. + * @param reason The reason why the DID could not be resolved. + * + * @see CastorError + */ + class NotPossibleToResolveDID(did: String, reason: String, cause: Throwable? = null) : + CastorError("Not possible to resolve DID $did due to $reason", cause) { override val code: Int get() = 27 - - override val message: String - get() = "Not possible to resolve DID $did due to $reason" } - class InvalidJWKKeysError : CastorError() { + /** + * Represents an error that occurs when the JWK (JSON Web Key) keys are not in a valid format. + * + * @property code The error code associated with the `InvalidJWKKeysError`. + * + * @see CastorError + */ + class InvalidJWKKeysError : CastorError("JWK is not in a valid format") { override val code: Int get() = 28 - - override val message: String - get() = "JWK is not in a valid format" } - class InvalidKeyError : CastorError() - - class InvalidPeerDIDError : CastorError() - - class NoResolversAvailableForDIDMethod(val method: String) : CastorError() { + /** + * Represents an error that occurs when an invalid key is encountered. + * + * @see CastorError + */ + class InvalidKeyError @JvmOverloads constructor(message: String? = null) : CastorError(message) + + /** + * An error that occurs when the provided PeerDID is invalid. + * + * @see CastorError + */ + class InvalidPeerDIDError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : + CastorError(message, cause) + + /** + * Class representing an error thrown when no resolvers are available to resolve a given DID method. + * + * @param method The method that couldn't be resolved. + * + * @see CastorError + */ + class NoResolversAvailableForDIDMethod(method: String) : CastorError( + "No resolvers in castor are able to resolve the method $method, please provide a resolver" + ) { override val code: Int get() = 29 - - override val message: String - get() = "No resolvers in castor are able to resolve the method $method, please provide a resolver" } } /** - * A class representing a known error in a Mercury API response. + * A class representing a known error in a Mercury. * - * Note: When an error occurs during an API request/response cycle, the server may return an error object in the response. - * This object may include an error code and an error message. If the error received conforms to the [KnownPrismError], - * it will be classified as a known error. + * @see KnownPrismError */ -sealed class MercuryError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : - KnownPrismError(message, cause) { - - class NoDIDReceiverSetError : MercuryError() { +sealed class MercuryError +@JvmOverloads +constructor( + message: String? = null, + cause: Throwable? = null +) : KnownPrismError(message, cause) { + + /** + * Error class representing a message that has no recipient set. + * To send a message, please set the "to" field. + * + * @see MercuryError + */ + class NoDIDReceiverSetError : + MercuryError("Message has no recipient set, to send a message please set the \"to\"") { override val code: Int get() = 31 - - override val message: String - get() = "Message has no recipient set, to send a message please set the \"to\"" } - class NoValidServiceFoundError(val did: String? = null) : MercuryError() { + /** + * An error class that indicates that no valid service is found for a given DID. + * + * @constructor Creates an instance of NoValidServiceFoundError. + * @param did The DID that has no valid services + * + * @see MercuryError + */ + class NoValidServiceFoundError + @JvmOverloads + constructor( + did: String? = null + ) : MercuryError(did?.let { "The did ($did) has no valid services" } ?: "No valid services") { override val code: Int get() = 32 - - override val message: String - get() = did?.let { "The did ($did) has no valid services" } ?: "No valid services" } - class NoDIDSenderSetError : MercuryError() { + /** + * Represents an error that occurs when a message does not have a sender set. + * + * @see MercuryError + */ + class NoDIDSenderSetError : MercuryError( + "Message has no sender set, to send a message please set the \"from\"" + ) { override val code: Int get() = 33 - - override val message: String - get() = "Message has no sender set, to send a message please set the \"from\"" } - class UnknownAttachmentDataError : MercuryError() { + /** + * Represents an error that occurs when an unknown AttachmentData type is found while decoding a message. + * + * @see MercuryError + */ + class UnknownAttachmentDataError : MercuryError( + "Unknown AttachmentData type was found while decoding message" + ) { override val code: Int get() = 34 - - override val message: String - get() = "Unknown AttachamentData type was found while decoding message" } - class MessageAttachmentWithoutIDError : MercuryError() { + /** + * Represents an error that occurs when decoding a message and a message attachment is found without an "id". + * + * @see MercuryError + */ + class MessageAttachmentWithoutIDError : MercuryError( + "While decoding a message, a message attachment was found without \"id\" this is invalid" + ) { override val code: Int get() = 35 - - override val message: String - get() = "While decoding a message, a message attachment was found without \"id\" this is invalid" } - class MessageInvalidBodyDataError : MercuryError() { + /** + * A class representing an error that occurs when decoding a message with an invalid body. + * + * @see MercuryError + */ + class MessageInvalidBodyDataError : MercuryError( + "While decoding a message, a body was found to be invalid while decoding" + ) { override val code: Int get() = 36 - - override val message: String - get() = "While decoding a message, a body was found to be invalid while decoding" } - class DidCommError @JvmOverloads constructor( - private val customMessage: String? = null, - private val customUnderlyingErrors: Array - ) : - MercuryError() { + /** + * A class representing a DIDComm error in the PRISM SDK. + * + * @param customMessage The custom message associated with the error. Defaults to null. + * @param customUnderlyingErrors The array of underlying errors associated with the error. + * + * @see MercuryError + */ + class DidCommError + @JvmOverloads + constructor( + customMessage: String? = null, + customUnderlyingErrors: Array + ) : MercuryError( + "DIDComm error has occurred with message: $customMessage\nErrors: ${ + customUnderlyingErrors.joinToString( + separator = "\n" + ) { it.errorDescription ?: "" } + }" + ) { override val code: Int get() = 37 - - override val message: String - get() { - val errorsMessages = customUnderlyingErrors.joinToString(separator = "\n") { it.errorDescription ?: "" } - return "DIDComm error has occurred with message: $customMessage\nErrors: $errorsMessages" - } } } /** - * A class representing a known error in a Pluto API response. + * A class representing a known error in a Pluto. * - * Note: When an error occurs during an API request/response cycle, the server may return an error object in the response. - * This object may include an error code and an error message. If the error received conforms to the [KnownPrismError], - * it will be classified as a known error. + * @see KnownPrismError */ -sealed class PlutoError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : - KnownPrismError(message, cause) { - class MissingDataPersistence(val type: String, private val affecting: String) : - PlutoError() { +sealed class PlutoError +@JvmOverloads +constructor( + message: String? = null, + cause: Throwable? = null +) : KnownPrismError(message, cause) { + + /** + * Represents an error that occurs when data is not persisted for a specific type while adding or making changes to another object. + * + * @param type The type of data that is not persisted. + * @param affecting The object to which the data is being added or modified. + * + * @see PlutoError + */ + class MissingDataPersistence(type: String, affecting: String) : + PlutoError("$type is not persisted while trying to add or make changes to $affecting") { override val code: Int get() = 41 - - override val message: String - get() = "$type is not persisted while trying to add or make changes to $affecting" } - class MissingRequiredFields(val type: String, private val fields: Array) : - PlutoError() { + /** + * Represents a specific error that occurs when required fields are missing. + * + * @param type The type that requires the fields. + * @param fields The array of missing fields. + * + * @see PlutoError + */ + class MissingRequiredFields(type: String, fields: Array) : + PlutoError("$type requires the following fields: ${fields.joinToString(", ")}") { override val code: Int get() = 42 - - override val message: String - get() = "$type requires the following fields: ${fields.joinToString(", ")}" } - class Duplication(val type: String) : PlutoError() { + /** + * Represents a duplication error when trying to save an object with an existing ID. + * + * @param type The type of object that is being duplicated. + * + * @see PlutoError + */ + class Duplication(type: String) : PlutoError("Trying to save $type with an ID that already exists") { override val code: Int get() = 43 - - override val message: String - get() = "Trying to save $type with an ID that already exists" } - class UnknownCredentialTypeError : PlutoError() { + /** + * A class representing an unknown credential type error in the Pluto SDK. + * + * @see PlutoError + */ + class UnknownCredentialTypeError : PlutoError("The credential type needs to be JWT or W3C") { override val code: Int get() = 44 - - override val message: String - get() = "The credential type needs to be JWT or W3C" } - class InvalidCredentialJsonError : PlutoError() { + /** + * Represents an error that occurs when the credential JSON cannot be decoded. + * + * @see PlutoError + */ + class InvalidCredentialJsonError : PlutoError("Could not decode the credential JSON") { override val code: Int get() = 45 - - override val message: String - get() = "Could not decode the credential JSON" } - class DatabaseConnectionError : PlutoError() { + /** + * An error class representing a database connection error. + * + * @see PlutoError + */ + class DatabaseConnectionError : PlutoError("Database connection error") { override val code: Int get() = 46 - - override val message: String - get() = "Database connection error" } - class DatabaseContextError : PlutoError() { + /** + * Custom error class that represents an error when a context is required to be initialized in Pluto. + * + * @see PlutoError + */ + class DatabaseContextError : PlutoError("Pluto requires a context to be initialized") { override val code: Int get() = 47 - - override val message: String - get() = "Pluto requires a context to be initialized" } - class DatabaseServiceAlreadyRunning : PlutoError() { + /** + * Class representing an error that occurs when the database service is already running. + * + * @see PlutoError + */ + class DatabaseServiceAlreadyRunning : PlutoError("Database service already running.") { override val code: Int get() = 48 - - override val message: String - get() = "Database service already running." } - class InvalidRestorationIdentifier : PlutoError() { + /** + * Represents an error that occurs when an invalid restoration identifier is encountered. + * + * @see PlutoError + */ + class InvalidRestorationIdentifier : PlutoError("Invalid restoration identifier") { override val code: Int get() = 49 - - override val message: String - get() = "Invalid restoration identifier" } } /** - * A class representing a known error in a Pollux API response. + * A class representing a known error in a Pollux. * - * Note: When an error occurs during an API request/response cycle, the server may return an error object in the response. - * This object may include an error code and an error message. If the error received conforms to the [KnownPrismError], - * it will be classified as a known error. + * @see KnownPrismError */ -sealed class PolluxError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : - KnownPrismError(message, cause) { - class InvalidPrismDID : PolluxError() { +sealed class PolluxError +@JvmOverloads +constructor( + message: String? = null, + cause: Throwable? = null +) : KnownPrismError(message, cause) { + + /** + * Represents an error that occurs when attempting to create a JWT presentation without providing a PRISM DID. + * + * @see PolluxError + */ + class InvalidPrismDID(message: String? = "To create a JWT presentation a Prism DID is required") : + PolluxError(message) { override val code: Int get() = 53 - - override val message: String - get() = "To create a JWT presentation a Prism DID is required" } - class InvalidCredentialError @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : - PolluxError(message, cause) { + /** + * Represents an error encountered when invalid credentials are provided. + * + * @see PolluxError + */ + class InvalidCredentialError + @JvmOverloads + constructor( + cause: Throwable? = null + ) : PolluxError("Invalid credential, could not decode", cause) { override val code: Int get() = 51 - - override val message: String - get() = "Invalid credential, could not decode" } - class InvalidJWTString : PolluxError() { + /** + * Represents an error that occurs when an invalid JWT string is encountered while decoding a credential. + * + * @see PolluxError + */ + class InvalidJWTString : PolluxError("Invalid JWT while decoding credential") { override val code: Int get() = 52 - - override val message: String - get() = "Invalid JWT while decoding credential" } - class InvalidJWTCredential : PolluxError() { + /** + * A class representing an error when creating a JSON Web Token (JWT) presentation with an invalid JWTCredential. + * + * This error occurs when the provided JWTCredential is not valid or is missing required information. + * + * @see PolluxError + */ + class InvalidJWTCredential : PolluxError("To create a JWT presentation please provide a valid JWTCredential") { override val code: Int get() = 54 - - override val message: String - get() = "To create a JWT presentation please provide a valid JWTCredential" } - class NoDomainOrChallengeFound : PolluxError() { + /** + * A class representing an error when no domain or challenge is found as part of the offer JSON. + * + * @see PolluxError + */ + class NoDomainOrChallengeFound : PolluxError("No domain or challenge found as part of the offer json") { override val code: Int get() = 55 - - override val message: String - get() = "No domain or challenge found as part of the offer json" } - class InvalidCredentialDefinitionError @JvmOverloads constructor( - message: String? = null, - cause: Throwable? = null - ) : PolluxError(message, cause) { + /** + * Represents an error that occurs when there is an invalid credential definition. + * + * @see PolluxError + */ + class InvalidCredentialDefinitionError : PolluxError("Invalid credential definition") { override val code: Int get() = 56 - - override val message: String - get() = "Invalid credential definition" } } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpClient.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpClient.kt index bc57ea154..1919c0d95 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpClient.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpClient.kt @@ -3,4 +3,10 @@ package io.iohk.atala.prism.walletsdk.domain.models import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig +/** + * Creates a new instance of HttpClient with the given configuration. + * + * @param config The configuration block for HttpClient. If not provided, default configuration will be used. + * @return A new instance of HttpClient. + */ expect fun httpClient(config: HttpClientConfig<*>.() -> Unit = {}): HttpClient diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpResponse.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpResponse.kt index 427708066..5a0048584 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpResponse.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/HttpResponse.kt @@ -2,5 +2,11 @@ package io.iohk.atala.prism.walletsdk.domain.models import kotlinx.serialization.Serializable +/** + * Represents an HTTP response. + * + * @param status The status code of the response. + * @param jsonString The JSON string representing the response body. + */ @Serializable data class HttpResponse(val status: Int, val jsonString: JsonString) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/JWTPayload.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/JWTPayload.kt index 10891a75a..da3d09668 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/JWTPayload.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/JWTPayload.kt @@ -14,7 +14,7 @@ import kotlinx.serialization.json.jsonPrimitive * A data class representing a JWT credential payload. * This payload includes the issuer (`iss`), subject (`sub`), and the verifiable credential (`verifiableCredential`). * - *Note: This data class conforms to the JSON Web Token (JWT) format. For more information, see https://jwt.io/introduction/. + * Note: This data class conforms to the JSON Web Token (JWT) format. For more information, see https://jwt.io/introduction/. */ @OptIn(ExperimentalSerializationApi::class) @Serializable @@ -49,6 +49,12 @@ data class JWTPayload val evidence: VerifiableCredentialTypeContainer? = null, val termsOfUse: VerifiableCredentialTypeContainer? = null ) { + /** + * Checks if this JWTVerifiableCredential object is equal to the specified object. + * + * @param other The object to compare this JWTVerifiableCredential object against. + * @return true if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -67,6 +73,12 @@ data class JWTPayload return true } + /** + * Calculates the hash code value for the current object. The hash code is computed + * based on the values of the object's properties. + * + * @return The hash code value for the object. + */ override fun hashCode(): Int { var result = context.contentHashCode() result = 31 * result + type.contentHashCode() @@ -80,6 +92,12 @@ data class JWTPayload } } + /** + * Checks if this JWTPayload object is equal to the specified object. + * + * @param other The object to compare this JWTPayload object against. + * @return true if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -101,6 +119,12 @@ data class JWTPayload return true } + /** + * Calculates the hash code value for the current `JWTPayload` object. + * The hash code is computed based on the values of the object's properties. + * + * @return The hash code value for the object. + */ override fun hashCode(): Int { var result = iss.hashCode() result = 31 * result + (sub?.hashCode() ?: 0) @@ -114,6 +138,14 @@ data class JWTPayload } } +/** + * Retrieves the value of the specified credential field from a JsonObject. + * + * @param name The name of the credential field. + * @param isOptional Indicates whether the field is optional. If set to false and the field is not found, a [PolluxError.InvalidJWTString] error is thrown. + * @return The value of the credential field. The return type is inferred based on the actual type of the field in the JsonObject. + * @throws PolluxError.InvalidJWTString if the field is not found and isOptional is set to false. + */ inline fun JsonObject.getCredentialField(name: String, isOptional: Boolean = false): T { if (!isOptional && this[name] == null) throw PolluxError.InvalidJWTString() return when (val field = this[name]) { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/JsonString.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/JsonString.kt index 4a9326c20..5712aec1d 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/JsonString.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/JsonString.kt @@ -1,3 +1,6 @@ package io.iohk.atala.prism.walletsdk.domain.models +/** + * Alias for a JSON string. + */ typealias JsonString = String diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/KeyCurve.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/KeyCurve.kt index 057aad1db..94219f0c2 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/KeyCurve.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/KeyCurve.kt @@ -11,6 +11,13 @@ data class KeyCurve @JvmOverloads constructor( val index: Int? = 0 ) +/** + * Enumeration representing supported key curves. + * + * @property value The string value of the curve. + * + * @constructor Creates a Curve object with the given value. + */ @Serializable enum class Curve(val value: String) { X25519("X25519"), diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Mediator.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Mediator.kt index 806a1ffad..d6875ad90 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Mediator.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Mediator.kt @@ -2,6 +2,15 @@ package io.iohk.atala.prism.walletsdk.domain.models import kotlinx.serialization.Serializable +/** + * Mediator is a data class that represents a mediator entity. + * It contains the mediator's ID, mediator DID, host DID, and routing DID. + * + * @property id The ID of the mediator. + * @property mediatorDID The DID of the mediator. + * @property hostDID The DID of the host. + * @property routingDID The DID used for routing messages. + */ @Serializable data class Mediator( val id: String, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Message.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Message.kt index 8837d1913..3d8893e97 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Message.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Message.kt @@ -1,8 +1,10 @@ package io.iohk.atala.prism.walletsdk.domain.models import io.iohk.atala.prism.apollo.uuid.UUID +import io.iohk.atala.prism.walletsdk.domain.buildingblocks.Mercury import kotlinx.datetime.Clock import kotlinx.serialization.EncodeDefault +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -15,7 +17,10 @@ import kotlin.time.Duration.Companion.days * [Message] objects are typically exchanged between DID controllers using the [Mercury] building block. */ @Serializable -data class Message @JvmOverloads constructor( +data class Message +@OptIn(ExperimentalSerializationApi::class) +@JvmOverloads +constructor( @EncodeDefault val id: String = UUID.randomUUID4().toString(), val piuri: String, @@ -32,6 +37,12 @@ data class Message @JvmOverloads constructor( val ack: Array? = emptyArray(), val direction: Direction = Direction.RECEIVED ) { + /** + * The `equals` method compares this `Message` object with another object for equality. + * + * @param other The object to compare with this `Message` object. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -54,6 +65,14 @@ data class Message @JvmOverloads constructor( return true } + /** + * Calculates the hash code for the Message object. + * The hash code is calculated based on the values of the object's id, piuri, from, to, fromPrior, + * body, extraHeaders, createdTime, expiresTimePlus, attachments, thid, pthid, and ack properties. + * If any of these properties is null, it is treated as 0 in the calculation. + * + * @return The hash code for the Message object. + */ override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + piuri.hashCode() @@ -71,26 +90,59 @@ data class Message @JvmOverloads constructor( return result } + /** + * Converts the current object to a JSON string representation. + * + * @return The JSON string representation of the object. + */ fun toJsonString(): String { return Json.encodeToString(this) } + /** + * Enumeration representing the direction of a message. + * + * @param value The numeric value representing the direction. + */ enum class Direction(val value: Int) { SENT(0), RECEIVED(1) } companion object { + /** + * Checks if the given [AttachmentData] is of type [AttachmentBase64]. + * + * @param data The [AttachmentData] object to check. + * @return `true` if the [AttachmentData] is of type [AttachmentBase64], `false` otherwise. + */ + @JvmStatic fun isBase64Attachment(data: AttachmentData): Boolean { return data is AttachmentBase64 } + /** + * Checks if the given [AttachmentData] is of type [AttachmentJsonData]. + * + * @param data The attachment data to check. + * @return `true` if the attachment data is of type [AttachmentJsonData], `false` otherwise. + */ + @JvmStatic fun isJsonAttachment(data: AttachmentData): Boolean { return data is AttachmentJsonData } } } +/** + * Retrieves the direction of a message based on the given value. + * + * @param value The value representing the direction of the message. + * 0 indicates SENT direction. + * 1 indicates RECEIVED direction. + * Any other value defaults to SENT direction. + * @return The message direction, either SENT or RECEIVED. + */ fun getDirectionByValue(value: Int): Message.Direction { return when (value) { 0 -> Message.Direction.SENT diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/MessageAttachment.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/MessageAttachment.kt index c2dd0cd9f..7a088dc4e 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/MessageAttachment.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/MessageAttachment.kt @@ -54,6 +54,14 @@ data class AttachmentLinkData( val links: Array, val hash: String ) : AttachmentData { + /** + * Overrides the equals method of the [Any] class. + * + * Two [AttachmentLinkData] instances are considered equal if all of their properties have the same values. + * + * @param other the object to compare for equality + * @return true if the objects are equal, false otherwise + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -66,6 +74,14 @@ data class AttachmentLinkData( return true } + /** + * Calculates the hash code for the [AttachmentLinkData] instance. + * + * The hash code is calculated by combining the hash codes of the `links` array and the `hash` property using the formula: + * `result = 31 * result + hash.hashCode()`. + * + * @return the hash code value for the [AttachmentLinkData] instance + */ override fun hashCode(): Int { var result = links.contentHashCode() result = 31 * result + hash.hashCode() @@ -96,6 +112,22 @@ data class AttachmentDescriptor @JvmOverloads constructor( val description: String? = null ) : AttachmentData { + /** + * Checks if this [AttachmentDescriptor] object is equal to the specified [other] object. + * + * Two [AttachmentDescriptor] objects are considered equal if they have the same values for the following properties: + * - [id] (unique identifier) + * - [mediaType] (media type of the attachment) + * - [data] (attachment data) + * - [filename] (array of filenames associated with the attachment) + * - [format] (format of the attachment) + * - [lastModTime] (last modification time of the attachment) + * - [byteCount] (byte count of the attachment) + * - [description] (description of the attachment) + * + * @param other The object to compare with this [AttachmentDescriptor] object. + * @return true if the specified [other] object is equal to this [AttachmentDescriptor] object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -114,6 +146,11 @@ data class AttachmentDescriptor @JvmOverloads constructor( return true } + /** + * Calculates the hash code for the AttachmentDescriptor object. + * + * @return The hash code value for the AttachmentDescriptor object. + */ override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + (mediaType?.hashCode() ?: 0) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/OctetPublicKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/OctetPublicKey.kt index d3a5207d0..80e42c3af 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/OctetPublicKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/OctetPublicKey.kt @@ -2,12 +2,29 @@ package io.iohk.atala.prism.walletsdk.domain.models import io.iohk.atala.prism.walletsdk.mercury.OKP import kotlinx.serialization.EncodeDefault +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable +/** + * Represents an Octet Key Pair (OKP) public key. + * + * @property kty The key type. Must be "OKP". + * @property crv The curve for the key. + * @property x The value of the public key. + */ @Serializable internal data class OctetPublicKey +@OptIn(ExperimentalSerializationApi::class) @JvmOverloads internal constructor(@EncodeDefault val kty: String = OKP, val crv: String, val x: String) +/** + * Represents an Octet Key Pair (OKP) private key. + * + * @property kty The key type. + * @property crv The curve for the key. + * @property x The public key value. + * @property d The private key value. + */ @Serializable internal data class OctetPrivateKey(val kty: String, val crv: String, val x: String, val d: String) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PeerDID.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PeerDID.kt index 05d19c649..70d46bfc6 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PeerDID.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PeerDID.kt @@ -2,10 +2,23 @@ package io.iohk.atala.prism.walletsdk.domain.models import io.iohk.atala.prism.walletsdk.domain.models.keyManagement.PrivateKey +/** + * Represents a PeerDID, which is used as a unique and persistent identifier for a subject or object. + * It consists of a [DID] and an array of [PrivateKey]s. + * + * @property did The [DID] associated with the PeerDID. + * @property privateKeys The array of [PrivateKey]s associated with the PeerDID. + */ data class PeerDID( val did: DID, val privateKeys: Array ) { + /** + * Compares this [PeerDID] object with the specified [other] object for equality. + * + * @param other The object to compare with this [PeerDID] object. + * @return `true` if the [other] object is equal to this [PeerDID] object, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -18,6 +31,15 @@ data class PeerDID( return true } + /** + * Calculates the hash code value for this PeerDID object. + * + * The hash code is calculated using the `did` and `privateKeys` properties of the PeerDID object. + * The hash code value is obtained by adding the hash code of the `did` property to the result variable, + * then multiplying the result by 31 and adding the hash code of the `privateKeys` array using the `contentHashCode()` method. + * + * @return The hash code value for this PeerDID object. + */ override fun hashCode(): Int { var result = did.hashCode() result = 31 * result + privateKeys.contentHashCode() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt index bf38a31fd..1a06c0bdb 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt @@ -1,5 +1,21 @@ package io.iohk.atala.prism.walletsdk.domain.models +/** + * The `Platform` class provides information about the current platform. + * + * This class is used for determining the type of platform and the operating system being used. + * It provides the following properties: + * + * - `OS`: The name of the operating system as a string. + * - `type`: The type of platform as an instance of the `PlatformType` enum class. + * + * Usage example: + * + * ``` + * val osName = Platform.OS + * val platformType = Platform.type + * ``` + */ expect object Platform { val OS: String val type: PlatformType diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PlatformType.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PlatformType.kt index ba4c3e0f0..066a3ac9c 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PlatformType.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PlatformType.kt @@ -1,5 +1,16 @@ package io.iohk.atala.prism.walletsdk.domain.models +/** + * Represents the type of platform. + * + * This enum class defines the different supported platform types: + * - JVM: Represents the Java Virtual Machine platform. + * - ANDROID: Represents the Android platform. + * - IOS: Represents the iOS platform. + * - WEB: Represents the web platform. + * + * @property value The string representation of the platform type. + */ enum class PlatformType(val value: String) { JVM("JVM"), ANDROID("ANDROID"), diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PublicKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PublicKey.kt index cab7d249e..ae1f88870 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PublicKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/PublicKey.kt @@ -10,6 +10,14 @@ data class PublicKey( val curve: KeyCurve, val value: ByteArray ) { + /** + * Checks whether the current [PublicKey] object is equal to the specified [other] object. + * + * Two [PublicKey] objects are considered equal if they have the same key curve and value. + * + * @param other The object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -22,6 +30,14 @@ data class PublicKey( return true } + /** + * Computes the hash code value for this [PublicKey] object. + * + * The hash code is computed based on the key curve and value of the [PublicKey] object. + * Two [PublicKey] objects that are equal according to the [equals] method will have the same hash code. + * + * @return The hash code value for this [PublicKey] object. + */ override fun hashCode(): Int { var result = curve.hashCode() result = 31 * result + value.contentHashCode() @@ -37,6 +53,14 @@ data class CompressedPublicKey( val uncompressed: PublicKey, val value: ByteArray ) { + /** + * Checks whether the current [CompressedPublicKey] object is equal to the specified [other] object. + * + * Two [CompressedPublicKey] objects are considered equal if they have the same uncompressed key and value. + * + * @param other The object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -49,6 +73,14 @@ data class CompressedPublicKey( return true } + /** + * Computes the hash code value for this [CompressedPublicKey] object. + * + * The hash code is computed based on the uncompressed key and value of the [CompressedPublicKey] object. + * Two [CompressedPublicKey] objects that are equal according to the [equals] method will have the same hash code. + * + * @return The hash code value for this [CompressedPublicKey] object. + */ override fun hashCode(): Int { var result = uncompressed.hashCode() result = 31 * result + value.contentHashCode() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Secret.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Secret.kt index e03c6c97b..1b887b9d7 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Secret.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Secret.kt @@ -1,7 +1,17 @@ package io.iohk.atala.prism.walletsdk.domain.models +/** + * Represents a secret material in the form of a JSON Web Key (JWK). + * + * @param value The string value of the JWK. + */ data class SecretMaterialJWK(val value: String) +/** + * Represents a type of secret. + * + * @property value The value associated with the secret type. + */ enum class SecretType(val value: String) { JsonWebKey2020("JsonWebKey2020") } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Seed.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Seed.kt index 35d49991f..e180dea3b 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Seed.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Seed.kt @@ -9,17 +9,26 @@ import kotlinx.serialization.Serializable data class Seed( val value: ByteArray ) { + /** + * Compares this Seed object to the specified [other] object for equality. + * + * Two Seed objects are considered equal if they have the same [value] property. + * + * @param other The object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false other as Seed - if (!value.contentEquals(other.value)) return false - - return true + return value.contentEquals(other.value) } + /** + * + */ override fun hashCode(): Int { return value.contentHashCode() } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/SeedWords.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/SeedWords.kt index 5dc1e7232..5ff5f8e32 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/SeedWords.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/SeedWords.kt @@ -2,8 +2,22 @@ package io.iohk.atala.prism.walletsdk.domain.models import kotlinx.serialization.Serializable +/** + * Represents a set of seed words along with the corresponding seed object. + * + * @property mnemonics An array of seed words. + * @property seed The seed object used for key generation. + */ @Serializable data class SeedWords(val mnemonics: Array, val seed: Seed) { + /** + * Compares this SeedWords object to the specified [other] object for equality. + * + * Two SeedWords objects are considered equal if they have the same [mnemonics] and [seed] properties. + * + * @param other The object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -16,6 +30,13 @@ data class SeedWords(val mnemonics: Array, val seed: Seed) { return true } + /** + * Calculates the hash code for the SeedWords object. + * + * The hash code is calculated based on the array of mnemonics and the seed object. + * + * @return The hash code value for the SeedWords object. + */ override fun hashCode(): Int { var result = mnemonics.contentHashCode() result = 31 * result + seed.hashCode() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Session.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Session.kt index c1512958f..617d5ae3f 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Session.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Session.kt @@ -3,6 +3,13 @@ package io.iohk.atala.prism.walletsdk.domain.models import io.iohk.atala.prism.apollo.uuid.UUID import kotlin.jvm.JvmOverloads +/** + * Represents a session between two entities. + * + * @property uuid The unique identifier for the session. + * @property seed The seed used for key generation. + * @constructor Creates a Session object with the specified [uuid] and [seed]. + */ data class Session @JvmOverloads constructor( val uuid: UUID = UUID.randomUUID4(), val seed: Seed diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Signature.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Signature.kt index e2595fdbd..7585150bb 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Signature.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Signature.kt @@ -9,17 +9,26 @@ import kotlinx.serialization.Serializable data class Signature( val value: ByteArray ) { + /** + * Check whether this Signature is equal to the specified object. + * + * @param other the object to compare with + * @return true if the given object is a Signature and has the same content as this Signature, false otherwise + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false other as Signature - if (!value.contentEquals(other.value)) return false - - return true + return value.contentEquals(other.value) } + /** + * Calculates the hash code value of the Signature object. + * + * @return the hash code value of the Signature object + */ override fun hashCode(): Int { return value.contentHashCode() } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/StorableCredential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/StorableCredential.kt index 8db654177..9b3a05185 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/StorableCredential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/StorableCredential.kt @@ -1,5 +1,8 @@ package io.iohk.atala.prism.walletsdk.domain.models +/** + * Represents a storable credential that can be stored and retrieved from a storage system. + */ interface StorableCredential : Credential { val recoveryId: String val credentialData: ByteArray @@ -10,5 +13,10 @@ interface StorableCredential : Credential { val revoked: Boolean? val availableClaims: Array + /** + * Converts a storable credential to a regular credential. + * + * @return The converted Credential object. + */ fun fromStorableCredential(): Credential } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/VerifiableCredential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/VerifiableCredential.kt index d6700b34c..a34fc2be0 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/VerifiableCredential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/VerifiableCredential.kt @@ -8,7 +8,9 @@ import kotlinx.serialization.json.Json * A data class representing a container for verifiable credential types. * This data class is used to encode and decode verifiable credential types for use with JSON. * The VerifiableCredentialTypeContainer contains properties for the ID and type of the verifiable credential. - * Note: The VerifiableCredentialTypeContainer is used to encode and decode verifiable credential types for use with JSON. + * ::: info + * The VerifiableCredentialTypeContainer is used to encode and decode verifiable credential types for use with JSON. + * ::: */ @Serializable data class VerifiableCredentialTypeContainer( @@ -18,9 +20,12 @@ data class VerifiableCredentialTypeContainer( /** * Enum class representing different types of verifiable credentials. - * The CredentialType is used to indicate the type of a verifiable credential. + * The CredentialType is used to indicate the type of verifiable credential. * The possible values of the enum are jwt, w3c, and unknown. - * Note: The CredentialType enum is used to indicate the type of a verifiable credential. + * + * ::: info + * The CredentialType enum is used to indicate the type of verifiable credential. + * ::: */ @Serializable enum class CredentialType(val type: String) { @@ -54,6 +59,12 @@ sealed interface VerifiableCredential { val validUntil: VerifiableCredentialTypeContainer? val proof: JsonString? val aud: Array + + /** + * Converts the object to a JSON string representation. + * + * @return The JSON string representation of the object. + */ fun toJsonString(): String { return Json.encodeToString(this) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/ExportableImportableKey.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/ExportableImportableKey.kt index aff99d45c..1b316026c 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/ExportableImportableKey.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/ExportableImportableKey.kt @@ -86,7 +86,47 @@ data class PEMKey(val keyType: PEMKeyType, val keyData: ByteArray) { return "$beginMarker\n$base64Data\n$endMarker" } + /** + * Overrides the `equals` method of the `Any` class. + * + * This method checks if the current `PEMKey` object is equal to the specified `other` object. + * Two `PEMKey` objects are considered equal if they have the same `keyType` and `keyData`. + * + * @param other The object to compare for equality. + * @return `true` if the `other` object is equal to the current `PEMKey` object, `false` otherwise. + */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as PEMKey + + if (keyType != other.keyType) return false + if (!keyData.contentEquals(other.keyData)) return false + + return true + } + + /** + * Calculates the hash code for the PEMKey instance. + * The hash code is calculated based on the keyType and keyData properties of the PEMKey. + * + * @return The hash code value for the PEMKey. + */ + override fun hashCode(): Int { + var result = keyType.hashCode() + result = 31 * result + keyData.contentHashCode() + return result + } + companion object { + /** + * Decodes a PEM-encoded string into a PEMKey object. + * + * @param pemString The PEM-encoded string to decode. + * @return A PEMKey object if the decoding was successful, or null otherwise. + */ + @JvmStatic fun fromPemEncoded(pemString: String): PEMKey? { val lines = pemString.split("\n") if (lines.size < 3) { @@ -120,6 +160,13 @@ enum class PEMKeyType(val value: Pair) { EC_PUBLIC_KEY(Pair("-----BEGIN EC PUBLIC KEY-----", "-----END EC PUBLIC KEY-----")); companion object { + /** + * Converts a string value to the corresponding PEMKeyType enum value. + * + * @param value The string value to convert. + * @return The PEMKeyType enum value if the conversion was successful, or null otherwise. + */ + @JvmStatic fun fromString(value: String): PEMKeyType? { return values().firstOrNull { it.value.first == value || it.value.second == value } } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/Key.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/Key.kt index 861456564..c5540b230 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/Key.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/Key.kt @@ -14,6 +14,17 @@ abstract class Key { abstract val size: Int abstract val raw: ByteArray + /** + * Checks if the current Key object is equal to the provided object. + * Two Key objects are considered equal if the following conditions are met: + * - The objects are references to the same memory location (this === other). + * - The other object is not null and is of the same class as Key. + * - The raw byte arrays of the keys are equal (raw.contentEquals(other.raw)). + * - The keySpecification map contains the CurveKey property and its value is equal to the value of the other key's CurveKey property. + * + * @param other The object to compare with the current Key. + * @return True if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -31,6 +42,13 @@ abstract class Key { return true } + /** + * Computes the hash code of the Key object. + * The hash code is calculated based on the properties of the keySpecification map and the raw byte array. + * Two Key objects with the same keySpecification map and the raw byte array are guaranteed to have the same hash code. + * + * @return The hash code of the Key object. + */ override fun hashCode(): Int { var result = keySpecification[CurveKey().property].hashCode() result = 31 * result + raw.contentHashCode() @@ -116,7 +134,7 @@ fun getKeyCurveByNameAndIndex(name: String, index: Int?): KeyCurve { } else -> { - throw ApolloError.InvalidKeyCurve(name, Curve.values().map { it.value }.toTypedArray()) + throw ApolloError.InvalidKeyCurve(name) } } } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyPair.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyPair.kt index fe379a950..117f64420 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyPair.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyPair.kt @@ -10,6 +10,11 @@ abstract class KeyPair { abstract var privateKey: PrivateKey abstract var publicKey: PublicKey + /** + * Returns the value of the key curve for this key pair. + * + * @return The value of the key curve. + */ fun getCurve(): String { return this.privateKey.getProperty(CurveKey().property) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyProperties.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyProperties.kt index 6c640a91c..16168c24f 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyProperties.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyProperties.kt @@ -1,20 +1,91 @@ package io.iohk.atala.prism.walletsdk.domain.models.keyManagement +/** + * The `KeyProperties` class is an abstract class that provides a framework for defining key properties. + * Each subclass of `KeyProperties` must implement the `property` property. + */ abstract class KeyProperties { abstract val property: String } +/** + * Represents a key that holds an algorithm property. + * + * @property property The value of the algorithm property. + */ class AlgorithmKey(override val property: String = "algorithm") : KeyProperties() + +/** + * Represents a key property for the curve. + * + * @property property The name of the key property. + */ class CurveKey(override val property: String = "curve") : KeyProperties() + +/** + * Represents a seed key used for deriving private keys. + * + * @param property The property name for the seed key. Default value is "seed". + */ class SeedKey(override val property: String = "seed") : KeyProperties() + +/** + * Represents a raw key with the property "raw". + * @property property The property of the raw key. + * @constructor Creates an instance of [RawKey] with the specified property, which defaults to "raw". + */ class RawKey(override val property: String = "raw") : KeyProperties() + +/** + * Represents a derivation path key. + * Inherits from the KeyProperties class. + * + * @property property The property of the derivation path key. + */ class DerivationPathKey(override val property: String = "derivationPath") : KeyProperties() + +/** + * Class representing an index key. + * @property property The property of the index key. + */ class IndexKey(override val property: String = "index") : KeyProperties() + +/** + * Represents a specific type of key with a "type" property. + * Inherits from the abstract class KeyProperties. + * + * @param property The value of the "type" property. + */ class TypeKey(override val property: String = "type") : KeyProperties() + +/** + * Class representing the CurvePointXKey. + * + * @property property The property associated with CurvePointXKey. + * @constructor Creates a CurvePointXKey object. + */ class CurvePointXKey(override val property: String = "curvePoint.x") : KeyProperties() + +/** + * Represents a key property for the y-coordinate of a curve point. + * + * @property property The name of the property. + */ class CurvePointYKey(override val property: String = "curvePoint.y") : KeyProperties() + +/** + * Represents a custom key with a specific property. + * + * @param property The property associated with the key. + */ class CustomKey(override val property: String) : KeyProperties() +/** + * Returns a KeyProperties object based on the given name. + * + * @param name The name of the key property. + * @return A KeyProperties object corresponding to the given name. + */ fun getKeyPropertyByName(name: String): KeyProperties { when (name) { AlgorithmKey().property -> { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyTypes.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyTypes.kt index 24fe30392..364f97b4f 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyTypes.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/keyManagement/KeyTypes.kt @@ -1,5 +1,10 @@ package io.iohk.atala.prism.walletsdk.domain.models.keyManagement +/** + * Enumeration class representing different types of keys. + * + * @property type The string representation of the key type. + */ enum class KeyTypes(val type: String) { EC("EC"), Curve25519("Curve25519") diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/logger/PrismLogger.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/logger/PrismLogger.kt index 5b2652659..8b2c13f23 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/logger/PrismLogger.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/logger/PrismLogger.kt @@ -4,23 +4,91 @@ import io.iohk.atala.prism.apollo.hashing.SHA256 import io.iohk.atala.prism.apollo.uuid.UUID import org.lighthousegames.logging.logging +/** + * Constant value used to represent the privacy of metadata. + * + * This constant is used in the [Metadata] class to hide sensitive information + * based on the provided [LogLevel]. When the [LogLevel] is lower than the required level + * for accessing private metadata, this constant is returned instead of the actual value. + * + * @see Metadata + */ private const val METADATA_PRIVACY_STR = "------" + +/** + * Property representing the unique identifier for the hashing log. + * The value is generated as a random UUID string. + * + * @see UUID.randomUUID4 + */ private val hashingLog = UUID.randomUUID4().toString() +/** + * PrismLogger is an interface that defines methods for logging messages + * with different log levels and metadata. + */ interface PrismLogger { + /** + * Logs a debug message with optional metadata. + * + * @param message The debug message. + * @param metadata An array of metadata objects associated with the message (optional). + */ fun debug(message: String, metadata: Array = arrayOf()) + + /** + * Logs an information message with optional metadata. + * + * @param message The information message to be logged. + * @param metadata Optional metadata to be associated with the information message. + */ fun info(message: String, metadata: Array = arrayOf()) + + /** + * Logs a warning message with optional metadata. + * + * @param message The warning message to log. + * @param metadata An array of metadata objects associated with the warning message. + */ fun warning(message: String, metadata: Array = arrayOf()) + + /** + * Logs an error message with optional metadata. + * + * @param message The error message to be logged + * @param metadata An array of Metadata objects containing additional information (optional) + */ fun error(message: String, metadata: Array = arrayOf()) + + /** + * This function is used to log an error with optional metadata. + * + * @param error The error to be logged. + * @param metadata An array of metadata objects to be included in the log message. Defaults to an empty array if not provided. + * + * @see PrismLogger.error + * @see Metadata + */ fun error(error: Error, metadata: Array = arrayOf()) } +/** + * Implementation of the PrismLogger interface. + * + * @property category the LogComponent category for this logger + */ class PrismLoggerImpl(category: LogComponent) : PrismLogger { private val log = logging("[io.prism.kmm.sdk.$category]") private var logLevel: LogLevel = LogLevel.INFO + /** + * Logs a debug message with optional metadata. + * + * @param message The debug message. + * @param metadata An array of metadata objects associated with the message (optional). + */ override fun debug(message: String, metadata: Array) { if (logLevel != LogLevel.NONE) { log.debug { message } @@ -30,6 +98,12 @@ class PrismLoggerImpl(category: LogComponent) : PrismLogger { } } + /** + * Logs an information message with optional metadata. + * + * @param message The information message to be logged. + * @param metadata An array of metadata objects to be associated with the information message. + */ override fun info(message: String, metadata: Array) { if (logLevel != LogLevel.NONE) { log.info { message } @@ -39,6 +113,12 @@ class PrismLoggerImpl(category: LogComponent) : PrismLogger { } } + /** + * Logs a warning message with optional metadata. + * + * @param message The warning message to log. + * @param metadata An array of metadata objects associated with the warning message. + */ override fun warning(message: String, metadata: Array) { if (logLevel != LogLevel.NONE) { log.warn { message } @@ -48,6 +128,12 @@ class PrismLoggerImpl(category: LogComponent) : PrismLogger { } } + /** + * Logs an error message with optional metadata. + * + * @param message The error message to be logged. + * @param metadata An array of metadata objects to be associated with the error message (optional). + */ override fun error(message: String, metadata: Array) { if (logLevel != LogLevel.NONE) { log.error { message } @@ -57,6 +143,12 @@ class PrismLoggerImpl(category: LogComponent) : PrismLogger { } } + /** + * Logs an error with optional metadata. + * + * @param error The error object to be logged. + * @param metadata An array of metadata objects associated with the error (optional). + */ override fun error(error: Error, metadata: Array) { if (logLevel != LogLevel.NONE) { log.error { error.message } @@ -66,51 +158,130 @@ class PrismLoggerImpl(category: LogComponent) : PrismLogger { } } + /** + * Converts an array of Metadata objects to a String representation. + * + * @param array An array of Metadata objects to be converted. + * @return The converted String representation of the Metadata objects, with each object's value separated by a new line. + */ private fun arrayToString(array: Array): String { return array.joinToString { "${it.getValue(logLevel)}\n" } } } +/** + * Sealed class representing different types of metadata. + * This class has several subclasses: PublicMetadata, PrivateMetadata, PrivateMetadataByLevel, MaskedMetadata, + * and MaskedMetadataByLevel. + */ sealed class Metadata { + /** + * Represents public metadata with a key-value pair. + * + * @property key The key for the metadata. + * @property value The value*/ data class PublicMetadata(val key: String, val value: String) : Metadata() { + /** + * + */ override fun toString(): String { return value } } + /** + * Data class representing private metadata. + * It extends the Metadata class. + * + * @property key The key of the metadata. + * @property value The value of the metadata. + * + * @constructor Creates a new instance of the PrivateMetadata class. + */ data class PrivateMetadata(val key: String, val value: String) : Metadata() { + /** + * Returns a string representation of the object. In this case, it returns the value of the metadata. + * + * @return The value of the metadata as a string. + */ override fun toString(): String { return value } } + /** + * Represents private metadata with a specific level. + * + * @property category The category of the log component. + * @property key The key of the metadata. + * @property value The value of the metadata. + * @property level The level of the metadata. + */ data class PrivateMetadataByLevel( val category: LogComponent, val key: String, val value: String, val level: LogLevel ) : Metadata() { + /** + * Returns a string representation of the object. In the case of the `toString` method, it returns the value of the metadata. + * + * @return The value of the metadata as a string. + */ override fun toString(): String { return value } } + /** + * Represents metadata with masked value. + * + * This class extends the abstract class Metadata and provides a masked representation + * for the value of the metadata. The mask function used is SHA256 hashing. + * + * @property key The key of the metadata. + * @property value The value of the metadata. + * @constructor Creates an instance of MaskedMetadata. + */ data class MaskedMetadata(val key: String, val value: String) : Metadata() { + /** + * Returns a string representation of the object. In this case, it returns the value of the metadata. + * + * @return The value of the metadata as a string. + */ override fun toString(): String { return value } } + /** + * Represents masked metadata with a specific level of confidentiality. + * + * @property key The key of the metadata. + * @property value The value of the metadata. + * @property level The level of confidentiality associated with the metadata. + */ data class MaskedMetadataByLevel( val key: String, val value: String, val level: LogLevel ) : Metadata() { + /** + * Returns a string representation of the object. The string representation is the value property of the object. + * + * @return The value of the object as a string. + */ override fun toString(): String { return value } } + /** + * Returns the value associated with the given LogLevel. + * + * @param level The LogLevel to check against. + * @return The value associated with the given LogLevel as a String. + */ fun getValue(level: LogLevel): String { return when (this) { is PublicMetadata -> value @@ -121,12 +292,30 @@ sealed class Metadata { } } + /** + * Computes the SHA256 hash of the input string with a masking algorithm. + * + * @param input The input string to be hashed. + * @return The SHA256 hash of the input string, represented as a hexadecimal string. + */ private fun sha256Masked(input: String): String { val sha256 = SHA256().digest((hashingLog + input).toByteArray()) return sha256.joinToString("") { "%02x".format(it) } } } +/** + * The `LogLevel` enum represents different levels of logging. + * + * The available values are: + * - INFO: Logs informational messages. + * - DEBUG: Logs debug messages, typically used for troubleshooting. + * - WARNING: Logs warning messages that indicate potential issues. + * - ERROR: Logs error messages that indicate failures or errors in the system. + * - NONE: Disables logging. + * + * @property value The numerical value associated with the log level. + */ enum class LogLevel(val value: Int) { INFO(0), DEBUG(1), @@ -135,6 +324,17 @@ enum class LogLevel(val value: Int) { NONE(4) } +/** + * The `LogComponent` enum represents the different logging components in the system. + * + * The available values are: + * - APOLLO + * - CASTOR + * - MERCURY + * - PLUTO + * - POLLUX + * - PRISM_AGENT + */ enum class LogComponent { APOLLO, CASTOR, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/MercuryImpl.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/MercuryImpl.kt index 9378ae9ef..e51f0c555 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/MercuryImpl.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/MercuryImpl.kt @@ -20,9 +20,26 @@ import io.ktor.http.HttpMethod import org.didcommx.didcomm.common.Typ import org.didcommx.didcomm.utils.isDID +/** + * The DIDCommProtocol interface provides methods for packing and unpacking DIDComm messages. + */ interface DIDCommProtocol { + /** + * Packs a given message object into a string representation. + * + * @param message The message object to pack. + * @return The string representation of the packed message. + * @throws [MercuryError.NoDIDReceiverSetError] if DIDReceiver is invalid. + * @throws [MercuryError.NoDIDSenderSetError] if DIDSender is invalid. + */ fun packEncrypted(message: Message): String + /** + * Unpacks a given string representation of a message into a [Message] object. + * + * @param message The string representation of the message to unpack. + * @return The unpacked [Message] object. + */ fun unpack(message: String): Message } @@ -171,6 +188,14 @@ class MercuryImpl( return null } + /** + * Prepares a [ForwardMessage] object to forward a message. + * + * @param message The original message to be forwarded. + * @param encrypted The encrypted representation of the message. + * @param mediatorDid The DID of the mediator. + * @return The [ForwardMessage] object with the necessary information for forwarding the message. + */ private fun prepareForwardMessage(message: Message, encrypted: String, mediatorDid: DID): ForwardMessage { return ForwardMessage( body = ForwardMessage.ForwardBody(message.to.toString()), @@ -180,6 +205,14 @@ class MercuryImpl( ) } + /** + * Makes a request to the specified service. + * + * @param service The service to make the request to + * @param message The message to send in the request + * @return The response data as a byte array + * @throws MercuryError.NoValidServiceFoundError if no valid service is found for the given service + */ @Throws(MercuryError.NoValidServiceFoundError::class) private suspend fun makeRequest(service: DIDDocument.Service?, message: String): ByteArray? { if (service !is DIDDocument.Service) { @@ -208,6 +241,14 @@ class MercuryImpl( return result.jsonString.toByteArray() } + /** + * Makes a request to the specified URI. + * + * @param uri The URI of the service to make the request to + * @param message The message to send in the request + * @return The response data as a byte array, or null if the request fails + * @throws MercuryError.NoValidServiceFoundError if no valid service is found for the given service + */ @Throws(MercuryError.NoValidServiceFoundError::class) private suspend fun makeRequest(uri: String?, message: String): ByteArray? { if (uri !is String) { @@ -234,6 +275,12 @@ class MercuryImpl( return result.jsonString.toByteArray() } + /** + * Retrieves the Mediator DID (Decentralized Identifier) from the given service. + * + * @param service The service for which to retrieve the Mediator DID. + * @return The Mediator DID, or null if it could not be found or is invalid. + */ private fun getMediatorDID(service: DIDDocument.Service?): DID? { return service?.serviceEndpoint?.uri?.let { uri -> if (isDID(uri)) { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/forward/ForwardMessage.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/forward/ForwardMessage.kt index 3e6c05009..73d5d50fa 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/forward/ForwardMessage.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/forward/ForwardMessage.kt @@ -6,11 +6,24 @@ import io.iohk.atala.prism.walletsdk.domain.models.DID import io.iohk.atala.prism.walletsdk.domain.models.Message import io.ktor.http.ContentType import kotlinx.serialization.EncodeDefault +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import java.util.UUID +/** + * The ForwardMessage class represents a message for forwarding data using the DIDComm protocol. + * It contains the necessary information for creating a forward message, including the message body, + * sender and recipient DIDs, encrypted message, and an optional ID. + * + * @param body The body of the forward message. + * @param from The sender DID of the forward message. + * @param to The recipient DID of the forward message. + * @param encryptedMessage The encrypted message to be forwarded. + * @param id The optional ID of the forward message. If not provided, a random UUID will be generated. + */ +@OptIn(ExperimentalSerializationApi::class) class ForwardMessage @JvmOverloads constructor( val body: ForwardBody, val from: DID, @@ -19,14 +32,20 @@ class ForwardMessage @JvmOverloads constructor( @EncodeDefault val id: String = UUID.randomUUID().toString() ) { + /** + * Creates a [Message] object with the provided data. + * + * @return The created [Message] object. + */ fun makeMessage(): Message { val forwardBody = Json.encodeToString(body) val attachmentData = AttachmentJsonData(encryptedMessage) - val attachment = AttachmentDescriptor(UUID.randomUUID().toString(), ContentType.Application.Json.toString(), attachmentData) + val attachment = + AttachmentDescriptor(UUID.randomUUID().toString(), ContentType.Application.Json.toString(), attachmentData) val message = Message( id = id, - piuri = type, + piuri = TYPE, from = from, to = to, body = forwardBody, @@ -36,10 +55,21 @@ class ForwardMessage @JvmOverloads constructor( return message } + /** + * Represents the body of a forward message. + * + * @property next The next message recipient's DID. + */ @Serializable data class ForwardBody(val next: String) companion object { - const val type = "https://didcomm.org/routing/2.0/forward" + /** + * The constant variable `TYPE` represents the URL of the type of forward message. + * + * @see ForwardMessage + * @see ForwardMessage.makeMessage + */ + const val TYPE = "https://didcomm.org/routing/2.0/forward" } } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommDIDResolver.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommDIDResolver.kt index 4cd02cf35..fa1ff5ced 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommDIDResolver.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommDIDResolver.kt @@ -24,7 +24,20 @@ import org.didcommx.didcomm.diddoc.DIDDocResolver import org.didcommx.didcomm.diddoc.VerificationMethod import java.util.Optional +/** + * A resolver that resolves a Decentralized Identifier (DID) to its corresponding DID Document. + * + * @param castor The instance of Castor used to resolve DIDs. + */ class DIDCommDIDResolver(val castor: Castor) : DIDDocResolver { + /** + * Resolves a DID to its corresponding DID Document. + * + * @param did The DID to resolve. + * @return An optional containing the DID Document associated with the DID, or an empty optional if the document cannot be retrieved. + * @throws [CastorError.InvalidJWKKeysError] if the JWK keys are not in a valid format. + */ + @Throws(CastorError.InvalidJWKKeysError::class) override fun resolve(did: String): Optional { return runBlocking { val doc = castor.resolveDID(did) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommSecretsResolver.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommSecretsResolver.kt index fa3f9da07..5bc863166 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommSecretsResolver.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommSecretsResolver.kt @@ -16,13 +16,32 @@ import org.didcommx.didcomm.secret.Secret import org.didcommx.didcomm.secret.SecretResolver import java.util.Optional +/** + * DIDCommSecretsResolver is a class that implements the SecretResolver interface. + * It is responsible for resolving secrets using the Pluto and Apollo components. + * + * @property pluto The Pluto component used to get DID private keys. + * @property apollo The Apollo component used for some other functionality. + */ class DIDCommSecretsResolver(val pluto: Pluto, val apollo: Apollo) : SecretResolver { + /** + * Finds the keys associated with the provided list of kid values. + * + * @param kids The list of kid values to search for. + * @return A set of keys that match the provided kid values. + */ override fun findKeys(kids: List): Set { return runBlocking { kids.filter { pluto.getDIDPrivateKeyByID(it).firstOrNull() != null }.toSet() } } + /** + * Finds a key associated with the provided kid value and returns it as an Optional. + * + * @param kid The kid value to search for. + * @return An Optional containing the key as a Secret object, or an empty Optional if no key is found. + */ override fun findKey(kid: String): Optional { return runBlocking { pluto.getDIDPrivateKeyByID(kid) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommWrapper.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommWrapper.kt index b48edcc4e..746aefda5 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommWrapper.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DIDCommWrapper.kt @@ -46,15 +46,29 @@ import org.didcommx.didcomm.utils.fromJsonToMap import java.time.Instant.now import kotlin.jvm.Throws +/** + * Wrapper class for the DIDComm functionality. + * + * @param castor The instance of Castor used for DID resolution. + * @param pluto The instance of Pluto used for secrets resolution. + * @param apollo The instance of Apollo used for secrets resolution. + */ class DIDCommWrapper(castor: Castor, pluto: Pluto, apollo: Apollo) : DIDCommProtocol { private val didDocResolver = DIDCommDIDResolver(castor) private val secretsResolver = DIDCommSecretsResolver(pluto, apollo) private val didComm = DIDComm(didDocResolver, secretsResolver) private val logger = PrismLoggerImpl(LogComponent.MERCURY) + /** + * Converts a JSON element to a map. + * + * @param element The JSON element to convert. + * @return The resulting map. + */ private fun jsonObjectToMap(element: JsonElement): Map { - var bodyMap = mutableMapOf() - if (element is JsonPrimitive) { + val bodyMap = mutableMapOf() + return if (element is JsonPrimitive) { + bodyMap } else { val keys = element.jsonObject.keys keys.forEach { key -> @@ -64,7 +78,7 @@ class DIDCommWrapper(castor: Castor, pluto: Pluto, apollo: Apollo) : DIDCommProt } is JsonArray -> { - var array = mutableListOf() + val array = mutableListOf() value.forEach { when (it) { is JsonObject -> { @@ -116,10 +130,16 @@ class DIDCommWrapper(castor: Castor, pluto: Pluto, apollo: Apollo) : DIDCommProt } } } + bodyMap } - return bodyMap } + /** + * Packs a [Message] object into an encrypted string message. + * + * @param message The [Message] object to be packed. + * @return The packed message as a string. + */ override fun packEncrypted(message: Message): String { val toString = message.to.toString() @@ -158,6 +178,12 @@ class DIDCommWrapper(castor: Castor, pluto: Pluto, apollo: Apollo) : DIDCommProt return result.packedMessage } + /** + * Parses an array of AttachmentDescriptors and converts them into a list of Attachments. + * + * @param attachments The array of AttachmentDescriptors to be parsed. + * @return The list of parsed Attachments. + */ private fun parseAttachments(attachments: Array): List { return attachments.fold(mutableListOf()) { acc, attachment -> acc.add( @@ -177,6 +203,13 @@ class DIDCommWrapper(castor: Castor, pluto: Pluto, apollo: Apollo) : DIDCommProt } } + /** + * Parse the given [AttachmentData] and return an instance of [Attachment.Data]. + * + * @throws MercuryError.UnknownAttachmentDataError if an unknown [AttachmentData] type is found + * @param data The [AttachmentData] to parse + * @return The parsed [Attachment.Data] + */ @Throws(MercuryError.UnknownAttachmentDataError::class) private fun parseAttachmentData(data: AttachmentData): Attachment.Data { if (data is AttachmentBase64) { @@ -194,6 +227,12 @@ class DIDCommWrapper(castor: Castor, pluto: Pluto, apollo: Apollo) : DIDCommProt throw MercuryError.UnknownAttachmentDataError() } + /** + * Unpacks a packed message into a domain-specific [Message] object. + * + * @param message The packed message to unpack. + * @return The unpacked [Message] object. + */ override fun unpack(message: String): Message { val result = didComm.unpack( UnpackParams( @@ -224,6 +263,13 @@ class DIDCommWrapper(castor: Castor, pluto: Pluto, apollo: Apollo) : DIDCommProt return domainMsg } + /** + * Parses a list of attachments into an array of AttachmentDescriptors. + * + * @param attachments The list of attachments to be parsed. Can be null. + * @return An array of parsed AttachmentDescriptors. + * @throws MercuryError.MessageAttachmentWithoutIDError if a message attachment is found without an "id". + */ @Throws(MercuryError.MessageAttachmentWithoutIDError::class) private fun parseAttachmentsToDomain(attachments: List?): Array { return (attachments ?: emptyList()).fold(arrayOf()) { acc, attachment -> @@ -250,6 +296,16 @@ class DIDCommWrapper(castor: Castor, pluto: Pluto, apollo: Apollo) : DIDCommProt } } + /** + * Parses the given [Attachment.Data] and converts it into an instance of [AttachmentData]. + * If the [Attachment.Data] represents base64-encoded data, it creates an instance of [AttachmentBase64]. + * If the [Attachment.Data] represents JSON data, it creates an instance of [AttachmentJsonData]. + * If the [Attachment.Data] represents a link to external data, it creates an instance of [AttachmentLinkData]. + * + * @throws MercuryError.UnknownAttachmentDataError if an unknown [Attachment.Data] type is found + * @param data The [Attachment.Data] to parse + * @return The parsed [AttachmentData] + */ @Throws(MercuryError.UnknownAttachmentDataError::class) private fun parseAttachmentDataToDomain(data: Attachment.Data): AttachmentData { val jsonObj = data.toJSONObject() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DefaultSecretsResolverImpl.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DefaultSecretsResolverImpl.kt index d5e7714ac..7c2160f8e 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DefaultSecretsResolverImpl.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/DefaultSecretsResolverImpl.kt @@ -9,8 +9,22 @@ import io.iohk.atala.prism.walletsdk.mercury.OKP import kotlinx.coroutines.flow.firstOrNull import kotlinx.serialization.Serializable +/** + * Default implementation of the [SecretsResolver] interface. + * + * @property pluto Instance of the Pluto class used for resolving secrets. + */ class DefaultSecretsResolverImpl(val pluto: Pluto) : SecretsResolver { + /** + * Represents a Private JSON Web Key (JWK). + * This class is used to hold the necessary information for a private key used in JSON Web Signature (JWS). + * + * @property kty The key type. Default value is "OKP". + * @property kid The key ID. + * @property crv The cryptographic curve used by the key. + * @property d The private key value. It is nullable and defaults to null. + */ @Serializable data class PrivateJWK @JvmOverloads constructor( val kty: String = OKP, @@ -19,6 +33,12 @@ class DefaultSecretsResolverImpl(val pluto: Pluto) : SecretsResolver { val d: String? = null ) + /** + * Finds secrets based on the provided secret IDs. + * + * @param secretIds An array of secret IDs. + * @return An array of secrets that match the provided secret IDs. + */ override suspend fun findSecrets(secretIds: Array): Array { return secretIds.filter { pluto.getDIDPrivateKeyByID(it) @@ -26,6 +46,12 @@ class DefaultSecretsResolverImpl(val pluto: Pluto) : SecretsResolver { }.toTypedArray() } + /** + * Retrieves a secret based on its ID. + * + * @param secretId The ID of the secret. + * @return The secret object if found, otherwise null. + */ override suspend fun getSecret(secretId: String): Secret? { return pluto.getDIDPrivateKeyByID(secretId).firstOrNull()?.let { privateKey -> return Secret( diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/SecretsResolver.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/SecretsResolver.kt index 3204b0768..10a2ae551 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/SecretsResolver.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/mercury/resolvers/SecretsResolver.kt @@ -2,7 +2,23 @@ package io.iohk.atala.prism.walletsdk.mercury.resolvers import io.iohk.atala.prism.walletsdk.domain.models.Secret +/** + * Resolves secrets by finding secrets based on secret IDs or retrieving a specific secret by its ID. + */ interface SecretsResolver { + /** + * Asynchronously finds secrets based on the provided secret IDs. + * + * @param secretIds An array of secret IDs to be searched. + * @return An array of strings representing the secret values found. + */ suspend fun findSecrets(secretIds: Array): Array + + /** + * Suspends the execution until the secret with the given secretId is retrieved. + * + * @param secretId The ID of the secret to retrieve. + * @return The secret with the specified ID, or null if the secret does not exist. + */ suspend fun getSecret(secretId: String): Secret? } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/CredentialRecovery.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/CredentialRecovery.kt index 843ae597f..16f8d7ec7 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/CredentialRecovery.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/CredentialRecovery.kt @@ -1,3 +1,9 @@ package io.iohk.atala.prism.walletsdk.pluto +/** + * Class representing a credential recovery object. + * + * @property restorationId The restoration ID associated with the credential recovery. + * @property credentialData The credential data as a byte array. + */ class CredentialRecovery(val restorationId: String, val credentialData: ByteArray) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/PlutoImpl.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/PlutoImpl.kt index 82252a507..aba703f6d 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/PlutoImpl.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/PlutoImpl.kt @@ -39,14 +39,31 @@ import ioiohkatalaprismwalletsdkpluto.data.Message as MessageDB import ioiohkatalaprismwalletsdkpluto.data.PrivateKey as PrivateKeyDB import ioiohkatalaprismwalletsdkpluto.data.StorableCredential as StorableCredentialDB +/** + * `PlutoImpl` is a class that provides an implementation of the Pluto interface for interacting with the database. + * + * @property db The instance of `PrismPlutoDb` representing the connection to the database. + * @property isConnected A flag to indicate whether the database connection is established or not. + */ class PlutoImpl(private val connection: DbConnection) : Pluto { private var db: PrismPlutoDb? = null + /** + * isConnected indicates whether the connection to the database is currently established or not. + * + * @return true if the connection is established, false otherwise + */ val isConnected: Boolean get() { return this.connection.driver?.isConnected ?: false } + /** + * Starts the database service. + * + * @param context The context data required for establishing the connection. This can be null in some cases. + * @throws PlutoError.DatabaseServiceAlreadyRunning if the database service is already running. + */ @Throws(PlutoError.DatabaseServiceAlreadyRunning::class) @JvmOverloads public suspend fun start(context: Any? = null) { @@ -56,6 +73,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { this.db = this.connection.connectDb(context) } + /** + * Closes the connection to the database. + * + * @throws PlutoError.DatabaseConnectionError if there is an error with the database connection + */ @Throws(PlutoError.DatabaseConnectionError::class) public fun stop() { val driver = this.connection.driver ?: throw PlutoError.DatabaseConnectionError() @@ -63,11 +85,26 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { driver.close() } + /** + * Retrieves an instance of the PrismPlutoDb object. + * Throws DatabaseConnectionError if the database connection is not established. + * + * @throws PlutoError.DatabaseConnectionError if the database connection is not established + * @return the PrismPlutoDb instance + */ @Throws(PlutoError.DatabaseConnectionError::class) private fun getInstance(): PrismPlutoDb { return this.db ?: throw PlutoError.DatabaseConnectionError() } + /** + * Stores the Prism DID, key path index, alias, and private keys. + * + * @param did The Prism DID to store. + * @param keyPathIndex The key path index. + * @param alias The optional alias for the Prism DID. + * @param privateKeys The list of private keys to store. + */ override fun storePrismDIDAndPrivateKeys( did: DID, keyPathIndex: Int, @@ -88,6 +125,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Stores the PeerDID in the system. + * + * @param did The PeerDID to store. + */ override fun storePeerDID(did: DID) { getInstance().dIDQueries.insert( DIDDB( @@ -100,6 +142,13 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { ) } + /** + * Stores a pair of Distributed Identifier (DID) and a receiver DID with a given name. + * + * @param host The host DID to store. + * @param receiver The receiver DID to store. + * @param name The name of the stored pair. + */ override fun storeDIDPair(host: DID, receiver: DID, name: String) { getInstance().dIDPairQueries.insert( DIDPairDB( @@ -111,6 +160,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { ) } + /** + * Stores a message in the system. + * + * @param message The message to store. + */ override fun storeMessage(message: Message) { getInstance().messageQueries.insert( MessageDB( @@ -126,6 +180,14 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { ) } + /** + * Stores the private key along with additional information. + * + * @param privateKey The private key to store. Must implement the [StorableKey] interface. + * @param did The DID associated with the private key. + * @param keyPathIndex The key path index. + * @param metaId The optional metadata ID. + */ override fun storePrivateKeys( storableKey: StorableKey, did: DID, @@ -160,12 +222,24 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Stores a list of messages in the system. + * + * @param messages The list of messages to store. + */ override fun storeMessages(messages: List) { messages.map { message -> storeMessage(message) } } + /** + * Stores a mediator in the system. + * + * @param mediator The mediator DID to store. + * @param host The host DID associated with the mediator. + * @param routing The routing DID for the mediator. + */ override fun storeMediator(mediator: DID, host: DID, routing: DID) { val instance = getInstance() instance.dIDQueries.insert( @@ -196,6 +270,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { ) } + /** + * Stores a credential in the system. + * + * @param credential The credential to store. It must implement the [StorableCredential] interface. + */ override fun storeCredential(storableCredential: StorableCredential) { getInstance().storableCredentialQueries.insert( StorableCredentialDB( @@ -218,11 +297,21 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Stores a link secret in the system. + * + * @param linkSecret The link secret to store. + */ override fun storeLinkSecret(linkSecret: String) { getInstance().linkSecretQueries .insert(LinkSecretDB(linkSecret)) } + /** + * Stores the metadata associated with a credential request. + * + * @param metadata The metadata to store. It must be an instance of [CredentialRequestMeta]. + */ override fun storeCredentialMetadata(metadata: CredentialRequestMeta) { getInstance().credentialMetadataQueries.insert( id = UUID.randomUUID4().toString(), @@ -232,6 +321,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { ) } + /** + * Retrieves all PrismDIDs and their associated information. + * + * @return A flow of lists of [PrismDIDInfo] objects representing the PrismDIDs and their information. + */ override fun getAllPrismDIDs(): Flow> { return getInstance().dIDQueries .fetchAllPrismDID() @@ -244,6 +338,13 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the [PrismDIDInfo] associated with a given [DID]. + * + * @param did The [DID] for which to retrieve the [PrismDIDInfo]. + * @return A [Flow] that emits a nullable [PrismDIDInfo] object representing the [PrismDIDInfo] associated + * with the specified [DID]. If no [PrismDIDInfo] is found, null is emitted. + */ @OptIn(ExperimentalCoroutinesApi::class) override fun getDIDInfoByDID(did: DID): Flow { return getInstance().dIDQueries @@ -259,6 +360,13 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the [PrismDIDInfo] objects associated with a given alias. + * + * @param alias The alias for which to retrieve the [PrismDIDInfo] objects. + * @return A [Flow] that emits a list of [PrismDIDInfo] objects representing the + * [PrismDIDInfo] associated with the specified alias. + */ override fun getDIDInfoByAlias(alias: String): Flow> { return getInstance().dIDQueries .fetchDIDInfoByAlias(alias) @@ -271,6 +379,12 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves a list of private keys associated with a given DID. + * + * @param did The DID for which to retrieve private keys. + * @return A flow that emits a list of nullable [PrivateKey] objects. In case a private key is not found, null is emitted. + */ override fun getDIDPrivateKeysByDID(did: DID): Flow> { return getInstance().privateKeyQueries .fetchPrivateKeyByDID(did.toString()) @@ -299,11 +413,18 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the private key associated with a given ID. + * + * @param id The ID of the private key. + * @return A [Flow] that emits the private key as a nullable [PrivateKey] object. If no private key is found, + * null is emitted. + */ override fun getDIDPrivateKeyByID(id: String): Flow { return getInstance().privateKeyQueries .fetchPrivateKeyByID(id) .asFlow() - .map { it -> + .map { it.executeAsList().firstOrNull()?.let { storableKey -> when (storableKey.restorationIdentifier) { "secp256k1+priv" -> { @@ -326,6 +447,13 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the key path index associated with a given Prism DID. + * + * @param did The Prism DID for which to retrieve the key path index. + * @return A [Flow] that emits a nullable [Int] representing the key path index associated with the specified Prism DID. + * If no key path index is found, null is emitted. + */ override fun getPrismDIDKeyPathIndex(did: DID): Flow { return getInstance().privateKeyQueries.fetchKeyPathIndexByDID(did.toString()) .asFlow() @@ -338,6 +466,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the last key path index associated with the Prism DID. + * + * @return A [Flow] that emits an [Int] representing the last key path index associated with the Prism DID. + */ override fun getPrismLastKeyPathIndex(): Flow { return getInstance().privateKeyQueries.fetchLastkeyPathIndex() .asFlow() @@ -346,6 +479,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves all PeerDIDs. + * + * @return A flow of lists of PeerDIDs. + */ override fun getAllPeerDIDs(): Flow> { return getInstance().dIDQueries.fetchAllPeerDID() .asFlow() @@ -353,8 +491,8 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { allDIDs.executeAsList() .groupBy { allPeerDid -> allPeerDid.did } .map { - println("Restoration ID: ${it.value.get(0).restorationIdentifier}") - val privateKeyList: Array = it.value.mapNotNull { allPeerDID -> + println("Restoration ID: ${it.value[0].restorationIdentifier}") + val privateKeyList: Array = it.value.map { allPeerDID -> when (allPeerDID.restorationIdentifier) { "secp256k1+priv" -> { Secp256k1PrivateKey(allPeerDID.data_.base64UrlDecodedBytes) @@ -378,6 +516,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves all the pairs of DIDs stored in the system. + * + * @return a [Flow] emitting a list of [DIDPair] objects representing the pairs of DIDs. + */ override fun getAllDidPairs(): Flow> { return getInstance().dIDPairQueries.fetchAllDIDPairs() .asFlow() @@ -387,6 +530,13 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves a DIDPair object using the provided DID. + * + * @param did The DID to search for. + * @return A Flow of DIDPair objects. If a match is found, the flow emits the matching DIDPair. + * If no match is found, the flow emits null. + */ override fun getPairByDID(did: DID): Flow { return getInstance().dIDPairQueries.fetchDIDPairByDID(did.toString()) .asFlow() @@ -400,6 +550,13 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieve a [DIDPair] from a flow by its name. + * + * @param name The name of the [DIDPair] to retrieve. + * @return A [Flow] emitting the [DIDPair] object that matches the given name, + * or `null` if no matching [DIDPair] is found. + */ override fun getPairByName(name: String): Flow { return getInstance().dIDPairQueries.fetchDIDPairByName(name) .asFlow() @@ -413,6 +570,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves all the messages. + * + * @return a Flow of List of Message objects representing all the messages. + */ override fun getAllMessages(): Flow> { return getInstance().messageQueries.fetchAllMessages() .asFlow() @@ -439,10 +601,23 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves all messages based on the provided DID. + * + * @param did The DID (Direct Inward Dialing) to filter messages by. + * @return A flow of list of messages. + */ override fun getAllMessages(did: DID): Flow> { return getAllMessages(did, did) } + /** + * Retrieves all messages exchanged between the specified 'from' and 'to' DIDs. + * + * @param from the sender DID + * @param to the receiver DID + * @return a Flow emitting a list of messages exchanged between the 'from' and 'to' DIDs + */ override fun getAllMessages(from: DID, to: DID): Flow> { return getInstance().messageQueries.fetchAllMessagesFromTo(from.toString(), to.toString()) .asFlow() @@ -469,6 +644,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves all the messages that have been sent. + * + * @return A [Flow] of type [List] containing the sent messages. + */ override fun getAllMessagesSent(): Flow> { return getInstance().messageQueries.fetchAllSentMessages() .asFlow() @@ -495,6 +675,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves all messages received by the user. + * + * @return A [Flow] emitting a list of [Message] objects representing all the messages received. + */ override fun getAllMessagesReceived(): Flow> { return getInstance().messageQueries.fetchAllReceivedMessages() .asFlow() @@ -521,6 +706,12 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves all messages sent to the specified DID. + * + * @param did the destination DID to filter the messages by + * @return a [Flow] of [List] of [Message] objects containing all the messages sent to the specified DID + */ override fun getAllMessagesSentTo(did: DID): Flow> { return getInstance().messageQueries.fetchAllMessagesSentTo(did.toString()) .asFlow() @@ -547,6 +738,12 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Returns a Flow of lists of all messages received from the specified DID. + * + * @param did the DID (Decentralized Identifier) to get the received messages from + * @return a Flow of lists of messages received from the specified DID + */ override fun getAllMessagesReceivedFrom(did: DID): Flow> { return getInstance().messageQueries.fetchAllMessagesReceivedFrom(did.toString()) .asFlow() @@ -573,6 +770,13 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves all messages of a specific type that are related to a given DID. + * + * @param type The type of the messages to retrieve. + * @param relatedWithDID The optional DID to which the messages are related. + * @return A [Flow] emitting a list of [Message] objects that match the given type and are related to the specified DID. + */ override fun getAllMessagesOfType(type: String, relatedWithDID: DID?): Flow> { return getInstance().messageQueries.fetchAllMessagesOfType( type, @@ -602,6 +806,13 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the message with the specified ID. + * + * @param id The unique ID of the message. + * @return A [Flow] that emits the message with the specified ID, or null if no such message exists. + * The [Flow] completes when the message is successfully retrieved, or when an error occurs. + */ override fun getMessage(id: String): Flow { return getInstance().messageQueries.fetchMessageById(id) .asFlow() @@ -630,11 +841,16 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Returns a Flow of lists of [Mediator] objects representing all the available mediators. + * + * @return a Flow of lists of [Mediator] objects. + */ override fun getAllMediators(): Flow> { return getInstance().mediatorQueries.fetchAllMediators() .asFlow() - .map { - val fetchAllMediators = it.executeAsList() + .map { query -> + val fetchAllMediators = query.executeAsList() fetchAllMediators.map { Mediator( it.id, @@ -646,6 +862,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves all credentials for credential recovery. + * + * @return A flow of a list of [CredentialRecovery] objects representing the credentials for recovery. + */ override fun getAllCredentials(): Flow> { return getInstance().storableCredentialQueries.fetchAllCredentials() .asFlow() @@ -659,10 +880,22 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Inserts an available claim for a specific credential. + * + * @param credentialId The ID of the credential. + * @param claim The claim to insert. + */ override fun insertAvailableClaim(credentialId: String, claim: String) { getInstance().availableClaimsQueries.insert(credentialId, claim) } + /** + * Inserts the available claims for a given credential ID. + * + * @param credentialId the ID of the credential + * @param claims an array of available claims to be inserted + */ override fun insertAvailableClaims(credentialId: String, claims: Array) { getInstance().availableClaimsQueries.transaction { claims.forEach { @@ -671,6 +904,12 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the available claims for a given credential ID. + * + * @param credentialId The ID of the credential. + * @return A flow that emits an array of AvailableClaims. + */ override fun getAvailableClaimsByCredentialId(credentialId: String): Flow> { return getInstance().availableClaimsQueries.fetchAvailableClaimsByCredentialId(credentialId) .asFlow() @@ -679,6 +918,12 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the available claims for a given claim. + * + * @param claim The claim for which the available claims are to be retrieved. + * @return A flow of arrays of AvailableClaims representing the available claims for the given claim. + */ override fun getAvailableClaimsByClaim(claim: String): Flow> { return getInstance().availableClaimsQueries.fetchAvailableClaimsByClaim(claim) .asFlow() @@ -687,6 +932,11 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the secret link associated with the current instance. + * + * @return A [Flow] emitting the secret link as a nullable [String]. + */ override fun getLinkSecret(): Flow { return getInstance().linkSecretQueries.fetchLinkSecret() .asFlow() @@ -700,6 +950,13 @@ class PlutoImpl(private val connection: DbConnection) : Pluto { } } + /** + * Retrieves the metadata associated with a credential request. + * + * @param linkSecretName The name of the link secret used for the credential request. + * @return A [Flow] emitting the [CredentialRequestMeta] object for the specified link secret name, + * or null if no metadata is found. + */ override fun getCredentialMetadata(linkSecretName: String): Flow { return getInstance().credentialMetadataQueries.fetchCredentialMetadata(linkSecretName = linkSecretName) .asFlow() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/data/DbConnection.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/data/DbConnection.kt index 56d29f1e1..11f46351c 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/data/DbConnection.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pluto/data/DbConnection.kt @@ -3,9 +3,23 @@ package io.iohk.atala.prism.walletsdk.pluto.data import com.squareup.sqldelight.db.SqlDriver import io.iohk.atala.prism.walletsdk.PrismPlutoDb +/** + * DbConnection class represents a connection to the database. + */ expect class DbConnection() { var driver: SqlDriver? + + /** + * Establishes a connection to the database. + * + * @param context The context data required for establishing the connection. This can be null in some cases. + * + * @return The PrismPlutoDb instance representing the connection to the database. + */ suspend fun connectDb(context: Any?): PrismPlutoDb } +/** + * Represents the current connection status of the SQL driver. + */ expect val SqlDriver.isConnected: Boolean diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/PolluxImpl.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/PolluxImpl.kt index 135b9088b..bccb6a502 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/PolluxImpl.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/PolluxImpl.kt @@ -45,12 +45,21 @@ import java.security.interfaces.ECPrivateKey import java.security.spec.ECParameterSpec import java.security.spec.ECPrivateKeySpec +/** + * Class representing the implementation of the Pollux interface. + * + * @property castor An API object for interacting with the Castor system. + */ class PolluxImpl( val castor: Castor, private val api: Api = ApiImpl(httpClient()) ) : Pollux { - @Throws(PolluxError.InvalidJWTString::class, PolluxError.InvalidCredentialError::class) + /** + * Parses a verifiable credential from the given data. + * + * @param data The data representing the*/ + @Throws(PolluxError.InvalidCredentialError::class) fun parseVerifiableCredential(data: String): Credential { return try { JWTCredential(data) @@ -63,6 +72,15 @@ class PolluxImpl( } } + /** + * Parses the given JSON data into a verifiable credential of the specified type. + * + * @param jsonData The JSON data representing the verifiable credential. + * @param type The type of the verifiable credential. + * @param linkSecret The optional link secret for the credential. + * @param credentialMetadata The metadata for the credential request. + * @return The parsed credential. + */ override suspend fun parseCredential( jsonData: String, type: CredentialType, @@ -108,6 +126,13 @@ class PolluxImpl( } } + /** + * Restores a credential using the provided restoration identifier and credential data. + * + * @param restorationIdentifier The restoration identifier of the credential. + * @param credentialData The byte array containing the credential data. + * @return The restored credential. + */ override fun restoreCredential( restorationIdentifier: String, credentialData: ByteArray @@ -131,6 +156,15 @@ class PolluxImpl( } } + /** + * Creates a verifiable presentation JSON Web Token (JWT) for the given subjectDID, privateKey, credential, and requestPresentationJson. + * + * @param subjectDID The DID of the subject for whom the presentation is being created. + * @param privateKey The private key used to sign the JWT. + * @param credential The credential to be included in the presentation. + * @param requestPresentationJson The JSON object representing the request presentation. + * @return The created verifiable presentation JWT. + */ @Throws(PolluxError.NoDomainOrChallengeFound::class) override fun processCredentialRequestJWT( subjectDID: DID, @@ -143,6 +177,15 @@ class PolluxImpl( return signClaimsRequestCredentialJWT(subjectDID, parsedPrivateKey, domain, challenge) } + /** + * Creates a verifiable presentation JSON Web Token (JWT) for the given subjectDID, privateKey, credential, and requestPresentationJson. + * + * @param subjectDID The DID of the subject for whom the presentation is being created. + * @param privateKey The private key used to sign the JWT. + * @param credential The credential to be included in the presentation. + * @param requestPresentationJson The JSON object representing the request presentation. + * @return The created verifiable presentation JWT. + */ @Throws(PolluxError.NoDomainOrChallengeFound::class) override fun createVerifiablePresentationJWT( subjectDID: DID, @@ -164,6 +207,13 @@ class PolluxImpl( ) } + /** + * Converts a [Credential] object to a [StorableCredential] object of the specified [CredentialType]. + * + * @param type The type of the [StorableCredential]. + * @param credential The [Credential] object to be converted. + * @return The converted [StorableCredential]. + */ override fun credentialToStorableCredential( type: CredentialType, credential: Credential @@ -187,6 +237,12 @@ class PolluxImpl( } } + /** + * Extracts the credential format from the given array of attachment descriptors. + * + * @param formats The array of attachment descriptors. + * @return The credential format as a CredentialType enum value. + */ override fun extractCredentialFormatFromMessage(formats: Array): CredentialType { val desiredFormats = setOf( CredentialType.JWT.type, @@ -206,6 +262,15 @@ class PolluxImpl( } ?: throw Error("Unknown credential type") } + /** + * Processes a credential request for anonymous credentials. + * + * @param did The DID of the subject requesting the credential. + * @param offer The credential offer. + * @param linkSecret The link secret for the credential. + * @param linkSecretName The name of the link secret. + * @return A pair containing the credential request and its metadata. + */ override suspend fun processCredentialRequestAnoncreds( did: DID, offer: CredentialOffer, @@ -223,6 +288,16 @@ class PolluxImpl( ) } + /** + * Creates a credential request for anonymous credentials. + * + * @param did The DID of the subject requesting the credential. + * @param credentialDefinition The credential definition. + * @param credentialOffer The credential offer. + * @param linkSecret The link secret for the credential. + * @param linkSecretId The name of the link secret. + * @return A Pair containing the CredentialRequest and CredentialRequestMetadata. + */ private fun createAnonCredentialRequest( did: DID, credentialDefinition: CredentialDefinition, @@ -241,6 +316,12 @@ class PolluxImpl( return Pair(credentialRequest.request, credentialRequest.metadata) } + /** + * Retrieves the credential definition for the specified ID. + * + * @param id The ID of the credential definition. + * @return The credential definition. + */ override suspend fun getCredentialDefinition(id: String): CredentialDefinition { val result = api.request( HttpMethod.Get.value, @@ -255,6 +336,12 @@ class PolluxImpl( throw PolluxError.InvalidCredentialDefinitionError() } + /** + * Parses a PrivateKey into an ECPrivateKey. + * + * @param privateKey The PrivateKey to parse. + * @return The parsed ECPrivateKey. + */ private fun parsePrivateKey(privateKey: PrivateKey): ECPrivateKey { val curveName = KMMEllipticCurve.SECP256k1.value val sp = ECNamedCurveTable.getParameterSpec(curveName) @@ -264,50 +351,54 @@ class PolluxImpl( return keyFactory.generatePrivate(privateKeySpec) as ECPrivateKey } + /** + * Returns the domain from the given JsonObject. + * + * @param jsonObject The JsonObject from which to retrieve the domain. + * @return The domain as a String, or null if not found. + */ private fun getDomain(jsonObject: JsonObject): String? { return jsonObject[OPTIONS]?.jsonObject?.get(DOMAIN)?.jsonPrimitive?.content } + /** + * Retrieves the challenge value from the given JsonObject. + * + * @param jsonObject The JsonObject from which to retrieve the challenge. + * @return The challenge value as a String, or null if not found in the JsonObject. + */ private fun getChallenge(jsonObject: JsonObject): String? { return jsonObject[OPTIONS]?.jsonObject?.get(CHALLENGE)?.jsonPrimitive?.content } + /** + * Signs the claims for a request credential JWT. + * + * @param subjectDID The DID of the subject for whom the JWT is being created. + * @param privateKey The private key used to sign the JWT. + * @param domain The domain of the JWT. + * @param challenge The challenge value for the JWT. + * @return The signed JWT as a string. + */ private fun signClaimsRequestCredentialJWT( subjectDID: DID, privateKey: ECPrivateKey, domain: String, challenge: String ): String { - // Define the JWT claims - val vp = mapOf( - CONTEXT to setOf(CONTEXT_URL), - TYPE to setOf(VERIFIABLE_PRESENTATION) - ) - val claims = JWTClaimsSet.Builder() - .issuer(subjectDID.toString()) - .audience(domain) - .claim(NONCE, challenge) - .claim(VP, vp) - .build() - - // Generate a JWS header with the ES256K algorithm - val header = JWSHeader.Builder(JWSAlgorithm.ES256K) - .build() - - // Sign the JWT with the private key - val jwsObject = SignedJWT(header, claims) - val signer = ECDSASigner( - privateKey as java.security.PrivateKey, - com.nimbusds.jose.jwk.Curve.SECP256K1 - ) - val provider = BouncyCastleProviderSingleton.getInstance() - signer.jcaContext.provider = provider - jwsObject.sign(signer) - - // Serialize the JWS object to a string - return jwsObject.serialize() + return signClaims(subjectDID, privateKey, domain, challenge) } + /** + * Signs the claims for a proof presentation JSON Web Token (JWT). + * + * @param subjectDID The DID of the subject for whom the JWT is being created. + * @param privateKey The private key used to sign the JWT. + * @param credential The credential to be included in the presentation. + * @param domain The domain of the JWT. + * @param challenge The challenge value for the JWT. + * @return The signed JWT as a string. + */ private fun signClaimsProofPresentationJWT( subjectDID: DID, privateKey: ECPrivateKey, @@ -315,15 +406,36 @@ class PolluxImpl( domain: String, challenge: String ): String { - // Define the JWT claims - val vp = mapOf( + return signClaims(subjectDID, privateKey, domain, challenge, credential) + } + + /** + * Signs the claims for a JWT. + * + * @param subjectDID The DID of the subject for whom the JWT is being created. + * @param privateKey The private key used to sign the JWT. + * @param domain The domain of the JWT. + * @param challenge The challenge value for the JWT. + * @param credential The optional credential to be included in the JWT. + * @return The signed JWT as a string. + */ + private fun signClaims( + subjectDID: DID, + privateKey: ECPrivateKey, + domain: String, + challenge: String, + credential: Credential? = null + ): String { + val vp: MutableMap> = mutableMapOf( CONTEXT to setOf(CONTEXT_URL), - TYPE to setOf(VERIFIABLE_PRESENTATION), - VERIFIABLE_CREDENTIAL to listOf(credential.id) + TYPE to setOf(VERIFIABLE_PRESENTATION) ) + credential?.let { + vp[VERIFIABLE_CREDENTIAL] = listOf(it.id) + } val claims = JWTClaimsSet.Builder() - .audience(domain) .issuer(subjectDID.toString()) + .audience(domain) .claim(NONCE, challenge) .claim(VP, vp) .build() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/AnonCredential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/AnonCredential.kt index 4b3d981a4..d8ab731ff 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/AnonCredential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/AnonCredential.kt @@ -8,8 +8,24 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +/** + * Represents an anonymous verifiable credential that contains information about an entity or identity. + * + * This class implements the [Credential] interface and provides methods for converting the credential + * to a storable format and restoring it from a storable format. + * + * @param schemaID The ID of the credential's schema. + * @param credentialDefinitionID The ID of the credential's definition. + * @param values The values of the attributes in the credential. + * @param signatureJson The JSON representation of the credential's signature. + * @param signatureCorrectnessProofJson The JSON representation of the credential's signature correctness proof. + * @param revocationRegistryId The ID of the credential's revocation registry (optional). + * @param revocationRegistryJson The JSON representation of the credential's revocation registry (optional). + * @param witnessJson The JSON representation of the credential's witness. + * @param json The JSON representation of the credential. + */ @Serializable -data class AnonCredential constructor( +data class AnonCredential( val schemaID: String, val credentialDefinitionID: String, val values: Map, @@ -21,6 +37,12 @@ data class AnonCredential constructor( private val json: String ) : Credential { + /** + * Represents an attribute in a verifiable credential. + * + * @property raw The raw value of the attribute as a string. + * @property encoded The encoded value of the attribute as a string. + */ @Serializable data class Attribute( val raw: String, @@ -30,22 +52,18 @@ data class AnonCredential constructor( override val id: String get() = json - override - val issuer: String + override val issuer: String get() = "" - override - val subject: String? + override val subject: String? get() = null - override - val claims: Array + override val claims: Array get() = values.map { Claim(key = it.key, value = ClaimType.StringValue(it.value.raw)) }.toTypedArray() - override - val properties: Map + override val properties: Map get() { val properties = mutableMapOf() properties["schemaID"] = this.schemaID @@ -60,6 +78,11 @@ data class AnonCredential constructor( return properties.toMap() } + /** + * Converts the current credential object into a storable credential object. + * + * @return The converted storable credential object. + */ fun toStorableCredential(): StorableCredential { val c = this return object : StorableCredential { @@ -102,6 +125,11 @@ data class AnonCredential constructor( override val availableClaims: Array get() = c.claims.map { it.key }.toTypedArray() + /** + * Converts a storable credential to a regular credential. + * + * @return The converted Credential object. + */ override fun fromStorableCredential(): Credential { return c } @@ -109,6 +137,13 @@ data class AnonCredential constructor( } companion object { + /** + * Converts a byte array of storable credential data to an AnonCredential object. + * + * @param data The byte array containing the storable credential data. + * @return The converted AnonCredential object. + */ + @JvmStatic fun fromStorableData(data: ByteArray): AnonCredential { val dataString = data.decodeToString() val cred = Json.decodeFromString(dataString) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/AnoncredPayload.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/AnoncredPayload.kt index df24f543f..3accb535d 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/AnoncredPayload.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/AnoncredPayload.kt @@ -2,6 +2,15 @@ package io.iohk.atala.prism.walletsdk.pollux.models import kotlinx.serialization.SerialName +/** + * Represents the payload of an anonymous credential. + * + * @property schemaId The ID of the schema associated with the credential. + * @property credDefId The ID of the credential definition associated with the credential. + * @property keyCorrectnessProof The proof of correctness of the public key used for signing the credential. + * @property nonce The cryptographic nonce used for the proof of correctness. + * @property methodName The method name for the anonymous credential. + */ data class AnoncredPayload( @SerialName("schema_id") val schemaId: String, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/CredentialRequest.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/CredentialRequest.kt index da2131738..8bfce8f15 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/CredentialRequest.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/CredentialRequest.kt @@ -6,6 +6,15 @@ import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +/** + * The `CredentialRequest` interface represents a request for verifiable credentials. + * + * @property cred_def_id The ID of the credential definition. + * @property blinded_ms The blinded master secret for the credential request. + * @property blinded_ms_correctness_proof The correctness proof for the blinded master secret. + * @property entropy The entropy for the credential request. + * @property nonce The nonce for the credential request. + */ interface CredentialRequest { val cred_def_id: String val blinded_ms: CredentialRequestBlindedMS @@ -14,17 +23,34 @@ interface CredentialRequest { val nonce: String } +/** + * Represents the blinded master secret used in the credential request. + */ interface CredentialRequestBlindedMS { val u: String val ur: String } +/** + * This interface represents a blinded master secret correctness proof for a credential request. + * + * @property c The blinded master secret contribution to the proof. + * @property v_dash_cap The value used in the proof calculation. + * @property m_caps The map of attribute names to their corresponding blinded value commitments. + */ interface CredentialRequestBlindedMSCorrectnessProof { val c: String val v_dash_cap: String val m_caps: Map } +/** + * Represents the blinding data used in the Link-Secret protocol. + * This class is serialized and deserialized using Kotlinx Serialization library. + * + * @param vPrime The blinding factor generated by the Holder and sent to the Issuer. + * @param vrPrime The blinded master secret generated by the Holder. Default value is null. + */ @Serializable data class LinkSecretBlindingData @OptIn(ExperimentalSerializationApi::class) @@ -36,6 +62,15 @@ constructor( var vrPrime: String? = null ) +/** + * Represents a credential definition. + * + * @property schemaId The unique identifier of the schema associated with the credential definition. + * @property type The type of the credential definition. + * @property tag The tag associated with the credential definition. + * @property value An array of values associated with the credential definition. + * @property issuerId The unique identifier of the issuer of the credential definition. + */ data class CredentialDefinition( val schemaId: String, val type: String, @@ -43,6 +78,19 @@ data class CredentialDefinition( val value: Array, val issuerId: String ) { + /** + * Checks if this CredentialDefinition object is equal to the specified object. + * + * Two CredentialDefinition objects are considered equal if they have the same values for the following properties: + * - [schemaId] + * - [type] + * - [tag] + * - [value] + * - [issuerId] + * + * @param other The object to compare with this CredentialDefinition object. + * @return true if the specified object is equal to this CredentialDefinition object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -58,6 +106,18 @@ data class CredentialDefinition( return true } + /** + * Calculates the hash code of the [CredentialDefinition] object. + * + * The hash code is computed based on the values of the following properties: + * - [schemaId] + * - [type] + * - [tag] + * - [value] + * - [issuerId] + * + * @return The hash code of the [CredentialDefinition] object. + */ override fun hashCode(): Int { var result = schemaId.hashCode() result = 31 * result + type.hashCode() @@ -68,10 +128,21 @@ data class CredentialDefinition( } } +/** + * Represents an interface for a verifiable credential that has been issued. + * + * Implementing classes are expected to provide implementation for all properties + * and functions defined in this interface. + */ interface CredentialIssued : Credential { val values: List> } +/** + * Represents a credential value, which consists of an encoded value and its raw value. + * + * Implementing classes are expected to provide implementation for both [encoded] and [raw] properties. + */ interface CredentialValue { val encoded: String val raw: String diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/CredentialRequestMeta.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/CredentialRequestMeta.kt index 1a44437b8..3210865a9 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/CredentialRequestMeta.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/CredentialRequestMeta.kt @@ -1,15 +1,28 @@ package io.iohk.atala.prism.walletsdk.pollux.models import anoncreds_wrapper.CredentialRequestMetadata -import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json +/** + * Represents the metadata for a credential request. + * + * @property linkSecretBlindingData The blinding data used in the Link-Secret protocol. + * @property linkSecretName The name of the link secret. + * @property nonce The nonce value. + */ data class CredentialRequestMeta( var linkSecretBlindingData: LinkSecretBlindingData, var linkSecretName: String, var nonce: String ) { companion object { + /** + * Converts a [CredentialRequestMetadata] object into a [CredentialRequestMeta] object. + * + * @param metadata The [CredentialRequestMetadata] object to convert. + * @return The converted [CredentialRequestMeta] object. + */ + @JvmStatic fun fromCredentialRequestMetadata(metadata: CredentialRequestMetadata): CredentialRequestMeta { return CredentialRequestMeta( linkSecretName = metadata.linkSecretName, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/JWTCredential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/JWTCredential.kt index d19cd84c3..18b51af5e 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/JWTCredential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/JWTCredential.kt @@ -9,6 +9,16 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import java.util.Base64 +/** + * Represents a JSON Web Token (JWT) credential. + * + * This class provides a way to parse and extract information from a JWT string. + * It implements the Credential interface and provides implementations for all its properties and functions. + * + * @property data The original JWT string representation of the credential. + * @property jwtString The JWT string representation of the credential. + * @property jwtPayload The parsed JWT payload containing the credential information. + */ data class JWTCredential(val data: String) : Credential { private var jwtString: String = data var jwtPayload: JWTPayload @@ -67,6 +77,11 @@ data class JWTCredential(val data: String) : Credential { return properties.toMap() } + /** + * Converts the current instance of [JWTCredential] to a [StorableCredential]. + * + * @return The converted [StorableCredential]. + */ fun toStorableCredential(): StorableCredential { val c = this return object : StorableCredential { @@ -129,6 +144,11 @@ data class JWTCredential(val data: String) : Credential { return properties.toMap() } + /** + * Converts the current instance of [JWTCredential] to a [Credential]. + * + * @return The converted [Credential]. + */ override fun fromStorableCredential(): Credential { return c } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/JWTJsonPayload.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/JWTJsonPayload.kt index ab2d41358..ae08a2231 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/JWTJsonPayload.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/JWTJsonPayload.kt @@ -3,6 +3,15 @@ package io.iohk.atala.prism.walletsdk.pollux.models import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonElement +/** + * Represents a JSON Web Token (JWT) payload as a Kotlin data class. + * + * @property iss The issuer of the token. It identifies the entity that issued the token. + * @property sub The subject of the token. It represents the entity that the token pertains to. + * @property nbf The "not before" time of the token. It specifies the time before which the token should not be considered valid. + * @property exp The expiration time of the token. It specifies the time after which the token should not be considered valid. + * @property vc The JSON payload contained within the token. + */ @Serializable data class JWTJsonPayload @JvmOverloads constructor( val iss: String? = null, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/KeyCorrectnessProof.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/KeyCorrectnessProof.kt index c877358d4..60b9616d1 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/KeyCorrectnessProof.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/KeyCorrectnessProof.kt @@ -3,6 +3,13 @@ package io.iohk.atala.prism.walletsdk.pollux.models import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +/** + * Represents the proof of correctness of a public key used for signing a credential. + * + * @property c The value `c` used in the proof. + * @property xzCap The value `xz_cap` used in the proof. + * @property xrCap The map of `xr_cap` values used in the proof. + */ @Serializable data class KeyCorrectnessProof( val c: String, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/W3CCredential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/W3CCredential.kt index 86e36dae1..d0398c6d4 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/W3CCredential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/pollux/models/W3CCredential.kt @@ -82,6 +82,11 @@ data class W3CCredential @JvmOverloads constructor( return properties.toMap() } + /** + * Converts the current W3CCredential object to a StorableCredential object that can be stored and retrieved from a storage system. + * + * @return The converted StorableCredential object. + */ fun toStorableCredential(): StorableCredential { val c = this return object : StorableCredential { @@ -140,12 +145,42 @@ data class W3CCredential @JvmOverloads constructor( return properties.toMap() } + /** + * Converts the current W3CCredential object to a StorableCredential object that can be stored and retrieved from a storage system. + * + * @return The converted StorableCredential object. + */ override fun fromStorableCredential(): Credential { return c } } } + /** + * Checks if the current W3CCredential object is equal to the specified object. + * + * Two W3CCredential objects are considered equal if they have the same values for the following properties: + * - id + * - credentialType + * - context + * - type + * - issuer + * - issuanceDate + * - expirationDate + * - credentialSchema + * - credentialSubject + * - credentialStatus + * - refreshService + * - evidence + * - termsOfUse + * - validFrom + * - validUntil + * - proof + * - aud + * + * @param other The object to compare with the current W3CCredential object. + * @return true if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -173,6 +208,30 @@ data class W3CCredential @JvmOverloads constructor( return true } + /** + * Calculates a hash code value for the current `W3CCredential` object. + * + * The hash code is generated by combining the hash codes of the following properties: + * - `id` + * - `credentialType` + * - `context` + * - `type` + * - `issuer` + * - `issuanceDate` + * - `expirationDate` + * - `credentialSchema` + * - `credentialSubject` + * - `credentialStatus` + * - `refreshService` + * - `evidence` + * - `termsOfUse` + * - `validFrom` + * - `validUntil` + * - `proof` + * - `aud` + * + * @return The calculated hash code value. + */ override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + credentialType.hashCode() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ConnectionManager.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ConnectionManager.kt index 9f6f9b5eb..496d75275 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ConnectionManager.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ConnectionManager.kt @@ -13,6 +13,15 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlin.jvm.Throws +/** + * ConnectionManager is responsible for managing connections and communication between entities. + * + * @property mercury The instance of the Mercury interface used for sending and receiving messages. + * @property castor The instance of the Castor interface used for working with DIDs. + * @property pluto The instance of the Pluto interface used for storing messages and connection information. + * @property mediationHandler The instance of the MediationHandler interface used for handling mediation. + * @property pairings The mutable list of DIDPair representing the connections managed by the ConnectionManager. + */ class ConnectionManager( private val mercury: Mercury, private val castor: Castor, @@ -21,16 +30,33 @@ class ConnectionManager( private var pairings: MutableList ) : ConnectionsManager, DIDCommConnection { + /** + * Suspends the current coroutine and boots the registered mediator associated with the mediator handler. + * If no mediator is available, a [PrismAgentError.NoMediatorAvailableError] is thrown. + * + * @throws PrismAgentError.NoMediatorAvailableError if no mediator is available. + */ suspend fun startMediator() { mediationHandler.bootRegisteredMediator() ?: throw PrismAgentError.NoMediatorAvailableError() } + /** + * Registers a mediator with the given host DID. + * + * @param host The DID of the entity to mediate with. + */ suspend fun registerMediator(host: DID) { mediationHandler.achieveMediation(host).collect { println("Achieve mediation") } } + /** + * Sends a message over the connection. + * + * @param message The message to send. + * @return The response message, if one is received. + */ @Throws(PrismAgentError.NoMediatorAvailableError::class) override suspend fun sendMessage(message: Message): Message? { if (mediationHandler.mediator == null) { @@ -40,16 +66,32 @@ class ConnectionManager( return mercury.sendMessageParseResponse(message) } + /** + * Awaits messages from the connection. + * + * @return An array of messages received from the connection. + */ override suspend fun awaitMessages(): Flow>> { return mediationHandler.pickupUnreadMessages(NUMBER_OF_MESSAGES) } + /** + * Adds a connection to the manager. + * + * @param paired The [DIDPair] representing the connection to be added. + */ override suspend fun addConnection(paired: DIDPair) { if (pairings.contains(paired)) return pluto.storeDIDPair(paired.host, paired.receiver, paired.name ?: "") pairings.add(paired) } + /** + * Removes a connection from the manager. + * + * @param pair The [DIDPair] representing the connection to be removed. + * @return The [DIDPair] object that was removed from the manager, or null if the connection was not found. + */ override suspend fun removeConnection(pair: DIDPair): DIDPair? { val index = pairings.indexOf(pair) if (index > -1) { @@ -58,6 +100,12 @@ class ConnectionManager( return null } + /** + * Awaits a response to a specified message ID from the connection. + * + * @param id The ID of the message for which to await a response. + * @return The response message, if one is received. + */ override suspend fun awaitMessageResponse(id: String): Message? { return try { awaitMessages().first().map { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt index 54d7c8193..84e613a88 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt @@ -125,6 +125,20 @@ class PrismAgent { private var connectionManager: ConnectionManager private var logger: PrismLogger + /** + * Initializes the PrismAgent with the given dependencies. + * + * @param apollo The Apollo instance used by the PrismAgent. + * @param castor The Castor instance used by the PrismAgent. + * @param pluto The Pluto instance used by the PrismAgent. + * @param mercury The Mercury instance used by the PrismAgent. + * @param pollux The Pollux instance used by the PrismAgent. + * @param connectionManager The ConnectionManager instance used by the PrismAgent. + * @param seed An optional Seed instance used by the Apollo if provided, otherwise a random seed will be used. + * @param api An optional Api instance used by the PrismAgent if provided, otherwise a default ApiImpl will be used. + * @param logger An optional PrismLogger instance used by the PrismAgent if provided, otherwise a PrismLoggerImpl with + * LogComponent.PRISM_AGENT will be used. + */ @JvmOverloads constructor( apollo: Apollo, @@ -163,6 +177,19 @@ class PrismAgent { this.logger = logger } + /** + * Initializes the PrismAgent constructor. + * + * @param apollo The instance of Apollo. + * @param castor The instance of Castor. + * @param pluto The instance of Pluto. + * @param mercury The instance of Mercury. + * @param pollux The instance of Pollux. + * @param seed The seed value for random generation. Default is null. + * @param api The instance of the API. Default is null. + * @param mediatorHandler The mediator handler. + * @param logger The logger for PrismAgent. Default is PrismLoggerImpl with LogComponent.PRISM_AGENT. + */ @JvmOverloads constructor( apollo: Apollo, @@ -208,7 +235,8 @@ class PrismAgent { if (flowState.subscriptionCount.value <= 0) { state = State.STOPPED } else { - throw Exception("Agent state only accepts one subscription.") + throw io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError("Agent state only accepts one subscription.") + // throw Exception("Agent state only accepts one subscription.") } } } @@ -367,9 +395,10 @@ class PrismAgent { /** * Registers a peer DID with the specified DID and private keys. * - * @param did The DID to register. - * @param privateKeys The list of private keys associated with the peer DID. - * @param updateMediator Determines whether to update the mediator with the specified DID. + * @param did The DID (Decentralized Identifier) to register. + * @param keyAgreementKeyPair The key pair used for key agreement. + * @param authenticationKeyPair The key pair used for authentication. + * @param updateMediator Whether to update the mediator with the DID. */ suspend fun registerPeerDID( did: DID, @@ -385,7 +414,7 @@ class PrismAgent { // to get the secret(private key) that is pair of the public key within the DIDPeer Document // to this end the library will give you the id of the public key that is `did:{method}:{methodId}#ecnumbasis`. // So the code below after the did is created, it will retrieve the document and - // and store the private keys with the corresponding `id` of the one created on the document. + // store the private keys with the corresponding `id` of the one created on the document. // So when the secret resolver asks for the secret we can identify it. val document = castor.resolveDID(did.toString()) @@ -496,7 +525,7 @@ class PrismAgent { * @return The message sent if successful, null otherwise */ suspend fun sendMessage(message: Message): Message? { - return connectionManager?.sendMessage(message) + return connectionManager.sendMessage(message) } // Credentials related actions @@ -513,20 +542,19 @@ class PrismAgent { val privateKey = pluto.getDIDPrivateKeysByDID(did).first().first() ?: throw PrismAgentError.CannotFindDIDPrivateKey(did.toString()) - var returnByteArray: ByteArray - when (privateKey.getCurve()) { + val returnByteArray: ByteArray = when (privateKey.getCurve()) { Curve.ED25519.value -> { val ed = privateKey as Ed25519PrivateKey - returnByteArray = ed.sign(message) + ed.sign(message) } Curve.SECP256K1.value -> { val secp = privateKey as Secp256k1PrivateKey - returnByteArray = secp.sign(message) + secp.sign(message) } else -> { - throw ApolloError.InvalidKeyCurve( + throw ApolloError.InvalidSpecificKeyCurve( privateKey.getCurve(), arrayOf(Curve.SECP256K1.value, Curve.ED25519.value) ) @@ -541,17 +569,18 @@ class PrismAgent { * @param offer Received offer credential. * @return Created request credential. * @throws [PolluxError.InvalidPrismDID] if there is a problem creating the request credential. + * @throws [io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError] if credential type is not supported **/ - @Throws(PolluxError.InvalidPrismDID::class) + @Throws(PolluxError.InvalidPrismDID::class, io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError::class) suspend fun prepareRequestCredentialWithIssuer( did: DID, offer: OfferCredential ): RequestCredential { if (did.method != "prism") { - throw PolluxError.InvalidPrismDID() + throw PolluxError.InvalidPrismDID("DID method is not \"prism\" ") } - return when (pollux.extractCredentialFormatFromMessage(offer.attachments)) { + return when (val type = pollux.extractCredentialFormatFromMessage(offer.attachments)) { CredentialType.JWT -> { val privateKeyKeyPath = pluto.getPrismDIDKeyPathIndex(did).first() @@ -559,12 +588,12 @@ class PrismAgent { seed, KeyCurve(Curve.SECP256K1, privateKeyKeyPath) ) - val offerDataString = offer.attachments.mapNotNull { + val offerDataString = offer.attachments.firstNotNullOf { when (it.data) { is AttachmentJsonData -> it.data.data else -> null } - }.first() + } val offerJsonObject = Json.parseToJsonElement(offerDataString).jsonObject val jwtString = pollux.processCredentialRequestJWT(did, keyPair.privateKey, offerJsonObject) @@ -587,12 +616,12 @@ class PrismAgent { CredentialType.ANONCREDS_OFFER -> { val linkSecret = getLinkSecret() - val offerDataString = offer.attachments.mapNotNull { + val offerDataString = offer.attachments.firstNotNullOf { when (it.data) { is AttachmentBase64 -> it.data.base64 else -> null } - }.first() + } val anonOffer = CredentialOffer(offerDataString.base64UrlDecoded) val pair = pollux.processCredentialRequestAnoncreds( @@ -632,7 +661,8 @@ class PrismAgent { else -> { // TODO: Create new prism agent error message - throw Error("Not supported credential type") + throw io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError("Not supported credential type: $type") + // throw Error("Not supported credential type: $type") } } } @@ -641,8 +671,9 @@ class PrismAgent { * This function parses an issued credential message, stores, and returns the verifiable credential. * @param message Issue credential Message. * @return The parsed verifiable credential. - * @throws PrismAgentError if there is a problem parsing the credential. + * @throws io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError if there is a problem parsing the credential. */ + @Throws(io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError::class) suspend fun processIssuedCredentialMessage(message: IssueCredential): Credential { val credentialType = pollux.extractCredentialFormatFromMessage(message.attachments) val attachment = message.attachments.firstOrNull()?.data as? AttachmentBase64 @@ -661,7 +692,7 @@ class PrismAgent { val metadata = if (credentialType == CredentialType.ANONCREDS_ISSUE) { val plutoMetadata = pluto.getCredentialMetadata(message.thid).first() - ?: throw Exception("Invalid credential metadata") + ?: throw io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError("Invalid credential metadata") CredentialRequestMetadata( linkSecretBlindingData = Json.encodeToString(plutoMetadata.linkSecretBlindingData.toString()), linkSecretName = plutoMetadata.linkSecretName, @@ -673,7 +704,7 @@ class PrismAgent { val credential = pollux.parseCredential( - data = credentialData, + jsonData = credentialData, type = credentialType, linkSecret = linkSecret, credentialMetadata = metadata @@ -686,8 +717,8 @@ class PrismAgent { ) pluto.storeCredential(storableCredential) return credential - } ?: throw UnknownError("Thid should not be null") - } ?: throw UnknownError("Cannot find attachment base64 in message") + } ?: throw io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError("Thid should not be null") + } ?: throw io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError("Cannot find attachment base64 in message") } // Message Events @@ -756,8 +787,9 @@ class PrismAgent { * @param str The string to parse * @return The parsed invitation [InvitationType] * @throws [PrismAgentError.UnknownInvitationTypeError] if the invitation is not a valid Prism or OOB type + * @throws [SerializationException] if Serialization failed */ - @Throws(PrismAgentError.UnknownInvitationTypeError::class) + @Throws(PrismAgentError.UnknownInvitationTypeError::class, SerializationException::class) suspend fun parseInvitation(str: String): InvitationType { Url.parse(str)?.let { return parseOOBInvitation(it) @@ -770,16 +802,16 @@ class PrismAgent { "" } - val invite: InvitationType = when (findProtocolTypeByValue(typeString)) { + val invite: InvitationType = when (val type = findProtocolTypeByValue(typeString)) { ProtocolType.PrismOnboarding -> parsePrismInvitation(str) ProtocolType.Didcomminvitation -> parseOOBInvitation(str) else -> - throw PrismAgentError.UnknownInvitationTypeError() + throw PrismAgentError.UnknownInvitationTypeError(type.toString()) } return invite } catch (e: SerializationException) { - throw PrismAgentError.UnknownInvitationTypeError() + throw e } } } @@ -788,9 +820,9 @@ class PrismAgent { * Parses the given string as a Prism Onboarding invitation * @param str The string to parse * @return The parsed Prism Onboarding invitation - * @throws [PrismAgentError.UnknownInvitationTypeError] if the string is not a valid Prism Onboarding invitation + * @throws [io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError] if the string is not a valid Prism Onboarding invitation */ - @Throws(PrismAgentError.UnknownInvitationTypeError::class) + @Throws(io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError::class) private suspend fun parsePrismInvitation(str: String): PrismOnboardingInvitation { try { val prismOnboarding = PrismOnboardingInvitation.fromJsonString(str) @@ -812,7 +844,7 @@ class PrismAgent { prismOnboarding.from = did return prismOnboarding } catch (e: Exception) { - throw PrismAgentError.UnknownInvitationTypeError() + throw io.iohk.atala.prism.walletsdk.domain.models.UnknownError.SomethingWentWrongError(e.message, e.cause) } } @@ -820,14 +852,14 @@ class PrismAgent { * Parses the given string as an Out-of-Band invitation * @param str The string to parse * @returns The parsed Out-of-Band invitation - * @throws [PrismAgentError.UnknownInvitationTypeError] if the string is not a valid URL + * @throws [SerializationException] if Serialization failed */ - @Throws(PrismAgentError.UnknownInvitationTypeError::class) + @Throws(SerializationException::class) private suspend fun parseOOBInvitation(str: String): OutOfBandInvitation { return try { Json.decodeFromString(str) } catch (ex: SerializationException) { - throw PrismAgentError.UnknownInvitationTypeError() + throw ex } } @@ -905,18 +937,18 @@ class PrismAgent { DID(it) } ?: DID("") if (subjectDID.method != PRISM) { - throw PolluxError.InvalidPrismDID() + throw PolluxError.InvalidPrismDID("DID method is not \"prism\"") } val privateKeyKeyPath = pluto.getPrismDIDKeyPathIndex(subjectDID).first() val keyPair = Secp256k1KeyPair.generateKeyPair(seed, KeyCurve(Curve.SECP256K1, privateKeyKeyPath)) - val requestData = request.attachments.mapNotNull { + val requestData = request.attachments.firstNotNullOf { when (it.data) { is AttachmentJsonData -> it.data.data else -> null } - }.first() + } val requestJsonObject = Json.parseToJsonElement(requestData).jsonObject val jwtString = pollux.createVerifiablePresentationJWT( subjectDID, @@ -938,6 +970,16 @@ class PrismAgent { ) } + /** + * This method retrieves the link secret from Pluto. + * + * The method first retrieves the link secret using the `pluto.getLinkSecret()` function. If the link secret is not + * found, a new `LinkSecret` object is created and stored in Pluto using the `pluto.storeLinkSecret()` function. The + * newly created link secret object is then returned. If a link secret is found, a new `LinkSecret` object is created + * using the existing link secret value and returned. + * + * @return The retrieved or newly created link secret object. + */ private suspend fun getLinkSecret(): LinkSecret { val linkSecret = pluto.getLinkSecret().firstOrNull() return if (linkSecret == null) { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentError.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentError.kt index 2a13f9efb..4f1b9882f 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentError.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentError.kt @@ -21,12 +21,12 @@ sealed class PrismAgentError : KnownPrismError() { get() = "The system could not parse the invitation, the message/json are invalid" } - class UnknownInvitationTypeError : PrismAgentError() { + class UnknownInvitationTypeError(private val type: String) : PrismAgentError() { override val code: Int get() = 113 override val message: String - get() = "The type of the invitation is not supported." + get() = "The type of the invitation is not supported: $type" } class InvalidMessageType(private val type: String, private val shouldBe: String) : PrismAgentError() { @@ -45,7 +45,8 @@ sealed class PrismAgentError : KnownPrismError() { get() = "There is no mediator.\nYou need to provide a mediation handler and start the prism agent before doing some operations." } - class MediationRequestFailedError(private val underlyingError: Array? = null) : PrismAgentError() { + class MediationRequestFailedError + @JvmOverloads constructor(private val underlyingError: Array? = null) : PrismAgentError() { override val code: Int get() = 116 diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/connectionsmanager/ConnectionsManager.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/connectionsmanager/ConnectionsManager.kt index d208e5c51..d1c179f96 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/connectionsmanager/ConnectionsManager.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/connectionsmanager/ConnectionsManager.kt @@ -2,7 +2,23 @@ package io.iohk.atala.prism.walletsdk.prismagent.connectionsmanager import io.iohk.atala.prism.walletsdk.domain.models.DIDPair +/** + * This interface represents a manager for managing connections between different entities. + * It provides methods for adding and removing connections. + */ interface ConnectionsManager { + /** + * Adds a connection to the manager. + * + * @param paired The [DIDPair] representing the connection to be added. + */ suspend fun addConnection(paired: DIDPair) + + /** + * Removes a connection from the manager. + * + * @param pair The [DIDPair] representing the connection to be removed. + * @return The [DIDPair] object that was removed from the manager, or null if the connection was not found. + */ suspend fun removeConnection(pair: DIDPair): DIDPair? } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/AttachmentDescriptorBuild.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/AttachmentDescriptorBuild.kt index b0d9c74b6..3b278ba50 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/AttachmentDescriptorBuild.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/AttachmentDescriptorBuild.kt @@ -9,6 +9,14 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +/** + * Builds an AttachmentDescriptor object with the specified parameters. + * + * @param id The unique identifier for the attachment. If not provided, a random UUID will be generated. + * @param payload The payload data for the attachment. + * @param mediaType The media type of the attachment. If not provided, the default media type will be used. + * @return The built AttachmentDescriptor object. + */ @JvmOverloads inline fun AttachmentDescriptor.Companion.build( id: String = UUID.randomUUID4().toString(), diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/mediation/BasicMediatorHandler.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/mediation/BasicMediatorHandler.kt index 07053689c..ae332322f 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/mediation/BasicMediatorHandler.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/mediation/BasicMediatorHandler.kt @@ -86,7 +86,9 @@ class BasicMediatorHandler( try { val requestMessage = MediationRequest(from = host, to = mediatorDID).makeMessage() val message = mercury.sendMessageParseResponse(message = requestMessage) - ?: throw UnknownError.SomethingWentWrongError() + ?: throw UnknownError.SomethingWentWrongError( + message = "BasicMediatorHandler => mercury.sendMessageParseResponse returned null" + ) val grantedMessage = MediationGrant(message) val routingDID = DID(grantedMessage.body.routingDid) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/ProtocolType.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/ProtocolType.kt index f81bf2879..6aaab7d13 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/ProtocolType.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/ProtocolType.kt @@ -37,6 +37,7 @@ enum class ProtocolType(val value: String) { None(""); companion object { + @JvmStatic fun findProtocolType(type: String, default: ProtocolType): ProtocolType { return ProtocolType.values().find { it.value == type } ?: default } @@ -59,6 +60,13 @@ object ProtocolTypeSerializer : KSerializer { } } +/** + * Finds the ProtocolType based on the given string value. + * + * @param string The string value to match with the ProtocolType's value. + * @return The matched ProtocolType. + * @throws PrismAgentError.UnknownInvitationTypeError If the type of the invitation is not supported. + */ @Throws(PrismAgentError.UnknownInvitationTypeError::class) fun findProtocolTypeByValue(string: String): ProtocolType { val it = ProtocolType.values().iterator() @@ -68,5 +76,5 @@ fun findProtocolTypeByValue(string: String): ProtocolType { return internalType } } - throw PrismAgentError.UnknownInvitationTypeError() + throw PrismAgentError.UnknownInvitationTypeError(string) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/ConnectionAccept.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/ConnectionAccept.kt index 6e94cfb9e..828dd5217 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/ConnectionAccept.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/ConnectionAccept.kt @@ -17,7 +17,7 @@ import kotlinx.serialization.json.Json */ class ConnectionAccept { val type: String = ProtocolType.DidcommconnectionResponse.value - lateinit var id: String + var id: String = UUID.randomUUID4().toString() lateinit var from: DID lateinit var to: DID var thid: String? = null @@ -37,7 +37,6 @@ class ConnectionAccept { thid: String? = null, body: Body ) { - id = UUID.randomUUID4().toString() this.from = from this.to = to this.thid = thid @@ -75,6 +74,11 @@ class ConnectionAccept { ) } + /** + * The `makeMessage` method creates a new `Message` object with the specified parameters. + * + * @return A new `Message` object. + */ fun makeMessage(): Message { return Message( id = id, @@ -105,6 +109,14 @@ class ConnectionAccept { */ val accept: Array? = null ) { + /** + * Checks if this [Body] object is equal to the specified [other] object. + * + * Two [Body] objects are considered equal if their [goalCode], [goal], and [accept] properties are equal. + * + * @param other The object to compare for equality. If the [other] object is not of type [Body], the method returns false. + * @return true if this [Body] object is equal to the specified [other] object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -121,6 +133,16 @@ class ConnectionAccept { return true } + /** + * Returns a hash code value for the object. + * + * The hash code is calculated based on the `goalCode`, `goal`, and `accept` properties. + * If the `goalCode` is not null, its hash code value is added to the result. + * If the `goal` is not null, its hash code value is multiplied by 31 and added to the result. + * If the `accept` array is not null, its content hash code value is multiplied by 31 and added to the result. + * + * @return The hash code value for the object. + */ override fun hashCode(): Int { var result = goalCode?.hashCode() ?: 0 result = 31 * result + (goal?.hashCode() ?: 0) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/ConnectionRequest.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/ConnectionRequest.kt index aa0246b19..eb868fe9b 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/ConnectionRequest.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/ConnectionRequest.kt @@ -25,6 +25,14 @@ class ConnectionRequest { var thid: String? = null lateinit var body: Body + /** + * Represents a connection request message in the messaging protocol. + * + * @param from The sender's DID. + * @param to The recipient's DID. + * @param thid The thread ID. + * @param body The body of the connection request message. + */ constructor( from: DID, to: DID, @@ -94,6 +102,11 @@ class ConnectionRequest { } } + /** + * Creates a [Message] object based on the current state of the [ConnectionRequest] instance. + * + * @return The created [Message] object. + */ fun makeMessage(): Message { return Message( id = this.id, @@ -124,6 +137,12 @@ class ConnectionRequest { */ val accept: Array? = null ) { + /** + * Checks if the current object is equal to the specified object. + * + * @param other The other object to compare. + * @return true if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -140,6 +159,11 @@ class ConnectionRequest { return true } + /** + * Generates a hash code for the object based on its properties. + * + * @return The hash code value. + */ override fun hashCode(): Int { var result = goalCode?.hashCode() ?: 0 result = 31 * result + (goal?.hashCode() ?: 0) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/DIDCommConnectionRunner.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/DIDCommConnectionRunner.kt index d81274419..e3731e2a5 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/DIDCommConnectionRunner.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/connection/DIDCommConnectionRunner.kt @@ -7,6 +7,14 @@ import io.iohk.atala.prism.walletsdk.prismagent.PrismAgentError import io.iohk.atala.prism.walletsdk.prismagent.connectionsmanager.DIDCommConnection import io.iohk.atala.prism.walletsdk.prismagent.protocols.outOfBand.OutOfBandInvitation +/** + * Represents a runner for the DIDComm connection process. + * + * @property invitationMessage The out-of-band invitation message. + * @property pluto The Pluto instance. + * @property ownDID The own DID. + * @property connection The DIDComm connection. + */ internal class DIDCommConnectionRunner( private val invitationMessage: OutOfBandInvitation, private val pluto: Pluto, @@ -14,6 +22,12 @@ internal class DIDCommConnectionRunner( private val connection: DIDCommConnection ) { + /** + * Executes the DIDComm connection process and returns a pair of DIDs. + * + * @return A [DIDPair] representing the sender and receiver DIDs of the connection. + * @throws [PrismAgentError.InvitationIsInvalidError] if the invitation is invalid and cannot be parsed. + */ @Throws(PrismAgentError.InvitationIsInvalidError::class) internal suspend fun run(): DIDPair { val request = ConnectionRequest(invitationMessage, ownDID) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/CredentialPreview.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/CredentialPreview.kt index f2b366925..63daf2ff0 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/CredentialPreview.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/CredentialPreview.kt @@ -21,8 +21,20 @@ constructor( ) { val type: String = ProtocolType.DidcommCredentialPreview.value + /** + * Initializes a new instance of [CredentialPreview]. + * + * @param schemaId The ID of the schema associated with the credential. Defaults to `null` if not provided. + * @param attributes An array of attributes to include in the credential preview. + */ constructor(schemaId: String? = null, attributes: Array) : this(schemaId, Body(attributes)) + /** + * Compares this [CredentialPreview] object to the specified [other] object for equality. + * + * @param other The object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -32,14 +44,32 @@ constructor( return type == other.type } + /** + * Computes the hash code value for this object. + * + * @return The hash code value for this object. + */ override fun hashCode(): Int { return type.hashCode() } + /** + * Represents a body object. + * + * @property attributes The array of attributes. + * + * @see Attribute + */ @Serializable data class Body( val attributes: Array ) { + /** + * Checks if this `Body` object is equal to another object. + * + * @param other The object to compare to this `Body` object. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -49,11 +79,28 @@ constructor( return attributes.contentEquals(other.attributes) } + /** + * Calculates the hash code for this `Body` object. + * + * The hash code is calculated based on the `attributes` property of the `Body` object. + * + * @return The hash code value for this object. + * + * @see Body + * @see Attribute + */ override fun hashCode(): Int { return attributes.contentHashCode() } } + /** + * Represents an attribute in a credential preview. + * + * @property name The name of the attribute. + * @property value The value of the attribute. + * @property mediaType The media type of the attribute, if applicable. + */ @Serializable data class Attribute( val name: String, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/IssueCredential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/IssueCredential.kt index 3aa6e79fd..678d59d68 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/IssueCredential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/IssueCredential.kt @@ -18,6 +18,9 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +/** + * The IssueCredential class represents a credential issuance in the context of DIDComm messaging. + */ @Serializable data class IssueCredential( val id: String = UUID.randomUUID4().toString(), @@ -29,6 +32,19 @@ data class IssueCredential( ) { val type: String = ProtocolType.DidcommIssueCredential.value + /** + * Creates a [Message] object representing a DIDComm message. + * This function is used to generate a [Message] object based on the current state of an [IssueCredential] object. + * + * @return A [Message] object with the following properties: + * - id: A unique identifier generated using [UUID.randomUUID4]. + * - piuri: The type of the message. + * - from: The sender's DID (Decentralized Identifier). + * - to: The recipient's DID. + * - body: The JSON-encoded body of the message. + * - attachments: An array of [AttachmentDescriptor] objects. + * - thid: The thread ID. + */ fun makeMessage(): Message { return Message( id = id, @@ -41,6 +57,11 @@ data class IssueCredential( ) } + /** + * Retrieves an array of credential strings from the attachments. + * + * @return An array of credential strings. + */ fun getCredentialStrings(): Array { return attachments.mapNotNull { when (it.data) { @@ -54,6 +75,14 @@ data class IssueCredential( } companion object { + /** + * Converts a Message into an IssueCredential object. + * + * @param fromMessage The Message object to convert. + * @return The converted IssueCredential object. + * @throws PrismAgentError.InvalidMessageType if the fromMessage doesn't represent the DidcommIssueCredential protocol, + * or if it doesn't have "from" and "to" fields. + */ @JvmStatic @Throws(PrismAgentError.InvalidMessageType::class) fun fromMessage(fromMessage: Message): IssueCredential { @@ -82,6 +111,12 @@ data class IssueCredential( ) } + /** + * Creates an [IssueCredential] object from a [Message] object. + * + * @param msg The [Message] object containing the request credential information. + * @return The created [IssueCredential] object. + */ @JvmStatic fun makeIssueFromRequestCedential(msg: Message): IssueCredential { val request = RequestCredential.fromMessage(msg) @@ -99,6 +134,14 @@ data class IssueCredential( } } + /** + * Represents the body of an issue credential message. + * + * @property goalCode The goal code associated with the credential (optional). + * @property comment Additional comment about the credential (optional). + * @property replacementId The ID of the credential being replaced (optional). + * @property moreAvailable Additional information about the availability of more credentials (optional). + */ @Serializable data class Body( @SerialName(GOAL_CODE) @@ -110,6 +153,19 @@ data class IssueCredential( val moreAvailable: String? = null // val formats: Array ) { + /** + * Checks if the object is equal to the current `Body` object. + * + * Two `Body` objects are considered equal if they meet the following conditions: + * - They are the same instance (reference equality). + * - They belong to the same class. + * - Their `goalCode` fields have the same value. + * - Their `comment` fields have the same value. + * - Their `replacementId` fields have the same value. + * + * @param other The object to compare against the current `Body` object. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -125,6 +181,17 @@ data class IssueCredential( return true } + /** + * Calculates the hash code for the `hashCode()` method of the `Body` class. + * + * The hash code is calculated using the following formula: + * - The hash code of the `goalCode` field is calculated using its `hashCode()` method, or zero if it is null. + * - The hash code of the `comment` field is calculated using its `hashCode()` method, or zero if it is null. + * - The hash code of the `replacementId` field is calculated using its `hashCode()` method, or zero if it is null. + * - The final hash code is calculated by multiplying each field's hash code by 31 and summing them up. + * + * @return The calculated hash code value for the `Body` object. + */ override fun hashCode(): Int { var result = goalCode?.hashCode() ?: 0 result = 31 * result + (comment?.hashCode() ?: 0) @@ -135,6 +202,23 @@ data class IssueCredential( } } + /** + * Checks if the object is equal to the current `IssueCredential` object. + * + * Two `IssueCredential` objects are considered equal if they meet the following conditions: + * - They are the same instance (reference equality). + * - They belong to the same class. + * - Their `id` fields have the same value. + * - Their `body` fields have the same value. + * - Their `attachments` arrays have the same content. + * - Their `thid` fields have the same value. + * - Their `from` fields have the same value. + * - Their `to` fields have the same value. + * - Their `type` fields have the same value. + * + * @param other The object to compare against the current `IssueCredential` object. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -152,6 +236,21 @@ data class IssueCredential( return true } + /** + * Calculates the hash code for the `IssueCredential` object. + * + * The hash code is calculated using the following formula: + * - The hash code of the `id` field is calculated using its `hashCode()` method. + * - The hash code of the `body` field is calculated using its `hashCode()` method. + * - The hash code of the `attachments` field is calculated using its `contentHashCode()` method. + * - The hash code of the `thid` field is calculated using its `hashCode()` method, or zero if it is null. + * - The hash code of the `from` field is calculated using its `hashCode()` method. + * - The hash code of the `to` field is calculated using its `hashCode()` method. + * - The hash code of the `type` field is calculated using its `hashCode()` method. + * - The final hash code is calculated by multiplying each field's hash code by 31 and summing them up. + * + * @return The calculated hash code value for the `IssueCredential` object. + */ override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + body.hashCode() @@ -164,6 +263,16 @@ data class IssueCredential( } } +/** + * Builds an instance of [IssueCredential] with the provided parameters. + * + * @param T The type of the credentials. + * @param fromDID The DID of the sender. + * @param toDID The DID of the recipient. + * @param thid The thread ID (optional). + * @param credentials The map of credential formats and their corresponding values (default is an empty map). + * @return An instance of [IssueCredential] with the specified parameters. + */ @JvmOverloads inline fun IssueCredential.Companion.build( fromDID: DID, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/IssueCredentialProtocol.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/IssueCredentialProtocol.kt index 388b20092..16fea5919 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/IssueCredentialProtocol.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/IssueCredentialProtocol.kt @@ -5,6 +5,15 @@ import io.iohk.atala.prism.walletsdk.domain.models.UnknownError import io.iohk.atala.prism.walletsdk.prismagent.connectionsmanager.DIDCommConnection import kotlinx.serialization.Serializable +/** + * A class that represents the issue credential protocol in the DIDCommv2 format. + * + * @property stage The current stage of the protocol. + * @property propose The `ProposeCredential` object representing the propose message, or null if not applicable. + * @property offer The `OfferCredential` object representing the offer message, or null if not applicable. + * @property request The `RequestCredential` object representing the request message, or null if not applicable. + * @property connector The `DIDCommConnection` object representing the connection used to send and receive messages. + */ @Serializable class IssueCredentialProtocol { @@ -14,6 +23,16 @@ class IssueCredentialProtocol { var request: RequestCredential? = null val connector: DIDCommConnection + /** + * The IssueCredentialProtocol class represents a protocol for issuing credentials in the Atala PRISM architecture. + * It handles different stages of the protocol and communicates with a DIDComm connection to exchange messages. + * + * @param stage The current stage of the protocol. + * @param proposeMessage The propose message received in the protocol. + * @param offerMessage The offer message received in the protocol. + * @param requestMessage The request message received in the protocol. + * @param connector The DIDComm connection to communicate with. + */ @JvmOverloads constructor( stage: Stage, @@ -47,6 +66,16 @@ class IssueCredentialProtocol { } } + /** + * Constructs an instance of [IssueCredentialProtocol] class. + * This constructor initializes the object with the provided [message] and [connector]. + * It determines the stage of the credential issuance process based on the message type in [message], + * and assigns the corresponding values to the [stage] and relevant property (propose, offer, or request). + * + * @param message The message object representing the received message. + * @param connector The DIDCommConnection instance used for message exchange. + * @throws [UnknownError.SomethingWentWrongError] if the message does not match any known message type. + */ @Throws(UnknownError.SomethingWentWrongError::class) constructor(message: Message, connector: DIDCommConnection) { this.connector = connector @@ -83,11 +112,44 @@ class IssueCredentialProtocol { } else -> throw UnknownError.SomethingWentWrongError( - customMessage = "Invalid step" + message = "Invalid step" ) } } + /** + * Proceeds to the next stage of the credential issuance process. + * + * If the current stage is PROPOSE: + * - If `propose` is null, sets the stage to REFUSED and returns. + * + * If the current stage is OFFER: + * - If `offer` is null, sets the stage to REFUSED and returns. + * + * Based on the current stage, performs the following actions: + * - PROPOSE: + * - Creates an OfferCredential from the proposed credential using the method `makeOfferFromProposedCredential()`. + * - Sends the offer message over the connector's connection using `sendMessage()`. + * - Sets the `messageId` to the ID of the sent message. + * + * - OFFER: + * - Creates a RequestCredential from the offer credential using the method `makeRequestFromOfferCredential()`. + * - Sends the request message over the connector's connection using `sendMessage()`. + * - Sets the `messageId` to the ID of the sent message. + * + * Based on the value of `messageId`, performs the following actions: + * - If `messageId` is null, returns. + * + * - Otherwise, awaits a response message with the specified `messageId` using `awaitMessageResponse()`. + * If no response message is received, returns. + * + * Based on the received response message, performs the following actions: + * - If the response is an IssueCredential message, sets the stage to COMPLETED. + * - If the response is an OfferCredential message, sets the stage to OFFER and assigns the received offer to `this.offer`. + * - If the response is a RequestCredential message, sets the stage to REQUEST and assigns the received request to `this.request`. + * + * @throws Throwable If there is an error in processing the messages. + */ suspend fun nextStage() { if (this.stage == Stage.PROPOSE) { if (propose == null) { @@ -154,6 +216,10 @@ class IssueCredentialProtocol { } } + /** + * Represents the different stages of the credential issuance process. + * The stages are PROPOSE, OFFER, REQUEST, COMPLETED, and REFUSED. + */ enum class Stage { PROPOSE, OFFER, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/OfferCredential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/OfferCredential.kt index 240f71913..27b3f2fc0 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/OfferCredential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/OfferCredential.kt @@ -32,6 +32,14 @@ data class OfferCredential @JvmOverloads constructor( ) { public val type: String = ProtocolType.DidcommOfferCredential.value + /** + * Creates a [Message] object with the provided data and returns it. + * The [Message] object includes information about the sender, recipient, message body, + * and other metadata. The [Message] object is typically used for secure, decentralized communication + * in the Atala PRISM architecture. + * + * @return The [Message] object with the provided data. + */ fun makeMessage(): Message { return Message( id = id, @@ -46,6 +54,12 @@ data class OfferCredential @JvmOverloads constructor( companion object { + /** + * Creates an [OfferCredential] object from the provided [ProposeCredential] data. + * + * @param proposed The [ProposeCredential] object containing the proposed credential data. + * @return The [OfferCredential] object created with the provided data. + */ @JvmStatic fun makeOfferFromProposedCredential(proposed: ProposeCredential): OfferCredential { return OfferCredential( @@ -61,6 +75,13 @@ data class OfferCredential @JvmOverloads constructor( ) } + /** + * Converts a Message object to an OfferCredential object. + * + * @param fromMessage The Message object to convert. + * @return The converted OfferCredential object. + * @throws PrismAgentError.InvalidMessageType if the message type is invalid or the "from" and "to" fields are not present. + */ @JvmStatic @Throws(PrismAgentError.InvalidMessageType::class) fun fromMessage(fromMessage: Message): OfferCredential { @@ -77,9 +98,6 @@ data class OfferCredential @JvmOverloads constructor( val fromDID = fromMessage.from val toDID = fromMessage.to - val json = Json { - ignoreUnknownKeys = true - } val body = Json.decodeFromString(fromMessage.body) return OfferCredential( id = fromMessage.id, @@ -92,6 +110,12 @@ data class OfferCredential @JvmOverloads constructor( } } + /** + * Checks if the current instance of `OfferCredential` is equal to the given object. + * + * @param other The object to compare with the current instance of `OfferCredential`. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -109,8 +133,22 @@ data class OfferCredential @JvmOverloads constructor( return true } + /** + * Calculates the hash code for the current instance of the OfferCredential class. + * + * The hash code is computed by combining the hash codes of the following properties: + * - id + * - body + * - attachments + * - thid (if not null) + * - from + * - to + * - type + * + * @return The computed hash code for the current instance of the OfferCredential class. + */ override fun hashCode(): Int { - var result = id?.hashCode() ?: 0 + var result = id.hashCode() result = 31 * result + body.hashCode() result = 31 * result + attachments.contentHashCode() result = 31 * result + (thid?.hashCode() ?: 0) @@ -120,6 +158,15 @@ data class OfferCredential @JvmOverloads constructor( return result } + /** + * Represents the body of an OfferCredential message. + * + * @property goalCode The goal code associated with the credential. + * @property comment Additional comments related to the credential. + * @property replacementId The ID of the credential being replaced, if applicable. + * @property multipleAvailable Indicates if multiple credentials of the same type are available for selection. + * @property credentialPreview The preview of the credential to be offered. + */ @Serializable data class Body @JvmOverloads constructor( @SerialName(GOAL_CODE) @@ -132,6 +179,12 @@ data class OfferCredential @JvmOverloads constructor( @SerialName(CREDENTIAL_PREVIEW) val credentialPreview: CredentialPreview ) { + /** + * Compares this [Body] object to the specified [other] object for equality. + * + * @param other The object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -147,6 +200,18 @@ data class OfferCredential @JvmOverloads constructor( return true } + /** + * Computes the hash code value for this object. + * + * The hash code is computed by combining the hash codes of the following properties: + * - goalCode + * - comment + * - replacementId + * - multipleAvailable + * - credentialPreview + * + * @return The hash code value for this object. + */ override fun hashCode(): Int { var result = goalCode?.hashCode() ?: 0 result = 31 * result + (comment?.hashCode() ?: 0) @@ -158,6 +223,16 @@ data class OfferCredential @JvmOverloads constructor( } } +/** + * Builds an OfferCredential object with the provided data. + * + * @param fromDID The DID of the sender. + * @param toDID The DID of the recipient. + * @param thid The thread ID. + * @param credentialPreview The preview of the credential. + * @param credentials The map of credentials. Default value is an empty map. + * @return The constructed OfferCredential object. + */ @JvmOverloads inline fun OfferCredential.Companion.build( fromDID: DID, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/ProposeCredential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/ProposeCredential.kt index a01a227b4..4b6ffdadb 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/ProposeCredential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/ProposeCredential.kt @@ -27,6 +27,15 @@ data class ProposeCredential @JvmOverloads constructor( ) { public val type: String = ProtocolType.DidcommProposeCredential.value + /** + * This function creates a new [Message] object based on the provided data. The [Message] object represents a DIDComm message, + * which is used for secure, decentralized communication in the Atala PRISM architecture. The function sets the id, piuri, + * from, to, body, attachments, and thid properties of the [Message] object. The id property is generated using a random UUID, + * and the body property is encoded as a JSON string using the [Json.encodeToString] function. The other properties are set + * based on the values passed as arguments to the function. + * + * @return A new [Message] object. + */ fun makeMessage(): Message { return Message( id = id, @@ -40,6 +49,13 @@ data class ProposeCredential @JvmOverloads constructor( } companion object { + /** + * Converts a Message object to a ProposeCredential object. + * + * @param fromMessage The input Message object to convert. + * @return A ProposeCredential object created from the input Message. + * @throws PrismAgentError.InvalidMessageType If the input message does not represent the expected protocol type or if it does not have "from" and "to" fields. + */ @JvmStatic @Throws(PrismAgentError.InvalidMessageType::class) fun fromMessage(fromMessage: Message): ProposeCredential { @@ -69,12 +85,25 @@ data class ProposeCredential @JvmOverloads constructor( } } + /** + * Represents the body of a message for proposing a credential. + * + * @property goalCode The goal code. + * @property comment The comment. + * @property credentialPreview The credential preview. + */ @Serializable data class Body @JvmOverloads constructor( val goalCode: String? = null, val comment: String? = null, val credentialPreview: CredentialPreview ) { + /** + * Checks if this object is equal to the specified [other] object. + * + * @param other The object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -88,6 +117,11 @@ data class ProposeCredential @JvmOverloads constructor( return true } + /** + * Computes the hash code value for this object. + * + * @return The hash code value for this object. + */ override fun hashCode(): Int { var result = goalCode?.hashCode() ?: 0 result = 31 * result + (comment?.hashCode() ?: 0) @@ -96,6 +130,12 @@ data class ProposeCredential @JvmOverloads constructor( } } + /** + * Checks if this object is equal to the specified [other] object. + * + * @param other The object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -113,8 +153,13 @@ data class ProposeCredential @JvmOverloads constructor( return true } + /** + * Computes the hash code value for this object. + * + * @return The hash code value for this object. + */ override fun hashCode(): Int { - var result = id?.hashCode() ?: 0 + var result = id.hashCode() result = 31 * result + body.hashCode() result = 31 * result + attachments.contentHashCode() result = 31 * result + (thid?.hashCode() ?: 0) @@ -125,6 +170,19 @@ data class ProposeCredential @JvmOverloads constructor( } } +/** + * This method builds a ProposeCredential object based on the provided parameters. The ProposeCredential represents a proposal to issue a credential in the Atala PRISM architecture + *. The method takes in the following parameters: + * + * @param fromDID The DID of the sender of the proposal. + * @param toDID The DID of the recipient of the proposal. + * @param thid The thread ID of the proposal. Optional. + * @param credentialPreview The credential preview object that describes the proposed credential. + * @param credentials A map of credential formats and their corresponding values. The values must be of type T, which must implement the Serializable interface. The default value + * is an empty map. + * + * @return A new ProposeCredential object. + */ @JvmOverloads inline fun ProposeCredential.Companion.build( fromDID: DID, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/RequestCredential.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/RequestCredential.kt index c2ef58804..5f2cb432e 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/RequestCredential.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/issueCredential/RequestCredential.kt @@ -27,6 +27,11 @@ data class RequestCredential @JvmOverloads constructor( ) { val type: String = ProtocolType.DidcommRequestCredential.value + /** + * This method is used to create a [Message] object with the specified properties. + * + * @return The created [Message] object. + */ fun makeMessage(): Message { return Message( id = id, @@ -40,6 +45,13 @@ data class RequestCredential @JvmOverloads constructor( } companion object { + /** + * Converts a Message object to a RequestCredential object. + * + * @param fromMessage The Message object to convert. + * @return The converted RequestCredential object. + * @throws PrismAgentError.InvalidMessageType If the Message object does not represent the expected protocol or is missing the "from" and "to" fields. + */ @JvmStatic @Throws(PrismAgentError.InvalidMessageType::class) fun fromMessage(fromMessage: Message): RequestCredential { @@ -68,6 +80,12 @@ data class RequestCredential @JvmOverloads constructor( ) } + /** + * Creates a [RequestCredential] object based on the provided [OfferCredential]. + * + * @param offer The [OfferCredential] object containing the offer credential data. + * @return The [RequestCredential] object created with the data from the offer credential. + */ @JvmStatic fun makeRequestFromOfferCredential(offer: OfferCredential): RequestCredential { return RequestCredential( @@ -83,11 +101,27 @@ data class RequestCredential @JvmOverloads constructor( } } + /** + * Represents the body of a request credential. + * + * @property goalCode The goal code. + * @property comment The comment. + */ @Serializable data class Body @JvmOverloads constructor( val goalCode: String? = null, val comment: String? = null ) { + /** + * Checks if this [Body] object is equal to the specified [other] object. + * + * Two [Body] objects are considered equal if they have the same values for the following properties: + * - [goalCode] (the goal code) + * - [comment] (the comment) + * + * @param other The object to compare with this [Body] object. + * @return true if the specified [other] object is equal to this [Body] object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -100,6 +134,15 @@ data class RequestCredential @JvmOverloads constructor( return true } + /** + * Calculates the hash code for the object. + * + * The hash code is calculated based on the values of the `goalCode` and `comment` properties. + * If `goalCode` is not null, its hash code is used as part of the calculation. + * If `comment` is not null, its hash code is used as part of the calculation. + * + * @return The hash code value for the object. + */ override fun hashCode(): Int { var result = goalCode?.hashCode() ?: 0 result = 31 * result + (comment?.hashCode() ?: 0) @@ -107,6 +150,21 @@ data class RequestCredential @JvmOverloads constructor( } } + /** + * Checks if this [RequestCredential] object is equal to the specified [other] object. + * + * Two [RequestCredential] objects are considered equal if they have the same values for the following properties: + * - [id] (the ID) + * - [body] (the body) + * - [attachments] (the attachments) + * - [thid] (the THID) + * - [from] (the sender) + * - [to] (the receiver) + * - [type] (the type) + * + * @param other The object to compare with this [RequestCredential] object. + * @return true if the specified [other] object is equal to this [RequestCredential] object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -124,8 +182,22 @@ data class RequestCredential @JvmOverloads constructor( return true } + /** + * Calculates the hash code for the [RequestCredential] object. + * + * The hash code is calculated based on the values of the following properties: + * - [id] (the ID) + * - [body] (the body) + * - [attachments] (the attachments) + * - [thid] (the THID) + * - [from] (the sender) + * - [to] (the receiver) + * - [type] (the type) + * + * @return The hash code value for the [RequestCredential] object. + */ override fun hashCode(): Int { - var result = id?.hashCode() ?: 0 + var result = id.hashCode() result = 31 * result + body.hashCode() result = 31 * result + attachments.contentHashCode() result = 31 * result + (thid?.hashCode() ?: 0) @@ -136,6 +208,15 @@ data class RequestCredential @JvmOverloads constructor( } } +/** + * Builds a [RequestCredential] object using the provided parameters. + * + * @param fromDID The DID of the sender. + * @param toDID The DID of the receiver. + * @param thid The THID (thread ID). + * @param credentials The map of credential formats and corresponding payloads. + * @return The created [RequestCredential] object. + */ @JvmOverloads inline fun RequestCredential.Companion.build( fromDID: DID, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationGrant.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationGrant.kt index 80a47fdec..1a4dca871 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationGrant.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationGrant.kt @@ -10,15 +10,48 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlin.jvm.Throws +/** + * The `MediationProtocolError` class represents an error that can occur during mediation protocol processing. + * It is derived from the [Throwable] class and is sealed, meaning that it cannot be directly instantiated. + * + * @see Throwable + */ sealed class MediationProtocolError : Throwable() { + /** + * The `InvalidMediationGrantError` class represents an error that can occur when a provided message is not a valid mediation grant. + * + * @throws MediationProtocolError.InvalidMediationGrantError if the provided message is not a valid mediation grant. + */ class InvalidMediationGrantError : MediationProtocolError() } +/** + * The MediationGrant class represents a mediation grant in the Atala PRISM architecture. + * A mediation grant is used for granting permission to mediate a specific request. + * + * @property id The unique identifier of the mediation grant. + * @property type The type of the mediation grant. + * @property body The body of the mediation grant containing the routing DID. + * @constructor Creates a MediationGrant object with the specified ID and body. + * @throws MediationProtocolError.InvalidMediationGrantError if the provided message is not a valid mediation grant. + */ class MediationGrant { var id: String var type = ProtocolType.DidcommMediationGrant.value var body: Body + /** + * Represents a mediation grant in the Atala PRISM architecture. + * A mediation grant is used for granting permission to mediate a specific request. + * + * @property id The unique identifier of the mediation grant. + * @property type The type of the mediation grant. + * @property body The body of the mediation grant containing the routing DID. + * + * @constructor Creates a MediationGrant object with the specified ID and body. + * + * @throws MediationProtocolError.InvalidMediationGrantError if the provided message is not a valid mediation grant. + */ constructor( id: String = UUID.randomUUID4().toString(), body: Body @@ -27,6 +60,16 @@ class MediationGrant { this.body = body } + /** + * The `MediationGrant` class represents a mediation grant in the Atala PRISM architecture. + * A mediation grant is used for granting permission to mediate a specific request. + * + * @property id The unique identifier of the mediation grant. + * @property type The type of the mediation grant. + * @property body The body of the mediation grant containing the routing DID. + * @constructor Creates a MediationGrant object with the specified ID and body. + * @throws MediationProtocolError.InvalidMediationGrantError if the provided message is not a valid mediation grant. + */ @Throws(MediationProtocolError.InvalidMediationGrantError::class) constructor(fromMessage: Message) { if (fromMessage.piuri != ProtocolType.DidcommMediationGrant.value) { @@ -36,6 +79,12 @@ class MediationGrant { this.body = Json.decodeFromString(fromMessage.body) } + /** + * The [Body] class represents a body object that can be included in a [Message] object. + * It is used for secure, decentralized communication in the Atala PRISM architecture. + * + * @see Message + */ @Serializable data class Body(@SerialName(ROUTING_DID)var routingDid: String) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationKeysUpdateList.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationKeysUpdateList.kt index be966ea6e..60d034e4b 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationKeysUpdateList.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationKeysUpdateList.kt @@ -14,6 +14,15 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +/** + * MediationKeysUpdateList is a serializable class representing the list of keys updated in a mediation process. + * + * @property id The ID of the mediation keys update list. + * @property from The sender of the mediation keys update list. + * @property to The recipient of the mediation keys update list. + * @property type The type of the mediation keys update list. + * @property body The body of the mediation keys update list, containing the updates. + */ @Serializable final class MediationKeysUpdateList { var id: String @@ -22,6 +31,15 @@ final class MediationKeysUpdateList { var type = ProtocolType.DidcommMediationKeysUpdate.value var body: Body + /** + * The `MediationKeysUpdateList` class represents a list of updates for mediation keys. + * It is used to create a `Message` object with the specified parameters. + * + * @property id The ID of the `MediationKeysUpdateList` object. + * @property from The sender DID. + * @property to The recipient DID. + * @property recipientDids An array of recipient DIDs. + */ @JvmOverloads constructor( id: String = UUID.randomUUID4().toString(), @@ -39,6 +57,14 @@ final class MediationKeysUpdateList { ) } + /** + * This method creates a [Message] object with the specified parameters. + * The [Message] object represents a DIDComm message used for secure and decentralized communication in the Atala PRISM architecture. + * The [Message] object includes information about the sender, recipient, message body, and other metadata. + * The method sets default values for some properties and returns the created [Message] object. + * + * @return The created [Message] object. + */ fun makeMessage(): Message { return Message( id = id, @@ -58,6 +84,13 @@ final class MediationKeysUpdateList { ) } + /** + * Represents an update object for mediation keys. + * + * @property recipientDid The recipient DID. + * @property action The action to be performed. + * @constructor Creates an instance of [Update]. + */ @Serializable data class Update @OptIn(ExperimentalSerializationApi::class) @@ -69,23 +102,43 @@ final class MediationKeysUpdateList { var action: String = ADD ) + /** + * Represents a body object that contains `updates` for mediation keys. + * + * @property updates An array of [Update] objects representing the updates for mediation keys. + */ @Serializable data class Body @JvmOverloads constructor(var updates: Array = emptyArray()) { + /** + * Checks if this object is equal to another object. + * + * @param other The object to compare with. + * @return true if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false other as Body - if (!updates.contentEquals(other.updates)) return false - - return true + return updates.contentEquals(other.updates) } + /** + * Calculates the hash code for the object. + * + * @return The hash code value for the object. + */ override fun hashCode(): Int { return updates.contentHashCode() } + /** + * Converts the updates in this [Body] object to a [Map] with keys of type [String] + * and values of type [Any?]. + * + * @return A [Map] containing the updates as key-value pairs. + */ fun toMapStringAny(): Map { return mapOf(Pair(UPDATES, updates)) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationRequest.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationRequest.kt index c81e46d8c..755cc4dbb 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationRequest.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/mediation/MediationRequest.kt @@ -6,12 +6,36 @@ import io.iohk.atala.prism.walletsdk.domain.models.Message import io.iohk.atala.prism.walletsdk.prismagent.EMPTY_BODY import io.iohk.atala.prism.walletsdk.prismagent.protocols.ProtocolType +/** + * The `MediationRequest` class represents a mediation request in the application. + * + * @property id The unique identifier of the mediation request. + * @property type The type of the mediation request. Default value is [ProtocolType.DidcommMediationRequest]. + * @property from The source DID (Decentralized Identifier) of the mediation request. + * @property to The target DID (Decentralized Identifier) of the mediation request. + * @constructor Creates a `MediationRequest`. + * @param id The unique identifier of the mediation request. + * @param type The type of the mediation request. Default value is [ProtocolType.DidcommMediationRequest]. + * @param from The source DID (Decentralized Identifier) of the mediation request. + * @param to The target DID (Decentralized Identifier) of the mediation request. + */ final class MediationRequest @JvmOverloads constructor( val id: String, val type: String = ProtocolType.DidcommMediationRequest.value, val from: DID, val to: DID ) { + /** + * The `MediationRequest` class represents a request for mediation between two entities. + * It contains information about the sender (`from`) and the recipient (`to`) of the mediation request. + * + * @property id The unique identifier of the mediation request. + * @property from The DID of the entity sending the request. + * @property to The DID of the entity receiving the request. + * + * @constructor Creates a new `MediationRequest` object with the specified `from` and `to` DIDs. + * The `id` is automatically generated using a random UUID. + */ constructor( from: DID, to: DID @@ -21,6 +45,11 @@ final class MediationRequest @JvmOverloads constructor( to = to ) + /** + * Creates a new [Message] object with default values for some properties and returns it. + * + * @return The newly created [Message] object. + */ fun makeMessage(): Message { return Message( id = id, @@ -38,6 +67,14 @@ final class MediationRequest @JvmOverloads constructor( ) } + /** + * Checks if this [MediationRequest] object is equal to another object. + * + * Two [MediationRequest] objects are considered equal if their properties match. + * + * @param other The object to compare equality with. + * @return true if this [MediationRequest] object is equal to the [other] object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -52,6 +89,11 @@ final class MediationRequest @JvmOverloads constructor( return true } + /** + * Generates the hash code for the `MediationRequest` object. + * + * @return The hash code value for the `MediationRequest` object. + */ override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + type.hashCode() diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/DIDCommInvitationRunner.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/DIDCommInvitationRunner.kt index 836afdd6e..536dab3f6 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/DIDCommInvitationRunner.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/DIDCommInvitationRunner.kt @@ -6,14 +6,26 @@ import io.ktor.http.Url import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json +/** + * This class represents a runner for the DIDComm Invitation protocol. It is responsible for running the invitation + * process and parsing the invitation message. + * + * @property url The URL of the invitation message. + */ internal class DIDCommInvitationRunner(private val url: Url) { + /** + * Runs the DIDComm Invitation protocol. + * + * @return The parsed OutOfBandInvitation message. + * @throws PrismAgentError.UnknownInvitationTypeError If the type of the invitation is unknown or unsupported. + */ @Throws(PrismAgentError.UnknownInvitationTypeError::class) internal suspend fun run(): OutOfBandInvitation { val messageString = OutOfBandParser().parseMessage(url) val message: OutOfBandInvitation = Json.decodeFromString(messageString) if (message.type != ProtocolType.Didcomminvitation) { - throw PrismAgentError.UnknownInvitationTypeError() + throw PrismAgentError.UnknownInvitationTypeError(message.type.toString()) } return message } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/InvitationRunner.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/InvitationRunner.kt index 42e7cfb1c..2c54c1825 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/InvitationRunner.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/InvitationRunner.kt @@ -4,7 +4,19 @@ import io.iohk.atala.prism.walletsdk.domain.buildingblocks.Mercury import io.iohk.atala.prism.walletsdk.domain.models.Message import io.ktor.http.Url +/** + * The InvitationRunner class is responsible for running the invitation process by parsing the out-of-band URL, + * unpacking the message, and returning the unpacked message object. + * + * @param mercury The Mercury interface implementation used for packing and unpacking messages. + * @param url The URL object representing the out-of-band URL. + */ class InvitationRunner(private val mercury: Mercury, private val url: Url) { + /** + * Runs the invitation process by parsing the out-of-band URL, unpacking the message, and returning the unpacked message object. + * + * @return The unpacked [Message] object. + */ suspend fun run(): Message { val messageString = OutOfBandParser().parseMessage(url) return mercury.unpackMessage(messageString) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/InvitationType.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/InvitationType.kt index 152d6a530..22aab2a7a 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/InvitationType.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/InvitationType.kt @@ -2,5 +2,8 @@ package io.iohk.atala.prism.walletsdk.prismagent.protocols.outOfBand import kotlinx.serialization.Serializable +/** + * Represents a sealed class for different types of invitations. + */ @Serializable sealed class InvitationType diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/OutOfBandParser.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/OutOfBandParser.kt index 373760eef..9ac6da753 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/OutOfBandParser.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/OutOfBandParser.kt @@ -6,8 +6,18 @@ import io.iohk.atala.prism.walletsdk.prismagent.OOB import io.ktor.http.URLBuilder import io.ktor.http.Url +/** + * The OutOfBandParser class is responsible for parsing out-of-band messages. + */ class OutOfBandParser { + /** + * Parses the message from the given URL. + * + * @param url The URL object representing the message. + * @return The parsed message. + * @throws CommonError.InvalidURLError If the URL is invalid. + */ @Throws(CommonError.InvalidURLError::class) fun parseMessage(url: Url): String { val urlBuilder = URLBuilder(url) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/PrismOnboardingInvitation.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/PrismOnboardingInvitation.kt index 2b2a5ab20..bcd927fb1 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/PrismOnboardingInvitation.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/outOfBand/PrismOnboardingInvitation.kt @@ -8,6 +8,14 @@ import kotlinx.serialization.Transient import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json +/** + * Represents an onboarding invitation for PRISM. + * + * @param onboardEndpoint The endpoint for onboarding. + * @property fromString The string representation of the "from" field. + * @property from The DID object representing the "from" field. + * @property type The type of the invitation. + */ @Serializable data class PrismOnboardingInvitation @JvmOverloads constructor( val onboardEndpoint: String, @@ -24,6 +32,13 @@ data class PrismOnboardingInvitation @JvmOverloads constructor( } companion object { + /** + * Parses a JSON string into a PrismOnboardingInvitation object. + * + * @param string The JSON string to parse. + * @return A PrismOnboardingInvitation object parsed from the JSON string. + */ + @JvmStatic fun fromJsonString(string: String): PrismOnboardingInvitation { return Json.decodeFromString(string) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupDelivery.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupDelivery.kt index cbd8f3f29..8e6fa9de5 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupDelivery.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupDelivery.kt @@ -5,6 +5,16 @@ import io.iohk.atala.prism.walletsdk.domain.models.Message import io.iohk.atala.prism.walletsdk.prismagent.PrismAgentError import io.iohk.atala.prism.walletsdk.prismagent.protocols.ProtocolType +/** + * The `PickupDelivery` class represents a pickup delivery protocol type in the Atala PRISM architecture. + * It is a final class, meaning it cannot be subclassed. + * + * @throws (PrismAgentError.InvalidMessageType):: if the protocol type of the given message is not `ProtocolType.PickupDelivery`. + * + * @property id: The id of the pickup delivery. + * @property type: The protocol type of the pickup delivery, always set to `ProtocolType.PickupDelivery.value`. + * @property attachments: An array of attachment descriptors associated with the pickup delivery. + */ final class PickupDelivery @Throws(PrismAgentError.InvalidMessageType::class) constructor(fromMessage: Message) { diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupReceived.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupReceived.kt index 4e7e3ec38..866c37e41 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupReceived.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupReceived.kt @@ -10,26 +10,27 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -final class PickupReceived { - var id: String - var type = ProtocolType.PickupReceived.value - val from: DID - val to: DID +/** + * Represents a pickup received message. + * + * @property id The unique identifier of the pickup received message. If not provided, a random UUID will be generated. + * @property from The sender's DID (Decentralized Identifier) of the pickup received message. + * @property to The recipient's DID (Decentralized Identifier) of the pickup received message. + * @property body The body of the pickup received message. + */ +final class PickupReceived @JvmOverloads constructor( + var id: String = UUID.randomUUID4().toString(), + val from: DID, + val to: DID, var body: Body +) { + var type = ProtocolType.PickupReceived.value - @JvmOverloads - constructor( - id: String = UUID.randomUUID4().toString(), - from: DID, - to: DID, - body: Body - ) { - this.id = id - this.from = from - this.to = to - this.body = body - } - + /** + * Creates a [Message] object for sending a message. + * + * @return A [Message] object representing the message to send. + */ fun makeMessage(): Message { return Message( piuri = type, @@ -40,19 +41,45 @@ final class PickupReceived { ) } + /** + * Represents a body of a message. + * + * @property messageIdList An array of message IDs. + */ @Serializable data class Body(@SerialName(MESSAGE_ID_LIST) var messageIdList: Array) { + /** + * Overrides the default implementation of `equals` defined in the `Any` class. + * This method checks if the current instance is equal to the specified [other] object. + * + * Two objects are considered equal if they meet the following conditions: + * - They refer to the same memory address (identity check) + * - They are of the same class + * - The [messageIdList] property of both objects is equal + * + * @param other The object to compare equality with + * @return `true` if the objects are equal, `false` otherwise + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as Body - if (!messageIdList.contentEquals(other.messageIdList)) return false - - return true + return messageIdList.contentEquals(other.messageIdList) } + /** + * Returns the hash code value for this object. + * + * This method overrides the default implementation of `hashCode` defined in the `Any` class. + * The hash code of an object is an integer value that represents its unique identity. + * Two objects that are equal must also have the same hash code. + * + * This implementation calculates the hash code based on the content of the `messageIdList` array. + * + * @return the hash code value for this object + */ override fun hashCode(): Int { return messageIdList.contentHashCode() } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupRequest.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupRequest.kt index b96d36917..b481b8612 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupRequest.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupRequest.kt @@ -8,6 +8,16 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +/** + * A class representing a pickup request. + * + * @property id The unique identifier of the pickup request. + * @property from The sender's DID (Decentralized Identifier). + * @property to The receiver's DID (Decentralized Identifier). + * @property body The body of the pickup request. + * @property type The type of the pickup request. + * @constructor Creates a pickup request with the specified parameters. + */ final class PickupRequest @JvmOverloads constructor( var id: String = UUID.randomUUID4().toString(), val from: DID, @@ -16,6 +26,11 @@ final class PickupRequest @JvmOverloads constructor( ) { var type = ProtocolType.PickupRequest.value + /** + * Creates a [Message] object using the provided parameters. + * + * @return The created [Message] object. + */ fun makeMessage(): Message { return Message( id = id, @@ -35,6 +50,13 @@ final class PickupRequest @JvmOverloads constructor( ) } + /** + * A class representing the body of a message. + * + * @property recipientKey The key of the message recipient. + * @property limit The maximum number of messages to pick up. + * @constructor Creates a Body object with the specified parameters. + */ @Serializable data class Body(var recipientKey: String? = null, var limit: Int) } diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupRunner.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupRunner.kt index f92c5671f..2a4e117ca 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupRunner.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/pickup/PickupRunner.kt @@ -9,15 +9,43 @@ import io.iohk.atala.prism.walletsdk.domain.models.Message import io.iohk.atala.prism.walletsdk.prismagent.PrismAgentError import io.iohk.atala.prism.walletsdk.prismagent.protocols.ProtocolType +/** + * The `PickupRunner` class is responsible for processing `Message` objects related to pickup requests and delivering them + * using the `Mercury` service. It provides methods to run the pickup request and process the response. + * + * @property message The pickup request message to process. + * @property mercury The `Mercury` service to use for message delivery. + */ class PickupRunner(message: Message, private val mercury: Mercury) { + /** + * The [PickupResponseType] enum class represents the response types for the pickup functionality. + * The response types can be either "status" or "delivery". + * + * @property type The string representation of the pickup response type. + * @constructor Creates a [PickupResponseType] enum with the given type string. + */ enum class PickupResponseType(val type: String) { STATUS("status"), DELIVERY("delivery") } + /** + * The `PickupResponse` data class represents the response from the pickup functionality. + * It includes the type of response (`PickupResponseType`) and a `Message` object. + * + * @property type The type of pickup response. + * @property message The message object. + */ data class PickupResponse(val type: PickupResponseType, val message: Message) + /** + * The [PickupAttachment] data class represents an attachment in the pickup functionality. + * It includes the attachment ID and the attachment data. + * + * @property attachmentId The ID of the attachment. + * @property data The data of the attachment. + */ data class PickupAttachment( val attachmentId: String, val data: String @@ -44,6 +72,13 @@ class PickupRunner(message: Message, private val mercury: Mercury) { } } + /** + * Runs the pickup functionality and returns an array of pairs containing attachment IDs and unpacked messages. + * If the type of the pickup response is DELIVERY, it processes the attachments, unpacks the messages, and returns them as an array. + * If the type is not DELIVERY, it returns an empty array. + * + * @return An array of pairs containing attachment IDs and unpacked messages. + */ suspend fun run(): Array> { return if (message.type == PickupResponseType.DELIVERY) { message.message.attachments @@ -55,7 +90,13 @@ class PickupRunner(message: Message, private val mercury: Mercury) { } } - // TODO: Clean this method + /** + * Process the given attachment and convert it to a PickupAttachment object. + * + * @param attachment The AttachmentDescriptor to be processed. + * @return The PickupAttachment object if the attachment data is of type AttachmentBase64 or AttachmentJsonData, otherwise null. + * @TODO: Clean this method + */ private fun processAttachment(attachment: AttachmentDescriptor): PickupAttachment? { return if (Message.isBase64Attachment(attachment.data)) { PickupAttachment(attachmentId = attachment.id, data = (attachment.data as AttachmentBase64).base64.base64UrlDecoded) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/prismOnboarding/PrismOnboardingInvitation.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/prismOnboarding/PrismOnboardingInvitation.kt index db1891f26..b2fe94683 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/prismOnboarding/PrismOnboardingInvitation.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/prismOnboarding/PrismOnboardingInvitation.kt @@ -5,6 +5,15 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json +/** + * Represents an onboarding invitation in PRISM. + * + * This class is responsible for parsing and storing the information from a PRISM onboarding invitation. + * + * @constructor Creates a PrismOnboardingInvitation object from a JSON string representation of the invitation. + * @param jsonString The JSON string representation of the invitation. + * @throws PrismAgentError.InvitationIsInvalidError If the JSON string is invalid and cannot be parsed. + */ class PrismOnboardingInvitation @Throws(PrismAgentError.InvitationIsInvalidError::class) constructor(jsonString: String) { @@ -23,6 +32,13 @@ constructor(jsonString: String) { } } + /** + * Represents the body of an invitation in the PrismOnboardingInvitation class. + * + * @property type The type of the invitation. + * @property onboardEndpoint The onboard endpoint of the invitation. + * @property from The sender of the invitation. + */ @Serializable data class Body( val type: String, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/Presentation.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/Presentation.kt index 74c27727d..7e210a998 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/Presentation.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/Presentation.kt @@ -11,12 +11,25 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +/** + * Data class representing proof types. + * + * @property schema The schema of the proof. + * @property requiredFields An optional array of required fields for the proof. + * @property trustIssuers An optional array of trusted issuers for the proof. + */ @Serializable data class ProofTypes( val schema: String, val requiredFields: Array?, val trustIssuers: Array? ) { + /** + * Overrides the equals method from the Any class to compare two ProofTypes objects for equality. + * + * @param other The object to compare for equality. + * @return true if the objects are equal, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -36,6 +49,11 @@ data class ProofTypes( return true } + /** + * Overrides the hashCode method from the Any class to generate a hash code for the ProofTypes object. + * + * @return The hash code value for the ProofTypes object. + */ override fun hashCode(): Int { var result = schema.hashCode() result = 31 * result + (requiredFields?.contentHashCode() ?: 0) @@ -44,6 +62,18 @@ data class ProofTypes( } } +/** + * The Presentation class represents a presentation message in the PrismAgent software. + * It contains the necessary information for constructing a presentation message. + * + * @property type The type of the presentation message. + * @property id The unique identifier for the presentation message. + * @property body The body of the presentation message, including goal code and comment. + * @property attachments An array of AttachmentDescriptor objects representing the attachments in the message. + * @property thid The thread ID of the presentation message. + * @property from The sender's DID. + * @property to The recipient's DID. + */ class Presentation { val type = ProtocolType.DidcommPresentation.value lateinit var id: String @@ -53,6 +83,17 @@ class Presentation { lateinit var from: DID lateinit var to: DID + /** + * The Presentation class represents a presentation message in the PrismAgent software. + * It contains the necessary information for constructing a presentation message. + * + * @param id The unique identifier for the presentation message. + * @param body The body of the presentation message, including goal code and comment. + * @param attachments An array of AttachmentDescriptor objects representing the attachments in the message. + * @param thid The thread ID of the presentation message. + * @param from The sender's DID. + * @param to The recipient's DID. + */ @JvmOverloads constructor( id: String? = null, @@ -70,6 +111,12 @@ class Presentation { this.to = to } + /** + * Constructor for creating a Presentation object from a Message object. + * + * @param fromMessage The Message object to create Presentation from. + * @throws PrismAgentError.InvalidMessageType if the message type does not represent the protocol "didcomm.presentation" or if the message does not have "from" and "to" fields. + */ @Throws(PrismAgentError.InvalidMessageType::class) constructor(fromMessage: Message) { if ( @@ -94,6 +141,11 @@ class Presentation { } } + /** + * Creates a new [Message] object based on the provided parameters. + * + * @return The newly created [Message] object. + */ fun makeMessage(): Message { return Message( id = id, @@ -106,6 +158,13 @@ class Presentation { ) } + /** + * Converts a message into a Presentation object. + * + * @param msg The input message to convert. + * @return The converted Presentation object. + * @throws PrismAgentError.InvalidMessageType If the message type is invalid. + */ @Throws(PrismAgentError.InvalidMessageType::class) fun makePresentationFromRequest(msg: Message): Presentation { val requestPresentation = RequestPresentation.fromMessage(msg) @@ -121,6 +180,12 @@ class Presentation { ) } + /** + * Compares this Presentation object with the specified object for equality. + * + * @param other The object to compare with this Presentation object. + * @return `true` if the specified object is equal to this Presentation object, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (other == null) return false if (other::class != this::class) return false @@ -134,6 +199,20 @@ class Presentation { otherPresentation.to == this.to } + /** + * Calculates the hash code value for the Presentation object. + * + * The hash code is calculated based on the values of the following properties: + * - type + * - id + * - body + * - attachments + * - thid (nullable) + * - from + * - to + * + * @return The hash code value for the Presentation object. + */ override fun hashCode(): Int { var result = type.hashCode() result = 31 * result + id.hashCode() @@ -145,6 +224,12 @@ class Presentation { return result } + /** + * Represents the body of a Presentation object. + * + * @param goalCode The goal code of the presentation body. + * @param comment The comment associated with the presentation body. + */ @Serializable data class Body @JvmOverloads constructor( val goalCode: String? = null, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/ProposePresentation.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/ProposePresentation.kt index 4b02f2fba..cf1e68b19 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/ProposePresentation.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/ProposePresentation.kt @@ -14,6 +14,19 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +/** + * Class representing a proposal for a presentation. + * + * @property id The ID of the presentation. + * @property type The type of the presentation. + * @property body The body of the presentation. + * @property attachments The attachments of the presentation. + * @property thid The thread ID of the presentation. + * @property from The sender of the presentation. + * @property to The recipient of the presentation. + * @constructor Creates a ProposePresentation instance. + * @throws PrismAgentError.InvalidMessageType If the message type is invalid. + */ class ProposePresentation { lateinit var id: String @@ -24,6 +37,17 @@ class ProposePresentation { lateinit var from: DID lateinit var to: DID + /** + * The `ProposePresentation` class represents a proposal for a presentation in the Prism agent. + * It is used to create a new `ProposePresentation` object with the given parameters. + * + * @param id The ID of the proposal. If not provided, a new random UUID will be generated. + * @param body The body of the proposal, including goal code, comment, and proof types. + * @param attachments An array of attachment descriptors for the proposal. + * @param thid The thread ID of the message. + * @param from The sender's DID. + * @param to The recipient's DID. + */ @JvmOverloads constructor( id: String? = UUID.randomUUID4().toString(), @@ -41,6 +65,13 @@ class ProposePresentation { this.to = to } + /** + * Constructs a ProposePresentation object by processing a Message. + * + * @throws PrismAgentError.InvalidMessageType if the fromMessage does not represent the expected protocol type + * + * @param fromMessage the input Message object + */ @Throws(PrismAgentError.InvalidMessageType::class) constructor(fromMessage: Message) { if (fromMessage.piuri == ProtocolType.DidcommProposePresentation.value && @@ -63,6 +94,12 @@ class ProposePresentation { } } + /** + * Creates a [Message] object based on the current state of the [ProposePresentation] instance. + * The [Message] object includes information about the sender, recipient, message body, and other metadata. + * + * @return The created [Message] object. + */ fun makeMessage(): Message { return Message( id = this.id, @@ -75,6 +112,13 @@ class ProposePresentation { ) } + /** + * Creates a proposal presentation from a request message. + * + * @param msg The request message. + * @return The created `ProposePresentation` object. + * @throws PrismAgentError.InvalidMessageType If the message type does not represent the expected protocol. + */ @Throws(PrismAgentError.InvalidMessageType::class) fun makeProposalFromRequest(msg: Message): ProposePresentation { val request = RequestPresentation.fromMessage(msg) @@ -92,6 +136,12 @@ class ProposePresentation { ) } + /** + * Compares this object with the specified object for equality. + * + * @param other the object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (other == null) return false if (other::class != this::class) return false @@ -105,6 +155,20 @@ class ProposePresentation { otherPresentation.to == this.to } + /** + * Calculates the hash code of the [ProposePresentation] instance. + * + * The hash code is calculated based on the following fields of the instance: + * - id + * - type + * - body + * - attachments + * - thid (nullable) + * - from + * - to + * + * @return The hash code of the [ProposePresentation] instance. + */ override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + type.hashCode() @@ -116,6 +180,13 @@ class ProposePresentation { return result } + /** + * Represents the body of a message in the ProposePresentation protocol. + * + * @property goalCode The goal code for the presentation. + * @property comment Additional comment about the presentation. + * @property proofTypes An array of proof types. + */ @Serializable data class Body @JvmOverloads constructor( @SerialName(GOAL_CODE) @@ -124,6 +195,12 @@ class ProposePresentation { @SerialName(PROOF_TYPES) val proofTypes: Array ) { + /** + * Compares this [Body] object with the specified object for equality. + * + * @param other the object to compare for equality. + * @return `true` if the objects are equal, `false` otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -137,6 +214,16 @@ class ProposePresentation { return true } + /** + * Calculates the hash code of the [Body] instance. + * + * The hash code is calculated based on the following fields of the instance: + * - goalCode + * - comment + * - proofTypes + * + * @return The hash code of the [Body] instance. + */ override fun hashCode(): Int { var result = goalCode?.hashCode() ?: 0 result = 31 * result + (comment?.hashCode() ?: 0) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/RequestPresentation.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/RequestPresentation.kt index 37ea31119..bf6fc882e 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/RequestPresentation.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/proofOfPresentation/RequestPresentation.kt @@ -15,6 +15,16 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +/** + * The `RequestPresentation` class represents a request for presentation of credentials or proofs in a DIDComm protocol. + * + * @property id The unique identifier of the request. + * @property body The content of the request. + * @property attachments The array of attachment descriptors associated with the request. + * @property thid The thread ID of the request message. Default value is `null`. + * @property from The DID of the sender of the request. + * @property to The DID of the recipient of the request. + */ data class RequestPresentation( val id: String = UUID.randomUUID4().toString(), val body: Body, @@ -26,6 +36,13 @@ data class RequestPresentation( val type = ProtocolType.DidcommRequestPresentation.value + /** + * Creates a new [Message] object based on the current state of the [RequestPresentation] instance. + * The [Message] object contains information about the sender, recipient, message body, and other metadata. + * This method is typically used to convert a [RequestPresentation] instance into a [Message] object for communication purposes. + * + * @return The newly created [Message] object. + */ fun makeMessage(): Message { return Message( id = this.id, @@ -38,6 +55,16 @@ data class RequestPresentation( ) } + /** + * Checks if this [RequestPresentation] object is equal to the specified [other] object. + * + * Two [RequestPresentation] objects are considered equal if they meet the following conditions: + * - The two objects have the same class type. + * - The id, body, attachments, thid, from, to, and type properties of the two objects are also equal. + * + * @param other The object to compare with this [RequestPresentation] object. + * @return true if the specified [other] object is equal to this [RequestPresentation] object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -53,6 +80,20 @@ data class RequestPresentation( return type == other.type } + /** + * Calculates the hash code for the [RequestPresentation] object. + * + * The hash code is calculated based on the following properties of the [RequestPresentation] object: + * - [id] + * - [body] + * - [attachments] + * - [thid] + * - [from] + * - [to] + * - [type] + * + * @return The hash code value for the [RequestPresentation] object. + */ override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + body.hashCode() @@ -65,6 +106,14 @@ data class RequestPresentation( } companion object { + /** + * Converts a given [Message] object to a [RequestPresentation] object. + * + * @param fromMessage The [Message] object to convert. + * @return The converted [RequestPresentation] object. + * @throws PrismAgentError.InvalidMessageType if the [Message] object does not represent the correct protocol + * or if it is missing the "from" and "to" fields. + */ @JvmStatic @Throws(PrismAgentError.InvalidMessageType::class) fun fromMessage(fromMessage: Message): RequestPresentation { @@ -88,6 +137,13 @@ data class RequestPresentation( } } + /** + * Creates a [RequestPresentation] object based on the given [msg]. + * + * @param msg The [Message] object representing a proposal. + * @return The newly created [RequestPresentation] object. + * @throws PrismAgentError.InvalidMessageType if the message type is invalid. + */ @JvmStatic @Throws(PrismAgentError.InvalidMessageType::class) fun makeRequestFromProposal(msg: Message): RequestPresentation { @@ -108,6 +164,14 @@ data class RequestPresentation( } } + /** + * Represents a class that encapsulates the body of a message. + * + * @property goalCode The goal code associated with the body. + * @property comment The comment associated with the body. + * @property willConfirm A boolean indicating whether confirmation is required. + * @property proofTypes An array of proof types. + */ @Serializable data class Body @JvmOverloads constructor( @SerialName(GOAL_CODE) @@ -118,6 +182,16 @@ data class RequestPresentation( @SerialName(PROOF_TYPES) val proofTypes: Array ) { + /** + * Checks if this [Body] object is equal to the specified [other] object. + * + * Two [Body] objects are considered equal if they meet the following conditions: + * - The two objects have the same class type. + * - The goalCode, comment, willConfirm, and proofTypes properties of the two objects are also equal. + * + * @param other The object to compare with this [Body] object. + * @return true if the specified [other] object is equal to this [Body] object, false otherwise. + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -132,6 +206,17 @@ data class RequestPresentation( return true } + /** + * Calculates the hash code for the current object. + * + * The hash code is calculated based on the values of the following properties: + * - goalCode + * - comment + * - willConfirm + * - proofTypes + * + * @return The hash code value for the current object. + */ override fun hashCode(): Int { var result = goalCode?.hashCode() ?: 0 result = 31 * result + (comment?.hashCode() ?: 0) diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/shared/KeyValue.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/shared/KeyValue.kt index fdcfb3e6a..6df3c68e9 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/shared/KeyValue.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/shared/KeyValue.kt @@ -2,6 +2,12 @@ package io.iohk.atala.prism.walletsdk.prismagent.shared import kotlinx.serialization.Serializable +/** + * Represents a key-value pair. + * + * @param key The key. + * @param value The value. + */ @Serializable data class KeyValue( val key: String, diff --git a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/shared/PrismShared.kt b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/shared/PrismShared.kt index 153fe55c0..65f626ce3 100644 --- a/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/shared/PrismShared.kt +++ b/atala-prism-sdk/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/shared/PrismShared.kt @@ -9,7 +9,16 @@ import io.ktor.http.Url import io.ktor.http.contentType import io.ktor.http.path +/** + * Utility class for shared functionality used by Prism API. + */ internal object PrismShared { + /** + * Maps an array of [KeyValue] objects to a [Map] with key-value pairs. + * + * @param array The array of [KeyValue] objects to be mapped. + * @return A [Map] containing the key-value pairs from the array. + */ @JvmStatic fun mapFromKeyValueArray(array: Array): Map { val response = mutableMapOf() @@ -19,6 +28,16 @@ internal object PrismShared { return response } + /** + * Constructs an HTTP request builder with the specified parameters. + * + * @param httpMethod the HTTP method to be used for the request (e.g., "GET", "POST", "PUT", "DELETE", etc.) + * @param url the URL to send the request to + * @param urlParametersArray the array of URL parameters to be included in the request (default is an empty array) + * @param httpHeadersArray the array of HTTP headers to be included in the request (default is an empty array) + * @param body the request body to be sent with the request (default is null) + * @return the constructed HttpRequestBuilder object + */ @JvmStatic fun getRequestBuilder( httpMethod: HttpMethod, diff --git a/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/apollo/ApolloTests.kt b/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/apollo/ApolloTests.kt index afa0f98cc..712054168 100644 --- a/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/apollo/ApolloTests.kt +++ b/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/apollo/ApolloTests.kt @@ -199,7 +199,7 @@ class ApolloTests { fun testSignAndVerify_whenSignatureIsIncorrect_thenVerifyFails() { val keyPair = Ed25519KeyPair.generateKeyPair() val message = "This is a test message" - var signature = (keyPair.privateKey as Ed25519PrivateKey).sign(message.toByteArray()) + val signature = (keyPair.privateKey as Ed25519PrivateKey).sign(message.toByteArray()) signature[0] = 1 assertFalse((keyPair.publicKey as Ed25519PublicKey).verify(message.toByteArray(), signature)) } diff --git a/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PolluxMock.kt b/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PolluxMock.kt index 0a5d97c26..7acd24254 100644 --- a/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PolluxMock.kt +++ b/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PolluxMock.kt @@ -20,7 +20,7 @@ class PolluxMock : Pollux { var processCredentialRequestAnoncredsReturn: Pair? = null override suspend fun parseCredential( - data: String, + jsonData: String, type: CredentialType, linkSecret: LinkSecret?, credentialMetadata: CredentialRequestMetadata? diff --git a/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt b/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt index e737dede6..8a92c10e9 100644 --- a/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt +++ b/atala-prism-sdk/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt @@ -31,6 +31,7 @@ import io.iohk.atala.prism.walletsdk.prismagent.protocols.outOfBand.PrismOnboard import io.ktor.http.HttpStatusCode import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.runTest +import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json import kotlin.test.BeforeTest import kotlin.test.Test @@ -225,7 +226,7 @@ class PrismAgentTests { "from":"did:prism:b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k" } """ - assertFailsWith { + assertFailsWith { agent.parseInvitation(invitationString) } } @@ -351,7 +352,7 @@ class PrismAgentTests { } """ - assertFailsWith { + assertFailsWith { agent.parseInvitation(invitationString.trim()) } } diff --git a/atala-prism-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt b/atala-prism-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt index 7c0b24e72..b5adbbc89 100644 --- a/atala-prism-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt +++ b/atala-prism-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/domain/models/Platform.kt @@ -2,7 +2,7 @@ package io.iohk.atala.prism.walletsdk.domain.models actual object Platform { actual val OS: String - get() = "JVM" + get() = "JVM - ${System.getProperty("java.runtime.name")} - ${System.getProperty("java.runtime.version")}" actual val type: PlatformType get() = PlatformType.JVM } diff --git a/protosLib/build.gradle.kts b/protosLib/build.gradle.kts index 53b89517f..f5b6d2ddf 100644 --- a/protosLib/build.gradle.kts +++ b/protosLib/build.gradle.kts @@ -10,7 +10,7 @@ plugins { // Mock configuration which derives compile only. // Needed to resolve jar files of the dependency -val jarPathConf by configurations.creating { +val jarPathConf: Configuration by configurations.creating { extendsFrom(configurations.compileOnly.get()) } diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/Sdk.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/Sdk.kt index c1eb371ab..123c8bb37 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/Sdk.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/Sdk.kt @@ -144,6 +144,7 @@ class Sdk { companion object { private lateinit var instance: Sdk + @JvmStatic fun getInstance(): Sdk { if (!this::instance.isInitialized) { instance = Sdk() diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/agent/AgentFragment.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/agent/AgentFragment.kt index c4e2e2374..186a3509f 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/agent/AgentFragment.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/agent/AgentFragment.kt @@ -43,6 +43,7 @@ class AgentFragment : Fragment() { } companion object { + @JvmStatic fun newInstance(): AgentFragment { return AgentFragment() } diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsAdapter.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsAdapter.kt index d6d800a53..08f6fc855 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsAdapter.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsAdapter.kt @@ -53,13 +53,8 @@ class ContactsAdapter(private var data: MutableList = mutableListOf()) } inner class ContactsHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val host: TextView - private val receiver: TextView - - init { - host = itemView.findViewById(R.id.contact_host) - receiver = itemView.findViewById(R.id.contact_receiver) - } + private val host: TextView = itemView.findViewById(R.id.contact_host) + private val receiver: TextView = itemView.findViewById(R.id.contact_receiver) fun bind(contact: DIDPair) { host.text = contact.host.toString() diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsFragment.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsFragment.kt index 61990d4ba..705cb6797 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsFragment.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsFragment.kt @@ -86,6 +86,7 @@ class ContactsFragment : Fragment() { } companion object { + @JvmStatic fun newInstance(): ContactsFragment { return ContactsFragment() } diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsViewModel.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsViewModel.kt index 1c1744f25..d1f7a0bdd 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsViewModel.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/contacts/ContactsViewModel.kt @@ -46,7 +46,7 @@ class ContactsViewModel(application: Application) : AndroidViewModel(application } else -> { - throw PrismAgentError.UnknownInvitationTypeError() + throw PrismAgentError.UnknownInvitationTypeError(invitation.toString()) } } } diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/credentials/CredentialsAdapter.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/credentials/CredentialsAdapter.kt index 6a36ee5bb..c9e0bcc52 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/credentials/CredentialsAdapter.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/credentials/CredentialsAdapter.kt @@ -59,21 +59,12 @@ class CredentialsAdapter(private var data: MutableList = mutableList } inner class CredentialHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val type: TextView - private val issuanceDate: TextView - private val expDate: TextView - private val typeString: String - private val issuanceString: String - private val expirationString: String - - init { - type = itemView.findViewById(R.id.credential_id) - issuanceDate = itemView.findViewById(R.id.credential_issuance_date) - expDate = itemView.findViewById(R.id.credential_expiration_date) - typeString = itemView.context.getString(R.string.credential_type) - issuanceString = itemView.context.getString(R.string.credential_issuance) - expirationString = itemView.context.getString(R.string.credential_expiration) - } + private val type: TextView = itemView.findViewById(R.id.credential_id) + private val issuanceDate: TextView = itemView.findViewById(R.id.credential_issuance_date) + private val expDate: TextView = itemView.findViewById(R.id.credential_expiration_date) + private val typeString: String = itemView.context.getString(R.string.credential_type) + private val issuanceString: String = itemView.context.getString(R.string.credential_issuance) + private val expirationString: String = itemView.context.getString(R.string.credential_expiration) fun bind(cred: Credential) { when (cred::class) { diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/credentials/CredentialsFragment.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/credentials/CredentialsFragment.kt index 9884ed686..1acea3229 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/credentials/CredentialsFragment.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/credentials/CredentialsFragment.kt @@ -43,6 +43,7 @@ class CredentialsFragment : Fragment() { } companion object { + @JvmStatic fun newInstance(): CredentialsFragment { return CredentialsFragment() } diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/dids/DIDsAdapter.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/dids/DIDsAdapter.kt index d2ce68d4a..8ed859e8f 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/dids/DIDsAdapter.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/dids/DIDsAdapter.kt @@ -52,11 +52,7 @@ class DIDsAdapter(private var data: MutableList = mutableListOf()) : } inner class DIDHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val did: TextView - - init { - did = itemView.findViewById(R.id.did) - } + private val did: TextView = itemView.findViewById(R.id.did) fun bind(did: DID) { this.did.text = did.toString() diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/dids/DIDsFragment.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/dids/DIDsFragment.kt index 377b7ac5d..be19238bd 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/dids/DIDsFragment.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/dids/DIDsFragment.kt @@ -46,6 +46,7 @@ class DIDsFragment : Fragment() { } companion object { + @JvmStatic fun newInstance(): DIDsFragment { return DIDsFragment() } diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/messages/MessagesAdapter.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/messages/MessagesAdapter.kt index 5a2acb298..64157975d 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/messages/MessagesAdapter.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/messages/MessagesAdapter.kt @@ -52,13 +52,8 @@ class MessagesAdapter(private var data: MutableList = mutableListOf()) } inner class MessageHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val type: TextView - private val body: TextView - - init { - type = itemView.findViewById(R.id.message_type) - body = itemView.findViewById(R.id.message) - } + private val type: TextView = itemView.findViewById(R.id.message_type) + private val body: TextView = itemView.findViewById(R.id.message) fun bind(message: Message) { type.text = message.piuri diff --git a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/messages/MessagesFragment.kt b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/messages/MessagesFragment.kt index ab2e042e9..8fd7c8419 100644 --- a/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/messages/MessagesFragment.kt +++ b/sampleapp/src/main/java/io/iohk/atala/prism/sampleapp/ui/messages/MessagesFragment.kt @@ -46,6 +46,7 @@ class MessagesFragment : Fragment() { } companion object { + @JvmStatic fun newInstance(): MessagesFragment { return MessagesFragment() }