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 b22ab43ff0..69cfc710bf 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 @@ -11,13 +11,7 @@ import org.hyperledger.identus.api.util.PaginationUtils import org.hyperledger.identus.castor.core.model.did.{DIDUrl, PrismDID, VerificationRelationship} import org.hyperledger.identus.castor.core.service.DIDService import org.hyperledger.identus.connect.core.service.ConnectionService -import org.hyperledger.identus.issue.controller.http.{ - AcceptCredentialOfferInvitation, - AcceptCredentialOfferRequest, - CreateIssueCredentialRecordRequest, - IssueCredentialRecord, - IssueCredentialRecordPage -} +import org.hyperledger.identus.issue.controller.http.* import org.hyperledger.identus.mercury.model.DidId import org.hyperledger.identus.pollux.core.model.{CredentialFormat, DidCommID, ResourceResolutionMethod} import org.hyperledger.identus.pollux.core.model.CredentialFormat.{AnonCreds, JWT, SDJWT} @@ -77,7 +71,10 @@ class IssueControllerImpl( pairwiseHolderDID = offerContext.pairwiseHolderDID, kidIssuer = request.issuingKid, thid = DidCommID(), - maybeSchemaId = request.schemaId, + maybeSchemaIds = request.schemaId.map { + case schemaId: String => List(schemaId) + case schemaIds: List[String] => schemaIds + }, claims = jsonClaims, validityPeriod = request.validityPeriod, automaticIssuance = request.automaticIssuance.orElse(Some(true)), @@ -98,7 +95,10 @@ class IssueControllerImpl( pairwiseHolderDID = offerContext.pairwiseHolderDID, kidIssuer = request.issuingKid, thid = DidCommID(), - maybeSchemaId = request.schemaId, + maybeSchemaIds = request.schemaId.map { + case schemaId: String => List(schemaId) + case schemaIds: List[String] => schemaIds + }, claims = jsonClaims, validityPeriod = request.validityPeriod, automaticIssuance = request.automaticIssuance.orElse(Some(true)), @@ -121,7 +121,7 @@ class IssueControllerImpl( credentialDefinitionId <- { credentialDefinition.resolutionMethod match - case ResourceResolutionMethod.`did` => + case ResourceResolutionMethod.did => val publicEndpointServiceName = appConfig.agent.httpEndpoint.serviceName val didUrlResourcePath = s"credential-definition-registry/definitions/did-url/${credentialDefinitionGUID.toString}/definition" @@ -146,7 +146,7 @@ class IssueControllerImpl( .fromEither(didUrl) .mapError(_ => ErrorResponse.badRequest(detail = Some("Could not parse credential definition"))) - case ResourceResolutionMethod.`http` => + case ResourceResolutionMethod.http => val publicEndpointUrl = appConfig.agent.httpEndpoint.publicEndpointUrl.toExternalForm val httpUrlSuffix = s"credential-definition-registry/definitions/${credentialDefinitionGUID.toString}/definition" diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/CreateIssueCredentialRecordRequest.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/CreateIssueCredentialRecordRequest.scala index 279a4cb46d..5c530b194d 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/CreateIssueCredentialRecordRequest.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/issue/controller/http/CreateIssueCredentialRecordRequest.scala @@ -9,6 +9,7 @@ import sttp.tapir.Schema.annotations.{description, encodedExample} import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} import java.util.UUID +import scala.language.implicitConversions /** A class to represent an incoming request to create a new credential offer. * @@ -33,7 +34,7 @@ final case class CreateIssueCredentialRecordRequest( validityPeriod: Option[Double] = None, @description(annotations.schemaId.description) @encodedExample(annotations.schemaId.example) - schemaId: Option[String], + schemaId: Option[String | List[String]] = None, @description(annotations.credentialDefinitionId.description) @encodedExample(annotations.credentialDefinitionId.example) credentialDefinitionId: Option[UUID], @@ -177,6 +178,19 @@ object CreateIssueCredentialRecordRequest { ) } + given schemaIdEncoder: JsonEncoder[String | List[String]] = + JsonEncoder[String] + .orElseEither(JsonEncoder[List[String]]) + .contramap[String | List[String]] { + case schemaId: String => Left(schemaId) + case schemaIds: List[String] => Right(schemaIds) + } + + given schemaIdDecoder: JsonDecoder[String | List[String]] = + JsonDecoder[List[String]] + .map(schemaId => schemaId: String | List[String]) + .orElse(JsonDecoder[String].map(schemaId => schemaId: String | List[String])) + given encoder: JsonEncoder[CreateIssueCredentialRecordRequest] = DeriveJsonEncoder.gen[CreateIssueCredentialRecordRequest] @@ -184,6 +198,17 @@ object CreateIssueCredentialRecordRequest { DeriveJsonDecoder.gen[CreateIssueCredentialRecordRequest] given schemaJson: Schema[KeyId] = Schema.schemaForString.map[KeyId](v => Some(KeyId(v)))(KeyId.value) + + given schemaId: Schema[String | List[String]] = Schema + .schemaForEither(Schema.schemaForString, Schema.schemaForArray[String]) + .map[String | List[String]] { + case Left(value) => Some(value) + case Right(values) => Some(values.toList) + } { + case value: String => Left(value) + case values: List[String] => Right(values.toArray) + } + given schema: Schema[CreateIssueCredentialRecordRequest] = Schema.derived } diff --git a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/verification/controller/VcVerificationControllerImplSpec.scala b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/verification/controller/VcVerificationControllerImplSpec.scala index 210390472c..2e75ce25a2 100644 --- a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/verification/controller/VcVerificationControllerImplSpec.scala +++ b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/verification/controller/VcVerificationControllerImplSpec.scala @@ -42,11 +42,9 @@ object VcVerificationControllerImplSpec extends ZIOSpecDefault with VcVerificati maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( diff --git a/mercury/protocol-issue-credential/src/main/scala/org/hyperledger/identus/mercury/protocol/issuecredential/CredentialPreview.scala b/mercury/protocol-issue-credential/src/main/scala/org/hyperledger/identus/mercury/protocol/issuecredential/CredentialPreview.scala index 9997acdaf1..4351ca6367 100644 --- a/mercury/protocol-issue-credential/src/main/scala/org/hyperledger/identus/mercury/protocol/issuecredential/CredentialPreview.scala +++ b/mercury/protocol-issue-credential/src/main/scala/org/hyperledger/identus/mercury/protocol/issuecredential/CredentialPreview.scala @@ -27,14 +27,20 @@ import io.circe.generic.semiauto.* */ final case class CredentialPreview( `type`: String = "https://didcomm.org/issue-credential/3.0/credential-credential", + schema_ids: Option[List[String]] = None, schema_id: Option[String] = None, body: CredentialPreviewBody, ) object CredentialPreview { def apply(attributes: Seq[Attribute]) = new CredentialPreview(body = CredentialPreviewBody(attributes)) - def apply(schema_id: Option[String], attributes: Seq[Attribute]) = - new CredentialPreview(schema_id = schema_id, body = CredentialPreviewBody(attributes)) + def apply(schema_ids: Option[List[String]], attributes: Seq[Attribute]) = + new CredentialPreview( + schema_ids = schema_ids, + // Done for backward compatibility + schema_id = schema_ids.flatMap(s => s.headOption), + body = CredentialPreviewBody(attributes) + ) given Encoder[CredentialPreview] = deriveEncoder[CredentialPreview] given Decoder[CredentialPreview] = deriveDecoder[CredentialPreview] 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 2a9dfce4d6..62829323d3 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 @@ -23,7 +23,7 @@ final case class IssueCredentialRecord( createdAt: Instant, updatedAt: Option[Instant], thid: DidCommID, - schemaUri: Option[String], + schemaUris: Option[List[String]], credentialDefinitionId: Option[UUID], credentialDefinitionUri: Option[String], credentialFormat: CredentialFormat, @@ -86,7 +86,7 @@ final case class ValidFullIssuedCredentialRecord( id: DidCommID, issuedCredential: Option[IssueCredential], credentialFormat: CredentialFormat, - schemaUri: Option[String], + schemaUris: Option[List[String]], credentialDefinitionUri: Option[String], subjectId: Option[String], keyId: Option[KeyId], 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 2ac6c75c7a..896ef7b971 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 @@ -79,7 +79,7 @@ trait CredentialRepository { recordId: DidCommID, issue: IssueCredential, issuedRawCredential: String, - schemaUri: Option[String], + schemaUris: Option[List[String]], credentialDefinitionUri: Option[String], protocolState: ProtocolState ): URIO[WalletAccessContext, Unit] 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 34b3007c08..3414f8a351 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 @@ -27,7 +27,7 @@ trait CredentialService { pairwiseHolderDID: Option[DidId], kidIssuer: Option[KeyId], thid: DidCommID, - maybeSchemaId: Option[String], + maybeSchemaIds: Option[List[String]], claims: io.circe.Json, validityPeriod: Option[Double] = None, automaticIssuance: Option[Boolean], @@ -43,7 +43,7 @@ trait CredentialService { pairwiseHolderDID: Option[DidId], kidIssuer: Option[KeyId], thid: DidCommID, - maybeSchemaId: Option[String], + maybeSchemaIds: Option[List[String]], claims: io.circe.Json, validityPeriod: Option[Double] = None, automaticIssuance: Option[Boolean], 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 855c42df32..a95ead74b0 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 @@ -127,7 +127,7 @@ class CredentialServiceImpl( pairwiseIssuerDID: DidId, kidIssuer: Option[KeyId], thid: DidCommID, - schemaUri: Option[String], + schemaUris: Option[List[String]], validityPeriod: Option[Double], automaticIssuance: Option[Boolean], issuingDID: Option[CanonicalPrismDID], @@ -161,7 +161,7 @@ class CredentialServiceImpl( createdAt = Instant.now, updatedAt = None, thid = thid, - schemaUri = schemaUri, + schemaUris = schemaUris, credentialDefinitionId = credentialDefinitionGUID, credentialDefinitionUri = credentialDefinitionId, credentialFormat = credentialFormat, @@ -196,7 +196,7 @@ class CredentialServiceImpl( pairwiseHolderDID: Option[DidId], kidIssuer: Option[KeyId], thid: DidCommID, - maybeSchemaId: Option[String], + maybeSchemaIds: Option[List[String]], claims: Json, validityPeriod: Option[Double], automaticIssuance: Option[Boolean], @@ -207,12 +207,12 @@ class CredentialServiceImpl( connectionId: Option[UUID], ): URIO[WalletAccessContext, IssueCredentialRecord] = { for { - _ <- validateClaimsAgainstSchemaIfAny(claims, maybeSchemaId) + _ <- validateClaimsAgainstSchemaIfAny(claims, maybeSchemaIds) attributes <- CredentialService.convertJsonClaimsToAttributes(claims) offer <- createDidCommOfferCredential( pairwiseIssuerDID = pairwiseIssuerDID, pairwiseHolderDID = pairwiseHolderDID, - maybeSchemaId = maybeSchemaId, + maybeSchemaIds = maybeSchemaIds, claims = attributes, thid = thid, UUID.randomUUID().toString, @@ -223,7 +223,7 @@ class CredentialServiceImpl( pairwiseIssuerDID = pairwiseIssuerDID, kidIssuer = kidIssuer, thid = thid, - schemaUri = maybeSchemaId, + schemaUris = maybeSchemaIds, validityPeriod = validityPeriod, automaticIssuance = automaticIssuance, issuingDID = Some(issuingDID), @@ -244,7 +244,7 @@ class CredentialServiceImpl( pairwiseHolderDID: Option[DidId], kidIssuer: Option[KeyId], thid: DidCommID, - maybeSchemaId: Option[String], + maybeSchemaIds: Option[List[String]], claims: io.circe.Json, validityPeriod: Option[Double] = None, automaticIssuance: Option[Boolean], @@ -255,12 +255,12 @@ class CredentialServiceImpl( connectionId: Option[UUID], ): URIO[WalletAccessContext, IssueCredentialRecord] = { for { - _ <- validateClaimsAgainstSchemaIfAny(claims, maybeSchemaId) + _ <- validateClaimsAgainstSchemaIfAny(claims, maybeSchemaIds) attributes <- CredentialService.convertJsonClaimsToAttributes(claims) offer <- createDidCommOfferCredential( pairwiseIssuerDID = pairwiseIssuerDID, pairwiseHolderDID = pairwiseHolderDID, - maybeSchemaId = maybeSchemaId, + maybeSchemaIds = maybeSchemaIds, claims = attributes, thid = thid, UUID.randomUUID().toString, @@ -271,7 +271,7 @@ class CredentialServiceImpl( pairwiseIssuerDID = pairwiseIssuerDID, kidIssuer = kidIssuer, thid = thid, - schemaUri = maybeSchemaId, + schemaUris = maybeSchemaIds, validityPeriod = validityPeriod, automaticIssuance = automaticIssuance, issuingDID = Some(issuingDID), @@ -324,7 +324,7 @@ class CredentialServiceImpl( pairwiseIssuerDID = pairwiseIssuerDID, kidIssuer = None, thid = thid, - schemaUri = Some(credentialDefinition.schemaId), + schemaUris = Some(List(credentialDefinition.schemaId)), validityPeriod = validityPeriod, automaticIssuance = automaticIssuance, issuingDID = None, @@ -379,7 +379,7 @@ class CredentialServiceImpl( createdAt = Instant.now, updatedAt = None, thid = DidCommID(offer.thid.getOrElse(offer.id)), - schemaUri = None, + schemaUris = None, credentialDefinitionId = None, credentialDefinitionUri = None, credentialFormat = credentialFormat, @@ -442,12 +442,19 @@ class CredentialServiceImpl( private[this] def validateClaimsAgainstSchemaIfAny( claims: Json, - maybeSchemaId: Option[String] - ): UIO[Unit] = maybeSchemaId match - case Some(schemaId) => - CredentialSchema - .validateJWTCredentialSubject(schemaId, claims.noSpaces, uriResolver) - .orDieAsUnmanagedFailure + maybeSchemaIds: Option[List[String]] + ): UIO[Unit] = maybeSchemaIds match + case Some(schemaIds) => + for { + _ <- ZIO + .collectAll( + schemaIds.map(schemaId => + CredentialSchema + .validateJWTCredentialSubject(schemaId, claims.noSpaces, uriResolver) + ) + ) + .orDieAsUnmanagedFailure + } yield ZIO.unit case None => ZIO.unit @@ -810,7 +817,7 @@ class CredentialServiceImpl( processedIssuedCredential, record, attachment, - Some(processedCredential.getSchemaId), + Some(List(processedCredential.getSchemaId)), Some(processedCredential.getCredDefId) ) } yield result @@ -826,7 +833,7 @@ class CredentialServiceImpl( issueCredential: IssueCredential, record: IssueCredentialRecord, attachment: AttachmentDescriptor, - schemaId: Option[String], + schemaId: Option[List[String]], credDefId: Option[String] ) = { credentialRepository @@ -961,7 +968,7 @@ class CredentialServiceImpl( private def createDidCommOfferCredential( pairwiseIssuerDID: DidId, pairwiseHolderDID: Option[DidId], - maybeSchemaId: Option[String], + maybeSchemaIds: Option[List[String]], claims: Seq[Attribute], thid: DidCommID, challenge: String, @@ -969,7 +976,7 @@ class CredentialServiceImpl( offerFormat: IssueCredentialOfferFormat ): UIO[OfferCredential] = { for { - credentialPreview <- ZIO.succeed(CredentialPreview(schema_id = maybeSchemaId, attributes = claims)) + credentialPreview <- ZIO.succeed(CredentialPreview(schema_ids = maybeSchemaIds, attributes = claims)) body = OfferCredential.Body( goal_code = Some("Offer Credential"), credential_preview = credentialPreview, @@ -1005,7 +1012,7 @@ class CredentialServiceImpl( thid: DidCommID ): URIO[WalletAccessContext, OfferCredential] = { for { - credentialPreview <- ZIO.succeed(CredentialPreview(schema_id = Some(schemaUri), attributes = claims)) + credentialPreview <- ZIO.succeed(CredentialPreview(schema_ids = Some(List(schemaUri)), attributes = claims)) body = OfferCredential.Body( goal_code = Some("Offer Credential"), credential_preview = credentialPreview, @@ -1147,8 +1154,8 @@ class CredentialServiceImpl( issuer = CredentialIssuer(jwtIssuer.did.toString, `type` = "Profile"), issuanceDate = issuanceDate, maybeExpirationDate = record.validityPeriod.map(sec => issuanceDate.plusSeconds(sec.toLong)), - maybeCredentialSchema = record.schemaUri.map(id => - Left(org.hyperledger.identus.pollux.vc.jwt.CredentialSchema(id, VC_JSON_SCHEMA_TYPE)) + maybeCredentialSchema = record.schemaUris.map(ids => + ids.map(id => org.hyperledger.identus.pollux.vc.jwt.CredentialSchema(id, VC_JSON_SCHEMA_TYPE)) ), maybeCredentialStatus = Some(credentialStatus), credentialSubject = claims.add("id", jwtPresentation.iss.asJson).asJson, 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 5046688d45..500fdf4c29 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 @@ -28,7 +28,7 @@ class CredentialServiceNotifier( pairwiseHolderDID: Option[DidId], kidIssuer: Option[KeyId], thid: DidCommID, - maybeSchemaId: Option[String], + maybeSchemaIds: Option[List[String]], claims: Json, validityPeriod: Option[Double], automaticIssuance: Option[Boolean], @@ -44,7 +44,7 @@ class CredentialServiceNotifier( pairwiseHolderDID, kidIssuer, thid, - maybeSchemaId, + maybeSchemaIds, claims, validityPeriod, automaticIssuance, @@ -61,7 +61,7 @@ class CredentialServiceNotifier( pairwiseHolderDID: Option[DidId], kidIssuer: Option[KeyId], thid: DidCommID, - maybeSchemaId: Option[String], + maybeSchemaIds: Option[List[String]], claims: io.circe.Json, validityPeriod: Option[Double] = None, automaticIssuance: Option[Boolean], @@ -77,7 +77,7 @@ class CredentialServiceNotifier( pairwiseHolderDID, kidIssuer, thid, - maybeSchemaId, + maybeSchemaIds, claims, validityPeriod, automaticIssuance, diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/OID4VCIIssuerMetadataService.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/OID4VCIIssuerMetadataService.scala index 00949f1177..532000c850 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/OID4VCIIssuerMetadataService.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/OID4VCIIssuerMetadataService.scala @@ -68,7 +68,7 @@ trait OID4VCIIssuerMetadataService { format: CredentialFormat, configurationId: String, schemaId: String - ): ZIO[WalletAccessContext, InvalidSchemaId | UnsupportedCredentialFormat, CredentialConfiguration] + ): ZIO[WalletAccessContext, InvalidSchemaId | UnsupportedCredentialFormat | IssuerIdNotFound, CredentialConfiguration] def getCredentialConfigurations( issuerId: UUID ): IO[IssuerIdNotFound, Seq[CredentialConfiguration]] @@ -128,8 +128,13 @@ class OID4VCIIssuerMetadataServiceImpl(repository: OID4VCIIssuerMetadataReposito format: CredentialFormat, configurationId: String, schemaId: String - ): ZIO[WalletAccessContext, InvalidSchemaId | UnsupportedCredentialFormat, CredentialConfiguration] = { + ): ZIO[ + WalletAccessContext, + InvalidSchemaId | UnsupportedCredentialFormat | IssuerIdNotFound, + CredentialConfiguration + ] = { for { + _ <- getCredentialIssuer(issuerId) _ <- format match { case CredentialFormat.JWT => ZIO.unit case f => ZIO.fail(UnsupportedCredentialFormat(f)) 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 cde1ee64a5..8200595ebf 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 @@ -239,7 +239,7 @@ private class PresentationServiceImpl( ) presentationPayload <- createAnoncredPresentationPayloadFromCredential( issuedCredentials, - issuedValidCredentials.flatMap(_.schemaUri), + issuedValidCredentials.flatMap(_.schemaUris.getOrElse(List())), issuedValidCredentials.flatMap(_.credentialDefinitionUri), requestPresentation, anoncredCredentialProof.credentialProofs diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationServiceImpl.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationServiceImpl.scala index a94987f2ce..2d43eb120f 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationServiceImpl.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationServiceImpl.scala @@ -1,9 +1,15 @@ package org.hyperledger.identus.pollux.core.service.verification import org.hyperledger.identus.pollux.core.model.schema.CredentialSchema -import org.hyperledger.identus.pollux.vc.jwt.{CredentialPayload, DidResolver, JWT, JWTVerification, JwtCredential} +import org.hyperledger.identus.pollux.vc.jwt.{ + CredentialPayload, + CredentialSchema as JwtCredentialSchema, + DidResolver, + JWT, + JWTVerification, + JwtCredential +} import org.hyperledger.identus.shared.http.UriResolver -// import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits //TODO: might not be necessary import zio.* import java.time.OffsetDateTime @@ -53,7 +59,10 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriResolver: UriResolv ZIO .fromOption(decodedJwt.maybeCredentialSchema) .mapError(error => VcVerificationServiceError.UnexpectedError(s"Missing Credential Schema: $error")) - credentialSchemas = credentialSchema.fold(List(_), identity) + credentialSchemas = credentialSchema match { + case schema: JwtCredentialSchema => List(schema) + case schemaList: List[JwtCredentialSchema] => schemaList + } result <- ZIO.collectAll( credentialSchemas.map(credentialSchema => @@ -97,7 +106,10 @@ class VcVerificationServiceImpl(didResolver: DidResolver, uriResolver: UriResolv ZIO .fromOption(decodedJwt.maybeCredentialSchema) .mapError(error => VcVerificationServiceError.UnexpectedError(s"Missing Credential Schema: $error")) - credentialSchemas = credentialSchema.fold(List(_), identity) + credentialSchemas = credentialSchema match { + case schema: JwtCredentialSchema => List(schema) + case schemaList: List[JwtCredentialSchema] => schemaList + } result <- ZIO.collectAll( credentialSchemas.map(credentialSchema => diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositoryInMemory.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositoryInMemory.scala index aa7d5390f2..d59c0cd30d 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositoryInMemory.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositoryInMemory.scala @@ -104,7 +104,7 @@ class CredentialRepositoryInMemory( recordId: DidCommID, issue: IssueCredential, issuedRawCredential: String, - schemaUri: Option[String], + schemaUris: Option[List[String]], credentialDefinitionUri: Option[String], protocolState: ProtocolState ): URIO[WalletAccessContext, Unit] = { @@ -117,7 +117,7 @@ class CredentialRepositoryInMemory( recordId, record.copy( updatedAt = Some(Instant.now), - schemaUri = schemaUri, + schemaUris = schemaUris, credentialDefinitionUri = credentialDefinitionUri, issueCredentialData = Some(issue), issuedCredentialRaw = Some(issuedRawCredential), @@ -155,7 +155,7 @@ class CredentialRepositoryInMemory( recordId.contains( rec.id ) && rec.issueCredentialData.isDefined - && rec.schemaUri.isDefined + && rec.schemaUris.isDefined && rec.credentialDefinitionUri.isDefined && rec.credentialFormat == CredentialFormat.AnonCreds ) @@ -164,7 +164,7 @@ class CredentialRepositoryInMemory( rec.id, rec.issueCredentialData, rec.credentialFormat, - rec.schemaUri, + rec.schemaUris, rec.credentialDefinitionUri, rec.subjectId, rec.keyId, 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 fc61ba2f73..c598c4c876 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 @@ -21,7 +21,7 @@ object CredentialRepositorySpecSuite { createdAt = Instant.now, updatedAt = None, thid = DidCommID(), - schemaUri = None, + schemaUris = None, credentialDefinitionId = None, credentialDefinitionUri = None, credentialFormat = credentialFormat, @@ -373,7 +373,7 @@ object CredentialRepositorySpecSuite { aRecord.id, issueCredential, "RAW_CREDENTIAL_DATA", - Some("schemaUri"), + Some(List("schemaUri")), Some("credentialDefinitionUri"), ProtocolState.CredentialReceived ) @@ -383,7 +383,7 @@ object CredentialRepositorySpecSuite { assertTrue(updatedRecord.get.issueCredentialData.contains(issueCredential)) && assertTrue(updatedRecord.get.issuedCredentialRaw.contains("RAW_CREDENTIAL_DATA")) assertTrue(updatedRecord.get.credentialDefinitionUri.contains("credentialDefinitionUri")) - assertTrue(updatedRecord.get.schemaUri.contains("schemaUri")) + assertTrue(updatedRecord.get.schemaUris.getOrElse(List.empty).contains("schemaUri")) } }, test("updateFail (fail one retry) updates record") { 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 a835375a53..0e15ad2d55 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 @@ -76,14 +76,14 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS thid = thid, pairwiseIssuerDID = pairwiseIssuerDid, pairwiseHolderDID = pairwiseHolderDid, - maybeSchemaId = None, + maybeSchemaIds = None, validityPeriod = validityPeriod, automaticIssuance = automaticIssuance ) } yield { assertTrue(record.thid == thid) && assertTrue(record.updatedAt.isEmpty) && - assertTrue(record.schemaUri.isEmpty) && + assertTrue(record.schemaUris.getOrElse(List.empty).isEmpty) && assertTrue(record.validityPeriod == validityPeriod) && assertTrue(record.automaticIssuance == automaticIssuance) && assertTrue(record.role == Role.Issuer) && @@ -149,7 +149,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS thid = thid, pairwiseIssuerDID = pairwiseIssuerDid, pairwiseHolderDID = pairwiseHolderDid, - maybeSchemaId = Some("resource:///vc-schema-example.json"), + maybeSchemaIds = Some(List("resource:///vc-schema-example.json")), claims = claims, validityPeriod = validityPeriod, automaticIssuance = automaticIssuance @@ -159,7 +159,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS assertTrue(record.thid == thid) && assertTrue(record.updatedAt.isEmpty) && assertTrue( - record.schemaUri.contains("resource:///vc-schema-example.json") + record.schemaUris.getOrElse(List.empty).contains("resource:///vc-schema-example.json") ) && assertTrue(record.validityPeriod == validityPeriod) && assertTrue(record.automaticIssuance == automaticIssuance) && @@ -209,7 +209,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS thid = thid, pairwiseIssuerDID = pairwiseIssuerDid, pairwiseHolderDID = pairwiseHolderDid, - maybeSchemaId = Some("resource:///vc-schema-example.json"), + maybeSchemaIds = Some(List("resource:///vc-schema-example.json")), claims = claims, validityPeriod = validityPeriod, automaticIssuance = automaticIssuance @@ -288,7 +288,7 @@ object CredentialServiceImplSpec extends MockSpecDefault with CredentialServiceS } yield { assertTrue(holderRecord.thid.toString == offer.thid.get) && assertTrue(holderRecord.updatedAt.isEmpty) && - assertTrue(holderRecord.schemaUri.isEmpty) && + assertTrue(holderRecord.schemaUris.getOrElse(List.empty).isEmpty) && assertTrue(holderRecord.validityPeriod.isEmpty) && assertTrue(holderRecord.automaticIssuance.isEmpty) && assertTrue(holderRecord.role == Role.Holder) && diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceSpecHelper.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceSpecHelper.scala index 69a94b9e7b..a03eb88803 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceSpecHelper.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/CredentialServiceSpecHelper.scala @@ -108,7 +108,7 @@ trait CredentialServiceSpecHelper { pairwiseIssuerDID: DidId = DidId("did:prism:issuer"), pairwiseHolderDID: Option[DidId] = Some(DidId("did:prism:holder-pairwise")), thid: DidCommID = DidCommID(), - maybeSchemaId: Option[String] = None, + maybeSchemaIds: Option[List[String]] = None, claims: Json = io.circe.parser .parse(""" |{ @@ -131,7 +131,7 @@ trait CredentialServiceSpecHelper { pairwiseHolderDID = pairwiseHolderDID, kidIssuer = None, thid = thid, - maybeSchemaId = maybeSchemaId, + maybeSchemaIds = maybeSchemaIds, claims = claims, validityPeriod = validityPeriod, automaticIssuance = automaticIssuance, diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/MockCredentialService.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/MockCredentialService.scala index 6e389cf499..eff67638bc 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/MockCredentialService.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/MockCredentialService.scala @@ -22,7 +22,7 @@ object MockCredentialService extends Mock[CredentialService] { DidId, Option[DidId], DidCommID, - Option[String], + Option[List[String]], Json, Option[Double], Option[Boolean], @@ -41,7 +41,7 @@ object MockCredentialService extends Mock[CredentialService] { DidId, Option[DidId], DidCommID, - Option[String], + Option[List[String]], Json, Option[Double], Option[Boolean], @@ -130,7 +130,7 @@ object MockCredentialService extends Mock[CredentialService] { pairwiseHolderDID: Option[DidId], kidIssuer: Option[KeyId], thid: DidCommID, - maybeSchemaId: Option[String], + maybeSchemaIds: Option[List[String]], claims: Json, validityPeriod: Option[Double], automaticIssuance: Option[Boolean], @@ -145,7 +145,7 @@ object MockCredentialService extends Mock[CredentialService] { pairwiseIssuerDID, pairwiseHolderDID, thid, - maybeSchemaId, + maybeSchemaIds, claims, validityPeriod, automaticIssuance, @@ -161,7 +161,7 @@ object MockCredentialService extends Mock[CredentialService] { pairwiseHolderDID: Option[DidId], kidIssuer: Option[KeyId], thid: DidCommID, - maybeSchemaId: Option[String], + maybeSchemaIds: Option[List[String]], claims: Json, validityPeriod: Option[Double], automaticIssuance: Option[Boolean], @@ -176,7 +176,7 @@ object MockCredentialService extends Mock[CredentialService] { pairwiseIssuerDID, pairwiseHolderDID, thid, - maybeSchemaId, + maybeSchemaIds, claims, validityPeriod, automaticIssuance, diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpec.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpec.scala index b1feb03cd2..981a187601 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpec.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpec.scala @@ -521,7 +521,7 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp aIssueCredentialRecord.id, issueCredential, rawCredentialData, - Some("SchemaId"), + Some(List("SchemaId")), Some("CredDefId"), IssueCredentialRecord.ProtocolState.CredentialReceived ) @@ -865,7 +865,7 @@ object PresentationServiceSpec extends ZIOSpecDefault with PresentationServiceSp createdAt = Instant.now, updatedAt = None, thid = DidCommID(), - schemaUri = Some(schemaId), + schemaUris = Some(List(schemaId)), credentialDefinitionId = Some(credentialDefinitionDb.guid), credentialDefinitionUri = Some(credentialDefinitionId), credentialFormat = CredentialFormat.AnonCreds, diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala index 1c23d92241..e438d4687b 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala @@ -135,7 +135,7 @@ trait PresentationServiceSpecHelper { createdAt = Instant.now, updatedAt = None, thid = DidCommID(), - schemaUri = None, + schemaUris = None, credentialDefinitionId = None, credentialDefinitionUri = None, credentialFormat = credentialFormat, diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationServiceImplSpec.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationServiceImplSpec.scala index b5c8c326e5..25daf11202 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationServiceImplSpec.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationServiceImplSpec.scala @@ -33,11 +33,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( @@ -100,11 +98,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( @@ -167,11 +163,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( @@ -234,11 +228,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( @@ -308,11 +300,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( @@ -379,11 +369,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "resource:///vc-schema-personal.json", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "resource:///vc-schema-personal.json", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( @@ -450,16 +438,14 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Right( - List( - CredentialSchema( - id = "resource:///vc-schema-personal.json", - `type` = "JsonSchemaValidator2018" - ), - CredentialSchema( - id = "resource:///vc-schema-driver-license.json", - `type` = "JsonSchemaValidator2018" - ) + List( + CredentialSchema( + id = "resource:///vc-schema-personal.json", + `type` = "JsonSchemaValidator2018" + ), + CredentialSchema( + id = "resource:///vc-schema-driver-license.json", + `type` = "JsonSchemaValidator2018" ) ) ), @@ -530,16 +516,14 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Right( - List( - CredentialSchema( - id = "resource:///vc-schema-personal.json", - `type` = "JsonSchemaValidator2018" - ), - CredentialSchema( - id = "resource:///vc-schema-driver-license.json", - `type` = "JsonSchemaValidator2018" - ) + List( + CredentialSchema( + id = "resource:///vc-schema-personal.json", + `type` = "JsonSchemaValidator2018" + ), + CredentialSchema( + id = "resource:///vc-schema-driver-license.json", + `type` = "JsonSchemaValidator2018" ) ) ), @@ -611,11 +595,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( @@ -679,11 +661,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( @@ -747,11 +727,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( @@ -815,11 +793,9 @@ object VcVerificationServiceImplSpec extends ZIOSpecDefault with VcVerificationS maybeValidFrom = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeValidUntil = Some(Instant.parse("2010-01-12T00:00:00Z")), maybeCredentialSchema = Some( - Left( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) + CredentialSchema( + id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", + `type` = "JsonSchemaValidator2018" ) ), credentialSubject = Json.obj( diff --git a/pollux/sql-doobie/src/main/resources/sql/pollux/V28__support_multiple_credential_schema.sql b/pollux/sql-doobie/src/main/resources/sql/pollux/V28__support_multiple_credential_schema.sql new file mode 100644 index 0000000000..5dd92dedb2 --- /dev/null +++ b/pollux/sql-doobie/src/main/resources/sql/pollux/V28__support_multiple_credential_schema.sql @@ -0,0 +1,9 @@ +ALTER TABLE public.issue_credential_records + ADD COLUMN schema_uris VARCHAR(500)[]; + +UPDATE public.issue_credential_records +SET schema_uris = ARRAY[schema_uri] +WHERE schema_uri IS NOT NULL; + +ALTER TABLE public.issue_credential_records + DROP COLUMN schema_uri; \ No newline at end of file diff --git a/pollux/sql-doobie/src/main/resources/sql/pollux/V28__add_resolution_method_to_schema_and_cred_definition.sql b/pollux/sql-doobie/src/main/resources/sql/pollux/V29__add_resolution_method_to_schema_and_cred_definition.sql similarity index 100% rename from pollux/sql-doobie/src/main/resources/sql/pollux/V28__add_resolution_method_to_schema_and_cred_definition.sql rename to pollux/sql-doobie/src/main/resources/sql/pollux/V29__add_resolution_method_to_schema_and_cred_definition.sql 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 339e2946ad..151ebd9e3f 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 @@ -72,7 +72,7 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ | created_at, | updated_at, | thid, - | schema_uri, + | schema_uris, | credential_definition_id, | credential_definition_uri, | credential_format, @@ -98,7 +98,7 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ | ${record.createdAt}, | ${record.updatedAt}, | ${record.thid}, - | ${record.schemaUri}, + | ${record.schemaUris}, | ${record.credentialDefinitionId}, | ${record.credentialDefinitionUri}, | ${record.credentialFormat}, @@ -142,7 +142,7 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ | created_at, | updated_at, | thid, - | schema_uri, + | schema_uris, | credential_definition_id, | credential_definition_uri, | credential_format, @@ -214,7 +214,7 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ | created_at, | updated_at, | thid, - | schema_uri, + | schema_uris, | credential_definition_id, | credential_definition_uri, | credential_format, @@ -278,7 +278,7 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ | created_at, | updated_at, | thid, - | schema_uri, + | schema_uris, | credential_definition_id, | credential_definition_uri, | credential_format, @@ -323,7 +323,7 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ | created_at, | updated_at, | thid, - | schema_uri, + | schema_uris, | credential_definition_id, | credential_definition_uri, | credential_format, @@ -502,13 +502,13 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ | id, | issue_credential_data, | credential_format, - | schema_uri, + | schema_uris, | credential_definition_uri, | subject_id | FROM public.issue_credential_records | WHERE 1=1 | AND issue_credential_data IS NOT NULL - | AND schema_uri IS NOT NULL + | AND schema_uris IS NOT NULL | AND credential_definition_uri IS NOT NULL | AND credential_format = 'AnonCreds' | AND $inClauseFragment @@ -538,14 +538,14 @@ class JdbcCredentialRepository(xa: Transactor[ContextAwareTask], xb: Transactor[ recordId: DidCommID, issue: IssueCredential, issuedRawCredential: String, - schemaUri: Option[String], + schemaUris: Option[List[String]], credentialDefinitionUri: Option[String], protocolState: ProtocolState ): URIO[WalletAccessContext, Unit] = { val cxnIO = sql""" | UPDATE public.issue_credential_records | SET - | schema_uri = $schemaUri, + | schema_uris = $schemaUris, | credential_definition_uri = $credentialDefinitionUri, | issue_credential_data = $issue, | issued_credential_raw = $issuedRawCredential, 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 aa4b5c3805..3d24747bd1 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 @@ -87,7 +87,7 @@ sealed trait CredentialPayload { def maybeTermsOfUse: Option[Json] - def maybeCredentialSchema: Option[Either[CredentialSchema, List[CredentialSchema]]] + def maybeCredentialSchema: Option[CredentialSchema | List[CredentialSchema]] def credentialSubject: Json @@ -140,7 +140,7 @@ sealed trait CredentialPayload { case class JwtVc( `@context`: Set[String], `type`: Set[String], - maybeCredentialSchema: Option[Either[CredentialSchema, List[CredentialSchema]]], + maybeCredentialSchema: Option[CredentialSchema | List[CredentialSchema]], credentialSubject: Json, maybeValidFrom: Option[Instant], maybeValidUntil: Option[Instant], @@ -180,7 +180,7 @@ case class W3cCredentialPayload( issuer: String | CredentialIssuer, issuanceDate: Instant, maybeExpirationDate: Option[Instant], - override val maybeCredentialSchema: Option[Either[CredentialSchema, List[CredentialSchema]]], + override val maybeCredentialSchema: Option[CredentialSchema | List[CredentialSchema]], override val credentialSubject: Json, override val maybeCredentialStatus: Option[CredentialStatus], override val maybeRefreshService: Option[RefreshService], @@ -244,9 +244,9 @@ object CredentialPayload { case credentialIssuer: CredentialIssuer => Encoder[CredentialIssuer].apply(credentialIssuer) } - implicit val eitherCredentialSchemaOrListEncoder: Encoder[Either[CredentialSchema, List[CredentialSchema]]] = { - case Left(credentialSchema) => credentialSchema.asJson - case Right(credentialSchemas) => credentialSchemas.asJson + implicit val credentialSchemaOrListEncoder: Encoder[CredentialSchema | List[CredentialSchema]] = Encoder.instance { + case schema: CredentialSchema => Encoder[CredentialSchema].apply(schema) + case schemaList: List[CredentialSchema] => Encoder[List[CredentialSchema]].apply(schemaList) } implicit val w3cCredentialPayloadEncoder: Encoder[W3cCredentialPayload] = @@ -378,10 +378,10 @@ object CredentialPayload { .map(schema => schema: String | CredentialIssuer) .or(Decoder[CredentialIssuer].map(schema => schema: String | CredentialIssuer)) - implicit val eitherCredentialSchemaOrListDecoder: Decoder[Either[CredentialSchema, List[CredentialSchema]]] = + implicit val credentialSchemaOrListDecoder: Decoder[CredentialSchema | List[CredentialSchema]] = Decoder[CredentialSchema] - .map(Left(_)) - .or(Decoder[List[CredentialSchema]].map(Right(_))) + .map(schema => schema: CredentialSchema | List[CredentialSchema]) + .or(Decoder[List[CredentialSchema]].map(schema => schema: CredentialSchema | List[CredentialSchema])) implicit val w3cCredentialPayloadDecoder: Decoder[W3cCredentialPayload] = (c: HCursor) => @@ -402,7 +402,7 @@ object CredentialPayload { maybeValidUntil <- c.downField("validUntil").as[Option[Instant]] maybeCredentialSchema <- c .downField("credentialSchema") - .as[Option[Either[CredentialSchema, List[CredentialSchema]]]] + .as[Option[CredentialSchema | List[CredentialSchema]]] credentialSubject <- c.downField("credentialSubject").as[Json] maybeCredentialStatus <- c.downField("credentialStatus").as[Option[CredentialStatus]] maybeRefreshService <- c.downField("refreshService").as[Option[RefreshService]] @@ -441,7 +441,7 @@ object CredentialPayload { .orElse(c.downField("type").as[String].map(Set(_))) maybeCredentialSchema <- c .downField("credentialSchema") - .as[Option[Either[CredentialSchema, List[CredentialSchema]]]] + .as[Option[CredentialSchema | List[CredentialSchema]]] credentialSubject <- c.downField("credentialSubject").as[Json] maybeCredentialStatus <- c.downField("credentialStatus").as[Option[CredentialStatus]] maybeRefreshService <- c.downField("refreshService").as[Option[RefreshService]]