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(prism-agnet): Verifiable Credential #281

Merged
merged 1 commit into from
Dec 20, 2022
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
2 changes: 1 addition & 1 deletion infrastructure/local/.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MERCURY_MEDIATOR_VERSION=0.2.0
IRIS_SERVICE_VERSION=0.1.0
PRISM_AGENT_VERSION=0.22.0
PRISM_NODE_VERSION=2.0.0
PRISM_NODE_VERSION=v2.0.0
PORT=80
8 changes: 6 additions & 2 deletions prism-agent/service/api/http/pollux/schemas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -540,16 +540,20 @@ components:
type: string
PresentationStatus:
description: Presentation Status
required: [presentationId, status, proofs]
required: [presentationId, status, proofs, data]
properties:
presentationId:
type: string
status:
type: string
proofs:
type: array
type: array
items:
$ref: "#/components/schemas/ProofRequestAux"
data:
type: array
items:
type: string
connectionId:
type: string
RequestPresentationAction:
Expand Down
2 changes: 1 addition & 1 deletion prism-agent/service/project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object Dependencies {
val akka = "2.6.20"
val akkaHttp = "10.2.9"
val castor = "0.5.1"
val pollux = "0.13.0"
val pollux = "0.14.0"
val connect = "0.6.0"
val bouncyCastle = "1.70"
val logback = "1.4.5"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ object Main extends ZIOAppDefault {

app <- appComponents(didCommServicePort, restServicePort).provide(
didCommAgentLayer(didCommServiceUrl),
AppModule.didJwtResolverlayer,
AppModule.didServiceLayer,
DIDResolver.layer,
ZioHttpClient.layer,
AppModule.credentialServiceLayer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ import io.circe.DecodingFailure
import io.iohk.atala.agent.walletapi.sql.JdbcDIDSecretStorage
import io.iohk.atala.resolvers.DIDResolver
import io.iohk.atala.agent.walletapi.storage.DIDSecretStorage
import io.iohk.atala.pollux.vc.jwt.{DidResolver => JwtDidResolver}
import io.iohk.atala.castor.core.model.error.DIDOperationError.TooManyDidServiceAccess
import io.iohk.atala.pollux.vc.jwt.PrismDidResolver

object Modules {

Expand Down Expand Up @@ -153,13 +156,16 @@ object Modules {
Server.start(port, app)
}

val didCommExchangesJob
: RIO[DIDResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage, Unit] =
val didCommExchangesJob: RIO[
DIDResolver & JwtDidResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage,
Unit
] =
BackgroundJobs.didCommExchanges
.repeat(Schedule.spaced(10.seconds))
.unit

val presentProofExchangeJob: RIO[DIDResolver & HttpClient & PresentationService & ManagedDIDService, Unit] =
val presentProofExchangeJob
: RIO[DIDResolver & JwtDidResolver & HttpClient & PresentationService & ManagedDIDService, Unit] =
BackgroundJobs.presentProofExchanges
.repeat(Schedule.spaced(10.seconds))
.unit
Expand Down Expand Up @@ -397,6 +403,9 @@ object SystemModule {
object AppModule {
val didOpValidatorLayer: ULayer[DIDOperationValidator] = DIDOperationValidator.layer()

val didJwtResolverlayer: URLayer[DIDService, JwtDidResolver] =
ZLayer.fromFunction(PrismDidResolver(_))

val didServiceLayer: TaskLayer[DIDService] =
(didOpValidatorLayer ++ GrpcModule.layers) >>> DIDServiceImpl.layer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
given RootJsonFormat[ProofRequestAux] = jsonFormat2(ProofRequestAux.apply)
given RootJsonFormat[RequestPresentationInput] = jsonFormat2(RequestPresentationInput.apply)
given RootJsonFormat[RequestPresentationOutput] = jsonFormat1(RequestPresentationOutput.apply)
given RootJsonFormat[PresentationStatus] = jsonFormat4(PresentationStatus.apply)
given RootJsonFormat[PresentationStatus] = jsonFormat5(PresentationStatus.apply)
given RootJsonFormat[RequestPresentationAction] = jsonFormat2(RequestPresentationAction.apply)

// Connections Management
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import io.iohk.atala.agent.openapi.model.*
import akka.http.scaladsl.server.Directives.*
import akka.http.scaladsl.marshalling.ToEntityMarshaller
import akka.http.scaladsl.server.Route

import zio._
import scala.concurrent.Future
import io.iohk.atala.agent.server.http.model.HttpServiceError
Expand All @@ -24,6 +23,7 @@ import io.iohk.atala.pollux.vc.jwt.Issuer
import io.iohk.atala.pollux.core.service.PresentationService
import io.iohk.atala.pollux.core.model.error.PresentationError
import io.iohk.atala.pollux.core.model.PresentationRecord
import io.iohk.atala.mercury.model.Base64

class PresentProofApiServiceImpl(
presentationService: PresentationService,
Expand Down Expand Up @@ -88,7 +88,18 @@ class PresentProofApiServiceImpl(

presentationStatus = records.map { record =>
val connectionId = record.connectionId
PresentationStatus(record.id.toString, record.protocolState.toString, Seq.empty, connectionId)
val data = record.presentationData match
case Some(p) =>
p.attachments.head.data match {
case Base64(data) =>
val base64Decoded = new String(java.util.Base64.getDecoder().decode(data)).drop(1).dropRight(1)
println(s"Base64decode:\n\n ${base64Decoded} \n\n")
Seq(base64Decoded)
case any => ???
}
case None => Seq.empty

PresentationStatus(record.id.toString, record.protocolState.toString, Seq.empty, data, connectionId)
}
} yield presentationStatus

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import io.iohk.atala.pollux.core.model.IssueCredentialRecord
import io.iohk.atala.pollux.core.model.error.CredentialServiceError
import io.iohk.atala.pollux.core.service.CredentialService
import io.iohk.atala.pollux.vc.jwt.W3cCredentialPayload
import zio.*

import zio.Duration
import java.time.Instant

import java.time.Clock
import java.time.ZoneId
import io.iohk.atala.mercury.DidComm
import io.iohk.atala.mercury.MediaTypes
import io.iohk.atala.mercury.MessagingService
Expand All @@ -22,7 +22,7 @@ import io.iohk.atala.mercury.protocol.presentproof.RequestPresentation
import io.iohk.atala.resolvers.DIDResolver
import io.iohk.atala.resolvers.UniversalDidResolver
import java.io.IOException

import io.iohk.atala.pollux.vc.jwt._
import zhttp.service._
import zhttp.http._
import io.iohk.atala.pollux.vc.jwt.W3CCredential
Expand All @@ -37,7 +37,7 @@ import io.iohk.atala.agent.walletapi.model.error.DIDSecretStorageError
import io.iohk.atala.agent.walletapi.model.ManagedDIDTemplate
import io.iohk.atala.agent.walletapi.sql.JdbcDIDSecretStorage
import io.iohk.atala.pollux.vc.jwt.ES256KSigner
import io.iohk.atala.castor.core.model.did.EllipticCurve
import io.iohk.atala.castor.core.model.did._
import java.security.KeyFactory
import java.security.spec.EncodedKeySpec
import java.security.spec.ECPrivateKeySpec
Expand All @@ -53,6 +53,9 @@ import io.circe.Json
import io.circe.syntax._
import io.iohk.atala.agent.walletapi.storage.DIDSecretStorage
import io.iohk.atala.agent.walletapi.model.error.CreateManagedDIDError
import io.iohk.atala.pollux.vc.jwt.JWT
import io.iohk.atala.pollux.vc.jwt.{DidResolver => JwtDidResolver}
import io.iohk.atala.agent.walletapi.model._

object BackgroundJobs {

Expand All @@ -77,7 +80,10 @@ object BackgroundJobs {

private[this] def performExchange(
record: IssueCredentialRecord
): URIO[DIDResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage, Unit] = {
): URIO[
DIDResolver & JwtDidResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage,
Unit
] = {
import IssueCredentialRecord._
import IssueCredentialRecord.ProtocolState._
import IssueCredentialRecord.PublicationState._
Expand Down Expand Up @@ -249,9 +255,16 @@ object BackgroundJobs {
private[this] def createPrismDIDIssuer(): ZIO[ManagedDIDService & DIDSecretStorage, Throwable, Issuer] = {
for {
managedDIDService <- ZIO.service[ManagedDIDService]
longFormPrismDID <- managedDIDService.createAndStoreDID(ManagedDIDTemplate(Nil, Nil))
longFormPrismDID <- managedDIDService.createAndStoreDID(
ManagedDIDTemplate(
Seq(
DIDPublicKeyTemplate("issuing", VerificationRelationship.Authentication)
),
Nil
)
)
didSecretStorage <- ZIO.service[DIDSecretStorage]
maybeECKeyPair <- didSecretStorage.getKey(longFormPrismDID.asCanonical, "master0")
maybeECKeyPair <- didSecretStorage.getKey(longFormPrismDID.asCanonical, "issuing")
_ <- ZIO.logInfo(s"ECKeyPair => $maybeECKeyPair")
maybeIssuer <- ZIO.succeed(maybeECKeyPair.map(ecKeyPair => {
val ba = ecKeyPair.privateKey.toPaddedByteArray(EllipticCurve.SECP256K1)
Expand Down Expand Up @@ -284,7 +297,7 @@ object BackgroundJobs {

private[this] def performPresentation(
record: PresentationRecord
): URIO[DIDResolver & HttpClient & PresentationService & ManagedDIDService, Unit] = {
): URIO[DIDResolver & JwtDidResolver & HttpClient & PresentationService & ManagedDIDService, Unit] = {
import io.iohk.atala.pollux.core.model.PresentationRecord.ProtocolState._

val aux = for {
Expand Down Expand Up @@ -332,14 +345,43 @@ object BackgroundJobs {
} yield ()
case PresentationRecord(id, _, _, _, _, _, _, _, PresentationSent, _, _, _) =>
ZIO.logDebug("PresentationRecord: PresentationSent") *> ZIO.unit
case PresentationRecord(id, _, _, _, _, _, _, _, PresentationReceived, _, _, _) =>
case PresentationRecord(id, _, _, _, _, _, _, _, PresentationReceived, _, _, presentation) => // Verifier
ZIO.logDebug("PresentationRecord: PresentationReceived") *> ZIO.unit
for {
_ <- ZIO.log(s"PresentationRecord: PresentationPending (Send Massage)")
// TODO Verify https://input-output.atlassian.net/browse/ATL-2702
service <- ZIO.service[PresentationService]
_ <- service.markPresentationVerified(id)
} yield ()
val clock = java.time.Clock.system(ZoneId.systemDefault)
presentation match
case None => ZIO.fail(InvalidState("PresentationRecord in 'PresentationReceived' with no Presentation"))
case Some(p) =>
for {
_ <- ZIO.log(s"PresentationRecord: 'PresentationReceived' ")
didResolverService <- ZIO.service[JwtDidResolver]
credentialsValidationResult <- p.attachments.head.data match {
case Base64(data) =>
val base64Decoded = new String(java.util.Base64.getDecoder().decode(data)).drop(1).dropRight(1)

println(s"Base64decode:\n\n ${base64Decoded} \n\n")
JwtPresentation.verify(
JWT(base64Decoded),
JwtPresentation.PresentationVerificationOptions(
maybeProofPurpose = Some(VerificationRelationship.Authentication),
verifySignature = false,
verifyDates = true,
leeway = Duration.Zero,
maybeCredentialOptions = Some(
CredentialVerification.CredentialVerificationOptions(
verifySignature = true,
verifyDates = false,
leeway = Duration.Zero,
maybeProofPurpose = Some(VerificationRelationship.Authentication)
)
)
)
)(didResolverService)(clock)
case any => ZIO.fail(NotImplemented)
}
_ <- ZIO.log(s"CredentialsValidationResult: $credentialsValidationResult")
service <- ZIO.service[PresentationService]
_ <- service.markPresentationVerified(id)
} yield ()
// TODO move the state to PresentationVerified
case PresentationRecord(id, _, _, _, _, _, _, _, PresentationVerified, _, _, _) =>
ZIO.logDebug("PresentationRecord: PresentationVerified") *> ZIO.unit
Expand Down
2 changes: 1 addition & 1 deletion prism-agent/service/version.sbt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ThisBuild / version := "0.9.0-SNAPSHOT"
ThisBuild / version := "0.17.0-SNAPSHOT"