Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: migrate pollux VC JWT from Circe to zio-json #1475

Merged
merged 7 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 7 additions & 38 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ inThisBuild(
// scalacOptions += "-Ysafe-init",
// scalacOptions += "-Werror", // <=> "-Xfatal-warnings"
scalacOptions += "-Dquill.macro.log=false", // disable quill macro logs // TODO https://github.com/zio/zio-protoquill/issues/470,
scalacOptions ++= Seq("-Xmax-inlines", "50") // manually increase max-inlines above 32 (https://github.com/circe/circe/issues/2162)
scalacOptions ++= Seq("-Xmax-inlines", "50")
)
)

Expand All @@ -58,9 +58,6 @@ lazy val V = new {
val mockito = "3.2.18.0"
val monocle = "3.2.0"

// https://mvnrepository.com/artifact/io.circe/circe-core
val circe = "0.14.7"

val tapir = "1.11.7" // scala-steward:off // TODO "1.10.5"
val http4sBlaze = "0.23.15" // scala-steward:off // TODO "0.23.16"

Expand All @@ -80,7 +77,7 @@ lazy val V = new {

val scalaUri = "4.0.3"

val jwtCirceVersion = "9.4.6"
val jwtZioVersion = "9.4.6"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥇

val zioPreludeVersion = "1.0.0-RC31"

val apollo = "1.3.5"
Expand Down Expand Up @@ -123,12 +120,8 @@ lazy val D = new {
val zioConfigMagnolia: ModuleID = "dev.zio" %% "zio-config-magnolia" % V.zioConfig
val zioConfigTypesafe: ModuleID = "dev.zio" %% "zio-config-typesafe" % V.zioConfig

val circeCore: ModuleID = "io.circe" %% "circe-core" % V.circe
val circeGeneric: ModuleID = "io.circe" %% "circe-generic" % V.circe
val circeParser: ModuleID = "io.circe" %% "circe-parser" % V.circe

val networkntJsonSchemaValidator = "com.networknt" % "json-schema-validator" % V.jsonSchemaValidator
val jwtCirce = "com.github.jwt-scala" %% "jwt-circe" % V.jwtCirceVersion
val jwtZio = "com.github.jwt-scala" %% "jwt-zio-json" % V.jwtZioVersion
val jsonCanonicalization: ModuleID = "io.github.erdtman" % "java-json-canonicalization" % "1.1"
val titaniumJsonLd: ModuleID = "com.apicatalog" % "titanium-json-ld" % "1.4.0"
val jakartaJson: ModuleID = "org.glassfish" % "jakarta.json" % "2.0.1"
Expand Down Expand Up @@ -156,7 +149,6 @@ lazy val D = new {
"com.github.dasniko" % "testcontainers-keycloak" % V.testContainersJavaKeycloak % Test

val doobiePostgres: ModuleID = "org.tpolecat" %% "doobie-postgres" % V.doobie
val doobiePostgresCirce: ModuleID = "org.tpolecat" %% "doobie-postgres-circe" % V.doobie
val doobieHikari: ModuleID = "org.tpolecat" %% "doobie-hikari" % V.doobie
val flyway: ModuleID = "org.flywaydb" % "flyway-core" % V.flyway

Expand Down Expand Up @@ -185,7 +177,7 @@ lazy val D = new {

// LIST of Dependencies
val doobieDependencies: Seq[ModuleID] =
Seq(doobiePostgres, doobiePostgresCirce, doobieHikari, flyway)
Seq(doobiePostgres, doobieHikari, flyway)
}

lazy val D_Shared = new {
Expand All @@ -210,9 +202,6 @@ lazy val D_SharedJson = new {
Seq(
D.zio,
D.zioJson,
D.circeCore,
D.circeGeneric,
D.circeParser,
D.jsonCanonicalization,
D.titaniumJsonLd,
D.jakartaJson,
Expand Down Expand Up @@ -274,9 +263,6 @@ lazy val D_Castor = new {
D.zioMock,
D.zioTestSbt,
D.zioTestMagnolia,
D.circeCore,
D.circeGeneric,
D.circeParser
)

// Project Dependencies
Expand Down Expand Up @@ -343,7 +329,7 @@ lazy val D_Pollux_VC_JWT = new {
// Dependency Modules
val zioDependencies: Seq[ModuleID] = Seq(zio, zioPrelude, zioTest, zioTestSbt, zioTestMagnolia)
val baseDependencies: Seq[ModuleID] =
zioDependencies :+ D.jwtCirce :+ D.networkntJsonSchemaValidator :+ D.nimbusJwt :+ D.scalaTest
zioDependencies :+ D.jwtZio :+ D.networkntJsonSchemaValidator :+ D.nimbusJwt :+ D.scalaTest

// Project Dependencies
lazy val polluxVcJwtDependencies: Seq[ModuleID] = baseDependencies
Expand Down Expand Up @@ -426,7 +412,7 @@ lazy val D_CloudAgent = new {
lazy val keyManagementDependencies: Seq[ModuleID] =
baseDependencies ++ D.doobieDependencies ++ Seq(D.zioCatsInterop, D.zioMock, vaultDriver)

lazy val iamDependencies: Seq[ModuleID] = Seq(keycloakAuthz, D.jwtCirce)
lazy val iamDependencies: Seq[ModuleID] = Seq(keycloakAuthz, D.jwtZio)

lazy val serverDependencies: Seq[ModuleID] =
baseDependencies ++ tapirDependencies ++ postgresDependencies ++ Seq(
Expand Down Expand Up @@ -533,13 +519,7 @@ lazy val models = project
.configure(commonConfigure)
.settings(name := "mercury-data-models")
.settings(
libraryDependencies ++= Seq(D.zio),
libraryDependencies ++= Seq(
D.circeCore,
D.circeGeneric,
D.circeParser
), // TODO try to remove this from this module
// libraryDependencies += D.didScala
libraryDependencies ++= Seq(D.zio)
)
.settings(libraryDependencies += D.nimbusJwt) // FIXME just for the DidAgent
.dependsOn(shared)
Expand All @@ -561,7 +541,6 @@ lazy val protocolConnection = project
.configure(commonConfigure)
.settings(name := "mercury-protocol-connection")
.settings(libraryDependencies += D.zio)
.settings(libraryDependencies ++= Seq(D.circeCore, D.circeGeneric, D.circeParser))
.settings(libraryDependencies += D.munitZio)
.dependsOn(models, protocolInvitation)

Expand All @@ -570,7 +549,6 @@ lazy val protocolCoordinateMediation = project
.configure(commonConfigure)
.settings(name := "mercury-protocol-coordinate-mediation")
.settings(libraryDependencies += D.zio)
.settings(libraryDependencies ++= Seq(D.circeCore, D.circeGeneric, D.circeParser))
.settings(libraryDependencies += D.munitZio)
.dependsOn(models)

Expand All @@ -579,7 +557,6 @@ lazy val protocolDidExchange = project
.configure(commonConfigure)
.settings(name := "mercury-protocol-did-exchange")
.settings(libraryDependencies += D.zio)
.settings(libraryDependencies ++= Seq(D.circeCore, D.circeGeneric, D.circeParser))
.dependsOn(models, protocolInvitation)

lazy val protocolInvitation = project
Expand All @@ -589,9 +566,6 @@ lazy val protocolInvitation = project
.settings(libraryDependencies += D.zio)
.settings(
libraryDependencies ++= Seq(
D.circeCore,
D.circeGeneric,
D.circeParser,
D.munit,
D.munitZio
)
Expand All @@ -611,7 +585,6 @@ lazy val protocolLogin = project
.settings(name := "mercury-protocol-outofband-login")
.settings(libraryDependencies += D.zio)
.settings(libraryDependencies += D.zio)
.settings(libraryDependencies ++= Seq(D.circeCore, D.circeGeneric, D.circeParser))
.settings(libraryDependencies += D.munitZio)
.dependsOn(models)

Expand All @@ -634,7 +607,6 @@ lazy val protocolIssueCredential = project
.configure(commonConfigure)
.settings(name := "mercury-protocol-issue-credential")
.settings(libraryDependencies += D.zio)
.settings(libraryDependencies ++= Seq(D.circeCore, D.circeGeneric, D.circeParser))
.settings(libraryDependencies += D.munitZio)
.dependsOn(models, protocolInvitation)

Expand All @@ -643,7 +615,6 @@ lazy val protocolRevocationNotification = project
.configure(commonConfigure)
.settings(name := "mercury-protocol-revocation-notification")
.settings(libraryDependencies += D.zio)
.settings(libraryDependencies ++= Seq(D.circeCore, D.circeGeneric, D.circeParser))
.settings(libraryDependencies += D.munitZio)
.dependsOn(models)

Expand All @@ -652,7 +623,6 @@ lazy val protocolPresentProof = project
.configure(commonConfigure)
.settings(name := "mercury-protocol-present-proof")
.settings(libraryDependencies += D.zio)
.settings(libraryDependencies ++= Seq(D.circeCore, D.circeGeneric, D.circeParser))
.settings(libraryDependencies += D.munitZio)
.dependsOn(models, protocolInvitation)

Expand All @@ -667,7 +637,6 @@ lazy val protocolTrustPing = project
.configure(commonConfigure)
.settings(name := "mercury-protocol-trust-ping")
.settings(libraryDependencies += D.zio)
.settings(libraryDependencies ++= Seq(D.circeCore, D.circeGeneric, D.circeParser))
.settings(libraryDependencies += D.munitZio)
.dependsOn(models)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ import org.hyperledger.identus.pollux.core.model.{CredInStatusList, CredentialSt
import org.hyperledger.identus.pollux.core.service.{CredentialService, CredentialStatusListService}
import org.hyperledger.identus.pollux.vc.jwt.revocation.{BitString, VCStatusList2021, VCStatusList2021Error}
import org.hyperledger.identus.resolvers.DIDResolver
import org.hyperledger.identus.shared.json.JsonInterop
import org.hyperledger.identus.shared.messaging
import org.hyperledger.identus.shared.messaging.{Message, Producer, WalletIdAndRecordId}
import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId}
import org.hyperledger.identus.shared.utils.DurationOps.toMetricsSeconds
import zio.*
import zio.json.{DecoderOps, EncoderOps}
import zio.json.ast.Json
import zio.json.DecoderOps
import zio.metrics.Metric

import java.util.UUID
Expand Down Expand Up @@ -78,7 +77,7 @@ object StatusListJobs extends BackgroundJobsHelper {
vcStatusListCredJson <- ZIO.fromEither(vcStatusListCredString.fromJson[Json])
issuer <- createJwtVcIssuer(statusListWithCreds.issuer, VerificationRelationship.AssertionMethod, None)
vcStatusListCred <- VCStatusList2021
.decodeFromJson(JsonInterop.toCirceJsonAst(vcStatusListCredJson), issuer)
.decodeFromJson(vcStatusListCredJson, issuer)
.mapError(x => new Throwable(x.msg))
bitString <- vcStatusListCred.getBitString.mapError(x => new Throwable(x.msg))
_ <- ZIO.collectAll(
Expand All @@ -99,7 +98,7 @@ object StatusListJobs extends BackgroundJobsHelper {
case VCStatusList2021Error.EncodingError(msg: String) => new Throwable(msg)
case VCStatusList2021Error.DecodingError(msg: String) => new Throwable(msg)
}
vcStatusListCredJsonString <- updatedVcStatusListCred.toJsonWithEmbeddedProof.map(_.spaces2)
vcStatusListCredJsonString <- updatedVcStatusListCred.toJsonWithEmbeddedProof.map(_.toJson)
_ <- credentialStatusListService.updateStatusListCredential(
statusListWithCreds.id,
vcStatusListCredJsonString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.hyperledger.identus.iam.authentication.AuthenticationError.{
InvalidCredentials
}
import org.hyperledger.identus.shared.utils.Traverse.*
import pdi.jwt.{JwtCirce, JwtClaim, JwtOptions}
import pdi.jwt.{JwtClaim, JwtOptions, JwtZIOJson}
import zio.*
import zio.json.ast.Json

Expand Down Expand Up @@ -61,7 +61,7 @@ final class AccessToken private (token: String, claims: JwtClaim, rolesClaimPath

object AccessToken {
def fromString(token: String, rolesClaimPath: Seq[String] = Nil): Either[String, AccessToken] =
JwtCirce
JwtZIOJson
.decode(token, JwtOptions(false, false, false))
.map(claims => AccessToken(token, claims, rolesClaimPath))
.toEither
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import org.hyperledger.identus.castor.core.model.did.{DID, DIDUrl, PrismDID, Ver
import org.hyperledger.identus.oid4vci.domain.{IssuanceSession, Openid4VCIProofJwtOps}
import org.hyperledger.identus.oid4vci.http.*
import org.hyperledger.identus.oid4vci.storage.IssuanceSessionStorage
import org.hyperledger.identus.pollux.core.model.primitives.UriString
import org.hyperledger.identus.pollux.core.model.primitives.UriString.toUriString
import org.hyperledger.identus.pollux.core.model.schema.CredentialSchema
import org.hyperledger.identus.pollux.core.service.{
Expand All @@ -23,7 +22,6 @@ import org.hyperledger.identus.pollux.vc.jwt.{
*
}
import org.hyperledger.identus.shared.http.UriResolver
import org.hyperledger.identus.shared.json.JsonInterop
import org.hyperledger.identus.shared.models.*
import zio.*
import zio.json.ast.Json
Expand Down Expand Up @@ -206,7 +204,7 @@ case class OIDCCredentialIssuerServiceImpl(
issuanceDate = Instant.now(),
maybeExpirationDate = None, // TODO: Add expiration date
maybeCredentialSchema = None, // TODO: Add schema from schema registry
credentialSubject = JsonInterop.toCirceJsonAst(buildCredentialSubject(subjectDid, claims)),
credentialSubject = buildCredentialSubject(subjectDid, claims),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

maybeCredentialStatus = None, // TODO: Add credential status
maybeRefreshService = None, // TODO: Add refresh service
maybeEvidence = None, // TODO: Add evidence
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import org.hyperledger.identus.api.http.ErrorResponse
import org.hyperledger.identus.castor.core.model.did.{DIDData, DIDMetadata, PrismDIDOperation, VerificationRelationship}
import org.hyperledger.identus.castor.core.service.MockDIDService
import org.hyperledger.identus.connect.core.model.ConnectionRecord
import org.hyperledger.identus.connect.core.model.ConnectionRecord.ProtocolState
import org.hyperledger.identus.connect.core.service
import org.hyperledger.identus.connect.core.service.MockConnectionService
import org.hyperledger.identus.container.util.MigrationAspects.migrate
import org.hyperledger.identus.iam.authentication.AuthenticatorWithAuthZ
Expand All @@ -21,16 +19,16 @@ import org.hyperledger.identus.mercury.model.DidId
import org.hyperledger.identus.mercury.protocol.connection.ConnectionResponse
import org.hyperledger.identus.mercury.protocol.invitation.v2.Invitation
import org.hyperledger.identus.pollux.core.model.{CredentialFormat, DidCommID, IssueCredentialRecord}
import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.{ProtocolState, Role}
import org.hyperledger.identus.pollux.core.repository.CredentialDefinitionRepositoryInMemory
import org.hyperledger.identus.pollux.core.service.{CredentialDefinitionServiceImpl, MockCredentialService}
import org.hyperledger.identus.pollux.core.service.uriResolvers.ResourceUrlResolver
import org.hyperledger.identus.shared.models.{KeyId, WalletId}
import sttp.client3.{basicRequest, DeserializationException, UriContext}
import sttp.client3.{basicRequest, UriContext}
import sttp.client3.ziojson.*
import sttp.model.StatusCode
import zio.*
import zio.json.EncoderOps
import zio.json.{DecoderOps, EncoderOps}
import zio.json.ast.Json
import zio.mock.Expectation
import zio.test.*
import zio.test.Assertion.*
Expand All @@ -54,7 +52,7 @@ object IssueControllerImplSpec extends ZIOSpecDefault with IssueControllerTestTo
schemaId = Some("mySchemaId"),
credentialDefinitionId = Some(UUID.fromString("123e4567-e89b-12d3-a456-426614174000")),
credentialFormat = Some("JWT"),
claims = json.toJsonAST.toOption.get,
claims = json.fromJson[Json].toOption.get,
automaticIssuance = Some(true),
issuingDID =
"did:prism:332518729a7b7805f73a788e0944802527911901d9b7c16152281be9bc62d944:CosBCogBEkkKFW15LWtleS1hdXRoZW50aWNhdGlvbhAESi4KCXNlY3AyNTZrMRIhAuYoRIefsLhkvYwHz8gDtkG2b0kaZTDOLj_SExWX1fOXEjsKB21hc3RlcjAQAUouCglzZWNwMjU2azESIQLOzab8f0ibt1P0zdMfoWDQTSlPc8_tkV9Jk5BBsXB8fA",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package org.hyperledger.identus.verification.controller

import org.hyperledger.identus.agent.walletapi.model.BaseEntity
import org.hyperledger.identus.agent.walletapi.service.{ManagedDIDService, MockManagedDIDService}
import org.hyperledger.identus.agent.walletapi.service.MockManagedDIDService
import org.hyperledger.identus.castor.core.service.MockDIDService
import org.hyperledger.identus.iam.authentication.AuthenticatorWithAuthZ
import org.hyperledger.identus.pollux.vc.jwt.*
import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.*
import org.hyperledger.identus.shared.json.JsonInterop
import org.hyperledger.identus.verification.controller.http.*
import sttp.client3.{basicRequest, DeserializationException, Response, UriContext}
import sttp.client3.ziojson.*
Expand Down Expand Up @@ -47,12 +45,10 @@ object VcVerificationControllerImplSpec extends ZIOSpecDefault with VcVerificati
`type` = "JsonSchemaValidator2018"
)
),
credentialSubject = JsonInterop.toCirceJsonAst(
Json.Obj(
"userName" -> Json.Str("Bob"),
"age" -> Json.Num(42),
"email" -> Json.Str("email")
)
credentialSubject = Json.Obj(
"userName" -> Json.Str("Bob"),
"age" -> Json.Num(42),
"email" -> Json.Str("email")
),
maybeCredentialStatus = Some(
CredentialStatus(
Expand All @@ -73,7 +69,7 @@ object VcVerificationControllerImplSpec extends ZIOSpecDefault with VcVerificati
maybeTermsOfUse = Option.empty,
aud = Set(verifier)
).toJwtCredentialPayload
signedJwtCredential = issuer.signer.encode(io.circe.syntax.EncoderOps(jwtCredentialPayload).asJson)
signedJwtCredential = issuer.signer.encode(jwtCredentialPayload.toJsonAST.toOption.get)
authenticator <- ZIO.service[AuthenticatorWithAuthZ[BaseEntity]]
backend = httpBackend(vcVerificationController, authenticator)
request = List(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.hyperledger.identus.pollux.vc.jwt.revocation.BitStringError.{
import org.hyperledger.identus.pollux.vc.jwt.Issuer
import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId}
import zio.*
import zio.json.EncoderOps

import java.util.UUID

Expand All @@ -36,7 +37,7 @@ trait CredentialStatusListRepository {
.mapError(x => new Throwable(x.msg))

credentialWithEmbeddedProof <- emptyStatusListCredential.toJsonWithEmbeddedProof
} yield credentialWithEmbeddedProof.spaces2
} yield credentialWithEmbeddedProof.toJson
}

def getCredentialStatusListIds: UIO[Seq[(WalletId, UUID)]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ import org.hyperledger.identus.pollux.core.repository.{CredentialRepository, Cre
import org.hyperledger.identus.pollux.prex.{ClaimFormat, Jwt, PresentationDefinition}
import org.hyperledger.identus.pollux.sdjwt.*
import org.hyperledger.identus.pollux.vc.jwt.{Issuer as JwtIssuer, *}
import org.hyperledger.identus.pollux.vc.jwt.PresentationPayload.Implicits.*
import org.hyperledger.identus.shared.crypto.{Ed25519KeyPair, Secp256k1KeyPair}
import org.hyperledger.identus.shared.http.UriResolver
import org.hyperledger.identus.shared.json.JsonInterop
import org.hyperledger.identus.shared.messaging.{Producer, WalletIdAndRecordId}
import org.hyperledger.identus.shared.models.*
import org.hyperledger.identus.shared.models.Failure.orDieAsUnmanagedFailure
Expand Down Expand Up @@ -1219,7 +1217,7 @@ class CredentialServiceImpl(
ids.map(id => org.hyperledger.identus.pollux.vc.jwt.CredentialSchema(id, VC_JSON_SCHEMA_TYPE))
),
maybeCredentialStatus = Some(credentialStatus),
credentialSubject = JsonInterop.toCirceJsonAst(claims.add("id", Json.Str(jwtPresentation.iss))),
credentialSubject = claims.add("id", Json.Str(jwtPresentation.iss)),
maybeRefreshService = None,
maybeEvidence = None,
maybeTermsOfUse = None,
Expand Down Expand Up @@ -1455,7 +1453,7 @@ class CredentialServiceImpl(
.fromOption(offer.attachments.headOption)
.orElse(ZIO.dieMessage(s"Attachments not found in record: ${record.id}"))
json <- attachmentDescriptor.data match
case JsonData(json) => ZIO.succeed(json.toJsonAST.toOption.get)
case JsonData(json) => ZIO.succeed(json)
case _ => ZIO.dieMessage(s"Attachment doesn't contain JsonData: ${record.id}")
maybeOptions <- ZIO
.fromEither(json.as[PresentationAttachment].map(_.options))
Expand Down
Loading
Loading