From 4a6a659040ea8cc2bc0c23dcd77cb5adc6e13eea Mon Sep 17 00:00:00 2001 From: Bassam Riman Date: Tue, 24 Sep 2024 10:51:27 -0400 Subject: [PATCH] ATL-7663-CredentialStatus-List-Support Signed-off-by: Bassam Riman --- .../vc/jwt/VerifiableCredentialPayload.scala | 6 ++-- .../pollux/vc/jwt/JWTVerificationTest.scala | 32 +++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/VerifiableCredentialPayload.scala b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/VerifiableCredentialPayload.scala index bf5d4f9560..efc3566707 100644 --- a/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/VerifiableCredentialPayload.scala +++ b/pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/VerifiableCredentialPayload.scala @@ -240,7 +240,7 @@ object CredentialPayload { ) implicit val credentialStatusOrListEncoder: Encoder[CredentialStatus | List[CredentialStatus]] = Encoder.instance { - case status: CredentialStatus => Encoder[CredentialStatus].apply(status) + case status: CredentialStatus => Encoder[CredentialStatus].apply(status) case statusList: List[CredentialStatus] => Encoder[List[CredentialStatus]].apply(statusList) } @@ -414,7 +414,7 @@ object CredentialPayload { .downField("credentialSchema") .as[Option[CredentialSchema | List[CredentialSchema]]] credentialSubject <- c.downField("credentialSubject").as[Json] - maybeCredentialStatus <- c.downField("credentialStatus").as[Option[CredentialStatus]] + maybeCredentialStatus <- c.downField("credentialStatus").as[Option[CredentialStatus | List[CredentialStatus]]] maybeRefreshService <- c.downField("refreshService").as[Option[RefreshService]] maybeEvidence <- c.downField("evidence").as[Option[Json]] maybeTermsOfUse <- c.downField("termsOfUse").as[Option[Json]] @@ -453,7 +453,7 @@ object CredentialPayload { .downField("credentialSchema") .as[Option[CredentialSchema | List[CredentialSchema]]] credentialSubject <- c.downField("credentialSubject").as[Json] - maybeCredentialStatus <- c.downField("credentialStatus").as[Option[CredentialStatus]] + maybeCredentialStatus <- c.downField("credentialStatus").as[Option[CredentialStatus | List[CredentialStatus]]] maybeRefreshService <- c.downField("refreshService").as[Option[RefreshService]] maybeEvidence <- c.downField("evidence").as[Option[Json]] maybeTermsOfUse <- c.downField("termsOfUse").as[Option[Json]] diff --git a/pollux/vc-jwt/src/test/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerificationTest.scala b/pollux/vc-jwt/src/test/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerificationTest.scala index e09f9e6e96..d0976cea09 100644 --- a/pollux/vc-jwt/src/test/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerificationTest.scala +++ b/pollux/vc-jwt/src/test/scala/org/hyperledger/identus/pollux/vc/jwt/JWTVerificationTest.scala @@ -7,6 +7,7 @@ import io.circe.* import io.circe.syntax.* import org.hyperledger.identus.castor.core.model.did.{DID, VerificationRelationship} import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* +import org.hyperledger.identus.pollux.vc.jwt.StatusPurpose.Revocation import org.hyperledger.identus.shared.http.* import zio.* import zio.prelude.Validation @@ -62,7 +63,11 @@ object JWTVerificationTest extends ZIOSpecDefault { |} |""".stripMargin - private def createJwtCredential(issuer: IssuerWithKey, issuerAsObject: Boolean = false): JWT = { + private def createJwtCredential( + issuer: IssuerWithKey, + issuerAsObject: Boolean = false, + credentialStatus: Option[CredentialStatus | List[CredentialStatus]] = None + ): JWT = { val validFrom = Instant.parse("2010-01-05T00:00:00Z") // ISSUANCE DATE val jwtCredentialNbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE val validUntil = Instant.parse("2010-01-09T00:00:00Z") // EXPIRATION DATE @@ -75,7 +80,7 @@ object JWTVerificationTest extends ZIOSpecDefault { `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), maybeCredentialSchema = None, credentialSubject = Json.obj("id" -> Json.fromString("1")), - maybeCredentialStatus = None, + maybeCredentialStatus = credentialStatus, maybeRefreshService = None, maybeEvidence = None, maybeTermsOfUse = None, @@ -223,6 +228,29 @@ object JWTVerificationTest extends ZIOSpecDefault { jwtWithObjectIssuerIssuer.equals(jwtIssuer) ) }, + test("validate credential status list") { + val issuer = createUser("did:prism:issuer") + val status = CredentialStatus(id = "id", `type` = "type", statusPurpose = Revocation, 1, "1") + val encodedJwtWithStatusList = createJwtCredential( + issuer, + false, + Some(List(status)) + ) + val econdedJwtWithStatusObject = createJwtCredential(issuer, true, Some(status)) + for { + decodeJwtWithStatusList <- JwtCredential + .decodeJwt(encodedJwtWithStatusList) + decodeJwtWithStatusObject <- JwtCredential + .decodeJwt(econdedJwtWithStatusObject) + statusFromList = decodeJwtWithStatusList.vc.maybeCredentialStatus.map { + case list: List[CredentialStatus] => list.head + case _: CredentialStatus => throw new IllegalStateException("List expected") + }.get + statusFromObjet = decodeJwtWithStatusObject.vc.maybeCredentialStatus.get + } yield assertTrue( + statusFromList.equals(statusFromObjet) + ) + }, test("validate dates should fail given after valid until") { val issuer = createUser("did:prism:issuer") val jwtCredential = createJwtCredential(issuer)