diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/BackgroundJobsHelper.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/BackgroundJobsHelper.scala index 5c2f555616..350c1ee7d0 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/BackgroundJobsHelper.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/BackgroundJobsHelper.scala @@ -15,7 +15,7 @@ import org.hyperledger.identus.mercury.{AgentPeerService, DidAgent} import org.hyperledger.identus.mercury.model.DidId import org.hyperledger.identus.pollux.core.model.error.PresentationError import org.hyperledger.identus.pollux.sdjwt.SDJWT.* -import org.hyperledger.identus.pollux.vc.jwt.{DIDResolutionFailed, DIDResolutionSucceeded, ES256KSigner, EdSigner, *} +import org.hyperledger.identus.pollux.vc.jwt.{DIDResolutionFailed, DIDResolutionSucceeded, ES256KSigner, *} import org.hyperledger.identus.pollux.vc.jwt.{DidResolver as JwtDidResolver, Issuer as JwtIssuer} import org.hyperledger.identus.shared.crypto.{ Ed25519KeyPair, @@ -24,6 +24,7 @@ import org.hyperledger.identus.shared.crypto.{ Secp256k1KeyPair, X25519KeyPair } +import org.hyperledger.identus.shared.models.KeyId import org.hyperledger.identus.shared.models.WalletAccessContext import zio.{ZIO, ZLayer} @@ -125,7 +126,7 @@ trait BackgroundJobsHelper { def findHolderEd25519SigningKey( proverDid: PrismDID, verificationRelationship: VerificationRelationship, - keyId: String + keyId: KeyId ): ZIO[DIDService & ManagedDIDService & WalletAccessContext, RuntimeException, Ed25519KeyPair] = { for { managedDIDService <- ZIO.service[ManagedDIDService] @@ -137,7 +138,7 @@ trait BackgroundJobsHelper { .map { case (_, didData) => didData.publicKeys .find(pk => - pk.id == keyId + pk.id == keyId.value && pk.purpose == verificationRelationship && pk.publicKeyData.crv == EllipticCurve.ED25519 ) .map(_.id) @@ -153,70 +154,6 @@ trait BackgroundJobsHelper { ) } yield ed25519keyPair } - def getEd25519SigningKeyPair( - proverDid: PrismDID, - verificationRelationship: VerificationRelationship, - keyId: Option[String] = None - ): ZIO[DIDService & ManagedDIDService & WalletAccessContext, RuntimeException, Ed25519KeyPair] = { - for { - managedDIDService <- ZIO.service[ManagedDIDService] - didService <- ZIO.service[DIDService] - issuingKeyId <- didService - .resolveDID(proverDid) - .mapError(e => RuntimeException(s"Error occured while resolving Issuing DID during VC creation: ${e.toString}")) - .someOrFail(RuntimeException(s"Issuing DID resolution result is not found")) - .map { case (_, didData) => - keyId match { - case Some(kid) => - didData.publicKeys - .find(pk => - pk.id.endsWith( - s"#$kid" - ) && pk.purpose == verificationRelationship && pk.publicKeyData.crv == EllipticCurve.ED25519 - ) - .map(_.id) - case None => // TODO Remove this None mean we cannot use the holder binding In SDJWT you will always have keyID with credentil since you did when you accept the offer with keyId - didData.publicKeys - .find(pk => pk.purpose == verificationRelationship && pk.publicKeyData.crv == EllipticCurve.ED25519) - .map(_.id) - } - } - .someOrFail( - RuntimeException(s"Issuing DID doesn't have a key in ${verificationRelationship.name} to use: $proverDid") - ) - ed25519keyPair <- managedDIDService - .findDIDKeyPair(proverDid.asCanonical, issuingKeyId) - .map(_.collect { case keyPair: Ed25519KeyPair => keyPair }) - .someOrFail( - RuntimeException(s"Issuer key-pair does not exist in the wallet: ${proverDid.toString}#$issuingKeyId") - ) - } yield ed25519keyPair - } - - /** @param proverDid - * This is holder prism did - * @param verificationRelationship - * Holder it Authentication and Issuer it is AssertionMethod - * @return - * JwtIssuer - * @see - * org.hyperledger.identus.pollux.vc.jwt.Issuer - */ - def getSDJwtIssuer( - proverDid: PrismDID, - verificationRelationship: VerificationRelationship, - keyId: Option[String] - ): ZIO[DIDService & ManagedDIDService & WalletAccessContext, RuntimeException, JwtIssuer] = { - for { - ed25519keyPair <- getEd25519SigningKeyPair(proverDid, verificationRelationship, keyId) - } yield { - JwtIssuer( - org.hyperledger.identus.pollux.vc.jwt.DID(proverDid.toString), - EdSigner(ed25519keyPair, keyId), - Ed25519PublicKey.toJavaEd25519PublicKey(ed25519keyPair.publicKey.getEncoded) - ) - } - } def resolveToEd25519PublicKey(did: String): ZIO[JwtDidResolver, PresentationError, Ed25519PublicKey] = { for { diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/PresentBackgroundJobs.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/PresentBackgroundJobs.scala index ae7c99174f..d5e75d2714 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/PresentBackgroundJobs.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/PresentBackgroundJobs.scala @@ -144,46 +144,6 @@ object PresentBackgroundJobs extends BackgroundJobsHelper { case None => ZIO.succeed(None) } yield optionalHolderPrivateKey - // Holder / Prover Get the Holder/Prover PrismDID from the IssuedCredential - // When holder accepts offer he provides the subjectdid - private def getPrismDIDForHolderFromCredentials( - presentationId: DidCommID, - credentialsToUse: Seq[String] - ) = - for { - credentialService <- ZIO.service[CredentialService] - // Choose first credential from the list to detect the subject DID to be used in Presentation. - // Holder binding check implies that any credential record can be chosen to detect the DID to use in VP. - credentialRecordId <- ZIO - .fromOption(credentialsToUse.headOption) - .mapError(_ => - PresentationError.UnexpectedError(s"No credential found in the Presentation record: $presentationId") - ) - credentialRecordUuid <- ZIO - .attempt(DidCommID(credentialRecordId)) - .mapError(_ => PresentationError.UnexpectedError(s"$credentialRecordId is not a valid DidCommID")) - credentialRecord <- credentialService - .findById(credentialRecordUuid) - .someOrFail(CredentialServiceError.RecordNotFound(credentialRecordUuid)) - vcSubjectId <- ZIO - .fromOption(credentialRecord.subjectId) - .orDieWith(_ => RuntimeException(s"VC SubjectId not found in credential record: $credentialRecordUuid")) - - proverDID <- ZIO - .fromEither(PrismDID.fromString(vcSubjectId)) - .mapError(e => - PresentationError - .UnexpectedError( - s"One of the credential(s) subject is not a valid Prism DID: ${vcSubjectId}" - ) - ) - longFormProverPrismDID <- getLongForm(proverDID, true) - jwtIssuer <- getSDJwtIssuer( - longFormProverPrismDID, - VerificationRelationship.Authentication, - credentialRecord.keyId - ) - } yield jwtIssuer private def performPresentProofExchange(record: PresentationRecord): URIO[ AppConfig & DidOps & DIDResolver & JwtDidResolver & HttpClient & PresentationService & CredentialService & diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/IssueControllerImpl.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/IssueControllerImpl.scala index 356baa85da..3a346e8d9d 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/IssueControllerImpl.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/IssueControllerImpl.scala @@ -21,6 +21,7 @@ import org.hyperledger.identus.pollux.core.model.{CredentialFormat, DidCommID} import org.hyperledger.identus.pollux.core.model.CredentialFormat.{AnonCreds, JWT, SDJWT} import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.Role import org.hyperledger.identus.pollux.core.service.CredentialService +import org.hyperledger.identus.shared.models.KeyId import org.hyperledger.identus.shared.models.WalletAccessContext import zio.{URLayer, ZIO, ZLayer} @@ -161,7 +162,7 @@ class IssueControllerImpl( case Some(did) => extractPrismDIDFromString(did).flatMap(validatePrismDID(_, true, Role.Holder)) case None => ZIO.succeed(()) id <- extractDidCommIdFromString(recordId) - outcome <- credentialService.acceptCredentialOffer(id, request.subjectId, request.keyId) + outcome <- credentialService.acceptCredentialOffer(id, request.subjectId, request.keyId.map(KeyId(_))) } yield IssueCredentialRecord.fromDomain(outcome) } diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/AcceptCredentialOfferRequest.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/AcceptCredentialOfferRequest.scala index b204adf571..7b99014403 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/AcceptCredentialOfferRequest.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/AcceptCredentialOfferRequest.scala @@ -2,6 +2,7 @@ package org.hyperledger.identus.issue.controller.http import org.hyperledger.identus.api.http.Annotation import org.hyperledger.identus.issue.controller.http.AcceptCredentialOfferRequest.annotations +import org.hyperledger.identus.shared.models.KeyId import sttp.tapir.{Schema, Validator} import sttp.tapir.Schema.annotations.{description, encodedExample, validate} import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/IssueCredentialRecord.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/IssueCredentialRecord.scala index 2c5867eaa9..030fa2865a 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/IssueCredentialRecord.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/IssueCredentialRecord.scala @@ -11,6 +11,7 @@ import org.hyperledger.identus.mercury.protocol.issuecredential.{ } import org.hyperledger.identus.pollux.anoncreds.AnoncredCredentialRequestMetadata import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.* +import org.hyperledger.identus.shared.models.KeyId import java.time.temporal.ChronoUnit import java.time.Instant @@ -27,7 +28,7 @@ final case class IssueCredentialRecord( credentialFormat: CredentialFormat, role: Role, subjectId: Option[String], - keyId: Option[String], + keyId: Option[KeyId], validityPeriod: Option[Double] = None, automaticIssuance: Option[Boolean], protocolState: ProtocolState, @@ -76,7 +77,7 @@ final case class ValidIssuedCredentialRecord( issuedCredentialRaw: Option[String], credentialFormat: CredentialFormat, subjectId: Option[String], - keyId: Option[String], + keyId: Option[KeyId], ) final case class ValidFullIssuedCredentialRecord( @@ -86,7 +87,7 @@ final case class ValidFullIssuedCredentialRecord( schemaUri: Option[String], credentialDefinitionUri: Option[String], subjectId: Option[String], - keyId: Option[String], + keyId: Option[KeyId], ) object IssueCredentialRecord { diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepository.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepository.scala index 2d7d611bab..68c4199864 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepository.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepository.scala @@ -4,6 +4,7 @@ import org.hyperledger.identus.mercury.protocol.issuecredential.{IssueCredential import org.hyperledger.identus.pollux.anoncreds.AnoncredCredentialRequestMetadata import org.hyperledger.identus.pollux.core.model.* import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.ProtocolState +import org.hyperledger.identus.shared.models.KeyId import org.hyperledger.identus.shared.models.WalletAccessContext import zio.* @@ -52,7 +53,7 @@ trait CredentialRepository { def updateWithSubjectId( recordId: DidCommID, subjectId: String, - keyId: Option[String], + keyId: Option[KeyId], protocolState: ProtocolState ): URIO[WalletAccessContext, Unit] diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositoryInMemory.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositoryInMemory.scala index c369b1e69d..e395cc3b2b 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositoryInMemory.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositoryInMemory.scala @@ -5,6 +5,7 @@ import org.hyperledger.identus.pollux.anoncreds.AnoncredCredentialRequestMetadat import org.hyperledger.identus.pollux.core.model.* import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.ProtocolState import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId} +import org.hyperledger.identus.shared.models.KeyId import zio.* import java.time.Instant @@ -255,7 +256,7 @@ class CredentialRepositoryInMemory( override def updateWithSubjectId( recordId: DidCommID, subjectId: String, - keyId: Option[String] = None, + keyId: Option[KeyId] = None, protocolState: ProtocolState ): URIO[WalletAccessContext, Unit] = { for { diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialService.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialService.scala index ba81a6741d..a349955d24 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialService.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialService.scala @@ -14,6 +14,7 @@ import org.hyperledger.identus.pollux.core.model.* import org.hyperledger.identus.pollux.core.model.error.CredentialServiceError import org.hyperledger.identus.pollux.core.model.error.CredentialServiceError.* import org.hyperledger.identus.pollux.vc.jwt.Issuer +import org.hyperledger.identus.shared.models.KeyId import org.hyperledger.identus.shared.models.WalletAccessContext import zio.{Duration, IO, UIO, URIO, ZIO} @@ -94,7 +95,7 @@ trait CredentialService { def acceptCredentialOffer( recordId: DidCommID, subjectId: Option[String], - keyId: Option[String] + keyId: Option[KeyId] ): ZIO[WalletAccessContext, RecordNotFound | UnsupportedDidFormat, IssueCredentialRecord] def generateJWTCredentialRequest( @@ -155,7 +156,7 @@ trait CredentialService { def getJwtIssuer( jwtIssuerDID: PrismDID, verificationRelationship: VerificationRelationship, - keyId: Option[String] + keyId: Option[KeyId] ): URIO[WalletAccessContext, Issuer] } diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImpl.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImpl.scala index 332ad5b752..23db13c265 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImpl.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImpl.scala @@ -24,6 +24,7 @@ import org.hyperledger.identus.pollux.sdjwt.* import org.hyperledger.identus.pollux.vc.jwt.{ES256KSigner, Issuer as JwtIssuer, *} import org.hyperledger.identus.shared.crypto.{Ed25519KeyPair, Ed25519PublicKey, Secp256k1KeyPair} import org.hyperledger.identus.shared.http.{DataUrlResolver, GenericUriResolver} +import org.hyperledger.identus.shared.models.KeyId import org.hyperledger.identus.shared.models.WalletAccessContext import org.hyperledger.identus.shared.utils.aspects.CustomMetricsAspect import zio.* @@ -418,7 +419,7 @@ class CredentialServiceImpl( override def acceptCredentialOffer( recordId: DidCommID, maybeSubjectId: Option[String], - keyId: Option[String] + keyId: Option[KeyId] ): ZIO[WalletAccessContext, RecordNotFound | UnsupportedDidFormat, IssueCredentialRecord] = { for { record <- getRecordWithState(recordId, ProtocolState.OfferReceived) @@ -511,7 +512,7 @@ class CredentialServiceImpl( override def getJwtIssuer( jwtIssuerDID: PrismDID, verificationRelationship: VerificationRelationship, - keyId: Option[String] = None + keyId: Option[KeyId] = None ): URIO[WalletAccessContext, JwtIssuer] = { for { issuingKeyId <- getKeyId(jwtIssuerDID, verificationRelationship, EllipticCurve.SECP256K1) @@ -556,7 +557,7 @@ class CredentialServiceImpl( private def getSDJwtIssuer( jwtIssuerDID: PrismDID, verificationRelationship: VerificationRelationship, - keyId: Option[String] + keyId: Option[KeyId] ): URIO[WalletAccessContext, JwtIssuer] = { for { ed25519keyPair <- getEd25519SigningKeyPair(jwtIssuerDID, verificationRelationship) @@ -574,7 +575,7 @@ class CredentialServiceImpl( getIssuer: ( did: LongFormPrismDID, verificationRelation: VerificationRelationship, - keyId: Option[String] + keyId: Option[KeyId] ) => URIO[WalletAccessContext, JwtIssuer] ): ZIO[WalletAccessContext, RecordNotFound | UnsupportedDidFormat, IssueCredentialRecord] = { for { diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceNotifier.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceNotifier.scala index 21fea3bce4..d933059297 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceNotifier.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceNotifier.scala @@ -9,6 +9,7 @@ import org.hyperledger.identus.pollux.core.model.{DidCommID, IssueCredentialReco import org.hyperledger.identus.pollux.core.model.error.CredentialServiceError import org.hyperledger.identus.pollux.core.model.error.CredentialServiceError.* import org.hyperledger.identus.pollux.vc.jwt.Issuer +import org.hyperledger.identus.shared.models.KeyId import org.hyperledger.identus.shared.models.WalletAccessContext import zio.{Duration, UIO, URIO, URLayer, ZIO, ZLayer} @@ -103,7 +104,7 @@ class CredentialServiceNotifier( override def acceptCredentialOffer( recordId: DidCommID, subjectId: Option[String], - keyId: Option[String] + keyId: Option[KeyId] ): ZIO[WalletAccessContext, RecordNotFound | UnsupportedDidFormat, IssueCredentialRecord] = notifyOnSuccess(svc.acceptCredentialOffer(recordId, subjectId, keyId)) @@ -231,7 +232,7 @@ class CredentialServiceNotifier( override def getJwtIssuer( jwtIssuerDID: PrismDID, verificationRelationship: VerificationRelationship, - keyId: Option[String] + keyId: Option[KeyId] ): URIO[WalletAccessContext, Issuer] = svc.getJwtIssuer(jwtIssuerDID, verificationRelationship, keyId) } diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/MockCredentialService.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/MockCredentialService.scala index 5c9e412f3f..ebaee00e70 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/MockCredentialService.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/MockCredentialService.scala @@ -8,6 +8,7 @@ import org.hyperledger.identus.pollux.core.model.{DidCommID, IssueCredentialReco import org.hyperledger.identus.pollux.core.model.error.CredentialServiceError import org.hyperledger.identus.pollux.core.model.error.CredentialServiceError.* import org.hyperledger.identus.pollux.vc.jwt.Issuer +import org.hyperledger.identus.shared.models.KeyId import org.hyperledger.identus.shared.models.WalletAccessContext import zio.{mock, Duration, IO, UIO, URIO, URLayer, ZIO, ZLayer} import zio.mock.{Mock, Proxy} @@ -66,7 +67,7 @@ object MockCredentialService extends Mock[CredentialService] { object ReceiveCredentialOffer extends Effect[OfferCredential, InvalidCredentialOffer, IssueCredentialRecord] object AcceptCredentialOffer extends Effect[ - (DidCommID, Option[String], Option[String]), + (DidCommID, Option[String], Option[KeyId]), RecordNotFound | UnsupportedDidFormat, IssueCredentialRecord ] @@ -178,7 +179,7 @@ object MockCredentialService extends Mock[CredentialService] { override def acceptCredentialOffer( recordId: DidCommID, subjectId: Option[String], - keyId: Option[String] + keyId: Option[KeyId] ): IO[RecordNotFound | UnsupportedDidFormat, IssueCredentialRecord] = proxy(AcceptCredentialOffer, recordId, subjectId, keyId) @@ -284,7 +285,7 @@ object MockCredentialService extends Mock[CredentialService] { override def getJwtIssuer( jwtIssuerDID: PrismDID, verificationRelationship: VerificationRelationship, - keyId: Option[String] + keyId: Option[KeyId] ): URIO[WalletAccessContext, Issuer] = ??? } } diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceImpl.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceImpl.scala index 8da8573337..d153000be6 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceImpl.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceImpl.scala @@ -18,7 +18,6 @@ import org.hyperledger.identus.pollux.core.repository.{CredentialRepository, Pre import org.hyperledger.identus.pollux.core.service.serdes.* import org.hyperledger.identus.pollux.sdjwt.{CredentialCompact, HolderPrivateKey, PresentationCompact, SDJWT} import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.shared.crypto.Ed25519KeyPair import org.hyperledger.identus.shared.models.WalletAccessContext import org.hyperledger.identus.shared.utils.aspects.CustomMetricsAspect import zio.* diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositorySpecSuite.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositorySpecSuite.scala index 74ee6fcd23..089c42a57b 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositorySpecSuite.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositorySpecSuite.scala @@ -6,6 +6,7 @@ import org.hyperledger.identus.mercury.protocol.issuecredential.{IssueCredential import org.hyperledger.identus.pollux.core.model.* import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.* import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId} +import org.hyperledger.identus.shared.models.KeyId import zio.{Exit, ZIO, ZLayer} import zio.test.* import zio.test.Assertion.* @@ -469,7 +470,7 @@ object CredentialRepositorySpecSuite { record1 = issueCredentialRecord(CredentialFormat.JWT) record2 = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.create(record1).provide(wallet1) - res <- repo.updateWithSubjectId(record2.id, "my-id", Some("my-key-id"), newState).provide(wallet2).exit + res <- repo.updateWithSubjectId(record2.id, "my-id", Some(KeyId("my-key-id")), newState).provide(wallet2).exit } yield assert(res)(dies(isSubtype[RuntimeException](anything))) }, test("unable to delete IssueCredentialRecord outside of the wallet") { diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImplSpec.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImplSpec.scala index dc6fe8d945..c5f69d8389 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImplSpec.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceImplSpec.scala @@ -20,6 +20,7 @@ import org.hyperledger.identus.pollux.core.model.error.CredentialServiceError.{ import org.hyperledger.identus.pollux.core.model.schema.CredentialDefinition import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.{ProtocolState, Role} import org.hyperledger.identus.shared.models.{UnmanagedFailureException, WalletAccessContext, WalletId} +import org.hyperledger.identus.shared.models.KeyId import zio.* import zio.mock.MockSpecDefault import zio.test.* @@ -319,7 +320,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3" offerReceivedRecord <- holderSvc.receiveCredentialOffer(offer) offerAcceptedRecord <- holderSvc - .acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some("my-key-id")) + .acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id"))) } yield { assertTrue(offerAcceptedRecord.protocolState == ProtocolState.RequestPending) && assertTrue(offerAcceptedRecord.offerCredentialData.isDefined) && @@ -346,8 +347,10 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS offer = offerCredential() subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3" offerReceivedRecord <- holderSvc.receiveCredentialOffer(offer) - _ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some("my-key-id")) - exit <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some("my-key-id")).exit + _ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id"))) + exit <- holderSvc + .acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id"))) + .exit } yield { assertTrue(exit match case Exit.Failure(Cause.Fail(_: RecordNotFound, _)) => true @@ -361,7 +364,9 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS offer = offerCredential() subjectId = "did:unknown:subject" offerReceivedRecord <- holderSvc.receiveCredentialOffer(offer) - record <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some("my-key-id")).exit + record <- holderSvc + .acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id"))) + .exit } yield { assertTrue(record match case Exit.Failure(Cause.Fail(_: UnsupportedDidFormat, _)) => true @@ -445,7 +450,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS offer = offerCredential() subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3" offerReceivedRecord <- holderSvc.receiveCredentialOffer(offer) - _ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some("my-key-id")) + _ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id"))) _ <- holderSvc.generateJWTCredentialRequest(offerReceivedRecord.id) _ <- holderSvc.markRequestSent(offerReceivedRecord.id) issue = issueCredential(thid = Some(offerReceivedRecord.thid)) @@ -461,7 +466,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS offer = offerCredential() subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3" offerReceivedRecord <- holderSvc.receiveCredentialOffer(offer) - _ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some("my-key-id")) + _ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id"))) _ <- holderSvc.generateJWTCredentialRequest(offerReceivedRecord.id) _ <- holderSvc.markRequestSent(offerReceivedRecord.id) issue = issueCredential(thid = Some(offerReceivedRecord.thid)) @@ -480,7 +485,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS offer = offerCredential() subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3" offerReceivedRecord <- holderSvc.receiveCredentialOffer(offer) - _ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some("my-key-id")) + _ <- holderSvc.acceptCredentialOffer(offerReceivedRecord.id, Some(subjectId), Some(KeyId("my-key-id"))) _ <- holderSvc.generateJWTCredentialRequest(offerReceivedRecord.id) _ <- holderSvc.markRequestSent(offerReceivedRecord.id) issue = issueCredential(thid = Some(DidCommID())) @@ -508,7 +513,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS holderRecordId = offerReceivedRecord.id subjectId = "did:prism:60821d6833158c93fde5bb6a40d69996a683bf1fa5cdf32c458395b2887597c3" // Holder accepts offer - _ <- holderSvc.acceptCredentialOffer(holderRecordId, Some(subjectId), Some("my-key-id")) + _ <- holderSvc.acceptCredentialOffer(holderRecordId, Some(subjectId), Some(KeyId("my-key-id"))) // Holder generates proof requestGeneratedRecord <- holderSvc.generateJWTCredentialRequest(offerReceivedRecord.id) // Holder sends offer diff --git a/pollux/sd-jwt/src/main/scala/org/hyperledger/identus/pollux/sdjwt/Models.scala b/pollux/sd-jwt/src/main/scala/org/hyperledger/identus/pollux/sdjwt/Models.scala index b7bfee0375..20e00b5666 100644 --- a/pollux/sd-jwt/src/main/scala/org/hyperledger/identus/pollux/sdjwt/Models.scala +++ b/pollux/sd-jwt/src/main/scala/org/hyperledger/identus/pollux/sdjwt/Models.scala @@ -4,7 +4,6 @@ import org.bouncycastle.crypto.params.{Ed25519PrivateKeyParameters, Ed25519Publi import org.bouncycastle.crypto.util.{PrivateKeyInfoFactory, SubjectPublicKeyInfoFactory} import org.hyperledger.identus.shared.crypto.* import sdjwtwrapper.* -import zio.json.* import java.util.Base64 diff --git a/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/repository/JdbcCredentialRepository.scala b/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/repository/JdbcCredentialRepository.scala index 171860cf91..ab502e8907 100644 --- a/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/repository/JdbcCredentialRepository.scala +++ b/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/repository/JdbcCredentialRepository.scala @@ -15,6 +15,7 @@ import org.hyperledger.identus.pollux.core.model.* import org.hyperledger.identus.pollux.core.repository.CredentialRepository import org.hyperledger.identus.shared.db.ContextAwareTask import org.hyperledger.identus.shared.db.Implicits.* +import org.hyperledger.identus.shared.models.KeyId import org.hyperledger.identus.shared.models.WalletAccessContext import zio.* import zio.interop.catz.* @@ -53,6 +54,8 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ given issueCredentialGet: Get[IssueCredential] = Get[String].map(decode[IssueCredential](_).getOrElse(???)) given issueCredentialPut: Put[IssueCredential] = Put[String].contramap(_.asJson.toString) + given keyIdGet: Get[KeyId] = Get[String].map(KeyId(_)) + given keyIdPut: Put[KeyId] = Put[String].contramap(_.value) override def create(record: IssueCredentialRecord): URIO[WalletAccessContext, Unit] = { val cxnIO = sql""" | INSERT INTO public.issue_credential_records( @@ -362,7 +365,7 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ def updateWithSubjectId( recordId: DidCommID, subjectId: String, - keyId: Option[String] = None, + keyId: Option[KeyId] = None, protocolState: ProtocolState ): URIO[WalletAccessContext, Unit] = { val cxnIO = sql""" diff --git a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/DidJWT.scala b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/DidJWT.scala index 3e94cb16b3..990df782e5 100644 --- a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/DidJWT.scala +++ b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/DidJWT.scala @@ -7,6 +7,7 @@ import com.nimbusds.jose.jwk.{Curve, ECKey} import com.nimbusds.jwt.{JWTClaimsSet, SignedJWT} import io.circe.* import org.hyperledger.identus.shared.crypto.{Ed25519KeyPair, Secp256k1PrivateKey} +import org.hyperledger.identus.shared.models.KeyId import zio.* import java.security.* @@ -43,7 +44,7 @@ trait Signer { // 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, keyId: Option[String] = None) extends Signer { +class ES256KSigner(privateKey: PrivateKey, keyId: Option[KeyId] = None) extends Signer { lazy val signer: ECDSASigner = { val ecdsaSigner = ECDSASigner(privateKey, Curve.SECP256K1) val bouncyCastleProvider = BouncyCastleProviderSingleton.getInstance @@ -59,7 +60,7 @@ class ES256KSigner(privateKey: PrivateKey, keyId: Option[String] = None) extends val claimSet = JWTClaimsSet.parse(claim.noSpaces) val signedJwt = SignedJWT( keyId - .map(kid => new JWSHeader.Builder(JWSAlgorithm.ES256K).`type`(JOSEObjectType.JWT).keyID(kid)) + .map(kid => new JWSHeader.Builder(JWSAlgorithm.ES256K).`type`(JOSEObjectType.JWT).keyID(kid.value)) .getOrElse(new JWSHeader.Builder(JWSAlgorithm.ES256K).`type`(JOSEObjectType.JWT)) .build(), claimSet @@ -69,7 +70,7 @@ class ES256KSigner(privateKey: PrivateKey, keyId: Option[String] = None) extends } } -class EdSigner(ed25519KeyPair: Ed25519KeyPair, keyId: Option[String] = None) extends Signer { +class EdSigner(ed25519KeyPair: Ed25519KeyPair, keyId: Option[KeyId] = None) extends Signer { lazy val signer: Ed25519Signer = { val ed25519Signer = Ed25519Signer(ed25519KeyPair.toOctetKeyPair) ed25519Signer @@ -84,7 +85,7 @@ class EdSigner(ed25519KeyPair: Ed25519KeyPair, keyId: Option[String] = None) ext val signedJwt = SignedJWT( keyId - .map(kid => new JWSHeader.Builder(JWSAlgorithm.EdDSA).`type`(JOSEObjectType.JWT).keyID(kid)) + .map(kid => new JWSHeader.Builder(JWSAlgorithm.EdDSA).`type`(JOSEObjectType.JWT).keyID(kid.value)) .getOrElse(new JWSHeader.Builder(JWSAlgorithm.EdDSA).`type`(JOSEObjectType.JWT)) .build(), claimSet diff --git a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerification.scala b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerification.scala index ed0d3974a8..4d614a2436 100644 --- a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerification.scala +++ b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerification.scala @@ -8,7 +8,7 @@ import com.nimbusds.jose.JWSVerifier import com.nimbusds.jwt.SignedJWT import io.circe import io.circe.generic.auto.* -import org.hyperledger.identus.castor.core.model.did.{PrismDID, VerificationRelationship} +import org.hyperledger.identus.castor.core.model.did.VerificationRelationship import org.hyperledger.identus.shared.crypto.Ed25519PublicKey import pdi.jwt.* import zio.* diff --git a/shared/core/src/main/scala/org/hyperledger/identus/shared/models/KeyId.scala b/shared/core/src/main/scala/org/hyperledger/identus/shared/models/KeyId.scala new file mode 100644 index 0000000000..67f686971f --- /dev/null +++ b/shared/core/src/main/scala/org/hyperledger/identus/shared/models/KeyId.scala @@ -0,0 +1,6 @@ +package org.hyperledger.identus.shared.models + +opaque type KeyId = String +object KeyId: + def apply(value: String): KeyId = value + extension (id: KeyId) def value: String = id