Skip to content

Commit

Permalink
ATL-7775: Default Backend API to Array Of Credential Schema
Browse files Browse the repository at this point in the history
Signed-off-by: Bassam Riman <[email protected]>
  • Loading branch information
CryptoKnightIOG committed Sep 18, 2024
1 parent c18385c commit 1974e79
Show file tree
Hide file tree
Showing 18 changed files with 117 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.hyperledger.identus.issue.controller

import cats.Applicative
import org.hyperledger.identus.agent.server.config.AppConfig
import org.hyperledger.identus.agent.server.ControllerHelper
import org.hyperledger.identus.agent.walletapi.model.PublicationState
Expand All @@ -11,13 +12,7 @@ import org.hyperledger.identus.api.util.PaginationUtils
import org.hyperledger.identus.castor.core.model.did.{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}
import org.hyperledger.identus.pollux.core.model.CredentialFormat.{AnonCreds, JWT, SDJWT}
Expand Down Expand Up @@ -48,6 +43,7 @@ class IssueControllerImpl(
request: CreateIssueCredentialRecordRequest,
offerContext: OfferContext
): ZIO[WalletAccessContext, ErrorResponse, IssueCredentialRecord] = {

for {
jsonClaims <- ZIO
.fromEither(io.circe.parser.parse(request.claims.toString()))
Expand All @@ -69,7 +65,7 @@ class IssueControllerImpl(
pairwiseHolderDID = offerContext.pairwiseHolderDID,
kidIssuer = request.issuingKid,
thid = DidCommID(),
maybeSchemaId = request.schemaId,
maybeSchemaIds = Applicative[Option].map2(request.schemaIds, request.schemaId.map(List(_)))(_ ++ _),
claims = jsonClaims,
validityPeriod = request.validityPeriod,
automaticIssuance = request.automaticIssuance.orElse(Some(true)),
Expand All @@ -94,7 +90,7 @@ class IssueControllerImpl(
pairwiseHolderDID = offerContext.pairwiseHolderDID,
kidIssuer = request.issuingKid,
thid = DidCommID(),
maybeSchemaId = request.schemaId,
maybeSchemaIds = request.schemaId.map(List(_)),
claims = jsonClaims,
validityPeriod = request.validityPeriod,
automaticIssuance = request.automaticIssuance.orElse(Some(true)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ final case class CreateIssueCredentialRecordRequest(
validityPeriod: Option[Double] = None,
@description(annotations.schemaId.description)
@encodedExample(annotations.schemaId.example)
schemaId: Option[String],
schemaId: Option[String] = None,
@description(annotations.schemaId.description)
@encodedExample(annotations.schemaId.example)
schemaIds: Option[List[String]] = None,
@description(annotations.credentialDefinitionId.description)
@encodedExample(annotations.credentialDefinitionId.example)
credentialDefinitionId: Option[UUID],
Expand Down Expand Up @@ -85,6 +88,21 @@ object CreateIssueCredentialRecordRequest {
)
)

object schemaIds
extends Annotation[Option[List[String]]](
description = """
|The URL pointing to the JSON schema that will be used for this offer (should be 'http' or 'https').
|When dereferenced, the returned content should be a JSON schema compliant with the '[Draft 2020-12](https://json-schema.org/draft/2020-12/release-notes)' version of the specification.
|Note that this parameter only applies when the offer is of type 'JWT'.
|""".stripMargin,
example = Some(
List(
"https://agent-host.com/cloud-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676/schema",
"https://agent-host.com/cloud-agent/schema-registry/schemas/d9569cec-c81e-4779-aa86-0d5994d82676/schema2"
)
)
)

object credentialDefinitionId
extends Annotation[Option[UUID]](
description = """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -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],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down Expand Up @@ -161,7 +161,7 @@ class CredentialServiceImpl(
createdAt = Instant.now,
updatedAt = None,
thid = thid,
schemaUri = schemaUri,
schemaUris = schemaUris,
credentialDefinitionId = credentialDefinitionGUID,
credentialDefinitionUri = credentialDefinitionId,
credentialFormat = credentialFormat,
Expand Down Expand Up @@ -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],
Expand All @@ -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,
Expand All @@ -223,7 +223,7 @@ class CredentialServiceImpl(
pairwiseIssuerDID = pairwiseIssuerDID,
kidIssuer = kidIssuer,
thid = thid,
schemaUri = maybeSchemaId,
schemaUris = maybeSchemaIds,
validityPeriod = validityPeriod,
automaticIssuance = automaticIssuance,
issuingDID = Some(issuingDID),
Expand All @@ -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],
Expand All @@ -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,
Expand All @@ -271,7 +271,7 @@ class CredentialServiceImpl(
pairwiseIssuerDID = pairwiseIssuerDID,
kidIssuer = kidIssuer,
thid = thid,
schemaUri = maybeSchemaId,
schemaUris = maybeSchemaIds,
validityPeriod = validityPeriod,
automaticIssuance = automaticIssuance,
issuingDID = Some(issuingDID),
Expand Down Expand Up @@ -320,7 +320,7 @@ class CredentialServiceImpl(
pairwiseIssuerDID = pairwiseIssuerDID,
kidIssuer = None,
thid = thid,
schemaUri = Some(credentialDefinition.schemaId),
schemaUris = Some(List(credentialDefinition.schemaId)),
validityPeriod = validityPeriod,
automaticIssuance = automaticIssuance,
issuingDID = None,
Expand Down Expand Up @@ -375,7 +375,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,
Expand Down Expand Up @@ -438,12 +438,19 @@ class CredentialServiceImpl(

private[this] def validateClaimsAgainstSchemaIfAny(
claims: Json,
maybeSchemaId: Option[String]
): UIO[Unit] = maybeSchemaId match
case Some(schemaId) =>
CredentialSchema
.validateJWTCredentialSubject(schemaId, claims.noSpaces, uriDereferencer)
.orDieAsUnmanagedFailure
maybeSchemaIds: Option[List[String]]
): UIO[Unit] = maybeSchemaIds match
case Some(schemaIds) =>
for {
_ <- ZIO
.collectAll(
schemaIds.map(schemaId =>
CredentialSchema
.validateJWTCredentialSubject(schemaId, claims.noSpaces, uriDereferencer)
)
)
.orDieAsUnmanagedFailure
} yield ZIO.unit
case None =>
ZIO.unit

Expand Down Expand Up @@ -806,7 +813,7 @@ class CredentialServiceImpl(
processedIssuedCredential,
record,
attachment,
Some(processedCredential.getSchemaId),
Some(List(processedCredential.getSchemaId)),
Some(processedCredential.getCredDefId)
)
} yield result
Expand All @@ -822,7 +829,7 @@ class CredentialServiceImpl(
issueCredential: IssueCredential,
record: IssueCredentialRecord,
attachment: AttachmentDescriptor,
schemaId: Option[String],
schemaId: Option[List[String]],
credDefId: Option[String]
) = {
credentialRepository
Expand Down Expand Up @@ -957,15 +964,15 @@ class CredentialServiceImpl(
private def createDidCommOfferCredential(
pairwiseIssuerDID: DidId,
pairwiseHolderDID: Option[DidId],
maybeSchemaId: Option[String],
maybeSchemaIds: Option[List[String]],
claims: Seq[Attribute],
thid: DidCommID,
challenge: String,
domain: String,
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,
Expand Down Expand Up @@ -1001,7 +1008,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,
Expand Down Expand Up @@ -1143,8 +1150,8 @@ class CredentialServiceImpl(
issuer = Right(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 =>
Right(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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -44,7 +44,7 @@ class CredentialServiceNotifier(
pairwiseHolderDID,
kidIssuer,
thid,
maybeSchemaId,
maybeSchemaIds,
claims,
validityPeriod,
automaticIssuance,
Expand All @@ -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],
Expand All @@ -77,7 +77,7 @@ class CredentialServiceNotifier(
pairwiseHolderDID,
kidIssuer,
thid,
maybeSchemaId,
maybeSchemaIds,
claims,
validityPeriod,
automaticIssuance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ private class PresentationServiceImpl(
)
presentationPayload <- createAnoncredPresentationPayloadFromCredential(
issuedCredentials,
issuedValidCredentials.flatMap(_.schemaUri),
issuedValidCredentials.flatMap(_.schemaUris.getOrElse(List())),
issuedValidCredentials.flatMap(_.credentialDefinitionUri),
requestPresentation,
anoncredCredentialProof.credentialProofs
Expand Down
Loading

0 comments on commit 1974e79

Please sign in to comment.