From 61859972fcfffd6dfcbdf2cbc2f7a5f2444f6034 Mon Sep 17 00:00:00 2001 From: Bassam Date: Sat, 11 Nov 2023 15:14:52 -0500 Subject: [PATCH] feat: Accept Presentation Request (#781) Signed-off-by: Bassam Riman --- .../core/model/IssueCredentialRecord.scala | 1 + .../core/model/error/PresentationError.scala | 1 + .../CredentialRepositoryInMemory.scala | 2 +- .../service/PresentationServiceImpl.scala | 27 ++-- .../CredentialRepositorySpecSuite.scala | 131 +++++++++++------- .../PresentationServiceNotifierSpec.scala | 4 +- .../service/PresentationServiceSpec.scala | 116 ++++++++++++++-- .../PresentationServiceSpecHelper.scala | 8 +- .../repository/JdbcCredentialRepository.scala | 1 + 9 files changed, 210 insertions(+), 81 deletions(-) diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/model/IssueCredentialRecord.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/model/IssueCredentialRecord.scala index a232e39848..2cbae20941 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/model/IssueCredentialRecord.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/model/IssueCredentialRecord.scala @@ -69,6 +69,7 @@ final case class IssueCredentialRecord( final case class ValidIssuedCredentialRecord( id: DidCommID, issuedCredentialRaw: Option[String], + credentialFormat: CredentialFormat, subjectId: Option[String] ) diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/model/error/PresentationError.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/model/error/PresentationError.scala index a7227cee7e..194d706178 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/model/error/PresentationError.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/model/error/PresentationError.scala @@ -11,6 +11,7 @@ object PresentationError { final case class InvalidFlowStateError(msg: String) extends PresentationError final case class UnexpectedError(msg: String) extends PresentationError final case class IssuedCredentialNotFoundError(cause: Throwable) extends PresentationError + final case class NotMatchingPresentationCredentialFormat(cause: Throwable) extends PresentationError final case class PresentationDecodingError(cause: Throwable) extends PresentationError final case class PresentationNotFoundError(cause: Throwable) extends PresentationError final case class HolderBindingError(msg: String) extends PresentationError diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/repository/CredentialRepositoryInMemory.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/repository/CredentialRepositoryInMemory.scala index f69e3b94e4..4624e0a156 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/repository/CredentialRepositoryInMemory.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/repository/CredentialRepositoryInMemory.scala @@ -133,7 +133,7 @@ class CredentialRepositoryInMemory( store <- storeRef.get } yield store.values .filter(rec => recordId.contains(rec.id) && rec.issuedCredentialRaw.isDefined) - .map(rec => ValidIssuedCredentialRecord(rec.id, rec.issuedCredentialRaw, rec.subjectId)) + .map(rec => ValidIssuedCredentialRecord(rec.id, rec.issuedCredentialRaw, rec.credentialFormat, rec.subjectId)) .toSeq } diff --git a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationServiceImpl.scala b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationServiceImpl.scala index f81699abeb..340e36ec3b 100644 --- a/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationServiceImpl.scala +++ b/pollux/lib/core/src/main/scala/io/iohk/atala/pollux/core/service/PresentationServiceImpl.scala @@ -411,23 +411,32 @@ private class PresentationServiceImpl( for { record <- getRecordWithState(recordId, ProtocolState.RequestReceived) - issuedValidCredentials <- credentialRepository + issuedCredentials <- credentialRepository .getValidIssuedCredentials(credentialsToUse.map(DidCommID(_))) .mapError(RepositoryError.apply) _ <- ZIO.cond( - (issuedValidCredentials.map(_.subjectId).toSet.size == 1), + (issuedCredentials.map(_.subjectId).toSet.size == 1), (), PresentationError.HolderBindingError( - s"Creating a Verifiable Presentation for credential with different subject DID is not supported, found : ${issuedValidCredentials + s"Creating a Verifiable Presentation for credential with different subject DID is not supported, found : ${issuedCredentials .map(_.subjectId)}" ) ) - signedCredentials = issuedValidCredentials.flatMap(_.issuedCredentialRaw) - // record.credentialFormat match { - // case PresentationRecord.CredentialFormat.JWT => issuedRawCredentials - // case CredentialFormat.AnonCreds => issuedRawCredentials - // } - issuedCredentials <- ZIO.fromEither( + validatedCredentials <- ZIO.fromEither( + Either.cond( + issuedCredentials.forall(issuedValidCredential => + issuedValidCredential.credentialFormat == record.credentialFormat + ), + issuedCredentials, + PresentationError.NotMatchingPresentationCredentialFormat( + new IllegalArgumentException( + s"No matching issued credentials format: expectedFormat=${record.credentialFormat}" + ) + ) + ) + ) + signedCredentials = validatedCredentials.flatMap(_.issuedCredentialRaw) + _ <- ZIO.fromEither( Either.cond( signedCredentials.nonEmpty, signedCredentials, diff --git a/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/repository/CredentialRepositorySpecSuite.scala b/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/repository/CredentialRepositorySpecSuite.scala index b363446d36..ce622e7a16 100644 --- a/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/repository/CredentialRepositorySpecSuite.scala +++ b/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/repository/CredentialRepositorySpecSuite.scala @@ -17,14 +17,14 @@ import java.util.UUID object CredentialRepositorySpecSuite { val maxRetries = 5 // TODO Move to config - private def issueCredentialRecord = IssueCredentialRecord( + private def issueCredentialRecord(credentialFormat: CredentialFormat) = IssueCredentialRecord( id = DidCommID(), createdAt = Instant.now, updatedAt = None, thid = DidCommID(), schemaId = None, credentialDefinitionId = None, - credentialFormat = CredentialFormat.JWT, + credentialFormat = credentialFormat, role = IssueCredentialRecord.Role.Issuer, subjectId = None, validityPeriod = None, @@ -53,7 +53,7 @@ object CredentialRepositorySpecSuite { test("createIssueCredentialRecord creates a new record in DB") { for { repo <- ZIO.service[CredentialRepository] - record = issueCredentialRecord + record = issueCredentialRecord(CredentialFormat.JWT) count <- repo.createIssueCredentialRecord(record) } yield assertTrue(count == 1) }, @@ -61,8 +61,8 @@ object CredentialRepositorySpecSuite { for { repo <- ZIO.service[CredentialRepository] thid = DidCommID() - aRecord = issueCredentialRecord.copy(thid = thid) - bRecord = issueCredentialRecord.copy(thid = thid) + aRecord = issueCredentialRecord(CredentialFormat.JWT).copy(thid = thid) + bRecord = issueCredentialRecord(CredentialFormat.JWT).copy(thid = thid) aCount <- repo.createIssueCredentialRecord(aRecord) bCount <- repo.createIssueCredentialRecord(bRecord).exit } yield assertTrue(aCount == 1) && assert(bCount)(fails(isSubtype[UniqueConstraintViolation](anything))) @@ -71,7 +71,7 @@ object CredentialRepositorySpecSuite { for { repo <- ZIO.service[CredentialRepository] issuingDID <- ZIO.fromEither(PrismDID.buildCanonicalFromSuffix("0" * 64)) - record = issueCredentialRecord.copy(issuingDID = Some(issuingDID)) + record = issueCredentialRecord(CredentialFormat.JWT).copy(issuingDID = Some(issuingDID)) count <- repo.createIssueCredentialRecord(record) readRecord <- repo.getIssueCredentialRecord(record.id) } yield assertTrue(count == 1) && assert(readRecord)(isSome(equalTo(record))) @@ -79,8 +79,8 @@ object CredentialRepositorySpecSuite { test("getIssueCredentialRecord correctly returns an existing record") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) record <- repo.getIssueCredentialRecord(bRecord.id) @@ -89,8 +89,8 @@ object CredentialRepositorySpecSuite { test("getIssuanceCredentialRecord returns None for an unknown record") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) record <- repo.getIssueCredentialRecord(DidCommID()) @@ -99,8 +99,8 @@ object CredentialRepositorySpecSuite { test("getIssuanceCredentialRecord returns all records") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) records <- repo.getIssueCredentialRecords(false).map(_._1) @@ -113,8 +113,8 @@ object CredentialRepositorySpecSuite { test("getIssuanceCredentialRecord returns records with offset") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) records <- repo.getIssueCredentialRecords(false, offset = Some(1)).map(_._1) @@ -126,8 +126,8 @@ object CredentialRepositorySpecSuite { test("getIssuanceCredentialRecord returns records with limit") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) records <- repo.getIssueCredentialRecords(false, limit = Some(1)).map(_._1) @@ -139,9 +139,9 @@ object CredentialRepositorySpecSuite { test("getIssuanceCredentialRecord returns records with offset and limit") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord - cRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) + cRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) _ <- repo.createIssueCredentialRecord(cRecord) @@ -156,8 +156,8 @@ object CredentialRepositorySpecSuite { test("deleteIssueCredentialRecord deletes an exsiting record") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) count <- repo.deleteIssueCredentialRecord(aRecord.id) @@ -171,8 +171,8 @@ object CredentialRepositorySpecSuite { test("deleteIssueCredentialRecord does nothing for an unknown record") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) count <- repo.deleteIssueCredentialRecord(DidCommID()) @@ -188,8 +188,8 @@ object CredentialRepositorySpecSuite { for { repo <- ZIO.service[CredentialRepository] thid = DidCommID() - aRecord = issueCredentialRecord.copy(thid = thid) - bRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT).copy(thid = thid) + bRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) record <- repo.getIssueCredentialRecordByThreadId(thid, false) @@ -198,8 +198,8 @@ object CredentialRepositorySpecSuite { test("getIssueCredentialRecordByThreadId returns nothing for an unknown thid") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) record <- repo.getIssueCredentialRecordByThreadId(DidCommID(), false) @@ -208,9 +208,9 @@ object CredentialRepositorySpecSuite { test("getIssueCredentialRecordsByStates returns valid records") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord - cRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) + cRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) _ <- repo.createIssueCredentialRecord(cRecord) @@ -242,9 +242,9 @@ object CredentialRepositorySpecSuite { test("getIssueCredentialRecordsByStates returns an empty list if 'states' parameter is empty") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord - cRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) + cRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) _ <- repo.createIssueCredentialRecord(cRecord) @@ -256,30 +256,55 @@ object CredentialRepositorySpecSuite { test("getValidIssuedCredentials returns valid records") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord - bRecord = issueCredentialRecord - cRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) + bRecord = issueCredentialRecord(CredentialFormat.JWT) + cRecord = issueCredentialRecord(CredentialFormat.JWT) + dRecord = issueCredentialRecord(CredentialFormat.AnonCreds) _ <- repo.createIssueCredentialRecord(aRecord) _ <- repo.createIssueCredentialRecord(bRecord) _ <- repo.createIssueCredentialRecord(cRecord) + _ <- repo.createIssueCredentialRecord(dRecord) _ <- repo.updateWithIssuedRawCredential( aRecord.id, IssueCredential.makeIssueCredentialFromRequestCredential(requestCredential.makeMessage), "RAW_CREDENTIAL_DATA", ProtocolState.CredentialReceived ) - records <- repo.getValidIssuedCredentials(Seq(aRecord.id, bRecord.id)) + _ <- repo.updateWithIssuedRawCredential( + dRecord.id, + IssueCredential.makeIssueCredentialFromRequestCredential(requestCredential.makeMessage), + "RAW_CREDENTIAL_DATA", + ProtocolState.CredentialReceived + ) + records <- repo.getValidIssuedCredentials(Seq(aRecord.id, bRecord.id, dRecord.id)) } yield { - assertTrue(records.size == 1) && + assertTrue(records.size == 2) && assertTrue( - records.contains(ValidIssuedCredentialRecord(aRecord.id, Some("RAW_CREDENTIAL_DATA"), aRecord.subjectId)) + records.contains( + ValidIssuedCredentialRecord( + dRecord.id, + Some("RAW_CREDENTIAL_DATA"), + CredentialFormat.JWT, + aRecord.subjectId + ) + ) + ) + assertTrue( + records.contains( + ValidIssuedCredentialRecord( + dRecord.id, + Some("RAW_CREDENTIAL_DATA"), + CredentialFormat.AnonCreds, + aRecord.subjectId + ) + ) ) } }, test("updateCredentialRecordProtocolState updates the record") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) record <- repo.getIssueCredentialRecord(aRecord.id) count <- repo.updateCredentialRecordProtocolState( @@ -297,7 +322,7 @@ object CredentialRepositorySpecSuite { test("updateCredentialRecordProtocolState doesn't update the record for invalid from state") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) record <- repo.getIssueCredentialRecord(aRecord.id) count <- repo.updateCredentialRecordProtocolState( @@ -315,7 +340,7 @@ object CredentialRepositorySpecSuite { test("updateWithRequestCredential updates record") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) record <- repo.getIssueCredentialRecord(aRecord.id) request = requestCredential @@ -334,7 +359,7 @@ object CredentialRepositorySpecSuite { test("updateWithIssueCredential updates record") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) record <- repo.getIssueCredentialRecord(aRecord.id) issueCredential = IssueCredential.makeIssueCredentialFromRequestCredential(requestCredential.makeMessage) @@ -353,7 +378,7 @@ object CredentialRepositorySpecSuite { test("updateWithIssuedRawCredential updates record") { for { repo <- ZIO.service[CredentialRepository] - aRecord = issueCredentialRecord + aRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aRecord) record <- repo.getIssueCredentialRecord(aRecord.id) issueCredential = IssueCredential.makeIssueCredentialFromRequestCredential(requestCredential.makeMessage) @@ -372,7 +397,7 @@ object CredentialRepositorySpecSuite { } }, test("updateFail (fail one retry) updates record") { - val aRecord = issueCredentialRecord + val aRecord = issueCredentialRecord(CredentialFormat.JWT) val failReason = Some("Just to test") for { @@ -402,7 +427,7 @@ object CredentialRepositorySpecSuite { } }, test("updateFail (fail all retry) updates record") { - val aRecord = issueCredentialRecord + val aRecord = issueCredentialRecord(CredentialFormat.JWT) for { repo <- ZIO.service[CredentialRepository] @@ -443,8 +468,8 @@ object CredentialRepositorySpecSuite { val wallet2 = ZLayer.succeed(WalletAccessContext(walletId2)) for { repo <- ZIO.service[CredentialRepository] - record1 = issueCredentialRecord - record2 = issueCredentialRecord + record1 = issueCredentialRecord(CredentialFormat.JWT) + record2 = issueCredentialRecord(CredentialFormat.JWT) count1 <- repo.createIssueCredentialRecord(record1).provide(wallet1) count2 <- repo.createIssueCredentialRecord(record2).provide(wallet2) ownWalletRecords1 <- repo.getIssueCredentialRecords(false).provide(wallet1) @@ -466,8 +491,8 @@ object CredentialRepositorySpecSuite { val newState = IssueCredentialRecord.ProtocolState.OfferReceived for { repo <- ZIO.service[CredentialRepository] - record1 = issueCredentialRecord - record2 = issueCredentialRecord + record1 = issueCredentialRecord(CredentialFormat.JWT) + record2 = issueCredentialRecord(CredentialFormat.JWT) count1 <- repo.createIssueCredentialRecord(record1).provide(wallet1) update1 <- repo.updateWithSubjectId(record2.id, "my-id", newState).provide(wallet2) update2 <- repo.updateAfterFail(record2.id, Some("fail reason")).provide(wallet2) @@ -486,7 +511,7 @@ object CredentialRepositorySpecSuite { val wallet2 = ZLayer.succeed(WalletAccessContext(walletId2)) for { repo <- ZIO.service[CredentialRepository] - record1 = issueCredentialRecord + record1 = issueCredentialRecord(CredentialFormat.JWT) count1 <- repo.createIssueCredentialRecord(record1).provide(wallet1) delete1 <- repo.deleteIssueCredentialRecord(record1.id).provide(wallet2) } yield assert(count1)(equalTo(1)) && assert(delete1)(isZero) @@ -498,8 +523,8 @@ object CredentialRepositorySpecSuite { val wallet2 = ZLayer.succeed(WalletAccessContext(walletId2)) for { repo <- ZIO.service[CredentialRepository] - record1 = issueCredentialRecord - record2 = issueCredentialRecord + record1 = issueCredentialRecord(CredentialFormat.JWT) + record2 = issueCredentialRecord(CredentialFormat.JWT) count1 <- repo.createIssueCredentialRecord(record1).provide(wallet1) count2 <- repo.createIssueCredentialRecord(record2).provide(wallet2) _ <- repo diff --git a/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceNotifierSpec.scala b/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceNotifierSpec.scala index c65a1d512c..759f64326f 100644 --- a/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceNotifierSpec.scala +++ b/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceNotifierSpec.scala @@ -2,7 +2,7 @@ package io.iohk.atala.pollux.core.service import io.iohk.atala.event.notification.{EventNotificationService, EventNotificationServiceImpl} import io.iohk.atala.mercury.model.DidId -import io.iohk.atala.mercury.protocol.presentproof.{Presentation, RequestPresentation} +import io.iohk.atala.mercury.protocol.presentproof.{PresentCredentialRequestFormat, Presentation, RequestPresentation} import io.iohk.atala.pollux.core.model.PresentationRecord.ProtocolState import io.iohk.atala.pollux.core.model.{CredentialFormat, DidCommID, PresentationRecord} import zio.mock.Expectation @@ -169,7 +169,7 @@ object PresentationServiceNotifierSpec extends ZIOSpecDefault with PresentationS svc <- ZIO.service[PresentationService] ens <- ZIO.service[EventNotificationService] - _ <- svc.receiveRequestPresentation(None, requestPresentationJWT) + _ <- svc.receiveRequestPresentation(None, requestPresentation(PresentCredentialRequestFormat.JWT)) _ <- svc.acceptRequestPresentation(record.id, Seq.empty) _ <- svc.markPresentationGenerated(record.id, presentation(record.thid.value)) _ <- svc.markPresentationSent(record.id) diff --git a/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceSpec.scala b/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceSpec.scala index 332810668a..a311a3a2b4 100644 --- a/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceSpec.scala +++ b/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceSpec.scala @@ -210,7 +210,7 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp test("createPresentationPayloadFromRecord returns jwt prsentation payload") { for { repo <- ZIO.service[CredentialRepository] - aIssueCredentialRecord = issueCredentialRecord + aIssueCredentialRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aIssueCredentialRecord) rawCredentialData = """{"base64":"ZXlKaGJHY2lPaUpGVXpJMU5rc2lMQ0owZVhBaU9pSktWMVFpZlEuZXlKcFlYUWlPakUyTnprek1qYzROaklzSW1GMVpDSTZJbVJ2YldGcGJpSXNJbTV2Ym1ObElqb2lZMlk1T1RJMk56Z3RPREV3TmkwME1EZzVMV0UxWXprdE5tTmhObU0wWkRBMU1HVTBJaXdpZG5BaU9uc2lRR052Ym5SbGVIUWlPbHNpYUhSMGNITTZMeTkzZDNjdWR6TXViM0puTHpJd01UZ3ZjSEpsYzJWdWRHRjBhVzl1Y3k5Mk1TSmRMQ0owZVhCbElqcGJJbFpsY21sbWFXRmliR1ZRY21WelpXNTBZWFJwYjI0aVhYMHNJbWx6Y3lJNkltUnBaRHB3Y21semJUcGhaR0psT1RJNE9XUXdZelZtWWpVMlptWmhOVEF6T0Rka01UZ3dOR0ZpTkdFeE5UYzJOVEkzWXprME5tRTFNalV5T0RFM1ptRTRaVGhoTW1OalpXUXdPa056YzBKRGMyZENSVzFKUzBSWE1XaGpNMUpzWTJsb2NHSnRVbXhsUTJ0UlFWVktVRU5uYkZSYVYwNTNUV3BWTW1GNlJWTkpSUzFNYVVkTU0xRklaRlZ1VG10d1dXSkthSE5VYTIxWVVGaEpVM0ZXZWpjMll6RlZPWGhvVURseWNFZHBSSEZXTlRselJYcEtWbEpEYWxJMGEwMHdaMGg0YkhWUU5tVk5Ta2wwZHpJMk4yWllWbEpoTUhoRE5XaEthVU5uTVhSWldFNHdXbGhKYjJGWE5XdGFXR2R3UlVGU1ExUjNiMHBWTWxacVkwUkpNVTV0YzNoRmFVSlFhVFJvYVRrd1FqTldTbnBhUzFkSGVWbGlSVFZLYkhveGVVVnhiR010TFc1T1ZsQmpXVlJmWVRaU2IyYzJiR1ZtWWtKTmVWWlZVVzh3WlVwRVRrbENPRnBpYWkxdWFrTlRUR05PZFhVek1URlZWM1JOVVhWWkluMC5CcmFpbEVXa2VlSXhWbjY3dnpkVHZGTXpBMV9oNzFoaDZsODBHRFBpbkRaVVB4ajAxSC0tUC1QZDIxTk9wRDd3am51SDkxdUNBOFZMUW9fS2FnVjlnQQo="}""" @@ -444,10 +444,10 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp fails(isSubtype[InvalidAnoncredPresentationRequest](anything)) ) }, - test("acceptRequestPresentation updates the PresentatinRecord JWT") { + test("acceptRequestPresentation updates the PresentationRecord JWT") { for { repo <- ZIO.service[CredentialRepository] - aIssueCredentialRecord = issueCredentialRecord + aIssueCredentialRecord = issueCredentialRecord(CredentialFormat.JWT) _ <- repo.createIssueCredentialRecord(aIssueCredentialRecord) rawCredentialData = """{"base64":"ZXlKaGJHY2lPaUpGVXpJMU5rc2lMQ0owZVhBaU9pSktWMVFpZlEuZXlKcFlYUWlPakUyTnprek1qYzROaklzSW1GMVpDSTZJbVJ2YldGcGJpSXNJbTV2Ym1ObElqb2lZMlk1T1RJMk56Z3RPREV3TmkwME1EZzVMV0UxWXprdE5tTmhObU0wWkRBMU1HVTBJaXdpZG5BaU9uc2lRR052Ym5SbGVIUWlPbHNpYUhSMGNITTZMeTkzZDNjdWR6TXViM0puTHpJd01UZ3ZjSEpsYzJWdWRHRjBhVzl1Y3k5Mk1TSmRMQ0owZVhCbElqcGJJbFpsY21sbWFXRmliR1ZRY21WelpXNTBZWFJwYjI0aVhYMHNJbWx6Y3lJNkltUnBaRHB3Y21semJUcGhaR0psT1RJNE9XUXdZelZtWWpVMlptWmhOVEF6T0Rka01UZ3dOR0ZpTkdFeE5UYzJOVEkzWXprME5tRTFNalV5T0RFM1ptRTRaVGhoTW1OalpXUXdPa056YzBKRGMyZENSVzFKUzBSWE1XaGpNMUpzWTJsb2NHSnRVbXhsUTJ0UlFWVktVRU5uYkZSYVYwNTNUV3BWTW1GNlJWTkpSUzFNYVVkTU0xRklaRlZ1VG10d1dXSkthSE5VYTIxWVVGaEpVM0ZXZWpjMll6RlZPWGhvVURseWNFZHBSSEZXTlRselJYcEtWbEpEYWxJMGEwMHdaMGg0YkhWUU5tVk5Ta2wwZHpJMk4yWllWbEpoTUhoRE5XaEthVU5uTVhSWldFNHdXbGhKYjJGWE5XdGFXR2R3UlVGU1ExUjNiMHBWTWxacVkwUkpNVTV0YzNoRmFVSlFhVFJvYVRrd1FqTldTbnBhUzFkSGVWbGlSVFZLYkhveGVVVnhiR010TFc1T1ZsQmpXVlJmWVRaU2IyYzJiR1ZtWWtKTmVWWlZVVzh3WlVwRVRrbENPRnBpYWkxdWFrTlRUR05PZFhVek1URlZWM1JOVVhWWkluMC5CcmFpbEVXa2VlSXhWbjY3dnpkVHZGTXpBMV9oNzFoaDZsODBHRFBpbkRaVVB4ajAxSC0tUC1QZDIxTk9wRDd3am51SDkxdUNBOFZMUW9fS2FnVjlnQQo="}""" @@ -460,7 +460,54 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp svc <- ZIO.service[PresentationService] connectionId = Some("connectionId") - aRecord <- svc.receiveRequestPresentation(connectionId, requestPresentationJWT) + aRecord <- svc.receiveRequestPresentation( + connectionId, + requestPresentation(PresentCredentialRequestFormat.JWT) + ) + credentialsToUse = Seq(aIssueCredentialRecord.id.value) + updateRecord <- svc.acceptRequestPresentation(aRecord.id, credentialsToUse) + + } yield { + assertTrue(updateRecord.connectionId == connectionId) && + // assertTrue(updateRecord.requestPresentationData == Some(requestPresentation)) && // FIXME: enabling them make the test fail. + assertTrue(updateRecord.credentialsToUse.contains(credentialsToUse)) + } + }, + test("acceptRequestPresentation updates the PresentationRecord AnonCreds") { + for { + repo <- ZIO.service[CredentialRepository] + aIssueCredentialRecord = issueCredentialRecord(CredentialFormat.AnonCreds) + _ <- repo.createIssueCredentialRecord(aIssueCredentialRecord) + rawCredentialData = + """{"base64":"ZXlKaGJHY2lPaUpGVXpJMU5rc2lMQ0owZVhBaU9pSktWMVFpZlEuZXlKcFlYUWlPakUyTnprek1qYzROaklzSW1GMVpDSTZJbVJ2YldGcGJpSXNJbTV2Ym1ObElqb2lZMlk1T1RJMk56Z3RPREV3TmkwME1EZzVMV0UxWXprdE5tTmhObU0wWkRBMU1HVTBJaXdpZG5BaU9uc2lRR052Ym5SbGVIUWlPbHNpYUhSMGNITTZMeTkzZDNjdWR6TXViM0puTHpJd01UZ3ZjSEpsYzJWdWRHRjBhVzl1Y3k5Mk1TSmRMQ0owZVhCbElqcGJJbFpsY21sbWFXRmliR1ZRY21WelpXNTBZWFJwYjI0aVhYMHNJbWx6Y3lJNkltUnBaRHB3Y21semJUcGhaR0psT1RJNE9XUXdZelZtWWpVMlptWmhOVEF6T0Rka01UZ3dOR0ZpTkdFeE5UYzJOVEkzWXprME5tRTFNalV5T0RFM1ptRTRaVGhoTW1OalpXUXdPa056YzBKRGMyZENSVzFKUzBSWE1XaGpNMUpzWTJsb2NHSnRVbXhsUTJ0UlFWVktVRU5uYkZSYVYwNTNUV3BWTW1GNlJWTkpSUzFNYVVkTU0xRklaRlZ1VG10d1dXSkthSE5VYTIxWVVGaEpVM0ZXZWpjMll6RlZPWGhvVURseWNFZHBSSEZXTlRselJYcEtWbEpEYWxJMGEwMHdaMGg0YkhWUU5tVk5Ta2wwZHpJMk4yWllWbEpoTUhoRE5XaEthVU5uTVhSWldFNHdXbGhKYjJGWE5XdGFXR2R3UlVGU1ExUjNiMHBWTWxacVkwUkpNVTV0YzNoRmFVSlFhVFJvYVRrd1FqTldTbnBhUzFkSGVWbGlSVFZLYkhveGVVVnhiR010TFc1T1ZsQmpXVlJmWVRaU2IyYzJiR1ZtWWtKTmVWWlZVVzh3WlVwRVRrbENPRnBpYWkxdWFrTlRUR05PZFhVek1URlZWM1JOVVhWWkluMC5CcmFpbEVXa2VlSXhWbjY3dnpkVHZGTXpBMV9oNzFoaDZsODBHRFBpbkRaVVB4ajAxSC0tUC1QZDIxTk9wRDd3am51SDkxdUNBOFZMUW9fS2FnVjlnQQo="}""" + _ <- repo.updateWithIssuedRawCredential( + aIssueCredentialRecord.id, + IssueCredential.makeIssueCredentialFromRequestCredential(requestCredential.makeMessage), + rawCredentialData, + IssueCredentialRecord.ProtocolState.CredentialReceived + ) + svc <- ZIO.service[PresentationService] + connectionId = Some("connectionId") + anoncredPresentationRequestV1 = AnoncredPresentationRequestV1( + Map.empty, + Map.empty, + "name", + "nonce", + "version", + None + ) + attachmentDescriptor = AttachmentDescriptor.buildBase64Attachment( + mediaType = Some("application/json"), + format = Some(PresentCredentialRequestFormat.Anoncred.name), + payload = AnoncredPresentationRequestV1.schemaSerDes.serialize(anoncredPresentationRequestV1).getBytes() + ) + requestPresentation = RequestPresentation( + body = RequestPresentation.Body(goal_code = Some("Presentation Request")), + attachments = Seq(attachmentDescriptor), + to = DidId("did:peer:Prover"), + from = DidId("did:peer:Verifier"), + ) + aRecord <- svc.receiveRequestPresentation(connectionId, requestPresentation) credentialsToUse = Seq(aIssueCredentialRecord.id.value) updateRecord <- svc.acceptRequestPresentation(aRecord.id, credentialsToUse) @@ -470,11 +517,56 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp assertTrue(updateRecord.credentialsToUse.contains(credentialsToUse)) } }, - test("rejectRequestPresentation updates the PresentatinRecord") { + test("acceptRequestPresentation should fail given unmatching format") { + for { + repo <- ZIO.service[CredentialRepository] + aIssueCredentialRecord = issueCredentialRecord(CredentialFormat.JWT) + _ <- repo.createIssueCredentialRecord(aIssueCredentialRecord) + rawCredentialData = + """{"base64":"ZXlKaGJHY2lPaUpGVXpJMU5rc2lMQ0owZVhBaU9pSktWMVFpZlEuZXlKcFlYUWlPakUyTnprek1qYzROaklzSW1GMVpDSTZJbVJ2YldGcGJpSXNJbTV2Ym1ObElqb2lZMlk1T1RJMk56Z3RPREV3TmkwME1EZzVMV0UxWXprdE5tTmhObU0wWkRBMU1HVTBJaXdpZG5BaU9uc2lRR052Ym5SbGVIUWlPbHNpYUhSMGNITTZMeTkzZDNjdWR6TXViM0puTHpJd01UZ3ZjSEpsYzJWdWRHRjBhVzl1Y3k5Mk1TSmRMQ0owZVhCbElqcGJJbFpsY21sbWFXRmliR1ZRY21WelpXNTBZWFJwYjI0aVhYMHNJbWx6Y3lJNkltUnBaRHB3Y21semJUcGhaR0psT1RJNE9XUXdZelZtWWpVMlptWmhOVEF6T0Rka01UZ3dOR0ZpTkdFeE5UYzJOVEkzWXprME5tRTFNalV5T0RFM1ptRTRaVGhoTW1OalpXUXdPa056YzBKRGMyZENSVzFKUzBSWE1XaGpNMUpzWTJsb2NHSnRVbXhsUTJ0UlFWVktVRU5uYkZSYVYwNTNUV3BWTW1GNlJWTkpSUzFNYVVkTU0xRklaRlZ1VG10d1dXSkthSE5VYTIxWVVGaEpVM0ZXZWpjMll6RlZPWGhvVURseWNFZHBSSEZXTlRselJYcEtWbEpEYWxJMGEwMHdaMGg0YkhWUU5tVk5Ta2wwZHpJMk4yWllWbEpoTUhoRE5XaEthVU5uTVhSWldFNHdXbGhKYjJGWE5XdGFXR2R3UlVGU1ExUjNiMHBWTWxacVkwUkpNVTV0YzNoRmFVSlFhVFJvYVRrd1FqTldTbnBhUzFkSGVWbGlSVFZLYkhveGVVVnhiR010TFc1T1ZsQmpXVlJmWVRaU2IyYzJiR1ZtWWtKTmVWWlZVVzh3WlVwRVRrbENPRnBpYWkxdWFrTlRUR05PZFhVek1URlZWM1JOVVhWWkluMC5CcmFpbEVXa2VlSXhWbjY3dnpkVHZGTXpBMV9oNzFoaDZsODBHRFBpbkRaVVB4ajAxSC0tUC1QZDIxTk9wRDd3am51SDkxdUNBOFZMUW9fS2FnVjlnQQo="}""" + _ <- repo.updateWithIssuedRawCredential( + aIssueCredentialRecord.id, + IssueCredential.makeIssueCredentialFromRequestCredential(requestCredential.makeMessage), + rawCredentialData, + IssueCredentialRecord.ProtocolState.CredentialReceived + ) + svc <- ZIO.service[PresentationService] + connectionId = Some("connectionId") + anoncredPresentationRequestV1 = AnoncredPresentationRequestV1( + Map.empty, + Map.empty, + "name", + "nonce", + "version", + None + ) + attachmentDescriptor = AttachmentDescriptor.buildBase64Attachment( + mediaType = Some("application/json"), + format = Some(PresentCredentialRequestFormat.Anoncred.name), + payload = AnoncredPresentationRequestV1.schemaSerDes.serialize(anoncredPresentationRequestV1).getBytes() + ) + requestPresentation = RequestPresentation( + body = RequestPresentation.Body(goal_code = Some("Presentation Request")), + attachments = Seq(attachmentDescriptor), + to = DidId("did:peer:Prover"), + from = DidId("did:peer:Verifier"), + ) + aRecord <- svc.receiveRequestPresentation(connectionId, requestPresentation) + credentialsToUse = Seq(aIssueCredentialRecord.id.value) + result <- svc.acceptRequestPresentation(aRecord.id, credentialsToUse).exit + + } yield assert(result)( + fails(isSubtype[NotMatchingPresentationCredentialFormat](anything)) + ) + }, + test("rejectRequestPresentation updates the PresentationRecord") { for { svc <- ZIO.service[PresentationService] connectionId = Some("connectionId") - aRecord <- svc.receiveRequestPresentation(connectionId, requestPresentationJWT) + aRecord <- svc.receiveRequestPresentation( + connectionId, + requestPresentation(PresentCredentialRequestFormat.JWT) + ) updateRecord <- svc.rejectRequestPresentation(aRecord.id) } yield { @@ -500,7 +592,7 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp assertTrue(record.protocolState == PresentationRecord.ProtocolState.PresentationSent) } }, - test("receivePresentation updates the PresentatinRecord") { + test("receivePresentation updates the PresentationRecord") { for { svc <- ZIO.service[PresentationService] aRecord <- svc.createJwtRecord() @@ -512,7 +604,7 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp assertTrue(aRecordReceived.presentationData == Some(p)) } }, - test("acceptPresentation updates the PresentatinRecord") { + test("acceptPresentation updates the PresentationRecord") { for { svc <- ZIO.service[PresentationService] aRecord <- svc.createJwtRecord() @@ -530,7 +622,7 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp assertTrue(aRecordReceived.presentationData == Some(p)) } }, - test("markPresentationRejected updates the PresentatinRecord") { + test("markPresentationRejected updates the PresentationRecord") { for { svc <- ZIO.service[PresentationService] aRecord <- svc.createJwtRecord() @@ -549,7 +641,7 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp assertTrue(aRecordReject.protocolState == PresentationRecord.ProtocolState.PresentationRejected) } }, - test("rejectPresentation updates the PresentatinRecord") { + test("rejectPresentation updates the PresentationRecord") { for { svc <- ZIO.service[PresentationService] aRecord <- svc.createJwtRecord() @@ -601,7 +693,7 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp assertTrue(record.protocolState == PresentationRecord.ProtocolState.ProposalSent) } }, - test("receiveProposePresentation updates the PresentatinRecord") { + test("receiveProposePresentation updates the PresentationRecord") { for { svc <- ZIO.service[PresentationService] aRecord <- svc.createJwtRecord() @@ -612,7 +704,7 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp assertTrue(aRecordReceived.proposePresentationData == Some(p)) } }, - test("acceptProposePresentation updates the PresentatinRecord") { + test("acceptProposePresentation updates the PresentationRecord") { for { svc <- ZIO.service[PresentationService] aRecord <- svc.createJwtRecord() diff --git a/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceSpecHelper.scala b/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceSpecHelper.scala index a6ce5b0ba7..e3456f5fca 100644 --- a/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceSpecHelper.scala +++ b/pollux/lib/core/src/test/scala/io/iohk/atala/pollux/core/service/PresentationServiceSpecHelper.scala @@ -53,7 +53,7 @@ trait PresentationServiceSpecHelper { attachments = Nil ) - protected def requestPresentationJWT: RequestPresentation = { + protected def requestPresentation(credentialFormat: PresentCredentialRequestFormat): RequestPresentation = { val body = RequestPresentation.Body(goal_code = Some("Presentation Request")) val presentationAttachmentAsJson = """{ @@ -66,7 +66,7 @@ trait PresentationServiceSpecHelper { val attachmentDescriptor = AttachmentDescriptor.buildJsonAttachment( payload = presentationAttachmentAsJson, - format = Some(PresentCredentialRequestFormat.JWT.name) + format = Some(credentialFormat.name) ) RequestPresentation( body = body, @@ -116,14 +116,14 @@ trait PresentationServiceSpecHelper { ) } - protected def issueCredentialRecord = IssueCredentialRecord( + protected def issueCredentialRecord(credentialFormat: CredentialFormat) = IssueCredentialRecord( id = DidCommID(), createdAt = Instant.now, updatedAt = None, thid = DidCommID(), schemaId = None, credentialDefinitionId = None, - credentialFormat = CredentialFormat.JWT, + credentialFormat = credentialFormat, role = IssueCredentialRecord.Role.Issuer, subjectId = None, validityPeriod = None, diff --git a/pollux/lib/sql-doobie/src/main/scala/io/iohk/atala/pollux/sql/repository/JdbcCredentialRepository.scala b/pollux/lib/sql-doobie/src/main/scala/io/iohk/atala/pollux/sql/repository/JdbcCredentialRepository.scala index 24cbdb5113..dd7b5d5319 100644 --- a/pollux/lib/sql-doobie/src/main/scala/io/iohk/atala/pollux/sql/repository/JdbcCredentialRepository.scala +++ b/pollux/lib/sql-doobie/src/main/scala/io/iohk/atala/pollux/sql/repository/JdbcCredentialRepository.scala @@ -433,6 +433,7 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ | SELECT | id, | issued_credential_raw, + | credential_format, | subject_id | FROM public.issue_credential_records | WHERE