Skip to content

Commit

Permalink
Add repository and credentialStatus data types
Browse files Browse the repository at this point in the history
Signed-off-by: Shota Jolbordi <shota.jolbordi@iohk.io>
  • Loading branch information
Shota Jolbordi committed Dec 5, 2023
1 parent 027fe28 commit 5aa345b
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.iohk.atala.pollux.core.model
import io.iohk.atala.castor.core.model.did.DID
import io.iohk.atala.pollux.vc.jwt.StatusPurpose
import io.iohk.atala.shared.models.WalletId

import java.time.Instant
import java.util.UUID

final case class CredentialStatusList(
id: UUID,
walletId: WalletId,
issuer: DID,
issued: Instant,
purpose: StatusPurpose,
statusListJwtCredential: String,
size: Int,
lastUsedIndex: Int,
createdAt: Instant,
updatedAt: Option[Instant]
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.iohk.atala.pollux.core.repository

import io.iohk.atala.mercury.protocol.issuecredential.{IssueCredential, RequestCredential}
import io.iohk.atala.pollux.anoncreds.CredentialRequestMetadata
import io.iohk.atala.pollux.core.model.*
import io.iohk.atala.pollux.core.model.IssueCredentialRecord.ProtocolState
import io.iohk.atala.shared.models.{WalletAccessContext, WalletId}
import zio.*

trait CredentialStatusListRepository {
def getLatestOfTheWallet(walletId: WalletId): RIO[WalletAccessContext, CredentialStatusList]

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import io.iohk.atala.pollux.core.model.error.CredentialServiceError.*
import io.iohk.atala.pollux.core.model.presentation.*
import io.iohk.atala.pollux.core.model.schema.CredentialSchema
import io.iohk.atala.pollux.core.model.secret.CredentialDefinitionSecret
import io.iohk.atala.pollux.core.repository.CredentialRepository
import io.iohk.atala.pollux.core.repository.{CredentialRepository, CredentialStatusListRepository}
import io.iohk.atala.pollux.vc.jwt.{ES256KSigner, Issuer as JwtIssuer, *}
import io.iohk.atala.shared.models.WalletAccessContext
import io.iohk.atala.shared.models.{WalletAccessContext, WalletId}
import io.iohk.atala.shared.utils.aspects.CustomMetricsAspect
import zio.*
import zio.prelude.ZValidation
Expand All @@ -34,18 +34,19 @@ import scala.language.implicitConversions

object CredentialServiceImpl {
val layer: URLayer[
CredentialRepository & DidResolver & URIDereferencer & GenericSecretStorage & CredentialDefinitionService &
LinkSecretService & DIDService & ManagedDIDService,
CredentialRepository & CredentialStatusListRepository & DidResolver & URIDereferencer & GenericSecretStorage &
CredentialDefinitionService & LinkSecretService & DIDService & ManagedDIDService,
CredentialService
] =
ZLayer.fromFunction(CredentialServiceImpl(_, _, _, _, _, _, _, _))
ZLayer.fromFunction(CredentialServiceImpl(_, _, _, _, _, _, _, _, _))

// private val VC_JSON_SCHEMA_URI = "https://w3c-ccg.github.io/vc-json-schemas/schema/2.0/schema.json"
private val VC_JSON_SCHEMA_TYPE = "CredentialSchema2022"
}

private class CredentialServiceImpl(
credentialRepository: CredentialRepository,
credentialStatusListRepository: CredentialStatusListRepository,
didResolver: DidResolver,
uriDereferencer: URIDereferencer,
genericSecretStorage: GenericSecretStorage,
Expand Down Expand Up @@ -975,6 +976,8 @@ private class CredentialServiceImpl(
.mapError(_ =>
CredentialServiceError.UnexpectedError(s"Issue credential data not found in record: ${recordId.value}")
)
walletId <- ZIO.serviceWith[WalletAccessContext](_.walletId)
_ <- ZIO.logInfo("wallet id is " + walletId)
longFormPrismDID <- getLongForm(issuingDID, true).mapError(err => UnexpectedError(err.getMessage))
jwtIssuer <- createJwtIssuer(longFormPrismDID, VerificationRelationship.AssertionMethod)
offerCredentialData <- ZIO
Expand Down Expand Up @@ -1015,8 +1018,16 @@ private class CredentialServiceImpl(
maybeExpirationDate = record.validityPeriod.map(sec => issuanceDate.plusSeconds(sec.toLong)),
maybeCredentialSchema =
record.schemaId.map(id => io.iohk.atala.pollux.vc.jwt.CredentialSchema(id, VC_JSON_SCHEMA_TYPE)),
maybeCredentialStatus = Some(
CredentialStatus(
id = "id",
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "abc"
)
),
credentialSubject = claims.add("id", jwtPresentation.iss.asJson).asJson,
maybeCredentialStatus = None,
maybeRefreshService = None,
maybeEvidence = None,
maybeTermsOfUse = None
Expand All @@ -1032,6 +1043,20 @@ private class CredentialServiceImpl(
} yield record
}

// what needs to happen:
// get the last status list of this wallet that was created
// check its size and last used index
// if last used index is less then size, that is the status list we will use, status list index is last_used_index + 1
// if the last used index is equals to the size create new status list for this wallet, and use that, status list_index is 0
//

private[this] def allocateNewCredentialInStatusListForWallet(walletId: WalletId, recordId: DidCommID) = {
for {
lastStatusList <- credentialStatusListRepository.getLatestOfTheWallet(walletId)
} yield ()
}


override def generateAnonCredsCredential(
recordId: DidCommID
): ZIO[WalletAccessContext, CredentialServiceError, IssueCredentialRecord] = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.iohk.atala.pollux.sql.repository

import cats.data.NonEmptyList
import doobie.*
import doobie.free.connection
import doobie.implicits.*
import doobie.postgres.implicits.*
import io.circe.*
import io.circe.parser.*
import io.circe.syntax.*
import io.iohk.atala.castor.core.model.did.*
import io.iohk.atala.mercury.protocol.issuecredential.{IssueCredential, OfferCredential, RequestCredential}
import io.iohk.atala.pollux.anoncreds.CredentialRequestMetadata
import io.iohk.atala.pollux.core.model.*
import io.iohk.atala.pollux.core.model.error.CredentialRepositoryError
import io.iohk.atala.pollux.core.model.error.CredentialRepositoryError.*
import io.iohk.atala.pollux.core.repository.{CredentialRepository, CredentialStatusListRepository}
import io.iohk.atala.shared.db.ContextAwareTask
import io.iohk.atala.shared.db.Implicits.*
import io.iohk.atala.shared.models.WalletAccessContext
import org.postgresql.util.PSQLException
import zio.*
import zio.interop.catz.*
import zio.json.*
import io.iohk.atala.shared.models.{WalletAccessContext, WalletId}

import java.time.Instant

class JdbcCredentialStatusListRepository(xa: Transactor[ContextAwareTask], xb: Transactor[Task])
extends CredentialStatusListRepository {
def getLatestOfTheWallet(walletId: WalletId): RIO[WalletAccessContext, CredentialStatusList] = ???

}

object JdbcCredentialStatusListRepository {
val layer: URLayer[Transactor[ContextAwareTask] & Transactor[Task], CredentialStatusListRepository] =
ZLayer.fromFunction(new JdbcCredentialStatusListRepository(_, _))
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.circe
import io.circe.generic.auto.*
import io.circe.parser.decode
import io.circe.syntax.*
import io.circe.{Decoder, Encoder, HCursor, Json}
import io.circe.{CursorOp, Decoder, DecodingFailure, Encoder, HCursor, Json}
import io.iohk.atala.castor.core.model.did.VerificationRelationship
import io.iohk.atala.pollux.vc.jwt.schema.{SchemaResolver, SchemaValidator}
import pdi.jwt.*
Expand Down Expand Up @@ -36,9 +36,17 @@ case class JwtVerifiableCredentialPayload(jwt: JWT) extends VerifiableCredential

case class AnoncredVerifiableCredentialPayload(json: String) extends VerifiableCredentialPayload //FIXME json type

enum StatusPurpose(val str: String) {
case Revocation extends StatusPurpose("Revocation")
case Suspension extends StatusPurpose("Suspension")
}

case class CredentialStatus(
id: String,
`type`: String
`type`: String,
statusPurpose: StatusPurpose,
statusListIndex: Int,
statusListCredential: String
)

case class RefreshService(
Expand Down Expand Up @@ -250,10 +258,10 @@ case class JwtCredentialPayload(
case class W3cCredentialPayload(
override val `@context`: Set[String],
override val `type`: Set[String],
val maybeId: Option[String],
val issuer: DID,
val issuanceDate: Instant,
val maybeExpirationDate: Option[Instant],
maybeId: Option[String],
issuer: DID,
issuanceDate: Instant,
maybeExpirationDate: Option[Instant],
override val maybeCredentialSchema: Option[CredentialSchema],
override val credentialSubject: Json,
override val maybeCredentialStatus: Option[CredentialStatus],
Expand Down Expand Up @@ -294,12 +302,17 @@ object CredentialPayload {
("type", credentialSchema.`type`.asJson)
)

implicit val credentialStatusPurposeEncoder: Encoder[StatusPurpose] = (a: StatusPurpose) => a.toString.asJson

implicit val credentialStatusEncoder: Encoder[CredentialStatus] =
(credentialStatus: CredentialStatus) =>
Json
.obj(
("id", credentialStatus.id.asJson),
("type", credentialStatus.`type`.asJson)
("type", credentialStatus.`type`.asJson),
("statusPurpose", credentialStatus.statusPurpose.asJson),
("statusListIndex", credentialStatus.statusListIndex.asJson),
("statusListCredential", credentialStatus.statusListCredential.asJson)
)

implicit val w3cCredentialPayloadEncoder: Encoder[W3cCredentialPayload] =
Expand Down Expand Up @@ -385,13 +398,29 @@ object CredentialPayload {
CredentialSchema(id = id, `type` = `type`)
}

implicit val credentialStatusPurposeDecoder: Decoder[StatusPurpose] = (c: HCursor) =>
Decoder.decodeString(c).flatMap { str =>
Try(StatusPurpose.valueOf(str)).toEither.leftMap { _ =>
DecodingFailure(s"no enum value matched for $str", List(CursorOp.Field(str)))
}
}

implicit val credentialStatusDecoder: Decoder[CredentialStatus] =
(c: HCursor) =>
for {
id <- c.downField("id").as[String]
`type` <- c.downField("type").as[String]
statusPurpose <- c.downField("statusPurpose").as[StatusPurpose]
statusListIndex <- c.downField("statusListIndex").as[Int]
statusListCredential <- c.downField("statusListCredential").as[String]
} yield {
CredentialStatus(id = id, `type` = `type`)
CredentialStatus(
id = id,
`type` = `type`,
statusPurpose = statusPurpose,
statusListIndex = statusListIndex,
statusListCredential = statusListCredential
)
}

implicit val w3cCredentialPayloadDecoder: Decoder[W3cCredentialPayload] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ import java.time.Instant
maybeCredentialStatus = Some(
CredentialStatus(
id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0",
`type` = "CredentialStatusList2017"
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "https://example.com/credentials/status/3"
)
),
maybeRefreshService = Some(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ object JwtCredentialDIDDocumentValidationDemo extends ZIOAppDefault {
maybeCredentialStatus = Some(
CredentialStatus(
id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0",
`type` = "CredentialStatusList2017"
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "https://example.com/credentials/status/3"
)
),
maybeRefreshService = Some(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ import java.time.Instant
maybeCredentialStatus = Some(
CredentialStatus(
id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0",
`type` = "CredentialStatusList2017"
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "https://example.com/credentials/status/3"
)
),
maybeRefreshService = Some(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ import java.time.*
maybeCredentialStatus = Some(
CredentialStatus(
id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0",
`type` = "CredentialStatusList2017"
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "https://example.com/credentials/status/3"
)
),
maybeRefreshService = Some(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ import java.time.Instant
maybeCredentialStatus = Some(
CredentialStatus(
id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0",
`type` = "CredentialStatusList2017"
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "https://example.com/credentials/status/3"
)
),
maybeRefreshService = Some(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ import scala.collection.immutable.Set
maybeCredentialStatus = Some(
CredentialStatus(
id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0",
`type` = "CredentialStatusList2017"
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "https://example.com/credentials/status/3"
)
),
maybeRefreshService = Some(
Expand Down Expand Up @@ -117,7 +120,10 @@ import scala.collection.immutable.Set
maybeCredentialStatus = Some(
CredentialStatus(
id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0",
`type` = "CredentialStatusList2017"
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "https://example.com/credentials/status/3"
)
),
maybeRefreshService = Some(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ object JwtPresentationVerificationDemo extends ZIOAppDefault {
maybeCredentialStatus = Some(
CredentialStatus(
id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0",
`type` = "CredentialStatusList2017"
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "https://example.com/credentials/status/3"
)
),
maybeRefreshService = Some(
Expand Down Expand Up @@ -146,7 +149,10 @@ object JwtPresentationVerificationDemo extends ZIOAppDefault {
maybeCredentialStatus = Some(
CredentialStatus(
id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0",
`type` = "CredentialStatusList2017"
`type` = "StatusList2021Entry",
statusPurpose = StatusPurpose.Revocation,
statusListIndex = 0,
statusListCredential = "https://example.com/credentials/status/3"
)
),
maybeRefreshService = Some(
Expand Down
Loading

0 comments on commit 5aa345b

Please sign in to comment.