From 393c29654b8d3d53071f0d2932a16ff81688ece6 Mon Sep 17 00:00:00 2001 From: Bassam Date: Mon, 6 May 2024 05:26:27 -0400 Subject: [PATCH 01/14] fix: Fix OneOf OpenAPI Serialization Issue (#1010) Signed-off-by: Bassam Riman --- .../client/kotlin/.openapi-generator-ignore | 4 ++ .../client/models/DateTimeParameter.kt | 41 ++++++++++++++++++ .../identus/client/models/DidParameter.kt | 40 +++++++++++++++++ .../client/models/VcVerificationParameter.kt | 41 ++++++++++++++++++ .../controller/http/VcVerification.scala | 9 ++-- .../http/VcVerificationParameter.scala | 32 ++++++++++---- .../VcVerificationControllerImplSpec.scala | 43 +++++++++---------- 7 files changed, 175 insertions(+), 35 deletions(-) create mode 100644 cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/DateTimeParameter.kt create mode 100644 cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/DidParameter.kt create mode 100644 cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/VcVerificationParameter.kt diff --git a/cloud-agent/client/kotlin/.openapi-generator-ignore b/cloud-agent/client/kotlin/.openapi-generator-ignore index 6d1ca9e7b9..2f78a69926 100644 --- a/cloud-agent/client/kotlin/.openapi-generator-ignore +++ b/cloud-agent/client/kotlin/.openapi-generator-ignore @@ -11,3 +11,7 @@ src/main/kotlin/org/hyperledger/identus/client/models/ServiceType.kt src/main/kotlin/org/hyperledger/identus/client/models/StatusPurpose.kt src/main/kotlin/org/hyperledger/identus/client/models/CredentialSubject.kt + +src/main/kotlin/org/hyperledger/identus/client/models/DateTimeParameter.kt +src/main/kotlin/org/hyperledger/identus/client/models/DidParameter.kt +src/main/kotlin/org/hyperledger/identus/client/models/VcVerificationParameter.kt diff --git a/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/DateTimeParameter.kt b/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/DateTimeParameter.kt new file mode 100644 index 0000000000..be24c039e2 --- /dev/null +++ b/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/DateTimeParameter.kt @@ -0,0 +1,41 @@ +/** + * + * Please note: + * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + * + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package org.hyperledger.identus.client.models + + +import com.google.gson.annotations.SerializedName + +/** + * + * + * @param dateTime + * @param parameterType + */ + + +data class DateTimeParameter ( + + @SerializedName("did") + override val did: kotlin.String? = null, + + @SerializedName("parameterType") + override val parameterType: kotlin.String = "DateTimeParameter", + + @SerializedName("dateTime") + override val dateTime: java.time.OffsetDateTime, + +) : VcVerificationParameter + diff --git a/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/DidParameter.kt b/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/DidParameter.kt new file mode 100644 index 0000000000..bec73ad0d1 --- /dev/null +++ b/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/DidParameter.kt @@ -0,0 +1,40 @@ +/** + * + * Please note: + * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + * + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package org.hyperledger.identus.client.models + + +import com.google.gson.annotations.SerializedName + +/** + * + * + * @param did + * @param parameterType + */ + + +data class DidParameter ( + + @SerializedName("did") + override val did: kotlin.String, + + @SerializedName("parameterType") + override val parameterType: kotlin.String = "DidParameter", + + @get:SerializedName("dateTime") + override val dateTime: java.time.OffsetDateTime? = null, +) : VcVerificationParameter + diff --git a/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/VcVerificationParameter.kt b/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/VcVerificationParameter.kt new file mode 100644 index 0000000000..5ff79ee8e3 --- /dev/null +++ b/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/VcVerificationParameter.kt @@ -0,0 +1,41 @@ +/** + * + * Please note: + * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + * + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package org.hyperledger.identus.client.models + +import org.hyperledger.identus.client.models.DateTimeParameter +import org.hyperledger.identus.client.models.DidParameter + +import com.google.gson.annotations.SerializedName + +/** + * + * + * @param dateTime + * @param parameterType + * @param did + */ + + +interface VcVerificationParameter { + + @get:SerializedName("dateTime") + val dateTime: java.time.OffsetDateTime? + @get:SerializedName("parameterType") + val parameterType: kotlin.String + @get:SerializedName("did") + val did: kotlin.String? +} + diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/verification/controller/http/VcVerification.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/verification/controller/http/VcVerification.scala index 159d86cf62..13e90fd4e1 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/verification/controller/http/VcVerification.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/verification/controller/http/VcVerification.scala @@ -4,7 +4,7 @@ import org.hyperledger.identus.api.http.ErrorResponse import org.hyperledger.identus.pollux.core.service import org.hyperledger.identus.pollux.core.service.verification.VcVerification as ServiceVcVerification import sttp.tapir.Schema -import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} +import zio.json.{JsonDecoder, JsonEncoder} import zio.{IO, *} enum VcVerification { @@ -23,11 +23,12 @@ enum VcVerification { } object VcVerification { - given encoder: JsonEncoder[VcVerification] = - DeriveJsonEncoder.gen[VcVerification] + given encoder: JsonEncoder[VcVerification] = JsonEncoder[String].contramap(_.toString) given decoder: JsonDecoder[VcVerification] = - DeriveJsonDecoder.gen[VcVerification] + JsonDecoder[String].mapOrFail(s => + VcVerification.values.find(_.toString == s).toRight(s"Unknown VcVerification: $s") + ) given schema: Schema[VcVerification] = Schema.derivedEnumeration.defaultStringBased diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/verification/controller/http/VcVerificationParameter.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/verification/controller/http/VcVerificationParameter.scala index 4821fa3ba8..0ceba92f3f 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/verification/controller/http/VcVerificationParameter.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/verification/controller/http/VcVerificationParameter.scala @@ -5,19 +5,33 @@ import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} import java.time.OffsetDateTime -sealed trait VcVerificationParameter +sealed trait VcVerificationParameter(val parameterType: String) object VcVerificationParameter { - given encoder: JsonEncoder[VcVerificationParameter] = - DeriveJsonEncoder.gen[VcVerificationParameter] + given encoder: JsonEncoder[VcVerificationParameter] = DidParameter.encoder + .orElseEither(DateTimeParameter.encoder) + .contramap[VcVerificationParameter] { + case did: DidParameter => Left(did) + case dateTime: DateTimeParameter => Right(dateTime) + } + + given decoder: JsonDecoder[VcVerificationParameter] = DidParameter.decoder + .orElseEither(DateTimeParameter.decoder) + .map[VcVerificationParameter] { + case Left(did) => did + case Right(dateTime) => dateTime + } + + given schema: Schema[VcVerificationParameter] = + Schema + .oneOfUsingField[VcVerificationParameter, String](a => a.parameterType, t => t)( + ("DidParameter", DidParameter.schema), + ("DateTimeParameter", DateTimeParameter.schema) + ) - given decoder: JsonDecoder[VcVerificationParameter] = - DeriveJsonDecoder.gen[VcVerificationParameter] - - given schema: Schema[VcVerificationParameter] = Schema.derived } -case class DidParameter(aud: String) extends VcVerificationParameter +case class DidParameter(did: String) extends VcVerificationParameter("DidParameter") object DidParameter { given encoder: JsonEncoder[DidParameter] = @@ -29,7 +43,7 @@ object DidParameter { given schema: Schema[DidParameter] = Schema.derived } -case class DateTimeParameter(dateTime: OffsetDateTime) extends VcVerificationParameter +case class DateTimeParameter(dateTime: OffsetDateTime) extends VcVerificationParameter("DateTimeParameter") object DateTimeParameter { given encoder: JsonEncoder[DateTimeParameter] = diff --git a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/verification/controller/VcVerificationControllerImplSpec.scala b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/verification/controller/VcVerificationControllerImplSpec.scala index 1bbb9282ab..86ac30be9b 100644 --- a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/verification/controller/VcVerificationControllerImplSpec.scala +++ b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/verification/controller/VcVerificationControllerImplSpec.scala @@ -72,31 +72,30 @@ object VcVerificationControllerImplSpec extends ZIOSpecDefault with VcVerificati signedJwtCredential = issuer.signer.encode(jwtCredentialPayload.asJson) authenticator <- ZIO.service[AuthenticatorWithAuthZ[BaseEntity]] backend = httpBackend(vcVerificationController, authenticator) + request = List( + VcVerificationRequest( + signedJwtCredential.value, + List( + ParameterizableVcVerification(VcVerification.SignatureVerification, None), + ParameterizableVcVerification(VcVerification.NotBeforeCheck, Some(DateTimeParameter(currentTime))), + ParameterizableVcVerification(VcVerification.ExpirationCheck, Some(DateTimeParameter(currentTime))) + ) + ), + VcVerificationRequest( + signedJwtCredential.value, + List( + ParameterizableVcVerification(VcVerification.AudienceCheck, Some(DidParameter(verifier.value))), + ParameterizableVcVerification( + VcVerification.IssuerIdentification, + Some(DidParameter(issuer.did.value)) + ) + ) + ) + ).toJsonPretty response: Response[Either[DeserializationException[String], List[VcVerificationResponse]]] <- basicRequest .post(uri"${vcVerificationUriBase}") - .body( - List( - VcVerificationRequest( - signedJwtCredential.value, - List( - ParameterizableVcVerification(VcVerification.SignatureVerification, None), - ParameterizableVcVerification(VcVerification.NotBeforeCheck, Some(DateTimeParameter(currentTime))), - ParameterizableVcVerification(VcVerification.ExpirationCheck, Some(DateTimeParameter(currentTime))) - ) - ), - VcVerificationRequest( - signedJwtCredential.value, - List( - ParameterizableVcVerification(VcVerification.AudienceCheck, Some(DidParameter(verifier.value))), - ParameterizableVcVerification( - VcVerification.IssuerIdentification, - Some(DidParameter(issuer.did.value)) - ) - ) - ) - ).toJsonPretty - ) + .body(request) .response(asJsonAlways[List[VcVerificationResponse]]) .send(backend) statusCodeIs200 = assert(response.code)(equalTo(StatusCode.Ok)) From 46e594c21bdb43d78f41be6c803ad8b80dc89504 Mon Sep 17 00:00:00 2001 From: patlo-iog Date: Tue, 7 May 2024 14:04:14 +0700 Subject: [PATCH 02/14] fix: remove prism-crypto dependency (#1015) Signed-off-by: Pat Losoponkul --- build.sbt | 23 +---- .../castor/core/model/did/PrismDID.scala | 6 +- .../core/model/did/PrismDIDOperation.scala | 6 +- .../castor/core/model/did/PrismDIDSpec.scala | 10 +- .../apikey/ApiKeyAuthenticatorImpl.scala | 8 +- .../agent/walletapi/model/KeyManagement.scala | 4 +- .../vault/VaultDIDSecretStorage.scala | 6 +- .../vault/VaultGenericSecretStorage.scala | 4 +- .../identus/shared/crypto/Prism14Apollo.scala | 96 ------------------- .../identus/shared/crypto/Sha256.scala | 55 +++++++++++ 10 files changed, 82 insertions(+), 136 deletions(-) delete mode 100644 shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Prism14Apollo.scala create mode 100644 shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Sha256.scala diff --git a/build.sbt b/build.sbt index 655eac4939..0cfb605dac 100644 --- a/build.sbt +++ b/build.sbt @@ -67,6 +67,8 @@ lazy val V = new { val typesafeConfig = "1.4.3" val protobuf = "3.1.9" + val grpcOkHttp = "1.63.0" + val testContainersScala = "0.41.3" val testContainersJavaKeycloak = "3.2.0" // scala-steward:off @@ -77,7 +79,6 @@ lazy val V = new { val logback = "1.4.14" val slf4j = "2.0.13" - val prismSdk = "1.4.1" // scala-steward:off val scalaUri = "4.0.3" val jwtCirceVersion = "9.4.6" @@ -138,6 +139,7 @@ lazy val D = new { val scalaPbRuntime: ModuleID = "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf" val scalaPbGrpc: ModuleID = "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion + val grpcOkHttp: ModuleID = "io.grpc" % "grpc-okhttp" % V.grpcOkHttp val testcontainersPostgres: ModuleID = "com.dimafeng" %% "testcontainers-scala-postgresql" % V.testContainersScala % Test @@ -165,16 +167,6 @@ lazy val D = new { val monocleMacro: ModuleID = "dev.optics" %% "monocle-macro" % V.monocle % Test val apollo = "io.iohk.atala.prism.apollo" % "apollo-jvm" % V.apollo - // We have to exclude bouncycastle since for some reason bitcoinj depends on bouncycastle jdk15to18 - // (i.e. JDK 1.5 to 1.8), but we are using JDK 11 - val prismCrypto = "io.iohk.atala" % "prism-crypto-jvm" % V.prismSdk excludeAll - ExclusionRule( - organization = "org.bouncycastle" - ) - // Added here to make prism-crypto works. - // Once migrated to apollo, re-evaluate if this should be removed. - val bouncyBcpkix = "org.bouncycastle" % "bcpkix-jdk18on" % V.bouncyCastle - val bouncyBcprov = "org.bouncycastle" % "bcprov-jdk18on" % V.bouncyCastle // LIST of Dependencies val doobieDependencies: Seq[ModuleID] = @@ -204,9 +196,6 @@ lazy val D_SharedCrypto = new { Seq( D.zioJson, D.apollo, - D.bouncyBcpkix, - D.bouncyBcprov, - D.prismCrypto, // TODO: remove after migrated all primitives to apollo D.nimbusJwt, D.zioTest, D.zioTestSbt, @@ -290,7 +279,6 @@ lazy val D_Pollux = new { D.zioMock, D.munit, D.munitZio, - D.prismCrypto, // shared, logback, slf4jApi, @@ -399,7 +387,6 @@ lazy val D_CloudAgent = new { D.micrometer, D.micrometerPrometheusRegistry ) - val bouncyDependencies: Seq[ModuleID] = Seq(D.bouncyBcpkix, D.bouncyBcprov) val tapirDependencies: Seq[ModuleID] = Seq( tapirSwaggerUiBundle, @@ -417,7 +404,7 @@ lazy val D_CloudAgent = new { // Project Dependencies lazy val keyManagementDependencies: Seq[ModuleID] = - baseDependencies ++ bouncyDependencies ++ D.doobieDependencies ++ Seq(D.zioCatsInterop, D.zioMock, vaultDriver) + baseDependencies ++ D.doobieDependencies ++ Seq(D.zioCatsInterop, D.zioMock, vaultDriver) lazy val iamDependencies: Seq[ModuleID] = Seq(keycloakAuthz, D.jwtCirce) @@ -697,7 +684,7 @@ val prismNodeClient = project .in(file("prism-node/client/scala-client")) .settings( name := "prism-node-client", - libraryDependencies ++= Seq(D.scalaPbGrpc, D.scalaPbRuntime), + libraryDependencies ++= Seq(D.scalaPbGrpc, D.scalaPbRuntime, D.grpcOkHttp), coverageEnabled := false, // gRPC settings Compile / PB.targets := Seq(scalapb.gen() -> (Compile / sourceManaged).value / "scalapb"), diff --git a/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PrismDID.scala b/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PrismDID.scala index a929f65bc0..b204c38281 100644 --- a/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PrismDID.scala +++ b/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PrismDID.scala @@ -1,7 +1,7 @@ package org.hyperledger.identus.castor.core.model.did import org.hyperledger.identus.castor.core.model.ProtoModelHelper -import io.iohk.atala.prism.crypto.{Sha256, Sha256Digest} +import org.hyperledger.identus.shared.crypto.Sha256Hash import io.iohk.atala.prism.protos.node_models import io.iohk.atala.prism.protos.node_models.AtalaOperation.Operation import org.hyperledger.identus.shared.models.Base64UrlString @@ -30,7 +30,7 @@ object PrismDID extends ProtoModelHelper { val LONG_FORM_SUFFIX_REGEX: Regex = "^([0-9a-f]{64}):([A-Za-z0-9_-]+$)".r def buildCanonical(stateHash: Array[Byte]): Either[String, CanonicalPrismDID] = - Try(Sha256Digest.fromBytes(stateHash)).toEither.left + Try(Sha256Hash.fromBytes(stateHash)).toEither.left .map(_.getMessage) .map(_ => CanonicalPrismDID(HexString.fromByteArray(stateHash))) @@ -109,7 +109,7 @@ final case class LongFormPrismDID private[did] (atalaOperation: node_models.Atal override val stateHash: HexString = { val encodedState = atalaOperation.toByteArray - HexString.fromByteArray(Sha256.compute(encodedState).getValue) + HexString.fromByteArray(Sha256Hash.compute(encodedState).bytes.toArray) } override val suffix: DIDMethodSpecificId = { diff --git a/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDOperation.scala b/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDOperation.scala index 42cb8ec1e3..656abf4688 100644 --- a/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDOperation.scala +++ b/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDOperation.scala @@ -1,7 +1,7 @@ package org.hyperledger.identus.castor.core.model.did import org.hyperledger.identus.castor.core.model.ProtoModelHelper -import io.iohk.atala.prism.crypto.Sha256 +import org.hyperledger.identus.shared.crypto.Sha256Hash import scala.collection.compat.immutable.ArraySeq import io.iohk.atala.prism.protos.node_models @@ -9,7 +9,7 @@ import io.iohk.atala.prism.protos.node_models sealed trait PrismDIDOperation { def did: CanonicalPrismDID def toAtalaOperation: node_models.AtalaOperation - def toAtalaOperationHash: Array[Byte] = Sha256.compute(toAtalaOperation.toByteArray).getValue + def toAtalaOperationHash: Array[Byte] = Sha256Hash.compute(toAtalaOperation.toByteArray).bytes.toArray } object PrismDIDOperation extends ProtoModelHelper { @@ -38,7 +38,7 @@ final case class SignedPrismDIDOperation( import ProtoModelHelper.* this.toProto } - def toAtalaOperationId: Array[Byte] = Sha256.compute(toSignedAtalaOperation.toByteArray).getValue + def toAtalaOperationId: Array[Byte] = Sha256Hash.compute(toSignedAtalaOperation.toByteArray).bytes.toArray } final case class ScheduleDIDOperationOutcome( diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDSpec.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDSpec.scala index 54a18c23ed..ac4cade98a 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDSpec.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDSpec.scala @@ -1,7 +1,7 @@ package org.hyperledger.identus.castor.core.model.did import com.google.protobuf.ByteString -import io.iohk.atala.prism.crypto.{Sha256, Sha256Digest} +import org.hyperledger.identus.shared.crypto.Sha256Hash import io.iohk.atala.prism.protos.node_models import org.hyperledger.identus.shared.models.Base64UrlString import zio.* @@ -12,11 +12,11 @@ import org.hyperledger.identus.castor.core.model.did.PrismDID object PrismDIDSpec extends ZIOSpecDefault { private val canonicalSuffixHex = "9b5118411248d9663b6ab15128fba8106511230ff654e7514cdcc4ce919bde9b" - private val canonicalSuffix = Sha256Digest.fromHex(canonicalSuffixHex) + private val canonicalSuffix = Sha256Hash.fromHex(canonicalSuffixHex) private val encodedStateUsedBase64 = "Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VjcDI1NmsxEiEDHpf-yhIns-LP3tLvA8icC5FJ1ZlBwbllPtIdNZ3q0jU" - private val short = PrismDID.buildCanonical(canonicalSuffix.getValue).toOption.get + private val short = PrismDID.buildCanonical(canonicalSuffix.bytes.toArray).toOption.get private val long = PrismDID .buildLongFormFromAtalaOperation( node_models.AtalaOperation.parseFrom(Base64UrlString.fromStringUnsafe(encodedStateUsedBase64).toByteArray) @@ -27,7 +27,7 @@ object PrismDIDSpec extends ZIOSpecDefault { private val didParserSpec = suite("PrismDID.fromString")( test("success for valid DID") { - val stateHash = Sha256.compute(Array()).getValue + val stateHash = Sha256Hash.compute(Array()).bytes.toArray val validDID = PrismDID.buildCanonical(stateHash).toOption.get val unsafeDID = PrismDID.fromString(validDID.toString) assert(unsafeDID)(isRight(equalTo(validDID))) @@ -58,7 +58,7 @@ object PrismDIDSpec extends ZIOSpecDefault { ) val encodedState = mockAtalaOperation.toByteArray val encodedStateBase64 = Base64UrlString.fromByteArray(encodedState).toStringNoPadding - val stateHash = Sha256.compute(encodedState).getHexValue + val stateHash = Sha256Hash.compute(encodedState).hexEncoded val didString = s"did:prism:$stateHash:$encodedStateBase64" val unsafeDID = PrismDID.fromString(didString) assert(unsafeDID)(isLeft(containsString("CreateDid Atala operation expected"))) diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/apikey/ApiKeyAuthenticatorImpl.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/apikey/ApiKeyAuthenticatorImpl.scala index 364b0b1468..16d7b14c2c 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/apikey/ApiKeyAuthenticatorImpl.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/apikey/ApiKeyAuthenticatorImpl.scala @@ -5,7 +5,7 @@ import org.hyperledger.identus.agent.walletapi.model.Wallet import org.hyperledger.identus.agent.walletapi.service.{EntityService, WalletManagementService} import org.hyperledger.identus.iam.authentication.AuthenticationError import org.hyperledger.identus.iam.authentication.AuthenticationError.* -import io.iohk.atala.prism.crypto.Sha256 +import org.hyperledger.identus.shared.crypto.Sha256Hash import org.hyperledger.identus.shared.models.WalletAdministrationContext import org.hyperledger.identus.shared.models.WalletId import zio.{IO, URLayer, ZIO, ZLayer} @@ -73,7 +73,7 @@ case class ApiKeyAuthenticatorImpl( for { saltAndApiKey <- ZIO.succeed(apiKeyConfig.salt + apiKey) secret <- ZIO - .fromTry(Try(Sha256.compute(saltAndApiKey.getBytes).getHexValue)) + .fromTry(Try(Sha256Hash.compute(saltAndApiKey.getBytes).hexEncoded)) .logError("Failed to compute SHA256 hash") .mapError(cause => AuthenticationRepositoryError.UnexpectedError(cause)) entityId <- repository @@ -88,7 +88,7 @@ case class ApiKeyAuthenticatorImpl( for { saltAndApiKey <- ZIO.succeed(apiKeyConfig.salt + apiKey) secret <- ZIO - .fromTry(Try(Sha256.compute(saltAndApiKey.getBytes).getHexValue)) + .fromTry(Try(Sha256Hash.compute(saltAndApiKey.getBytes).hexEncoded)) .logError("Failed to compute SHA256 hash") .mapError(cause => AuthenticationError.UnexpectedError(cause.getMessage)) _ <- repository @@ -102,7 +102,7 @@ case class ApiKeyAuthenticatorImpl( for { saltAndApiKey <- ZIO.succeed(apiKeyConfig.salt + apiKey) secret <- ZIO - .fromTry(Try(Sha256.compute(saltAndApiKey.getBytes).getHexValue)) + .fromTry(Try(Sha256Hash.compute(saltAndApiKey.getBytes).hexEncoded)) .logError("Failed to compute SHA256 hash") .mapError(cause => AuthenticationError.UnexpectedError(cause.getMessage)) _ <- repository diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/KeyManagement.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/KeyManagement.scala index baa03202cb..9cc9cc260f 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/KeyManagement.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/KeyManagement.scala @@ -3,7 +3,7 @@ package org.hyperledger.identus.agent.walletapi.model import org.hyperledger.identus.castor.core.model.did.EllipticCurve import org.hyperledger.identus.castor.core.model.did.InternalKeyPurpose import org.hyperledger.identus.castor.core.model.did.VerificationRelationship -import io.iohk.atala.prism.crypto.Sha256 +import org.hyperledger.identus.shared.crypto.Sha256Hash import org.hyperledger.identus.shared.crypto.DerivationPath import org.hyperledger.identus.shared.crypto.Ed25519KeyPair import org.hyperledger.identus.shared.crypto.X25519KeyPair @@ -17,7 +17,7 @@ object WalletSeed { extension (s: WalletSeed) { final def toString(): String = "" def toByteArray: Array[Byte] = s.toArray - def sha256Digest: Array[Byte] = Sha256.compute(toByteArray).getValue() + def sha256Digest: Array[Byte] = Sha256Hash.compute(toByteArray).bytes.toArray } def fromByteArray(bytes: Array[Byte]): Either[String, WalletSeed] = { diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultDIDSecretStorage.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultDIDSecretStorage.scala index a334f0ac34..4b14248393 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultDIDSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultDIDSecretStorage.scala @@ -4,7 +4,7 @@ import com.nimbusds.jose.jwk.OctetKeyPair import org.hyperledger.identus.agent.walletapi.storage.DIDSecretStorage import org.hyperledger.identus.mercury.model.DidId import org.hyperledger.identus.castor.core.model.did.PrismDID -import io.iohk.atala.prism.crypto.Sha256 +import org.hyperledger.identus.shared.crypto.Sha256Hash import org.hyperledger.identus.shared.crypto.jwk.FromJWK import org.hyperledger.identus.shared.crypto.jwk.JWK import org.hyperledger.identus.shared.models.HexString @@ -74,7 +74,7 @@ class VaultDIDSecretStorage(vaultKV: VaultKVClient, useSemanticPath: Boolean) ex if (useSemanticPath) { s"$basePath/$relativePath" -> Map.empty } else { - val relativePathHash = Sha256.compute(relativePath.getBytes(StandardCharsets.UTF_8)).getHexValue() + val relativePathHash = Sha256Hash.compute(relativePath.getBytes(StandardCharsets.UTF_8)).hexEncoded s"$basePath/$relativePathHash" -> Map(SEMANTIC_PATH_METADATA_KEY -> relativePath) } } @@ -88,7 +88,7 @@ class VaultDIDSecretStorage(vaultKV: VaultKVClient, useSemanticPath: Boolean) ex if (useSemanticPath) { s"$basePath/$relativePath" -> Map.empty } else { - val relativePathHash = Sha256.compute(relativePath.getBytes(StandardCharsets.UTF_8)).getHexValue() + val relativePathHash = Sha256Hash.compute(relativePath.getBytes(StandardCharsets.UTF_8)).hexEncoded s"$basePath/$relativePathHash" -> Map(SEMANTIC_PATH_METADATA_KEY -> relativePath) } } diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultGenericSecretStorage.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultGenericSecretStorage.scala index 268c0eb4e9..d4a32f940b 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultGenericSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultGenericSecretStorage.scala @@ -2,7 +2,7 @@ package org.hyperledger.identus.agent.walletapi.vault import org.hyperledger.identus.agent.walletapi.storage.GenericSecret import org.hyperledger.identus.agent.walletapi.storage.GenericSecretStorage -import io.iohk.atala.prism.crypto.Sha256 +import org.hyperledger.identus.shared.crypto.Sha256Hash import org.hyperledger.identus.shared.models.WalletAccessContext import org.hyperledger.identus.shared.models.WalletId import zio.* @@ -43,7 +43,7 @@ class VaultGenericSecretStorage(vaultKV: VaultKVClient, useSemanticPath: Boolean if (useSemanticPath) { s"$basePath/$relativePath" -> Map.empty } else { - val relativePathHash = Sha256.compute(relativePath.getBytes(StandardCharsets.UTF_8)).getHexValue() + val relativePathHash = Sha256Hash.compute(relativePath.getBytes(StandardCharsets.UTF_8)).hexEncoded s"$basePath/$relativePathHash" -> Map(SEMANTIC_PATH_METADATA_KEY -> relativePath) } } diff --git a/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Prism14Apollo.scala b/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Prism14Apollo.scala deleted file mode 100644 index 6501618619..0000000000 --- a/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Prism14Apollo.scala +++ /dev/null @@ -1,96 +0,0 @@ -package org.hyperledger.identus.shared.crypto - -import io.iohk.atala.prism.crypto.EC -import io.iohk.atala.prism.crypto.derivation.DerivationAxis -import io.iohk.atala.prism.crypto.derivation.KeyDerivation -import zio.* - -import scala.jdk.CollectionConverters.* -import scala.util.{Try, Success, Failure} - -final case class Prism14Secp256k1PublicKey(publicKey: io.iohk.atala.prism.crypto.keys.ECPublicKey) - extends Secp256k1PublicKey { - - override def getEncoded: Array[Byte] = getEncodedCompressed - - override def getEncodedUncompressed: Array[Byte] = publicKey.getEncoded() - - override def getEncodedCompressed: Array[Byte] = publicKey.getEncodedCompressed() - - override def getECPoint: ECPoint = { - val point = publicKey.getCurvePoint - ECPoint(point.getX().bytes(), point.getY().bytes()) - } - - override def verify(data: Array[Byte], signature: Array[Byte]): Try[Unit] = Try { - val sig = EC.INSTANCE.toSignatureFromBytes(signature) - EC.INSTANCE.verifyBytes(data, publicKey, sig) - }.flatMap(isValid => if (isValid) Success(()) else Failure(Exception("The signature verification does not match"))) - -} - -final case class Prism14Secp256k1PrivateKey(privateKey: io.iohk.atala.prism.crypto.keys.ECPrivateKey) - extends Secp256k1PrivateKey { - - override def toPublicKey: Secp256k1PublicKey = Prism14Secp256k1PublicKey( - EC.INSTANCE.toPublicKeyFromPrivateKey(privateKey) - ) - - override def getEncoded: Array[Byte] = privateKey.getEncoded() - - override def sign(data: Array[Byte]): Array[Byte] = EC.INSTANCE.signBytes(data, privateKey).getEncoded - -} - -object Prism14Secp256k1Ops extends Secp256k1KeyOps { - - override def generateKeyPair: Secp256k1KeyPair = { - val keyPair = EC.INSTANCE.generateKeyPair() - Secp256k1KeyPair( - Prism14Secp256k1PublicKey(keyPair.getPublicKey()), - Prism14Secp256k1PrivateKey(keyPair.getPrivateKey()), - ) - } - - override def privateKeyFromEncoded(bytes: Array[Byte]): Try[Secp256k1PrivateKey] = - Try(Prism14Secp256k1PrivateKey(EC.INSTANCE.toPrivateKeyFromBytes(bytes))) - - override def publicKeyFromEncoded(bytes: Array[Byte]): Try[Secp256k1PublicKey] = - Try(EC.INSTANCE.toPublicKeyFromBytes(bytes)) - .orElse(Try(EC.INSTANCE.toPublicKeyFromCompressed(bytes))) - .map(Prism14Secp256k1PublicKey.apply) - - override def publicKeyFromCoordinate(x: Array[Byte], y: Array[Byte]): Try[Secp256k1PublicKey] = - Try { - val pk = EC.INSTANCE.toPublicKeyFromByteCoordinates(x, y) - val point = pk.getCurvePoint() - val isOnCurve = EC.INSTANCE.isSecp256k1(point) - if (isOnCurve) Prism14Secp256k1PublicKey(pk) - else throw Exception("The point is not on the secp256k1 curve") - } - - override def deriveKeyPair(seed: Array[Byte])(path: DerivationPath*): UIO[Secp256k1KeyPair] = - ZIO.attempt { - val extendedKey = path - .foldLeft(KeyDerivation.INSTANCE.derivationRoot(seed)) { case (extendedKey, p) => - val axis = p match { - case DerivationPath.Hardened(i) => DerivationAxis.hardened(i) - case DerivationPath.Normal(i) => DerivationAxis.normal(i) - } - extendedKey.derive(axis) - } - val prism14KeyPair = extendedKey.keyPair() - Secp256k1KeyPair( - Prism14Secp256k1PublicKey(prism14KeyPair.getPublicKey()), - Prism14Secp256k1PrivateKey(prism14KeyPair.getPrivateKey()) - ) - }.orDie - - override def randomBip32Seed: UIO[(Array[Byte], Seq[String])] = - ZIO.attemptBlocking { - val mnemonic = KeyDerivation.INSTANCE.randomMnemonicCode() - val words = mnemonic.getWords().asScala.toList - KeyDerivation.INSTANCE.binarySeed(mnemonic, "") -> words - }.orDie - -} diff --git a/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Sha256.scala b/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Sha256.scala new file mode 100644 index 0000000000..00bf6e6e8d --- /dev/null +++ b/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Sha256.scala @@ -0,0 +1,55 @@ +package org.hyperledger.identus.shared.crypto + +import java.security.MessageDigest + +// Reference: https://github.com/input-output-hk/atala-prism/blob/open-source-node/node/src/main/scala/io/iohk/atala/prism/node/crypto/CryptoUtils.scala +sealed trait Sha256Hash { + def bytes: Vector[Byte] + def hexEncoded: String = { + bytes.map(byte => f"${byte & 0xff}%02x").mkString + } + + override def equals(obj: Any): Boolean = obj match { + case other: Sha256Hash => bytes == other.bytes + case _ => false + } + + override def hashCode(): Int = bytes.hashCode() +} + +private[crypto] case class Sha256HashImpl(bytes: Vector[Byte]) extends Sha256Hash { + require(bytes.size == 32) +} + +object Sha256Hash { + + def fromBytes(arr: Array[Byte]): Sha256Hash = Sha256HashImpl(arr.toVector) + + def compute(bArray: Array[Byte]): Sha256Hash = { + Sha256HashImpl( + MessageDigest + .getInstance("SHA-256") + .digest(bArray) + .toVector + ) + } + + def fromHex(hexedBytes: String): Sha256Hash = { + val HEX_STRING_RE = "^[0-9a-fA-F]{64}$".r + if (HEX_STRING_RE.matches(hexedBytes)) Sha256HashImpl(hexToBytes(hexedBytes)) + else + throw new IllegalArgumentException( + "The given hex string doesn't correspond to a valid SHA-256 hash encoded as string" + ) + } + + private def hexToBytes(hex: String): Vector[Byte] = { + val HEX_ARRAY = "0123456789abcdef".toCharArray + for { + pair <- hex.grouped(2).toVector + firstIndex = HEX_ARRAY.indexOf(pair(0)) + secondIndex = HEX_ARRAY.indexOf(pair(1)) + octet = firstIndex << 4 | secondIndex + } yield octet.toByte + } +} From 17feffafac02b09a78bccb249b0a16670b13d0ff Mon Sep 17 00:00:00 2001 From: Yurii Shynbuiev - IOHK Date: Tue, 7 May 2024 17:33:12 +0700 Subject: [PATCH 03/14] ci: semantic-release upgrade, oasdiff fix (#1017) Signed-off-by: Yurii Shynbuiev --- .github/workflows/oasdiff.yml | 57 +- package-lock.json | 1889 ++++++++++++++------------------- package.json | 12 +- 3 files changed, 805 insertions(+), 1153 deletions(-) diff --git a/.github/workflows/oasdiff.yml b/.github/workflows/oasdiff.yml index 463d95f898..76030e6e40 100644 --- a/.github/workflows/oasdiff.yml +++ b/.github/workflows/oasdiff.yml @@ -1,7 +1,6 @@ --- name: "OAS Breaking Changes" - defaults: run: shell: bash @@ -10,7 +9,6 @@ on: pull_request: branches: - main - workflow_dispatch: inputs: revision_tag: @@ -23,6 +21,10 @@ on: description: "Base tag to check the breaking changes in the OAS" default: "main" +permissions: + pull-requests: write + actions: write + # https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/prism-agent-v1.29.0/prism-agent/service/api/http/prism-agent-openapi-spec.yaml # https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/main/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml @@ -32,32 +34,36 @@ jobs: runs-on: ubuntu-latest steps: - name: Resolve the base OpenAPI spec URL + env: + BASE_TAG: ${{ github.event.inputs.base_tag }} + GITHUB_EVENT_NAME: ${{ github.event_name }} run: | - BASE_TAG="${{ github.event.inputs.base_tag }}" - echo "Base tag: $BASE_TAG" - if [[ $BASE_TAG == 'cloud-agent-v*' ]]; then - echo "BASE_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/$BASE_TAG/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> $GITHUB_ENV - elif [[ $BASE_TAG == 'prism-agent-v*' ]]; then - echo "BASE_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/$BASE_TAG/prism-agent/service/api/http/prism-agent-openapi-spec.yaml" >> $GITHUB_ENV - elif [[ $BASE_TAG == 'main' ]]; then - echo "BASE_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/$BASE_TAG/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> $GITHUB_ENV - elif [[ ${{ github.event_name }} == 'pull_request' ]]; then - echo "BASE_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/main/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> $GITHUB_ENV + echo Base tag: "$BASE_TAG" + if [[ "$BASE_TAG" =~ cloud-agent-v* ]]; then + echo "BASE_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/${BASE_TAG}/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> "$GITHUB_ENV" + elif [[ "$BASE_TAG" =~ prism-agent-v* ]]; then + echo "BASE_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/${BASE_TAG}/prism-agent/service/api/http/prism-agent-openapi-spec.yaml" >> "$GITHUB_ENV" + elif [[ "$BASE_TAG" == 'main' ]]; then + echo "BASE_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/${BASE_TAG}/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> "$GITHUB_ENV" + elif [[ "$GITHUB_EVENT_NAME" == 'pull_request' ]]; then + echo "BASE_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/main/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> "$GITHUB_ENV" fi - name: Resolve the revision OpenAPI spec URL + env: + REV_TAG: ${{ github.event.inputs.revision_tag }} + GITHUB_EVENT_NAME: ${{ github.event_name }} + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} run: | - REV_TAG="${{ github.event.inputs.revision_tag }}" - echo "Revision tag: $REV_TAG" - if [[ $REV_TAG == 'cloud-agent-v*' ]]; then - echo "REV_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/$REV_TAG/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> $GITHUB_ENV - elif [[ $REV_TAG == 'prism-agent-v*' ]]; then - echo "REV_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/$REV_TAG/prism-agent/service/api/http/prism-agent-openapi-spec.yaml" >> $GITHUB_ENV - elif [[ $REV_TAG == 'main' ]]; then - echo "REV_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/$REV_TAG/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> $GITHUB_ENV - elif [[ ${{ github.event_name }} == 'pull_request' ]]; then - BRANCH_NAME=${{ github.head_ref || github.ref_name }} - echo "REV_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/$BRANCH_NAME/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> $GITHUB_ENV + echo Revision tag: "$REV_TAG" + if [[ "$REV_TAG" =~ cloud-agent-v* ]]; then + echo "REV_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/${REV_TAG}/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> "$GITHUB_ENV" + elif [[ "$REV_TAG" =~ prism-agent-v* ]]; then + echo "REV_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/${REV_TAG}/prism-agent/service/api/http/prism-agent-openapi-spec.yaml" >> "$GITHUB_ENV" + elif [[ "$REV_TAG" == 'main' ]]; then + echo "REV_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/${REV_TAG}/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> "$GITHUB_ENV" + elif [[ "$GITHUB_EVENT_NAME" == 'pull_request' ]]; then + echo "REV_URL=https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/${BRANCH_NAME}/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml" >> "$GITHUB_ENV" fi - name: Check URLS @@ -71,8 +77,3 @@ jobs: fail-on-diff: false base: ${{ env.BASE_URL }} revision: ${{ env.REV_URL }} - - - - - diff --git a/package-lock.json b/package-lock.json index 6658a86bf3..a53edf3355 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,18 +8,18 @@ "name": "identus-cloud-agent", "version": "1.32.0", "devDependencies": { - "@commitlint/cli": "^17.0.3", - "@commitlint/config-conventional": "^17.0.3", + "@commitlint/cli": "^19.3.0", + "@commitlint/config-conventional": "^19.2.2", "@semantic-release/changelog": "^6.0.1", "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", - "conventional-changelog-conventionalcommits": "^5.0.0", + "conventional-changelog-conventionalcommits": "^8.0.0", "gradle-semantic-release-plugin": "1.9.1", - "husky": "^8.0.1", + "husky": "^9.0.11", "pinst": "^3.0.0", - "prettier": "^2.7.1", + "prettier": "^3.2.5", "semantic-release": "^23.0.8", - "semantic-release-slack-bot": "^3.5.3" + "semantic-release-slack-bot": "^4.0.2" }, "engines": { "node": ">=16.13.0" @@ -135,61 +135,205 @@ } }, "node_modules/@commitlint/cli": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.5.1.tgz", - "integrity": "sha512-pRRgGSzdHQHehxZbGA3qF6wVPyl+EEQgTe/t321rtMLFbuJ7nRj2waS17s/v5oEbyZtiY5S8PGB6XtEIm0I+Sg==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.3.0.tgz", + "integrity": "sha512-LgYWOwuDR7BSTQ9OLZ12m7F/qhNY+NpAyPBgo4YNMkACE7lGuUnuQq1yi9hz1KA4+3VqpOYl8H1rY/LYK43v7g==", "dev": true, "dependencies": { - "@commitlint/format": "^17.4.4", - "@commitlint/lint": "^17.4.4", - "@commitlint/load": "^17.5.0", - "@commitlint/read": "^17.5.1", - "@commitlint/types": "^17.4.4", - "execa": "^5.0.0", - "lodash.isfunction": "^3.0.9", - "resolve-from": "5.0.0", - "resolve-global": "1.0.0", + "@commitlint/format": "^19.3.0", + "@commitlint/lint": "^19.2.2", + "@commitlint/load": "^19.2.0", + "@commitlint/read": "^19.2.1", + "@commitlint/types": "^19.0.3", + "execa": "^8.0.1", "yargs": "^17.0.0" }, "bin": { "commitlint": "cli.js" }, "engines": { - "node": ">=v14" + "node": ">=v18" + } + }, + "node_modules/@commitlint/cli/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@commitlint/cli/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/@commitlint/cli/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@commitlint/cli/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@commitlint/config-conventional": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.4.4.tgz", - "integrity": "sha512-u6ztvxqzi6NuhrcEDR7a+z0yrh11elY66nRrQIpqsqW6sZmpxYkDLtpRH8jRML+mmxYQ8s4qqF06Q/IQx5aJeQ==", + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.2.2.tgz", + "integrity": "sha512-mLXjsxUVLYEGgzbxbxicGPggDuyWNkf25Ht23owXIH+zV2pv1eJuzLK3t1gDY5Gp6pxdE60jZnWUY5cvgL3ufw==", "dev": true, "dependencies": { - "conventional-changelog-conventionalcommits": "^5.0.0" + "@commitlint/types": "^19.0.3", + "conventional-changelog-conventionalcommits": "^7.0.2" }, "engines": { - "node": ">=v14" + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-conventional/node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" } }, "node_modules/@commitlint/config-validator": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.4.4.tgz", - "integrity": "sha512-bi0+TstqMiqoBAQDvdEP4AFh0GaKyLFlPPEObgI29utoKEYoPQTvF0EYqIwYYLEoJYhj5GfMIhPHJkTJhagfeg==", + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.0.3.tgz", + "integrity": "sha512-2D3r4PKjoo59zBc2auodrSCaUnCSALCx54yveOFwwP/i2kfEAQrygwOleFWswLqK0UL/F9r07MFi5ev2ohyM4Q==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^19.0.3", "ajv": "^8.11.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/ensure": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.4.4.tgz", - "integrity": "sha512-AHsFCNh8hbhJiuZ2qHv/m59W/GRE9UeOXbkOqxYMNNg9pJ7qELnFcwj5oYpa6vzTSHtPGKf3C2yUFNy1GGHq6g==", + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.0.3.tgz", + "integrity": "sha512-SZEpa/VvBLoT+EFZVb91YWbmaZ/9rPH3ESrINOl0HD2kMYsjvl0tF7nMHh0EpTcv4+gTtZBAe1y/SS6/OhfZzQ==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^19.0.3", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", @@ -197,224 +341,488 @@ "lodash.upperfirst": "^4.3.1" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/execute-rule": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-17.4.0.tgz", - "integrity": "sha512-LIgYXuCSO5Gvtc0t9bebAMSwd68ewzmqLypqI2Kke1rqOqqDbMpYcYfoPfFlv9eyLIh4jocHWwCK5FS7z9icUA==", + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.0.0.tgz", + "integrity": "sha512-mtsdpY1qyWgAO/iOK0L6gSGeR7GFcdW7tIjcNFxcWkfLDF5qVbPHKuGATFqRMsxcO8OUKNj0+3WOHB7EHm4Jdw==", "dev": true, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/format": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-17.4.4.tgz", - "integrity": "sha512-+IS7vpC4Gd/x+uyQPTAt3hXs5NxnkqAZ3aqrHd5Bx/R9skyCAWusNlNbw3InDbAK6j166D9asQM8fnmYIa+CXQ==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.3.0.tgz", + "integrity": "sha512-luguk5/aF68HiF4H23ACAfk8qS8AHxl4LLN5oxPc24H+2+JRPsNr1OS3Gaea0CrH7PKhArBMKBz5RX9sA5NtTg==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", - "chalk": "^4.1.0" + "@commitlint/types": "^19.0.3", + "chalk": "^5.3.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" + } + }, + "node_modules/@commitlint/format/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/@commitlint/is-ignored": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.7.0.tgz", - "integrity": "sha512-043rA7m45tyEfW7Zv2vZHF++176MLHH9h70fnPoYlB1slKBeKl8BwNIlnPg4xBdRBVNPaCqvXxWswx2GR4c9Hw==", + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.2.2.tgz", + "integrity": "sha512-eNX54oXMVxncORywF4ZPFtJoBm3Tvp111tg1xf4zWXGfhBPKpfKG6R+G3G4v5CPlRROXpAOpQ3HMhA9n1Tck1g==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", - "semver": "7.5.4" + "@commitlint/types": "^19.0.3", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/lint": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.2.2.tgz", + "integrity": "sha512-xrzMmz4JqwGyKQKTpFzlN0dx0TAiT7Ran1fqEBgEmEj+PU98crOFtysJgY+QdeSagx6EDRigQIXJVnfrI0ratA==", + "dev": true, + "dependencies": { + "@commitlint/is-ignored": "^19.2.2", + "@commitlint/parse": "^19.0.3", + "@commitlint/rules": "^19.0.3", + "@commitlint/types": "^19.0.3" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.2.0.tgz", + "integrity": "sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ==", + "dev": true, + "dependencies": { + "@commitlint/config-validator": "^19.0.3", + "@commitlint/execute-rule": "^19.0.0", + "@commitlint/resolve-extends": "^19.1.0", + "@commitlint/types": "^19.0.3", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^5.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/message": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.0.0.tgz", + "integrity": "sha512-c9czf6lU+9oF9gVVa2lmKaOARJvt4soRsVmbR7Njwp9FpbBgste5i7l/2l5o8MmbwGh4yE1snfnsy2qyA2r/Fw==", + "dev": true, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/parse": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.0.3.tgz", + "integrity": "sha512-Il+tNyOb8VDxN3P6XoBBwWJtKKGzHlitEuXA5BP6ir/3loWlsSqDr5aecl6hZcC/spjq4pHqNh0qPlfeWu38QA==", + "dev": true, + "dependencies": { + "@commitlint/types": "^19.0.3", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read": { + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.2.1.tgz", + "integrity": "sha512-qETc4+PL0EUv7Q36lJbPG+NJiBOGg7SSC7B5BsPWOmei+Dyif80ErfWQ0qXoW9oCh7GTpTNRoaVhiI8RbhuaNw==", + "dev": true, + "dependencies": { + "@commitlint/top-level": "^19.0.0", + "@commitlint/types": "^19.0.3", + "execa": "^8.0.1", + "git-raw-commits": "^4.0.0", + "minimist": "^1.2.8" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@commitlint/read/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/@commitlint/read/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/read/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@commitlint/read/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.1.0.tgz", + "integrity": "sha512-z2riI+8G3CET5CPgXJPlzftH+RiWYLMYv4C9tSLdLXdr6pBNimSKukYP9MS27ejmscqCTVA4almdLh0ODD2KYg==", + "dev": true, + "dependencies": { + "@commitlint/config-validator": "^19.0.3", + "@commitlint/types": "^19.0.3", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/rules": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.0.3.tgz", + "integrity": "sha512-TspKb9VB6svklxNCKKwxhELn7qhtY1rFF8ls58DcFd0F97XoG07xugPjjbVnLqmMkRjZDbDIwBKt9bddOfLaPw==", + "dev": true, + "dependencies": { + "@commitlint/ensure": "^19.0.3", + "@commitlint/message": "^19.0.0", + "@commitlint/to-lines": "^19.0.0", + "@commitlint/types": "^19.0.3", + "execa": "^8.0.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/rules/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@commitlint/rules/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" }, - "engines": { - "node": ">=v14" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/lint": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.4.4.tgz", - "integrity": "sha512-qgkCRRFjyhbMDWsti/5jRYVJkgYZj4r+ZmweZObnbYqPUl5UKLWMf9a/ZZisOI4JfiPmRktYRZ2JmqlSvg+ccw==", + "node_modules/@commitlint/rules/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, - "dependencies": { - "@commitlint/is-ignored": "^17.4.4", - "@commitlint/parse": "^17.4.4", - "@commitlint/rules": "^17.4.4", - "@commitlint/types": "^17.4.4" - }, "engines": { - "node": ">=v14" + "node": ">=16.17.0" } }, - "node_modules/@commitlint/load": { - "version": "17.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.5.0.tgz", - "integrity": "sha512-l+4W8Sx4CD5rYFsrhHH8HP01/8jEP7kKf33Xlx2Uk2out/UKoKPYMOIRcDH5ppT8UXLMV+x6Wm5osdRKKgaD1Q==", + "node_modules/@commitlint/rules/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, - "dependencies": { - "@commitlint/config-validator": "^17.4.4", - "@commitlint/execute-rule": "^17.4.0", - "@commitlint/resolve-extends": "^17.4.4", - "@commitlint/types": "^17.4.4", - "@types/node": "*", - "chalk": "^4.1.0", - "cosmiconfig": "^8.0.0", - "cosmiconfig-typescript-loader": "^4.0.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "lodash.uniq": "^4.5.0", - "resolve-from": "^5.0.0", - "ts-node": "^10.8.1", - "typescript": "^4.6.4 || ^5.0.0" - }, "engines": { - "node": ">=v14" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/message": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.4.2.tgz", - "integrity": "sha512-3XMNbzB+3bhKA1hSAWPCQA3lNxR4zaeQAQcHj0Hx5sVdO6ryXtgUBGGv+1ZCLMgAPRixuc6en+iNAzZ4NzAa8Q==", + "node_modules/@commitlint/rules/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, "engines": { - "node": ">=v14" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/parse": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.4.4.tgz", - "integrity": "sha512-EKzz4f49d3/OU0Fplog7nwz/lAfXMaDxtriidyGF9PtR+SRbgv4FhsfF310tKxs6EPj8Y+aWWuX3beN5s+yqGg==", + "node_modules/@commitlint/rules/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", - "conventional-changelog-angular": "^5.0.11", - "conventional-commits-parser": "^3.2.2" + "path-key": "^4.0.0" }, "engines": { - "node": ">=v14" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/read": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.5.1.tgz", - "integrity": "sha512-7IhfvEvB//p9aYW09YVclHbdf1u7g7QhxeYW9ZHSO8Huzp8Rz7m05aCO1mFG7G8M+7yfFnXB5xOmG18brqQIBg==", + "node_modules/@commitlint/rules/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "dependencies": { - "@commitlint/top-level": "^17.4.0", - "@commitlint/types": "^17.4.4", - "fs-extra": "^11.0.0", - "git-raw-commits": "^2.0.11", - "minimist": "^1.2.6" + "mimic-fn": "^4.0.0" }, "engines": { - "node": ">=v14" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/resolve-extends": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.4.4.tgz", - "integrity": "sha512-znXr1S0Rr8adInptHw0JeLgumS11lWbk5xAWFVno+HUFVN45875kUtqjrI6AppmD3JI+4s0uZlqqlkepjJd99A==", + "node_modules/@commitlint/rules/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, - "dependencies": { - "@commitlint/config-validator": "^17.4.4", - "@commitlint/types": "^17.4.4", - "import-fresh": "^3.0.0", - "lodash.mergewith": "^4.6.2", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0" - }, "engines": { - "node": ">=v14" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/rules": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.4.4.tgz", - "integrity": "sha512-0tgvXnHi/mVcyR8Y8mjTFZIa/FEQXA4uEutXS/imH2v1UNkYDSEMsK/68wiXRpfW1euSgEdwRkvE1z23+yhNrQ==", + "node_modules/@commitlint/rules/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "dependencies": { - "@commitlint/ensure": "^17.4.4", - "@commitlint/message": "^17.4.2", - "@commitlint/to-lines": "^17.4.0", - "@commitlint/types": "^17.4.4", - "execa": "^5.0.0" - }, "engines": { - "node": ">=v14" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@commitlint/to-lines": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-17.4.0.tgz", - "integrity": "sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg==", + "node_modules/@commitlint/rules/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, "engines": { - "node": ">=v14" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/top-level": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-17.4.0.tgz", - "integrity": "sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g==", + "node_modules/@commitlint/to-lines": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.0.0.tgz", + "integrity": "sha512-vkxWo+VQU5wFhiP9Ub9Sre0FYe019JxFikrALVoD5UGa8/t3yOJEpEhxC5xKiENKKhUkTpEItMTRAjHw2SCpZw==", "dev": true, - "dependencies": { - "find-up": "^5.0.0" - }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, - "node_modules/@commitlint/types": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-17.4.4.tgz", - "integrity": "sha512-amRN8tRLYOsxRr6mTnGGGvB5EmW/4DDjLMgiwK3CCVEmN6Sr/6xePGEpWaspKkckILuUORCwe6VfDBw6uj4axQ==", + "node_modules/@commitlint/top-level": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.0.0.tgz", + "integrity": "sha512-KKjShd6u1aMGNkCkaX4aG1jOGdn7f8ZI8TR1VEuNqUOjWTOdcDSsmglinglJ18JTjuBX5I1PtjrhQCRcixRVFQ==", "dev": true, "dependencies": { - "chalk": "^4.1.0" + "find-up": "^7.0.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/@commitlint/types": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.0.3.tgz", + "integrity": "sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" }, "engines": { - "node": ">=12" + "node": ">=v18" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/@nodelib/fs.scandir": { @@ -676,81 +1084,6 @@ "semantic-release": ">=20.1.0" } }, - "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-changelog-angular": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", - "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", - "dev": true, - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-commits-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", - "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", - "dev": true, - "dependencies": { - "is-text-path": "^2.0.0", - "JSONStream": "^1.3.5", - "meow": "^12.0.1", - "split2": "^4.0.0" - }, - "bin": { - "conventional-commits-parser": "cli.mjs" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/is-text-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", - "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", - "dev": true, - "dependencies": { - "text-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/meow": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", - "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", - "dev": true, - "engines": { - "node": ">=16.10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/text-extensions": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", - "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@semantic-release/error": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", @@ -1229,36 +1562,6 @@ "semantic-release": ">=20.1.0" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-changelog-angular": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", - "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", - "dev": true, - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-commits-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", - "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", - "dev": true, - "dependencies": { - "is-text-path": "^2.0.0", - "JSONStream": "^1.3.5", - "meow": "^12.0.1", - "split2": "^4.0.0" - }, - "bin": { - "conventional-commits-parser": "cli.mjs" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", @@ -1283,18 +1586,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/is-text-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", - "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", - "dev": true, - "dependencies": { - "text-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@semantic-release/release-notes-generator/node_modules/lru-cache": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz", @@ -1304,18 +1595,6 @@ "node": "14 || >=16.14" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/meow": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", - "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", - "dev": true, - "engines": { - "node": ">=16.10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@semantic-release/release-notes-generator/node_modules/normalize-package-data": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", @@ -1385,27 +1664,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/@semantic-release/release-notes-generator/node_modules/text-extensions": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", - "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@semantic-release/release-notes-generator/node_modules/type-fest": { "version": "4.17.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.17.0.tgz", @@ -1442,29 +1700,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/mdast": { "version": "3.0.11", @@ -1475,17 +1718,14 @@ "@types/unist": "*" } }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, "node_modules/@types/node": { - "version": "18.15.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", - "dev": true + "version": "20.12.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.10.tgz", + "integrity": "sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", @@ -1499,27 +1739,6 @@ "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==", "dev": true }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agent-base": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", @@ -1546,15 +1765,15 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -1603,12 +1822,6 @@ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", "dev": true }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1627,15 +1840,6 @@ "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/bail": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", @@ -1679,32 +1883,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ccount": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", @@ -1897,30 +2075,27 @@ } }, "node_modules/conventional-changelog-angular": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", - "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", "dev": true, "dependencies": { - "compare-func": "^2.0.0", - "q": "^1.5.1" + "compare-func": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=16" } }, "node_modules/conventional-changelog-conventionalcommits": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", - "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-8.0.0.tgz", + "integrity": "sha512-eOvlTO6OcySPyyyk8pKz2dP4jjElYunj9hn9/s0OB+gapTO8zwS9UQWrZ1pmF2hFs3vw1xhonOLGcGjy/zgsuA==", "dev": true, "dependencies": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" + "compare-func": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/conventional-changelog-writer": { @@ -1943,27 +2118,6 @@ "node": ">=16" } }, - "node_modules/conventional-changelog-writer/node_modules/meow": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", - "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", - "dev": true, - "engines": { - "node": ">=16.10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/conventional-changelog-writer/node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "engines": { - "node": ">= 10.x" - } - }, "node_modules/conventional-commits-filter": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-4.0.0.tgz", @@ -1974,23 +2128,21 @@ } }, "node_modules/conventional-commits-parser": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", - "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", "dev": true, "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.0.4", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" }, "bin": { - "conventional-commits-parser": "cli.js" + "conventional-commits-parser": "cli.mjs" }, "engines": { - "node": ">=10" + "node": ">=16" } }, "node_modules/convert-hrtime": { @@ -2012,45 +2164,48 @@ "dev": true }, "node_modules/cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "dependencies": { - "import-fresh": "^3.2.1", + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/cosmiconfig-typescript-loader": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz", - "integrity": "sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz", + "integrity": "sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==", "dev": true, + "dependencies": { + "jiti": "^1.19.1" + }, "engines": { - "node": ">=12", - "npm": ">=6" + "node": ">=v16" }, "peerDependencies": { "@types/node": "*", - "cosmiconfig": ">=7", - "ts-node": ">=10", - "typescript": ">=3" + "cosmiconfig": ">=8.2", + "typescript": ">=4" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2093,12 +2248,15 @@ } }, "node_modules/dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", + "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/debug": { @@ -2118,40 +2276,6 @@ } } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -2161,15 +2285,6 @@ "node": ">=4.0.0" } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2486,16 +2601,17 @@ } }, "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", "dev": true, "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2626,22 +2742,20 @@ } }, "node_modules/git-raw-commits": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", - "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", + "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", "dev": true, "dependencies": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" + "dargs": "^8.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" }, "bin": { - "git-raw-commits": "cli.js" + "git-raw-commits": "cli.mjs" }, "engines": { - "node": ">=10" + "node": ">=16" } }, "node_modules/glob-parent": { @@ -2656,16 +2770,28 @@ "node": ">= 6" } }, - "node_modules/global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", "dev": true, "dependencies": { - "ini": "^1.3.4" + "ini": "4.1.1" }, "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/globby": { @@ -2728,15 +2854,6 @@ "semantic-release": "^23.0.0" } }, - "node_modules/gradle-semantic-release-plugin/node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "engines": { - "node": ">= 10.x" - } - }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -2758,15 +2875,6 @@ "uglify-js": "^3.1.4" } }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2809,18 +2917,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -2857,15 +2953,15 @@ } }, "node_modules/husky": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", - "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", + "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", "dev": true, "bin": { - "husky": "lib/bin.js" + "husky": "bin.mjs" }, "engines": { - "node": ">=14" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/typicode" @@ -3110,15 +3206,6 @@ "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3132,15 +3219,15 @@ } }, "node_modules/is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", "dev": true, "dependencies": { - "text-extensions": "^1.0.0" + "text-extensions": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/is-unicode-supported": { @@ -3192,6 +3279,15 @@ "node": ">= 0.6.0" } }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3271,15 +3367,6 @@ "node": "*" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -3315,15 +3402,15 @@ } }, "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "dependencies": { - "p-locate": "^5.0.0" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3359,12 +3446,6 @@ "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", "dev": true }, - "node_modules/lodash.isfunction": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", - "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", - "dev": true - }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", @@ -3447,24 +3528,6 @@ "node": ">=10" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/markdown-table": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", @@ -3667,25 +3730,12 @@ } }, "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", "dev": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, "engines": { - "node": ">=10" + "node": ">=16.10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3843,15 +3893,6 @@ "node": ">=6" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -3861,20 +3902,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -3934,24 +3961,9 @@ "encoding": "^0.1.0" }, "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" + "encoding": { + "optional": true + } } }, "node_modules/normalize-url": { @@ -6664,30 +6676,30 @@ } }, "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "dependencies": { - "p-limit": "^3.0.2" + "p-limit": "^4.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6799,12 +6811,12 @@ "dev": true }, "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/path-key": { @@ -6816,12 +6828,6 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -6943,15 +6949,15 @@ } }, "node_modules/prettier": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", - "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -6983,24 +6989,14 @@ "dev": true }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" } }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -7021,15 +7017,6 @@ } ] }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -7146,144 +7133,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -7299,19 +7148,6 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/registry-auth-token": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", @@ -7391,23 +7227,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -7417,18 +7236,6 @@ "node": ">=8" } }, - "node_modules/resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", - "dev": true, - "dependencies": { - "global-dirs": "^0.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -7512,9 +7319,9 @@ } }, "node_modules/semantic-release-slack-bot": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/semantic-release-slack-bot/-/semantic-release-slack-bot-3.5.3.tgz", - "integrity": "sha512-QoLRfZPkgkER2s/DiIu0qA9pYu4am8ASu7xq3omCXl2oJ+fKdb1Rentgezzv7RefMXhO2q2aah1aqutWnSnlhw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/semantic-release-slack-bot/-/semantic-release-slack-bot-4.0.2.tgz", + "integrity": "sha512-EgpUGmxDq5l9qSfAJNkGMOjxi6p5a7lAMnV5sNG53QxpIOsgMUF9X3J+NeaFWXsGyRP5CEkVtDdDkfvvNNo2ag==", "dev": true, "dependencies": { "@semantic-release/error": "^2.2.0", @@ -7523,10 +7330,10 @@ "slackify-markdown": "^4.3.0" }, "engines": { - "node": ">=14.7" + "node": ">=18.13" }, "peerDependencies": { - "semantic-release": ">=11.0.0 <20.0.0" + "semantic-release": ">=11.0.0" } }, "node_modules/semantic-release-slack-bot/node_modules/@semantic-release/error": { @@ -7588,32 +7395,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/semantic-release/node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/semantic-release/node_modules/escape-string-regexp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", @@ -7806,9 +7587,9 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -8049,26 +7830,12 @@ "dev": true }, "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/split2/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, "engines": { - "node": ">= 6" + "node": ">= 10.x" } }, "node_modules/stream-combiner2": { @@ -8134,18 +7901,6 @@ "node": ">=6" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -8196,18 +7951,6 @@ "node": ">=14.18" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/temp-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", @@ -8260,12 +8003,15 @@ } }, "node_modules/text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", "dev": true, "engines": { - "node": ">=0.10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/thenify": { @@ -8295,29 +8041,6 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "dependencies": { - "readable-stream": "3" - } - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/time-span": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", @@ -8360,15 +8083,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/trough": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", @@ -8379,66 +8093,12 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8460,6 +8120,12 @@ "node": ">=0.8.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/unicode-emoji-modifier-base": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", @@ -8627,12 +8293,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -8787,22 +8447,13 @@ "node": ">=12" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" diff --git a/package.json b/package.json index cc242db472..e2f1fe9728 100644 --- a/package.json +++ b/package.json @@ -5,18 +5,18 @@ "node": ">=16.13.0" }, "devDependencies": { - "@commitlint/cli": "^17.0.3", - "@commitlint/config-conventional": "^17.0.3", + "@commitlint/cli": "^19.3.0", + "@commitlint/config-conventional": "^19.2.2", "@semantic-release/changelog": "^6.0.1", "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", - "conventional-changelog-conventionalcommits": "^5.0.0", + "conventional-changelog-conventionalcommits": "^8.0.0", "gradle-semantic-release-plugin": "1.9.1", - "husky": "^8.0.1", + "husky": "^9.0.11", "pinst": "^3.0.0", - "prettier": "^2.7.1", + "prettier": "^3.2.5", "semantic-release": "^23.0.8", - "semantic-release-slack-bot": "^3.5.3" + "semantic-release-slack-bot": "^4.0.2" }, "release": { "branches": [ From 3b17c34f69f1e7e0715090306b380c981afe59bf Mon Sep 17 00:00:00 2001 From: Hyperledger Bot Date: Tue, 7 May 2024 11:16:50 +0000 Subject: [PATCH 04/14] chore(release): cut Identus Cloud agent 1.32.1 release ## [1.32.1](https://github.com/hyperledger/identus-cloud-agent/compare/cloud-agent-v1.32.0...cloud-agent-v1.32.1) (2024-05-07) ### Bug Fixes * expose pg_admin port on the localhost interface only ([#957](https://github.com/hyperledger/identus-cloud-agent/issues/957)) ([73674b5](https://github.com/hyperledger/identus-cloud-agent/commit/73674b5da6a41c4972ac3c45005ce768608b558e)) * Fix OneOf OpenAPI Serialization Issue ([#1010](https://github.com/hyperledger/identus-cloud-agent/issues/1010)) ([393c296](https://github.com/hyperledger/identus-cloud-agent/commit/393c29654b8d3d53071f0d2932a16ff81688ece6)) * remove prism-crypto dependency ([#1015](https://github.com/hyperledger/identus-cloud-agent/issues/1015)) ([46e594c](https://github.com/hyperledger/identus-cloud-agent/commit/46e594c21bdb43d78f41be6c803ad8b80dc89504)) * update open-api-spec and generator script and package.json ([#990](https://github.com/hyperledger/identus-cloud-agent/issues/990)) ([88c1b5e](https://github.com/hyperledger/identus-cloud-agent/commit/88c1b5eadf62ad0efcd4ee53b793bb08cce9667f)) Signed-off-by: Allain Magyar --- CHANGELOG.md | 10 + DEPENDENCIES.md | 247 +++++++++--------- .../api/http/cloud-agent-openapi-spec.yaml | 55 +++- infrastructure/charts/agent/Chart.yaml | 4 +- infrastructure/charts/index.yaml | 66 +++-- infrastructure/charts/prism-agent-1.32.1.tgz | Bin 0 -> 161106 bytes infrastructure/local/.env | 2 +- package-lock.json | 4 +- package.json | 2 +- version.sbt | 2 +- 10 files changed, 227 insertions(+), 165 deletions(-) create mode 100644 infrastructure/charts/prism-agent-1.32.1.tgz diff --git a/CHANGELOG.md b/CHANGELOG.md index 59af0deea7..494cf27ff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## [1.32.1](https://github.com/hyperledger/identus-cloud-agent/compare/cloud-agent-v1.32.0...cloud-agent-v1.32.1) (2024-05-07) + + +### Bug Fixes + +* expose pg_admin port on the localhost interface only ([#957](https://github.com/hyperledger/identus-cloud-agent/issues/957)) ([73674b5](https://github.com/hyperledger/identus-cloud-agent/commit/73674b5da6a41c4972ac3c45005ce768608b558e)) +* Fix OneOf OpenAPI Serialization Issue ([#1010](https://github.com/hyperledger/identus-cloud-agent/issues/1010)) ([393c296](https://github.com/hyperledger/identus-cloud-agent/commit/393c29654b8d3d53071f0d2932a16ff81688ece6)) +* remove prism-crypto dependency ([#1015](https://github.com/hyperledger/identus-cloud-agent/issues/1015)) ([46e594c](https://github.com/hyperledger/identus-cloud-agent/commit/46e594c21bdb43d78f41be6c803ad8b80dc89504)) +* update open-api-spec and generator script and package.json ([#990](https://github.com/hyperledger/identus-cloud-agent/issues/990)) ([88c1b5e](https://github.com/hyperledger/identus-cloud-agent/commit/88c1b5eadf62ad0efcd4ee53b793bb08cce9667f)) + # [1.32.0](https://github.com/hyperledger/identus-cloud-agent/compare/cloud-agent-v1.31.0...cloud-agent-v1.32.0) (2024-04-26) diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index e1d2e54810..0e78cdf2a5 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -2,15 +2,14 @@ Category | License | Dependency | Notes --- | --- | --- | --- -Apache | [APL2](http://www.apache.org/licenses/LICENSE-2.0.txt) | [net.reactivecore # circe-json-schema_2.13 # 0.3.0](https://github.com/reactivecore/rc-circe-json-schema) | +Apache | [APL2](http://www.apache.org/licenses/LICENSE-2.0.txt) | [net.reactivecore # circe-json-schema_2.13 # 0.4.1](https://github.com/reactivecore/rc-circe-json-schema) | Apache | [Apache 2](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.thesamet.scalapb # lenses_3 # 0.11.13](https://github.com/scalapb/ScalaPB) | Apache | [Apache 2](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.thesamet.scalapb # scalapb-runtime-grpc_3 # 0.11.13](https://github.com/scalapb/ScalaPB) | Apache | [Apache 2](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.thesamet.scalapb # scalapb-runtime_3 # 0.11.13](https://github.com/scalapb/ScalaPB) | Apache | [Apache 2](http://www.apache.org/licenses/LICENSE-2.0) | [io.lemonlabs # scala-uri_3 # 4.0.3](https://github.com/lemonlabsuk/scala-uri) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.google.android # annotations # 4.1.1.4](http://source.android.com/) | -Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.google.code.gson # gson # 2.8.6 | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.google.errorprone # error_prone_annotations # 2.10.0 | -Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.magnolia1_3 # magnolia_3 # 1.1.5](http://softwaremill.com/open-source) | +Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.google.errorprone # error_prone_annotations # 2.23.0 | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.magnolia1_3 # magnolia_3 # 1.3.0](http://softwaremill.com/open-source) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.magnolia1_3 # magnolia_3 # 1.3.3](http://softwaremill.com/open-source) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.quicklens # quicklens_3 # 1.9.6](http://softwaremill.com/open-source) | @@ -21,8 +20,8 @@ Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwar Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.apispec # openapi-circe_3 # 0.6.0](http://softwaremill.com/open-source) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.apispec # openapi-model_3 # 0.6.0](http://softwaremill.com/open-source) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.client3 # core_3 # 3.8.16](http://softwaremill.com/open-source) | -Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.client3 # json-common_3 # 3.8.3](http://softwaremill.com/open-source) | -Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.client3 # zio-json_3 # 3.8.3](http://softwaremill.com/open-source) | +Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.client3 # json-common_3 # 3.8.16](http://softwaremill.com/open-source) | +Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.client3 # zio-json_3 # 3.8.16](http://softwaremill.com/open-source) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.model # core_3 # 1.7.1](http://softwaremill.com/open-source) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.shared # core_3 # 1.3.15](http://softwaremill.com/open-source) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.shared # fs2_3 # 1.3.15](http://softwaremill.com/open-source) | @@ -48,19 +47,20 @@ Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwar Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.tapir # tapir-swagger-ui_3 # 1.6.4](http://softwaremill.com/open-source) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.tapir # tapir-zio-http-server_3 # 1.6.4](http://softwaremill.com/open-source) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.softwaremill.sttp.tapir # tapir-zio_3 # 1.6.4](http://softwaremill.com/open-source) | -Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.squareup.okhttp # okhttp # 2.7.4 | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.squareup.okhttp3 # okhttp # 3.14.9 | -Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.squareup.okio # okio # 1.17.5 | +Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.squareup.okio # okio # 1.17.2 | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [io.circe # circe-yaml_3 # 0.14.2](https://github.com/circe/circe-yaml) | Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-api # 1.47.1](https://github.com/grpc/grpc-java) | +Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-api # 1.63.0](https://github.com/grpc/grpc-java) | Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-context # 1.47.1](https://github.com/grpc/grpc-java) | -Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-core # 1.36.0](https://github.com/grpc/grpc-java) | -Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-kotlin-stub # 1.0.0](https://github.com/grpc/grpc-kotlin) | -Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-okhttp # 1.36.0](https://github.com/grpc/grpc-java) | +Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-context # 1.63.0](https://github.com/grpc/grpc-java) | +Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-core # 1.63.0](https://github.com/grpc/grpc-java) | +Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-okhttp # 1.63.0](https://github.com/grpc/grpc-java) | Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-protobuf # 1.47.1](https://github.com/grpc/grpc-java) | Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-protobuf-lite # 1.47.1](https://github.com/grpc/grpc-java) | Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-stub # 1.47.1](https://github.com/grpc/grpc-java) | -Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.perfmark # perfmark-api # 0.23.0](https://github.com/perfmark/perfmark) | +Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.grpc # grpc-util # 1.63.0](https://github.com/grpc/grpc-java) | +Apache | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | [io.perfmark # perfmark-api # 0.26.0](https://github.com/perfmark/perfmark) | Apache | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.typelevel # simulacrum-scalafix-annotations_3 # 0.5.4](https://github.com/typelevel/simulacrum-scalafix) | Apache | [Apache 2.0](https://github.com/swagger-api/swagger-ui) | [org.webjars # swagger-ui # 5.1.3](http://webjars.org) | Apache | [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0.html) | [com.typesafe.scala-logging # scala-logging_3 # 3.9.5](https://github.com/lightbend/scala-logging) | @@ -92,11 +92,10 @@ Apache | [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2 Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.github.stephenc.jcip # jcip-annotations # 1.0-1](http://stephenc.github.com/jcip-annotations) | Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.google.crypto.tink # tink # 1.6.1](http://github.com/google/tink) | Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.google.guava # guava # 31.0.1-android](https://github.com/google/guava) | +Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.google.guava # guava # 32.1.3-android](https://github.com/google/guava) | +Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.google.j2objc # j2objc-annotations # 2.8](https://github.com/google/j2objc/) | Apache | [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [commons-codec # commons-codec # 1.11](http://commons.apache.org/proper/commons-codec/) | Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [io.github.erdtman # java-json-canonicalization # 1.1](https://github.com/erdtman/java-json-canonicalization) | -Apache | [Apache License, Version 2.0](https://opensource.org/licenses/Apache-2.0) | [io.iohk.atala # prism-common-jvm # 1.4.1](https://github.com/input-output-hk/atala-prism-sdk.git) | -Apache | [Apache License, Version 2.0](https://opensource.org/licenses/Apache-2.0) | [io.iohk.atala # prism-crypto-jvm # 1.4.1](https://github.com/input-output-hk/atala-prism-sdk.git) | -Apache | [Apache License, Version 2.0](https://opensource.org/licenses/Apache-2.0) | [io.iohk.atala # prism-protos-jvm # 1.4.1](https://github.com/input-output-hk/atala-prism-sdk.git) | Apache | [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) | io.netty # netty-buffer # 4.1.101.Final | Apache | [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) | io.netty # netty-codec # 4.1.101.Final | Apache | [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) | io.netty # netty-codec-http # 4.1.101.Final | @@ -118,7 +117,7 @@ Apache | [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2 Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.apache.httpcomponents # httpclient # 4.5.14](http://hc.apache.org/httpcomponents-client-ga) | Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.apache.httpcomponents # httpcore # 4.4.16](http://hc.apache.org/httpcomponents-core-ga) | Apache | [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | org.eclipse.microprofile.openapi # microprofile-openapi-api # 3.1.1 | -Apache | [Apache License, Version 2.0](https://flywaydb.org/licenses/flyway-community) | org.flywaydb # flyway-core # 9.8.3 | +Apache | [Apache License, Version 2.0](https://flywaydb.org/licenses/flyway-community) | org.flywaydb # flyway-core # 9.22.3 | Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | org.jboss.shrinkwrap # shrinkwrap-api # 1.2.6 | Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | org.jboss.shrinkwrap # shrinkwrap-impl-base # 1.2.6 | Apache | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | org.jboss.shrinkwrap # shrinkwrap-spi # 1.2.6 | @@ -138,67 +137,63 @@ Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.geirsso Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.geirsson # metaconfig-pprint_2.13 # 0.11.1](https://github.com/olafurpg/metaconfig) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.geirsson # metaconfig-typesafe-config_2.13 # 0.11.1](https://github.com/olafurpg/metaconfig) | Apache | [Apache-2.0](https://opensource.org/licenses/Apache-2.0) | [com.github.dasniko # testcontainers-keycloak # 3.2.0](https://github.com/dasniko/testcontainers-keycloak) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.github.jwt-scala # jwt-circe_3 # 9.1.2](https://jwt-scala.github.io/jwt-scala/) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.github.jwt-scala # jwt-core_3 # 9.1.2](https://jwt-scala.github.io/jwt-scala/) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.github.jwt-scala # jwt-json-common_3 # 9.1.2](https://jwt-scala.github.io/jwt-scala/) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.github.jwt-scala # jwt-circe_3 # 9.4.6](https://jwt-scala.github.io/jwt-scala/) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.github.jwt-scala # jwt-core_3 # 9.4.6](https://jwt-scala.github.io/jwt-scala/) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [com.github.jwt-scala # jwt-json-common_3 # 9.4.6](https://jwt-scala.github.io/jwt-scala/) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.google.api.grpc # proto-google-common-protos # 2.0.1](https://github.com/googleapis/java-iam/proto-google-common-protos) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | com.google.code.gson # gson # 2.10.1 | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [com.typesafe # config # 1.4.2](https://github.com/lightbend/config) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [com.typesafe # config # 1.4.3](https://github.com/lightbend/config) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # izumi-reflect-thirdparty-boopickle-shaded_3 # 2.3.8](https://zio.dev) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # izumi-reflect_3 # 2.3.8](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-concurrent_3 # 2.0.18](https://zio.dev) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-concurrent_3 # 2.0.22](https://zio.dev) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-config-derivation_3 # 4.0.1](https://zio.dev/zio-config/) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-config-magnolia_3 # 4.0.1](https://zio.dev/zio-config/) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-config-typesafe_3 # 4.0.1](https://zio.dev/zio-config/) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-config_3 # 4.0.1](https://zio.dev/zio-config/) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-constraintless_3 # 0.3.2](https://zio.dev/zio-flow/) | -Apache | [Apache-2.0](https://github.com/zio/zio-http/blob/master/LICENSE) | [dev.zio # zio-http_3 # 3.0.0-RC4](https://github.com/zio/zio-http) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-internal-macros_3 # 2.0.18](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-internal-macros_3 # 2.0.19](https://zio.dev) | +Apache | [Apache-2.0](https://github.com/zio/zio-http/blob/master/LICENSE) | [dev.zio # zio-http_3 # 3.0.0-RC6](https://github.com/zio/zio-http) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-internal-macros_3 # 2.0.22](https://zio.dev) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-interop-cats_3 # 23.0.0.8](https://zio.dev) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-interop-cats_3 # 3.3.0](https://zio.dev) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-interop-tracer_3 # 23.0.0.8](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-json_3 # 0.3.0](https://zio.github.io/zio-json/) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-json_3 # 0.6.2](https://zio.dev/zio-json/) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [dev.zio # zio-logging-slf4j_3 # 2.1.16](https://zio.dev/zio-logging) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [dev.zio # zio-logging_3 # 2.1.16](https://zio.dev/zio-logging) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [dev.zio # zio-logging-slf4j_3 # 2.1.17](https://zio.dev/zio-logging) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [dev.zio # zio-logging_3 # 2.1.17](https://zio.dev/zio-logging) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-managed_3 # 2.0.0](https://zio.dev) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-managed_3 # 2.0.13](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-metrics-connectors-micrometer_3 # 2.1.0](https://zio.dev/zio-metrics-connectors/) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-metrics-connectors_3 # 2.1.0](https://zio.dev/zio-metrics-connectors/) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-mock_3 # 1.0.0-RC11](https://zio.dev/zio-mock/) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-metrics-connectors-micrometer_3 # 2.3.1](https://zio.dev/zio-metrics-connectors/) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-metrics-connectors_3 # 2.3.1](https://zio.dev/zio-metrics-connectors/) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-mock_3 # 1.0.0-RC12](https://zio.dev/zio-mock/) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-parser_3 # 0.1.9](https://zio.dev/zio-parser/) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-prelude-macros_3 # 1.0.0-RC21](https://zio.dev/zio-prelude/) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-prelude_3 # 1.0.0-RC21](https://zio.dev/zio-prelude/) | -Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v0.4.16/LICENSE) | [dev.zio # zio-schema-derivation_3 # 0.4.16](https://zio.dev/zio-schema) | -Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v0.4.16/LICENSE) | [dev.zio # zio-schema-json_3 # 0.4.16](https://zio.dev/zio-schema) | -Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v0.4.16/LICENSE) | [dev.zio # zio-schema-macros_3 # 0.4.16](https://zio.dev/zio-schema) | -Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v0.4.16/LICENSE) | [dev.zio # zio-schema-protobuf_3 # 0.4.16](https://zio.dev/zio-schema) | -Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v0.4.16/LICENSE) | [dev.zio # zio-schema_3 # 0.4.16](https://zio.dev/zio-schema) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-stacktracer_3 # 2.0.18](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-stacktracer_3 # 2.0.19](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-streams_3 # 2.0.19](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-streams_3 # 2.0.2](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-test-magnolia_3 # 2.0.18](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-test-sbt_3 # 2.0.18](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-test_3 # 2.0.12](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-test_3 # 2.0.18](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio_3 # 2.0.18](https://zio.dev) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio_3 # 2.0.19](https://zio.dev) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-core_3 # 0.14.6](https://github.com/circe/circe) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-generic_3 # 0.14.6](https://github.com/circe/circe) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-jawn_3 # 0.14.6](https://github.com/circe/circe) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-numbers_3 # 0.14.6](https://github.com/circe/circe) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-parser_3 # 0.14.6](https://github.com/circe/circe) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-prelude-macros_3 # 1.0.0-RC24](https://zio.dev/zio-prelude/) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-prelude_3 # 1.0.0-RC24](https://zio.dev/zio-prelude/) | +Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v1.1.0/LICENSE) | [dev.zio # zio-schema-derivation_3 # 1.1.0](https://zio.dev/zio-schema) | +Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v1.1.0/LICENSE) | [dev.zio # zio-schema-json_3 # 1.1.0](https://zio.dev/zio-schema) | +Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v1.1.0/LICENSE) | [dev.zio # zio-schema-macros_3 # 1.1.0](https://zio.dev/zio-schema) | +Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v1.1.0/LICENSE) | [dev.zio # zio-schema-protobuf_3 # 1.1.0](https://zio.dev/zio-schema) | +Apache | [Apache-2.0](https://zio.dev/zio-schema/blob/v1.1.0/LICENSE) | [dev.zio # zio-schema_3 # 1.1.0](https://zio.dev/zio-schema) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-stacktracer_3 # 2.0.22](https://zio.dev) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-streams_3 # 2.0.16](https://zio.dev) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-streams_3 # 2.0.21](https://zio.dev) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-streams_3 # 2.0.22](https://zio.dev) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-test-magnolia_3 # 2.0.22](https://zio.dev) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-test-sbt_3 # 2.0.22](https://zio.dev) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-test_3 # 2.0.19](https://zio.dev) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio-test_3 # 2.0.22](https://zio.dev) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [dev.zio # zio_3 # 2.0.22](https://zio.dev) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-core_3 # 0.14.7](https://github.com/circe/circe) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-generic_3 # 0.14.7](https://github.com/circe/circe) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-jawn_3 # 0.14.7](https://github.com/circe/circe) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-numbers_3 # 0.14.7](https://github.com/circe/circe) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.circe # circe-parser_3 # 0.14.7](https://github.com/circe/circe) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [io.suzaku # boopickle_3 # 1.4.0](https://github.com/suzaku-io/boopickle) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [net.java.dev.jna # jna # 5.12.1](https://github.com/java-native-access/jna) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [net.java.dev.jna # jna # 5.13.0](https://github.com/java-native-access/jna) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.apache.commons # commons-compress # 1.23.0](https://commons.apache.org/proper/commons-compress/) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.apache.commons # commons-compress # 1.24.0](https://commons.apache.org/proper/commons-compress/) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.http4s # blaze-core_3 # 0.23.12](https://github.com/http4s/blaze) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.http4s # blaze-http_3 # 0.23.12](https://github.com/http4s/blaze) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.http4s # http4s-blaze-core_3 # 0.23.12](https://github.com/http4s/blaze) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.http4s # http4s-blaze-server_3 # 0.23.12](https://github.com/http4s/blaze) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.http4s # blaze-core_3 # 0.23.15](https://github.com/http4s/blaze) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.http4s # blaze-http_3 # 0.23.15](https://github.com/http4s/blaze) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.http4s # http4s-blaze-core_3 # 0.23.15](https://github.com/http4s/blaze) | +Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.http4s # http4s-blaze-server_3 # 0.23.15](https://github.com/http4s/blaze) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.html) | [org.http4s # http4s-core_3 # 0.23.23](https://http4s.org/) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.http4s # http4s-crypto_3 # 0.2.4](https://github.com/http4s/http4s-crypto) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.html) | [org.http4s # http4s-server_3 # 0.23.23](https://http4s.org/) | @@ -213,20 +208,20 @@ Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [org.scala- Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [org.scala-lang # scalap # 2.13.11](https://www.scala-lang.org/) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [org.scala-lang # tasty-core_3 # 3.3.3](https://github.com/lampepfl/dotty) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [org.scala-lang.modules # scala-collection-compat_3 # 2.11.0](http://www.scala-lang.org/) | -Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [org.scala-lang.modules # scala-collection-compat_3 # 2.8.1](http://www.scala-lang.org/) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [org.scala-lang.modules # scala-collection-compat_3 # 2.9.0](http://www.scala-lang.org/) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [org.scala-lang.modules # scala-parallel-collections_3 # 1.0.4](http://www.scala-lang.org/) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [org.scala-lang.modules # scala-xml_3 # 2.1.0](http://www.scala-lang.org/) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) | [org.scala-sbt # compiler-interface # 1.9.3](https://github.com/sbt/zinc) | Apache | [Apache-2.0](https://github.com/sbt/sbt/blob/develop/LICENSE) | [org.scala-sbt # util-interface # 1.9.2](https://github.com/sbt/sbt) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # junit-interface # 0.7.29](https://github.com/scalameta/munit) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # junit-interface # 1.0.0-M8](https://github.com/scalameta/munit) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # junit-interface # 1.0.0-RC1](https://github.com/scalameta/munit) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # munit-diff_3 # 1.0.0-RC1](https://github.com/scalameta/munit) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # munit_3 # 0.7.29](https://github.com/scalameta/munit) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # munit_3 # 1.0.0-M8](https://github.com/scalameta/munit) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # munit_3 # 1.0.0-RC1](https://github.com/scalameta/munit) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # scalafmt-config_2.13 # 3.7.14](https://github.com/scalameta/scalafmt) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # scalafmt-core_2.13 # 3.7.14](https://github.com/scalameta/scalafmt) | Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalameta # scalafmt-sysops_2.13 # 3.7.14](https://github.com/scalameta/scalafmt) | -Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatestplus # mockito-4-11_3 # 3.2.16.0](https://github.com/scalatest/scalatestplus-mockito) | +Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatestplus # mockito-4-11_3 # 3.2.18.0](https://github.com/scalatest/scalatestplus-mockito) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.typelevel # case-insensitive_3 # 1.4.0](https://typelevel.org/case-insensitive) | Apache | [Apache-2.0](http://www.apache.org/licenses/) | [org.typelevel # cats-effect-kernel_3 # 3.3.4](https://github.com/typelevel/cats-effect) | Apache | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.typelevel # cats-effect-kernel_3 # 3.5.1](https://github.com/typelevel/cats-effect) | @@ -244,7 +239,7 @@ Apache | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.typelev Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.ionspin.kotlin # bignum-jvm # 0.3.9](https://github.com/ionspin/kotlin-multiplatform-bignum) | Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.zmannotes # varint # 1.0.0](https://github.com/zman2013/varint) | Apache | [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.iohk.atala.prism.apollo # apollo-jvm # 1.2.14](https://docs.atalaprism.io/) | -Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.didcommx # didcomm # 0.3.1](https://github.com/sicpa-dlab/didcomm-jvm) | +Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.didcommx # didcomm # 0.3.2](https://github.com/sicpa-dlab/didcomm-jvm) | Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.didcommx # peerdid # 0.5.0](https://github.com/sicpa-dlab/peer-did-jvm) | Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlin # kotlin-stdlib # 1.8.22](https://kotlinlang.org/) | Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlin # kotlin-stdlib # 1.9.22](https://kotlinlang.org/) | @@ -254,21 +249,17 @@ Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENS Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlin # kotlin-stdlib-jdk7 # 1.9.21](https://kotlinlang.org/) | Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlin # kotlin-stdlib-jdk8 # 1.8.22](https://kotlinlang.org/) | Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlin # kotlin-stdlib-jdk8 # 1.9.21](https://kotlinlang.org/) | -Apache | [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlinx # kotlinx-datetime-jvm # 0.2.1](https://github.com/Kotlin/kotlinx-datetime) | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-annotations # 2.10.3](http://github.com/FasterXML/jackson) | -Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-annotations # 2.14.0](https://github.com/FasterXML/jackson) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-annotations # 2.15.1](https://github.com/FasterXML/jackson) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-annotations # 2.15.2](https://github.com/FasterXML/jackson) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-annotations # 2.15.3](https://github.com/FasterXML/jackson) | -Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-core # 2.14.0](https://github.com/FasterXML/jackson-core) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-core # 2.15.1](https://github.com/FasterXML/jackson-core) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-core # 2.15.2](https://github.com/FasterXML/jackson-core) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-core # 2.15.3](https://github.com/FasterXML/jackson-core) | -Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-databind # 2.14.0](https://github.com/FasterXML/jackson) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-databind # 2.15.1](https://github.com/FasterXML/jackson) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-databind # 2.15.2](https://github.com/FasterXML/jackson) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-databind # 2.15.3](https://github.com/FasterXML/jackson) | -Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.dataformat # jackson-dataformat-toml # 2.14.0](https://github.com/FasterXML/jackson-dataformats-text) | +Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.dataformat # jackson-dataformat-toml # 2.15.2](https://github.com/FasterXML/jackson-dataformats-text) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.dataformat # jackson-dataformat-yaml # 2.15.1](https://github.com/FasterXML/jackson-dataformats-text) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.dataformat # jackson-dataformat-yaml # 2.15.3](https://github.com/FasterXML/jackson-dataformats-text) | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.fasterxml.jackson.datatype # jackson-datatype-jsr310 # 2.12.1 | @@ -282,15 +273,16 @@ Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licens Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.google.guava # failureaccess # 1.0.1 | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.google.guava # listenablefuture # 9999.0-empty-to-avoid-conflict-with-guava | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.google.j2objc # j2objc-annotations # 1.3](https://github.com/google/j2objc/) | +Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.squareup.okio # okio # 3.4.0](https://github.com/square/okio/) | +Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.squareup.okio # okio-jvm # 3.4.0](https://github.com/square/okio/) | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | com.twitter # hpack # 1.0.2 | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.zaxxer # HikariCP # 4.0.3](https://github.com/brettwooldridge/HikariCP) | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | io.github.java-diff-utils # java-diff-utils # 4.12 | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.iohk.atala # nimbus-jose-jwt # 10.0.0](https://bitbucket.org/connect2id/nimbus-jose-jwt) | -Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [io.ktor # ktor-io-jvm # 1.6.5](https://github.com/ktorio/ktor) | -Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [io.micrometer # micrometer-commons # 1.11.2](https://github.com/micrometer-metrics/micrometer) | -Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [io.micrometer # micrometer-core # 1.11.2](https://github.com/micrometer-metrics/micrometer) | -Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [io.micrometer # micrometer-observation # 1.11.2](https://github.com/micrometer-metrics/micrometer) | -Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [io.micrometer # micrometer-registry-prometheus # 1.11.2](https://github.com/micrometer-metrics/micrometer) | +Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [io.micrometer # micrometer-commons # 1.11.11](https://github.com/micrometer-metrics/micrometer) | +Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [io.micrometer # micrometer-core # 1.11.11](https://github.com/micrometer-metrics/micrometer) | +Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [io.micrometer # micrometer-observation # 1.11.11](https://github.com/micrometer-metrics/micrometer) | +Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [io.micrometer # micrometer-registry-prometheus # 1.11.11](https://github.com/micrometer-metrics/micrometer) | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | io.prometheus # simpleclient # 0.16.0 | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | io.prometheus # simpleclient_common # 0.16.0 | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | io.prometheus # simpleclient_tracer_common # 0.16.0 | @@ -301,9 +293,6 @@ Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licen Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains # annotations # 13.0](http://www.jetbrains.org) | Apache | [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains # annotations # 15.0](http://www.jetbrains.org) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains # annotations # 17.0.0](https://github.com/JetBrains/java-annotations) | -Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlinx # kotlinx-coroutines-core # 1.5.1-new-mm-dev2](https://github.com/Kotlin/kotlinx.coroutines) | -Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlinx # kotlinx-coroutines-core-jvm # 1.5.1-new-mm-dev2](https://github.com/Kotlin/kotlinx.coroutines) | -Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlinx # kotlinx-coroutines-jdk8 # 1.5.2](https://github.com/Kotlin/kotlinx.coroutines) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlinx # kotlinx-serialization-core-jvm # 1.6.2](https://github.com/Kotlin/kotlinx.serialization) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.jetbrains.kotlinx # kotlinx-serialization-json-jvm # 1.6.2](https://github.com/Kotlin/kotlinx.serialization) | Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.kotlincrypto.core # common-jvm # 0.4.0](https://github.com/KotlinCrypto/core/) | @@ -314,10 +303,13 @@ Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licen Apache | [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) | [org.kotlincrypto.macs # hmac-sha2-jvm # 0.3.0](https://github.com/KotlinCrypto/MACs/) | Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalactic # scalactic_3 # 3.2.15](http://www.scalatest.org) | Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalactic # scalactic_3 # 3.2.16](http://www.scalatest.org) | +Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalactic # scalactic_3 # 3.2.18](http://www.scalatest.org) | Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatest # scalatest-compatible # 3.2.15](http://www.scalatest.org) | Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatest # scalatest-compatible # 3.2.16](http://www.scalatest.org) | +Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatest # scalatest-compatible # 3.2.18](http://www.scalatest.org) | Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatest # scalatest-core_3 # 3.2.15](http://www.scalatest.org) | Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatest # scalatest-core_3 # 3.2.16](http://www.scalatest.org) | +Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatest # scalatest-core_3 # 3.2.18](http://www.scalatest.org) | Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatest # scalatest-diagrams_3 # 3.2.15](http://www.scalatest.org) | Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatest # scalatest-diagrams_3 # 3.2.16](http://www.scalatest.org) | Apache | [the Apache License, ASL Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | [org.scalatest # scalatest-featurespec_3 # 3.2.15](http://www.scalatest.org) | @@ -387,102 +379,99 @@ BSD | [The BSD License](https://opensource.org/licenses/BSD-3-Clause) | org.jlin BSD | [The BSD License](https://opensource.org/licenses/BSD-3-Clause) | org.jline # jline-reader # 3.19.0 | BSD | [The BSD License](https://opensource.org/licenses/BSD-3-Clause) | org.jline # jline-terminal # 3.19.0 | BSD | [The BSD License](https://opensource.org/licenses/BSD-3-Clause) | org.jline # jline-terminal-jna # 3.19.0 | -Bouncy Castle License | [Bouncy Castle Licence](https://www.bouncycastle.org/licence.html) | [org.bouncycastle # bcpkix-jdk15on # 1.70](https://www.bouncycastle.org/java.html) | -Bouncy Castle License | [Bouncy Castle Licence](https://www.bouncycastle.org/licence.html) | [org.bouncycastle # bcprov-jdk15on # 1.70](https://www.bouncycastle.org/java.html) | +Bouncy Castle License | [Bouncy Castle Licence](http://www.bouncycastle.org/licence.html) | [org.bouncycastle # bcprov-jdk15on # 1.68](http://www.bouncycastle.org/java.html) | Bouncy Castle License | [Bouncy Castle Licence](http://www.bouncycastle.org/licence.html) | [org.bouncycastle # bcprov-jdk15to18 # 1.69](http://www.bouncycastle.org/java.html) | -Bouncy Castle License | [Bouncy Castle Licence](https://www.bouncycastle.org/licence.html) | [org.bouncycastle # bcutil-jdk15on # 1.70](https://www.bouncycastle.org/java.html) | EPL | [Eclipse Public License 1.0](http://www.eclipse.org/legal/epl-v10.html) | [junit # junit # 4.13.1](http://junit.org) | EPL | [Eclipse Public License 1.0](http://www.eclipse.org/legal/epl-v10.html) | [junit # junit # 4.13.2](http://junit.org) | -GPL with Classpath Extension | [CDDL + GPLv2 with classpath exception](https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html) | [javax.annotation # javax.annotation-api # 1.2](http://jcp.org/en/jsr/detail?id=250) | -LGPL | [GNU Lesser General Public License](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) | ch.qos.logback # logback-classic # 1.4.8 | -LGPL | [GNU Lesser General Public License](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) | ch.qos.logback # logback-core # 1.4.8 | +LGPL | [GNU Lesser General Public License](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) | ch.qos.logback # logback-classic # 1.4.14 | +LGPL | [GNU Lesser General Public License](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) | ch.qos.logback # logback-core # 1.4.14 | MIT | [MIT](http://opensource.org/licenses/MIT) | [co.fs2 # fs2-core_3 # 3.2.4](https://github.com/typelevel/fs2) | MIT | [MIT](http://opensource.org/licenses/MIT) | [co.fs2 # fs2-core_3 # 3.7.0](https://typelevel.org/fs2) | MIT | [MIT](http://opensource.org/licenses/MIT) | [co.fs2 # fs2-io_3 # 3.2.4](https://github.com/typelevel/fs2) | MIT | [MIT](http://opensource.org/licenses/MIT) | [co.fs2 # fs2-io_3 # 3.7.0](https://typelevel.org/fs2) | -MIT | [MIT](http://opensource.org/licenses/MIT) | [com.github.poslegm # munit-zio_3 # 0.1.1](https://github.com/poslegm/munit-zio/) | +MIT | [MIT](http://opensource.org/licenses/MIT) | [com.github.poslegm # munit-zio_3 # 0.2.0](https://github.com/poslegm/munit-zio/) | MIT | [MIT](http://opensource.org/licenses/MIT) | [com.github.takayahilton # sql-formatter_2.13 # 1.2.1](https://github.com/takayahilton/sql-formatter) | MIT | [MIT](https://spdx.org/licenses/MIT.html) | [com.lihaoyi # fansi_3 # 0.3.0](https://github.com/lihaoyi/Fansi) | MIT | [MIT](https://spdx.org/licenses/MIT.html) | [com.lihaoyi # fansi_3 # 0.4.0](https://github.com/com-lihaoyi/Fansi) | MIT | [MIT](https://spdx.org/licenses/MIT.html) | [com.lihaoyi # pprint_3 # 0.6.6](https://github.com/lihaoyi/PPrint) | MIT | [MIT](https://spdx.org/licenses/MIT.html) | [com.lihaoyi # pprint_3 # 0.8.1](https://github.com/com-lihaoyi/PPrint) | MIT | [MIT](https://spdx.org/licenses/MIT.html) | [com.lihaoyi # sourcecode_3 # 0.3.0](https://github.com/com-lihaoyi/sourcecode) | -MIT | [MIT](http://opensource.org/licenses/MIT) | [dev.optics # monocle-core_3 # 3.1.0](https://github.com/optics-dev/Monocle) | -MIT | [MIT](http://opensource.org/licenses/MIT) | [dev.optics # monocle-macro_3 # 3.1.0](https://github.com/optics-dev/Monocle) | +MIT | [MIT](http://opensource.org/licenses/MIT) | [dev.optics # monocle-core_3 # 3.2.0](https://github.com/optics-dev/Monocle) | +MIT | [MIT](http://opensource.org/licenses/MIT) | [dev.optics # monocle-macro_3 # 3.2.0](https://github.com/optics-dev/Monocle) | MIT | [MIT](https://github.com/jopenlibs/vault-java-driver/blob/master/README.md#license) | [io.github.jopenlibs # vault-java-driver # 6.2.0](https://github.com/jopenlibs/vault-java-driver) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.rnorth.duct-tape # duct-tape # 1.0.8](https://github.com/rnorth/${project.artifactId}) | -MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # database-commons # 1.19.0](https://java.testcontainers.org) | -MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # jdbc # 1.19.0](https://java.testcontainers.org) | -MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # postgresql # 1.19.0](https://java.testcontainers.org) | -MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # testcontainers # 1.19.0](https://java.testcontainers.org) | +MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # database-commons # 1.19.1](https://java.testcontainers.org) | +MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # jdbc # 1.19.1](https://java.testcontainers.org) | +MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # postgresql # 1.19.1](https://java.testcontainers.org) | +MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # testcontainers # 1.19.1](https://java.testcontainers.org) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # testcontainers # 1.19.3](https://java.testcontainers.org) | -MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # vault # 1.19.0](https://java.testcontainers.org) | +MIT | [MIT](http://opensource.org/licenses/MIT) | [org.testcontainers # vault # 1.19.1](https://java.testcontainers.org) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.tpolecat # doobie-core_3 # 1.0.0-RC2](https://github.com/tpolecat/doobie) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.tpolecat # doobie-free_3 # 1.0.0-RC2](https://github.com/tpolecat/doobie) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.tpolecat # doobie-hikari_3 # 1.0.0-RC2](https://github.com/tpolecat/doobie) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.tpolecat # doobie-postgres-circe_3 # 1.0.0-RC2](https://github.com/tpolecat/doobie) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.tpolecat # doobie-postgres_3 # 1.0.0-RC2](https://github.com/tpolecat/doobie) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.tpolecat # typename_3 # 1.0.0](https://github.com/tpolecat/typename) | +MIT | [MIT](https://opensource.org/licenses/MIT) | [org.typelevel # cats-core_3 # 2.10.0](https://typelevel.org/cats) | MIT | [MIT](https://opensource.org/licenses/MIT) | [org.typelevel # cats-core_3 # 2.8.0](https://typelevel.org/cats) | -MIT | [MIT](https://opensource.org/licenses/MIT) | [org.typelevel # cats-core_3 # 2.9.0](https://typelevel.org/cats) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.typelevel # cats-free_3 # 2.7.0](https://github.com/typelevel/cats) | +MIT | [MIT](https://opensource.org/licenses/MIT) | [org.typelevel # cats-free_3 # 2.9.0](https://typelevel.org/cats) | +MIT | [MIT](https://opensource.org/licenses/MIT) | [org.typelevel # cats-kernel_3 # 2.10.0](https://typelevel.org/cats) | MIT | [MIT](https://opensource.org/licenses/MIT) | [org.typelevel # cats-kernel_3 # 2.8.0](https://typelevel.org/cats) | -MIT | [MIT](https://opensource.org/licenses/MIT) | [org.typelevel # cats-kernel_3 # 2.9.0](https://typelevel.org/cats) | MIT | [MIT](https://opensource.org/licenses/MIT) | [org.typelevel # cats-parse_3 # 0.3.10](https://typelevel.org/cats-parse) | MIT | [MIT](https://opensource.org/licenses/MIT) | [org.typelevel # cats-parse_3 # 0.3.8](https://typelevel.org/cats-parse) | -MIT | [MIT](http://opensource.org/licenses/MIT) | [org.typelevel # jawn-parser_3 # 1.4.0](https://github.com/typelevel/jawn) | +MIT | [MIT](http://opensource.org/licenses/MIT) | [org.typelevel # jawn-parser_3 # 1.5.1](https://github.com/typelevel/jawn) | MIT | [MIT](http://opensource.org/licenses/MIT) | [org.typelevel # vault_3 # 3.5.0](https://typelevel.org/vault) | MIT | [MIT License](https://github.com/multiformats/java-multiaddr/blob/master/LICENSE) | [com.github.multiformats # java-multibase # v1.1.0](https://github.com/multiformats/java-multibase) | -MIT | [MIT License](https://raw.githubusercontent.com/korlibs/krypto/master/LICENSE) | [com.soywiz.korlibs.krypto # krypto-jvm # 2.4.12](https://github.com/korlibs/krypto) | -MIT | [MIT License](https://opensource.org/licenses/MIT) | [io.iohk # pbandk-protos # 0.20.7](https://github.com/input-output-hk/pbandk) | -MIT | [MIT License](https://opensource.org/licenses/MIT) | [io.iohk # pbandk-runtime-jvm # 0.20.7](https://github.com/input-output-hk/pbandk) | MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [nl.big-o # liqp # 0.8.2](https://github.com/bkiers/Liqp) | MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [org.nibor.autolink # autolink # 0.6.0](https://github.com/robinst/autolink-java) | MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [org.slf4j # slf4j-api # 1.7.32](http://www.slf4j.org) | MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [org.slf4j # slf4j-api # 1.7.36](http://www.slf4j.org) | +MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [org.slf4j # slf4j-api # 2.0.13](http://www.slf4j.org) | MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [org.slf4j # slf4j-api # 2.0.7](http://www.slf4j.org) | MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [org.slf4j # slf4j-api # 2.0.9](http://www.slf4j.org) | -MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [org.slf4j # slf4j-simple # 2.0.7](http://www.slf4j.org) | +MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [org.slf4j # slf4j-simple # 2.0.13](http://www.slf4j.org) | MIT | [MIT License](http://www.opensource.org/licenses/mit-license.php) | [ua.co.k # strftime4j # 1.0.5](https://github.com/msangel/strftime4j) | -MIT | [MIT license](http://www.opensource.org/licenses/mit-license.php) | org.codehaus.mojo # animal-sniffer-annotations # 1.19 | +MIT | [MIT license](https://spdx.org/licenses/MIT.txt) | org.codehaus.mojo # animal-sniffer-annotations # 1.23 | MIT | [The MIT License](http://opensource.org/licenses/MIT) | [org.checkerframework # checker-compat-qual # 2.5.5](https://checkerframework.org) | MIT | [The MIT License](http://opensource.org/licenses/MIT) | [org.checkerframework # checker-qual # 3.12.0](https://checkerframework.org) | +MIT | [The MIT License](http://opensource.org/licenses/MIT) | [org.checkerframework # checker-qual # 3.37.0](https://checkerframework.org/) | MIT | [The MIT License](https://jsoup.org/license) | [org.jsoup # jsoup # 1.17.2](https://jsoup.org/) | MIT | [The MIT License](https://github.com/mockito/mockito/blob/main/LICENSE) | [org.mockito # mockito-core # 4.11.0](https://github.com/mockito/mockito) | -MIT | [The MIT License (MIT)](https://opensource.org/licenses/MIT) | [com.dimafeng # testcontainers-scala-core_3 # 0.41.0](https://github.com/testcontainers/testcontainers-scala) | -MIT | [The MIT License (MIT)](https://opensource.org/licenses/MIT) | [com.dimafeng # testcontainers-scala-jdbc_3 # 0.41.0](https://github.com/testcontainers/testcontainers-scala) | -MIT | [The MIT License (MIT)](https://opensource.org/licenses/MIT) | [com.dimafeng # testcontainers-scala-postgresql_3 # 0.41.0](https://github.com/testcontainers/testcontainers-scala) | -MIT | [The MIT License (MIT)](https://opensource.org/licenses/MIT) | [com.dimafeng # testcontainers-scala-vault_3 # 0.41.0](https://github.com/testcontainers/testcontainers-scala) | +MIT | [The MIT License (MIT)](https://opensource.org/licenses/MIT) | [com.dimafeng # testcontainers-scala-core_3 # 0.41.3](https://github.com/testcontainers/testcontainers-scala) | +MIT | [The MIT License (MIT)](https://opensource.org/licenses/MIT) | [com.dimafeng # testcontainers-scala-jdbc_3 # 0.41.3](https://github.com/testcontainers/testcontainers-scala) | +MIT | [The MIT License (MIT)](https://opensource.org/licenses/MIT) | [com.dimafeng # testcontainers-scala-postgresql_3 # 0.41.3](https://github.com/testcontainers/testcontainers-scala) | +MIT | [The MIT License (MIT)](https://opensource.org/licenses/MIT) | [com.dimafeng # testcontainers-scala-vault_3 # 0.41.3](https://github.com/testcontainers/testcontainers-scala) | Public Domain | [Public Domain, per Creative Commons CC0](http://creativecommons.org/publicdomain/zero/1.0/) | [org.hdrhistogram # HdrHistogram # 2.1.12](http://hdrhistogram.github.io/HdrHistogram/) | Public Domain | [Public Domain, per Creative Commons CC0](http://creativecommons.org/publicdomain/zero/1.0/) | [org.latencyutils # LatencyUtils # 2.0.3](http://latencyutils.github.io/LatencyUtils/) | none specified | []() | [net.jcip # jcip-annotations # 1.0](http://jcip.net/) | -none specified | []() | [org.hyperledger # castor-core_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # cloud-agent-wallet-api_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # connect-core_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # connect-sql-doobie_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # event-notification_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-agent-core_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-agent-didcommx_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-data-models_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-connection_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-coordinate-mediation_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-invitation_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-issue-credential_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-mailbox_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-outofband-login_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-present-proof_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-report-problem_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-revocation-notification_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-routing-2-0_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-trust-ping_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-resolver_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-verifiable-credentials_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # pollux-anoncreds_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # pollux-core_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # pollux-sql-doobie_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # pollux-vc-jwt_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # prism-node-client_3 # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # shared # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # shared-crypto # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # shared-test # 1.31.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # castor-core_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # cloud-agent-wallet-api_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # connect-core_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # connect-sql-doobie_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # event-notification_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-agent-core_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-agent-didcommx_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-data-models_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-connection_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-coordinate-mediation_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-invitation_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-issue-credential_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-mailbox_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-outofband-login_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-present-proof_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-report-problem_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-revocation-notification_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-routing-2-0_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-trust-ping_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-resolver_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-verifiable-credentials_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # pollux-anoncreds_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # pollux-core_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # pollux-sql-doobie_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # pollux-vc-jwt_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # prism-node-client_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # shared # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # shared-crypto # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # shared-test # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | diff --git a/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml b/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml index b7fdecc6ae..701bc05122 100644 --- a/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml +++ b/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: Open Enterprise Agent API Reference - version: 1.32.0 + version: 1.32.1 description: |2 The Open Enterprise Agent API facilitates the integration and management of self-sovereign identity capabilities within applications. @@ -127,6 +127,31 @@ tags: The __metrics__ endpoint returns the runtime metrics of the running service scraped from the internal prometheus registry. This information is collected by the prometheus server and can be used to monitor the running service. +- name: Events + description: | + The __Events__ endpoints enable users to manage event-related resources, such as webhook notifications. + These notifications are specifically designed to inform about events occurring within the wallet, including but not limited to: + + - DID publication notifications + - DIDComm connection notifications + - Issuance protocol notifications + - Presentation protocol notifications + + For more detailed information regarding event notifications, please refer to this [documentation](https://docs.atalaprism.io/tutorials/webhooks/webhook). +- name: Identity and Access Management + description: |2 + + The __Identity and Access Management__ endpoints allow [agent administrators](https://docs.atalaprism.io/docs/concepts/glossary#administrator) + to manage identity and access management for the agent's tenants. + It provides basic built-in IAM capabilities as an alternative to more feature rich external IAM solutions. + + Entities are resources that represent individual tenants and + wallets act as containers for Self-Sovereign Identity (SSI) resources within the agent. + The administrator can grant tenant access to specific wallets by associating the wallet ID with the Entity. + Additionally, the administrator can create API keys for entities and provide them to the tenants out-of-band. + These API keys can then be used for authorization to access specific wallets. + + For more detailed information related to the agent IAM and its usage, please refer to this [documentation](https://docs.atalaprism.io/docs/atala-prism/prism-cloud-agent/authentication). servers: - url: http://localhost:8085 description: Local Prism Agent @@ -2849,6 +2874,10 @@ paths: tags: - Events summary: List wallet webhook notifications + description: "List all registered webhook notifications.\nEach webhook notification\ + \ contains a unique identifier, the URL to which the events are sent,\nand\ + \ the custom headers to be included in the dispatched webhook request.\n \ + \ " operationId: getEventsWebhooks responses: '200': @@ -2882,6 +2911,9 @@ paths: tags: - Events summary: Create wallet webhook notifications + description: "Create a new wallet webhook notification and subscribe to events.\n\ + A dispatched webhook request may contain static custom headers for authentication\ + \ or custom metadata.\n " operationId: postEventsWebhooks requestBody: content: @@ -3468,6 +3500,8 @@ components: properties: url: type: string + description: A URL of webhook for event notification + example: http://example.com customHeaders: $ref: '#/components/schemas/Map_String' CredentialDefinitionInput: @@ -4058,11 +4092,14 @@ components: DateTimeParameter: required: - dateTime + - parameterType type: object properties: dateTime: type: string format: date-time + parameterType: + type: string DidOperationSubmission: required: - id @@ -4079,10 +4116,13 @@ components: example: did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff DidParameter: required: - - aud + - did + - parameterType type: object properties: - aud: + did: + type: string + parameterType: type: string EntityResponse: required: @@ -4278,7 +4318,7 @@ components: type: string description: The date and time when the issue credential record was created. format: date-time - example: '2024-04-26T13:30:41.666452407Z' + example: '2024-05-07T10:53:56.428516424Z' updatedAt: type: string description: The date and time when the issue credential record was last @@ -4879,7 +4919,7 @@ components: type: string description: Issuance timestamp of status list credential format: date-time - example: '2024-04-26T13:30:41.708554220Z' + example: '2024-05-07T10:53:56.466164983Z' credentialSubject: $ref: '#/components/schemas/CredentialSubject' proof: @@ -4999,6 +5039,11 @@ components: oneOf: - $ref: '#/components/schemas/DateTimeParameter' - $ref: '#/components/schemas/DidParameter' + discriminator: + propertyName: parameterType + mapping: + DateTimeParameter: '#/components/schemas/DateTimeParameter' + DidParameter: '#/components/schemas/DidParameter' VcVerificationRequest: required: - credential diff --git a/infrastructure/charts/agent/Chart.yaml b/infrastructure/charts/agent/Chart.yaml index 4d296f9ca2..8b943782b5 100644 --- a/infrastructure/charts/agent/Chart.yaml +++ b/infrastructure/charts/agent/Chart.yaml @@ -13,12 +13,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.32.0 +version: 1.32.1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: 1.32.0 +appVersion: 1.32.1 dependencies: - name: vault version: 0.24.1 diff --git a/infrastructure/charts/index.yaml b/infrastructure/charts/index.yaml index 40a9be5c87..d012faf33d 100644 --- a/infrastructure/charts/index.yaml +++ b/infrastructure/charts/index.yaml @@ -1,9 +1,27 @@ apiVersion: v1 entries: prism-agent: + - apiVersion: v2 + appVersion: 1.32.1 + created: "2024-05-07T11:16:27.653690458Z" + dependencies: + - name: vault + repository: https://helm.releases.hashicorp.com + version: 0.24.1 + - condition: keycloak.enabled + name: keycloak + repository: https://charts.bitnami.com/bitnami + version: 17.2.0 + description: A Helm chart for deploying prism-agent + digest: c10e1f30eae30d047d36207c6e2a956bb5bbc7865bf34082fe10745d1492a715 + name: prism-agent + type: application + urls: + - https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/main/infrastructure/charts/prism-agent-1.32.1.tgz + version: 1.32.1 - apiVersion: v2 appVersion: 1.32.0 - created: "2024-04-26T13:53:00.924318867Z" + created: "2024-05-07T11:16:27.642515591Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -21,7 +39,7 @@ entries: version: 1.32.0 - apiVersion: v2 appVersion: 1.31.0 - created: "2024-04-26T13:53:00.914478047Z" + created: "2024-05-07T11:16:27.632501068Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -39,7 +57,7 @@ entries: version: 1.31.0 - apiVersion: v2 appVersion: 1.30.1 - created: "2024-04-26T13:53:00.898640334Z" + created: "2024-05-07T11:16:27.621312345Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -57,7 +75,7 @@ entries: version: 1.30.1 - apiVersion: v2 appVersion: 1.30.0 - created: "2024-04-26T13:53:00.888615591Z" + created: "2024-05-07T11:16:27.611378153Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -75,7 +93,7 @@ entries: version: 1.30.0 - apiVersion: v2 appVersion: 1.29.0 - created: "2024-04-26T13:53:00.877632701Z" + created: "2024-05-07T11:16:27.600753265Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -93,7 +111,7 @@ entries: version: 1.29.0 - apiVersion: v2 appVersion: 1.28.0 - created: "2024-04-26T13:53:00.861865286Z" + created: "2024-05-07T11:16:27.59061395Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -111,7 +129,7 @@ entries: version: 1.28.0 - apiVersion: v2 appVersion: 1.27.0 - created: "2024-04-26T13:53:00.846878701Z" + created: "2024-05-07T11:16:27.580733909Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -129,7 +147,7 @@ entries: version: 1.27.0 - apiVersion: v2 appVersion: 1.26.0 - created: "2024-04-26T13:53:00.835824187Z" + created: "2024-05-07T11:16:27.570285213Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -147,7 +165,7 @@ entries: version: 1.26.0 - apiVersion: v2 appVersion: 1.25.0 - created: "2024-04-26T13:53:00.819989755Z" + created: "2024-05-07T11:16:27.55993564Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -165,7 +183,7 @@ entries: version: 1.25.0 - apiVersion: v2 appVersion: 1.24.0 - created: "2024-04-26T13:53:00.80826429Z" + created: "2024-05-07T11:16:27.54997569Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -183,7 +201,7 @@ entries: version: 1.24.0 - apiVersion: v2 appVersion: 1.23.0 - created: "2024-04-26T13:53:00.791829194Z" + created: "2024-05-07T11:16:27.538591962Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -201,7 +219,7 @@ entries: version: 1.23.0 - apiVersion: v2 appVersion: 1.22.0 - created: "2024-04-26T13:53:00.780616541Z" + created: "2024-05-07T11:16:27.528993148Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -219,7 +237,7 @@ entries: version: 1.22.0 - apiVersion: v2 appVersion: 1.21.1 - created: "2024-04-26T13:53:00.770382101Z" + created: "2024-05-07T11:16:27.518115901Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -237,7 +255,7 @@ entries: version: 1.21.1 - apiVersion: v2 appVersion: 1.21.0 - created: "2024-04-26T13:53:00.759247785Z" + created: "2024-05-07T11:16:27.507791701Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -255,7 +273,7 @@ entries: version: 1.21.0 - apiVersion: v2 appVersion: 1.20.1 - created: "2024-04-26T13:53:00.74470437Z" + created: "2024-05-07T11:16:27.498373165Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -273,7 +291,7 @@ entries: version: 1.20.1 - apiVersion: v2 appVersion: 1.20.0 - created: "2024-04-26T13:53:00.732799898Z" + created: "2024-05-07T11:16:27.487590109Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -291,7 +309,7 @@ entries: version: 1.20.0 - apiVersion: v2 appVersion: 1.19.1 - created: "2024-04-26T13:53:00.721973955Z" + created: "2024-05-07T11:16:27.475636701Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -309,7 +327,7 @@ entries: version: 1.19.1 - apiVersion: v2 appVersion: 1.19.0 - created: "2024-04-26T13:53:00.705290074Z" + created: "2024-05-07T11:16:27.465601019Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -327,7 +345,7 @@ entries: version: 1.19.0 - apiVersion: v2 appVersion: 1.18.0 - created: "2024-04-26T13:53:00.693144356Z" + created: "2024-05-07T11:16:27.455032514Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -341,7 +359,7 @@ entries: version: 1.18.0 - apiVersion: v2 appVersion: 1.17.0 - created: "2024-04-26T13:53:00.68806769Z" + created: "2024-05-07T11:16:27.452077627Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -355,7 +373,7 @@ entries: version: 1.17.0 - apiVersion: v2 appVersion: 1.16.4 - created: "2024-04-26T13:53:00.683156552Z" + created: "2024-05-07T11:16:27.449273283Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -369,7 +387,7 @@ entries: version: 1.16.4 - apiVersion: v2 appVersion: 1.16.3 - created: "2024-04-26T13:53:00.677232701Z" + created: "2024-05-07T11:16:27.445784373Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -383,7 +401,7 @@ entries: version: 1.16.3 - apiVersion: v2 appVersion: 1.16.2 - created: "2024-04-26T13:53:00.672674125Z" + created: "2024-05-07T11:16:27.442955443Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -395,4 +413,4 @@ entries: urls: - https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/main/infrastructure/charts/prism-agent-1.16.2.tgz version: 1.16.2 -generated: "2024-04-26T13:53:00.667476213Z" +generated: "2024-05-07T11:16:27.439865083Z" diff --git a/infrastructure/charts/prism-agent-1.32.1.tgz b/infrastructure/charts/prism-agent-1.32.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..feedc0b66c0b9fcf4d219d887744e2611676f36e GIT binary patch literal 161106 zcmV)lK%c)KiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0POvHciT4BD2(@SeF_{o&m`$%Qj%}UXnr~8=h~jeCyDK4xtW>O zXI>W~Aqh1_Z~#z_n&kcL@4}VfO`>dBaa*%%H5LhM02>?ohK-GcVm9^Q7{$DEG=Y@+ zb2yE@TkF&9cDo0Ad-C6Iw_E(TyT7~lU2pH8cd*wzIOy$u*X`}@?RLKd-Su{(`bimw z^tflj z02C#JVNU404YgQ4*0kj>o`R8!gof_YI#Xs1IP0L^yx~R%=$k+_#?FCQo_&M_vMQAS=q5yVZ!`|Mj*C<5c>-}zPjABF~M`0hdce*>fUa#l%4z6~( z{r$i8cVGK^uMS?n-tF%HclTAl+im|Y)^*dzUH>x}rHHLx0a(2Ld)-&BO6&jN)&A4^ z-^7FCF-45^TL5U0+XtMcs0Ccn_7ja{5l_iUZwMLk6zMPygBu@m7(w~M$D{>75E=uI143nkPOnBVVo1J%QABR93B_X^vp#6IMQ2k!aVywS2v{*o zr-)ut#5l!)lKZ94tPg(vw|uh&PCju&V;F%W^ASLb0ErO;w-ZDW;1dKG3Mk@&wXx3O z#VO$A2E|N+5ap9Jickn}3{oZ(3JZ21YclXNj6(s6q7k7;)QO*SVEGXk&VgXJs#{3c zJ}Py%_~jj%Ur;o{pK?gQL31yWuUjqEb%|p2=YSK6a>aEK@xBE>NP-(gFVPq?PUlx* zq`A`SyGL~aPvSzfLuZJJX7Ch_k(!~r2pCTSswQ1L0%aE@!oj=`PDf{iUr@w^x}`pI zIPQbVJV7)<;TX{l4pGcg<^>T+L#>$!_>819K$?akJjI-u#)Bm7gZ*xIs((+>RCc7- z-P!wqTdIHmNf9el+1W2u+3)Sh8WEnM7%_H1$xshcNVXplHxLrYCwbjly(>a6wfdv@f5`z%pk>L0W!b|7$N|}5QXAzwPFN0h$Y7%ju90L*Md2TXCF=F zKKT5#1whKsN1=+?9?&AawwLxfR+%(1%pl(CcJvhG7H4_2>GjsjmT0!(cJ>eS8Z9nsUF%g(B?tX2A`do;t{(JF%xZqH<~Y~2Zo`Lq~Hx`|J?8YyZ?GesH)lbAW9iW z^tz&4&n>qFPUMh48Vi|R!&olC3vf|4oX6O=M=o(Snh z=t~zWM-dVb=DFc)fnqb)x|wU;%p1@a$jSBatNoGvCFB$wBhVh<2<34mSfGH@kyF?a z)Y^6+w49NDg3}~IdX`cubssrACBI?HiI>IoZqsmO+3;_r<9SVGtH0BOWK7kxyCUqV{@o$R1 zYJ~lGbRqkZl^5Lw?QxIG>B`8xS&%KUvoSa>#x1rWx4U_rFktli{QX!X;+Z0Rjrr+sAB!H3R(676% zyTJ4CRPbX@3V7goBLsO$5qlG&AcA7@XUG%1@DfTS6KF|xSzyzd^iMhYF*E%2d$G7M z6O$u}Nhm6mL`)7^%5J86a@ozU<7+XVUQJm zVu)rE*huOBL^U$W*aydsXfOAvo$r*g$ui}^wBl)I ze-IL5=kPKCG`1QQgdg5#f#V`5*Qd_qAg zt$kHV0UMx5>Tg$w3dC<^n4dx(Oin%}LO;SJc0W2()8_L8wez04BoQM^a~*67c?57KrD+hqERIp zlYUIs|HsiZi6BR;b3H*(f++KOvIbY+69511PPbd|{~dIDdr$tqO+24Jdmuz393#*U z2xV>XRp}_=10DhYqjCxxN1Z5RHs?%H!(+s^maED1T}5UQz??_VfVI|=Wqt+6-{;Rw zpnU=VNeM?8RM8QkyEp^YKh2+>{yRgA@~e4{2eDlqeYsEp8xoysKzxQt;@_l0L}SFofJi5SlzU{9_u|w+oFEtq zR?AS3Qq1Qi!lH;JBxcB?=$2xR>X%rNQZ#7SFT`Buk$C>;9Z6lDdsp)WdFP3iKJA#W z7>`EnLg~L#p{QrYLKM&QWemK59*}4Jx$O{*q=Cn10G=}xjh;&_tp7KlHsqZTe-nd= zQILO!r{k*1d>)}(xsmLo^g3}uS@xdLsRz~i((m$pAIRnBT~Qb_sUDd@^g(+HKZ&V) zv)kL>J?M73e*-uUqBKN=KO-rHEz-V4_=!F%@tIg9(x|K}jT$?*-!3 zHi(HQeeiC1il$_S`rzmGKzf_n|6WR6+Q)VpR*;wc;^A;r!n#%f+W+(}HH_2ateYA+ z*Eqg56s%#oef`$*@6Y~J>whr841Y3WOZ30q{;QpW{`YEculJuH{BkDB1j?zgWphu?bTt7j4a zrzGWQ4dFn`;(xk3`$hZz)$UXL&qki*{C_20a4ATpf)QxPqx@Q0`s-cwa{s{beCnpt zNIN+p5A6D%5NF$Yfo+|xIoYFBdSG&PL_*1@`RX>R zG|;b8iiJ7z|K!l~!vFqdd%N9v)@%Pe*HlWeH;iP&QS*jmg=;|vOf+R8V)VYCZb9|v zR}`qNXvW}J5UJi<<-~3ynji*%8Hfp2t|=6P5hYUqW4q-7BBHS0E>p4cxA~bPD)+6* z#X5`e$GRl=t zIoZUVBRC7krwX=h!R3S8JP)p3{{f;LkK~Dr2lxMXd)?hq{NKUutEct9iD$L-FX+OX zsuNT`CY@PNul}QqV4AOg0qwyU001zK3D?22${kL}BnW-+PeRGBVgPI&2i`55iKe|? z+p-O{bkCZt?ogjS>4Tl#L3h%fb{W_Lf9;0yBx;Oqe~`y}`(QWw+S?ajF=HvBcK=af zD?*&1Se}egdzK2rD){|W))0-xOyXyqyzNN^{L?)({9oEHQJ{P5lN4~K)3>z^*)zj;=Al`nXB{NeQM`lrFkrBgI}SylMra4`7C z`Q>q`g83jTU7j4i|8RYF_~GQuv+QsA>EiNq@ZtLK$CI!bIl;-AywH_s|x*Hsvt z99^DVRaR1;6hcO6tRhy&h+oU|OV={H!i$&o{GU85X9I=bJbPh14?#*J;Cb3J04~l4 zSD;-+Xh)t2Vx1`zLZ*{Y!bw1)4oOgqLr=%zc4WJ4@ITqcv*(QY7f~l7tCueVIeL z+8S0f^5)qK6if(sW@Z9>0l)qScoaPM-Ez+j2vyqsBtLvDOgv`S8W-{;9V^Xzz7xIN zw+xHVc3QbF6V8)s#vxDH0+RXhq?%&noEW-smPbc5$U4t#%Q?(TTDb-7|N1Q37s&tG z2Kf>MbV4-i#Ay`eKfDF)Lw)L5t6V=IND<8=F`Fs<2Ofc+!82#P;LRJb)9r$P{|)d7 za*x-^DaoBVM<%y~TR(+irmnQxxz+*^3_q zuVE^YfvhLyGglhAgBU0W@WKk(NqneI<1Z;HW+&fW^Ujvj=T$Y$D5CmNpCVQ#jcw4$ z4T^#9`>KNCNry*ACxgND)%m-Vvp3IP6eNSDdo4>&{&_mMdh_f>k&A$5WmuqEf+>Eb zR*?%;EF--X3QI{1=t!&pIU*3F+Zy1SsIwu0{K{FOpOvq*EY%CORj_!A87HeZavG^d zwI_W|vErd!qaqnXZ_8TkTxgcsxyZVy&cA1e+6?8jb^qJWMud(IUS!f$>;Kt_-E|lM zi}nAV-Cp-qQUBlHJ9yInH}T}Xy9vu&I>(jgLWEo9Dz6h-fu2TGnp4`)(GFtECs%P^;}doO#cA(_jY&w2124l zj~ImzJR?FuHW+hq{%?Rq2qi#Ph|%9{^k+dh6q#?~;Bx_K)-;@>&;YIVU<>|+ z9N-1wT%}quc56O9qOygYgTiU$@03jQCws;0aq=%Xjh3`-GueCrF^)r_a`kqqx>E3g zG##T-St{VwdrO*vRvMyj^5!*c#L)=vi@{t66tk{H9b_4zH;;|8lKA7SQ1b03*Pr}`5~RQ6Ff ziD;qE7pK?nPX2X0IDCJ#_D&~Q=H+ED;?=#b{Ia~$7w7Na|Mbu6;~%cyo)0RzonN{S zqLH;1cI)E&vbtMY>aMz~1p#EMCM1f|PYbIS5a-gReE4Lu$Pb&u8NPS4tx+T+92dKTFFdAY^ZW8_NfA+Lww=8qb2 z_n?3vg35~PU2u*S_$Wx_9&0R{l(ny}$A+bKEU5J}Z)2Q4 zLJqVJvU(WC{fLov4=Ou8Jw7`B@ZoxJa{2M}sJL^Gu}O22-RI8$$07Q(G!(lFzJ9IB zqfo_bFHZ(n58s1IuZ#4apPe6{)XFVqg0uTo{0U*aoO`zhbe-_22AvRE1G;*{Dnzpn zB&_Mh@yW;Q59h~~60CIfi1eLDtQOSY4}W@pb^VXS_wP@{e4VU)b=|@!Lfm5rm1$Yu z;#2XZp2{my^p+i;hd*7tJvqBNJvzKPxjr0Rn{ih2+#0l%r^Q_ERNeST*~H=Tadi_l zdv!LGp1euKulroO9Vg%Fn*G!2Ruf7HU*w)%@O{PkTXho~RP8pNoE`q~zKVb==C@S2 zhDEKi!CC=TZa*$z6HE6VE8tdbJ>GNkvA&hk-s1w|y8r&;UYRl~$wg<2yg~DA@J#l{ zO&F;gt-h+Qdf1;oOKACzE>d+XwQRh!XSrG+!YsSP1FW>kTDrvply7%iutTdiDuul1 zgYJH}>wGI*^^x7}phFn)DWTOpAH{Da)VOzL)KZNp%<}`PPrnWZym<= z^xW~Oj{h{->y&hR;QY@!z0&=^ul9OR=f5`cxbdH6*3H$g>V)qQacE*f%>}kf&{UoD zy<1>n;S_M4+SV!tV>XT+rD#MEo1DfR(V0-B+EV>oz~Uv!v^ zfR-s5p1LwBaBhT<@~C3$71#e}f$|TXfqETu`2hKxH%g4T&R0=nL6KTOnazmcPm=-r z&;3-(f5*G_;O9TOyE}X3^B=FC?*H1zd&Xd}i_1c=fX5>)ATG!*?y_*)$nC)@| zr>EhH9Tt63wxnu}$vdtWgK+P|HkTcgFT-94qEuduJ9imkYl*SvyQLk2P5T5&R$pU_ zPXj1~pH@^akE<#MRf9{JjX-we#hkQ$X@aOIW#6b{g5fY%sj&Z$)sM(nU;UYjVrbkz z-NtlP3(huMWBAqkCuQgct2t!lgY4Y?7J@dirgEEs71zklEMMsDwHuwAEFGKN1V^d8 zC-#Y*EMq6mlFMI^+n8o;HFeGI&;Ksdr@d#od&(^K{PCmL-w5o3+~ z=M=|dHS5NnUZsf^XYih#BC{|e#{3+)A7Dk~TqRy-* z*R-|Z29iV;Yy=glrl~n**3*d409_*88U;oZY)fE}Q9oGNe!BhVCjXV#%{vE2>00S`1G+Y0@gQxZ1 zc>P=F&FV2BOV)pHr+ELv&hF0s)B4}Y^T6xhQjH2wbdsh&G$(NGUTDe-D*V^$#7N%# zxgsj==%l^_=4^7_mGr0zIK~}+H-O)IVf;y+#{Azod9ZH#Z}-)HN&o9U?f-A&d0_tU zP|Ze|KC0p}6ZEOf?{{85@t8*I|Nfgm%k;l)uXz8@tM0*5{O?Ad>>E?>n(|tcrPxe&ve|2IpjTwS# zhyY!}|94(>4@&&M*L~vun|QW>IX13NX9zCVAyYKQB+ijRXBd&8xgQ37g3}~Itdni4 zbplG_U&&CCOL60};>52j3Wkse6X!BHO5*=Zh829??U1J%%=UVN2@2ClFvagXyIt_T z`cH<|r}8d^Q5yYUGGuQt3~0?Ii+^W9V@t$#WjoE*NFr_8&hq6<#OYV0jMe65}eq}-snSJfJ@ zIW}y$=H2gYwEI=9-K+aM8|{8oYs6ld!l&Vni!Si4k3RU#Y8qx(+!eHAR;|f+&b^jQo~=Jh)cp z*S5fsw6nm+qX7spWi5Yjc=Tq@Fp?KW-{{L-lfsc@4k}`05e8O6OLdmZv;4L4A2zFF)N`7tm zGZv5#b$$;8v#&Q=K11 zm?F2gx4xu8y~2DfwjN@h4jv}KQRbp4$@zxR7!gMZqm zmjBO`<^JIJKlgTf`>#spe|LAD;y*X?2rVd?Q#_t<@FIAbvFB}Y8V5q<8(bX!(|eBt z6f@+V$^?ufjA$QxxOngF_}x}(3mncMj^Hp7svCt<#1Ume;RAevFtxY0D4LRYa`6e$ z0zguo-)adp63T;MTfl5TU?vMHuakYtZZQugJ{aihGPzJnIgz*C079*ceGA;;DALu$ zhY&OQCyXKqHz3o5#3<%WDxo-5pk$B0aBlkTw}5F|U#%m7pHATzfh3J0&HhCnQikOC zOm-6?0ww}yDxlq$H4h^h6)v>oXud7GqOxI4;T#N+^a=?ihX4vR0!S&G12O`7Urs+5P#|n=w zGECgNl3GAH{D3yU?Tq92S9u&m(#Fx?6d0MIQK!(8n^!r7X5zAJG6EYg*O>2w+e^wi z3`5!n?Y5q+k*+Nv6L6lOcpy}q764Y=G21h;hP=EKfeR82wA9yE2B|ycLe>HxVLDHk zq7OGg-xfHux|OU_0_5v*(x}1=Krl@sjy+-WSg&KKCml>-B8?~z2#Sapk(7eCppkza zet55-x%!;GT~vB%1gZN*d#OC00i%fAqVR$eVF^k1M<1xXFCD!QwrLu3JVoZW1`m@2 z(kY=C{2}6vz*oa-)LmW0f!7B$@EY~65j=UKND$i0d*fRz%fT-bz)xG zwSwv|D48NYK`9edCpSBFtpP%^1SbiI&uI41^;(#j))17GMPM3FLqn&qKzbxLAN($`y6uS#rn#Q6c^UD5$0dH24$u zkXe) zNGGP0MrNXltP$XtaRkF9d{c@G!DrO0QIrrR+2L65U?sb>t)L4#V$hvmE49=RvK!+1 zpj}~jsGSE6$9>T5`8$43y-4cz9%OGN(Vi~vvQj-NyQ@AO>g4rX&VGvzwEs)dsb;@I z@t7b$jDhQb_JRJ@^LPE;e*?@UM2h~CVu~c@vkouEN**J^#@2ImH9>VcmO?%X-C?;y zGF>=U)tTXEe81GaCo!UuceweGG)M;7G4=ZPW_ZRsl?X-q(nGESyhK|vpe7a0M6K^Vh|v&zZA zaS){;>Vvkr{$3DgdkT}bs$e%9)yra^G!U(^${BsmY^7_3MZh?We}j2|iUXT16!Z!6 z^Y~JT8NJJxyEu}G2@I4Hd5Pi>Q72)UCcK}RP!5S8KB2Q{T;wlBWJ;S8q+fBt;uiRa zKqM4`Yly%I;)rd7ca};N%M_Aur22R@p@>aL6apccnGuO&JQF0Ds(WUOW&2=9w{|8o zVMtvX1tbm`fFr?ul{ugZ3``(Xmo}o%G@$y2W6ZH&{t}$}6&<4p&IbxyAMERv-jZ8D zMnaOkz_DrVrNCB#s8~}<3JS1_u_213hN!@p4u8Ngo~BdLIibEt&$`~uc9yy79hW+x zC@FMmp*q@qZ#~QjlxPz8(Rspk5eHShC8)Zc;9%mmD(8WuToW6fB9ihPKI$liA{gRI zQptaLqLn9F$z6%+P)hl7)lJb!?{`Ni`+polk(46uQU({0Px6YLGuMYHpMVdDPl(dD zQa(`^D7VF*jy}?^v{E861~Wv5LMfY@MqG_{3k=kDC<Lg0Z4jbiI^LGr z)Hb+cp z)Fh0eoW>~TK7dr3Lln)(4brYXdE{CtLu`^NzfDMPW68orx$}51Nx69C7%R7EI3eW5 zELW#ty~?zwMGsXM_obrSPGhTJwXNDaM1l%QNWu$ zfEp(Z0mFy{Hy|OQviPJ8Kfw`l`ylkYG=|3Cxvfk9Y0k8%z>PpjeLthz=!kT7wCU$AUXT!Jid+0Zk*ZPDdK1c=aI_nqxfvhr-yA ztJQA?A13I)qe{DHo_yn?M>08S;Dm?^0pUAnb1>5fC!b)z4bJj>$oQwByqDc&YMQ^h zgroanT@fl6A=H4S+dAt8I2{4Z1$UUbGO4zxEo!zCxuWuswf;tevO>|4=U)&o6^#YhswHBBO`x0JAAJ{Y2W??jny zX**4^X3x6!K<1MJ6%fJauVxa+P*hpx4Ctc}-w69^JaWqp$*lBv+vUuSX zy88%H3UIFFfkOo44F^S9c~@kTxgwt%L7rn;&y6RtsDwO#F0f1!SgZ%!T?g2>1|axv zt@K|$K_#}4pQLqh?^@pdI5>AT^T@G|8lGLnIU4ZmT5i33#`3HtKV56#^Oaow5%Bm% zlT_yJ3ub6JXD{;grjz6_%lr(j#B}vvhh@$iAey=Gm8V)>u%>5Rke6Y4CS+j(x%5nk zcZD4;8M3QjB^1xZn;RtAo7|<$Z{AtHd^%Fwl9+)wjUpM|;F@At4Y{*#9PI>P&TPP3 z;Kb2^DG8D4sH_4R!{b;(gFxr<6NZY^!Zo^VGn@c(`cgJQZsXE69&nJ=m)$nfFn~X# zaTp=BKd+8edh(zp3cn>ThlRNRDP`PKH=#p*EHXM^;&Lu_EC)gtsl2RDuE(HX{`PhQI{Q z5TFP$B3Gw|qsfYaVajE|#L)N=@oy*;h>MY6N090$3^Ry6;1Tl!s!*&)qh8*ic}ufA z6-FR^d*~C-9A+fU^er9!lo6u!1eW&fL_HImaHL^k%aLdrAF?wNUlPLY4vqcrBPD54 zNG+)yLt`9*FSe0hx7$^RiEZ7VWYX@cs%f!mR&#W>CIvc1E*8vgsL&y!h}>RKJi`$h zqZ1auNNpZEp2JGnX;*gJ^do)4~a zH&~faIW`Ma*X_jgga!^7B&@|z5<-9Rf4dQf|h9t_CVkU0XSvmeh;2Fo` z2&sq;&1e~5X)qCOeZVmmsFMC?b9;xj1rrh;#vC6OZgDgr0>^TveV|UZ;&`ldc>Vh1 zll0w_*fsg2Zk9J=%~P^uv!^bj?n(yaGLTr`K2VWaSZ8B!9~+$6&)J*m;Upmu8PDGd zbGbUrunvvT1?`Se4H;52>Ng5fxFz%^A~0kfQCIxWGoA5RLJ&Q4!jT&>gOQSV<_x?K#E$VP~9gXdxSWnh$ zQC5cz!jR#mLT)N;P%O@Ez4gI$-0Z^cCH`vDo{vpYje278MHf3;;{Q3DByS=*!!Qz{ zDnyb7lRkjc@L*5h^;5PmE+{5S_lO{?p07j~IT9swmXLOd0^ej?PZS8aa74c-aE7`kAVoi}^dXv6EW6 zw>G*WSRJs61MBBpg#@y!@HJCVZ2nN&V70x_1@6%q4WYhIhakj^riluhO~WzbTKQ52 ziQRyfQzXO4wIr8}BTGKtvL>4_Wr5Y{alKC-RJ|?%Q7dav{qGAsk%i;ebIIZ6GbRMSu>G3b|alCqPif&m~h22 z0F3ov8CzZjw2E=5@<{|^=~{_7C1DyUn_NSc&YT$*>yHS=t^^`UInq9x2npNT@h}V{ z7~g;w?e|bEpZw}3gwqdZ)JLZ9E|n+*FXw!u8(TiPx@?;;R#m-M^z0rCnO5h zimt-fm324iI>vco91o%a>upsKb>J?`$VlLgl>I~Pw$oLCM8~6Xm)<%JNPV`gKWMtU z)F!AkJ-0PK+XjdSzV$xn#h`CL6LTM+j4h~@tt6EYc_F4K;F*w9WUO(XUDGG+DcM9$ zTiXIZWKs4p(a>x?yV;Eyn8FbGt>&@cRZ-3g-RCnzDGqgzf@xhvdtanc1e{Iq#bM%h zlSx8SoCpjIi@h?jzT)G6LoS5%0P!aN?g~4>b!amUjUnFIQl2$Wvs*0VztlU^l`F|G z+vo8yiV#P|I2{uiG#1<-i&Dx*vS+8G)*7m`urE4NscA=a$Wqo56PUCO^i|ky)KdE~ zdTR9jEy`;kMxuUNUx1FHGhCmjf|++#?T)DJ453vxd_)J~FvC=Z-r^f^>G&qF+~>6C z+SIwi5fSZ(IZ?ZsSwx8j5d%W?0X+06Aq-hwf(0?8`h}DW`O`>ZNvmO2o=E{&QY_<2 zk_r`tqY)0WTfHkaIaB(J{j2CoP$?#*71Rgu7{{M#it>ngFi`h{&=j?8F#xR3Vx8a( zvy!?UjH0>3p@wK}GPC<5IBsZnjT}5UF%-=#R6}Z>wlZ)$Hsk1QWleZl6FS^9-!a#- ze<<~1hZK8$@2}f3IMC4h1>_UGH6cCmP^Nv69MqW1DD=xGRP=#1=O|4o574MHXJ9JK zr2w*AB+nY~AUfv>HB_0-Qttst{&{TMBN{}pG0b62vEt&*+P*~EA zWp|%5wKpjTvaLea?KZKrxl?^|AsegWFzV2$Le5miqBFhOt3McPMZnj4z_Lkd=})g# z2U0&bm&${b@`+Ft$B+|~FM$DQZ30Rn1co>c^&$8n(%u$iSGP-8dQ07$d#r>~7&${c zOb-I46%Xez zoZ0^hgjVaa%$!#obxX!HS@A%!t)jUYO!vy$spv5wAa zypRjPvLK%=z$TEQ3rd8Em1X@j%rj9R9A}XzFAXZhZxM=((9+=^g@$T)h^k{Fdhj@g z5el~f^2fenqj3lz7@Yq2_NNQ&ei4>3&D4_0Zs#@!WLFO9Sfft+fHlUX12GJ-vQqN? zR7l721UIvo6HqdvUukPH1!P4qg3JwhKeh_P(CwVcHfaP@=0Xvyr;1t1uH|^7ml2A- zc6V22bltMrqF@=`l*E`5fv80%oL4)ynwL_*obPZ4EKEcwd!W*0I@Y1<>k>=EMC7Rz zH0yQPoOLD$Mtt&rq~ByXCpT|01!)V25!-!_STpd#5RCp4Oi*xRqP=wXjU9`sr}MXe z>|>R?IhwbLO7aK#ooKh3L;V$=AVse2h4k9a(`$iX^PTu}((6I@iC_x^+j5<4AT;W9 zh7}u`DR`}tBF5+fV+sQyOQN~mF>D+TVseq#KfMT#P%sZ7mol7 zy>4F0n1duNLMV}g6(ce`y$MAFP7=U4N@Sde{5cS1iwC2NVoPb&%$h8gE(KyRlhR=B z=fgc5t4@byBclyD!EKsO@o(9lIiX-k2;&qcGMrdwjmGTt<<2fthB)r9 ziT>pU=Cx8hQ--KAmpaqAvbH)jjeRy*W1OVT*JU&e@z#VH2ii|5n=@$9`xOo-6St>S zwv-cdiOTXQ%OB6re|&#(eR=ZZ>G_$-ua*CHae4lKPmZqoU^+Lsr*q#AFD~An9vxnt zo}XPGU7j4DoL!wBz8~}}(WoJ0e|Z5#A@k*qONLdI0OnzEYXYH}i$V@>%xxb9-!)~rgjpuFSSkQUaCge8G&b7It$l+Xtdgv|i7leYg>ca<^v|kn! z@9ErRqBQT7wjfV3*jRpnr1F@4QMjK~A=12@!Vm!)kfJx=a+ae)tr#DbnT|AGXBYxb z{spHIpinvTCNLI^*E5VTROczI<@d4Z1yNA~NlK;bRwXK(3KGX0Ajs5l8ez)W?i#x? zpQUSNkgTnmtx7Xn8QC(p`4~H4gRY@og(UsONc<_3@>9hVm~Q-z(4;*Qd0aJdJQxgC z<5ft>^EjHj{>DZjutgF?tzL51Ss^2u)CfU1jERQ!qP4bX}t~S&W7_Kb14@C=Bs?SC#8h)+-AYe z?_KLnVtv%!4d9a7zZ#wloRKpZse{2&hN77mf^uG%eOH^ySZMcdb0+ra7iX*7X8Bxk z0NN$Dz7b@*&ngzJZUl0b>mle)EE>b<$h_Wm_pNPK1MS^2Ci*XnM0QWWT0s{c(kW`t)RtrZB9h_d+to_1H$VUfgK-p%I=^c(8zp4+Mkd*C0 z1gNTEH)e*?y(+!57ssdPSm8DEt^92 zKg+<}$Yg1xL+QRTW^U-*vXkfIS`O>gMFDM24M%R>s)m zGz&?u5Y#qO{^fa zYT^_oiDYJK3q@AED8ei2f9|;w0Z{HGU?<+QM)lJGS5p8NDSswRFBhOzaovg009EJm z9JHk9ITt%XaPjd-4mX4x>LYN3!ZC7AXxaoOVvH1uiB_?wwk(RrIIc=xRU7D*x6(A6 z4vs_gNd~=%KHkLSR%SP90olEQDpjwY4)AaG9FG{64hL0w75)tg+vi8D3ky!G6PzI( znJMZR(v~hWv%Bi}&)V7#D>`I$ZO`1~LK-E?AkugH0I>w6PZ#S;Y;3-LHqXCyv|#b4+~h$I1LF{zfeFFqb=omo^Cb^Acbw0}^{(Rmz{ zuktC|Bo@YcX%VI&Ru0LCjD=1mx|1DJGiv5`wgV@A2wAAMoW!pz%&4W6EeFXu>_pum zV;VG#UD>;rGBQvcWXtR(WgTop?6UX*;+Eg5soT9&X_MqFyYxigi|G3@jkCR{c8F$e zDSowtpyoJeOu#6mQdGzY;cf9o?gcuDzP4LN;fqOOU%7O`Kwee$DM1t)Kf6@URaeBH zBvrH-BV?kT)wV{nHq8&vLPc4sz95}++F`^XJON|J!4f$K z<=dn8zCqC$;lkjo2zrwa|7&&Cbnh))5rnp=rF8P{NVSxarwZdipwD z7fY&#>Q$CPIK|+NV{QX&FCYrqJV@H$v)y{)5xX{izBf7mOY(E==6M6!Kll6p?h9ie z+tAXEiR+3|y{we=C8n`+(WOxL^=)SQSiTYOWd@Vm+wVR*4HcWX)=gaN zCf?-FcLK0wcK6J`hLLE_kpY+S5^pNBT2Z%UN2(846wYlBYSuy)?z635{YZ#lCPxuT zL-6jyAWKXj0RH&y!$6856$lO^>0wa;FWWYt+;~sjGnR#%mlmSrzgQi*AylS1%uWyg zcyuBAU`mUQg7!E_f}1JJ(6Oa%5flV0f4|YYrt;coPe^#DAVp(=1XEB2Ex845(EM7m z!V)BfDes25#pQ*gx!efE#GKv>|Kct%^BjvvC6oiYFWgT>2J%uSn--7!F(}^ zuVsYZ8_?eEGG`Qev0a;OU9(W#ZWo2@+rvz_3RP8Q`miLcWup?HI=QDbmyOP@M3|8b z0Rovo6|(U(bBq`jNrk}ZV``W)6pf6GIU+GjRp5k7lERtoh%0VUjd0VKx`wI|x$h^_ zpk`3tqG)P~%(-Y6fKy4o_C&6X0*O<3j5_P>N0TyE3Pcqrfk!gYFc;%AoooRxfwi_o zc0uK?t2jxtCRj4Q3VKp)zdf`yR<-lD4Die^rA&Mz~wm7HIKt>V1==mR-V0hdp@{2JN$6+(yxfo7^P9r+c z<2tfMx$c}T2@TeQ<2I-%n;A}AjZH9mYU~&tPwo(A8i&YiI{S{7$n}5g+qShd(d%CV z63)Q5l})xBghdKg-`Q#&svqthfy={rD$$U)hsKU73$^!g|lAeT&8q3RXZO>@vKoj z@1%S>>ZhYbIy$IWL3yMt&_eSdl=63-J96K4E;4g&c-f>~s+gbE7~US1lm^Rq^LF+Q_IrDO7;DZV#7&l{ z=C6Y5%Mx+}(;RZtxkWyx1Hf4-JLeuhxvfc38T@mL*~B>{Sto|{i442$R2D8cBr~*8 zdlRfVGb*@OZdBm>&eETPs*D~$-c;yj6fIpG@*?i+y!3i{lP9*fotW`xD8}A1*)*T) zLkZBF>XxqYZA%#{AYcw)42aG=2&CgwceR-3G|MP(YVj0u_*xq%egmd4p4+K6iEnv~L@!i#LWu779OIb-MY}*TGzK;q2KFh9V(3cP=i(KUuJ7CczJKEP$ci#x9SxN!NDT$185vf!M z3al2NzAzf~VPL87Zrf9W(s9ZOXuE-~?R;3XqXk4n-y>(ji@^(d3dLsGefN4`5`(Gr z_tLQ_WDexhT+(wx8%rX6jj%7o9Lf!4J(o^EzKoVo=Ob*)e9N3ykZ&%CK3{3tcM#kM zZ5yrJ&OT+al{!|&ASD;!SPFWyUB6$1@*3ikmq#Z*d~EXa$mFfa8PPymMwjwB@V-4? zYmZd*4zhRttJnU{uD{#a-D&AywhYecMZfXkqZH>-6MloUN4Xx9M48Dn&phd+@&bmv zkm4Dlp570m%5T#O*a8-$7pYX48i4~LL{k!*bP8%~(L~Z{XhvDC0|^*PpwO(N`L^*{ zZB?bv%Sg{-cr3`R8sL_0*y9uA)fKYc{fE*2bZ^wXe`=6fGXBgkQ@5=f%SQrN2@Ulw ziek-piX%w#nMDuBD!;J0Qbb8J167(@Y#s-IPY6Rf$VF>Pf2&}b&GXz#OqgNjliu(8 z+R3#zi~XN5>48akpz`cy$vLug?WHsxGAHj-7KBRVRRq2ANcxtxD)SxODeb;Ym7nF; z&ob)wc3#_z`o*mKODd_fPsT0d1|sU5Bho2gZ(tpqf(yOWo-^?F!{L# zAeg0wF;n-1OO#HgFc{=70jaj-6hAInayp}x?13*s`E@D9DDu}n*kr#I_vKXko*KA1 zY>VI2Cd_)Vz^h@VN~!j8ci@Heo6B?hc1DwIMnxI5k!M~qng68SK|FB8R)xf}6$}am zpN|mF8kg^H)LUU8YREH4I}sjs^p|!cmrR-UXDGR+gC<}Y)Bvq^)D*4j`g?4hOIzb* zZQae#bIkF261FYMD=@w#87CxM=+dZ5RgoJ(^?a`(T?ME}SW%g>;!gBx;xN`ksRmp{ zRswm4U)@P3CoioTjH7uqxnrp6mZ8NuSMDMjb4iVPuW!b|@rbmv_LmoyC2?66m_=b{ z?wkP?chwZ-X7jprSu5ncEJ<0>^di6CzlZ&<>tn56_uNux;DXO(f6O8#3)z0%6s~?v z*5W^2_SC0rzl*Z{X2epT?$@u*_xnUDe|%EO<<^l`#F^XPq&XvA9n^}V0gA!8`myXJ?kOSg@KeVqX>?R+3$sx zv6UUbHExxFL^2JG^jax*xlHFrQn^bZLpE%PibkPz@sAMXia%?QolO%M%B|5~Y;4Hq zufIr*<2ML6X>B=9tw^!v+o5ezR%rG zY@`vYVg)9<2v&QsHh+|op@QeT+XP{%&d6XUBVvwZAd|T;HVZ>Crlviaqtl<6Ui$fM z;FximYMwx1Fd?^Yo1&sTz@z%5x5`E&jYAn9Wo?nFJ9sRHJe^pH&tQByY|K4q3Yd=5DNXxA4+l4xoW*%CxcL4=0Xf&emecU zAzV1|ozFU{?@-Z3L>{c~>TEI>?Y42AGB<&uz6Po9tT^r9(Hpw1m2@ij_Do23u5}A% zF|dHb1X&iU)h<<`4|cm2OIJ$mD2D3m`l@yLw=UQRJykjD;$<2kmK~T_@3MTLg}HcX z+9Jp5OnqL=iScIF(&(5~fxp8DQT{qj|lC9 z{i*vZ%4JyIGPs^0D)TK#Q zWNd3RCTCltDZ>T}$=f_l1h4?+^tKAldSvdEc6n^MQZgSV>VZADfnPAIXY_ zX}#jLT)VG=xy*K0zRYZUix}<#td`eJWj~i%9m}kZDyWOCi#6*hD_9Y0(hD0~3u|ew ziB-_Np?j>8TnxyjX15p*(i{~sBNd`|w2#a2AscEr7fiCDHj9xY8)`NmZ?eut??L5@ zl%*#N%Y7b|h2_LKuM?MX8bwVosf6Rhqx?RET@3DBPUdx;tpcBqCVdhQ57hFLcvwTD z_gF>Cy@E^GSryoPkoS`Sa-PQ|fbKy!?&-|?n1xFu(xOeFW+tINWcqme*sA{J^xY(_ zTk~#XQzL#w*MLsDAY&U2!?4~xc_%q6ZSRXTiqyH)^&0jhK{1=)Q3DRO5>679Jn=l| zxg*bu8@UHp*ss0^zvB@*Rn7EXgMNCljA8V6Ea;eiz?hE{B{q#*VoW~-&Qa-tWe6n5@ zI6!oRk`Vro#^EYz*S#bmqI{w6Zmq4|p!wz+%ThRf3kUAE^UMB@wu&FpZj}z3!UYWL z^|3W^3Ec^>c0w=NguWA2oV=!MHo2en=-1fZqmljUMyHdg+9ED><JKdUR&^LQ7}oO5 zDqHm7#$~TS+0fo5{%upcsA{Q6FV>%H9~Gv2a*QH0hJV_vj}UVB#A{0pKJnToUi%;| z{b_k^h-RB&Fd>><62h;@4XWRUD7Af`X?+#SyLn`#m ze1+q1?tPwX1w4Tp)87-kFqX5}?Bh{i7DY*`E3E&316%D7O@lG%zBU-uG9N#<^Qgk6 zu|l@S10NDLIS^rbZyHo-J5WqZloTyP?~)YOAzyKKT5 zioIEZOd7KaTcZifFwc5YT|SPb%Md>!Av%4~emuacSsJ8R>h6PXQ$8J0SYvyS=7<80 z#}qAan62GG&G8HkmV^tI8o!r3cydy&36aVR0r_Mzw<1gkTj1}gX=#ZZ#~e)?itv>b z1aJo>0hmEHE)7=U3hvWDOiI{Eqsgu8&XS4F_2!$1Q_bm?pD3_3*1_nb4Q5>wvv;N7 zY(j*sGOT56;2sj}nBEaUz2c9dR%+0f20$m31NJ|VUu%`D{M?86b(2@1`$HZvSs~9&tZOxG{sNC`$1cN5~*uw z^d5Zkp-v%_bU~K7CqGeL$v>Z;sF6?OcV}I%WbZy??&?h+ww6orTW_dsU@K{1iM#on zo>7M`mb2ln_x{$s}ji(FgAIpXG_h1|x z(J7AQGX9am09`cN61m$J-BaSX$3Ct!2_Z)Vok(zDgw~yQQJ*d|Tw@>Cl;giu{mado zmEuwZi$&h@j9JpVAg_eDAmMo&H3(8!NumB7rMmjvoYdEz?S-D1yGe%CoaT38JuCZK z?`X&=lYFTMYYhx!q0g(?lV^(d~A-2YY++-)^^C{I|Qm*ZZ!wchEc7>mD5RcE9WP zUhVI_`VMs0JJjkYWgOD)y7z9YIJn=*)4H0#_y){L3Pywix!)K?I39zykWKIrp$U*O z{eQJuXXF;}3FNZ$1kMl$Q4*0k3RRJ9`GHMH8igPth~X54;PYqTU#ge>8Jr^U^{WrA2#64*F_;pH034E(%f9K_+kn$~ztsZZ8JM7G z3K)kxWmT}UGGoNS6vlXj7_Th(*!fw5^?yAFyo$ zp4R^+p3k2<-?xrPGN*Vv;owE^GF$lD;4}{W*5Km!pPtU-irncm({9FiH`# zAJ1oqQXC>%rnbNrg%W`b@h6@R($NTi0&OpA07Wc=^h|cX|Hk6mKN4e7?8h`y*#|tz z@SvdNd6(^L?(NDQOel`|2(Mlj=W;omvxbEXx>A($b`Fp0&K%Bj_K zqDsjizS`-PW!klaadEBw{;1pf0w_u%7$DI8?>1;(w^tga8qLY4M08*DRgQ&>vVPb0 zI8Tg?sbcls9g%60awO>W}6YM4QMNDPIdZW{3kHwA}(P2yFrI z0{sWPFntdg_H`Sgzhofon3tfyubq$RYX{lGCB_C7ctB8<_af6o%gq)T-V2h`wRBP?XhAE$b(BzQ5Gwu&_nWz`x zJYRAdu5%f#7YsYY^}VL-rFGQ2hzXaV7DJK(t1YnpJD6+T_mx*vX(<_-sfJnk4c1)7 zwFLLcLs&G03(?UG8!2vrfpm%FP8SO9balC1SLGoXu0X>Se!|mq3gUD+L{w;9X_k8p zn7l~RTOx{IlrOmSTUWv$(aIMCoPZZ`XXmBY1Gf`I5r_q%rCw*-m?H5PGfJMOOr5>Z zZykmqfYP49Fam)vWkd%|Z{GB_HE7I@1IFlnoPe&-eQ!}zujnS>&@W_}b1emdW*qb4 zqMtzD^x!4v=?b6=TtmRIhq7A5G=GJ*4WzqPEZ86+o`DxE9fB9~uW1@J7)|#j*m((h z;;#ml#{el`(hO28JMw%=LiAi9-u6l8dsM0hlBSvC@pF%D|y zOh8k!1VCf%ql)4Y5E7xR_Z2U8e_38$kLAvDoKjRdW>s+A>HRo%+5$?a@s^pwgql^>ro9>Y<4Sv7|o zbX_rzPMvxl1HM>*y9Izt+KfZ60BdQYF)@V+kQXj6CE+mxn8nYz^v=z+?|v%qXWR@D zX9`t9+yp7(WNPs$x88jK4#NFiKngMG z3w*)SV4^&2DwVq061aLlcv;KzOcY0+nMtJ~MrIDgntiF1-g@d+!+Ke@jP<9NW+KGn zNheHSW5e0TR4+cjq@UZ{RHZ+EF0tjzW$1&iUp)&in^`q13ga;<(vO>Fx~g{q)e52~ z>68sT~SsH=2D4N#tB{7V=IMJfJEK**&?iYEJYa9F<{N*n|NLKFz zgEsr3zkIP}{?FGh-6b2?85j=9e!iWwQ>M@zal)xfJ5kh#u8ua8P~ORDD!*U#!57246#?krctpw*KA z%5I*pCL+sgvtl^4+y%w6T4lA2flL~FJpAeX)%Eeo$Lq`U^Q-Ht^LHm_*QdvYuq??x zsziV=o!m>8mN)bMbZ~WYCQ0dJFsN>){d2$n@BZtZZnxbCkGB&n)Wi&%M*eC?#}Fws zSMCL?%_wuaqE$k%VRzy=X0xU8m3WLju z{rg%7U==GtJQP70#oY&DeilzbB5<5(-EH0TtQ|4EoqSu3HF9;fps8A}OJ}-yZ|9pU z=b(XtUOo5KTJc|E;V*fchl+mSnS#g}&LuFj5V&a*+bDQKzF15?DI=u2iA zR`6XpmNRC0H<6I&b{)1wU z&f_32Ol(Fvw-N1xX9a^;HL*;rF#KDElcLPNa&?>wLfyLV`#MX!37iT?i7PIgPTpUW zsVADePE$cOvcSg3CO58cLpQlDG$ovTrF&3LBS1??XSsqd-8iEWjxnE0S587gAfw-; z!6T&$P2*VbARL2?g-Pc4_E7on>s>1vbQ2C=9KY$69hrI4cc>IR;|b`$0eqgI^YUbr zV7N<3R5izF%1Gr&NlUTdTw;H%qwb1rxVr%k)JpZo0(QX`;WeC8mXBVmpWO1C*}cS? zX)EnH-fNB)K)Ks2l>x48p30!tHdD2Sm+!s!>W@XQz8dR$X$N0hr1^Sn(8|3Qa6SBW zuju-g?m;+pYrMX(RTh0yaw)Be2d0fx+PNp=*Z_SrXlsqE#bkJR0MYKIkGKmzv9(<) zu`gXqYzfP#0JNM4K7X#}4;iqm5}d0Wm?mY#e!fuAM69HNde!0zr&(*FV4sY>b`BfEUQ7?bzSD5t#e`K z0Iz*zE}8BHi*vz5mMC={v$h1--52QkXRaFb+UL#*u~KPx0MmJR7EGHdvTVvsIn^`s ztKVugMfu8$r>1UNEDU!__Ht8FoQ_3PVZph;s$KVsr$7auiB;k_muj60uK%eL;l{kq z3Obf*_OhR&x5XZXDp2=xDmW1Rg}UD=4h08jGj+1r%-H3zbc!;IdFd=w6}|I3Ee3X9 z$HH3YsuJvj%$7MN(`?4fv6K~NuA++SYH9YGFt|Ek%V)24=Bi-&Wp-6HdkYy~1=u>E zjb^Wq>(U-o$t}DH%_j*pTSZU$BUo;xY9aY2>71su?qGY*JTy>#_Q8P zB#}RcK@t?R2_EqV2&QR#$j(T7NeD0O=F3k%Qj#XQ?E~BUF%F&Gl3usl&25p0+CMQw zt1G9)%5L4!U7Ecg+1s$7)rmjL*Sg{ouoZIzQ#)06To2jEa?Lbb87r-htR+7eV^P&` zd7-SjShCiZwsrS)vvfjW6p`Btif1@NV|2m-7)dtW2O}62f-?e`z#)z>$EdJL2tY_l zQhW!12M*uAzbkE=@nRfvk_Nz8=FNJwoD{E7tmo@b0 zMS&j2T?B!yy0REp(&W7t%FG-l&_SYiSt`o}!YUwEU`6*@K5Lf}E48^sd9hNvk6Uuo z5px4OOy{Cl$sRNL8S2flg+AT};O=d*)xx~L~psmJ{rSyI_**P@YB_S~qSzao?glDJAH(g{#1-fMr+uh9`RFL$5h3!DQWksHaB zRI0MAjBr^b6Z^s0mxmMJs(Qbd99MPvx9n;n#Py1&Zr(nuJ#CSa_4RTbxM{bs;V)*R zB4E5cfOQC80Rq-P!RQ-JVP)kBc(iDxZDr0=L_I4|Dq3r zU)^YcSPBUF4ys_G_=X?6@zsr8cK)q8!2IgQi(_8`MF2!!-N11>*TuY9q7c@Nt??+;%2aRvDj|s(UrkA86S=IQoXfw|7`In7Z;r+bz1$sR7dpDvwJ^B`i`n^#)EPrc z7o`&_WKF8fB)KqMlLx96E36mXZoQcElEJnrb5k*kN}>BT^T%3~z7{2Wun^pcx2fF1 zJ2E!a^S=-1uh?Vr+pxUjyI+vyeLoySGftV5tDLZTb#+r+MT5H@Uu{=+KDVkK?|ooZ zoj%k_LFxTf&Iw*z{gg_t-}Q`YI=b@-mHWH*`INhSsMEYn`b4{yOITVrKs#q6@Ipy5)lY3(rx0?P z3s&$sz27RG7H!!=%P%%rYDMeMu-HKIrR&VS(`1SHh7Yznjl_;FPM=G1IM)419-)Sv;mw~?l>y%OOj&kxtNWxZZMVc9V$~yE(DVI{c4fztI~?(fz9tWT)C;^S7Ef@Q zL&b`%S1``s_1sHiJnZQ&^OSf1AXw}au@WpiOaP&tW+K8B;s-0<%r>A=_~62xmK`N2 zM!{6|_8_52RUJP>U{Xd=lT_UBkgX7ZVdt_MIW4@I&9ox=V)-#u_O!||mG4}!yBg=d zh6l7X;Ns2))W`~^r?avR%wNL;+PYTh?r!MvlUTWybbK$4=oAp5Im|-ZPf0i?q8y2I zN)@?g^8?6oZ^(tKxS@7AEbU)`=_tJ}?z1n9~yGoj4(XL&`Q@CI*ci=f289bS_tH`~r!N>dU2R2`{o28v4 z7r}&0v5w4y(MU~5Fk!(pXty9=u6`d<>}(cAxZ{$HS!}8hB(o^8z(7W+m=ea-grx+r4G}4s(uA0d*{#Fu6PeB= zBp}px|0B%Uq#)D~|6HHM^D50rVJ_KbKrjX*D* zdujB@)$?>|AF-dcSAvG$(ul?ZOHJZO^UE6%GAPP#T^}p^GsvfMD1ROGpnyjndGpAp z<9D9+`oDLMiCKKIi_Xsa_V)_) zzx%tr-KYBBkMTTY{qJ%KGQW&(r-=F1y`MMAwR%y9yeKuU?vEzi)LcFwH@((1kHZ6U zWNX*7{6wWISLBhrZDr&f;F~^VLIXoS{c6_mwYmKCibY0hny_fvkrTXJ(5m2@X=+S& zEMG^Hq;u`co_Dy|auYAKteJC7FFck?qoeZ7>qnl_n2uT4zMAJ-Sx2Maerws?%}O~O zm;wywn)LUaEM4XhOZDV@@q5jbby*|dkTowtY(d+#+;~NKzSv=5M=e9E_w-VTjlZ-RqzNSmc?njn_vnq^@9tp)!JXfR>q@8(m)rP7QpS)0ZDI=gTQ@Y_ zN@uab;&_Rq2(GiSR3txyhAIChivi5hna_=uo}Nc~R;2%?5NRqR){OT5x8?M|*WKAE z(*It+|3v>E(Yf9Sa+DEx1jlm`vHO#F54H=m`*%i) z(^;eij5eVOhp1{;Mw_f@+@DKl-Yyh0ms?6)v$#db4NI@gD;Qq#L>2zfPjmc##p962 z;|6448U7#a^a}WYu)VYWg#RDo`Q79HZxI|HlnfXU|D96<5iw&)u=HTT-nIxSlhy|y zsB#7ow?LL~fQy{v?T%xtD2hMPu4T`P_}@AGH0S=8;s4(D_FlJu|9d;zgD3p|7|$1o z|7nuQ4Amc7Z>D==_&cfZerHJE)3eq1gn_C06|B(n>Rswe<~Q>lB-#ZJ372*uJD3Ho zxuEp4<()7^@`abkn1IPMmm4bIS-y!aY~HHSHZE*8r61qL^oH^XlwzibR74Sv$M4`> z>$sGEb@i!L50O**$y`>7DOJJbl?RCr1&eoqMthiMYK7`wQErwC=UKe2izj-wi&J+8 z5)sxw{}NBHYS`b;b&!XDLMrY+$&=2h{QUxF3$9M3YjmgN9haMa$^|sBRl>5jOFxx> zc|qfXzM7D{Kh>MNp=WmvrG3jeih4_S9<3hudHxNJu0`eUd%+SNQUI8h56bgxE_4FE z9|t+xhVBZ!?xZXck}HwU$#1_MRKB9eeYB2e)i8$Yl8aQR{THIb`N-9qq`~8a~<@5ZHq9=y~Y5a&zevUoY+l zkGbMBI%W}_U$8*Lp&5OApE5C1t4%Eb zGATq#(vW{C2cDnIgPeGw%X=Srp}+f`d7-m=9(tj-`cr=Zq_`3b3mq=!C2`ypI7n=PgS!**nDOUsCbIlqRC zTCr7Qc1>UQ(&C&zafYa%-|eo>;k|nM-G^5vKc2i=&MRdrh{X66yJ1m@ODgyM^6mNS z!^?)9zr>K3eD4c$D=$c8P8ufd*H`;(9L;rCFL}h|Tq-uL=+w(|-s^VDKN%}aubcaE zITKd!GV~vx=UEE28Yy1k%e8OV#a1lu;rXxz3|CWjYlYiW`U*R%&=pj3!4n~InRyBZ z3$IoD*{O5(>35&(e~Uf%q*Cwzl${9*RJ2 zrEJ7f76)vLg2>p`&=|wNf7{aFx%CWQ(R8}4MBDB49Zv$+vG((4ATSN^e{;t_^DOoM z>y`Y!yE{+*-;eVAe)0ci6X1_d9=9#Q*tlfrcbt8UF7NO89?g@5%rB zQJyal|2r&Sz#>one|Pu)E2KMWr-FO53@biQtLQ)I3e_f5?(Z z%%`lW0bnuy?{~Z1?V|pFZ|@2JKg#pP;s0mk*nyeLDeUh1f;<7P)dLWKKZh;{eMYB= zh*_)-h+*QtuuB zU%A|zhi&;t8wJN#wz^|diC3}2${VXi{kWMgF6T7uhPRx5&LUR5#`##9jHlI&@S#oEL1T(S0pT!6F&07 zTqi=RH%#4%^tyWW-U|!Xy(ndXDXUn%hIK2f4_&H=#&WHe1Y;H6TOk%}!6>;{thM5u zUVdivxeIE;j1Ip$d2{*U^v!>q99@2Rb$W4m@}@c($g3@L@Gm!O74R%lMe3r3^TR9- zYO2~F7t-`A3E2peRj=`QBx=Kxa|14pmj6tV>Qz|fZeuTO{>O`xUwp{#F2Db9c6j;y z>aeBd>ock*4MsVAefZr;gM$G?e7Yhg@m?;YlX{8-hRv$lLyMMk`Rd}s(aHJchnJ_X z>J|i{Y=$w}f>E}rrj6t4f6eICv4^GMe>nNegN=U8=9PojXA-HI)Zx3!x3v(|P`NT1 zuRi97@84crUOdpq@+R24OQYHw{II=gd~oO6zASjPhKQKZRga2j20f%{xEdunKl$

`epWT$f$-dUk8Uj4w{~e@E}m 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

1?ueaQIV?Na`)L4WV5{>P&{ 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�*r}*F9oxSIO+kNqB_tlG?SFd)T|7~aQ#p{>P{|0u}F#rkU zkp69F>9&gC?n$zo743Hb@F7PdLZ|!SB*)u302ns5ui39)V;vY{&3yO4^jYUmvVCv>PVs<3I#tq+x~mkNLPqvi*O^jK3dsojshUi0Kfv7A0C1UmF)UcS zy0VbGb1(&%GZYTJ&X`QlJ}`TkwT*SKFFI86Wji1@QAl9GwnH)^%zW!jAieV9Xw~5tcg13mlUVDeGn>Abgl~&`_fbLF|9Ez!~ZP{tlBo_@c*5?SFZ~E|K;A^ z?j!$SM|uJ>89c{^o`8$9qyOq@;j4Ed@70GG(S2}mc5wKE6l0|{pFgjQU(~Z{Te3Yo z**-kd-U?t8fS3{=F@~5Y^8Y8h!m%;llQAVbPo8w_zYU*L=hsIT)mmC+{hOVRZGXy? zG#-zO+@OB_@9w>PxszZ2&v$m7zj$2#>qvk6vHh%5!2(%0T5))yf-cwy zu+KsF3QfD9``!EZUC>nVYdX z-3NdC0pz2fKmW9hbBT7MC8ToeX9aUVXT>W}QRzU!(=Xq1HHmga6W|v7mJp7LUqx{g z1?J})Bxc1v*zK4Py;(ZSTe)TEC@NSj9aRgWh}o3f$tY^L(EbcB5uKzj7VZ%(YpAyb z;ZmB3#oh&7wOUp}K}9@;2@e7K4X8+Ox=oE-es$v-o>d_V8OqnH=1Y@WRf$}!dc14K zo|Bk_WHkL3YB2Oxp^O0bZ*r8Khc{PL^%vMbg4@i5D1T=)CQQE7>CS^G8NGEmvt784 zamOB$puqNhGKooqBA!k;9jQQizv}|;M|DVvNuXUvc4eT|w_@=YGZnv-4XiGImcfxs zp-@Tjv*@V26zzhqoJnJ$H6#30iWls^$q3U0UiKl&YmJ1RT@KwQ@N(bNQZs{4QgS9w zzVr-wy9&VxOcgU37vF00H5o=K?Y0c}&baF&>-xT2tQ*Bir@SY66MLF$06ph&Gb}&M z8J#_2yRf+lZb5{VnfLBao=t0p77-3M&?M$li^QA7tRSX1;zQ7daa=ItOAGCTuVtsw z=`horwZ9klnXj(UbPIeXxwatM>|`kR=qt6s$<0oeE8UJ}8n#xJEW8ZIvvX|D$}TyC zmG(?6rh&?uZ62aqX{QCJjY2!0r6i_UhWSYCe2k5FfEi7sSZE zG>i4~y|lg@?tTLC1ZsV0b0`{){E~T+Hht8)Y`jreE2hHSO z=iC|y8PRR1OxE^>CxB=|BIdmIvi#0NwEJT1Qwqj0Yj>DZX9lk0loj|(4HV;$qhS)d z&nUaZI)_R_{}O|wU&lKRkjY&!IA)L5*=jynHKe&5vY7MDmzl8T4gX{5hRb%HRyM20 zQCs&GfBx;kVHP6VaaGX)^c(P-<;5b^V8X|QYG2rmhOn-9dqa76e&jlUJ`Ea--||xr z#yFeyjfSqGWP77_aCV}@tU8VzjIk-;K7>1M451Eg(R}_@mThkse-KlfL|l3q3BWC=N4{{96ute zLNF~vjO#~YG$959oF;PLKFj z7M;K}L<&Vk#d_SZ|MSfv6K`Sgb2pLFA#vSMN{3;E>#uBYVTfK!cT%Dc*#-f_cI3y&dI)Ag|#U z)#wr2(jg4fuq*kv3Ee;b{Id%{`gGSbj&Ve{Ftgj1(Tpe>q0jQJTe`A9FaTsIFQ|vr zeE@&{2?ofA2}7!89F5W^|5r%8?=^XG1pec>_gozFq|+wpM4^i#j_45jNRG&mBvH^+ z4pO|%vuBqwLLfyGaxLSYA`@GX!;p-gGU;w~l0;?Hc=pUud!<9JS$)l|KWk*Ve{5WT z-0A(}m(6D%|KFd#Jp1#{uex9(H$31LaB?9-Ljmhfe(pZ=W$*u5y8l&KLmcgpOPKHtUPAMfO2i0%-hFpx!5*51xeH{0@Ndbqo)9_}{i;cnW)nXc%itzGz} z)w9{2*sxNwpAw494#8&LEL2RXbMtyQ4O=cfa_KNM#nwO%Xx7^Urlbc>MF+^x%B^Gf zF&%-H$~}HdFnb-gMNU1;O^op|B{ybM673qBwjMZ4|CP0OrXvby|96$U(7YkdPASEq zk`|=D5*$fW*V$394W(cdl$1B8Z|_{kq&s0Bv@58dWqIReF$#W+OQDAL}qDY8R| ztB~`yclZgMiU|-Q6evN6kI~fpdZpb$%>`5)2}C^6!ucO=={b5*a8s0E)>!xo4IVW6Y^I1YVX}k^SOJUT9W@%H0H(R zzt^v4<-gt6kMIB2lGZN&S(+9V+f=(-lu_SG#1B2Q4Y{qU9exMk+Vx zD(k&&(I8L?7*%_7zP(gxGl9irEY$rsz)O4JnNN0R6BVK~dm2wYEx?cvZaATGtKGNS z<%mvjq;`jVJsghgBd4uPFE@PDwv4I<(`RF^J`3_qMTuUOm7?`;(OlNk0FMykc6Thm zZ$S4y3ww=?`AtbhC8!IH=aI~AN!_p6_Sa1OU$>CANIR>ixqi(kp=Mi9)i2xURffv^}AR?vU_4oiz~yPC)(|Ty#VYn>ZQ*-bQM=P3Qid4 zPGFq91;}#b`tSz8SjHjC{ptw@Sg1HRxti2ftS5VgV$Z7lU%5v`dQ5XOTYrh~_c)ZX zuhN0QL$G1LOtLE8l+&>|EA|T`mFvnaNFw~3d6lJH_etj+h3@2f(;gQ<*Dy>}G;*y? z5l0>)ztt@D8UE1vf-fBW=PdG){>)$M`l~s-i+$AmJ4bJmqxu1Xrfg}xwXlhqdlnvt zT0x|SCa)Um>h)xevblZVY-y1-?~zk)nk>~X&9fefa~Pr1!?;g;9MTdl9; zhf6qeIZSLnQ&(WIauQ$SSN5%p3_Zb7z_!)Ru!XrWz4R;1Z z|Had2;$Z$ni^ksNO#`GW%c=G?d zX;JU3j7E_Ci6i^ZGl{qUfB`%e3gaN1Z}sPg%JY9)`X6nAUaA0^qyKsF^7V}V=lSc` zkNTf=r1ii5{9Xs(1A=vm35p^iuBzaXOon2B9RL69eQkH!w({qDehMs|{%y4;W!Z^y z*Z1$<<0k2?w{7CJ-Q?WU>}eqql2B6w3sACko9t)bg8@K-&yp-ZWUuuiCnmwcU@#cW z{4fB9k-3vBitG)dCugU|QVVf-|D~gyE7)uta+#ZDz8tS zS*uYN&1@mc2hSU>1dI{6p#q$5UDCAO{#w?PeceBeQy;-2a20kK*S7}uvioaw5;8hX zvx^B+j$@JCEfeY+2UE1b(@5VnEV;;*yRcplL+bi`8mDATDob6jrQqy!u1kFfs(fvd zK8!KQLXEbxs7mK#^OKcvb#&a3RaCdRrZ%~hakNAJED*2ThS95*YTh%UDzJK9`6IR} zvCJup+G!8mucfzkmHW%`2a+kHKIW*)6OA<@(q zlfDLm8a^{HQT|=EUPz9L1B-l?4+frQ%_qt-hTd>d^O4>WnYCSIu$xk^ny`vzzbP0c z&4pD{bB1F1HMTSlJgQLVlyFEIu#nDty`pe#ovFT8bE09d;;7g6W9_MKg`Sjz3Vqn} ziRndDTc7DaTEqvG~!D2+G(^(2P zc!2{d-Opfxu+S%X_#z>JFZ5Z4_SuBe6%g~FSfIt46puA*Gbq++sby>8d>|-*GHCntvPe|CRF8yZ@d3|I58W+5g`gJe~h|FTZ=w|9o?k$Vos>Ik5)F zVPhZo9F5b8ZJfNkh&~Dtz6CR6=51N>-JEbvLn5sspTz+>Jb?ew>BVd`qBqF(nyxN+ z#fkJN)tWA_DS0+4e^|RL!$r=znoYYJpq;t`x&*m`-dDmcHbnj3cwnCpCrN|@g4}Oh zzO6*mc95qz16)zgaDAiKk^pHAssmLNiJUFeHb> z)XNK5VI`t53fOcAyU)yZ+uf5g(5ac3?RKlWY=Z|+Za+)o#)%A$MbJAA?d^cuA{WuJ z(??x9OWoZN;pJn>@3lpNnz-LvNffvA|2E|RtL?>W<^K#0UksjC@_!DW@_+8-ckljx zmj0tuMo*h9^QKX)!c=JzYA*Et_PS-qVi`H5f>n~XNR1~Kxzk1V-?jvw5-AV8DLm+B zd(Yn`>J%20BO|#naG#X|WcJy>bL$dyG^TSBo3H`^IRqDnWZs5#K#MG5>@16kk6;>5 zE6OxAhF@ien7#2kf6PRx!N*MaJ@{mZgR5)I!#n|tMl@acz`-{(9Y1}Vf3ch7puj&PvR=UI9!=KAh-6gIe;%Fgf_G^MBcrF_;Cmcs*i3(}??L(jM zI-9Aep%n+Fds-;uEM;C-jerWIkIVCqc66%WtvI!sb%3(g=e`x>byxC^dZp!`*!Hjt z&vk1!wXR=dQJc|R0;c)(u0q-BT#?06M(4`9foC0?qpribBCz$(eKIWfVOXxnqW(CL zw-(+c3mJO>pLP%LtNeysPhA0ZbgV9TE)3h6QB%C>sxoehU-Syu-c^dS#-DMLm^^)J zUx?)87|}Q+H*H@%%b0H7$k93242kZsmL1^2IN~Jbl+20LELabUIKklp1>nkuOO46= zxD>UjX{GiS4!bcSb8!qJSD#iAzAs)+RX#swP;;ivzS~1?MB;HeanWE8`jE*!gdDPB z1Yh`nYx1xj`W1~uUO{EIRZnhb$7Q4I3E^r{FOxA9NTf`vd)rtjQLY&b>iT+HP{@Px zbpBfr`?g4}Y?RC?A7;N{jZxY~#2+6?7fk#aWfFFM^npeZf_1(TfCIn7wNtp~R zkyuQJEE1;49i(&gqQ=cB^@jp+z%awvIRaB1jm!R3u8qN-#B8Xs^RDxWkXJdNNPaTH zGOeyt}1*-kzqJ~|zNo1ZeJ_Pa=2(L|k+BuvO1lWVC~Af56IB8%2)Qga5P8c?7rRFs9A zTLJ@9Dp8WK=ODE2qqFQdEz{IF#pSV?3s2hV+)4<;v=L9yM6~h`+YP`jWR?QkmdEy2 zq(~=Ne=sAv<#rQo8Zx2kg0+o4@XU-TfE+B7nLs@H2>?brld`{w^lIo^! z=d;ceDIE_$VmypUSUdp7jL~CztTpYWer7fgoLM8jd;(;>UK*#^h|e7U2x4>%8?MDs z-5tKUpewAvF>Y&}VOedJSM8hkH3uN7gC*-3vEr>w9c0x!D!IysXyP&ri9Y~4SHy2mL%0upY&;vzqw7L8On=*(u$>S`hbkd z&ACc9IEkX4XbLEs`|;xkOBQf!($U;S1QC|g0{iES`#|Mj+(k?V6xUS1P9K42s!zLB z-jSI{b)d6EY^*3vcBc)_tySAMMKg7P4L$loIgp}uazu3)HI>iEY^LZV}EWL+$MzS*gi?6zOTV8AA z0HcJHIb}0ZjYO~=(u!pUyDHf=*dJ{4uBhEz%57R((&NqQaMhXqVovg3@3*P-|CDh& zCTpGlG1z~(Us?Zuarm_Ue;>bxI{(!^f9XOg4}v}4wFXaXS0D@I8;`T&xdT$a8fO*A z50-4th$~fHz%20u+Av=iV|eywwXp84k_!YQ4T3n=e>{+xwT zZjQRRJ+z}YdMY^9{W? zCHzS`jkZ8`o*Z`YzokZo*(8r@cgZ&?@Syos@lfAo6d{eVVJ5b)je# zeqQOs(@aIOv1n8+-x!QO=}pK`Va-Vd@Vv4W_i?)`8=C*sve|n3KVR%s@Bi3)ivRBC zcklDRI?Rp6>V8T%N-1S%Owv5pLnEZk#!G3N27AXO)g!tc2Q!zR>8J3GXC5xOU#g*E zYZB%r>$jd~sPB@!iRbSzHwT)Kn}qQcNef~KeExj=Z0Bk=BtaU1a12ssZQE(x!(T$U ztYr>;D4)i*kjKy;g2mE`AG?16hU?1`>I}Hga-RN#hFFlp=g5OwA<9$XcQYD=h{SU= z$6TehsC-kbw&8VlWJxHh7fsJh7hZ<4cXv&Rl!XVw8_0=HA_`NBkpF=z;$--%8*F_6 z>us;FAm3L$g}KoyA3$EN!w$|HspaQ)H&Ev8>uv;YNoj-4vSQJ zR#!dP*>kOV5?S`7`fH^jRw10DzOpqsYsBh7-z}~W)GvL&Y?Zzn{vlsHE3MO)+>E@Y zN(!$<$E(SBNYpMoPUe)Tjd{{^a=q5XMrivhv8{1_L}O%Ju4nD34W)&R9kWD|GgH(M z>&0=~l0~+%F_-<9r}{k8?!Nc=Giq7eP|ICLhE_&aVZjSAu1o3_1sFn*0UV*2#hxy` zjLJ3V1eH>GugGFh)I&(%T~!kc^_3IAb@L%PE_=txoNz&Yln;-Nk^WPcDr%WswA{(- z0Bk87eN84h9ewaN_nI$vMf zQCFn@jFVlH7e8VgZZM)TN?73>&0R!pq@2uVPjhM!+7X1Ht-;?8ULN+kJ&Hgxe5tw3 z*9OXb;eUq(Ig?fd!mge@zh_~Jjz-v& zri!p@ACT-`(HQ1cEh0CMSUw>!!TT=`WtV*!(aY2Cw!aOBi$WBb_OkE`N!~E%&9IGnTg5ni-r` zmm{HOGa6Q< z4elpK31^`S#$^~sIg8cCS=gS}d;_tT4dKFELJYep;DA9-*W$@qJgcM)t3FLJ5B}SX z{kKwm`@aQP2poqTo5`RH{~PR=&VM-A9~?g6fA{jccl)n%s0n&y)FeL{Kff{_bFgjd zKK|Cs*P1NzTmdtJP2ixp_$5n&Hyb&Ne*JPebHyFTx}3_B%NuL1U*tq5%bASQjOz^V z5}xK()ob$e>$d6n+2+K&CUa~87Wub~OR@T9Pv4PhZ{r-ftZ*&Rp|t(ECWOr?Xp)tU z^#yu*^TbkwRM`@RaQKTL{EU+ky;+LP6v*TUX~kq5(hHgKuV;)VclD;QUf z!?W_H*jj=LbI`g5` zxOEN{b8=jZxq1Mz(aE+~Od-fvv^1u?i7Kb5##Z^91+&0W%0z1;xiq0ob-W(Ac~e&F zdt=?|JAL`iFm#sa1sfY~?h(_l7TFg-W@-5vHp$g3aokq!W|N5O@0Db3PX)$<$b1ET zEzqMMeRd-{`n){K>bkS|=KqsC`2W=39mIcA%qb3sITY9t|Gj*9P`dx;U~qWw6#w1J z@8ROVpQW0-{%+&ZpHaU@6Z@HlHb#E1m+*E`pQ+<+V!j%Yt`zZ^?=?9*ODAgweI;7; zAs^M7Ya6q##%=_*~J@UIY`OjNTLD8=>(NZ zjcNv!9vdL^8mD-OMfv+sKfW(O>4KPzJyj@4z3ZfOGD|0Ka$T|LWO~s6L&4)W&1$v^ zUSf065sTgd`lT=kn}tUSi)mB$9{`J~59~p9n_4qE-C!IXz*lT?iI=;_ zH{FO8`h8vOt%1sIu{TZjkz;R5BQ#AO^j#t}8;)}t+t3BmSOaPenC4C)(YBD}%k7%m zPwPY97*H#Ox_{GWQ0nwCdv0BMChxygw z&2eqb*x1k!GgU5%@QRj@)sZV{q1}sl?-g-`nkvfu(IV_s0fkoOT&f4|7G7v?*<%74 z)^ndj63~!jmx2<>n4A&yWpSF%wmGk=Y%@W8bHiQX5cVsw@Yu*R@7m_IhU<2H1V_nB z&W9x9HiTooX{@<6Q&`D}H%=<;EhxIvr68u^PQBVvRy~$_DoqK=%@SV~uD-9+y$8dZ zx@XYUkce)2)RzQ|?oXmwF7TS8Ps8Jl$Bws)RQT zRas43QDfEvty&1(61lQF>v6+Z2JEP~ge!JIgIjrrV8~{}gQZ(^C)Oh``b)MT+HFC= zSFR4t7QIFG7)vTHV?HZHg{x>(|&U|t8eT+YZtw`oiba60eJ)eKyh0bi3;V<83V4yB-+tF z1N!zD4W9Rw?ulBr;}-f~OV0wk?3u?H_2Trkvx3jnQ*)u);Csmm^gXa^&K+fL+uaX3 zYO3BIu~NM|2IE6VVGsAagZST`x&Q^}i2t9zJSfNi`!8NR?f<)%-^1m9>2O${l!v?d?h9vQu{XvRj_vk=qpOXUPoOMe_Fcw42;e+hDV`4YJynarv4& zJ$27@t!(O=P`&fI)D0-HCVSJ$dXVFCqVF+Jnejw`>v*h5(b)1(;GX2dZpS>>Yrs=- zx1teGsjpX{F^LJsDGB?_Z?n|b{&&@{is`m#WWP6%hbMe)}u2T{Uaj12ppjS*5SRcFcx zBSym+jY4UE6C7OOF%iDAg)S#lATdi4##4dBghUZ!tDq@Pg9(ktyNHtrr*y6-y!<(i zLuU)cWUTU=cND0g^GMPE==tbf94!!w;Y-O9N(e_0jfwC0uP=VPkkga1gY}$Nikp5C>PY1fmwo>yj6VCo1LF)K4B)G52arTGf&qcsO(*J_+gxie&^EW52 ze}3an!;U&S_J6&2Ie1wb|IZKhpW^>}`E8-^)Q$dTH2g$|T>2ZYWLG=R3HtR15>1Pb z|If}OO%rj{@5>p$7n6R-0?|)dLIcr{RMFqGvTVsRJwUFdB0h9tcv zB+eL7-}#QSwS_K!`upp1$NByD-=$CNgd`zxNaBDJ?RU#r@krBy8Crv&M`+)_@o!AN z3==eEd~t+WK#%%;PR3NEeBllJkOfzS`;_&Es(w|ytP<)CSS(mX9N7w#)xSWqL^_&T zF<=iT^u4KmK5(vR93CMVg46NOIB}*V#nSzioGZR-VjlTI_@h}Asbof2k~UvW7s|Im z?hho282Z3?6uOFutu1sKr<{c|SVwRiu+_?wNI09*kO+j0=nZy=f@ab)R!UJ(gPxfy&=kjbOt|kj#a=B`0EYk9A7?{?lSJgy zuJjW>B=f$~oRB0DTTG>QC%sKY9{yw_1Pb~}(WfyAqM1kumm2gFV^@;hl*t+qn{kAb zEO`n_Cz-_lfiC$1{i+}^bdr}tuW*VZHqJTJs^SN1+9z>JxHO}rw+n7v{s57X0s%J4 zw7Z6`QuQ-VAkY^yCBkt$Bn87`k`jRi{@{Op<9Mp22mZdl_l^2SMxaDC7XG|QNI-Ff zXq?PaB!UTW&eQE(wO%D71X=ua^p>S(oCp%9+ln8x(l2s`Fz0yTAVgE5@P~FzP52xw zkT6Wgiip(AjD1}X+R69$V3Ao0(eoWAB*U2{?x9)?tcXUn1r}cD2rbwQU9(vfqKIA* z`9=_e$W6*IqVb6FsTvMyMi6!hI2)pX5~wzym9Oxk;qk~kpw$kI!|opLhkrmDPjcMUDy7J`(cZnfNDs+dE>lU&ETN1z)0to=q zTM&R*)n+>TrjS9Dt1b8>9j&zSHOep@@5Ms18VJjyrV|5GJ%x)o+p@_1ONvipgEHY6_Swe#) zV>4-~KFHAdT4#77L1IB67>2P3r{37U42==ijPD}BrUa#QN`xeEjbj*;WBIl6U${y| zNSF|GNF$mqRJGvYObF$oEDh-cncm&XEqPzd3Z8qOSMRuLsjTm{A{5~viS!JGlVtf% zRTsWX@Sii1dB1sY{Ph>gwp19P_Y)c(J|}UIZPxt!*(o$SOrpHSzVB;*k;L<(Y}>L4 zD9%nUEc4Pn>q!D~<*6KX4a|sSewu?B|1>`aGhhVW}@7VndZeH>&E&S|C z^M(aEe2%=Z=hTT{u$Bl0wg?8B5y9XNL@+3ez+fJ~Bx8<4>8XGTxnyYI@A-R<^Xt19 zy=8MU9TJWP2fJv0Z+~xBh0ybT17f3VED(esGCUg5n2HGr^GJV8)5&ZIfxc8;jeu^6 z6sI%cv5}Wfh^O&ji2tcTQ~U?x28fcOp2{s0vccMc$(Hnk3694^C|E*)F7ka2Y3MNq z0Yb{8QD8h_9H+{O4e4k^pj$=+r!y`|g&~1eSJl)55@8{vyr&Dous1AQnf9o{xV0fpF4} zbQ*+H>HtotZj=XRy$4}$fMcmtA(}FfQ6B8#A)BdjW%2d9S~B+?5B(ygpxhu0sQzBz zX@1}r*c#zK`&+uS2h4d|%{#b}6Q^=zQ2-sGSjd8zjBKFK+6T{k|F`+UZ&Nx}9o*l_{_D*I z@d7M}=;>jiU&Uk9d8Q31L-PZzEx!mdnnft0@fDz_|844)b^117o6b_kDUL*+6TzZ6 z@g#fu@b7__Fp+vWE2^ja-`W(HX-(}1!-$RhstoaDOQ23~zVD?>|M#H(Elg`V?b5Mw zGyf}K$>Q&F8apWFX*#-ah-Pu9Q`t`v988EIvy05GqkVr5?Z^VIe&zQ5?nvF4;svOo zw7#GNFuci4KoS`K0h=ZfRUx#QIy4F2`IjcZhAD;-FIhEnoi2rN>Np^hqkjMT`r609 zqR;raAE_du|I_KKH*YT>we(xZ`6Z5s5cy;|Tp0LXTI>j4BWXy+oG1fNV|2}F3aib6 zjZ!HhC!`|fbT~^3;xRl?f$Rd(F2~3{xj?5EF8c1|;`CzI`EYvq!@FND(T9`s^OLui zr*AIMyL0sF-P_lvm#6REUZ8j1qm#G)LO-6qeZ7kaRgm6|G@U{+NT)Eh`_2U+g~|=o zr9fF4pa{p~86FcfW^=-0SbQgZN`;y$aU41kozhfW#7cAgFKFTU>G$+|`aSsX{{;X5 N|NrIS`-cFW5CAXDfBpaf literal 0 HcmV?d00001 diff --git a/infrastructure/local/.env b/infrastructure/local/.env index 6a9eca469d..d18d8cae87 100644 --- a/infrastructure/local/.env +++ b/infrastructure/local/.env @@ -1,3 +1,3 @@ -AGENT_VERSION=1.32.0 +AGENT_VERSION=1.32.1 PRISM_NODE_VERSION=2.2.1 VAULT_DEV_ROOT_TOKEN_ID=root diff --git a/package-lock.json b/package-lock.json index a53edf3355..e4293ac19d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "identus-cloud-agent", - "version": "1.32.0", + "version": "1.32.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "identus-cloud-agent", - "version": "1.32.0", + "version": "1.32.1", "devDependencies": { "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", diff --git a/package.json b/package.json index e2f1fe9728..e40e86b10b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "identus-cloud-agent", - "version": "1.32.0", + "version": "1.32.1", "engines": { "node": ">=16.13.0" }, diff --git a/version.sbt b/version.sbt index 31006ecdc3..3dd20a0723 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "1.32.0-SNAPSHOT" +ThisBuild / version := "1.32.1-SNAPSHOT" From d674f3162be44ba05d50b305be4838525d982706 Mon Sep 17 00:00:00 2001 From: Bassam Date: Tue, 7 May 2024 09:10:47 -0400 Subject: [PATCH 05/14] fix: integration test (#1011) Signed-off-by: Bassam Riman Signed-off-by: Yurii Shynbuiev - IOHK Co-authored-by: Yurii Shynbuiev - IOHK --- tests/integration-tests/build.gradle.kts | 4 +- .../test/kotlin/abilities/ListenToEvents.kt | 4 +- .../test/kotlin/common/CredentialSchema.kt | 2 +- .../src/test/kotlin/steps/Setup.kt | 4 +- .../test/kotlin/steps/common/CommonSteps.kt | 8 +- .../steps/connection/ConnectionSteps.kt | 6 +- .../credentials/IssueCredentialsSteps.kt | 2 +- .../kotlin/steps/did/DeactivateDidSteps.kt | 4 +- .../test/kotlin/steps/did/ManageDidSteps.kt | 6 +- .../test/kotlin/steps/did/PublishDidSteps.kt | 2 +- .../test/kotlin/steps/did/UpdateDidSteps.kt | 6 +- .../kotlin/steps/multitenancy/EntitySteps.kt | 6 +- .../kotlin/steps/multitenancy/EventsSteps.kt | 2 +- .../kotlin/steps/multitenancy/WalletsSteps.kt | 6 +- .../proofs/AnoncredsPresentProofSteps.kt | 2 +- .../kotlin/steps/proofs/PresentProofSteps.kt | 2 +- .../steps/schemas/CredentialSchemasSteps.kt | 4 +- .../test/kotlin/steps/system/SystemSteps.kt | 2 +- .../steps/verification/VcVerificationSteps.kt | 90 +++++++++++++------ .../VerificationPoliciesSteps.kt | 4 +- .../verification/vc_verification.feature | 5 ++ 21 files changed, 103 insertions(+), 68 deletions(-) create mode 100644 tests/integration-tests/src/test/resources/features/verification/vc_verification.feature diff --git a/tests/integration-tests/build.gradle.kts b/tests/integration-tests/build.gradle.kts index f9a96b0d99..b9d606a6e1 100644 --- a/tests/integration-tests/build.gradle.kts +++ b/tests/integration-tests/build.gradle.kts @@ -33,9 +33,9 @@ dependencies { testImplementation("io.ktor:ktor-server-netty:2.3.0") testImplementation("io.ktor:ktor-client-apache:2.3.0") // RestAPI client - testImplementation("org.hyperledger.identus:cloud-agent-client-kotlin:1.32.0") + testImplementation("org.hyperledger.identus:cloud-agent-client-kotlin:1.32.1") // Test helpers library - testImplementation("io.iohk.atala:atala-automation:0.3.2") + testImplementation("io.iohk.atala:atala-automation:0.4.0") // Hoplite for configuration testImplementation("com.sksamuel.hoplite:hoplite-core:2.7.5") testImplementation("com.sksamuel.hoplite:hoplite-hocon:2.7.5") diff --git a/tests/integration-tests/src/test/kotlin/abilities/ListenToEvents.kt b/tests/integration-tests/src/test/kotlin/abilities/ListenToEvents.kt index 6a360d92f9..2ea3b69724 100644 --- a/tests/integration-tests/src/test/kotlin/abilities/ListenToEvents.kt +++ b/tests/integration-tests/src/test/kotlin/abilities/ListenToEvents.kt @@ -23,9 +23,7 @@ open class ListenToEvents( ) : Ability, HasTeardown { private val server: ApplicationEngine - private val gson = GsonBuilder() - .registerTypeAdapter(OffsetDateTime::class.java, CustomGsonObjectMapperFactory.OffsetDateTimeDeserializer()) - .create() + private val gson = GsonBuilder().registerTypeAdapter(OffsetDateTime::class.java, CustomGsonObjectMapperFactory.OffsetDateTimeTypeAdapter()).create() var connectionEvents: MutableList = mutableListOf() var credentialEvents: MutableList = mutableListOf() diff --git a/tests/integration-tests/src/test/kotlin/common/CredentialSchema.kt b/tests/integration-tests/src/test/kotlin/common/CredentialSchema.kt index 32990542a7..972f806069 100644 --- a/tests/integration-tests/src/test/kotlin/common/CredentialSchema.kt +++ b/tests/integration-tests/src/test/kotlin/common/CredentialSchema.kt @@ -1,8 +1,8 @@ package common -import org.hyperledger.identus.client.models.CredentialSchemaInput import models.JsonSchema import models.JsonSchemaProperty +import org.hyperledger.identus.client.models.CredentialSchemaInput import java.util.UUID enum class CredentialSchema { diff --git a/tests/integration-tests/src/test/kotlin/steps/Setup.kt b/tests/integration-tests/src/test/kotlin/steps/Setup.kt index dbb134ceb7..ce1034a63e 100644 --- a/tests/integration-tests/src/test/kotlin/steps/Setup.kt +++ b/tests/integration-tests/src/test/kotlin/steps/Setup.kt @@ -8,8 +8,6 @@ import config.AgentRole import config.Config import io.cucumber.java.AfterAll import io.cucumber.java.BeforeAll -import org.hyperledger.identus.client.models.CreateWalletRequest -import org.hyperledger.identus.client.models.CreateWebhookNotification import io.restassured.RestAssured import io.restassured.builder.RequestSpecBuilder import net.serenitybdd.screenplay.Actor @@ -17,6 +15,8 @@ import net.serenitybdd.screenplay.actors.Cast import net.serenitybdd.screenplay.actors.OnStage import net.serenitybdd.screenplay.rest.abilities.CallAnApi import org.apache.http.HttpStatus +import org.hyperledger.identus.client.models.CreateWalletRequest +import org.hyperledger.identus.client.models.CreateWebhookNotification import java.util.UUID object Setup { diff --git a/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt b/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt index 5edf9ebfb8..a4df15c5ed 100644 --- a/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt @@ -5,14 +5,14 @@ import io.cucumber.java.ParameterType import io.cucumber.java.en.Given import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.Connection -import org.hyperledger.identus.client.models.ConnectionsPage -import org.hyperledger.identus.client.models.IssueCredentialRecord -import org.hyperledger.identus.client.models.IssueCredentialRecordPage import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.actors.OnStage import org.apache.http.HttpStatus +import org.hyperledger.identus.client.models.Connection +import org.hyperledger.identus.client.models.ConnectionsPage +import org.hyperledger.identus.client.models.IssueCredentialRecord +import org.hyperledger.identus.client.models.IssueCredentialRecordPage import steps.connection.ConnectionSteps import steps.credentials.IssueCredentialsSteps import steps.did.PublishDidSteps diff --git a/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt b/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt index 230b9336cd..38922a021c 100644 --- a/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt @@ -8,14 +8,14 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.AcceptConnectionInvitationRequest -import org.hyperledger.identus.client.models.Connection -import org.hyperledger.identus.client.models.CreateConnectionRequest import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus.SC_CREATED import org.apache.http.HttpStatus.SC_OK import org.assertj.core.api.Assertions.assertThat +import org.hyperledger.identus.client.models.AcceptConnectionInvitationRequest +import org.hyperledger.identus.client.models.Connection +import org.hyperledger.identus.client.models.CreateConnectionRequest class ConnectionSteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt b/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt index 0ec5abd3d0..578ce9419d 100644 --- a/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt @@ -8,13 +8,13 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.* import models.AnoncredsSchema import models.CredentialEvent import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.rest.abilities.CallAnApi import org.apache.http.HttpStatus.* +import org.hyperledger.identus.client.models.* import java.util.UUID class IssueCredentialsSteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/did/DeactivateDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/DeactivateDidSteps.kt index d634bcca48..b95a9f3233 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/DeactivateDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/DeactivateDidSteps.kt @@ -8,11 +8,11 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.DIDOperationResponse -import org.hyperledger.identus.client.models.DIDResolutionResult import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus +import org.hyperledger.identus.client.models.DIDOperationResponse +import org.hyperledger.identus.client.models.DIDResolutionResult class DeactivateDidSteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt index 06c112df51..df87418e20 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt @@ -7,6 +7,9 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure +import net.serenitybdd.rest.SerenityRest +import net.serenitybdd.screenplay.Actor +import org.apache.http.HttpStatus.SC_CREATED import org.hyperledger.identus.client.models.CreateManagedDidRequest import org.hyperledger.identus.client.models.CreateManagedDidRequestDocumentTemplate import org.hyperledger.identus.client.models.Json @@ -15,9 +18,6 @@ import org.hyperledger.identus.client.models.ManagedDIDKeyTemplate import org.hyperledger.identus.client.models.ManagedDIDPage import org.hyperledger.identus.client.models.Purpose import org.hyperledger.identus.client.models.Service -import net.serenitybdd.rest.SerenityRest -import net.serenitybdd.screenplay.Actor -import org.apache.http.HttpStatus.SC_CREATED class ManageDidSteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt index d3328c85c7..cd04a6e14f 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt @@ -10,12 +10,12 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.* import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus import org.apache.http.HttpStatus.SC_CREATED import org.apache.http.HttpStatus.SC_OK +import org.hyperledger.identus.client.models.* class PublishDidSteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt index f641b56086..0f4517d15d 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt @@ -8,6 +8,9 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure +import net.serenitybdd.rest.SerenityRest +import net.serenitybdd.screenplay.Actor +import org.apache.http.HttpStatus import org.hyperledger.identus.client.models.ActionType import org.hyperledger.identus.client.models.DIDOperationResponse import org.hyperledger.identus.client.models.DIDResolutionResult @@ -19,9 +22,6 @@ import org.hyperledger.identus.client.models.Service import org.hyperledger.identus.client.models.UpdateManagedDIDRequest import org.hyperledger.identus.client.models.UpdateManagedDIDRequestAction import org.hyperledger.identus.client.models.UpdateManagedDIDServiceAction -import net.serenitybdd.rest.SerenityRest -import net.serenitybdd.screenplay.Actor -import org.apache.http.HttpStatus class UpdateDidSteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/multitenancy/EntitySteps.kt b/tests/integration-tests/src/test/kotlin/steps/multitenancy/EntitySteps.kt index 1672643016..3bd9c51839 100644 --- a/tests/integration-tests/src/test/kotlin/steps/multitenancy/EntitySteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/multitenancy/EntitySteps.kt @@ -3,12 +3,12 @@ package steps.multitenancy import interactions.Post import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.ApiKeyAuthenticationRequest -import org.hyperledger.identus.client.models.CreateEntityRequest -import org.hyperledger.identus.client.models.EntityResponse import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus.SC_CREATED +import org.hyperledger.identus.client.models.ApiKeyAuthenticationRequest +import org.hyperledger.identus.client.models.CreateEntityRequest +import org.hyperledger.identus.client.models.EntityResponse import java.util.* class EntitySteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/multitenancy/EventsSteps.kt b/tests/integration-tests/src/test/kotlin/steps/multitenancy/EventsSteps.kt index 3e0ba085de..34a89407ee 100644 --- a/tests/integration-tests/src/test/kotlin/steps/multitenancy/EventsSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/multitenancy/EventsSteps.kt @@ -2,9 +2,9 @@ package steps.multitenancy import interactions.Post import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.CreateWebhookNotification import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus +import org.hyperledger.identus.client.models.CreateWebhookNotification class EventsSteps { fun registerNewWebhook(actor: Actor, webhookUrl: String) { diff --git a/tests/integration-tests/src/test/kotlin/steps/multitenancy/WalletsSteps.kt b/tests/integration-tests/src/test/kotlin/steps/multitenancy/WalletsSteps.kt index cfed7d7db7..62cf9781c9 100644 --- a/tests/integration-tests/src/test/kotlin/steps/multitenancy/WalletsSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/multitenancy/WalletsSteps.kt @@ -8,12 +8,12 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.CreateWalletRequest -import org.hyperledger.identus.client.models.WalletDetail -import org.hyperledger.identus.client.models.WalletDetailPage import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus.* +import org.hyperledger.identus.client.models.CreateWalletRequest +import org.hyperledger.identus.client.models.WalletDetail +import org.hyperledger.identus.client.models.WalletDetailPage import java.util.* import kotlin.random.Random diff --git a/tests/integration-tests/src/test/kotlin/steps/proofs/AnoncredsPresentProofSteps.kt b/tests/integration-tests/src/test/kotlin/steps/proofs/AnoncredsPresentProofSteps.kt index ced971f571..566d2f1864 100644 --- a/tests/integration-tests/src/test/kotlin/steps/proofs/AnoncredsPresentProofSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/proofs/AnoncredsPresentProofSteps.kt @@ -7,12 +7,12 @@ import interactions.Post import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.* import models.PresentationEvent import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.rest.abilities.CallAnApi import org.apache.http.HttpStatus.SC_CREATED +import org.hyperledger.identus.client.models.* class AnoncredsPresentProofSteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt b/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt index 1700c6e75b..741ef0e9b6 100644 --- a/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt @@ -8,11 +8,11 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.* import models.PresentationEvent import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus.SC_CREATED +import org.hyperledger.identus.client.models.* class PresentProofSteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt b/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt index 4f908a9dc5..3fecf2e436 100644 --- a/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt @@ -11,12 +11,12 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.CredentialSchemaInput -import org.hyperledger.identus.client.models.CredentialSchemaResponse import models.JsonSchema import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus.* +import org.hyperledger.identus.client.models.CredentialSchemaInput +import org.hyperledger.identus.client.models.CredentialSchemaResponse import java.util.UUID class CredentialSchemasSteps { diff --git a/tests/integration-tests/src/test/kotlin/steps/system/SystemSteps.kt b/tests/integration-tests/src/test/kotlin/steps/system/SystemSteps.kt index 91312d5527..b9bfada0d2 100644 --- a/tests/integration-tests/src/test/kotlin/steps/system/SystemSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/system/SystemSteps.kt @@ -5,10 +5,10 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.HealthInfo import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus +import org.hyperledger.identus.client.models.HealthInfo class SystemSteps { @When("{actor} makes a request to the health endpoint") diff --git a/tests/integration-tests/src/test/kotlin/steps/verification/VcVerificationSteps.kt b/tests/integration-tests/src/test/kotlin/steps/verification/VcVerificationSteps.kt index 9e0d2f8037..fa3addf6ef 100644 --- a/tests/integration-tests/src/test/kotlin/steps/verification/VcVerificationSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/verification/VcVerificationSteps.kt @@ -1,13 +1,14 @@ package steps.verification -import interactions.Post +import com.google.gson.Gson import io.cucumber.java.en.When -import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.* +import io.restassured.http.Header import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor +import net.serenitybdd.screenplay.rest.interactions.Post import org.apache.http.HttpStatus.SC_OK +import org.hyperledger.identus.client.models.* import java.time.OffsetDateTime class VcVerificationSteps { @@ -15,60 +16,91 @@ class VcVerificationSteps { @When("{actor} verifies VcVerificationRequest") fun agentVerifiesVerifiableCredential(actor: Actor) { val signedJwtCredential = - "eyJhbGciOiJFUzI1NksifQ.eyJhdWQiOiJkaWQ6cHJpc206dmVyaWZpZXIiLCJuYmYiOjEyNjIzMDQwMDAsImlzcyI6ImRpZDpwcmlzbTo3NzYxMjBlZWIxMjhjZTdkZmQ5NDUwZmZhMTg4MWU5OTYxOWFhMGM5MDRiMDBjODJiYjE3YjU2ODE3Y2IwMmFlIiwiZXhwIjoxMjYzMjU0NDAwLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJVbml2ZXJzaXR5RGVncmVlQ3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiZGlkOndvcms6TURQOEFzRmhIemh3VXZHTnVZa1g3VDtpZD0wNmUxMjZkMS1mYTQ0LTQ4ODItYTI0My0xZTMyNmZiZTIxZGI7dmVyc2lvbj0xLjAiLCJ0eXBlIjoiSnNvblNjaGVtYVZhbGlkYXRvcjIwMTgifSwiY3JlZGVudGlhbFN1YmplY3QiOnsidXNlck5hbWUiOiJCb2IiLCJhZ2UiOjQyLCJlbWFpbCI6ImVtYWlsIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJkaWQ6d29yazpNRFA4QXNGaEh6aHdVdkdOdVlrWDdUO2lkPTA2ZTEyNmQxLWZhNDQtNDg4Mi1hMjQzLTFlMzI2ZmJlMjFkYjt2ZXJzaW9uPTEuMCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6IlJldm9jYXRpb24iLCJzdGF0dXNMaXN0SW5kZXgiOjAsInN0YXR1c0xpc3RDcmVkZW50aWFsIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9jcmVkZW50aWFscy9zdGF0dXMvMyJ9LCJyZWZyZXNoU2VydmljZSI6eyJpZCI6Imh0dHBzOi8vZXhhbXBsZS5lZHUvcmVmcmVzaC8zNzMyIiwidHlwZSI6Ik1hbnVhbFJlZnJlc2hTZXJ2aWNlMjAxOCJ9fSwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIifQ.JCHIAQdjmOxOdZ1SIf5Nd8FObiARXT6cDcGM3UyQ961Kv4Rb3ZtgpNM-cf2aj5ZFyFko-t7uCsSvrVrYKUYcWg" + "eyJhbGciOiJFUzI1NksifQ.eyJpc3MiOiJkaWQ6cHJpc206NDE1ODg1OGI1ZjBkYWMyZTUwNDdmMjI4NTk4OWVlMzlhNTNkZWJhNzY0NjFjN2FmMDM5NjU0ZGYzYjU5MjI1YyIsImF1ZCI6ImRpZDpwcmlzbTp2ZXJpZmllciIsIm5iZiI6MTI2MjMwNDAwMCwiZXhwIjoxMjYzMjU0NDAwLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJVbml2ZXJzaXR5RGVncmVlQ3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiZGlkOndvcms6TURQOEFzRmhIemh3VXZHTnVZa1g3VDtpZD0wNmUxMjZkMS1mYTQ0LTQ4ODItYTI0My0xZTMyNmZiZTIxZGI7dmVyc2lvbj0xLjAiLCJ0eXBlIjoiSnNvblNjaGVtYVZhbGlkYXRvcjIwMTgifSwiY3JlZGVudGlhbFN1YmplY3QiOnsidXNlck5hbWUiOiJCb2IiLCJhZ2UiOjQyLCJlbWFpbCI6ImVtYWlsIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJkaWQ6d29yazpNRFA4QXNGaEh6aHdVdkdOdVlrWDdUO2lkPTA2ZTEyNmQxLWZhNDQtNDg4Mi1hMjQzLTFlMzI2ZmJlMjFkYjt2ZXJzaW9uPTEuMCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6IlJldm9jYXRpb24iLCJzdGF0dXNMaXN0SW5kZXgiOjAsInN0YXR1c0xpc3RDcmVkZW50aWFsIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9jcmVkZW50aWFscy9zdGF0dXMvMyJ9LCJyZWZyZXNoU2VydmljZSI6eyJpZCI6Imh0dHBzOi8vZXhhbXBsZS5lZHUvcmVmcmVzaC8zNzMyIiwidHlwZSI6Ik1hbnVhbFJlZnJlc2hTZXJ2aWNlMjAxOCJ9fSwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIifQ.HBxrn8Nu6y1RvUAU8XcwUDPOiiHhC1OgHN757lWai6i8P-pHL4TBzIDartYtrMiZUKpNx9Onb19sJYywtqFkpg" + val request = - listOf( + arrayOf( VcVerificationRequest( signedJwtCredential, listOf( - ParameterizableVcVerification(VcVerification.SIGNATURE_VERIFICATION), ParameterizableVcVerification( VcVerification.NOT_BEFORE_CHECK, - DateTimeParameter(OffsetDateTime.now()) as VcVerificationParameter, + DateTimeParameter(dateTime = OffsetDateTime.parse("2010-01-01T00:00:00Z")), ), ParameterizableVcVerification( VcVerification.EXPIRATION_CHECK, - DateTimeParameter(OffsetDateTime.now()) as VcVerificationParameter, + DateTimeParameter(dateTime = OffsetDateTime.parse("2010-01-01T00:00:00Z")), + ), + ParameterizableVcVerification( + VcVerification.AUDIENCE_CHECK, + DidParameter(did = "did:prism:verifier"), + ), + ParameterizableVcVerification( + VcVerification.ISSUER_IDENTIFICATION, + DidParameter(did = "did:prism:4158858b5f0dac2e5047f2285989ee39a53deba76461c7af039654df3b59225c"), ), ), ), VcVerificationRequest( signedJwtCredential, listOf( + ParameterizableVcVerification( + VcVerification.EXPIRATION_CHECK, + DateTimeParameter(dateTime = OffsetDateTime.parse("2010-01-13T00:00:00Z")), + ), + ParameterizableVcVerification( + VcVerification.NOT_BEFORE_CHECK, + DateTimeParameter(dateTime = OffsetDateTime.parse("2009-01-01T00:00:00Z")), + ), ParameterizableVcVerification( VcVerification.AUDIENCE_CHECK, - DidParameter("did:prism:verifier") as VcVerificationParameter, + DidParameter(did = "BAD AUDIENCE"), + ), + ParameterizableVcVerification( + VcVerification.ISSUER_IDENTIFICATION, + DidParameter(did = "BAD ISSUER"), ), ), ), ) - actor.attemptsTo( + + val post = Post.to("/verification/credential").with { + it.header(Header("apiKey", "pylnapbvyudwmfrt")) it.body(request) - }, - ) - val vcVerificationResponses = SerenityRest.lastResponse().get>() + } actor.attemptsTo( - Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), - Ensure.that(vcVerificationResponses).containsExactlyInAnyOrderElementsFrom( + post, + ) + + val expected = listOf( + VcVerificationResponse( + signedJwtCredential, listOf( - VcVerificationResponse( - signedJwtCredential, - listOf( - VcVerificationResult(VcVerification.SIGNATURE_VERIFICATION, false), - VcVerificationResult(VcVerification.NOT_BEFORE_CHECK, true), - VcVerificationResult(VcVerification.EXPIRATION_CHECK, true), - ), - ), - VcVerificationResponse( - signedJwtCredential, - listOf( - VcVerificationResult(VcVerification.AUDIENCE_CHECK, true), - ), - ), + VcVerificationResult(VcVerification.NOT_BEFORE_CHECK, true), + VcVerificationResult(VcVerification.EXPIRATION_CHECK, true), + VcVerificationResult(VcVerification.AUDIENCE_CHECK, true), + VcVerificationResult(VcVerification.ISSUER_IDENTIFICATION, true), + ), + ), + VcVerificationResponse( + signedJwtCredential, + listOf( + VcVerificationResult(VcVerification.EXPIRATION_CHECK, false), + VcVerificationResult(VcVerification.NOT_BEFORE_CHECK, false), + VcVerificationResult(VcVerification.AUDIENCE_CHECK, false), + VcVerificationResult(VcVerification.ISSUER_IDENTIFICATION, false), ), ), ) + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), + Ensure.that( + SerenityRest.lastResponse().body().asString(), + ).isEqualTo( + Gson().toJson(expected), + ), + ) } } diff --git a/tests/integration-tests/src/test/kotlin/steps/verificationpolicies/VerificationPoliciesSteps.kt b/tests/integration-tests/src/test/kotlin/steps/verificationpolicies/VerificationPoliciesSteps.kt index f300f47ed7..ca6a4cf8ca 100644 --- a/tests/integration-tests/src/test/kotlin/steps/verificationpolicies/VerificationPoliciesSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/verificationpolicies/VerificationPoliciesSteps.kt @@ -8,11 +8,11 @@ import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import org.hyperledger.identus.client.models.VerificationPolicyInput -import org.hyperledger.identus.client.models.VerificationPolicyResponse import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus +import org.hyperledger.identus.client.models.VerificationPolicyInput +import org.hyperledger.identus.client.models.VerificationPolicyResponse import java.util.* class VerificationPoliciesSteps { diff --git a/tests/integration-tests/src/test/resources/features/verification/vc_verification.feature b/tests/integration-tests/src/test/resources/features/verification/vc_verification.feature new file mode 100644 index 0000000000..ed12bf50f2 --- /dev/null +++ b/tests/integration-tests/src/test/resources/features/verification/vc_verification.feature @@ -0,0 +1,5 @@ +Feature: Vc Verification schemas + +Scenario: Successful Verifies VcVerificationRequest + Given Issuer and Holder have an existing connection + When Issuer verifies VcVerificationRequest From 74560dabf59dac15ccd086edb7a77d9e5055621e Mon Sep 17 00:00:00 2001 From: Yurii Shynbuiev - IOHK Date: Wed, 8 May 2024 22:50:04 +0700 Subject: [PATCH 06/14] feat: rename `prism-agent` to `cloud-agent` (#1019) Signed-off-by: Yurii Shynbuiev Signed-off-by: Hyperledger Bot Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Hyperledger Bot --- cloud-agent/client/typescript/package.json | 2 +- .../src/main/resources/application.conf | 2 +- .../identus/agent/server/MainApp.scala | 21 ++- .../identus/agent/server/http/DocModels.scala | 15 +- .../controller/http/ConnectionsPage.scala | 6 +- .../entity/http/model/EntityResponse.scala | 4 +- .../http/model/EntityResponsePage.scala | 8 +- .../CreateIssueCredentialRecordRequest.scala | 2 +- .../http/IssueCredentialRecordPage.scala | 8 +- .../http/CredentialDefinitionResponse.scala | 4 +- .../CredentialDefinitionResponsePage.scala | 8 +- .../http/CredentialSchemaResponse.scala | 2 +- .../http/CredentialSchemaResponsePage.scala | 8 +- .../http/VerificationPolicyResponse.scala | 20 +-- docs/docusaurus/connections/connection.md | 8 +- .../docusaurus/credentialdefinition/create.md | 10 +- docs/docusaurus/credentials/issue.md | 16 +- docs/docusaurus/credentials/present-proof.md | 40 ++--- docs/docusaurus/credentials/revocation.md | 12 +- docs/docusaurus/dids/create.md | 10 +- docs/docusaurus/dids/deactivate.md | 4 +- docs/docusaurus/dids/publish.md | 6 +- docs/docusaurus/dids/update.md | 4 +- docs/docusaurus/index.md | 8 +- .../multitenancy/admin-authz-ext-iam.md | 24 +-- .../multitenancy/tenant-migration.md | 6 +- .../multitenancy/tenant-onboarding-ext-iam.md | 16 +- .../tenant-onboarding-self-service.md | 12 +- .../multitenancy/tenant-onboarding.md | 10 +- docs/docusaurus/schemas/create.md | 10 +- docs/docusaurus/schemas/update.md | 8 +- docs/docusaurus/webhooks/webhook.md | 2 +- docs/guides/linting.md | 2 +- .../charts/agent/templates/apisixroute.yaml | 15 +- .../charts/agent/templates/deployment.yaml | 4 +- .../ci/docker-compose-multiple-actors.yml | 154 ------------------ infrastructure/local/.env | 2 +- infrastructure/local/run-e2e-tests-local.sh | 16 +- infrastructure/multi/run-e2e-tests-local.sh | 8 +- infrastructure/multi/run-e2e-tests-remote.sh | 13 +- infrastructure/shared/apisix/conf/apisix.yaml | 12 +- infrastructure/shared/docker-compose-demo.yml | 10 +- .../shared/docker-compose-mt-keycloak.yml | 10 +- infrastructure/shared/docker-compose.yml | 12 +- .../apisix/conf/apisix.yaml | 18 ++ .../run-e2e-tests-local.sh | 14 +- .../run-performance-tests-local.sh | 36 ++-- .../agent-performance-tests-k6/.env | 2 +- .../agent-performance-tests-k6/run.sh | 4 +- .../src/common/Config.ts | 24 +-- .../agent-performance-tests/README.md | 4 +- 51 files changed, 279 insertions(+), 397 deletions(-) delete mode 100644 infrastructure/ci/docker-compose-multiple-actors.yml diff --git a/cloud-agent/client/typescript/package.json b/cloud-agent/client/typescript/package.json index 530dd6fc09..28ac1fbfcd 100644 --- a/cloud-agent/client/typescript/package.json +++ b/cloud-agent/client/typescript/package.json @@ -1,5 +1,5 @@ { - "name": "@hyperledger/cloud-agent-client-ts", + "name": "@hyperledger/identus-cloud-agent-client-ts", "version": "0.0.1", "description": "TypeScript OpenAPI client for Identus Cloud Agent", "author": "allain.magyar@iohk.io", diff --git a/cloud-agent/service/server/src/main/resources/application.conf b/cloud-agent/service/server/src/main/resources/application.conf index 1be6917b31..4e8a3be8e1 100644 --- a/cloud-agent/service/server/src/main/resources/application.conf +++ b/cloud-agent/service/server/src/main/resources/application.conf @@ -86,7 +86,7 @@ agent { port = 8085 port =${?AGENT_HTTP_PORT} } - publicEndpointUrl = "https://host.docker.internal:8080/prism-agent" + publicEndpointUrl = "https://host.docker.internal:8080/cloud-agent" publicEndpointUrl = ${?REST_SERVICE_URL} } didCommEndpoint { diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/MainApp.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/MainApp.scala index 3fd30afe4c..d334e3da4c 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/MainApp.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/MainApp.scala @@ -108,12 +108,19 @@ object MainApp extends ZIOAppDefault { val app = for { _ <- Console .printLine(s""" - |██████╗ ██████╗ ██╗███████╗███╗ ███╗ - |██╔══██╗██╔══██╗██║██╔════╝████╗ ████║ - |██████╔╝██████╔╝██║███████╗██╔████╔██║ - |██╔═══╝ ██╔══██╗██║╚════██║██║╚██╔╝██║ - |██║ ██║ ██║██║███████║██║ ╚═╝ ██║ - |╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═╝ + |██╗██████╗ ███████╗███╗ ██╗████████╗██╗ ██╗███████╗ + |██║██╔══██╗██╔════╝████╗ ██║╚══██╔══╝██║ ██║██╔════╝ + |██║██║ ██║█████╗ ██╔██╗ ██║ ██║ ██║ ██║███████╗ + |██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██║ ██║╚════██║ + |██║██████╔╝███████╗██║ ╚████║ ██║ ╚██████╔╝███████║ + |╚═╝╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚══════╝ + | + | ██████╗██╗ ██████╗ ██╗ ██╗██████╗ + |██╔════╝██║ ██╔═══██╗██║ ██║██╔══██╗ + |██║ ██║ ██║ ██║██║ ██║██║ ██║ + |██║ ██║ ██║ ██║██║ ██║██║ ██║ + |╚██████╗███████╗╚██████╔╝╚██████╔╝██████╔╝ + | ╚═════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ | | █████╗ ██████╗ ███████╗███╗ ██╗████████╗ |██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ @@ -122,7 +129,7 @@ object MainApp extends ZIOAppDefault { |██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ |╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ | - |version: ${BuildInfo.version} + |version: ${buildinfo.BuildInfo.version} | |""".stripMargin) .ignore diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/http/DocModels.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/http/DocModels.scala index fa72fabd34..4da38db95f 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/http/DocModels.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/http/DocModels.scala @@ -57,11 +57,11 @@ object DocModels { .openapi("3.0.3") .info( Info( - title = "Open Enterprise Agent API Reference", + title = "Identus Cloud Agent API Reference", version = "1.0", // Will be replaced dynamically by 'Tapir2StaticOAS' summary = None, description = Some(""" - |The Open Enterprise Agent API facilitates the integration and management of self-sovereign identity capabilities within applications. + |The Identus Cloud Agent API facilitates the integration and management of self-sovereign identity capabilities within applications. |It supports DID (Decentralized Identifiers) management, verifiable credential exchange, and secure messaging based on DIDComm standards. |The API is designed to be interoperable with various blockchain and DLT (Distributed Ledger Technology) platforms, ensuring wide compatibility and flexibility. |Key features include connection management, credential issuance and verification, and secure, privacy-preserving communication between entities. @@ -81,11 +81,14 @@ object DocModels { ) .servers( List( - Server(url = "http://localhost:8085", description = Some("Local Prism Agent")), - Server(url = "http://localhost/prism-agent", description = Some("Local Prism Agent with APISIX proxy")), + Server(url = "http://localhost:8085", description = Some("The local instance of the Cloud Agent")), Server( - url = "https://k8s-dev.atalaprism.io/prism-agent", - description = Some("Prism Agent on the Staging Environment") + url = "http://localhost/cloud-agent", + description = Some("The local instance of the Cloud Agent behind the APISIX proxy") + ), + Server( + url = "https://k8s-dev.atalaprism.io/cloud-agent", + description = Some("The Cloud Agent in the Staging Environment") ), ) ) diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/connect/controller/http/ConnectionsPage.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/connect/controller/http/ConnectionsPage.scala index cddb14d73c..2847599f50 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/connect/controller/http/ConnectionsPage.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/connect/controller/http/ConnectionsPage.scala @@ -57,7 +57,7 @@ object ConnectionsPage { object self extends Annotation[String]( description = "The URL that uniquely identifies the resource being returned in the response.", - example = "/prism-agent/connections?offset=10&limit=10" + example = "/cloud-agent/connections?offset=10&limit=10" ) object pageOf @@ -70,14 +70,14 @@ object ConnectionsPage { extends Annotation[String]( description = "An optional string field containing the URL of the next page of results. If the API response does not contain any more pages, this field should be set to None.", - example = "/prism-agent/connections?offset=20&limit=10" + example = "/cloud-agent/connections?offset=20&limit=10" ) object previous extends Annotation[String]( description = "An optional string field containing the URL of the previous page of results. If the API response is the first page of results, this field should be set to None.", - example = "/prism-agent/connections?offset=0&limit=10" + example = "/cloud-agent/connections?offset=0&limit=10" ) } diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/entity/http/model/EntityResponse.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/entity/http/model/EntityResponse.scala index 72d03d34bb..7884216feb 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/entity/http/model/EntityResponse.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/entity/http/model/EntityResponse.scala @@ -67,7 +67,7 @@ object EntityResponse { object self extends Annotation[String]( description = "The `self` link of the entity.", - example = "http://localhost:8080/prism-agent/iam/entities/00000000-0000-0000-0000-000000000000" + example = "http://localhost:8080/cloud-agent/iam/entities/00000000-0000-0000-0000-000000000000" ) object id @@ -103,7 +103,7 @@ object EntityResponse { val Example = EntityResponse( kind = "Entity", - self = "/prism-agent/iam/entities/00000000-0000-0000-0000-000000000000", + self = "/cloud-agent/iam/entities/00000000-0000-0000-0000-000000000000", id = UUID.fromString("00000000-0000-0000-0000-000000000000"), name = "John Doe", walletId = UUID.fromString("00000000-0000-0000-0000-000000000000"), diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/entity/http/model/EntityResponsePage.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/entity/http/model/EntityResponsePage.scala index 63bfae19da..cdf022c0b0 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/entity/http/model/EntityResponsePage.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/entity/http/model/EntityResponsePage.scala @@ -69,27 +69,27 @@ object EntityResponsePage { object self extends Annotation[String]( description = "A string field containing the URL of the current API endpoint", - example = "/prism-agent/schema-registry/schemas?skip=10&limit=10" + example = "/cloud-agent/schema-registry/schemas?skip=10&limit=10" ) object pageOf extends Annotation[String]( description = "A string field indicating the type of resource that the contents field contains", - example = "/prism-agent/schema-registry/schemas" + example = "/cloud-agent/schema-registry/schemas" ) object next extends Annotation[String]( description = "An optional string field containing the URL of the next page of results. " + "If the API response does not contain any more pages, this field should be set to None.", - example = "/prism-agent/schema-registry/schemas?skip=20&limit=10" + example = "/cloud-agent/schema-registry/schemas?skip=20&limit=10" ) object previous extends Annotation[String]( description = "An optional string field containing the URL of the previous page of results. " + "If the API response is the first page of results, this field should be set to None.", - example = "/prism-agent/schema-registry/schemas?skip=0&limit=10" + example = "/cloud-agent/schema-registry/schemas?skip=0&limit=10" ) } diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/CreateIssueCredentialRecordRequest.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/CreateIssueCredentialRecordRequest.scala index 89b043b7a2..fa859c42f9 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/CreateIssueCredentialRecordRequest.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/CreateIssueCredentialRecordRequest.scala @@ -71,7 +71,7 @@ object CreateIssueCredentialRecordRequest { |Note that this parameter only applies when the offer is of type 'JWT'. |""".stripMargin, example = Some( - "https://agent-host.com/prism-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676/schema" + "https://agent-host.com/cloud-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676/schema" ) ) diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/IssueCredentialRecordPage.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/IssueCredentialRecordPage.scala index dfc3a94ab0..7db33c1f0c 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/IssueCredentialRecordPage.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/IssueCredentialRecordPage.scala @@ -70,27 +70,27 @@ object IssueCredentialRecordPage { object self extends Annotation[String]( description = "The URL that uniquely identifies the resource being returned in the response.", - example = "/prism-agent/issue-credentials/records?offset=10&limit=10" + example = "/cloud-agent/issue-credentials/records?offset=10&limit=10" ) object pageOf extends Annotation[String]( description = "A string field indicating the type of resource that the contents field contains.", - example = "/prism-agent/issue-credentials/records" + example = "/cloud-agent/issue-credentials/records" ) object next extends Annotation[String]( description = "An optional string field containing the URL of the next page of results. If the API response does not contain any more pages, this field should be set to None.", - example = "/prism-agent/issue-credentials/records?offset=20&limit=10" + example = "/cloud-agent/issue-credentials/records?offset=20&limit=10" ) object previous extends Annotation[String]( description = "An optional string field containing the URL of the previous page of results. If the API response is the first page of results, this field should be set to None.", - example = "/prism-agent/issue-credentials/records?offset=0&limit=10" + example = "/cloud-agent/issue-credentials/records?offset=0&limit=10" ) } diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialdefinition/http/CredentialDefinitionResponse.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialdefinition/http/CredentialDefinitionResponse.scala index bb2c470672..23a65d25e9 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialdefinition/http/CredentialDefinitionResponse.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialdefinition/http/CredentialDefinitionResponse.scala @@ -135,7 +135,7 @@ object CredentialDefinitionResponse { object self extends Annotation[String]( description = "The URL that uniquely identifies the resource being returned in the response.", - example = "/prism-agent/credential-definition-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4" + example = "/cloud-agent/credential-definition-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4" ) object kind @@ -187,7 +187,7 @@ object CredentialDefinitionResponse { extends Annotation[Option[String]]( description = "The unique identifier of the schema used for this credential definition.", example = - Some("https://agent-host.com/prism-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676") + Some("https://agent-host.com/cloud-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676") ) object authored diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialdefinition/http/CredentialDefinitionResponsePage.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialdefinition/http/CredentialDefinitionResponsePage.scala index e1502c1213..789c810fb6 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialdefinition/http/CredentialDefinitionResponsePage.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialdefinition/http/CredentialDefinitionResponsePage.scala @@ -70,27 +70,27 @@ object CredentialDefinitionResponsePage { object self extends Annotation[String]( description = "A string field containing the URL of the current API endpoint", - example = "/prism-agent/credential-definition-registry/definitions?skip=10&limit=10" + example = "/cloud-agent/credential-definition-registry/definitions?skip=10&limit=10" ) object pageOf extends Annotation[String]( description = "A string field indicating the type of resource that the contents field contains", - example = "/prism-agent/credential-definition-registry/definitions" + example = "/cloud-agent/credential-definition-registry/definitions" ) object next extends Annotation[String]( description = "An optional string field containing the URL of the next page of results. " + "If the API response does not contain any more pages, this field should be set to None.", - example = "/prism-agent/credential-definition-registry/definitions?skip=20&limit=10" + example = "/cloud-agent/credential-definition-registry/definitions?skip=20&limit=10" ) object previous extends Annotation[String]( description = "An optional string field containing the URL of the previous page of results. " + "If the API response is the first page of results, this field should be set to None.", - example = "/prism-agent/credential-definition-registry/definitions?skip=0&limit=10" + example = "/cloud-agent/credential-definition-registry/definitions?skip=0&limit=10" ) } } diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/CredentialSchemaResponse.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/CredentialSchemaResponse.scala index ee53873913..1d0657cbdf 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/CredentialSchemaResponse.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/CredentialSchemaResponse.scala @@ -127,7 +127,7 @@ object CredentialSchemaResponse { object self extends Annotation[String]( description = "The URL that uniquely identifies the resource being returned in the response.", - example = "/prism-agent/schema-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4" + example = "/cloud-agent/schema-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4" ) object kind extends Annotation[String]( diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/CredentialSchemaResponsePage.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/CredentialSchemaResponsePage.scala index f54d7e8106..b5fc076b7a 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/CredentialSchemaResponsePage.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/CredentialSchemaResponsePage.scala @@ -64,27 +64,27 @@ object CredentialSchemaResponsePage { object self extends Annotation[String]( description = "A string field containing the URL of the current API endpoint", - example = "/prism-agent/schema-registry/schemas?skip=10&limit=10" + example = "/cloud-agent/schema-registry/schemas?skip=10&limit=10" ) object pageOf extends Annotation[String]( description = "A string field indicating the type of resource that the contents field contains", - example = "/prism-agent/schema-registry/schemas" + example = "/cloud-agent/schema-registry/schemas" ) object next extends Annotation[String]( description = "An optional string field containing the URL of the next page of results. " + "If the API response does not contain any more pages, this field should be set to None.", - example = "/prism-agent/schema-registry/schemas?skip=20&limit=10" + example = "/cloud-agent/schema-registry/schemas?skip=20&limit=10" ) object previous extends Annotation[String]( description = "An optional string field containing the URL of the previous page of results. " + "If the API response is the first page of results, this field should be set to None.", - example = "/prism-agent/schema-registry/schemas?skip=0&limit=10" + example = "/cloud-agent/schema-registry/schemas?skip=0&limit=10" ) } } diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/VerificationPolicyResponse.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/VerificationPolicyResponse.scala index df234f3098..80f96eea06 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/VerificationPolicyResponse.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/credentialschema/http/VerificationPolicyResponse.scala @@ -174,7 +174,7 @@ object VerificationPolicyResponse { object self extends Annotation[String]( description = "The URL that uniquely identifies the resource being returned in the response.", - example = "/prism-agent/verification/policies/0527aea1-d131-3948-a34d-03af39aba8b4" + example = "/cloud-agent/verification/policies/0527aea1-d131-3948-a34d-03af39aba8b4" ) object kind @@ -229,7 +229,7 @@ object VerificationPolicyResponse { } val example = VerificationPolicyResponse( - self = "/prism-agent/verification/policies", + self = "/cloud-agent/verification/policies", kind = "VerificationPolicy", id = UUID.fromString("0527aea1-d131-3948-a34d-03af39aba8b4"), nonce = 0, @@ -286,7 +286,7 @@ object VerificationPolicyResponsePage { object self extends Annotation[String]( description = "The URL that uniquely identifies the resource being returned in the response.", - example = "/prism-agent/verification/policies?name=Trusted&offset=0&limit=10" + example = "/cloud-agent/verification/policies?name=Trusted&offset=0&limit=10" ) object kind @@ -298,21 +298,21 @@ object VerificationPolicyResponsePage { object pageOf extends Annotation[String]( description = "A string field indicating the type of resource that the contents field contains", - example = "/prism-agent/verification/policies" + example = "/cloud-agent/verification/policies" ) object next extends Annotation[String]( description = "An optional string field containing the URL of the next page of results. " + "If the API response does not contain any more pages, this field should be set to None.", - example = "/prism-agent/verification/policies?skip=20&limit=10" + example = "/cloud-agent/verification/policies?skip=20&limit=10" ) object previous extends Annotation[String]( description = "An optional string field containing the URL of the previous page of results. " + "If the API response is the first page of results, this field should be set to None.", - example = "/prism-agent/verification/policies?skip=0&limit=10" + example = "/cloud-agent/verification/policies?skip=0&limit=10" ) object contents extends Annotation[Seq[VerificationPolicyResponse]]( @@ -323,11 +323,11 @@ object VerificationPolicyResponsePage { } val example = VerificationPolicyResponsePage( - self = "/prism-agent/verification/policies?name=Trusted&offset=0&limit=10", + self = "/cloud-agent/verification/policies?name=Trusted&offset=0&limit=10", kind = "VerificationPolicyPage", - pageOf = "/prism-agent/verification/policies", - next = Some("/prism-agent/verification/policies?skip=20&limit=10"), - previous = Some("/prism-agent/verification/policies?skip=0&limit=10"), + pageOf = "/cloud-agent/verification/policies", + next = Some("/cloud-agent/verification/policies?skip=20&limit=10"), + previous = Some("/cloud-agent/verification/policies?skip=0&limit=10"), contents = List(VerificationPolicyResponse.example) ) } diff --git a/docs/docusaurus/connections/connection.md b/docs/docusaurus/connections/connection.md index f33368bb89..488295856d 100644 --- a/docs/docusaurus/connections/connection.md +++ b/docs/docusaurus/connections/connection.md @@ -85,7 +85,7 @@ The following example demonstrates how you could use two Cloud Agent APIs to set ```shell curl -X 'POST' \ - 'http://localhost:8080/prism-agent/connections' \ + 'http://localhost:8080/cloud-agent/connections' \ -H 'Content-Type: application/json' \ -H "apikey: $API_KEY" \ -d '{ "label": "Connect with Alice" }' | jq @@ -114,7 +114,7 @@ Example response: Replace `{RAW_INVITATION}` with the value of the '_oob' query string parameter from the invitation URL above ```shell curl -X 'POST' \ - 'http://localhost:8090/prism-agent/connection-invitations' \ + 'http://localhost:8090/cloud-agent/connection-invitations' \ -H 'Content-Type: application/json' \ -H "apikey: $API_KEY" \ -d '{ "invitation": "{RAW_INVITATION}" }' | jq @@ -143,7 +143,7 @@ Example response: ### Invitee retrieves the list of connections ```shell -curl -X 'GET' 'http://localhost:8090/prism-agent/connections' \ +curl -X 'GET' 'http://localhost:8090/cloud-agent/connections' \ -H "apikey: $API_KEY" | jq ``` @@ -176,7 +176,7 @@ Example output: ### Inviter retrieves the list of connections ```shell -curl -X 'GET' 'http://localhost:8080/prism-agent/connections' \ +curl -X 'GET' 'http://localhost:8080/cloud-agent/connections' \ -H "apikey: $API_KEY" | jq ``` diff --git a/docs/docusaurus/credentialdefinition/create.md b/docs/docusaurus/credentialdefinition/create.md index f2a39bcb25..653e7eb6fc 100644 --- a/docs/docusaurus/credentialdefinition/create.md +++ b/docs/docusaurus/credentialdefinition/create.md @@ -23,7 +23,7 @@ Here's a sample content of the credential definition: "version": "1.0.0", "tag": "Licence", "author": "{{ISSUER_DID_SHORT}}", - "schemaId": "http://host.docker.internal:8080/prism-agent/schema-registry/schemas/{{SCHEMA_ID}}", + "schemaId": "http://host.docker.internal:8080/cloud-agent/schema-registry/schemas/{{SCHEMA_ID}}", "signatureType": "CL", "supportRevocation": true } @@ -46,7 +46,7 @@ Please note: The `author` field value should align with the short form of a PRIS "version": "1.0.0", "tag": "Licence", "author": "{{ISSUER_DID_SHORT}}", - "schemaId": "http://host.docker.internal:8080/prism-agent/schema-registry/schemas/{{SCHEMA_ID}}", + "schemaId": "http://host.docker.internal:8080/cloud-agent/schema-registry/schemas/{{SCHEMA_ID}}", "signatureType": "CL", "supportRevocation": true } @@ -70,7 +70,7 @@ curl -X 'POST' \ "version": "1.0.0", "tag": "Licence", "author": "{{ISSUER_DID_SHORT}}", - "schemaId": "http://host.docker.internal:8080/prism-agent/schema-registry/schemas/{{SCHEMA_ID}}", + "schemaId": "http://host.docker.internal:8080/cloud-agent/schema-registry/schemas/{{SCHEMA_ID}}", "signatureType": "CL", "supportRevocation": true } @@ -89,7 +89,7 @@ A potential response could be: "tag": "Licence", "author": "did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff", "authored": "2023-03-14T14:41:46.713943Z", - "schemaId": "http://host.docker.internal:8080/prism-agent/schema-registry/schemas/{{SCHEMA_ID}}", + "schemaId": "http://host.docker.internal:8080/cloud-agent/schema-registry/schemas/{{SCHEMA_ID}}", "signatureType": "CL", "supportRevocation": true, "kind": "CredentialDefinition", @@ -123,7 +123,7 @@ You should receive a response containing the JSON object representing the creden "tag": "Licence", "author": "did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff", "authored": "2023-03-14T14:41:46.713943Z", - "schemaId": "http://host.docker.internal:8080/prism-agent/schema-registry/schemas/{{SCHEMA_ID}}", + "schemaId": "http://host.docker.internal:8080/cloud-agent/schema-registry/schemas/{{SCHEMA_ID}}", "signatureType": "CL", "supportRevocation": true, "kind": "CredentialDefinition", diff --git a/docs/docusaurus/credentials/issue.md b/docs/docusaurus/credentials/issue.md index 6ce39431d8..936e038c78 100644 --- a/docs/docusaurus/credentials/issue.md +++ b/docs/docusaurus/credentials/issue.md @@ -87,7 +87,7 @@ To do this, make a `POST` request to the [`/issue-credentials/credential-offers` The Cloud Agent must be able to dereference the specified URL (i.e. fetch the VC schema content from it), in order to validate the provided claims against it. When not specified, the claims fields is not validated and can be any valid JSON object. Please refer to the [Create VC schema](../schemas/create.md) doc for details on how to create a VC schema. -5. `credentialFormat`: The format of the credential that will be issued - `JWT` in this case. When not specified, the default value is `JWT`. +5. `credentialFormat`: The format of the credential that will be issued - `JWT` in this case. When not specified, the default value is `JWT`. :::note @@ -99,7 +99,7 @@ Once the request initiates, a new credential record for the issuer gets created ```shell # Issuer POST request to create a new credential offer curl -X 'POST' \ - 'http://localhost:8080/prism-agent/issue-credentials/credential-offers' \ + 'http://localhost:8080/cloud-agent/issue-credentials/credential-offers' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -H "apikey: $API_KEY" \ @@ -115,7 +115,7 @@ curl -X 'POST' \ "credentialFormat": "JWT", "issuingDID": "did:prism:9f847f8bbb66c112f71d08ab39930d468ccbfe1e0e1d002be53d46c431212c26", "connectionId": "9d075518-f97e-4f11-9d10-d7348a7a0fda", - "schemaId": "http://localhost:8080/prism-agent/schema-registry/schemas/3f86a73f-5b78-39c7-af77-0c16123fa9c2" + "schemaId": "http://localhost:8080/cloud-agent/schema-registry/schemas/3f86a73f-5b78-39c7-af77-0c16123fa9c2" }' ``` @@ -136,7 +136,7 @@ Once the request initiates, a new credential record for the issuer gets created ```shell # Issuer POST request to create a new credential offer curl -X 'POST' \ - 'http://localhost:8080/prism-agent/issue-credentials/credential-offers' \ + 'http://localhost:8080/cloud-agent/issue-credentials/credential-offers' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -H "apikey: $API_KEY" \ @@ -177,7 +177,7 @@ The Issuer can then use the [`/issue-credentials/records/{recordId}/issue-creden # make sure you have `issuer_record_id` extracted from created credential offer # and the record achieved `RequestReceived` state curl -X POST \ - "http://localhost:8080/prism-agent/issue-credentials/records/$issuer_record_id/issue-credential" \ + "http://localhost:8080/cloud-agent/issue-credentials/records/$issuer_record_id/issue-credential" \ -H "Content-Type: application/json" \ -H "apikey: $API_KEY" ``` @@ -215,7 +215,7 @@ This process is automatic for the Cloud Agent. You could check if a new credential offer is available using [`/issue-credentials/records`](/#tag/Issue-Credentials-Protocol/operation/getCredentialRecords) request and check for any records available in `OfferReceived` state: ```shell # Holder GET request to retrieve credential records -curl "http://localhost:8090/prism-agent/issue-credentials/records" \ +curl "http://localhost:8090/cloud-agent/issue-credentials/records" \ -H "Content-Type: application/json" \ -H "apikey: $API_KEY" ``` @@ -233,7 +233,7 @@ To accept the offer, the Holder can make a `POST` request to the [`/issue-creden ```shell # Holder POST request to accept the credential offer -curl -X POST "http://localhost:8090/prism-agent/issue-credentials/records/$holder_record_id/accept-offer" \ +curl -X POST "http://localhost:8090/cloud-agent/issue-credentials/records/$holder_record_id/accept-offer" \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -H "apikey: $API_KEY" \ @@ -249,7 +249,7 @@ curl -X POST "http://localhost:8090/prism-agent/issue-credentials/records/$holde ```shell # Holder POST request to accept the credential offer -curl -X POST "http://localhost:8090/prism-agent/issue-credentials/records/$holder_record_id/accept-offer" \ +curl -X POST "http://localhost:8090/cloud-agent/issue-credentials/records/$holder_record_id/accept-offer" \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -H "apikey: $API_KEY" \ diff --git a/docs/docusaurus/credentials/present-proof.md b/docs/docusaurus/credentials/present-proof.md index 47be894982..f479ffbdb9 100644 --- a/docs/docusaurus/credentials/present-proof.md +++ b/docs/docusaurus/credentials/present-proof.md @@ -13,8 +13,8 @@ The protocol provides endpoints for a Verifier to request new proof presentation The present proof protocol has two roles: -1. Verifier: A subject requesting a proof presentation by sending a request presentation message, then verifying the presentation. -2. Holder/Prover: A [subject](/docs/concepts/glossary#subject) that receives a [proof presentation](/docs/concepts/glossary#proof-presentation) request, prepares a proof, and sends it to the verifier by sending a proof presentation message. +1. Verifier: A subject requesting a proof presentation by sending a request presentation message, then verifying the presentation. +2. Holder/Prover: A [subject](/docs/concepts/glossary#subject) that receives a [proof presentation](/docs/concepts/glossary#proof-presentation) request, prepares a proof, and sends it to the verifier by sending a proof presentation message. ## Prerequisites @@ -37,12 +37,12 @@ The protocol consists of the following main parts: ## Endpoints -| Endpoint | Method | Description | Role | -| --- | --- | --- | --- | -| [`/present-proof/presentations`](/agent-api/#tag/Present-Proof/operation/requestPresentation) | POST | Creates and sends a new proof presentation request. | Verifier | -| [`/present-proof/presentations`](/agent-api/#tag/Present-Proof/operation/getAllPresentation) | GET | Retrieves the collection of all the existing presentation proof records - sent or received. | Verifier, Holder/Prover | -| [`/present-proof/presentations/{id}`](/agent-api/#tag/Present-Proof/operation/getPresentation) | GET | Retrieves a specific presentation proof record by `id`. | Verifier, Holder/Prover | -| [`/present-proof/presentations/{id}`](/agent-api/#tag/Present-Proof/operation/updatePresentation) | PATCH | Updates an existing presentation proof record to, e.g., accept the request on the Holder/Prover side or accept the presentation on the Verifier side. | Verifier, Holder/Prover | +| Endpoint | Method | Description | Role | +|---------------------------------------------------------------------------------------------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------| +| [`/present-proof/presentations`](/agent-api/#tag/Present-Proof/operation/requestPresentation) | POST | Creates and sends a new proof presentation request. | Verifier | +| [`/present-proof/presentations`](/agent-api/#tag/Present-Proof/operation/getAllPresentation) | GET | Retrieves the collection of all the existing presentation proof records - sent or received. | Verifier, Holder/Prover | +| [`/present-proof/presentations/{id}`](/agent-api/#tag/Present-Proof/operation/getPresentation) | GET | Retrieves a specific presentation proof record by `id`. | Verifier, Holder/Prover | +| [`/present-proof/presentations/{id}`](/agent-api/#tag/Present-Proof/operation/updatePresentation) | PATCH | Updates an existing presentation proof record to, e.g., accept the request on the Holder/Prover side or accept the presentation on the Verifier side. | Verifier, Holder/Prover | :::info For more detailed information, please, check the full [Cloud Agent API](/agent-api). @@ -64,10 +64,10 @@ To do this, he makes a `POST` request to the [`/present-proof/presentations`](/a ```bash -curl -X 'POST' 'http://localhost:8070/prism-agent/present-proof/presentations' \ +curl -X 'POST' 'http://localhost:8070/cloud-agent/present-proof/presentations' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ - -H "apikey: $API_KEY" \ + -H "apikey: $API_KEY" \ -d '{ "connectionId": "872ddfa9-4115-46c2-8a1b-22c24c7431d7", "proofs":[], @@ -82,10 +82,10 @@ curl -X 'POST' 'http://localhost:8070/prism-agent/present-proof/presentations' \ ```bash -curl -X 'POST' 'http://localhost:8070/prism-agent/present-proof/presentations' \ +curl -X 'POST' 'http://localhost:8070/cloud-agent/present-proof/presentations' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ - -H "apikey: $API_KEY" \ + -H "apikey: $API_KEY" \ -d '{ "connectionId": "872ddfa9-4115-46c2-8a1b-22c24c7431d7", "anoncredPresentationRequest": { @@ -132,9 +132,9 @@ Upon execution, a new presentation request record gets created with an initial s The Verifier can retrieve the list of presentation records by making a `GET` request to the [`/present-proof/presentations`](/agent-api/#tag/Present-Proof/operation/getAllPresentation) endpoint: ```bash -curl -X 'GET' 'http://localhost:8070/prism-agent/present-proof/presentations' \ +curl -X 'GET' 'http://localhost:8070/cloud-agent/present-proof/presentations' \ -H 'accept: application/json' \ - -H "apikey: $API_KEY" + -H "apikey: $API_KEY" ``` ### Accept presentation proof received from the Holder/prover @@ -143,7 +143,7 @@ Once the Holder/Prover has received a proof presentation request, he can accept The Verifier can then explicitly accept the specific verified proof presentation to change the record state to `PresentationAccepted` by making a `PATCH` request to the [`/present-proof/presentations/{id}`](/agent-api/#tag/Present-Proof/operation/updatePresentation) endpoint: ```bash -curl -X 'PATCH' 'http://localhost:8070/prism-agent/present-proof/presentations/{PRESENTATION_ID}' \ +curl -X 'PATCH' 'http://localhost:8070/cloud-agent/present-proof/presentations/{PRESENTATION_ID}' \ -H 'Content-Type: application/json' \ -H "apikey: $API_KEY" \ -d '{ @@ -170,7 +170,7 @@ This section describes the interactions available to the Holder/Prover with his The Holder/Prover can retrieve the list of presentation requests received by its Cloud Agent from different Verifiers making a `GET` request to the [`/present-proof/presentations`](/agent-api/#tag/Present-Proof/operation/getAllPresentation) endpoint: ```bash -curl -X 'GET' 'http://localhost:8090/prism-agent/present-proof/presentations' \ +curl -X 'GET' 'http://localhost:8090/cloud-agent/present-proof/presentations' \ -H 'accept: application/json' \ -H "apikey: $API_KEY" ``` @@ -181,7 +181,7 @@ The Holder/Prover can then accept a specific request, generate the proof, and se ```bash -curl -X 'PATCH' 'http://localhost:8090/prism-agent/present-proof/presentations/{PRESENTATION_ID}' \ +curl -X 'PATCH' 'http://localhost:8090/cloud-agent/present-proof/presentations/{PRESENTATION_ID}' \ -H 'Content-Type: application/json' \ -H "apikey: $API_KEY" \ -d '{ @@ -198,7 +198,7 @@ The Holder/Prover will have to provide the following information: ```bash -curl -X 'PATCH' 'http://localhost:8090/prism-agent/present-proof/presentations/{PRESENTATION_ID}' \ +curl -X 'PATCH' 'http://localhost:8090/cloud-agent/present-proof/presentations/{PRESENTATION_ID}' \ -H 'Content-Type: application/json' \ -H "apikey: $API_KEY" \ -d '{ @@ -224,7 +224,7 @@ curl -X 'PATCH' 'http://localhost:8090/prism-agent/present-proof/presentations/{ The Holder/Prover will have to provide the following information: 1. `presentationId`: The unique identifier of the presentation record to accept. 2. `anoncredPresentationRequest`: A list of credential unique identifier with the attribute and predicate the credential is answering for. - + The record state is updated to `PresentationPending` and processed by the Holder/Prover Cloud Agent. The agent will automatically generate the proof presentation, change the state to `PresentationGenerated`, and will eventually send it to the Verifier Agent, and change the state to `PresentationSent`. ```mermaid @@ -240,7 +240,7 @@ stateDiagram-v2 ## Sequence diagram -The following diagram shows the end-to-end flow for a verifier to request and verify a proof presentation from a Holder/prover. +The following diagram shows the end-to-end flow for a verifier to request and verify a proof presentation from a Holder/prover. ### JWT Present Proof Flow Diagram ![](present-proof-flow.png) diff --git a/docs/docusaurus/credentials/revocation.md b/docs/docusaurus/credentials/revocation.md index ce1ee9baa0..997a66f4ac 100644 --- a/docs/docusaurus/credentials/revocation.md +++ b/docs/docusaurus/credentials/revocation.md @@ -8,11 +8,11 @@ Every credential will contain the property `credentialStatus`, which will look l ```json "credentialStatus": { - "id": "http://localhost:8080/prism-agent/prism-agent/credential-status/27526236-3836-4061-9867-f69314e258b4#94567" + "id": "http://localhost:8080/cloud-agent/cloud-agent/credential-status/27526236-3836-4061-9867-f69314e258b4#94567" "type": "StatusList2021Entry", "statusPurpose": "revocation", "statusListIndex": "94567", - "statusListCredential": "http://localhost:8080/prism-agent/prism-agent/credential-status/27526236-3836-4061-9867-f69314e258b4" + "statusListCredential": "http://localhost:8080/cloud-agent/cloud-agent/credential-status/27526236-3836-4061-9867-f69314e258b4" }, ``` @@ -36,7 +36,7 @@ Every credential will contain the property `credentialStatus`, which will look l "VerifiableCredential", "StatusList2021Credential" ], - "id" : "http://localhost:8080/prism-agent/credential-status/27526236-3836-4061-9867-f69314e258b4", + "id" : "http://localhost:8080/cloud-agent/credential-status/27526236-3836-4061-9867-f69314e258b4", "issuer" : "did:prism:462c4811bf61d7de25b3baf86c5d2f0609b4debe53792d297bf612269bf8593a", "issuanceDate" : 1711212350, "credentialSubject" : { @@ -69,12 +69,12 @@ Status list credential integrity can be verified using the embedded proof of typ ## Revocation -Only issuers of a credential can revoke a credential. +Only issuers of a credential can revoke a credential. *Get the list of credentials* ```bash curl -X 'GET' \ - 'http://localhost:8080/prism-agent/issue-credentials/records' \ + 'http://localhost:8080/cloud-agent/issue-credentials/records' \ -H 'accept: application/json' ``` This endpoint will return the credentials issued. Every credential includes an ID. @@ -82,7 +82,7 @@ This endpoint will return the credentials issued. Every credential includes an I *Revoke the credential* ```bash curl -X 'PATCH' \ - 'http://localhost:8080/prism-agent/revoke-credential/' \ + 'http://localhost:8080/cloud-agent/revoke-credential/' \ -H 'accept: */*' ``` diff --git a/docs/docusaurus/dids/create.md b/docs/docusaurus/dids/create.md index b8e616d288..2496a3a13e 100644 --- a/docs/docusaurus/dids/create.md +++ b/docs/docusaurus/dids/create.md @@ -45,7 +45,7 @@ The example uses the following endpoints ### 1. Check existing DID on the Cloud Agent ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/did-registrar/dids' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/did-registrar/dids' \ --header "apikey: $API_KEY" \ --header 'Accept: application/json' ``` @@ -58,7 +58,7 @@ Since key pairs are generated and managed by the Cloud Agent, DID controller onl The current PRISM DID method supports a key with a single purpose, but it is extendible to support a key with multiple purposes in the future. ```bash -curl --location --request POST 'http://localhost:8080/prism-agent/did-registrar/dids' \ +curl --location --request POST 'http://localhost:8080/cloud-agent/did-registrar/dids' \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ --header "apikey: $API_KEY" \ @@ -97,8 +97,8 @@ Check the `GET /did-registrar/dids` endpoint. The response should return a list } ], "kind": "ManagedDIDPage", - "pageOf": "http://localhost:8080/prism-agent/did-registrar/dids", - "self": "http://localhost:8080/prism-agent/did-registrar/dids" + "pageOf": "http://localhost:8080/cloud-agent/did-registrar/dids", + "self": "http://localhost:8080/cloud-agent/did-registrar/dids" } ``` @@ -110,7 +110,7 @@ Replacing the `{didRef}` with the long-form DID, and the response should return Replacing the `{didRef}` with the short-form DID, and the resolution should fail since the DID still needs to be published. ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/dids/{didRef}' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/dids/{didRef}' \ --header "apikey: $API_KEY" \ --header 'Accept: */*' ``` diff --git a/docs/docusaurus/dids/deactivate.md b/docs/docusaurus/dids/deactivate.md index 9fb1ac4918..e6527a62fc 100644 --- a/docs/docusaurus/dids/deactivate.md +++ b/docs/docusaurus/dids/deactivate.md @@ -45,7 +45,7 @@ The example uses the following endpoints Given the DID Controller has a DID managed by the Cloud Agent and that DID is published, he can resolve the DID document using short-form DID. ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/dids/{didRef}' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/dids/{didRef}' \ --header "apikey: $API_KEY" \ --header 'Accept: */*' ``` @@ -71,7 +71,7 @@ The active status comes from the last step. The DID deactivation can be performed by calling `POST /did-registrar/dids/{didRef}/deactivations` and replacing `{didRef}` with the DID to deactivate. ```bash -curl --location --request POST 'http://localhost:8080/prism-agent/did-registrar/dids/{didRef}/deactivations' \ +curl --location --request POST 'http://localhost:8080/cloud-agent/did-registrar/dids/{didRef}/deactivations' \ --header "apikey: $API_KEY" \ --header 'Accept: application/json' ``` diff --git a/docs/docusaurus/dids/publish.md b/docs/docusaurus/dids/publish.md index b233cbc19a..90da0dde4a 100644 --- a/docs/docusaurus/dids/publish.md +++ b/docs/docusaurus/dids/publish.md @@ -49,7 +49,7 @@ The `{didRef}` path segment can be either short-form or long-form DID. When a DID gets created and not published, it has the status of `CREATED`. ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/did-registrar/dids/{didRef}' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/did-registrar/dids/{didRef}' \ --header "apikey: $API_KEY" \ --header 'Accept: application/json' ``` @@ -68,7 +68,7 @@ Example response To publish a DID, use DID Controller `POST` a request to `/did-registrar/dids/{didRef}/publications` endpoint. ```bash -curl --location --request POST 'http://localhost:8080/prism-agent/did-registrar/dids/{didRef}/publications' \ +curl --location --request POST 'http://localhost:8080/cloud-agent/did-registrar/dids/{didRef}/publications' \ --header "apikey: $API_KEY" \ --header 'Accept: application/json' ``` @@ -127,7 +127,7 @@ To confirm that the short-form DID is resolvable, test the DID against the resol Replace `{didRef}` with the short-form DID; the response should return a DID document. ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/dids/{didRef}' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/dids/{didRef}' \ --header "apikey: $API_KEY" \ --header 'Accept: */*' ``` diff --git a/docs/docusaurus/dids/update.md b/docs/docusaurus/dids/update.md index 22fb55c7fd..b3e5e6760f 100644 --- a/docs/docusaurus/dids/update.md +++ b/docs/docusaurus/dids/update.md @@ -62,7 +62,7 @@ The example uses the following endpoints Given the DID Controller has a DID on the Cloud Agent and that DID is published, he can resolve the DID document using short-form DID. ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/dids/{didRef}' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/dids/{didRef}' \ --header "apikey: $API_KEY" \ --header 'Accept: */*' ``` @@ -104,7 +104,7 @@ The DID Controller wishes to remove that key and add a new key called `key-2` The DID Controller submits a DID update request to `POST /did-registrar/dids/{didRef}/updates`. ```bash -curl --location --request POST 'http://localhost:8080/prism-agent/did-registrar/dids/did:prism:4262377859267f308a06ec6acf211fbe4d6745aa9e637e04548771169616fb86/updates' \ +curl --location --request POST 'http://localhost:8080/cloud-agent/did-registrar/dids/did:prism:4262377859267f308a06ec6acf211fbe4d6745aa9e637e04548771169616fb86/updates' \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ --header "apikey: $API_KEY" \ diff --git a/docs/docusaurus/index.md b/docs/docusaurus/index.md index 45301dd870..e483a47ee5 100644 --- a/docs/docusaurus/index.md +++ b/docs/docusaurus/index.md @@ -9,14 +9,14 @@ Whether you are new to [self-sovereign identity (SSI)](/docs/concepts/glossary#s Throughout all code examples in tutorials, the following conventions are in use: * Issuer Keycloak is hosted at `http://localhost:9980/` -* Issuer Agent is hosted at `http://localhost:8080/prism-agent/` -* Holder Agent is hosted at `http://localhost:8090/prism-agent/` -* Verifier Agent is hosted at `http://localhost:8100/prism-agent/` +* Issuer Agent is hosted at `http://localhost:8080/cloud-agent/` +* Holder Agent is hosted at `http://localhost:8090/cloud-agent/` +* Verifier Agent is hosted at `http://localhost:8100/cloud-agent/` :::info To use the Identus Cloud Agents, you must include an `apiKey` header in your requests. You can configure the key, and in some instances, it will be provided to you, so make sure to create an environment variable with the proper value. ```shell export API_KEY= ``` -Alternatively, replace `$API_KEY` with your key in the CURL commands supplied throughout this tutorial. ::: +Alternatively, replace `$API_KEY` with your key in the CURL commands supplied throughout this tutorial. ::: diff --git a/docs/docusaurus/multitenancy/admin-authz-ext-iam.md b/docs/docusaurus/multitenancy/admin-authz-ext-iam.md index 28ab7e4025..983b50f3c5 100644 --- a/docs/docusaurus/multitenancy/admin-authz-ext-iam.md +++ b/docs/docusaurus/multitenancy/admin-authz-ext-iam.md @@ -18,16 +18,16 @@ The same person may also represent these roles. 1. Keycloak is up and running 2. Keycloak is configured as follows 1. A realm called `my-realm` is created - 2. A client called `prism-agent` under `my-realm` with __authorization__ feature is created. (See [create client instruction](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_server_create_client)) - 3. Make sure the `prism-agent` client has __direct access grants__ enabled to simplify the login + 2. A client called `cloud-agent` under `my-realm` with __authorization__ feature is created. (See [create client instruction](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_server_create_client)) + 3. Make sure the `cloud-agent` client has __direct access grants__ enabled to simplify the login 3. The Cloud Agent is up and running 4. The Cloud Agent is configured with the following environment variables: 1. `KEYCLOAK_ENABLED=true` 2. `KEYCLOAK_URL=http://localhost:9980` (replace with appropriate value) 3. `KEYCLOAK_REALM=my-realm` - 4. `KEYCLOAK_CLIENT_ID=prism-agent` + 4. `KEYCLOAK_CLIENT_ID=cloud-agent` 5. `KEYCLOAK_CLIENT_SECRET=` (replace with appropriate value) - 6. `KEYCLOAL_ROLES_CLAIM_PATH=resource_access.prism-agent.roles` + 6. `KEYCLOAL_ROLES_CLAIM_PATH=resource_access.cloud-agent.roles` ## Overview @@ -42,14 +42,14 @@ Despite UMA permissions configured for the user, the agent strictly maintains a ## Endpoints ### Agent endpoints -| Endpoint | Description | Role | -|--------------------------------------------|-------------------------------------|---------------| -| `GET /wallets` | List the wallets on the Cloud Agent | Administrator | +| Endpoint | Description | Role | +|----------------|-------------------------------------|---------------| +| `GET /wallets` | List the wallets on the Cloud Agent | Administrator | ### Keycloak endpoints -| Endpoint | Description | Role | -|------------------------------------------------------|-------------------------------|--------------| -| `POST /realms/{realm}/protocol/openid-connect/token` | Issue a new JWT token | Administrator| +| Endpoint | Description | Role | +|------------------------------------------------------|-----------------------|---------------| +| `POST /realms/{realm}/protocol/openid-connect/token` | Issue a new JWT token | Administrator | ## Keycloak Administrator interactions @@ -109,7 +109,7 @@ Inspecting the `access_token` payload, it should have the following content ```json { "resource_access": { - "prism-agent": { + "cloud-agent": { "roles": [ "admin" ] @@ -132,7 +132,7 @@ To prove that the admin can perform admin tasks, try listing all the tenants' wallets using the JWT in the `Authorization` header. ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/wallets' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/wallets' \ -H 'Authorization: Bearer eyJhbGciOi...e7H6W8RUvA' \ -H 'Accept: application/json' ``` diff --git a/docs/docusaurus/multitenancy/tenant-migration.md b/docs/docusaurus/multitenancy/tenant-migration.md index 2f0cfd94f0..7be06751dc 100644 --- a/docs/docusaurus/multitenancy/tenant-migration.md +++ b/docs/docusaurus/multitenancy/tenant-migration.md @@ -50,7 +50,7 @@ To find the wallet, list them using `apikey`. ```bash curl -X 'GET' \ - 'http://localhost:8080/prism-agent/wallets' \ + 'http://localhost:8080/cloud-agent/wallets' \ -H 'accept: application/json' \ -H "apikey: my-tenant-token" ``` @@ -126,7 +126,7 @@ To do this, invoke the `POST /wallets/{walletId}/uma-permissions` endpoint on th ```bash curl -X 'POST' \ - 'http://localhost:8080/prism-agent/wallets/99734c87-5c9d-4697-b5fd-dea4e9590ba7/uma-permissions' \ + 'http://localhost:8080/cloud-agent/wallets/99734c87-5c9d-4697-b5fd-dea4e9590ba7/uma-permissions' \ -v \ -H 'accept: */*' \ -H "apikey: my-tenant-token" \ @@ -147,7 +147,7 @@ List the wallet using a new `Authorization` header. The listed wallets should co ```bash curl -X 'GET' \ - 'http://localhost:8080/prism-agent/wallets' \ + 'http://localhost:8080/cloud-agent/wallets' \ -H 'accept: application/json' \ -H 'Authorization: Bearer eyJhbGciOi...7ocDHofUDQ' ``` diff --git a/docs/docusaurus/multitenancy/tenant-onboarding-ext-iam.md b/docs/docusaurus/multitenancy/tenant-onboarding-ext-iam.md index ce0c7d8e49..61aee50ac5 100644 --- a/docs/docusaurus/multitenancy/tenant-onboarding-ext-iam.md +++ b/docs/docusaurus/multitenancy/tenant-onboarding-ext-iam.md @@ -19,8 +19,8 @@ In tenant management with external IAM, there are 2 roles: 1. Keycloak up and running 2. Keycloak is configured as follows 1. A realm called `my-realm` is created - 2. A client called `prism-agent` under `my-realm` with __authorization__ feature is created. (See [create client instruction](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_server_create_client)) - 3. Make sure the `prism-agent` client has __direct access grants__ enabled to simplify the login process for this tutorial + 2. A client called `cloud-agent` under `my-realm` with __authorization__ feature is created. (See [create client instruction](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_server_create_client)) + 3. Make sure the `cloud-agent` client has __direct access grants__ enabled to simplify the login process for this tutorial 3. the Cloud Agent is up and running 4. the Cloud Agent is configured with the following environment variables: 1. `ADMIN_TOKEN=my-admin-token` @@ -28,7 +28,7 @@ In tenant management with external IAM, there are 2 roles: 3. `KEYCLOAK_ENABLED=true` 4. `KEYCLOAK_URL=http://localhost:9980` (replace with appropriate value) 5. `KEYCLOAK_REALM=my-realm` - 6. `KEYCLOAK_CLIENT_ID=prism-agent` + 6. `KEYCLOAK_CLIENT_ID=cloud-agent` 7. `KEYCLOAK_CLIENT_SECRET=` (replace with appropriate value) 8. `KEYCLOAK_UMA_AUTO_UPGRADE_RPT=false` @@ -75,7 +75,7 @@ Listing wallets on it should return empty results. ```bash curl -X 'GET' \ - 'http://localhost:8080/prism-agent/wallets' \ + 'http://localhost:8080/cloud-agent/wallets' \ -H 'accept: application/json' \ -H 'x-admin-api-key: my-admin-token' ``` @@ -100,7 +100,7 @@ Provide a wallet seed during the wallet creation or let the Agent generate one ```bash curl -X 'POST' \ - 'http://localhost:8080/prism-agent/wallets' \ + 'http://localhost:8080/cloud-agent/wallets' \ -H 'accept: application/json' \ -H 'x-admin-api-key: my-admin-token' \ -H 'Content-Type: application/json' \ @@ -196,7 +196,7 @@ This can be done by invoking the `POST /wallets/{walletId}/uma-permissions` endp ```bash curl -X 'POST' \ - 'http://localhost:8080/prism-agent/wallets/99734c87-5c9d-4697-b5fd-dea4e9590ba7/uma-permissions' \ + 'http://localhost:8080/cloud-agent/wallets/99734c87-5c9d-4697-b5fd-dea4e9590ba7/uma-permissions' \ -v \ -H 'accept: */*' \ -H 'x-admin-api-key: my-admin-token' \ @@ -258,7 +258,7 @@ curl -X POST \ 'http://localhost:9980/realms/my-realm/protocol/openid-connect/token' \ -H "Authorization: Bearer eyJhbGciOi...7ocDHofUDQ" \ -d "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \ - -d "audience=prism-agent" + -d "audience=cloud-agent" ``` Example token response (some fields omitted for readability) @@ -297,7 +297,7 @@ To prove that the tenant can access the wallet using RPT, try listing the DIDs in the wallet using RPT in the `Authorization` header. ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/did-registrar/dids' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/did-registrar/dids' \ -H 'Authorization: Bearer eyJhbGciOi...e7H6W8RUvA' \ -H 'Accept: application/json' ``` diff --git a/docs/docusaurus/multitenancy/tenant-onboarding-self-service.md b/docs/docusaurus/multitenancy/tenant-onboarding-self-service.md index d6b8fe91e7..3bdbef2e01 100644 --- a/docs/docusaurus/multitenancy/tenant-onboarding-self-service.md +++ b/docs/docusaurus/multitenancy/tenant-onboarding-self-service.md @@ -22,8 +22,8 @@ In self-service tenant management with external IAM, there is only one role: 1. Keycloak is up and running. 2. Keycloak is configured as follows 1. A realm called `my-realm` is created - 2. A client called `prism-agent` under `my-realm` with __authorization__ feature is created. (See [create client instruction](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_server_create_client)) - 3. Make sure the `prism-agent` client has __direct access grants__ enabled to simplify the login process for this tutorial. + 2. A client called `cloud-agent` under `my-realm` with __authorization__ feature is created. (See [create client instruction](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_server_create_client)) + 3. Make sure the `cloud-agent` client has __direct access grants__ enabled to simplify the login process for this tutorial. 4. Make sure to [allow user self-registration](https://www.keycloak.org/docs/latest/server_admin/index.html#con-user-registration_server_administration_guide). 3. The Cloud Agent is up and running 4. The Cloud Agent is configured with the following environment variables: @@ -32,7 +32,7 @@ In self-service tenant management with external IAM, there is only one role: 3. `KEYCLOAK_ENABLED=true` 4. `KEYCLOAK_URL=http://localhost:9980` (replace with appropriate value) 5. `KEYCLOAK_REALM=my-realm` - 6. `KEYCLOAK_CLIENT_ID=prism-agent` + 6. `KEYCLOAK_CLIENT_ID=cloud-agent` 7. `KEYCLOAK_CLIENT_SECRET=` (replace with appropriate value) 8. `KEYCLOAK_UMA_AUTO_UPGRADE_RPT=true` @@ -102,7 +102,7 @@ Listing wallets on it should return empty results. ```bash curl -X 'GET' \ - 'http://localhost:8080/prism-agent/wallets' \ + 'http://localhost:8080/cloud-agent/wallets' \ -H 'Authorization: Bearer eyJhbGciOi...7ocDHofUDQ' \ -H 'Accept: application/json' ``` @@ -130,7 +130,7 @@ If the user already has the wallet associated, the wallet creation will fail as ```bash curl -X 'POST' \ - 'http://localhost:8080/prism-agent/wallets' \ + 'http://localhost:8080/cloud-agent/wallets' \ -H 'Authorization: Bearer eyJhbGciOi...7ocDHofUDQ' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ @@ -159,7 +159,7 @@ Without further operation, the wallet should be available for the tenant. To prove that the tenant can access the wallet, list the DIDs using RPT in the `Authorization` header. ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/did-registrar/dids' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/did-registrar/dids' \ -H 'Authorization: Bearer eyJhbGciOi...7ocDHofUDQ' \ -H 'Accept: application/json' ``` diff --git a/docs/docusaurus/multitenancy/tenant-onboarding.md b/docs/docusaurus/multitenancy/tenant-onboarding.md index 55fc98c41a..815b162b50 100644 --- a/docs/docusaurus/multitenancy/tenant-onboarding.md +++ b/docs/docusaurus/multitenancy/tenant-onboarding.md @@ -48,7 +48,7 @@ Listing wallets on it should return empty results. ```bash curl -X 'GET' \ - 'http://localhost:8080/prism-agent/wallets' \ + 'http://localhost:8080/cloud-agent/wallets' \ -H 'accept: application/json' \ -H 'x-admin-api-key: my-admin-token' ``` @@ -72,7 +72,7 @@ The wallet seed may be provided during the wallet creation or omitted to let the ```bash curl -X 'POST' \ - 'http://localhost:8080/prism-agent/wallets' \ + 'http://localhost:8080/cloud-agent/wallets' \ -H 'accept: application/json' \ -H 'x-admin-api-key: my-admin-token' \ -H 'Content-Type: application/json' \ @@ -100,7 +100,7 @@ To create a new entity, send a `POST` request to the `/iam/entities` endpoint wi ```bash curl -X 'POST' \ - 'http://localhost:8080/prism-agent/iam/entities' \ + 'http://localhost:8080/cloud-agent/iam/entities' \ -H 'accept: application/json' \ -H 'x-admin-api-key: my-admin-token' \ -H 'Content-Type: application/json' \ @@ -134,7 +134,7 @@ Once this step is completed, the administrator should provide the tenant with an ```bash curl -X 'POST' \ - 'http://localhost:8080/prism-agent/iam/apikey-authentication' \ + 'http://localhost:8080/cloud-agent/iam/apikey-authentication' \ -H 'accept: */*' \ -H 'x-admin-api-key: my-admin-token' \ -H 'Content-Type: application/json' \ @@ -158,7 +158,7 @@ To prove that the tenant can be authenticated as the created entity and use the try listing the DIDs in the wallet using `apikey` header. ```bash -curl --location --request GET 'http://localhost:8080/prism-agent/did-registrar/dids' \ +curl --location --request GET 'http://localhost:8080/cloud-agent/did-registrar/dids' \ --header "apikey: my-tenant-token" \ --header 'Accept: application/json' ``` diff --git a/docs/docusaurus/schemas/create.md b/docs/docusaurus/schemas/create.md index ef5e0d7ca1..edfd7454f3 100644 --- a/docs/docusaurus/schemas/create.md +++ b/docs/docusaurus/schemas/create.md @@ -67,7 +67,7 @@ For the above fields, the JSON Schema definition must be: The fields `$id` and `$schema` must correspond values that describe - the identity of the given JSON Schema as a **correctly formatted URL** `https://example.com/driving-license-1.0.0` and -- the meta schema fixed to `https://json-schema.org/draft/2020-12/schema` which is the only supported value +- the meta schema fixed to `https://json-schema.org/draft/2020-12/schema` which is the only supported value All the claims are listed under the `properties` object with corresponding `type`s and `format`s according to JSON Specification. @@ -79,7 +79,7 @@ Specification. 1. Open your preferred REST API client, such as Postman or Insomnia, or use the client stub generated based on the OpenAPI specification. -2. In the client, create a new POST request to the `/prism-agent/schema-registry/schemas` endpoint. +2. In the client, create a new POST request to the `/cloud-agent/schema-registry/schemas` endpoint. Note that the value of the `author` field must match the short form of a PRISM DID that has been created using the same agent. An unpublished DID is sufficient. Please refer to the [Create DID](../dids/create.md) documentation page for more details on how to create a PRISM DID. @@ -141,7 +141,7 @@ In the request body, create a JSON object: ```shell curl -X 'POST' \ - 'http://localhost:8080/prism-agent/schema-registry/schemas' \ + 'http://localhost:8080/cloud-agent/schema-registry/schemas' \ -H 'accept: application/json' \ -H "apikey: $API_KEY" \ -H 'Content-Type: application/json' \ @@ -254,13 +254,13 @@ curl -X 'POST' \ ### 3. Retrieve the created schema -To retrieve the newly created schema, create a new GET request to the `/prism-agent/schema-registry/schemas/{guid}` +To retrieve the newly created schema, create a new GET request to the `/cloud-agent/schema-registry/schemas/{guid}` endpoint, where `{guid}` is the GUID returned in the response from the previous step. Send the GET request to retrieve the schema. Curl example is the following: ```shell curl -X 'GET' \ - 'http://localhost:8080/prism-agent/schema-registry/schemas/3f86a73f-5b78-39c7-af77-0c16123fa9c2' \ + 'http://localhost:8080/cloud-agent/schema-registry/schemas/3f86a73f-5b78-39c7-af77-0c16123fa9c2' \ -H 'accept: application/json' \ -H "apikey: $API_KEY" ``` diff --git a/docs/docusaurus/schemas/update.md b/docs/docusaurus/schemas/update.md index abd60ed9b7..17010d13cc 100644 --- a/docs/docusaurus/schemas/update.md +++ b/docs/docusaurus/schemas/update.md @@ -108,13 +108,13 @@ The JSON Schema changes must be defined as follows: 1. Open your preferred REST API client, such as Postman or Insomnia, or use the client stub generated based on the OpenAPI specification. -2. In the client, create a new PUT request to the `/prism-agent/schema-registry/schemas/{id}` endpoint, where `id` is a +2. In the client, create a new PUT request to the `/cloud-agent/schema-registry/schemas/{id}` endpoint, where `id` is a locally unique credential schema id, formatted as a URL. -Note that the value of the `author` field must match the short form of a PRISM DID that has been created using the same agent. An unpublished DID is sufficient. Please refer to the [Create DID](../dids/create.md) documentation page for more details on how to create a PRISM DID. +Note that the value of the `author` field must match the short form of a PRISM DID that has been created using the same agent. An unpublished DID is sufficient. Please refer to the [Create DID](../dids/create.md) documentation page for more details on how to create a PRISM DID. In the request body, create a JSON object: - + ```json { "name": "driving-license", @@ -184,7 +184,7 @@ The curl example might be the following: ```shell curl -X 'PUT' \ - 'http://localhost:8080/prism-agent/schema-registry/schemas/f2bfbf78-8bd6-4cc6-8b39-b3a25e01e8ea' \ + 'http://localhost:8080/cloud-agent/schema-registry/schemas/f2bfbf78-8bd6-4cc6-8b39-b3a25e01e8ea' \ -H 'accept: application/json' \ -H "apikey: $API_KEY" \ -H 'Content-Type: application/json' \ diff --git a/docs/docusaurus/webhooks/webhook.md b/docs/docusaurus/webhooks/webhook.md index 25069f484d..511caf06d1 100644 --- a/docs/docusaurus/webhooks/webhook.md +++ b/docs/docusaurus/webhooks/webhook.md @@ -64,7 +64,7 @@ For each individual wallet, users can create a new webhook by making a POST requ which in turn creates a new webhook resource specific to their wallet. ```bash -curl --location --request POST 'http://localhost:8080/prism-agent/events/webhooks' \ +curl --location --request POST 'http://localhost:8080/cloud-agent/events/webhooks' \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ --header "apiKey: $API_KEY" \ diff --git a/docs/guides/linting.md b/docs/guides/linting.md index dc26ac5f23..812ae396c3 100644 --- a/docs/guides/linting.md +++ b/docs/guides/linting.md @@ -128,7 +128,7 @@ Linter - Suggested Change: Customise In /github/workspace/infrastructure/dev/get-versions.sh line 8: - export AGENT_VERSION=$(cd ../../prism-agent/service && sbt "project server" -Dsbt.supershell=false -error "print version") + export AGENT_VERSION=$(cd ../../cloud-agent/service && sbt "project server" -Dsbt.supershell=false -error "print version") ^-----------------^ SC2155 (warning): Declare and assign separately to avoid masking return values. For more information: diff --git a/infrastructure/charts/agent/templates/apisixroute.yaml b/infrastructure/charts/agent/templates/apisixroute.yaml index 47f1f5a0b9..b45ad9a7ea 100644 --- a/infrastructure/charts/agent/templates/apisixroute.yaml +++ b/infrastructure/charts/agent/templates/apisixroute.yaml @@ -16,6 +16,7 @@ spec: {{- end }} paths: - /prism-agent/* + - /cloud-agent/* backends: - serviceName: agent-server-tapir-service servicePort: 8085 @@ -26,7 +27,7 @@ spec: - name: proxy-rewrite enable: true config: - regex_uri: ["^/prism-agent/(.*)","/$1"] + regex_uri: ["^/(prism-agent|cloud-agent)/(.*)","/$2"] - name: uri-blocker enable: true config: @@ -56,6 +57,7 @@ spec: {{- end }} paths: - /prism-agent/didcomm* + - /cloud-agent/didcomm* backends: - serviceName: agent-server-didcomm-service servicePort: 8090 @@ -63,7 +65,7 @@ spec: - name: proxy-rewrite enable: true config: - regex_uri: ["^/prism-agent/didcomm(.*)", "/$1"] + regex_uri: ["^/(prism-agent|cloud-agent)/didcomm(.*)", "/$2"] {{ template "cors" . }} {{ template "headers.requestId" . }} {{ template "headers.security" . }} @@ -87,6 +89,7 @@ spec: {{- end }} paths: - /prism-agent/schema-registry/schemas/* + - /cloud-agent/schema-registry/schemas/* methods: - GET backends: @@ -96,7 +99,7 @@ spec: - name: proxy-rewrite enable: true config: - regex_uri: ["^/prism-agent/schema-registry/schemas/(.*)", "/schema-registry/schemas/$1"] + regex_uri: ["^/(prism-agent|cloud-agent)/schema-registry/schemas/(.*)", "/schema-registry/schemas/$2"] {{ template "cors" . }} {{ template "headers.requestId" . }} {{ template "headers.security" . }} @@ -120,6 +123,7 @@ spec: {{- end }} paths: - /prism-agent/credential-definition-registry/definitions/* + - /cloud-agent/credential-definition-registry/definitions/* methods: - GET backends: @@ -129,7 +133,7 @@ spec: - name: proxy-rewrite enable: true config: - regex_uri: ["^/prism-agent/credential-definition-registry/definitions/(.*)", "/credential-definition-registry/definitions/$1"] + regex_uri: ["^/(prism-agent|cloud-agent)/credential-definition-registry/definitions/(.*)", "/credential-definition-registry/definitions/$2"] {{ template "cors" . }} {{ template "headers.requestId" . }} {{ template "headers.security" . }} @@ -153,6 +157,7 @@ spec: {{- end }} paths: - /prism-agent/docs/* + - /cloud-agent/docs/* backends: - serviceName: agent-server-tapir-service servicePort: 8085 @@ -160,7 +165,7 @@ spec: - name: proxy-rewrite enable: true config: - regex_uri: ["^/prism-agent/docs/(.*)","/docs/$1"] + regex_uri: ["^/(prism-agent|cloud-agent)/docs/(.*)","/docs/$2"] {{ template "cors" . }} {{ template "headers.requestId" . }} {{ template "headers.security" . }} diff --git a/infrastructure/charts/agent/templates/deployment.yaml b/infrastructure/charts/agent/templates/deployment.yaml index 22f85c74bc..4621487079 100644 --- a/infrastructure/charts/agent/templates/deployment.yaml +++ b/infrastructure/charts/agent/templates/deployment.yaml @@ -168,9 +168,9 @@ spec: key: password optional: false - name: DIDCOMM_SERVICE_URL - value: "https://{{ index .Values.ingress.applicationUrls 0 }}/prism-agent/didcomm" + value: "https://{{ index .Values.ingress.applicationUrls 0 }}/cloud-agent/didcomm" - name: REST_SERVICE_URL - value: "https://{{ index .Values.ingress.applicationUrls 0 }}/prism-agent" + value: "https://{{ index .Values.ingress.applicationUrls 0 }}/cloud-agent" - name: PRISM_NODE_HOST value: {{ .Values.vdrManager.host | quote }} - name: PRISM_NODE_PORT diff --git a/infrastructure/ci/docker-compose-multiple-actors.yml b/infrastructure/ci/docker-compose-multiple-actors.yml deleted file mode 100644 index a13c64e2d1..0000000000 --- a/infrastructure/ci/docker-compose-multiple-actors.yml +++ /dev/null @@ -1,154 +0,0 @@ -version: "3.8" - -services: - ########################## - # Pollux Databases - ########################## - - db_pollux_issuer: - image: postgres:13 - restart: always - environment: - POSTGRES_DB: pollux_issuer - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - ports: - - 5435:5432 - volumes: - - pg_data_pollux_db_issuer:/var/lib/postgresql/data - healthcheck: - test: ["CMD", "pg_isready", "-U", "postgres", "-d", "pollux_issuer"] - interval: 10s - timeout: 5s - retries: 5 - - db_pollux_holder: - image: postgres:13 - restart: always - environment: - POSTGRES_DB: pollux_holder - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - ports: - - 5436:5432 - volumes: - - pg_data_pollux_db_holder:/var/lib/postgresql/data - healthcheck: - test: ["CMD", "pg_isready", "-U", "postgres", "-d", "pollux_holder"] - interval: 10s - timeout: 5s - retries: 5 - - ########################## - # Connect Databases - ########################## - - db_connect_issuer: - image: postgres:13 - restart: always - environment: - POSTGRES_DB: connect_issuer - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - ports: - - 5437:5432 - volumes: - - pg_data_connect_db_issuer:/var/lib/postgresql/data - healthcheck: - test: ["CMD", "pg_isready", "-U", "postgres", "-d", "connect_issuer"] - interval: 10s - timeout: 5s - retries: 5 - - db_connect_holder: - image: postgres:13 - restart: always - environment: - POSTGRES_DB: connect_holder - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - ports: - - 5438:5432 - volumes: - - pg_data_connect_db_holder:/var/lib/postgresql/data - healthcheck: - test: ["CMD", "pg_isready", "-U", "postgres", "-d", "connect_holder"] - interval: 10s - timeout: 5s - retries: 5 - - ########################## - # Services - ##########################c - - prism-agent-issuer: - image: ghcr.io/hyperledger/prism-agent:0.5.0 - environment: - REST_SERVICE_PORT: 8080 - DIDCOMM_SERVICE_PORT: 8081 - CASTOR_DB_HOST: db_castor_issuer - CASTOR_DB_PORT: 5432 - CASTOR_DB_NAME: castor_issuer - CASTOR_DB_USER: postgres - CASTOR_DB_PASSWORD: postgres - POLLUX_DB_HOST: db_pollux_issuer - POLLUX_DB_PORT: 5432 - POLLUX_DB_NAME: pollux_issuer - POLLUX_DB_USER: postgres - POLLUX_DB_PASSWORD: postgres - CONNECT_DB_HOST: db_connect_issuer - CONNECT_DB_PORT: 5432 - CONNECT_DB_NAME: connect_issuer - CONNECT_DB_USER: postgres - CONNECT_DB_PASSWORD: postgres - DIDCOMM_SERVICE_URL: "http://prism-agent-issuer" - ports: - - "8080:8080" - - "8081:8081" - depends_on: - - db_castor_issuer - - db_pollux_issuer - healthcheck: - test: ["CMD", "curl", "-f", "http://prism-agent-issuer:8080/dids/xyz"] - interval: 30s - timeout: 10s - retries: 5 - - prism-agent-holder: - image: ghcr.io/hyperledger/prism-agent:0.5.0 - environment: - REST_SERVICE_PORT: 8090 - DIDCOMM_SERVICE_PORT: 8091 - CASTOR_DB_HOST: db_castor_holder - CASTOR_DB_PORT: 5432 - CASTOR_DB_NAME: castor_holder - CASTOR_DB_USER: postgres - CASTOR_DB_PASSWORD: postgres - POLLUX_DB_HOST: db_pollux_holder - POLLUX_DB_PORT: 5432 - POLLUX_DB_NAME: pollux_holder - POLLUX_DB_USER: postgres - POLLUX_DB_PASSWORD: postgres - CONNECT_DB_HOST: db_connect_holder - CONNECT_DB_PORT: 5432 - CONNECT_DB_NAME: connect_holder - CONNECT_DB_USER: postgres - CONNECT_DB_PASSWORD: postgres - DIDCOMM_SERVICE_URL: "http://prism-agent-holder" - ports: - - "8090:8090" - - "8091:8091" - depends_on: - - db_castor_holder - - db_pollux_holder - healthcheck: - test: ["CMD", "curl", "-f", "http://prism-agent-holder:8090/dids/xyz"] - interval: 30s - timeout: 10s - retries: 5 - -volumes: - pg_data_pollux_db_issuer: - pg_data_pollux_db_holder: - pg_data_connect_db_issuer: - pg_data_connect_db_holder: diff --git a/infrastructure/local/.env b/infrastructure/local/.env index d18d8cae87..0f9249eb0c 100644 --- a/infrastructure/local/.env +++ b/infrastructure/local/.env @@ -1,3 +1,3 @@ -AGENT_VERSION=1.32.1 +AGENT_VERSION=1.32.1-SNAPSHOT PRISM_NODE_VERSION=2.2.1 VAULT_DEV_ROOT_TOKEN_ID=root diff --git a/infrastructure/local/run-e2e-tests-local.sh b/infrastructure/local/run-e2e-tests-local.sh index c8d6d2992f..d7a44a5d27 100755 --- a/infrastructure/local/run-e2e-tests-local.sh +++ b/infrastructure/local/run-e2e-tests-local.sh @@ -8,21 +8,21 @@ echo "--------------------------------------" echo "Starting multitenant using local/run.sh" echo "--------------------------------------" -${SCRIPT_DIR}/run.sh -p 8080 -n multitenant -w +"${SCRIPT_DIR}"/run.sh -p 8080 -n multitenant -w export AGENT_AUTH_REQUIRED=true export AGENT_AUTH_HEADER=apikey export ACME_AUTH_KEY=acme -export ACME_AGENT_URL=http://localhost:8080/prism-agent +export ACME_AGENT_URL=http://localhost:8080/cloud-agent export BOB_AUTH_KEY=bob -export BOB_AGENT_URL=http://localhost:8080/prism-agent +export BOB_AGENT_URL=http://localhost:8080/cloud-agent export FABER_AUTH_KEY=faber -export FABER_AGENT_URL=http://localhost:8080/prism-agent +export FABER_AGENT_URL=http://localhost:8080/cloud-agent -curl --location 'http://localhost:8080/prism-agent/events/webhooks' \ +curl --location 'http://localhost:8080/cloud-agent/events/webhooks' \ --header "apikey: $ACME_AUTH_KEY" \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ @@ -30,7 +30,7 @@ curl --location 'http://localhost:8080/prism-agent/events/webhooks' \ "url": "http://host.docker.internal:9955" }' -curl --location 'http://localhost:8080/prism-agent/events/webhooks' \ +curl --location 'http://localhost:8080/cloud-agent/events/webhooks' \ --header "apikey: $BOB_AUTH_KEY" \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ @@ -38,7 +38,7 @@ curl --location 'http://localhost:8080/prism-agent/events/webhooks' \ "url": "http://host.docker.internal:9956" }' -curl --location 'http://localhost:8080/prism-agent/events/webhooks' \ +curl --location 'http://localhost:8080/cloud-agent/events/webhooks' \ --header "apikey: $FABER_AUTH_KEY" \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ @@ -47,6 +47,6 @@ curl --location 'http://localhost:8080/prism-agent/events/webhooks' \ }' ( - cd ${SCRIPT_DIR}/../../tests/e2e-tests/ + cd "${SCRIPT_DIR}"/../../tests/integration-tests/ ./gradlew test reports ) diff --git a/infrastructure/multi/run-e2e-tests-local.sh b/infrastructure/multi/run-e2e-tests-local.sh index 3ea71b45a5..6a6ed7f1f6 100755 --- a/infrastructure/multi/run-e2e-tests-local.sh +++ b/infrastructure/multi/run-e2e-tests-local.sh @@ -8,25 +8,25 @@ echo "--------------------------------------" echo "Starting issuer using local/run.sh" echo "--------------------------------------" -${SCRIPT_DIR}/../local/run.sh -p 8080 -n issuer -w +"${SCRIPT_DIR}"/../local/run.sh -p 8080 -n issuer -w echo "--------------------------------------" echo "Starting holder using local/run.sh" echo "--------------------------------------" -${SCRIPT_DIR}/../local/run.sh -p 8090 -n holder -w +"${SCRIPT_DIR}"/../local/run.sh -p 8090 -n holder -w echo "--------------------------------------" echo "Starting verifier using local/run.sh" echo "--------------------------------------" -${SCRIPT_DIR}/../local/run.sh -p 8100 -n verifier -w +"${SCRIPT_DIR}"/../local/run.sh -p 8100 -n verifier -w echo "--------------------------------------" echo "Run e2e tests" echo "--------------------------------------" ( - cd ${SCRIPT_DIR}/../../tests/e2e-tests/ + cd "${SCRIPT_DIR}"/../../tests/integration-tests/ ./gradlew test reports ) diff --git a/infrastructure/multi/run-e2e-tests-remote.sh b/infrastructure/multi/run-e2e-tests-remote.sh index 730de0ed8b..cb334fbf47 100755 --- a/infrastructure/multi/run-e2e-tests-remote.sh +++ b/infrastructure/multi/run-e2e-tests-remote.sh @@ -2,14 +2,17 @@ set -e -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) echo "--------------------------------------" echo "Run e2e tests" echo "--------------------------------------" -export ACME_AGENT_URL=https://agent-df56h.atalaprism.io/prism-agent -export BOB_AGENT_URL=https://agent-kj46b.atalaprism.io/prism-agent -export MALLORY_AGENT_URL=https://agent-sd98k.atalaprism.io/prism-agent +export ACME_AGENT_URL=https://agent-df56h.atalaprism.io/cloud-agent +export BOB_AGENT_URL=https://agent-kj46b.atalaprism.io/cloud-agent +export MALLORY_AGENT_URL=https://agent-sd98k.atalaprism.io/cloud-agent -(cd ${SCRIPT_DIR}/../../tests/e2e-tests/; AGENT_AUTH_REQUIRED=true ./gradlew test reports) +( + cd "${SCRIPT_DIR}"/../../tests/e2e-tests/ + AGENT_AUTH_REQUIRED=true ./gradlew test reports +) diff --git a/infrastructure/shared/apisix/conf/apisix.yaml b/infrastructure/shared/apisix/conf/apisix.yaml index b26494025b..e0c68e958f 100644 --- a/infrastructure/shared/apisix/conf/apisix.yaml +++ b/infrastructure/shared/apisix/conf/apisix.yaml @@ -3,18 +3,18 @@ plugins: - name: cors routes: - - uri: /prism-agent/* + - uri: /cloud-agent/* upstream_id: 4 plugins: cors: allow_origins: "*" proxy-rewrite: - regex_uri: ["^/prism-agent/(.*)", "/$1"] - - uri: /docs/prism-agent/api/* + regex_uri: ["^/cloud-agent/(.*)", "/$1"] + - uri: /docs/cloud-agent/api/* upstream_id: 4 plugins: proxy-rewrite: - regex_uri: ["^/docs/prism-agent/api/(.*)", "/docs/$1"] + regex_uri: ["^/docs/cloud-agent/api/(.*)", "/docs/$1"] - uri: /didcomm* upstream_id: 3 plugins: @@ -31,11 +31,11 @@ routes: upstreams: - id: 3 nodes: - "prism-agent:8090": 1 # didcom and system + "cloud-agent:8090": 1 # didcom and system type: roundrobin - id: 4 nodes: - "prism-agent:8085": 1 # tapir + "cloud-agent:8085": 1 # tapir type: roundrobin - id: 5 nodes: diff --git a/infrastructure/shared/docker-compose-demo.yml b/infrastructure/shared/docker-compose-demo.yml index eecb80ac05..59eec1b988 100644 --- a/infrastructure/shared/docker-compose-demo.yml +++ b/infrastructure/shared/docker-compose-demo.yml @@ -28,11 +28,11 @@ services: db: condition: service_healthy - prism-agent: + cloud-agent: image: ghcr.io/hyperledger/identus-cloud-agent:${AGENT_VERSION} environment: DIDCOMM_SERVICE_URL: http://${DOCKERHOST}:${PORT}/didcomm - REST_SERVICE_URL: http://${DOCKERHOST}:${PORT}/prism-agent + REST_SERVICE_URL: http://${DOCKERHOST}:${PORT}/cloud-agent PRISM_NODE_HOST: prism-node PRISM_NODE_PORT: 50053 SECRET_STORAGE_BACKEND: postgres @@ -54,7 +54,7 @@ services: prism-node: condition: service_started healthcheck: - test: ["CMD", "curl", "-f", "http://prism-agent:8085/_system/health"] + test: ["CMD", "curl", "-f", "http://cloud-agent:8085/_system/health"] interval: 30s timeout: 10s retries: 5 @@ -65,7 +65,7 @@ services: image: swaggerapi/swagger-ui:v5.4.2 environment: - 'URLS=[ - { name: "Prism Agent", url: "/docs/prism-agent/api/docs.yaml" } + { name: "Cloud Agent", url: "/docs/cloud-agent/api/docs.yaml" } ]' apisix: @@ -76,7 +76,7 @@ services: ports: - "${PORT}:9080/tcp" depends_on: - - prism-agent + - cloud-agent - swagger-ui volumes: diff --git a/infrastructure/shared/docker-compose-mt-keycloak.yml b/infrastructure/shared/docker-compose-mt-keycloak.yml index ea7f76d8b5..30a0bf9829 100644 --- a/infrastructure/shared/docker-compose-mt-keycloak.yml +++ b/infrastructure/shared/docker-compose-mt-keycloak.yml @@ -69,7 +69,7 @@ services: timeout: 5s retries: 5 - prism-agent: + cloud-agent: image: ghcr.io/hyperledger/identus-cloud-agent:${AGENT_VERSION} environment: POLLUX_DB_HOST: db @@ -110,7 +110,7 @@ services: KEYCLOAK_ENABLED: true KEYCLOAK_URL: http://keycloak:8080 KEYCLOAK_REALM: atala-demo - KEYCLOAK_CLIENT_ID: prism-agent + KEYCLOAK_CLIENT_ID: prism-agent # TODO: Fix this later KEYCLOAK_CLIENT_SECRET: prism-agent-demo-secret KEYCLOAK_UMA_AUTO_UPGRADE_RPT: true depends_on: @@ -121,7 +121,7 @@ services: vault-server: condition: service_healthy healthcheck: - test: ["CMD", "curl", "-f", "http://prism-agent:8085/_system/health"] + test: ["CMD", "curl", "-f", "http://cloud-agent:8085/_system/health"] interval: 30s timeout: 10s retries: 5 @@ -132,7 +132,7 @@ services: image: swaggerapi/swagger-ui:v5.1.0 environment: - 'URLS=[ - { name: "Prism Agent", url: "/docs/prism-agent/api/docs.yaml" } + { name: "Cloud Agent", url: "/docs/cloud-agent/api/docs.yaml" } ]' apisix: @@ -143,7 +143,7 @@ services: ports: - "${PORT}:9080/tcp" depends_on: - - prism-agent + - cloud-agent - swagger-ui keycloak: diff --git a/infrastructure/shared/docker-compose.yml b/infrastructure/shared/docker-compose.yml index 7dbe179c6e..836dbd4c84 100644 --- a/infrastructure/shared/docker-compose.yml +++ b/infrastructure/shared/docker-compose.yml @@ -70,7 +70,7 @@ services: timeout: 5s retries: 5 - prism-agent: + cloud-agent: image: ghcr.io/hyperledger/identus-cloud-agent:${AGENT_VERSION} environment: POLLUX_DB_HOST: db @@ -88,9 +88,9 @@ services: AGENT_DB_NAME: agent AGENT_DB_USER: postgres AGENT_DB_PASSWORD: postgres - POLLUX_STATUS_LIST_REGISTRY_PUBLIC_URL: http://${DOCKERHOST}:${PORT}/prism-agent + POLLUX_STATUS_LIST_REGISTRY_PUBLIC_URL: http://${DOCKERHOST}:${PORT}/cloud-agent DIDCOMM_SERVICE_URL: http://${DOCKERHOST}:${PORT}/didcomm - REST_SERVICE_URL: http://${DOCKERHOST}:${PORT}/prism-agent + REST_SERVICE_URL: http://${DOCKERHOST}:${PORT}/cloud-agent PRISM_NODE_HOST: prism-node PRISM_NODE_PORT: 50053 VAULT_ADDR: ${VAULT_ADDR:-http://vault-server:8200} @@ -118,7 +118,7 @@ services: vault-server: condition: service_healthy healthcheck: - test: ["CMD", "curl", "-f", "http://prism-agent:8085/_system/health"] + test: ["CMD", "curl", "-f", "http://cloud-agent:8085/_system/health"] interval: 30s timeout: 10s retries: 5 @@ -129,7 +129,7 @@ services: image: swaggerapi/swagger-ui:v5.1.0 environment: - 'URLS=[ - { name: "Prism Agent", url: "/docs/prism-agent/api/docs.yaml" } + { name: "Cloud Agent", url: "/docs/cloud-agent/api/docs.yaml" } ]' apisix: @@ -140,7 +140,7 @@ services: ports: - "${PORT}:9080/tcp" depends_on: - - prism-agent + - cloud-agent - swagger-ui volumes: diff --git a/infrastructure/single-tenant-testing-stack/apisix/conf/apisix.yaml b/infrastructure/single-tenant-testing-stack/apisix/conf/apisix.yaml index 92a710f380..4e9fc1648f 100644 --- a/infrastructure/single-tenant-testing-stack/apisix/conf/apisix.yaml +++ b/infrastructure/single-tenant-testing-stack/apisix/conf/apisix.yaml @@ -7,31 +7,49 @@ routes: plugins: proxy-rewrite: regex_uri: ["^/issuer/prism-agent/(.*)", "/$1"] + - uri: /issuer/cloud-agent/* + upstream_id: 1 + plugins: + proxy-rewrite: + regex_uri: ["^/issuer/cloud-agent/(.*)", "/$1"] - uri: /issuer/didcomm* upstream_id: 2 plugins: proxy-rewrite: regex_uri: ["^/issuer/didcomm(.*)", "/$1"] + - uri: /verifier/prism-agent/* upstream_id: 3 plugins: proxy-rewrite: regex_uri: ["^/verifier/prism-agent/(.*)", "/$1"] + - uri: /verifier/cloud-agent/* + upstream_id: 3 + plugins: + proxy-rewrite: + regex_uri: ["^/verifier/cloud-agent/(.*)", "/$1"] - uri: /verifier/didcomm* upstream_id: 4 plugins: proxy-rewrite: regex_uri: ["^/verifier/didcomm(.*)", "/$1"] + - uri: /holder/prism-agent/* upstream_id: 5 plugins: proxy-rewrite: regex_uri: ["^/holder/prism-agent/(.*)", "/$1"] + - uri: /holder/cloud-agent/* + upstream_id: 5 + plugins: + proxy-rewrite: + regex_uri: ["^/holder/cloud-agent/(.*)", "/$1"] - uri: /holder/didcomm* upstream_id: 6 plugins: proxy-rewrite: regex_uri: ["^/holder/didcomm(.*)", "/$1"] + upstreams: - id: 1 nodes: diff --git a/infrastructure/single-tenant-testing-stack/run-e2e-tests-local.sh b/infrastructure/single-tenant-testing-stack/run-e2e-tests-local.sh index 98dcd604ee..d9b9747b5c 100755 --- a/infrastructure/single-tenant-testing-stack/run-e2e-tests-local.sh +++ b/infrastructure/single-tenant-testing-stack/run-e2e-tests-local.sh @@ -13,20 +13,20 @@ echo "--------------------------------------" echo "Starting stack using docker compose" echo "--------------------------------------" -PORT=${PORT} docker compose -f ${SCRIPT_DIR}/docker-compose.yml \ - --env-file ${ENV_FILE} up -d --wait +PORT=${PORT} docker compose -f "${SCRIPT_DIR}"/docker-compose.yml \ + --env-file "${ENV_FILE}" up -d --wait export AGENT_AUTH_REQUIRED=true -export ACME_AGENT_URL=http://localhost:${PORT}/issuer/prism-agent +export ACME_AGENT_URL=http://localhost:${PORT}/issuer/cloud-agent export ACME_AUTH_KEY=default -export BOB_AGENT_URL=http://localhost:${PORT}/verifier/prism-agent +export BOB_AGENT_URL=http://localhost:${PORT}/verifier/cloud-agent export BOB_AUTH_KEY=default -export MALLORY_AGENT_URL=http://localhost:${PORT}/holder/prism-agent +export MALLORY_AGENT_URL=http://localhost:${PORT}/holder/cloud-agent export MALLORY_AUTH_KEY=default -export FABER_AGENT_URL=http://localhost:${PORT}/holder/prism-agent +export FABER_AGENT_URL=http://localhost:${PORT}/holder/cloud-agent export FABER_AUTH_KEY=default ( - cd ${SCRIPT_DIR}/../../tests/e2e-tests/ + cd "${SCRIPT_DIR}"/../../tests/e2e-tests/ ./gradlew test reports ) diff --git a/infrastructure/single-tenant-testing-stack/run-performance-tests-local.sh b/infrastructure/single-tenant-testing-stack/run-performance-tests-local.sh index f45e698acf..167983367b 100755 --- a/infrastructure/single-tenant-testing-stack/run-performance-tests-local.sh +++ b/infrastructure/single-tenant-testing-stack/run-performance-tests-local.sh @@ -13,14 +13,14 @@ echo "--------------------------------------" echo "Starting stack using docker compose" echo "--------------------------------------" -PORT=${PORT} docker compose -f ${SCRIPT_DIR}/docker-compose.yml \ - --env-file ${ENV_FILE} up -d --wait +PORT=${PORT} docker compose -f "${SCRIPT_DIR}"/docker-compose.yml \ + --env-file "${ENV_FILE}" up -d --wait -export ISSUER_AGENT_URL=http://localhost:${PORT}/issuer/prism-agent +export ISSUER_AGENT_URL=http://localhost:${PORT}/issuer/cloud-agent export ISSUER_AGENT_API_KEY=default -export HOLDER_AGENT_URL=http://localhost:${PORT}/holder/prism-agent +export HOLDER_AGENT_URL=http://localhost:${PORT}/holder/cloud-agent export HOLDER_AGENT_API_KEY=default -export VERIFIER_AGENT_URL=http://localhost:${PORT}/verifier/prism-agent +export VERIFIER_AGENT_URL=http://localhost:${PORT}/verifier/cloud-agent export VERIFIER_AGENT_API_KEY=default echo "--------------------------------------" @@ -28,17 +28,17 @@ echo "Run perf tests" echo "--------------------------------------" ( - export K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write - export K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM=true - cd ${SCRIPT_DIR}/../../tests/performance-tests/agent-performance-tests-k6 - yarn install - yarn webpack - k6 run -e SCENARIO_LABEL=st-create-prism-did-smoke dist/create-prism-did-test.js -o experimental-prometheus-rw - k6 run -e SCENARIO_LABEL=st-credential-offer-smoke dist/credential-offer-test.js -o experimental-prometheus-rw - k6 run -e SCENARIO_LABEL=st-credential-definition-smoke dist/credential-definition-test.js -o experimental-prometheus-rw - k6 run -e SCENARIO_LABEL=st-credential-schema-smoke dist/credential-schema-test.js -o experimental-prometheus-rw - k6 run -e SCENARIO_LABEL=st-did-publishing-smoke dist/did-publishing-test.js -o experimental-prometheus-rw - k6 run -e SCENARIO_LABEL=st-connection-flow-smoke dist/connection-flow-test.js -o experimental-prometheus-rw - k6 run -e SCENARIO_LABEL=st-issuance-flow-smoke dist/issuance-flow-test.js -o experimental-prometheus-rw - k6 run -e SCENARIO_LABEL=st-present-proof-flow-smoke dist/present-proof-flow-test.js -o experimental-prometheus-rw + export K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write + export K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM=true + cd "${SCRIPT_DIR}"/../../tests/performance-tests/agent-performance-tests-k6 + yarn install + yarn webpack + k6 run -e SCENARIO_LABEL=st-create-prism-did-smoke dist/create-prism-did-test.js -o experimental-prometheus-rw + k6 run -e SCENARIO_LABEL=st-credential-offer-smoke dist/credential-offer-test.js -o experimental-prometheus-rw + k6 run -e SCENARIO_LABEL=st-credential-definition-smoke dist/credential-definition-test.js -o experimental-prometheus-rw + k6 run -e SCENARIO_LABEL=st-credential-schema-smoke dist/credential-schema-test.js -o experimental-prometheus-rw + k6 run -e SCENARIO_LABEL=st-did-publishing-smoke dist/did-publishing-test.js -o experimental-prometheus-rw + k6 run -e SCENARIO_LABEL=st-connection-flow-smoke dist/connection-flow-test.js -o experimental-prometheus-rw + k6 run -e SCENARIO_LABEL=st-issuance-flow-smoke dist/issuance-flow-test.js -o experimental-prometheus-rw + k6 run -e SCENARIO_LABEL=st-present-proof-flow-smoke dist/present-proof-flow-test.js -o experimental-prometheus-rw ) diff --git a/tests/performance-tests/agent-performance-tests-k6/.env b/tests/performance-tests/agent-performance-tests-k6/.env index 4b8958681d..0f9249eb0c 100644 --- a/tests/performance-tests/agent-performance-tests-k6/.env +++ b/tests/performance-tests/agent-performance-tests-k6/.env @@ -1,3 +1,3 @@ -PRISM_AGENT_VERSION=1.30.1-SNAPSHOT +AGENT_VERSION=1.32.1-SNAPSHOT PRISM_NODE_VERSION=2.2.1 VAULT_DEV_ROOT_TOKEN_ID=root diff --git a/tests/performance-tests/agent-performance-tests-k6/run.sh b/tests/performance-tests/agent-performance-tests-k6/run.sh index e4b4198482..b836832198 100755 --- a/tests/performance-tests/agent-performance-tests-k6/run.sh +++ b/tests/performance-tests/agent-performance-tests-k6/run.sh @@ -139,13 +139,13 @@ echo "K6 downloaded" cd "$AGENT_DIR" ##sbt docker:publishLocal -PRISM_AGENT_VERSION=$(cut -d '"' -f 2 version.sbt) +AGENT_VERSION=$(cut -d '"' -f 2 version.sbt) ## back to performance folder cd "$PERF_DIR" # set version to env file -sed -i.bak "s/PRISM_AGENT_VERSION=.*/PRISM_AGENT_VERSION=${PRISM_AGENT_VERSION}/" "${ENV_FILE}" && rm -f "${ENV_FILE}.bak" +sed -i.bak "s/AGENT_VERSION=.*/AGENT_VERSION=${AGENT_VERSION}/" "${ENV_FILE}" && rm -f "${ENV_FILE}.bak" # create agents in parallel createIssuer & diff --git a/tests/performance-tests/agent-performance-tests-k6/src/common/Config.ts b/tests/performance-tests/agent-performance-tests-k6/src/common/Config.ts index 75fb009140..08ed0f2f92 100644 --- a/tests/performance-tests/agent-performance-tests-k6/src/common/Config.ts +++ b/tests/performance-tests/agent-performance-tests-k6/src/common/Config.ts @@ -1,49 +1,49 @@ -/*global __ENV*/ +/* global __ENV */ /** * Maximum number of iterations for the waiting loop. * If not provided, the default value is 100. */ -export const WAITING_LOOP_MAX_ITERATIONS = Number(__ENV.MY_USER_AGENT) || 1000; +export const WAITING_LOOP_MAX_ITERATIONS = Number(__ENV.MY_USER_AGENT) || 1000 /** * Pause interval in seconds for each iteration of the waiting loop. * If not provided, the default value is 10 milliseconds. */ -export const WAITING_LOOP_PAUSE_INTERVAL = Number(__ENV.WAITING_LOOP_PAUSE_INTERVAL) || 0.1; +export const WAITING_LOOP_PAUSE_INTERVAL = Number(__ENV.WAITING_LOOP_PAUSE_INTERVAL) || 0.1 /** * URL for the Issuer agent. - * If not provided, the default value is "http://localhost:8080/prism-agent". + * If not provided, the default value is "http://localhost:8080/cloud-agent". */ -export const ISSUER_AGENT_URL = __ENV.ISSUER_AGENT_URL || "http://localhost:8080/prism-agent"; +export const ISSUER_AGENT_URL = __ENV.ISSUER_AGENT_URL || 'http://localhost:8080/cloud-agent' /** * API key for the Issuer agent. * If not provided, the default value is an empty string. */ -export const ISSUER_AGENT_API_KEY = __ENV.ISSUER_AGENT_API_KEY || ""; +export const ISSUER_AGENT_API_KEY = __ENV.ISSUER_AGENT_API_KEY || '' /** * URL for the Holder agent. - * If not provided, the default value is "http://localhost:8090/prism-agent". + * If not provided, the default value is "http://localhost:8090/cloud-agent". */ -export const HOLDER_AGENT_URL = __ENV.HOLDER_AGENT_URL || "http://localhost:8090/prism-agent"; +export const HOLDER_AGENT_URL = __ENV.HOLDER_AGENT_URL || 'http://localhost:8090/cloud-agent' /** * API key for the Holder agent. * If not provided, the default value is an empty string. */ -export const HOLDER_AGENT_API_KEY = __ENV.HOLDER_AGENT_API_KEY || ""; +export const HOLDER_AGENT_API_KEY = __ENV.HOLDER_AGENT_API_KEY || '' /** * URL for the Verifier agent. - * If not provided, the default value is "http://localhost:8100/prism-agent". + * If not provided, the default value is "http://localhost:8100/cloud-agent". */ -export const VERIFIER_AGENT_URL = __ENV.VERIFIER_AGENT_URL || "http://localhost:8100/prism-agent"; +export const VERIFIER_AGENT_URL = __ENV.VERIFIER_AGENT_URL || 'http://localhost:8100/cloud-agent' /** * API key for the Verifier agent. * If not provided, the default value is an empty string. */ -export const VERIFIER_AGENT_API_KEY = __ENV.VERIFIER_AGENT_API_KEY || ""; +export const VERIFIER_AGENT_API_KEY = __ENV.VERIFIER_AGENT_API_KEY || '' diff --git a/tests/performance-tests/agent-performance-tests/README.md b/tests/performance-tests/agent-performance-tests/README.md index 3770c34f0c..c7b1318a5c 100644 --- a/tests/performance-tests/agent-performance-tests/README.md +++ b/tests/performance-tests/agent-performance-tests/README.md @@ -27,7 +27,7 @@ For example, running `ConnectionSimulation` from `simulations` package: ## Environments configuration There are multiple configuration environment variables available through `common.Configuration` module: -* `ISSUER_AGENT_URL`: URL for Issuer Agent, example: `http://localhost:8080/prism-agent` +* `ISSUER_AGENT_URL`: URL for Issuer Agent, example: `http://localhost:8080/cloud-agent` * `ISSUER_AGENT_API_KEY`: access key for Issuer agent if hosted on remote env -* `HOLDER_AGENT_URL`: URL for Holder Agent, example: `http://localhost:8090/prism-agent` +* `HOLDER_AGENT_URL`: URL for Holder Agent, example: `http://localhost:8090/cloud-agent` * `HOLDER_AGENT_API_KEY`: access key for Holder agent if hosted on remote env From 343843890cb7c2a567eb0e33d64cbf54b7e141f6 Mon Sep 17 00:00:00 2001 From: Hyperledger Bot Date: Thu, 9 May 2024 04:14:38 +0000 Subject: [PATCH 07/14] chore(release): cut Identus Cloud agent 1.33.0 release # [1.33.0](https://github.com/hyperledger/identus-cloud-agent/compare/cloud-agent-v1.32.1...cloud-agent-v1.33.0) (2024-05-09) ### Bug Fixes * integration test ([#1011](https://github.com/hyperledger/identus-cloud-agent/issues/1011)) ([d674f31](https://github.com/hyperledger/identus-cloud-agent/commit/d674f3162be44ba05d50b305be4838525d982706)) ### Features * rename `prism-agent` to `cloud-agent` ([#1019](https://github.com/hyperledger/identus-cloud-agent/issues/1019)) ([74560da](https://github.com/hyperledger/identus-cloud-agent/commit/74560dabf59dac15ccd086edb7a77d9e5055621e)) Signed-off-by: Allain Magyar --- CHANGELOG.md | 12 +++ DEPENDENCIES.md | 58 ++++++------ .../api/http/cloud-agent-openapi-spec.yaml | 84 +++++++++--------- infrastructure/charts/agent/Chart.yaml | 4 +- infrastructure/charts/index.yaml | 68 ++++++++------ infrastructure/charts/prism-agent-1.33.0.tgz | Bin 0 -> 160974 bytes infrastructure/local/.env | 2 +- package-lock.json | 4 +- package.json | 2 +- version.sbt | 2 +- 10 files changed, 133 insertions(+), 103 deletions(-) create mode 100644 infrastructure/charts/prism-agent-1.33.0.tgz diff --git a/CHANGELOG.md b/CHANGELOG.md index 494cf27ff8..5c8df47a90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# [1.33.0](https://github.com/hyperledger/identus-cloud-agent/compare/cloud-agent-v1.32.1...cloud-agent-v1.33.0) (2024-05-09) + + +### Bug Fixes + +* integration test ([#1011](https://github.com/hyperledger/identus-cloud-agent/issues/1011)) ([d674f31](https://github.com/hyperledger/identus-cloud-agent/commit/d674f3162be44ba05d50b305be4838525d982706)) + + +### Features + +* rename `prism-agent` to `cloud-agent` ([#1019](https://github.com/hyperledger/identus-cloud-agent/issues/1019)) ([74560da](https://github.com/hyperledger/identus-cloud-agent/commit/74560dabf59dac15ccd086edb7a77d9e5055621e)) + ## [1.32.1](https://github.com/hyperledger/identus-cloud-agent/compare/cloud-agent-v1.32.0...cloud-agent-v1.32.1) (2024-05-07) diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 0e78cdf2a5..854cdfa15d 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -445,33 +445,33 @@ MIT | [The MIT License (MIT)](https://opensource.org/licenses/MIT) | [com.dimafe Public Domain | [Public Domain, per Creative Commons CC0](http://creativecommons.org/publicdomain/zero/1.0/) | [org.hdrhistogram # HdrHistogram # 2.1.12](http://hdrhistogram.github.io/HdrHistogram/) | Public Domain | [Public Domain, per Creative Commons CC0](http://creativecommons.org/publicdomain/zero/1.0/) | [org.latencyutils # LatencyUtils # 2.0.3](http://latencyutils.github.io/LatencyUtils/) | none specified | []() | [net.jcip # jcip-annotations # 1.0](http://jcip.net/) | -none specified | []() | [org.hyperledger # castor-core_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # cloud-agent-wallet-api_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # connect-core_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # connect-sql-doobie_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # event-notification_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-agent-core_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-agent-didcommx_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-data-models_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-connection_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-coordinate-mediation_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-invitation_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-issue-credential_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-mailbox_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-outofband-login_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-present-proof_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-report-problem_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-revocation-notification_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-routing-2-0_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-protocol-trust-ping_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-resolver_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # mercury-verifiable-credentials_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # pollux-anoncreds_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # pollux-core_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # pollux-sql-doobie_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # pollux-vc-jwt_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # prism-node-client_3 # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # shared # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # shared-crypto # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | -none specified | []() | [org.hyperledger # shared-test # 1.32.0-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # castor-core_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # cloud-agent-wallet-api_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # connect-core_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # connect-sql-doobie_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # event-notification_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-agent-core_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-agent-didcommx_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-data-models_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-connection_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-coordinate-mediation_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-invitation_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-issue-credential_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-mailbox_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-outofband-login_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-present-proof_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-report-problem_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-revocation-notification_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-routing-2-0_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-protocol-trust-ping_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-resolver_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # mercury-verifiable-credentials_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # pollux-anoncreds_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # pollux-core_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # pollux-sql-doobie_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # pollux-vc-jwt_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # prism-node-client_3 # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # shared # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # shared-crypto # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | +none specified | []() | [org.hyperledger # shared-test # 1.32.1-SNAPSHOT](https://github.com/hyperledger/identus-cloud-agent) | diff --git a/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml b/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml index 701bc05122..ba6e254ce5 100644 --- a/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml +++ b/cloud-agent/service/api/http/cloud-agent-openapi-spec.yaml @@ -1,10 +1,10 @@ openapi: 3.0.3 info: - title: Open Enterprise Agent API Reference - version: 1.32.1 + title: Identus Cloud Agent API Reference + version: 1.33.0 description: |2 - The Open Enterprise Agent API facilitates the integration and management of self-sovereign identity capabilities within applications. + The Identus Cloud Agent API facilitates the integration and management of self-sovereign identity capabilities within applications. It supports DID (Decentralized Identifiers) management, verifiable credential exchange, and secure messaging based on DIDComm standards. The API is designed to be interoperable with various blockchain and DLT (Distributed Ledger Technology) platforms, ensuring wide compatibility and flexibility. Key features include connection management, credential issuance and verification, and secure, privacy-preserving communication between entities. @@ -154,11 +154,11 @@ tags: For more detailed information related to the agent IAM and its usage, please refer to this [documentation](https://docs.atalaprism.io/docs/atala-prism/prism-cloud-agent/authentication). servers: - url: http://localhost:8085 - description: Local Prism Agent -- url: http://localhost/prism-agent - description: Local Prism Agent with APISIX proxy -- url: https://k8s-dev.atalaprism.io/prism-agent - description: Prism Agent on the Staging Environment + description: The local instance of the Cloud Agent +- url: http://localhost/cloud-agent + description: The local instance of the Cloud Agent behind the APISIX proxy +- url: https://k8s-dev.atalaprism.io/cloud-agent + description: The Cloud Agent in the Staging Environment paths: /credential-definition-registry/definitions: get: @@ -3304,7 +3304,7 @@ components: type: string description: The URL that uniquely identifies the resource being returned in the response. - example: /prism-agent/connections?offset=10&limit=10 + example: /cloud-agent/connections?offset=10&limit=10 pageOf: type: string description: A string field indicating the type of resource that the contents @@ -3315,13 +3315,13 @@ components: description: An optional string field containing the URL of the next page of results. If the API response does not contain any more pages, this field should be set to None. - example: /prism-agent/connections?offset=20&limit=10 + example: /cloud-agent/connections?offset=20&limit=10 previous: type: string description: An optional string field containing the URL of the previous page of results. If the API response is the first page of results, this field should be set to None. - example: /prism-agent/connections?offset=0&limit=10 + example: /cloud-agent/connections?offset=0&limit=10 CreateConnectionRequest: type: object properties: @@ -3383,7 +3383,7 @@ components: The URL pointing to the JSON schema that will be used for this offer (should be 'http' or 'https'). When dereferenced, the returned content should be a JSON schema compliant with the '[Draft 2020-12](https://json-schema.org/draft/2020-12/release-notes)' version of the specification. Note that this parameter only applies when the offer is of type 'JWT'. - example: https://agent-host.com/prism-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676/schema + example: https://agent-host.com/cloud-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676/schema credentialDefinitionId: type: string description: |2 @@ -3549,7 +3549,7 @@ components: type: string description: The unique identifier of the schema used for this credential definition. - example: https://agent-host.com/prism-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676 + example: https://agent-host.com/cloud-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676 signatureType: type: string description: Signature type used in the CredentialDefinition. @@ -3631,7 +3631,7 @@ components: type: string description: The unique identifier of the schema used for this credential definition. - example: https://agent-host.com/prism-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676 + example: https://agent-host.com/cloud-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676 definition: description: Definition object that represents the actual definition of the credential. @@ -3666,7 +3666,7 @@ components: type: string description: The URL that uniquely identifies the resource being returned in the response. - example: /prism-agent/credential-definition-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4 + example: /cloud-agent/credential-definition-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4 CredentialDefinitionResponsePage: required: - kind @@ -3689,24 +3689,24 @@ components: self: type: string description: A string field containing the URL of the current API endpoint - example: /prism-agent/schema-registry/schemas?skip=10&limit=10 + example: /cloud-agent/schema-registry/schemas?skip=10&limit=10 pageOf: type: string description: A string field indicating the type of resource that the contents field contains - example: /prism-agent/schema-registry/schemas + example: /cloud-agent/schema-registry/schemas next: type: string description: An optional string field containing the URL of the next page of results. If the API response does not contain any more pages, this field should be set to None. - example: /prism-agent/schema-registry/schemas?skip=20&limit=10 + example: /cloud-agent/schema-registry/schemas?skip=20&limit=10 previous: type: string description: An optional string field containing the URL of the previous page of results. If the API response is the first page of results, this field should be set to None. - example: /prism-agent/schema-registry/schemas?skip=0&limit=10 + example: /cloud-agent/schema-registry/schemas?skip=0&limit=10 CredentialSchemaInput: required: - name @@ -3899,7 +3899,7 @@ components: type: string description: The URL that uniquely identifies the resource being returned in the response. - example: /prism-agent/schema-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4 + example: /cloud-agent/schema-registry/schemas/0527aea1-d131-3948-a34d-03af39aba8b4 CredentialSchemaResponsePage: required: - kind @@ -3922,24 +3922,24 @@ components: self: type: string description: A string field containing the URL of the current API endpoint - example: /prism-agent/schema-registry/schemas?skip=10&limit=10 + example: /cloud-agent/schema-registry/schemas?skip=10&limit=10 pageOf: type: string description: A string field indicating the type of resource that the contents field contains - example: /prism-agent/schema-registry/schemas + example: /cloud-agent/schema-registry/schemas next: type: string description: An optional string field containing the URL of the next page of results. If the API response does not contain any more pages, this field should be set to None. - example: /prism-agent/schema-registry/schemas?skip=20&limit=10 + example: /cloud-agent/schema-registry/schemas?skip=20&limit=10 previous: type: string description: An optional string field containing the URL of the previous page of results. If the API response is the first page of results, this field should be set to None. - example: /prism-agent/schema-registry/schemas?skip=0&limit=10 + example: /cloud-agent/schema-registry/schemas?skip=0&limit=10 CredentialSubject: required: - id @@ -4142,7 +4142,7 @@ components: self: type: string description: The `self` link of the entity. - example: http://localhost:8080/prism-agent/iam/entities/00000000-0000-0000-0000-000000000000 + example: http://localhost:8080/cloud-agent/iam/entities/00000000-0000-0000-0000-000000000000 id: type: string description: The unique `id` of the entity @@ -4181,7 +4181,7 @@ components: description: A sequence of CredentialSchemaResponse objects representing the list of credential schemas that the API response contains example: - - EntityResponse(Entity,/prism-agent/iam/entities/00000000-0000-0000-0000-000000000000,00000000-0000-0000-0000-000000000000,John + - EntityResponse(Entity,/cloud-agent/iam/entities/00000000-0000-0000-0000-000000000000,00000000-0000-0000-0000-000000000000,John Doe,00000000-0000-0000-0000-000000000000,2023-01-01T00:00:00Z,2023-01-01T00:00:00Z) kind: type: string @@ -4191,24 +4191,24 @@ components: self: type: string description: A string field containing the URL of the current API endpoint - example: /prism-agent/schema-registry/schemas?skip=10&limit=10 + example: /cloud-agent/schema-registry/schemas?skip=10&limit=10 pageOf: type: string description: A string field indicating the type of resource that the contents field contains - example: /prism-agent/schema-registry/schemas + example: /cloud-agent/schema-registry/schemas next: type: string description: An optional string field containing the URL of the next page of results. If the API response does not contain any more pages, this field should be set to None. - example: /prism-agent/schema-registry/schemas?skip=20&limit=10 + example: /cloud-agent/schema-registry/schemas?skip=20&limit=10 previous: type: string description: An optional string field containing the URL of the previous page of results. If the API response is the first page of results, this field should be set to None. - example: /prism-agent/schema-registry/schemas?skip=0&limit=10 + example: /cloud-agent/schema-registry/schemas?skip=0&limit=10 ErrorResponse: required: - status @@ -4318,7 +4318,7 @@ components: type: string description: The date and time when the issue credential record was created. format: date-time - example: '2024-05-07T10:53:56.428516424Z' + example: '2024-05-09T03:52:24.537313621Z' updatedAt: type: string description: The date and time when the issue credential record was last @@ -4392,24 +4392,24 @@ components: type: string description: The URL that uniquely identifies the resource being returned in the response. - example: /prism-agent/issue-credentials/records?offset=10&limit=10 + example: /cloud-agent/issue-credentials/records?offset=10&limit=10 pageOf: type: string description: A string field indicating the type of resource that the contents field contains. - example: /prism-agent/issue-credentials/records + example: /cloud-agent/issue-credentials/records next: type: string description: An optional string field containing the URL of the next page of results. If the API response does not contain any more pages, this field should be set to None. - example: /prism-agent/issue-credentials/records?offset=20&limit=10 + example: /cloud-agent/issue-credentials/records?offset=20&limit=10 previous: type: string description: An optional string field containing the URL of the previous page of results. If the API response is the first page of results, this field should be set to None. - example: /prism-agent/issue-credentials/records?offset=0&limit=10 + example: /cloud-agent/issue-credentials/records?offset=0&limit=10 Json: description: The service endpoint. Can contain multiple possible values as described in the [Create DID operation](https://github.com/input-output-hk/prism-did-method-spec/blob/main/w3c-spec/PRISM-method.md#create-did) @@ -4919,7 +4919,7 @@ components: type: string description: Issuance timestamp of status list credential format: date-time - example: '2024-05-07T10:53:56.466164983Z' + example: '2024-05-09T03:52:24.573534586Z' credentialSubject: $ref: '#/components/schemas/CredentialSubject' proof: @@ -5199,7 +5199,7 @@ components: type: string description: The URL that uniquely identifies the resource being returned in the response. - example: /prism-agent/verification/policies/0527aea1-d131-3948-a34d-03af39aba8b4 + example: /cloud-agent/verification/policies/0527aea1-d131-3948-a34d-03af39aba8b4 kind: type: string description: A string that identifies the type of resource being returned @@ -5262,7 +5262,7 @@ components: type: string description: The URL that uniquely identifies the resource being returned in the response. - example: /prism-agent/verification/policies?name=Trusted&offset=0&limit=10 + example: /cloud-agent/verification/policies?name=Trusted&offset=0&limit=10 kind: type: string description: A string that identifies the type of resource being returned @@ -5272,19 +5272,19 @@ components: type: string description: A string field indicating the type of resource that the contents field contains - example: /prism-agent/verification/policies + example: /cloud-agent/verification/policies next: type: string description: An optional string field containing the URL of the next page of results. If the API response does not contain any more pages, this field should be set to None. - example: /prism-agent/verification/policies?skip=20&limit=10 + example: /cloud-agent/verification/policies?skip=20&limit=10 previous: type: string description: An optional string field containing the URL of the previous page of results. If the API response is the first page of results, this field should be set to None. - example: /prism-agent/verification/policies?skip=0&limit=10 + example: /cloud-agent/verification/policies?skip=0&limit=10 contents: type: array items: @@ -5292,7 +5292,7 @@ components: description: A sequence of VerificationPolicyResponse objects representing the list of verification policies that the paginated response contains example: - - self: /prism-agent/verification/policies + - self: /cloud-agent/verification/policies kind: VerificationPolicy id: 0527aea1-d131-3948-a34d-03af39aba8b4 nonce: 0 diff --git a/infrastructure/charts/agent/Chart.yaml b/infrastructure/charts/agent/Chart.yaml index 8b943782b5..ba6bb3255b 100644 --- a/infrastructure/charts/agent/Chart.yaml +++ b/infrastructure/charts/agent/Chart.yaml @@ -13,12 +13,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.32.1 +version: 1.33.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: 1.32.1 +appVersion: 1.33.0 dependencies: - name: vault version: 0.24.1 diff --git a/infrastructure/charts/index.yaml b/infrastructure/charts/index.yaml index d012faf33d..a41b549451 100644 --- a/infrastructure/charts/index.yaml +++ b/infrastructure/charts/index.yaml @@ -1,9 +1,27 @@ apiVersion: v1 entries: prism-agent: + - apiVersion: v2 + appVersion: 1.33.0 + created: "2024-05-09T04:14:16.085599775Z" + dependencies: + - name: vault + repository: https://helm.releases.hashicorp.com + version: 0.24.1 + - condition: keycloak.enabled + name: keycloak + repository: https://charts.bitnami.com/bitnami + version: 17.2.0 + description: A Helm chart for deploying prism-agent + digest: 10a66e6d49cb02321d1eafd4bfe784e0fef6edeccb1c678abcc3befd731c0f3a + name: prism-agent + type: application + urls: + - https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/main/infrastructure/charts/prism-agent-1.33.0.tgz + version: 1.33.0 - apiVersion: v2 appVersion: 1.32.1 - created: "2024-05-07T11:16:27.653690458Z" + created: "2024-05-09T04:14:16.075537341Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -21,7 +39,7 @@ entries: version: 1.32.1 - apiVersion: v2 appVersion: 1.32.0 - created: "2024-05-07T11:16:27.642515591Z" + created: "2024-05-09T04:14:16.065760223Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -39,7 +57,7 @@ entries: version: 1.32.0 - apiVersion: v2 appVersion: 1.31.0 - created: "2024-05-07T11:16:27.632501068Z" + created: "2024-05-09T04:14:16.056525144Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -57,7 +75,7 @@ entries: version: 1.31.0 - apiVersion: v2 appVersion: 1.30.1 - created: "2024-05-07T11:16:27.621312345Z" + created: "2024-05-09T04:14:16.046167348Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -75,7 +93,7 @@ entries: version: 1.30.1 - apiVersion: v2 appVersion: 1.30.0 - created: "2024-05-07T11:16:27.611378153Z" + created: "2024-05-09T04:14:16.035349983Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -93,7 +111,7 @@ entries: version: 1.30.0 - apiVersion: v2 appVersion: 1.29.0 - created: "2024-05-07T11:16:27.600753265Z" + created: "2024-05-09T04:14:16.025603626Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -111,7 +129,7 @@ entries: version: 1.29.0 - apiVersion: v2 appVersion: 1.28.0 - created: "2024-05-07T11:16:27.59061395Z" + created: "2024-05-09T04:14:16.01558412Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -129,7 +147,7 @@ entries: version: 1.28.0 - apiVersion: v2 appVersion: 1.27.0 - created: "2024-05-07T11:16:27.580733909Z" + created: "2024-05-09T04:14:16.006104832Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -147,7 +165,7 @@ entries: version: 1.27.0 - apiVersion: v2 appVersion: 1.26.0 - created: "2024-05-07T11:16:27.570285213Z" + created: "2024-05-09T04:14:15.9952297Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -165,7 +183,7 @@ entries: version: 1.26.0 - apiVersion: v2 appVersion: 1.25.0 - created: "2024-05-07T11:16:27.55993564Z" + created: "2024-05-09T04:14:15.985684248Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -183,7 +201,7 @@ entries: version: 1.25.0 - apiVersion: v2 appVersion: 1.24.0 - created: "2024-05-07T11:16:27.54997569Z" + created: "2024-05-09T04:14:15.975103949Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -201,7 +219,7 @@ entries: version: 1.24.0 - apiVersion: v2 appVersion: 1.23.0 - created: "2024-05-07T11:16:27.538591962Z" + created: "2024-05-09T04:14:15.965236514Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -219,7 +237,7 @@ entries: version: 1.23.0 - apiVersion: v2 appVersion: 1.22.0 - created: "2024-05-07T11:16:27.528993148Z" + created: "2024-05-09T04:14:15.955207803Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -237,7 +255,7 @@ entries: version: 1.22.0 - apiVersion: v2 appVersion: 1.21.1 - created: "2024-05-07T11:16:27.518115901Z" + created: "2024-05-09T04:14:15.944448492Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -255,7 +273,7 @@ entries: version: 1.21.1 - apiVersion: v2 appVersion: 1.21.0 - created: "2024-05-07T11:16:27.507791701Z" + created: "2024-05-09T04:14:15.935028185Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -273,7 +291,7 @@ entries: version: 1.21.0 - apiVersion: v2 appVersion: 1.20.1 - created: "2024-05-07T11:16:27.498373165Z" + created: "2024-05-09T04:14:15.924585887Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -291,7 +309,7 @@ entries: version: 1.20.1 - apiVersion: v2 appVersion: 1.20.0 - created: "2024-05-07T11:16:27.487590109Z" + created: "2024-05-09T04:14:15.915008523Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -309,7 +327,7 @@ entries: version: 1.20.0 - apiVersion: v2 appVersion: 1.19.1 - created: "2024-05-07T11:16:27.475636701Z" + created: "2024-05-09T04:14:15.905444513Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -327,7 +345,7 @@ entries: version: 1.19.1 - apiVersion: v2 appVersion: 1.19.0 - created: "2024-05-07T11:16:27.465601019Z" + created: "2024-05-09T04:14:15.895893753Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -345,7 +363,7 @@ entries: version: 1.19.0 - apiVersion: v2 appVersion: 1.18.0 - created: "2024-05-07T11:16:27.455032514Z" + created: "2024-05-09T04:14:15.886190624Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -359,7 +377,7 @@ entries: version: 1.18.0 - apiVersion: v2 appVersion: 1.17.0 - created: "2024-05-07T11:16:27.452077627Z" + created: "2024-05-09T04:14:15.883157363Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -373,7 +391,7 @@ entries: version: 1.17.0 - apiVersion: v2 appVersion: 1.16.4 - created: "2024-05-07T11:16:27.449273283Z" + created: "2024-05-09T04:14:15.880375013Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -387,7 +405,7 @@ entries: version: 1.16.4 - apiVersion: v2 appVersion: 1.16.3 - created: "2024-05-07T11:16:27.445784373Z" + created: "2024-05-09T04:14:15.876828637Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -401,7 +419,7 @@ entries: version: 1.16.3 - apiVersion: v2 appVersion: 1.16.2 - created: "2024-05-07T11:16:27.442955443Z" + created: "2024-05-09T04:14:15.873974292Z" dependencies: - name: vault repository: https://helm.releases.hashicorp.com @@ -413,4 +431,4 @@ entries: urls: - https://raw.githubusercontent.com/hyperledger/identus-cloud-agent/main/infrastructure/charts/prism-agent-1.16.2.tgz version: 1.16.2 -generated: "2024-05-07T11:16:27.439865083Z" +generated: "2024-05-09T04:14:15.870872322Z" diff --git a/infrastructure/charts/prism-agent-1.33.0.tgz b/infrastructure/charts/prism-agent-1.33.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..e0995dd48c2366235acaabbfa7dabc7bd8dd75e8 GIT binary patch literal 160974 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

diUv0?Y~DQPV`diYIdLbRRN?ZV#2T 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.13.0" }, diff --git a/version.sbt b/version.sbt index 3dd20a0723..f7b55429b2 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "1.32.1-SNAPSHOT" +ThisBuild / version := "1.33.0-SNAPSHOT" From c166dc4149f2a4c70c709e3eef6455a8547ae8c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 13:09:40 +0000 Subject: [PATCH 08/14] chore(deps): bump follow-redirects from 1.15.2 to 1.15.6 in /cloud-agent/client/generator (#989) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yurii Shynbuiev - IOHK --- cloud-agent/client/generator/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cloud-agent/client/generator/yarn.lock b/cloud-agent/client/generator/yarn.lock index cc43396b3c..faf654ad56 100644 --- a/cloud-agent/client/generator/yarn.lock +++ b/cloud-agent/client/generator/yarn.lock @@ -457,9 +457,9 @@ figures@^3.0.0: escape-string-regexp "^1.0.5" follow-redirects@^1.14.9: - version "1.15.2" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== for-each@^0.3.3: version "0.3.3" From 92d17c2b5f82d0ca35313ab51bd90b6f55d2cd87 Mon Sep 17 00:00:00 2001 From: mkbreuning <97112931+mkbreuningIOHK@users.noreply.github.com> Date: Fri, 10 May 2024 23:45:24 +0800 Subject: [PATCH 09/14] fix: broken link for the cloud agent packages in readme file (#1032) Signed-off-by: mkbreuningIOHK Co-authored-by: Yurii Shynbuiev - IOHK --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1447ec6e1..aedaebcf3f 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ sbt clean compile test docker:publishLocal ### Installation and usage -Cloud Agent is distributed as a Docker image to be run in a containerized environment. All versions can be found [here](https://github.com/orgs/input-output-hk/packages/container/package/cloud-agent). +Cloud Agent is distributed as a Docker image to be run in a containerized environment. Versions after v1.31.0 can be found [here](https://github.com/hyperledger/identus-cloud-agent/pkgs/container/identus-cloud-agent) and before v1.31.0, [here](https://github.com/orgs/input-output-hk/packages/container/package/prism-agent). The following sections describe how to run the Cloud Agent in different configurations. From d193c3da85aa69d3e7a486a18eb3c373d1b759b7 Mon Sep 17 00:00:00 2001 From: Yurii Shynbuiev - IOHK Date: Sat, 11 May 2024 00:12:46 +0700 Subject: [PATCH 10/14] ci: fix the publishing of ts client [skip ci] (#1031) Signed-off-by: Yurii Shynbuiev --- .github/workflows/release-clients.yml | 14 +++++++++----- cloud-agent/client/generator/publish-clients.sh | 1 + cloud-agent/client/typescript/package.json | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-clients.yml b/.github/workflows/release-clients.yml index 0f607a5368..ff687ffad5 100644 --- a/.github/workflows/release-clients.yml +++ b/.github/workflows/release-clients.yml @@ -4,22 +4,26 @@ on: workflow_dispatch: inputs: releaseTag: - description: "Tag to release clients (e.g. identus-cloud-agent-v1.33.0)" + description: "Tag to release clients (e.g. cloud-agent-v1.33.0)" required: true type: string push: tags: - - "identus-cloud-agent-v*" + - "cloud-agent-v*" + +permissions: + contents: read + packages: write jobs: publish-clients: - name: 'Build and publish Identus-cloud-Agent clients' + name: "Build and publish Identus Cloud Agent clients" runs-on: ubuntu-latest env: VERSION_TAG: ${{inputs.releaseTag || github.ref_name}} GITHUB_ACTOR: "hyperledger-bot" GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout @@ -35,7 +39,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: "3.10" - name: Setup Gradle uses: gradle/gradle-build-action@v2.8.0 diff --git a/cloud-agent/client/generator/publish-clients.sh b/cloud-agent/client/generator/publish-clients.sh index 820e5aa3e2..ab1fd636c9 100755 --- a/cloud-agent/client/generator/publish-clients.sh +++ b/cloud-agent/client/generator/publish-clients.sh @@ -2,6 +2,7 @@ set -e AGENT_VERSION=${VERSION_TAG:13} +echo version=${AGENT_VERSION} # install dependencies yarn diff --git a/cloud-agent/client/typescript/package.json b/cloud-agent/client/typescript/package.json index 28ac1fbfcd..e90c6b1778 100644 --- a/cloud-agent/client/typescript/package.json +++ b/cloud-agent/client/typescript/package.json @@ -13,7 +13,7 @@ "openapi-client", "openapi-generator" ], - "license": "Unlicensed", + "license": "Apache-2.0", "main": "./dist/index.js", "type": "commonjs", "exports": { From 975730ae5053721e5d16d5e0a15bd63b31405d9c Mon Sep 17 00:00:00 2001 From: Yurii Shynbuiev - IOHK Date: Mon, 13 May 2024 19:21:25 +0700 Subject: [PATCH 11/14] ci: switch Scala Steward to make the PRs as the hyperledger-bot (#1037) Signed-off-by: Yurii Shynbuiev --- .github/workflows/scala-steward.yml | 5 ++++- .scala-steward.conf | 23 +++++++++++++++++------ README.md | 5 +++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/scala-steward.yml b/.github/workflows/scala-steward.yml index bf174d5564..ecb618c936 100644 --- a/.github/workflows/scala-steward.yml +++ b/.github/workflows/scala-steward.yml @@ -17,9 +17,12 @@ jobs: - uses: crazy-max/ghaction-import-gpg@v3 id: import_gpg with: - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-private-key: ${{ secrets.HYP_BOT_GPG_PRIVATE }} + passphrase: ${{ secrets.HYP_BOT_GPG_PASSWORD }} git-user-signingkey: true git-commit-gpgsign: true + git_config_global: true + git_tag_gpgsign: true - name: Launch Scala Steward uses: scala-steward-org/scala-steward-action@v2 diff --git a/.scala-steward.conf b/.scala-steward.conf index e20f84cfd9..1d35eceedd 100644 --- a/.scala-steward.conf +++ b/.scala-steward.conf @@ -1,12 +1,23 @@ -buildRoots = [ "." ] +buildRoots = ["."] pullRequests.grouping = [ - { name = "all", title = "build: scala-steward dependency updates", "filter" = [{"group" = "*"}] } + {name = "tapir", title = "build: tapir dependency updates", "filter" = [{"group" = "com.softwaremill.sttp.tapir"}]}, + {name = "zio", title = "build: zio dependency updates", "filter" = [{"group" = "dev.zio"}]}, + {name = "dal", title = "build: DAL dependency update", "filter" = [{"group" = "io.getquill"}, {"group" = "flywaydb"}, {"group" = "org.postgresql"}, {"group" = "org.tpolecat"}]}, + {name = "protobuf", title = "build: protobuf dependency update", "filter" = [{"group" = "com.thesamet*"}]}, + {name = "sbt", title = "build: sbt and plugins dependency update", "filter" = [{"group" = "com.eed3si9n"}, {"group" = "com.github.sbt"}, {"group" = "org.scala-sbt"}, {"group" = "org.scalameta"}, {"group" = "org.scoverage"}]}, + {name = "internal", title = "build: internal dependency updates", "filter" = [{"group" = "io.iohk.atala*"}, {"group" = "org.hyperledger.identus*"}]}, + {name = "all", title = "build: scala-steward dependency updates", "filter" = [{"group" = "*"}]} ] updates.ignore = [ -# { groupId = "com.softwaremill.sttp.tapir", artifactId = "tapir-json-zio" }, #TODO - { groupId = "com.github.dasniko", artifactId = "testcontainers-keycloak" }, #TODO - { groupId = "org.keycloak", artifactId = "keycloak-authz-client" }, #TODO - { groupId = "dev.zio", artifactId = "zio-interop-cats" } #TODO + # { groupId = "com.softwaremill.sttp.tapir", artifactId = "tapir-json-zio" }, #TODO + {groupId = "com.github.dasniko", artifactId = "testcontainers-keycloak"}, #TODO + {groupId = "org.keycloak", artifactId = "keycloak-authz-client"}, #TODO + {groupId = "dev.zio", artifactId = "zio-interop-cats"} #TODO ] + +# If set, Scala Steward will only create or update `n` PRs each time it runs (see `pullRequests.frequency` above). +# Useful if running frequently and/or CI build are costly +# Default: null +updates.limit = 5 \ No newline at end of file diff --git a/README.md b/README.md index aedaebcf3f..68b2a131d2 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,11 @@ Unit tests End-to-end tests Performance tests + + Scala Steward badge + + +


From 998a13a157dc3427a8231a8f14a3e277ddc36266 Mon Sep 17 00:00:00 2001 From: shotexa Date: Wed, 15 May 2024 19:26:11 +0400 Subject: [PATCH 12/14] refactor: remove usage of secp256r1 and demos (#1043) Signed-off-by: Shota Jolbordi --- build.sbt | 2 - .../PresentationServiceSpecHelper.scala | 19 +- .../io/iohk/atala/pollux/vc/jwt/DidJWT.scala | 13 - .../atala/pollux/vc/jwt/JWTVerification.scala | 2 +- .../vc/jwt/VerifiableCredentialPayload.scala | 18 +- .../pollux/vc/jwt/demos/CredentialDemo.scala | 105 ------- ...tCredentialDIDDocumentValidationDemo.scala | 203 ------------- .../jwt/demos/JwtCredentialEncodingDemo.scala | 108 ------- ...wtCredentialTemporalVerificationDemo.scala | 151 ---------- .../demos/JwtPresentationCredentialDemo.scala | 161 ---------- ...PresentationTemporalVerificationDemo.scala | 279 ------------------ .../JwtPresentationVerificationDemo.scala | 275 ----------------- .../pollux/vc/jwt/demos/SchemaDemo.scala | 83 ------ .../jwt/revocation/VCStatusList2021Spec.scala | 23 +- 14 files changed, 33 insertions(+), 1409 deletions(-) delete mode 100644 pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/CredentialDemo.scala delete mode 100644 pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialDIDDocumentValidationDemo.scala delete mode 100644 pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialEncodingDemo.scala delete mode 100644 pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialTemporalVerificationDemo.scala delete mode 100644 pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationCredentialDemo.scala delete mode 100644 pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationTemporalVerificationDemo.scala delete mode 100644 pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationVerificationDemo.scala delete mode 100644 pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/SchemaDemo.scala diff --git a/build.sbt b/build.sbt index 0cfb605dac..fc84ccc210 100644 --- a/build.sbt +++ b/build.sbt @@ -85,8 +85,6 @@ lazy val V = new { val zioPreludeVersion = "1.0.0-RC24" val apollo = "1.2.14" - val bouncyCastle = "1.78.1" - val jsonSchemaValidator = "1.3.2" // scala-steward:off //TODO 1.3.2 need to fix: // [error] org.hyperledger.identus.pollux.core.model.schema.AnoncredSchemaTypeSpec // [error] org.hyperledger.identus.pollux.core.model.schema.CredentialSchemaSpec diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala index 558c24be92..7938a84631 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala @@ -11,9 +11,8 @@ import org.hyperledger.identus.pollux.core.repository.* import org.hyperledger.identus.pollux.core.service.serdes.* import org.hyperledger.identus.pollux.vc.jwt.* import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId} +import org.hyperledger.identus.shared.crypto.KmpSecp256k1KeyOps import zio.* - -import java.security.* import java.time.Instant import java.util.UUID @@ -42,16 +41,16 @@ trait PresentationServiceSpecHelper { CredentialRepositoryInMemory.layer ) ++ defaultWalletLayer - def createIssuer(did: DID) = { - val keyGen = KeyPairGenerator.getInstance("EC") - keyGen.initialize(Curve.P_256.toECParameterSpec) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic + def createIssuer(did: DID): Issuer = { + + val keyPair = KmpSecp256k1KeyOps.generateKeyPair + val javaSKey = keyPair.privateKey.toJavaPrivateKey + val javaPKey = keyPair.publicKey.toJavaPublicKey + Issuer( did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey + signer = ES256KSigner(javaSKey), + publicKey = javaPKey ) } diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/DidJWT.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/DidJWT.scala index 7b7c90fdf0..19bf145f9d 100644 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/DidJWT.scala +++ b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/DidJWT.scala @@ -29,19 +29,6 @@ trait Signer { } -class ES256Signer(privateKey: PrivateKey) extends Signer { - val algorithm: JwtECDSAAlgorithm = JwtAlgorithm.ES256 - private val provider = BouncyCastleProviderSingleton.getInstance - Security.addProvider(provider) - - override def encode(claim: Json): JWT = JWT(JwtCirce.encode(claim, privateKey, algorithm)) - - override def generateProofForJson(payload: Json, pk: PublicKey): Task[Proof] = { - EddsaJcs2022ProofGenerator.generateProof(payload, privateKey, pk) - } - -} - // works with java 7, 8, 11 & bouncycastle provider // https://connect2id.com/products/nimbus-jose-jwt/jca-algorithm-support#alg-support-table class ES256KSigner(privateKey: PrivateKey) extends Signer { diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/JWTVerification.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/JWTVerification.scala index c40f8f3cdd..fbebe05907 100644 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/JWTVerification.scala +++ b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/JWTVerification.scala @@ -22,7 +22,7 @@ object JWTVerification { // https://github.com/decentralized-identity/did-jwt/blob/8b3655097a1382934cabdf774d580e6731a636b1/src/JWT.ts#L146 val SUPPORT_PUBLIC_KEY_TYPES: Map[String, Set[String]] = Map( "ES256K" -> Set("EcdsaSecp256k1VerificationKey2019", "JsonWebKey2020"), - "ES256" -> Set("ES256") // TODO: Only use valid type (added just for compatibility in the Demo code) + // Add support for other key types here ) def validateAlgorithm(jwt: JWT): Validation[String, Unit] = { diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/VerifiableCredentialPayload.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/VerifiableCredentialPayload.scala index f99dc7a492..445b707dd7 100644 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/VerifiableCredentialPayload.scala +++ b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/VerifiableCredentialPayload.scala @@ -17,6 +17,8 @@ import java.security.PublicKey import java.time.temporal.TemporalAmount import java.time.{Clock, Instant, OffsetDateTime, ZoneId} import scala.util.Try +import com.nimbusds.jwt.SignedJWT +import scala.util.Failure opaque type DID = String object DID { @@ -711,9 +713,15 @@ object JwtCredential { def encodeJwt(payload: JwtCredentialPayload, issuer: Issuer): JWT = issuer.signer.encode(payload.asJson) def decodeJwt(jwt: JWT, publicKey: PublicKey): Try[JwtCredentialPayload] = { - JwtCirce - .decodeRaw(jwt.value, publicKey, options = JwtOptions(expiration = false, notBefore = false)) - .flatMap(decode[JwtCredentialPayload](_).toTry) + val signedJWT = SignedJWT.parse(jwt.value) + val verifier = JWTVerification.toECDSAVerifier(publicKey) + + val isSignatureValid = signedJWT.verify(verifier) + + if isSignatureValid then + val claimsSet = signedJWT.getJWTClaimsSet.toString + decode[JwtCredentialPayload](claimsSet).toTry + else Failure(Exception(s"Invalid JWT signature for: ${JWT.value}")) } def decodeJwt(jwt: JWT): IO[String, JwtCredentialPayload] = { @@ -731,7 +739,9 @@ object JwtCredential { } def validateEncodedJwt(jwt: JWT, publicKey: PublicKey): Boolean = - JwtCirce.isValid(jwt.value, publicKey, JwtOptions(expiration = false, notBefore = false)) + val signedJWT = SignedJWT.parse(jwt.value) + val verifier = JWTVerification.toECDSAVerifier(publicKey) + signedJWT.verify(verifier) def validateEncodedJWT( jwt: JWT, diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/CredentialDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/CredentialDemo.scala deleted file mode 100644 index fd3c48733a..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/CredentialDemo.scala +++ /dev/null @@ -1,105 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.parser.decode -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import java.time.Instant - -@main def CredentialDemo(): Unit = - val w3cCredentialPayload = W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = DID("https://example.edu/issuers/565049"), - issuanceDate = Instant.parse("2010-01-01T00:00:00Z"), - maybeExpirationDate = Some(Instant.parse("2010-01-12T00:00:00Z")), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - - println("") - println("==================") - println("W3C => W3C Json") - println("==================") - val w3cJson = w3cCredentialPayload.asJson.toString() - println(w3cJson) - - println("") - println("==================") - println("W3C Json => W3C") - println("==================") - val decodedW3CJson = decode[W3cCredentialPayload](w3cJson).toOption.get - println(decodedW3CJson) - - println("") - println("==================") - println("W3C => JWT") - println("==================") - val jwtCredentialPayload = w3cCredentialPayload.toJwtCredentialPayload - println(jwtCredentialPayload) - - println("") - println("==================") - println("JWT => JWT+AUD") - println("==================") - val jwtAudCredentialPayload = - jwtCredentialPayload.copy(aud = - Set("did:example:4a57546973436f6f6c4a4a57573", "did:example:s7dfsd86f5sd6fsdf6sfs6d5sdf") - ) - println(jwtAudCredentialPayload) - - println("") - println("==================") - println("JWT+AUD => JWT+AUD Json") - println("==================") - val jwtAudCredentialJson = jwtAudCredentialPayload.asJson.toString() - println(jwtAudCredentialJson) - - println("") - println("==================") - println("JWT+AUD Json => JWT+AUD ") - println("==================") - val decodedJwtAudCredentialPayload = decode[JwtCredentialPayload](jwtAudCredentialJson).toOption.get - println(decodedJwtAudCredentialPayload) - - println("") - println("==================") - println("JWT+AUD => W3C") - println("==================") - val convertedJwtAudToW3CCredential = decodedJwtAudCredentialPayload.toW3CCredentialPayload - println(convertedJwtAudToW3CCredential.asJson.toString()) - - println("") - println("==================") - println("W3C => JWT+AUD") - println("==================") - val convertedW3CToJwtAudCredential = convertedJwtAudToW3CCredential.toJwtCredentialPayload - println(convertedW3CToJwtAudCredential.asJson.toString()) diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialDIDDocumentValidationDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialDIDDocumentValidationDemo.scala deleted file mode 100644 index dc4d4a546e..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialDIDDocumentValidationDemo.scala +++ /dev/null @@ -1,203 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import com.nimbusds.jose.jwk.* -import io.circe.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.schema.{PlaceholderSchemaValidator, SchemaResolver} -import pdi.jwt.JwtAlgorithm -import zio.* -import zio.Console.* -import java.security.* -import java.security.interfaces.{ECPrivateKey, ECPublicKey} -import java.time.Instant -import scala.collection.immutable.Set - -object JwtCredentialDIDDocumentValidationDemo extends ZIOAppDefault { - def run = - def createUser(did: DID) = { - val keyGen = KeyPairGenerator.getInstance("EC") - keyGen.initialize(Curve.P_256.toECParameterSpec) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - ( - Issuer( - did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey - ), - new ECKey.Builder(Curve.P_256, publicKey.asInstanceOf[ECPublicKey]) - .privateKey(privateKey.asInstanceOf[ECPrivateKey]) - .build() - ) - } - - println("") - println("==================") - println("Create Issuer1") - println("==================") - val (issuer1, issuer1Jwk) = - createUser(DID("did:issuer1:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer1) - - println("") - println("==================") - println("Create Issuer2") - println("==================") - val (issuer2, issuer2Jwk) = - createUser(DID("did:issuer2:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer2) - - println("") - println("==================") - println("Create Issuer3") - println("==================") - val (issuer3, issuer3Jwk) = - createUser(DID("did:issuer3:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer3) - - println("") - println("==================") - println("Create JWT Credential") - println("==================") - val jwtCredentialPayload = - JwtCredentialPayload( - iss = "https://example.edu/issuers/565049", // ISSUER DID - maybeSub = Some("1"), // SUBJECT DID - vc = JwtVc( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "id" -> Json.fromString("1"), - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ), - nbf = Instant.parse("2010-01-01T00:00:00Z"), // ISSUANCE DATE - aud = Set.empty, - maybeExp = Some(Instant.parse("2010-01-12T00:00:00Z")), // EXPIRATION DATE - maybeJti = Some("http://example.edu/credentials/3732") // CREDENTIAL ID - ) - - val schemaResolved = new SchemaResolver { - override def resolve(credentialSchema: CredentialSchema): IO[String, Json] = { - println("Resolving Schema") - val resolvedSchema = - """ - |{ - | "type": "object", - | "properties": { - | "userName": { - | "$ref": "#/$defs/user" - | }, - | "age": { - | "$ref": "#/$defs/age" - | }, - | "email": { - | "$ref": "#/$defs/email" - | } - | }, - | "required": ["userName", "age", "email"], - | "$defs": { - | "user": { - | "type": "string", - | "minLength": 3 - | }, - | "age": { - | "type": "number" - | }, - | "email": { - | "type": "string", - | "format": "email" - | } - | } - |} - |""".stripMargin - ZIO.succeed(io.circe.parser.parse(resolvedSchema).toOption.get) - } - } - - class DidResolverTest() extends DidResolver { - - override def resolve(didUrl: String): UIO[DIDResolutionResult] = { - val Issuer1Key = - VerificationMethod( - id = "Issuer1Key", - `type` = JwtAlgorithm.ES256.name, - controller = "", - publicKeyJwk = Some( - toJWKFormat(issuer1Jwk) - ) - ) - val issuer2Key = VerificationMethod( - id = "Issuer2Key", - `type` = JwtAlgorithm.ES256.name, - controller = "", - publicKeyJwk = Some( - toJWKFormat(issuer2Jwk) - ) - ) - val didDocument = DIDDocument( - id = "Test", - alsoKnowAs = Vector.empty, - controller = Vector.empty, - verificationMethod = Vector( - Issuer1Key, // <------ ISSUER PUBLIC-KEY 1 - issuer2Key // <------ ISSUER PUBLIC-KEY 2 - ), - service = Vector.empty - ) - ZIO.succeed( - DIDResolutionSucceeded( - didDocument, // <------ DID DOCUMENT - DIDDocumentMetadata() - ) - ) - } - } - - println("") - println("==================") - println("Encode JWT Credential") - println("==================") - val encodedJwt = JwtCredential.encodeJwt(jwtCredentialPayload, issuer = issuer2) - - println("") - println("==================") - println("Validate JWT Credential Using DID Document of the Issuer of the Credential") - println("==================") - val validator = - JwtCredential.validateSchemaAndSignature(encodedJwt)(DidResolverTest())(schemaResolved)( - PlaceholderSchemaValidator.fromSchema - ) - - for { - _ <- printLine("DEMO TIME! ") - result <- validator - _ <- printLine(s"IS VALID?: $result") - } yield () -} diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialEncodingDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialEncodingDemo.scala deleted file mode 100644 index bd3347ae8a..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialEncodingDemo.scala +++ /dev/null @@ -1,108 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import java.security.* -import java.security.spec.* -import java.time.Instant - -@main def JwtCredentialEncodingDemo(): Unit = - - println("") - println("==================") - println("Create Issuer") - println("==================") - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - val issuer = - Issuer( - did = DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T"), - signer = ES256Signer(privateKey), - publicKey = publicKey - ) - println(issuer) - - println("") - println("==================") - println("Create W3C") - println("==================") - val w3cCredentialPayload = - W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = DID("https://example.edu/issuers/565049"), - issuanceDate = Instant.parse("2010-01-01T00:00:00Z"), - maybeExpirationDate = Some(Instant.parse("2010-01-12T00:00:00Z")), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - println(w3cCredentialPayload.asJson.toString()) - - println("") - println("==================") - println("W3C => Encoded JWT") - println("==================") - val encodedJWT = W3CCredential.toEncodedJwt(w3cCredentialPayload, issuer) - println(encodedJWT) - - println("") - println("==================") - println("Validate: Encoded JWT") - println("==================") - val valid = JwtCredential.validateEncodedJwt(encodedJWT, issuer.publicKey) - println(s"Is Valid? $valid") - - println("") - println("==================") - println("Encoded JWT -> Decoded JWT") - println("==================") - val decodedJwtCredential = JwtCredential.decodeJwt(encodedJWT, issuer.publicKey) - val decodedJwtCredentialAsJson = decodedJwtCredential.toOption.get.asJson.toString() - println(decodedJwtCredentialAsJson) - - println("") - println("==================") - println("W3C -> JWT") - println("==================") - val jwtCredentialPayload = w3cCredentialPayload.toJwtCredentialPayload - val jwtCredentialPayloadAsJson = jwtCredentialPayload.asJson.toString() - println(jwtCredentialPayloadAsJson) - - println("") - println("==================") - println("JWT Json = Decoded JWT (W3C -> Decoded JWT -> Encoded JWT -> Decoded JWT )") - println("==================") - println(s"Are equal? ${jwtCredentialPayloadAsJson == decodedJwtCredentialAsJson}") diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialTemporalVerificationDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialTemporalVerificationDemo.scala deleted file mode 100644 index 07ed493702..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialTemporalVerificationDemo.scala +++ /dev/null @@ -1,151 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* - -import java.security.* -import java.security.spec.* -import java.time.* - -@main def JwtCredentialTemporalVerificationDemo(): Unit = - - println("") - println("==================") - println("Create Issuer") - println("==================") - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - val issuer = - Issuer( - did = DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T"), - signer = ES256Signer(privateKey), - publicKey = publicKey - ) - println(issuer) - - println("") - println("==================") - println("Create JWT Credential") - println("==================") - val nbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val exp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val jwtCredentialPayload = - JwtCredentialPayload( - iss = "https://example.edu/issuers/565049", // ISSUER DID - maybeSub = Some("1"), // SUBJECT DID - vc = JwtVc( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "id" -> Json.fromString("1"), - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ), - nbf = nbf, // ISSUANCE DATE - aud = Set.empty, - maybeExp = Some(exp), // EXPIRATION DATE - maybeJti = Some("http://example.edu/credentials/3732") // CREDENTIAL ID - ) - println(jwtCredentialPayload.asJson.toString()) - - println("") - println("==================") - println("Encoded JWT") - println("==================") - val encodedJWT = JwtCredential.encodeJwt(payload = jwtCredentialPayload, issuer = issuer) - println(encodedJWT) - - println("") - println("==================") - println("Validate JWT between ISSUANCE DATE and EXPIRATION DATE") - println("==================") - val clockWithCurrentTime = Clock.fixed(nbf.plus(Duration.ofDays(1)), ZoneId.systemDefault) - val validAtCurrentTime = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithCurrentTime) - println(s"Is Valid at current time? $validAtCurrentTime") - - println("") - println("==================") - println("Validate JWT on ISSUANCE DATE") - println("==================") - val clockWithFixedTimeAtNbf = Clock.fixed(nbf, ZoneId.systemDefault) - val validAtNbf = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithFixedTimeAtNbf) - println(s"Is Valid at ISSUANCE DATE? $validAtNbf") - - println("") - println("==================") - println("Validate JWT on EXPIRATION DATE") - println("==================") - val clockWithFixedTimeAtExp = Clock.fixed(exp, ZoneId.systemDefault) - val validAtExp = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithFixedTimeAtExp) - println(s"Is Valid at EXPIRATION DATE? $validAtExp") - - println("") - println("==================") - println("Validate JWT before ISSUANCE DATE") - println("==================") - val clockWithFixedTimeBeforeNbf = Clock.fixed(nbf.minus(Duration.ofDays(1)), ZoneId.systemDefault) - val validBeforeNbf = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithFixedTimeBeforeNbf) - println(s"Is Valid before ISSUANCE DATE? $validBeforeNbf") - - println("") - println("==================") - println("Validate JWT after EXPIRATION DATE") - println("==================") - val clockWithFixedTimeAfterExp = Clock.fixed(exp.plus(Duration.ofDays(1)), ZoneId.systemDefault) - val validAfterExp = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithFixedTimeAfterExp) - println(s"Is Valid after EXPIRATION DATE? $validAfterExp") - - println("") - println("==================") - println("Validate JWT before ISSUANCE DATE with 1 Day Leeway") - println("==================") - val leeway = Duration.ofDays(1) - val validBeforeNbfWithLeeway = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = leeway)(clock = clockWithFixedTimeBeforeNbf) - println( - s"Is Valid before ISSUANCE DATE with 1 Day Leeway? $validBeforeNbfWithLeeway with leeway:$leeway" - ) - - println("") - println("==================") - println("Validate JWT after EXPIRATION DATE with 1 Day Leeway") - println("==================") - val validAfterExpWithLeeway = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = leeway)(clock = clockWithFixedTimeAfterExp) - println(s"Is Valid after EXPIRATION DATE with 1 Day Leeway? $validAfterExpWithLeeway with leeway:$leeway") diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationCredentialDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationCredentialDemo.scala deleted file mode 100644 index f103d787e3..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationCredentialDemo.scala +++ /dev/null @@ -1,161 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import org.hyperledger.identus.pollux.vc.jwt.PresentationPayload.Implicits.* - -import java.security.* -import java.security.spec.* -import java.time.Instant - -@main def JwtPresentationWithJWTCredentialDemo(): Unit = - - def createUser(did: DID) = { - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - Issuer( - did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey - ) - } - - println("") - println("==================") - println("Create Issuer") - println("==================") - val issuer = - createUser(DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer) - - println("") - println("==================") - println("Create Holder") - println("==================") - val holder = - createUser(DID("did:holder:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder) - - println("") - println("==================") - println("Create W3C Presentation") - println("==================") - val w3cCredentialPayload = - W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = DID("https://example.edu/issuers/565049"), - issuanceDate = Instant.parse("2010-01-01T00:00:00Z"), - maybeExpirationDate = Some(Instant.parse("2010-01-12T00:00:00Z")), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - - val w3cIssuerSignedCredential = issuer.signer.encode(w3cCredentialPayload.asJson) - val w3cVerifiableCredentialPayload = - W3cVerifiableCredentialPayload( - payload = w3cCredentialPayload, - proof = JwtProof( - `type` = "JwtProof2020", - jwt = w3cIssuerSignedCredential - ) - ) - - val JWTIssuerSignedCredential = issuer.signer.encode(w3cCredentialPayload.toJwtCredentialPayload.asJson) - val jwtVerifiableCredentialPayload = JwtVerifiableCredentialPayload(JWTIssuerSignedCredential) - - val w3cPresentationPayload = - W3cPresentationPayload( - `@context` = - Vector("https://www.w3.org/2018/presentations/v1", "https://www.w3.org/2018/presentations/examples/v1"), - maybeId = Some("http://example.edu/presentations/3732"), - `type` = Vector("VerifiablePresentation", "UniversityDegreePresentation"), - verifiableCredential = Vector(w3cVerifiableCredentialPayload, jwtVerifiableCredentialPayload), - holder = "https://example.edu/holder/565049", - verifier = Vector("https://example.edu/issuers/565049"), - maybeIssuanceDate = Some(Instant.parse("2010-01-01T00:00:00Z")), - maybeExpirationDate = Some(Instant.parse("2010-01-12T00:00:00Z")) - ) - println(w3cPresentationPayload.asJson.toString()) - - println("") - println("==================") - println("W3C Presentation => Encoded JWT") - println("==================") - val encodedJWT = JwtPresentation.toEncodedJwt(w3cPresentationPayload, holder) - println(encodedJWT) - - println("") - println("==================") - println("Validate Encoded JWT") - println("==================") - val valid = JwtPresentation.validateEncodedJwt(encodedJWT, holder.publicKey) - println(s"Is Valid? $valid") - - println("") - println("==================") - println("Encoded JWT => Decoded JWT Presentation Json") - println("==================") - val decodedJwtPresentation = JwtPresentation.decodeJwt(encodedJWT, holder.publicKey).toOption.get - val decodedJwtPresentationAsJson = decodedJwtPresentation.asJson.toString() - println(decodedJwtPresentationAsJson) - - println("") - println("==================") - println("Validates Signature Of Credentials") - println("==================") - decodedJwtPresentation.vp.verifiableCredential.foreach { - case (w3cVerifiableCredentialPayload: W3cVerifiableCredentialPayload) => - println(s"w3cVerifiableCredentialPayload Is Valid? ${JwtPresentation - .validateEncodedJwt(w3cVerifiableCredentialPayload.proof.jwt, issuer.publicKey)}") - case (jwtVerifiableCredentialPayload: JwtVerifiableCredentialPayload) => - println(s"jwtVerifiableCredentialPayload Is Valid? ${JwtPresentation - .validateEncodedJwt(jwtVerifiableCredentialPayload.jwt, issuer.publicKey)}") - } - - println("") - println("==================") - println("W3C Presentation => JWT Presentation Json") - println("==================") - val jwtPresentationPayload = w3cPresentationPayload.toJwtPresentationPayload - val jwtPresentationPayloadAsJson = jwtPresentationPayload.asJson.toString() - println(jwtPresentationPayloadAsJson) - - println("") - println("==================") - println("JWT Presentation Json = Decoded JWT Presentation Json") - println("==================") - println(s"Are equal? ${jwtPresentationPayloadAsJson == decodedJwtPresentationAsJson}") diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationTemporalVerificationDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationTemporalVerificationDemo.scala deleted file mode 100644 index 8eab14abec..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationTemporalVerificationDemo.scala +++ /dev/null @@ -1,279 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import org.hyperledger.identus.pollux.vc.jwt.PresentationPayload.Implicits.* - -import java.security.* -import java.security.spec.* -import java.time.* -import scala.collection.immutable.Set - -@main def JwtPresentationTemporalVerificationDemo(): Unit = - def createUser(did: DID) = { - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - Issuer( - did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey - ) - } - - println("") - println("==================") - println("Create Issuer") - println("==================") - val issuer = - createUser(DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer) - - println("") - println("==================") - println("Create Holder") - println("==================") - val holder = - createUser(DID("did:holder:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder) - - println("") - println("==================") - println("Create W3C Presentation") - println("==================") - val w3cIssuanceDate = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val w3cExpirationDate = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val w3cCredentialPayload = - W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = DID("https://example.edu/issuers/565049"), - issuanceDate = w3cIssuanceDate, - maybeExpirationDate = Some(w3cExpirationDate), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - - val w3cIssuerSignedCredential = issuer.signer.encode(w3cCredentialPayload.asJson) - val w3cVerifiableCredentialPayload = - W3cVerifiableCredentialPayload( - payload = w3cCredentialPayload, - proof = JwtProof( - `type` = "JwtProof2020", - jwt = w3cIssuerSignedCredential - ) - ) - - val jwtCredentialNbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val jwtCredentialExp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val jwtCredentialPayload = - JwtCredentialPayload( - iss = "https://example.edu/issuers/565049", // ISSUER DID - maybeSub = Some("1"), // SUBJECT DID - vc = JwtVc( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "id" -> Json.fromString("1"), - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ), - nbf = jwtCredentialNbf, // ISSUANCE DATE - aud = Set.empty, - maybeExp = Some(jwtCredentialExp), // EXPIRATION DATE - maybeJti = Some("http://example.edu/credentials/3732") // CREDENTIAL ID - ) - - val JWTIssuerSignedCredential = issuer.signer.encode(jwtCredentialPayload.asJson) - val jwtVerifiableCredentialPayload = JwtVerifiableCredentialPayload(JWTIssuerSignedCredential) - - val jwtPresentationNbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val jwtPresentationExp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - - def presentationPayload( - maybeJwtPresentationNbf: Option[Instant], - maybeJwtPresentationExp: Option[Instant] - ): JwtPresentationPayload = { - JwtPresentationPayload( - iss = "https://example.edu/holder/565049", - maybeJti = Some("http://example.edu/presentations/3732"), - vp = JwtVp( - `@context` = - Vector("https://www.w3.org/2018/presentations/v1", "https://www.w3.org/2018/presentations/examples/v1"), - `type` = Vector("VerifiablePresentation", "UniversityDegreePresentation"), - verifiableCredential = Vector(w3cVerifiableCredentialPayload, jwtVerifiableCredentialPayload) - ), - aud = Vector("https://example.edu/issuers/565049"), - maybeNbf = maybeJwtPresentationNbf, - maybeExp = maybeJwtPresentationExp, - maybeNonce = None - ) - } - - val jwtPresentationPayload = presentationPayload(Some(jwtPresentationNbf), Some(jwtPresentationExp)) - println(jwtPresentationPayload.asJson.toString()) - - println("") - println("==================") - println("Encoded JWT") - println("==================") - val encodedJWTPresentation = JwtPresentation.encodeJwt(payload = jwtPresentationPayload, issuer = issuer) - println(encodedJWTPresentation) - - println("") - println("==================") - println("Validate JWT between ISSUANCE DATE and EXPIRATION DATE") - println("==================") - val clockWithCurrentTime = Clock.fixed(jwtPresentationNbf.plus(Duration.ofDays(1)), ZoneId.systemDefault) - val validAtCurrentTime = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = clockWithCurrentTime) - println(s"Is Valid at current time? $validAtCurrentTime") - - println("") - println("==================") - println("Validate JWT on ISSUANCE DATE") - println("==================") - val clockWithFixedTimeAtNbf = Clock.fixed(jwtPresentationNbf, ZoneId.systemDefault) - val validAtNbf = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = clockWithFixedTimeAtNbf) - println(s"Is Valid at ISSUANCE DATE? $validAtNbf") - - println("") - println("==================") - println("Validate JWT on EXPIRATION DATE") - println("==================") - val clockWithFixedTimeAtExp = Clock.fixed(jwtPresentationExp, ZoneId.systemDefault) - val validAtExp = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = clockWithFixedTimeAtExp) - println(s"Is Valid at EXPIRATION DATE? $validAtExp") - - println("") - println("==================") - println("Validate JWT before ISSUANCE DATE") - println("==================") - val clockWithFixedTimeBeforeNbf = Clock.fixed(jwtPresentationNbf.minus(Duration.ofDays(1)), ZoneId.systemDefault) - val validBeforeNbf = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = - clockWithFixedTimeBeforeNbf - ) - println(s"Is Valid before ISSUANCE DATE? $validBeforeNbf") - - println("") - println("==================") - println("Validate JWT after EXPIRATION DATE") - println("==================") - val clockWithFixedTimeAfterExp = Clock.fixed(jwtPresentationExp.plus(Duration.ofDays(1)), ZoneId.systemDefault) - val validAfterExp = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = - clockWithFixedTimeAfterExp - ) - println(s"Is Valid after EXPIRATION DATE? $validAfterExp") - - println("") - println("==================") - println("Validate JWT before ISSUANCE DATE with 1 Day Leeway") - println("==================") - val leeway = Duration.ofDays(1) - val validBeforeNbfWithLeeway = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = leeway)(clock = clockWithFixedTimeBeforeNbf) - println( - s"Is Valid before ISSUANCE DATE with 1 Day Leeway? $validBeforeNbfWithLeeway with leeway:$leeway" - ) - - println("") - println("==================") - println("Validate JWT after EXPIRATION DATE with 1 Day Leeway") - println("==================") - val validAfterExpWithLeeway = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = leeway)(clock = clockWithFixedTimeAfterExp) - println(s"Is Valid after EXPIRATION DATE with 1 Day Leeway? $validAfterExpWithLeeway with leeway:$leeway") - - println("") - println("==================") - println("Validate JWT No ISSUANCE DATE") - println("==================") - val encodedJWTPresentationNoNB = - JwtPresentation.encodeJwt(payload = presentationPayload(None, Some(jwtPresentationExp)), issuer = issuer) - - val noNbfValidBeforeExpiration = - JwtPresentation.verifyDates(jwt = encodedJWTPresentationNoNB, leeway = Duration.ZERO)(clock = clockWithCurrentTime) - println(s"Is Valid before EXPIRATION DATE: $noNbfValidBeforeExpiration") - - println("") - println("==================") - println("Validated JWT No EXPIRATION DATE") - println("==================") - val encodedJWTPresentationNoEXP = - JwtPresentation.encodeJwt(payload = presentationPayload(Some(jwtPresentationNbf), None), issuer = issuer) - val noExpValidAfterNbf = - JwtPresentation.verifyDates(jwt = encodedJWTPresentationNoEXP, leeway = Duration.ZERO)(clock = clockWithCurrentTime) - println(s"Is Valid after ISSUANCE DATE: $noExpValidAfterNbf") - - println("") - println("==================") - println("Validate JWT No EXPIRATION & No ISSUANCE DATE") - println("==================") - val encodedJWTPresentationNoEXPNoNbf: JWT = - JwtPresentation.encodeJwt(payload = presentationPayload(None, None), issuer = issuer) - val noEXPAndNbfAlwaysValid = - JwtPresentation.verifyDates(jwt = encodedJWTPresentationNoEXPNoNbf, leeway = Duration.ZERO)(clock = - clockWithCurrentTime - ) - println(s"Is Always Valid With non EXPIRATION DATE & No ISSUANCE DATE: $noEXPAndNbfAlwaysValid") diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationVerificationDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationVerificationDemo.scala deleted file mode 100644 index 2139cb95bd..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationVerificationDemo.scala +++ /dev/null @@ -1,275 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import com.nimbusds.jose.jwk.{Curve, ECKey} -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import org.hyperledger.identus.pollux.vc.jwt.PresentationPayload.Implicits.* -import pdi.jwt.JwtAlgorithm -import zio.Console.printLine -import zio.{UIO, ZIO, ZIOAppDefault} - -import java.security.* -import java.security.interfaces.{ECPrivateKey, ECPublicKey} -import java.time.* -import scala.collection.immutable.Set - -case class IssuerWithKey(issuer: Issuer, key: ECKey) -object JwtPresentationVerificationDemo extends ZIOAppDefault { - def run = - def createUser(did: DID): IssuerWithKey = { - val keyGen = KeyPairGenerator.getInstance("EC") - keyGen.initialize(Curve.P_256.toECParameterSpec) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - IssuerWithKey( - Issuer( - did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey - ), - new ECKey.Builder(Curve.P_256, publicKey.asInstanceOf[ECPublicKey]) - .privateKey(privateKey.asInstanceOf[ECPrivateKey]) - .build() - ) - } - - println("") - println("==================") - println("Create holder1") - println("==================") - val holder1 = createUser(DID("did:holder1:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder1) - - println("") - println("==================") - println("Create holder2") - println("==================") - val holder2 = createUser(DID("did:holder2:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder2) - - println("") - println("==================") - println("Create holder3") - println("==================") - val holder3 = createUser(DID("did:holder3:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder3) - - println("") - println("==================") - println("Create issuer1") - println("==================") - val issuer1 = createUser(DID("did:issuer1:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer1) - - println("") - println("==================") - println("Create issuer1") - println("==================") - val issuer2 = createUser(DID("did:issuer2:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer2) - - println("") - println("==================") - println("Create W3C Presentation") - println("==================") - val w3cIssuanceDate = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val w3cExpirationDate = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val w3cCredentialPayload = - W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = issuer1.issuer.did, - issuanceDate = w3cIssuanceDate, - maybeExpirationDate = Some(w3cExpirationDate), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - - val w3cIssuerSignedCredential = issuer1.issuer.signer.encode(w3cCredentialPayload.asJson) - val w3cVerifiableCredentialPayload = - W3cVerifiableCredentialPayload( - payload = w3cCredentialPayload, - proof = JwtProof( - `type` = "JwtProof2020", - jwt = w3cIssuerSignedCredential - ) - ) - - val jwtCredentialNbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val jwtCredentialExp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val jwtCredentialPayload = - JwtCredentialPayload( - iss = issuer2.issuer.did.value, // ISSUER DID - maybeSub = Some("1"), // SUBJECT DID - vc = JwtVc( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "id" -> Json.fromString("1"), - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ), - nbf = jwtCredentialNbf, // ISSUANCE DATE - aud = Set.empty, - maybeExp = Some(jwtCredentialExp), // EXPIRATION DATE - maybeJti = Some("http://example.edu/credentials/3732") // CREDENTIAL ID - ) - - val jwtIssuerSignedCredential = issuer2.issuer.signer.encode(jwtCredentialPayload.asJson) - val jwtVerifiableCredentialPayload = JwtVerifiableCredentialPayload(jwtIssuerSignedCredential) - - val jwtPresentationNbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val jwtPresentationExp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - - def presentationPayload( - maybeJwtPresentationNbf: Option[Instant], - maybeJwtPresentationExp: Option[Instant] - ): JwtPresentationPayload = { - JwtPresentationPayload( - iss = holder1.issuer.did.value, - maybeJti = Some("http://example.edu/presentations/3732"), - vp = JwtVp( - `@context` = - Vector("https://www.w3.org/2018/presentations/v1", "https://www.w3.org/2018/presentations/examples/v1"), - `type` = Vector("VerifiablePresentation", "UniversityDegreePresentation"), - verifiableCredential = Vector(w3cVerifiableCredentialPayload, jwtVerifiableCredentialPayload) - ), - aud = Vector("https://example.edu/issuers/565049"), - maybeNbf = maybeJwtPresentationNbf, - maybeExp = maybeJwtPresentationExp, - maybeNonce = None - ) - } - - val jwtPresentationPayload = presentationPayload(Some(jwtPresentationNbf), Some(jwtPresentationExp)) - println(jwtPresentationPayload.asJson.toString()) - - class DidResolverTest() extends DidResolver { - - private val resolverLookup: Map[String, DIDDocument] = Seq(holder1, holder2, holder3, issuer1, issuer2).map { - issuerWithKey => - val did = issuerWithKey.issuer.did.value - val verificationMethod = - VerificationMethod( - id = did, - `type` = JwtAlgorithm.ES256.name, - controller = "", - publicKeyJwk = Some( - toJWKFormat(issuerWithKey.key) - ) - ) - did -> DIDDocument( - id = did, - alsoKnowAs = Vector.empty, - controller = Vector.empty, - verificationMethod = Vector(verificationMethod), - service = Vector.empty - ) - }.toMap - - override def resolve(didUrl: String): UIO[DIDResolutionResult] = - resolverLookup - .get(didUrl) - .fold( - ZIO.succeed(DIDResolutionFailed(NotFound(s"DIDDocument not found for $didUrl"))) - )((didDocument: DIDDocument) => { - ZIO.succeed( - DIDResolutionSucceeded( - didDocument, - DIDDocumentMetadata() - ) - ) - }) - - } - - println("") - println("==================") - println("Validate JWT Presentation Using DID Document of the issuer of the presentation") - println("==================") - val encodedJWTPresentation = JwtPresentation.encodeJwt(payload = jwtPresentationPayload, issuer = holder1.issuer) - val encodedW3CPresentation = - JwtPresentation.toEncodeW3C(payload = jwtPresentationPayload.toW3CPresentationPayload, issuer = holder1.issuer) - val clock = Clock.system(ZoneId.systemDefault) - for { - _ <- printLine("DEMO TIME! ") - w3cSignatureValidationResult <- JwtPresentation.validateEncodedW3C(encodedW3CPresentation.proof.jwt, None)( - DidResolverTest() - ) - jwtSignatureValidationResult <- JwtPresentation.validateEncodedJWT(encodedJWTPresentation, None)( - DidResolverTest() - ) - enclosedCredentialsValidationResult <- - JwtPresentation.verify( - encodedJWTPresentation, - JwtPresentation.PresentationVerificationOptions( - verifySignature = true, - verifyDates = true, - verifyHoldersBinding = true, - leeway = Duration.ZERO, - Some(CredentialVerification.CredentialVerificationOptions(verifySignature = true, verifyDates = true)) - ) - )( - DidResolverTest(), - (_: String) => ZIO.succeed("") - )(clock) - _ <- printLine(s"W3C IS VALID?: $w3cSignatureValidationResult") - _ <- printLine(s"JWT IS VALID?: $jwtSignatureValidationResult") - _ <- printLine(s"Enclosed Credentials are VALID?: $enclosedCredentialsValidationResult") - } yield () -} diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/SchemaDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/SchemaDemo.scala deleted file mode 100644 index 77bea1dd20..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/SchemaDemo.scala +++ /dev/null @@ -1,83 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import net.reactivecore.cjs.{DocumentValidator, Loader} - -@main def schemaDemo(): Unit = - val schemaCode = - """ - |{ - | "type": "object", - | "properties": { - | "userName": { - | "$ref": "#/$defs/user" - | }, - | "age": { - | "$ref": "#/$defs/age" - | }, - | "email": { - | "$ref": "#/$defs/email" - | } - | }, - | "required": ["userName", "age", "email"], - | "$defs": { - | "user": { - | "type": "string", - | "minLength": 3 - | }, - | "age": { - | "type": "number" - | }, - | "email": { - | "type": "string", - | "format": "email" - | } - | } - |} - |""".stripMargin - - val validator = Loader.empty.fromJson(io.circe.parser.parse(schemaCode).toOption.get) - - def test(s: Json): Unit = { - validator match { - case Right(v) => - val result = v.validate(s) - println(s"Result of $s: $result") - case Left(e) => - println(s"Validation failed with error: $e") - } - } - - test(Json.fromString("wrongType")) - test( - Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42) - ) - ) - - // Missing UserName - test( - Json.obj( - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email@email.com") - ) - ) - - // Age has Wrong type - test( - Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromBoolean(false), - "email" -> Json.fromString("email@email.com") - ) - ) - - // Success - test( - Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ) - ) diff --git a/pollux/vc-jwt/src/test/scala/io/iohk/atala/pollux/vc/jwt/revocation/VCStatusList2021Spec.scala b/pollux/vc-jwt/src/test/scala/io/iohk/atala/pollux/vc/jwt/revocation/VCStatusList2021Spec.scala index db69cc8952..a6f4be663f 100644 --- a/pollux/vc-jwt/src/test/scala/io/iohk/atala/pollux/vc/jwt/revocation/VCStatusList2021Spec.scala +++ b/pollux/vc-jwt/src/test/scala/io/iohk/atala/pollux/vc/jwt/revocation/VCStatusList2021Spec.scala @@ -1,34 +1,30 @@ package org.hyperledger.identus.pollux.vc.jwt.revocation -import org.hyperledger.identus.pollux.vc.jwt.{DID, ES256Signer, Issuer, JwtCredential} +import org.hyperledger.identus.pollux.vc.jwt.{DID, ES256KSigner, Issuer, JwtCredential} import zio.test.{Spec, ZIOSpecDefault, assertTrue} import zio.{UIO, ZIO} - -import java.security.spec.ECGenParameterSpec -import java.security.{KeyPairGenerator, SecureRandom} +import org.hyperledger.identus.shared.crypto.KmpSecp256k1KeyOps object VCStatusList2021Spec extends ZIOSpecDefault { private val VC_ID = "https://example.com/credentials/status/3" private def generateIssuer(): UIO[Issuer] = { - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic + + val keyPair = KmpSecp256k1KeyOps.generateKeyPair + val javaSKey = keyPair.privateKey.toJavaPrivateKey + val javaPKey = keyPair.publicKey.toJavaPublicKey + ZIO.succeed( Issuer( did = DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T"), - signer = ES256Signer(privateKey), - publicKey = publicKey + signer = ES256KSigner(javaSKey), + publicKey = javaPKey ) ) } override def spec = suite("VCStatusList2021")( - // TODO: add test to verify the proof is valid test("Should generate status list VC as JSON with embedded proof") { for { issuer <- generateIssuer() @@ -57,7 +53,6 @@ object VCStatusList2021Spec extends ZIOSpecDefault { bitString <- BitString.getInstance() statusList <- VCStatusList2021.build(VC_ID, s"$VC_ID#list", issuer, bitString) encodedJwtVC <- statusList.encoded - _ <- ZIO.logInfo(s"$encodedJwtVC") valid <- ZIO.succeed(JwtCredential.validateEncodedJwt(encodedJwtVC, issuer.publicKey)) } yield { assertTrue(valid) From f5f2d7570dd539e7ef98aed394aa54ea3713d877 Mon Sep 17 00:00:00 2001 From: patlo-iog Date: Thu, 16 May 2024 11:43:52 +0700 Subject: [PATCH 13/14] test: add tests for the new key types (#1044) Signed-off-by: Pat Losoponkul --- .../core/model/ProtoModelHelperSpec.scala | 1 - .../castor/core/model/did/DIDSpec.scala | 1 - .../castor/core/model/did/PrismDIDSpec.scala | 1 - .../core/model/did/ServiceEndpointSpec.scala | 1 - .../core/model/did/ServiceTypeSpec.scala | 1 - .../model/did/w3c/W3CModelHelperSpec.scala | 1 - .../castor/core/service/DIDServiceSpec.scala | 1 - .../agent/server/config/AppConfig.scala | 2 +- .../event/controller/EventController.scala | 6 +- .../server/AgentInitializationSpec.scala | 5 +- .../sql/JdbcDIDNonSecretStorage.scala | 26 --- .../identus/agent/walletapi/sql/package.scala | 3 +- .../storage/DIDNonSecretStorage.scala | 5 +- .../UpdateManagedDIDActionValidator.scala | 31 +++- .../service/ManagedDIDServiceSpec.scala | 80 ++++++--- .../storage/DIDSecretStorageSpec.scala | 54 ++++++- .../JdbcWalletNonSecretStorageSpec.scala | 10 +- .../ManagedDIDTemplateValidatorSpec.scala | 24 +++ .../walletapi/util/OperationFactorySpec.scala | 153 +++++++++++++++--- .../UpdateManagedDIDActionValidatorSpec.scala | 50 ++++++ .../mercury/model/AttachmentDescriptor.scala | 2 +- .../protocol/invitation/OutOfBand.scala | 3 +- .../protocol/invitation/ServiceType.scala | 2 +- .../protocol/outofbandlogin/Utils.scala | 3 +- .../presentproof/PresentationSpec.scala | 1 - .../identus/shared/db/TransactorLayer.scala | 1 - .../identus/shared/crypto/Apollo.scala | 36 ++++- .../shared/crypto/ApolloSpecHelper.scala | 1 - 28 files changed, 403 insertions(+), 102 deletions(-) create mode 100644 cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/UpdateManagedDIDActionValidatorSpec.scala diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/ProtoModelHelperSpec.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/ProtoModelHelperSpec.scala index 91475c86ce..c982b6d817 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/ProtoModelHelperSpec.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/ProtoModelHelperSpec.scala @@ -15,7 +15,6 @@ import scala.language.implicitConversions import zio.* import zio.test.* import zio.test.Assertion.* -import org.hyperledger.identus.castor.core.model.ProtoModelHelper object ProtoModelHelperSpec extends ZIOSpecDefault { diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/DIDSpec.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/DIDSpec.scala index 90781225e2..452c15fcee 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/DIDSpec.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/DIDSpec.scala @@ -4,7 +4,6 @@ import zio.* import zio.test.* import zio.test.Assertion.* import org.hyperledger.identus.castor.core.util.GenUtils -import org.hyperledger.identus.castor.core.model.did.{DID, PrismDID} object DIDSpec extends ZIOSpecDefault { diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDSpec.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDSpec.scala index ac4cade98a..d9e99d9d2b 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDSpec.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/PrismDIDSpec.scala @@ -7,7 +7,6 @@ import org.hyperledger.identus.shared.models.Base64UrlString import zio.* import zio.test.* import zio.test.Assertion.* -import org.hyperledger.identus.castor.core.model.did.PrismDID object PrismDIDSpec extends ZIOSpecDefault { diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/ServiceEndpointSpec.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/ServiceEndpointSpec.scala index 5a2bc72bb2..cf7ae1787e 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/ServiceEndpointSpec.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/ServiceEndpointSpec.scala @@ -3,7 +3,6 @@ package org.hyperledger.identus.castor.core.model.did import zio.* import zio.test.* import zio.test.Assertion.* -import org.hyperledger.identus.castor.core.model.did.ServiceEndpoint object ServiceEndpointSpec extends ZIOSpecDefault { diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/ServiceTypeSpec.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/ServiceTypeSpec.scala index f1868c8fed..901aa9a7e4 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/ServiceTypeSpec.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/ServiceTypeSpec.scala @@ -3,7 +3,6 @@ package org.hyperledger.identus.castor.core.model.did import zio.* import zio.test.* import zio.test.Assertion.* -import org.hyperledger.identus.castor.core.model.did.ServiceType object ServiceTypeSpec extends ZIOSpecDefault { diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/w3c/W3CModelHelperSpec.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/w3c/W3CModelHelperSpec.scala index 57f874f451..eaac4b58d2 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/w3c/W3CModelHelperSpec.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/model/did/w3c/W3CModelHelperSpec.scala @@ -12,7 +12,6 @@ import org.hyperledger.identus.castor.core.util.GenUtils import zio.* import zio.test.* import zio.test.Assertion.* -import org.hyperledger.identus.castor.core.model.did.w3c.W3CModelHelper object W3CModelHelperSpec extends ZIOSpecDefault { diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/service/DIDServiceSpec.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/service/DIDServiceSpec.scala index 3935bff5f5..caa3b2a6c7 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/service/DIDServiceSpec.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/service/DIDServiceSpec.scala @@ -32,7 +32,6 @@ import zio.test.* import zio.test.Assertion.* import scala.concurrent.Future -import org.hyperledger.identus.castor.core.service.{DIDService, DIDServiceImpl} object DIDServiceSpec extends ZIOSpecDefault { diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/config/AppConfig.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/config/AppConfig.scala index b0379ce672..f77eb1b6bc 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/config/AppConfig.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/config/AppConfig.scala @@ -28,7 +28,7 @@ object AppConfig { val urlRegex = """^(http|https)://[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:[0-9]{1,5})?(/.*)?$""".r urlRegex.findFirstMatchIn(url) match case Some(_) => - Try(java.net.URL(url)).toEither.left.map(ex /*java.net.MalformedURLException*/ => + Try(java.net.URI(url).toURL()).toEither.left.map(ex /*java.net.MalformedURLException*/ => Config.Error.InvalidData(zio.Chunk.empty, ex.getMessage()) ) case _ => Left(Config.Error.InvalidData(zio.Chunk.empty, s"Invalid URL: $url")) diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/event/controller/EventController.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/event/controller/EventController.scala index 0aa9f38ed5..08c2a0f425 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/event/controller/EventController.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/event/controller/EventController.scala @@ -15,7 +15,7 @@ import org.hyperledger.identus.iam.wallet.http.controller.WalletManagementContro import org.hyperledger.identus.shared.models.WalletAccessContext import zio.* -import java.net.URL +import java.net.URI import scala.language.implicitConversions import java.util.UUID @@ -44,7 +44,9 @@ class EventControllerImpl(service: WalletManagementService) extends EventControl request: CreateWebhookNotification )(implicit rc: RequestContext): ZIO[WalletAccessContext, ErrorResponse, WebhookNotification] = { for { - url <- ZIO.attempt(new URL(request.url)).mapError(e => ErrorResponse.badRequest(detail = Some(e.toString()))) + url <- ZIO + .attempt(new URI(request.url).toURL()) + .mapError(e => ErrorResponse.badRequest(detail = Some(e.toString()))) notificationConfig <- EventNotificationConfig.applyWallet(url, request.customHeaders.getOrElse(Map.empty)) _ <- service .createWalletNotification(notificationConfig) diff --git a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/agent/server/AgentInitializationSpec.scala b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/agent/server/AgentInitializationSpec.scala index 028bca98cf..f1435c44e3 100644 --- a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/agent/server/AgentInitializationSpec.scala +++ b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/agent/server/AgentInitializationSpec.scala @@ -23,6 +23,7 @@ import zio.test.* import zio.test.Assertion.* import zio.test.ZIOSpecDefault +import java.net.URI import java.net.URL object AgentInitializationSpec extends ZIOSpecDefault, PostgresTestContainerSupport, ApolloSpecHelper { @@ -113,7 +114,7 @@ object AgentInitializationSpec extends ZIOSpecDefault, PostgresTestContainerSupp test("create wallet with provided webhook") { val url = "http://example.com" for { - _ <- AgentInitialization.run.overrideConfig(webhookUrl = Some(URL(url))) + _ <- AgentInitialization.run.overrideConfig(webhookUrl = Some(URI(url).toURL())) webhooks <- ZIO .serviceWithZIO[WalletNonSecretStorage]( _.walletNotification @@ -127,7 +128,7 @@ object AgentInitializationSpec extends ZIOSpecDefault, PostgresTestContainerSupp val url = "http://example.com" val apiKey = "secret" for { - _ <- AgentInitialization.run.overrideConfig(webhookUrl = Some(URL(url)), webhookApiKey = Some(apiKey)) + _ <- AgentInitialization.run.overrideConfig(webhookUrl = Some(URI(url).toURL()), webhookApiKey = Some(apiKey)) webhooks <- ZIO .serviceWithZIO[WalletNonSecretStorage]( _.walletNotification diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDNonSecretStorage.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDNonSecretStorage.scala index efaaea1d36..4a3cca2265 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDNonSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDNonSecretStorage.scala @@ -242,32 +242,6 @@ class JdbcDIDNonSecretStorage(xa: Transactor[ContextAwareTask], xb: Transactor[T } } - override def listHdKeyPath( - did: PrismDID - ): RIO[WalletAccessContext, Seq[(String, ArraySeq[Byte], ManagedDIDHdKeyPath)]] = { - val cxnIO = - sql""" - | SELECT - | key_id, - | operation_hash, - | key_usage, - | key_index - | FROM public.prism_did_key - | WHERE did = $did AND key_mode = ${KeyManagementMode.HD} - """.stripMargin - .query[(String, ArraySeq[Byte], VerificationRelationship | InternalKeyPurpose, Int)] - .to[List] - - for { - state <- getManagedDIDState(did) - paths <- cxnIO.transactWallet(xa) - } yield state.map(_.didIndex).fold(Nil) { didIndex => - paths.map { (keyId, operationHash, keyUsage, keyIndex) => - (keyId, operationHash, ManagedDIDHdKeyPath(didIndex, keyUsage, keyIndex)) - } - } - } - override def insertKeyMeta( did: PrismDID, keyId: String, diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/package.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/package.scala index aa0cd77a42..92a2b61ae7 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/package.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/package.scala @@ -22,6 +22,7 @@ import zio.json.* import zio.json.ast.Json import zio.json.ast.Json.* +import java.net.URI import java.net.URL import java.time.Instant import java.util.UUID @@ -123,7 +124,7 @@ package object sql { given arraySeqByteGet: Get[ArraySeq[Byte]] = Get[Array[Byte]].map(ArraySeq.from) given arraySeqBytePut: Put[ArraySeq[Byte]] = Put[Array[Byte]].contramap(_.toArray) - given urlGet: Get[URL] = Get[String].map(URL(_)) + given urlGet: Get[URL] = Get[String].map(URI(_).toURL()) given urlPut: Put[URL] = Put[String].contramap(_.toString()) given octetKeyPairGet: Get[OctetKeyPair] = Get[String].map(OctetKeyPair.parse) diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDNonSecretStorage.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDNonSecretStorage.scala index a4abb78c33..e8fce8710d 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDNonSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDNonSecretStorage.scala @@ -6,8 +6,6 @@ import org.hyperledger.identus.mercury.model.DidId import org.hyperledger.identus.shared.models.WalletAccessContext import zio.* -import scala.collection.immutable.ArraySeq - trait DIDNonSecretStorage { def getManagedDIDState(did: PrismDID): RIO[WalletAccessContext, Option[ManagedDIDState]] @@ -25,6 +23,7 @@ trait DIDNonSecretStorage { def getHdKeyCounter(did: PrismDID): RIO[WalletAccessContext, Option[HdKeyIndexCounter]] + /** Return a tuple of key metadata and the operation hash */ def getKeyMeta(did: PrismDID, keyId: String): RIO[WalletAccessContext, Option[(ManagedDIDKeyMeta, Array[Byte])]] def insertKeyMeta( @@ -34,8 +33,6 @@ trait DIDNonSecretStorage { operationHash: Array[Byte] ): RIO[WalletAccessContext, Unit] - def listHdKeyPath(did: PrismDID): RIO[WalletAccessContext, Seq[(String, ArraySeq[Byte], ManagedDIDHdKeyPath)]] - /** Return a list of Managed DID as well as a count of all filtered items */ def listManagedDID( offset: Option[Int], diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/UpdateManagedDIDActionValidator.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/UpdateManagedDIDActionValidator.scala index 28027f0cdf..9bda12f0c4 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/UpdateManagedDIDActionValidator.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/UpdateManagedDIDActionValidator.scala @@ -2,10 +2,16 @@ package org.hyperledger.identus.agent.walletapi.util import org.hyperledger.identus.agent.walletapi.model.UpdateManagedDIDAction import org.hyperledger.identus.agent.walletapi.service.ManagedDIDService +import org.hyperledger.identus.castor.core.model.did.EllipticCurve +import org.hyperledger.identus.castor.core.model.did.VerificationRelationship object UpdateManagedDIDActionValidator { - def validate(actions: Seq[UpdateManagedDIDAction]): Either[String, Unit] = validateReservedKeyId(actions) + def validate(actions: Seq[UpdateManagedDIDAction]): Either[String, Unit] = + for { + _ <- validateReservedKeyId(actions) + _ <- validateCurveUsage(actions) + } yield () private def validateReservedKeyId(actions: Seq[UpdateManagedDIDAction]): Either[String, Unit] = { val keyIds = actions.flatMap { @@ -22,4 +28,27 @@ object UpdateManagedDIDActionValidator { else Right(()) } + private def validateCurveUsage(actions: Seq[UpdateManagedDIDAction]): Either[String, Unit] = { + val ed25519AllowedUsage = Set(VerificationRelationship.Authentication, VerificationRelationship.AssertionMethod) + val x25519AllowedUsage = Set(VerificationRelationship.KeyAgreement) + val publicKeys = actions.collect { case UpdateManagedDIDAction.AddKey(template) => template } + val disallowedKeys = publicKeys + .filter { k => + k.curve match { + case EllipticCurve.ED25519 => !ed25519AllowedUsage.contains(k.purpose) + case EllipticCurve.X25519 => !x25519AllowedUsage.contains(k.purpose) + case _ => false + } + } + .map(_.id) + + if (disallowedKeys.isEmpty) Right(()) + else + Left( + s"Invalid key purpose for key ${disallowedKeys.mkString("[", ", ", "]")}. " + + s"Ed25519 must be used in ${ed25519AllowedUsage.mkString("[", ", ", "]")}. " + + s"X25519 must be used in ${x25519AllowedUsage.mkString("[", ", ", "]")}" + ) + } + } diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceSpec.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceSpec.scala index c819cc0f2e..2ab28ebaa0 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceSpec.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceSpec.scala @@ -15,6 +15,9 @@ import org.hyperledger.identus.castor.core.model.error import org.hyperledger.identus.castor.core.service.DIDService import org.hyperledger.identus.castor.core.util.DIDOperationValidator import org.hyperledger.identus.shared.crypto.ApolloSpecHelper +import org.hyperledger.identus.shared.crypto.Ed25519KeyPair +import org.hyperledger.identus.shared.crypto.Secp256k1KeyPair +import org.hyperledger.identus.shared.crypto.X25519KeyPair import org.hyperledger.identus.shared.models.WalletAccessContext import org.hyperledger.identus.shared.models.WalletAdministrationContext import org.hyperledger.identus.sharedtest.containers.PostgresTestContainerSupport @@ -239,14 +242,34 @@ object ManagedDIDServiceSpec val template = generateDIDTemplate( publicKeys = Seq( DIDPublicKeyTemplate("key1", VerificationRelationship.Authentication, EllipticCurve.SECP256K1), - DIDPublicKeyTemplate("key2", VerificationRelationship.KeyAgreement, EllipticCurve.SECP256K1) + DIDPublicKeyTemplate("key2", VerificationRelationship.Authentication, EllipticCurve.SECP256K1), + DIDPublicKeyTemplate("key3", VerificationRelationship.AssertionMethod, EllipticCurve.ED25519), + DIDPublicKeyTemplate("key4", VerificationRelationship.KeyAgreement, EllipticCurve.X25519), ) ) for { svc <- ZIO.service[ManagedDIDService] did <- svc.createAndStoreDID(template).map(_.asCanonical) - keyPaths <- svc.nonSecretStorage.listHdKeyPath(did) - } yield assert(keyPaths.map(_._1))(hasSameElements(Seq("key1", "key2", ManagedDIDService.DEFAULT_MASTER_KEY_ID))) + masterKey <- svc.nonSecretStorage.getKeyMeta(did, ManagedDIDService.DEFAULT_MASTER_KEY_ID).some.map(_._1) + key1 <- svc.nonSecretStorage.getKeyMeta(did, "key1").some.map(_._1) + key2 <- svc.nonSecretStorage.getKeyMeta(did, "key2").some.map(_._1) + key3 <- svc.nonSecretStorage.getKeyMeta(did, "key3").some.map(_._1) + key4 <- svc.nonSecretStorage.getKeyMeta(did, "key4").some.map(_._1) + masterKeyPair <- svc.findDIDKeyPair(did, ManagedDIDService.DEFAULT_MASTER_KEY_ID).some + key1KeyPair <- svc.findDIDKeyPair(did, "key1").some + key2KeyPair <- svc.findDIDKeyPair(did, "key2").some + key3KeyPair <- svc.findDIDKeyPair(did, "key3").some + key4KeyPair <- svc.findDIDKeyPair(did, "key4").some + } yield assert(masterKey)(isSubtype[ManagedDIDKeyMeta.HD](anything)) && + assert(key1)(isSubtype[ManagedDIDKeyMeta.HD](anything)) && + assert(key2)(isSubtype[ManagedDIDKeyMeta.HD](anything)) && + assert(key3)(isSubtype[ManagedDIDKeyMeta.Rand](anything)) && + assert(key4)(isSubtype[ManagedDIDKeyMeta.Rand](anything)) && + assert(masterKeyPair)(isSubtype[Secp256k1KeyPair](anything)) && + assert(key1KeyPair)(isSubtype[Secp256k1KeyPair](anything)) && + assert(key2KeyPair)(isSubtype[Secp256k1KeyPair](anything)) && + assert(key3KeyPair)(isSubtype[Ed25519KeyPair](anything)) && + assert(key4KeyPair)(isSubtype[X25519KeyPair](anything)) }, test("created DID have corresponding public keys in CreateOperation") { val template = generateDIDTemplate( @@ -320,7 +343,7 @@ object ManagedDIDServiceSpec ctx2 = ZLayer.succeed(WalletAccessContext(walletId2)) svc <- ZIO.service[ManagedDIDService] storage <- ZIO.service[DIDNonSecretStorage] - urlTmp = java.net.URL("http://example.com") + urlTmp = java.net.URI("http://example.com").toURL() peerDid1 <- svc.createAndStorePeerDID(urlTmp).provide(ctx1) peerDid2 <- svc.createAndStorePeerDID(urlTmp).provide(ctx2) record1 <- storage.getPeerDIDRecord(peerDid1.did) @@ -393,16 +416,25 @@ object ManagedDIDServiceSpec testDIDSvc <- ZIO.service[TestDIDService] did <- initPublishedDID _ <- testDIDSvc.setResolutionResult(Some(resolutionResult())) - actions = Seq("key-1", "key-2").map(id => + actions = Seq( UpdateManagedDIDAction.AddKey( - DIDPublicKeyTemplate(id, VerificationRelationship.Authentication, EllipticCurve.SECP256K1) + DIDPublicKeyTemplate("key-1", VerificationRelationship.Authentication, EllipticCurve.SECP256K1) + ), + UpdateManagedDIDAction.AddKey( + DIDPublicKeyTemplate("key-2", VerificationRelationship.Authentication, EllipticCurve.ED25519) + ), + UpdateManagedDIDAction.AddKey( + DIDPublicKeyTemplate("key-3", VerificationRelationship.KeyAgreement, EllipticCurve.X25519) ) ) _ <- svc.updateManagedDID(did, actions) - keyPaths <- svc.nonSecretStorage.listHdKeyPath(did) - } yield assert(keyPaths.map(_._1))( - hasSameElements(Seq(ManagedDIDService.DEFAULT_MASTER_KEY_ID, "key-1", "key-2")) - ) + _ <- svc.syncUnconfirmedUpdateOperations + key1KeyPair <- svc.findDIDKeyPair(did, "key-1").some + key2KeyPair <- svc.findDIDKeyPair(did, "key-2").some + key3KeyPair <- svc.findDIDKeyPair(did, "key-3").some + } yield assert(key1KeyPair)(isSubtype[Secp256k1KeyPair](anything)) && + assert(key2KeyPair)(isSubtype[Ed25519KeyPair](anything)) && + assert(key3KeyPair)(isSubtype[X25519KeyPair](anything)) }, test("store private keys with the same key-id across multiple update operation") { for { @@ -410,17 +442,29 @@ object ManagedDIDServiceSpec testDIDSvc <- ZIO.service[TestDIDService] did <- initPublishedDID _ <- testDIDSvc.setResolutionResult(Some(resolutionResult())) - actions = Seq("key-1", "key-2").map(id => + actions = Seq( + UpdateManagedDIDAction.AddKey( + DIDPublicKeyTemplate("key-1", VerificationRelationship.Authentication, EllipticCurve.SECP256K1) + ), UpdateManagedDIDAction.AddKey( - DIDPublicKeyTemplate(id, VerificationRelationship.Authentication, EllipticCurve.SECP256K1) + DIDPublicKeyTemplate("key-2", VerificationRelationship.Authentication, EllipticCurve.ED25519) ) ) _ <- svc.updateManagedDID(did, actions) // 1st update - _ <- svc.updateManagedDID(did, actions.take(1)) // 2nd update: key-1 is added twice - keyPaths <- svc.nonSecretStorage.listHdKeyPath(did) - } yield assert(keyPaths.map(_._1))( - hasSameElements(Seq(ManagedDIDService.DEFAULT_MASTER_KEY_ID, "key-1", "key-1", "key-2")) - ) + _ <- testDIDSvc.setOperationStatus(ScheduledDIDOperationStatus.Confirmed) + _ <- svc.syncUnconfirmedUpdateOperations + key1KeyPair1 <- svc.findDIDKeyPair(did, "key-1").some + key2KeyPair1 <- svc.findDIDKeyPair(did, "key-2").some + _ <- svc.updateManagedDID(did, actions) // 2nd update + _ <- testDIDSvc.setOperationStatus(ScheduledDIDOperationStatus.Rejected) + _ <- svc.syncUnconfirmedUpdateOperations + key1KeyPair2 <- svc.findDIDKeyPair(did, "key-1").some + key2KeyPair2 <- svc.findDIDKeyPair(did, "key-2").some + } yield assert(key1KeyPair1)(isSubtype[Secp256k1KeyPair](anything)) && + assert(key2KeyPair1)(isSubtype[Ed25519KeyPair](anything)) && + // 2nd update with rejected status does not update the key pair + assert(key1KeyPair2)(equalTo(key1KeyPair1)) && + assert(key2KeyPair2)(equalTo(key2KeyPair1)) }, test("store did lineage for each update operation") { for { @@ -519,7 +563,7 @@ object ManagedDIDServiceSpec ctx1 = ZLayer.succeed(WalletAccessContext(walletId1)) ctx2 = ZLayer.succeed(WalletAccessContext(walletId2)) svc <- ZIO.service[ManagedDIDService] - urlTmp = java.net.URL("http://example.com") + urlTmp = java.net.URI("http://example.com").toURL() dids1 <- ZIO.foreach(1 to 3)(_ => svc.createAndStorePeerDID(urlTmp)).provide(ctx1) dids2 <- ZIO.foreach(1 to 3)(_ => svc.createAndStorePeerDID(urlTmp)).provide(ctx2) ownWalletDids1 <- ZIO.foreach(dids1)(d => svc.getPeerDID(d.did).exit).provide(ctx1) diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorageSpec.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorageSpec.scala index b72d982e99..30ab5dec56 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorageSpec.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorageSpec.scala @@ -1,5 +1,7 @@ package org.hyperledger.identus.agent.walletapi.storage +import org.hyperledger.identus.agent.walletapi.model.ManagedDIDState +import org.hyperledger.identus.agent.walletapi.model.PublicationState import org.hyperledger.identus.agent.walletapi.model.Wallet import org.hyperledger.identus.agent.walletapi.service.{WalletManagementService, WalletManagementServiceImpl} import org.hyperledger.identus.agent.walletapi.sql.{ @@ -9,8 +11,12 @@ import org.hyperledger.identus.agent.walletapi.sql.{ JdbcWalletSecretStorage } import org.hyperledger.identus.agent.walletapi.vault.{VaultDIDSecretStorage, VaultWalletSecretStorage} +import org.hyperledger.identus.castor.core.model.did.PrismDIDOperation import org.hyperledger.identus.mercury.PeerDID +import org.hyperledger.identus.shared.crypto.Apollo import org.hyperledger.identus.shared.crypto.ApolloSpecHelper +import org.hyperledger.identus.shared.crypto.Ed25519KeyPair +import org.hyperledger.identus.shared.crypto.X25519KeyPair import org.hyperledger.identus.shared.models.WalletAccessContext import org.hyperledger.identus.shared.models.WalletAdministrationContext import org.hyperledger.identus.sharedtest.containers.PostgresTestContainerSupport @@ -130,7 +136,53 @@ object DIDSecretStorageSpec _ <- secretStorage.insertKey(peerDID.did, "agreement", peerDID.jwkForKeyAgreement) _ <- secretStorage.insertKey(peerDID.did, "authentication", peerDID.jwkForKeyAuthentication) } yield assertCompletes - } + }, + test("insert and get the same key for Prism KeyPair") { + for { + nonSecretStorage <- ZIO.service[DIDNonSecretStorage] + secretStorage <- ZIO.service[DIDSecretStorage] + key1 = Apollo.default.ed25519.generateKeyPair + key2 = Apollo.default.x25519.generateKeyPair + createOperation = PrismDIDOperation.Create(Nil, Nil, Nil) + did = createOperation.did + state = ManagedDIDState(createOperation, 0, PublicationState.Created()) + _ <- nonSecretStorage.insertManagedDID(did, state, Map.empty, Map.empty) + _ <- secretStorage.insertPrismDIDKeyPair(did, "key-1", createOperation.toAtalaOperationHash, key1) + _ <- secretStorage.insertPrismDIDKeyPair(did, "key-2", createOperation.toAtalaOperationHash, key2) + getKey1 <- secretStorage + .getPrismDIDKeyPair[Ed25519KeyPair](did, "key-1", createOperation.toAtalaOperationHash) + .some + getKey2 <- secretStorage + .getPrismDIDKeyPair[X25519KeyPair](did, "key-2", createOperation.toAtalaOperationHash) + .some + } yield assert(key1)(equalTo(getKey1)) && + assert(key2)(equalTo(getKey2)) + }, + test("insert same key id for Prism KeyPair return error") { + for { + nonSecretStorage <- ZIO.service[DIDNonSecretStorage] + secretStorage <- ZIO.service[DIDSecretStorage] + key1 = Apollo.default.ed25519.generateKeyPair + key2 = Apollo.default.x25519.generateKeyPair + createOperation = PrismDIDOperation.Create(Nil, Nil, Nil) + did = createOperation.did + state = ManagedDIDState(createOperation, 0, PublicationState.Created()) + _ <- nonSecretStorage.insertManagedDID(did, state, Map.empty, Map.empty) + _ <- secretStorage.insertPrismDIDKeyPair(did, "key-1", createOperation.toAtalaOperationHash, key1) + exit <- secretStorage.insertPrismDIDKeyPair(did, "key-1", createOperation.toAtalaOperationHash, key2).exit + getKey1 <- secretStorage + .getPrismDIDKeyPair[Ed25519KeyPair](did, "key-1", createOperation.toAtalaOperationHash) + .some + } yield assert(key1)(equalTo(getKey1)) && assert(exit)(dies(anything)) + }, + test("get non-exist Prism KeyPair return None") { + for { + secretStorage <- ZIO.service[DIDSecretStorage] + createOperation = PrismDIDOperation.Create(Nil, Nil, Nil) + did = createOperation.did + key1 <- secretStorage.getPrismDIDKeyPair[Ed25519KeyPair](did, "key-1", createOperation.toAtalaOperationHash) + } yield assert(key1)(isNone) + }, ).globalWallet private val multiWalletSpec = suite("multi-wallet")( diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/JdbcWalletNonSecretStorageSpec.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/JdbcWalletNonSecretStorageSpec.scala index e112843b3d..9214ac3b1d 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/JdbcWalletNonSecretStorageSpec.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/JdbcWalletNonSecretStorageSpec.scala @@ -14,7 +14,7 @@ import zio.* import zio.test.* import zio.test.Assertion.* -import java.net.URL +import java.net.URI object JdbcWalletNonSecretStorageSpec extends ZIOSpecDefault, PostgresTestContainerSupport { @@ -156,7 +156,7 @@ object JdbcWalletNonSecretStorageSpec extends ZIOSpecDefault, PostgresTestContai for { storage <- ZIO.service[WalletNonSecretStorage] wallet <- createWallets(1).map(_.head) - config = EventNotificationConfig(wallet.id, URL("https://example.com")) + config = EventNotificationConfig(wallet.id, URI("https://example.com").toURL()) _ <- storage .createWalletNotification(config) .provide(ZLayer.succeed(WalletAccessContext(wallet.id))) @@ -171,11 +171,11 @@ object JdbcWalletNonSecretStorageSpec extends ZIOSpecDefault, PostgresTestContai limit = JdbcWalletNonSecretStorage.MAX_WEBHOOK_PER_WALLET _ <- ZIO.foreach(1 to limit) { _ => storage - .createWalletNotification(EventNotificationConfig(wallet.id, URL("https://example.com"))) + .createWalletNotification(EventNotificationConfig(wallet.id, URI("https://example.com").toURL())) .provide(ZLayer.succeed(WalletAccessContext(wallet.id))) } exit <- storage - .createWalletNotification(EventNotificationConfig(wallet.id, URL("https://example.com"))) + .createWalletNotification(EventNotificationConfig(wallet.id, URI("https://example.com").toURL())) .provide(ZLayer.succeed(WalletAccessContext(wallet.id))) .exit } yield assert(exit)(fails(isSubtype[TooManyWebhook](anything))) @@ -186,7 +186,7 @@ object JdbcWalletNonSecretStorageSpec extends ZIOSpecDefault, PostgresTestContai wallets <- createWallets(2) wallet1 = wallets.head wallet2 = wallets.last - config = EventNotificationConfig(wallet1.id, URL("https://example.com")) + config = EventNotificationConfig(wallet1.id, URI("https://example.com").toURL()) _ <- storage .createWalletNotification(config) .provide(ZLayer.succeed(WalletAccessContext(wallet1.id))) diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/ManagedDIDTemplateValidatorSpec.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/ManagedDIDTemplateValidatorSpec.scala index 37e0d343be..0bdef0ea4b 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/ManagedDIDTemplateValidatorSpec.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/ManagedDIDTemplateValidatorSpec.scala @@ -53,6 +53,30 @@ object ManagedDIDTemplateValidatorSpec extends ZIOSpecDefault { contexts = Nil ) assert(ManagedDIDTemplateValidator.validate(template))(isLeft) + }, + test("reject DID template if key usage is not allowed") { + val makeTemplate = (keyTemplate: DIDPublicKeyTemplate) => + ManagedDIDTemplate( + publicKeys = Seq(keyTemplate), + services = Nil, + contexts = Nil + ) + val template1 = makeTemplate( + DIDPublicKeyTemplate( + id = "key-1", + purpose = VerificationRelationship.KeyAgreement, + curve = EllipticCurve.ED25519 + ) + ) + val template2 = makeTemplate( + DIDPublicKeyTemplate( + id = "key-1", + purpose = VerificationRelationship.Authentication, + curve = EllipticCurve.X25519 + ) + ) + assert(ManagedDIDTemplateValidator.validate(template1))(isLeft) && + assert(ManagedDIDTemplateValidator.validate(template2))(isLeft) } ) diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactorySpec.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactorySpec.scala index 6e28f86376..58daef141c 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactorySpec.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactorySpec.scala @@ -3,11 +3,15 @@ package org.hyperledger.identus.agent.walletapi.util import org.hyperledger.identus.agent.walletapi.model.* import org.hyperledger.identus.castor.core.model.did.* import org.hyperledger.identus.shared.crypto.ApolloSpecHelper +import org.hyperledger.identus.shared.crypto.Ed25519KeyPair +import org.hyperledger.identus.shared.crypto.X25519KeyPair import org.hyperledger.identus.shared.models.HexString import zio.* import zio.test.* import zio.test.Assertion.* +import scala.language.implicitConversions + object OperationFactorySpec extends ZIOSpecDefault, ApolloSpecHelper { private val didExample = PrismDID.buildLongFormFromOperation(PrismDIDOperation.Create(Nil, Nil, Nil)).asCanonical @@ -23,9 +27,9 @@ object OperationFactorySpec extends ZIOSpecDefault, ApolloSpecHelper { private val operationFactory = OperationFactory(apollo) override def spec = - suite("OperationFactory")(makeCreateOpeartionHdKeySpec, makeUpdateOperationHdKeySpec) + suite("OperationFactory")(makeCreateOpeartionSpec, makeUpdateOperationSpec) - private val makeCreateOpeartionHdKeySpec = suite("makeCreateOpeartionHdKeySpec ")( + private val makeCreateOpeartionSpec = suite("makeCreateOpeartionSpec")( test("make CrateOperation from same seed is deterministic") { val didTemplate = ManagedDIDTemplate(Nil, Nil, Nil) for { @@ -46,7 +50,7 @@ object OperationFactorySpec extends ZIOSpecDefault, ApolloSpecHelper { assert(pk.id)(equalTo("master-0")) && assert(pk.purpose)(equalTo(InternalKeyPurpose.Master)) }, - test("make CreateOperation containing multiple keys") { + test("make CreateOperation containing multiple key purposes") { val didTemplate = ManagedDIDTemplate( Seq( DIDPublicKeyTemplate("auth-0", VerificationRelationship.Authentication, EllipticCurve.SECP256K1), @@ -58,17 +62,61 @@ object OperationFactorySpec extends ZIOSpecDefault, ApolloSpecHelper { ) for { result <- operationFactory.makeCreateOperation("master-0", seed)(0, didTemplate) - (op, hdKey) = result + (op, keys) = result } yield assert(op.publicKeys.length)(equalTo(4)) && - assert(hdKey.hdKeys.size)(equalTo(4)) && - assert(hdKey.hdKeys.get("master-0").get.keyIndex)(equalTo(0)) && - assert(hdKey.hdKeys.get("auth-0").get.keyIndex)(equalTo(0)) && - assert(hdKey.hdKeys.get("auth-1").get.keyIndex)(equalTo(1)) && - assert(hdKey.hdKeys.get("issue-0").get.keyIndex)(equalTo(0)) + assert(keys.hdKeys.size)(equalTo(4)) && + assert(keys.randKeys)(isEmpty) && + assert(keys.hdKeys.get("master-0").get.keyIndex)(equalTo(0)) && + assert(keys.hdKeys.get("auth-0").get.keyIndex)(equalTo(0)) && + assert(keys.hdKeys.get("auth-1").get.keyIndex)(equalTo(1)) && + assert(keys.hdKeys.get("issue-0").get.keyIndex)(equalTo(0)) + }, + test("make CreateOperation containing multiple key types") { + val didTemplate = ManagedDIDTemplate( + Seq( + DIDPublicKeyTemplate("auth-0", VerificationRelationship.Authentication, EllipticCurve.SECP256K1), + DIDPublicKeyTemplate("auth-1", VerificationRelationship.Authentication, EllipticCurve.ED25519), + DIDPublicKeyTemplate("comm-0", VerificationRelationship.KeyAgreement, EllipticCurve.X25519), + ), + Nil, + Nil + ) + for { + result <- operationFactory.makeCreateOperation("master-0", seed)(0, didTemplate) + (op, keys) = result + publicKeyData = op.publicKeys.map { + case PublicKey(id, _, publicKeyData) => id -> publicKeyData + case InternalPublicKey(id, _, publicKeyData) => id -> publicKeyData + }.toMap + } yield assert(publicKeyData.size)(equalTo(4)) && + assert(publicKeyData.get("auth-0").get)( + isSubtype[PublicKeyData.ECCompressedKeyData]( + hasField[PublicKeyData.ECCompressedKeyData, Int]("data", _.data.toByteArray.length, equalTo(33)) && + hasField("crv", _.crv, equalTo(EllipticCurve.SECP256K1)) + ) + ) && + assert(publicKeyData.get("auth-1").get)( + isSubtype[PublicKeyData.ECCompressedKeyData]( + hasField[PublicKeyData.ECCompressedKeyData, Int]("data", _.data.toByteArray.length, equalTo(32)) && + hasField("crv", _.crv, equalTo(EllipticCurve.ED25519)) + ) + ) && + assert(publicKeyData.get("comm-0").get)( + isSubtype[PublicKeyData.ECCompressedKeyData]( + hasField[PublicKeyData.ECCompressedKeyData, Int]("data", _.data.toByteArray.length, equalTo(32)) && + hasField("crv", _.crv, equalTo(EllipticCurve.X25519)) + ) + ) && + assert(keys.hdKeys.size)(equalTo(2)) && + assert(keys.randKeys.size)(equalTo(2)) && + assert(keys.hdKeys.get("master-0").get.keyIndex)(equalTo(0)) && + assert(keys.hdKeys.get("auth-0").get.keyIndex)(equalTo(0)) && + assert(keys.randKeys.get("auth-1").get.keyPair)(isSubtype[Ed25519KeyPair](anything)) && + assert(keys.randKeys.get("comm-0").get.keyPair)(isSubtype[X25519KeyPair](anything)) } ) - private val makeUpdateOperationHdKeySpec = suite("makeUpdateOperationHdKeySpec ")( + private val makeUpdateOperationSpec = suite("makeUpdateOperationSpec")( test("make UpdateOperation from same seed is deterministic") { val counter = HdKeyIndexCounter.zero(0) val actions = @@ -84,7 +132,7 @@ object OperationFactorySpec extends ZIOSpecDefault, ApolloSpecHelper { (op2, hdKey2) = result2 } yield assert(op1)(equalTo(op2)) && assert(hdKey1)(equalTo(hdKey2)) }, - test("make UpdateOperation correctly construct operation and increment counter") { + test("make UpdateOperation correctly construct operation and increment counter for derived keys") { val counter = HdKeyIndexCounter .zero(42) .copy( @@ -103,25 +151,80 @@ object OperationFactorySpec extends ZIOSpecDefault, ApolloSpecHelper { ) for { result <- operationFactory.makeUpdateOperation(seed)(didExample, previousOperationHash, actions, counter) - (op, hdKey) = result + (op, keys) = result + addKeyActions = op.actions.collect { case UpdateDIDAction.AddKey(pk) => pk } } yield { // counter is correct - assert(hdKey.counter.didIndex)(equalTo(42)) && - assert(hdKey.counter.verificationRelationship.authentication)(equalTo(4)) && - assert(hdKey.counter.verificationRelationship.assertionMethod)(equalTo(2)) && - assert(hdKey.counter.verificationRelationship.capabilityDelegation)(equalTo(0)) && - assert(hdKey.counter.verificationRelationship.capabilityDelegation)(equalTo(0)) && - assert(hdKey.counter.verificationRelationship.keyAgreement)(equalTo(0)) && - assert(hdKey.counter.internalKey.master)(equalTo(0)) && - assert(hdKey.counter.internalKey.revocation)(equalTo(0)) && + assert(keys.counter.didIndex)(equalTo(42)) && + assert(keys.counter.verificationRelationship.authentication)(equalTo(4)) && + assert(keys.counter.verificationRelationship.assertionMethod)(equalTo(2)) && + assert(keys.counter.verificationRelationship.capabilityDelegation)(equalTo(0)) && + assert(keys.counter.verificationRelationship.capabilityDelegation)(equalTo(0)) && + assert(keys.counter.verificationRelationship.keyAgreement)(equalTo(0)) && + assert(keys.counter.internalKey.master)(equalTo(0)) && + assert(keys.counter.internalKey.revocation)(equalTo(0)) && // path is correct - assert(hdKey.hdKeys.size)(equalTo(2)) && - assert(hdKey.hdKeys.get("auth-42").get.keyIndex)(equalTo(3)) && - assert(hdKey.hdKeys.get("issue-42").get.keyIndex)(equalTo(1)) && + assert(keys.hdKeys.size)(equalTo(2)) && + assert(keys.hdKeys.get("auth-42").get.keyIndex)(equalTo(3)) && + assert(keys.hdKeys.get("issue-42").get.keyIndex)(equalTo(1)) && + // rand key is correct + assert(keys.randKeys)(isEmpty) && // operation is correct assert(op.actions)(hasSize(equalTo(2))) && - assert(op.actions.collect { case UpdateDIDAction.AddKey(pk) => pk.id })( - hasSameElements(Seq("auth-42", "issue-42")) + assert(addKeyActions.map(_.id))(hasSameElements(Seq("auth-42", "issue-42"))) && + assert(addKeyActions.map(_.publicKeyData))( + forall( + isSubtype[PublicKeyData.ECCompressedKeyData]( + hasField[PublicKeyData.ECCompressedKeyData, Int]("data", _.data.toByteArray.length, equalTo(33)) && + hasField("crv", _.crv, equalTo(EllipticCurve.SECP256K1)) + ) + ) + ) + } + }, + test("make UpdateOperation correctly construct operation for generated keys") { + val counter = HdKeyIndexCounter.zero(42) + val actions = Seq( + UpdateManagedDIDAction.AddKey( + DIDPublicKeyTemplate("auth-42", VerificationRelationship.Authentication, EllipticCurve.ED25519) + ), + UpdateManagedDIDAction.AddKey( + DIDPublicKeyTemplate("comm-42", VerificationRelationship.KeyAgreement, EllipticCurve.X25519) + ), + ) + for { + result <- operationFactory.makeUpdateOperation(seed)(didExample, previousOperationHash, actions, counter) + (op, keys) = result + addKeyActions = op.actions.collect { case UpdateDIDAction.AddKey(pk) => pk } + } yield { + // counter is correct + assert(keys.counter.didIndex)(equalTo(42)) && + assert(keys.counter.verificationRelationship.authentication)(equalTo(0)) && + assert(keys.counter.verificationRelationship.assertionMethod)(equalTo(0)) && + assert(keys.counter.verificationRelationship.capabilityDelegation)(equalTo(0)) && + assert(keys.counter.verificationRelationship.capabilityDelegation)(equalTo(0)) && + assert(keys.counter.verificationRelationship.keyAgreement)(equalTo(0)) && + assert(keys.counter.internalKey.master)(equalTo(0)) && + assert(keys.counter.internalKey.revocation)(equalTo(0)) && + // path is correct + assert(keys.hdKeys.size)(equalTo(0)) && + // rand key is correct + assert(keys.randKeys.size)(equalTo(2)) && + assert(keys.randKeys.get("auth-42").get.keyPair)(isSubtype[Ed25519KeyPair](anything)) && + assert(keys.randKeys.get("comm-42").get.keyPair)(isSubtype[X25519KeyPair](anything)) && + // operation is correct + assert(op.actions)(hasSize(equalTo(2))) && + assert(addKeyActions.find(_.id == "auth-42").get.publicKeyData)( + isSubtype[PublicKeyData.ECCompressedKeyData]( + hasField[PublicKeyData.ECCompressedKeyData, Int]("data", _.data.toByteArray.length, equalTo(32)) && + hasField("crv", _.crv, equalTo(EllipticCurve.ED25519)) + ) + ) && + assert(addKeyActions.find(_.id == "comm-42").get.publicKeyData)( + isSubtype[PublicKeyData.ECCompressedKeyData]( + hasField[PublicKeyData.ECCompressedKeyData, Int]("data", _.data.toByteArray.length, equalTo(32)) && + hasField("crv", _.crv, equalTo(EllipticCurve.X25519)) + ) ) } } diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/UpdateManagedDIDActionValidatorSpec.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/UpdateManagedDIDActionValidatorSpec.scala new file mode 100644 index 0000000000..811a30fecd --- /dev/null +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/UpdateManagedDIDActionValidatorSpec.scala @@ -0,0 +1,50 @@ +package org.hyperledger.identus.agent.walletapi.util + +import org.hyperledger.identus.agent.walletapi.model.DIDPublicKeyTemplate +import org.hyperledger.identus.agent.walletapi.model.UpdateManagedDIDAction +import org.hyperledger.identus.agent.walletapi.service.ManagedDIDService +import org.hyperledger.identus.castor.core.model.did.EllipticCurve +import org.hyperledger.identus.castor.core.model.did.VerificationRelationship +import zio.* +import zio.test.* +import zio.test.Assertion.* + +import scala.language.implicitConversions + +object UpdateManagedDIDActionValidatorSpec extends ZIOSpecDefault { + + override def spec = suite("UpdateManagedDIDActionValidator")( + test("reject actions if contain reserved key-id") { + val actions = Seq( + UpdateManagedDIDAction.AddKey( + DIDPublicKeyTemplate( + id = ManagedDIDService.DEFAULT_MASTER_KEY_ID, + purpose = VerificationRelationship.Authentication, + curve = EllipticCurve.SECP256K1 + ) + ) + ) + assert(UpdateManagedDIDActionValidator.validate(actions))(isLeft) + }, + test("reject actions if key usage is not allowed") { + val makeActions = (keyTemplate: DIDPublicKeyTemplate) => Seq(UpdateManagedDIDAction.AddKey(keyTemplate)) + val actions1 = makeActions( + DIDPublicKeyTemplate( + id = "key-1", + purpose = VerificationRelationship.KeyAgreement, + curve = EllipticCurve.ED25519 + ) + ) + val actions2 = makeActions( + DIDPublicKeyTemplate( + id = "key-1", + purpose = VerificationRelationship.Authentication, + curve = EllipticCurve.X25519 + ) + ) + assert(UpdateManagedDIDActionValidator.validate(actions1))(isLeft) && + assert(UpdateManagedDIDActionValidator.validate(actions2))(isLeft) + } + ) + +} diff --git a/mercury/models/src/main/scala/org/hyperledger/identus/mercury/model/AttachmentDescriptor.scala b/mercury/models/src/main/scala/org/hyperledger/identus/mercury/model/AttachmentDescriptor.scala index da4357d3df..ce1d3d09df 100644 --- a/mercury/models/src/main/scala/org/hyperledger/identus/mercury/model/AttachmentDescriptor.scala +++ b/mercury/models/src/main/scala/org/hyperledger/identus/mercury/model/AttachmentDescriptor.scala @@ -1,7 +1,7 @@ package org.hyperledger.identus.mercury.model import java.util.Base64 as JBase64 -import io.circe.{Decoder, Encoder, HCursor, Json, JsonObject} +import io.circe.{Decoder, Encoder, Json, JsonObject} import io.circe.generic.semiauto.* import io.circe.syntax.* import cats.syntax.functor.* diff --git a/mercury/protocol-invitation/src/main/scala/org/hyperledger/identus/mercury/protocol/invitation/OutOfBand.scala b/mercury/protocol-invitation/src/main/scala/org/hyperledger/identus/mercury/protocol/invitation/OutOfBand.scala index 7cd2a59be5..001958f311 100644 --- a/mercury/protocol-invitation/src/main/scala/org/hyperledger/identus/mercury/protocol/invitation/OutOfBand.scala +++ b/mercury/protocol-invitation/src/main/scala/org/hyperledger/identus/mercury/protocol/invitation/OutOfBand.scala @@ -1,5 +1,6 @@ package org.hyperledger.identus.mercury.protocol.invitation +import java.net.URI import java.net.URL import java.{util => ju} import org.hyperledger.identus.mercury.protocol.invitation.v2._ @@ -8,7 +9,7 @@ import io.circe.parser._ object OutOfBand { - def parseLink(url: String): Option[String] = parseLink(new URL(url)) + def parseLink(url: String): Option[String] = parseLink(new URI(url).toURL()) def parseLink(url: URL): Option[String] = (url.getQuery() match { case str if str.startsWith("_oob=") => Some(str.drop(5)) case _ => None diff --git a/mercury/protocol-invitation/src/main/scala/org/hyperledger/identus/mercury/protocol/invitation/ServiceType.scala b/mercury/protocol-invitation/src/main/scala/org/hyperledger/identus/mercury/protocol/invitation/ServiceType.scala index 7f3ea642ec..0ce650c6de 100644 --- a/mercury/protocol-invitation/src/main/scala/org/hyperledger/identus/mercury/protocol/invitation/ServiceType.scala +++ b/mercury/protocol-invitation/src/main/scala/org/hyperledger/identus/mercury/protocol/invitation/ServiceType.scala @@ -2,7 +2,7 @@ package org.hyperledger.identus.mercury.protocol.invitation import cats.implicits._ import io.circe.syntax._ import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} -import io.circe.{Decoder, Encoder, HCursor} +import io.circe.{Decoder, Encoder} sealed trait ServiceType diff --git a/mercury/protocol-outofband-login/src/main/scala/org/hyperledger/identus/mercury/protocol/outofbandlogin/Utils.scala b/mercury/protocol-outofband-login/src/main/scala/org/hyperledger/identus/mercury/protocol/outofbandlogin/Utils.scala index 675933383e..229a6abcf3 100644 --- a/mercury/protocol-outofband-login/src/main/scala/org/hyperledger/identus/mercury/protocol/outofbandlogin/Utils.scala +++ b/mercury/protocol-outofband-login/src/main/scala/org/hyperledger/identus/mercury/protocol/outofbandlogin/Utils.scala @@ -1,5 +1,6 @@ package org.hyperledger.identus.mercury.protocol.outofbandlogin +import java.net.URI import java.net.URL import org.hyperledger.identus.mercury @@ -10,7 +11,7 @@ object Utils { */ def getNewMsgId: String = java.util.UUID.randomUUID().toString - def parseLink(url: String): Option[String] = parseLink(new URL(url)) + def parseLink(url: String): Option[String] = parseLink(new URI(url).toURL()) def parseLink(url: URL): Option[String] = (url.getQuery() match { case str if str.startsWith("_oob=") => Some(str.drop(5)) case _ => None diff --git a/mercury/protocol-present-proof/src/test/scala/org/hyperledger/identus/mercury/protocol/presentproof/PresentationSpec.scala b/mercury/protocol-present-proof/src/test/scala/org/hyperledger/identus/mercury/protocol/presentproof/PresentationSpec.scala index 90c7121b31..43a12c46c7 100644 --- a/mercury/protocol-present-proof/src/test/scala/org/hyperledger/identus/mercury/protocol/presentproof/PresentationSpec.scala +++ b/mercury/protocol-present-proof/src/test/scala/org/hyperledger/identus/mercury/protocol/presentproof/PresentationSpec.scala @@ -7,7 +7,6 @@ import org.hyperledger.identus.mercury.model.AttachmentDescriptor import org.hyperledger.identus.mercury.model.AttachmentDescriptor.attachmentDescriptorEncoderV2 import munit.* import org.hyperledger.identus.mercury.model.{LinkData, DidId} -import org.hyperledger.identus.mercury.protocol.presentproof.Presentation class PresentationSpec extends ZSuite { diff --git a/shared/core/src/main/scala/org/hyperledger/identus/shared/db/TransactorLayer.scala b/shared/core/src/main/scala/org/hyperledger/identus/shared/db/TransactorLayer.scala index e5997305f9..5bedd409c0 100644 --- a/shared/core/src/main/scala/org/hyperledger/identus/shared/db/TransactorLayer.scala +++ b/shared/core/src/main/scala/org/hyperledger/identus/shared/db/TransactorLayer.scala @@ -5,7 +5,6 @@ import cats.effect.kernel.Resource import cats.effect.std.Dispatcher import com.zaxxer.hikari.HikariConfig import doobie.hikari.HikariTransactor -import doobie.util.log.LogHandler import doobie.util.ExecutionContexts import doobie.util.transactor.Transactor import zio.* diff --git a/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Apollo.scala b/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Apollo.scala index 8651df618d..304eef02a5 100644 --- a/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Apollo.scala +++ b/shared/crypto/src/main/scala/org/hyperledger/identus/shared/crypto/Apollo.scala @@ -121,9 +121,25 @@ trait Secp256k1KeyOps { // ed25519 final case class Ed25519KeyPair(publicKey: Ed25519PublicKey, privateKey: Ed25519PrivateKey) -trait Ed25519PublicKey extends PublicKey, Verifiable +trait Ed25519PublicKey extends PublicKey, Verifiable { + override final def hashCode(): Int = HexString.fromByteArray(getEncoded).hashCode() + + override final def equals(x: Any): Boolean = x match { + case otherPK: Ed25519PublicKey => + HexString.fromByteArray(this.getEncoded) == HexString.fromByteArray(otherPK.getEncoded) + case _ => false + } +} trait Ed25519PrivateKey extends PrivateKey, Signable { type Pub = Ed25519PublicKey + + override final def hashCode(): Int = HexString.fromByteArray(getEncoded).hashCode() + + override final def equals(x: Any): Boolean = x match { + case otherPK: Ed25519PrivateKey => + HexString.fromByteArray(this.getEncoded) == HexString.fromByteArray(otherPK.getEncoded) + case _ => false + } } trait Ed25519KeyOps { def publicKeyFromEncoded(bytes: Array[Byte]): Try[Ed25519PublicKey] @@ -133,9 +149,25 @@ trait Ed25519KeyOps { // x25519 final case class X25519KeyPair(publicKey: X25519PublicKey, privateKey: X25519PrivateKey) -trait X25519PublicKey extends PublicKey +trait X25519PublicKey extends PublicKey { + override final def hashCode(): Int = HexString.fromByteArray(getEncoded).hashCode() + + override final def equals(x: Any): Boolean = x match { + case otherPK: X25519PublicKey => + HexString.fromByteArray(this.getEncoded) == HexString.fromByteArray(otherPK.getEncoded) + case _ => false + } +} trait X25519PrivateKey extends PrivateKey { type Pub = X25519PublicKey + + override final def hashCode(): Int = HexString.fromByteArray(getEncoded).hashCode() + + override final def equals(x: Any): Boolean = x match { + case otherPK: X25519PrivateKey => + HexString.fromByteArray(this.getEncoded) == HexString.fromByteArray(otherPK.getEncoded) + case _ => false + } } trait X25519KeyOps { def publicKeyFromEncoded(bytes: Array[Byte]): Try[X25519PublicKey] diff --git a/shared/crypto/src/test/scala/org/hyperledger/identus/shared/crypto/ApolloSpecHelper.scala b/shared/crypto/src/test/scala/org/hyperledger/identus/shared/crypto/ApolloSpecHelper.scala index baff9c483f..273f6cd19d 100644 --- a/shared/crypto/src/test/scala/org/hyperledger/identus/shared/crypto/ApolloSpecHelper.scala +++ b/shared/crypto/src/test/scala/org/hyperledger/identus/shared/crypto/ApolloSpecHelper.scala @@ -1,7 +1,6 @@ package org.hyperledger.identus.shared.crypto import zio.* -import org.hyperledger.identus.shared.crypto.Apollo trait ApolloSpecHelper { protected val apollo: Apollo = Apollo.default From 7d5cebafb34191964acfdf190c743a2ba253e883 Mon Sep 17 00:00:00 2001 From: Yurii Shynbuiev - IOHK Date: Fri, 17 May 2024 13:41:12 +0700 Subject: [PATCH 14/14] perf: update ts client in the performance tests, cleanup `println` (#1041) Signed-off-by: Yurii Shynbuiev --- .../presentproof/controller/http/PresentationStatus.scala | 1 - .../CredentialDefinitionLookupAndPaginationSpec.scala | 6 ++---- tests/performance-tests/agent-performance-tests-k6/.env | 2 +- .../agent-performance-tests-k6/package.json | 2 +- .../agent-performance-tests-k6/yarn.lock | 8 ++++---- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/presentproof/controller/http/PresentationStatus.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/presentproof/controller/http/PresentationStatus.scala index 597348aef7..14f8b94aff 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/presentproof/controller/http/PresentationStatus.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/presentproof/controller/http/PresentationStatus.scala @@ -44,7 +44,6 @@ object PresentationStatus { p.attachments.head.data match { case Base64(data) => val base64Decoded = new String(java.util.Base64.getDecoder.decode(data)) - println(s"Base64decode:\n\n ${base64Decoded} \n\n") Seq(base64Decoded) case any => ??? } diff --git a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/pollux/credentialdefinition/CredentialDefinitionLookupAndPaginationSpec.scala b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/pollux/credentialdefinition/CredentialDefinitionLookupAndPaginationSpec.scala index 84b142a0c8..b295b0a803 100644 --- a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/pollux/credentialdefinition/CredentialDefinitionLookupAndPaginationSpec.scala +++ b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/pollux/credentialdefinition/CredentialDefinitionLookupAndPaginationSpec.scala @@ -38,10 +38,8 @@ object CredentialDefinitionLookupAndPaginationSpec .get(uri) .response(asJsonAlways[CredentialDefinitionResponsePage]) .send(backend) - } yield { - println(response) - response - } + } yield response + _ <- ZIO.log(response.toString) firstPage <- ZIO.fromEither(response.body) otherPagesStream = zio.stream.ZStream .unfoldZIO[Any, Throwable, CredentialDefinitionResponsePage, CredentialDefinitionResponsePage](firstPage)( diff --git a/tests/performance-tests/agent-performance-tests-k6/.env b/tests/performance-tests/agent-performance-tests-k6/.env index 0f9249eb0c..b899dbc3e1 100644 --- a/tests/performance-tests/agent-performance-tests-k6/.env +++ b/tests/performance-tests/agent-performance-tests-k6/.env @@ -1,3 +1,3 @@ -AGENT_VERSION=1.32.1-SNAPSHOT +AGENT_VERSION=1.33.0-SNAPSHOT PRISM_NODE_VERSION=2.2.1 VAULT_DEV_ROOT_TOKEN_ID=root diff --git a/tests/performance-tests/agent-performance-tests-k6/package.json b/tests/performance-tests/agent-performance-tests-k6/package.json index 66b789fea2..4ea644e137 100644 --- a/tests/performance-tests/agent-performance-tests-k6/package.json +++ b/tests/performance-tests/agent-performance-tests-k6/package.json @@ -26,7 +26,7 @@ "webpack": "webpack" }, "dependencies": { - "@input-output-hk/prism-typescript-client": "^1.12.0", + "@hyperledger/identus-cloud-agent-client-ts": "^1.33.0", "uuid": "^9.0.0" } } diff --git a/tests/performance-tests/agent-performance-tests-k6/yarn.lock b/tests/performance-tests/agent-performance-tests-k6/yarn.lock index 2568095e62..56535f4ddf 100644 --- a/tests/performance-tests/agent-performance-tests-k6/yarn.lock +++ b/tests/performance-tests/agent-performance-tests-k6/yarn.lock @@ -993,10 +993,10 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@input-output-hk/prism-typescript-client@^1.12.0": - version "1.12.0" - resolved "https://npm.pkg.github.com/download/@input-output-hk/prism-typescript-client/1.12.0/b327649cf9be1a2f6c41ac2cdac7467523165cfe#b327649cf9be1a2f6c41ac2cdac7467523165cfe" - integrity sha512-0YAR+Rhu7WA0Y2jAv8eH0i4VG0G4AOWysc+T+G7sCsCI0PjmgiG9CvUz10tupEnO7n8fwvVGSA7lu2SD5NKEyw== +"@hyperledger/identus-cloud-agent-client-ts@^1.33.0": + version "1.33.0" + resolved "https://npm.pkg.github.com/download/@hyperledger/identus-cloud-agent-client-ts/1.33.0/6f0f6f6a36ceb0790981ad3ba425db1d6b0103cd#6f0f6f6a36ceb0790981ad3ba425db1d6b0103cd" + integrity sha512-kVF/PnkV2T+G8TX0frHq7ENeK8RQCrif+HapyMj0CtWrfPmm5Qlh7XeFqY1H80HOMTanB9i15PwIabb717rkhQ== dependencies: es6-promise "^4.2.4" url-parse "^1.4.3"