Skip to content

Commit

Permalink
feat: VC Verification Abstraction (#959)
Browse files Browse the repository at this point in the history
Signed-off-by: Bassam Riman <bassam.riman@iohk.io>
  • Loading branch information
CryptoKnightIOG committed Apr 16, 2024
1 parent 1e0a1a2 commit 596f8ed
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 35 deletions.
@@ -0,0 +1,37 @@
package io.iohk.atala.pollux.core.service.verification

import io.iohk.atala.pollux.core.service.verification.VcVerificationFailureType.ERROR
import sttp.tapir.Schema
import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder}

enum VcVerificationFailureType {
case WARN extends VcVerificationFailureType
case ERROR extends VcVerificationFailureType
}

enum VcVerification(
val failureType: VcVerificationFailureType
) {
case SignatureVerification extends VcVerification(ERROR)
case IssuerIdentification extends VcVerification(ERROR)
case ExpirationCheck extends VcVerification(ERROR)
case NotBeforeCheck extends VcVerification(ERROR)
case AudienceCheck extends VcVerification(ERROR)
case SubjectVerification extends VcVerification(ERROR)
case IntegrityOfClaims extends VcVerification(ERROR)
case ComplianceWithStandards extends VcVerification(ERROR)
case RevocationCheck extends VcVerification(ERROR)
case AlgorithmVerification extends VcVerification(ERROR)
case SchemaCheck extends VcVerification(ERROR)
case SemanticCheckOfClaims extends VcVerification(ERROR)
}

object VcVerification {
given encoder: JsonEncoder[VcVerification] =
DeriveJsonEncoder.gen[VcVerification]

given decoder: JsonDecoder[VcVerification] =
DeriveJsonDecoder.gen[VcVerification]

given schema: Schema[VcVerification] = Schema.derivedEnumeration.defaultStringBased
}
@@ -0,0 +1,20 @@
package io.iohk.atala.pollux.core.service.verification

import zio.*

trait VcVerificationService {
def verify(request: List[VcVerificationRequest]): IO[VcVerificationServiceError, List[VcVerificationResult]]
}

final case class VcVerificationRequest(
credential: String,
verifications: List[VcVerification]
)

final case class VcVerificationResult(
credential: String,
checks: List[VcVerification],
successfulChecks: List[VcVerification],
failedChecks: List[VcVerification],
failedAsWarningChecks: List[VcVerification]
)
@@ -0,0 +1,9 @@
package io.iohk.atala.pollux.core.service.verification

sealed trait VcVerificationServiceError {
def error: String
}

object VcVerificationServiceError {
final case class UnexpectedError(error: String) extends VcVerificationServiceError
}
@@ -0,0 +1,57 @@
package io.iohk.atala.pollux.core.service.verification

import zio.{IO, *}

class VcVerificationServiceImpl extends VcVerificationService {
override def verify(
vcVerificationRequests: List[VcVerificationRequest]
): IO[VcVerificationServiceError, List[VcVerificationResult]] = {
vcVerificationRequests.map(vcVerificationRequest =>
val verificationOutcomesZIO = ZIO.collectAll(
vcVerificationRequest.verifications
.map(verification => verify(vcVerificationRequest.credential, verification))
)

verificationOutcomesZIO.map(verificationOutcomes => {
val successfulChecks = verificationOutcomes.filter(_.success).map(_.verification)

val failedVerifications = verificationOutcomes.filterNot(_.success).map(_.verification)

val failedAsErrorChecks =
failedVerifications.filter(verification => verification.failureType == VcVerificationFailureType.ERROR)

val failedAsWarningChecks =
failedVerifications.filter(verification => verification.failureType == VcVerificationFailureType.WARN)

VcVerificationResult(
credential = vcVerificationRequest.credential,
checks = vcVerificationRequest.verifications,
successfulChecks = successfulChecks,
failedChecks = failedAsErrorChecks,
failedAsWarningChecks = failedAsWarningChecks
)
})
)
ZIO.succeed(List.empty)
}

private case class VcVerificationOutcome(verification: VcVerification, success: Boolean)
private def verify(
credential: String,
verification: VcVerification
): IO[VcVerificationServiceError, VcVerificationOutcome] = {
verification match {
case VcVerification.SchemaCheck => verifySchema(credential)
case _ => ZIO.fail(VcVerificationServiceError.UnexpectedError(s"Unsupported Verification $verification"))
}
}

private def verifySchema(credential: String): IO[VcVerificationServiceError, VcVerificationOutcome] = {
ZIO.succeed(VcVerificationOutcome(verification = VcVerification.SchemaCheck, success = true))
}
}

object VcVerificationServiceImpl {
val layer: ULayer[VcVerificationService] =
ZLayer.succeed(VcVerificationServiceImpl())
}
Expand Up @@ -30,6 +30,7 @@ import io.iohk.atala.iam.wallet.http.controller.WalletManagementControllerImpl
import io.iohk.atala.issue.controller.IssueControllerImpl
import io.iohk.atala.mercury.*
import io.iohk.atala.pollux.core.service.*
import io.iohk.atala.pollux.core.service.verification.VcVerificationServiceImpl
import io.iohk.atala.pollux.credentialdefinition.controller.CredentialDefinitionControllerImpl
import io.iohk.atala.pollux.credentialschema.controller.{
CredentialSchemaController,
Expand Down Expand Up @@ -169,6 +170,7 @@ object MainApp extends ZIOAppDefault {
LinkSecretServiceImpl.layer >>> PresentationServiceImpl.layer >>> PresentationServiceNotifier.layer,
VerificationPolicyServiceImpl.layer,
WalletManagementServiceImpl.layer,
VcVerificationServiceImpl.layer,
// authentication
AppModule.builtInAuthenticatorLayer,
AppModule.keycloakAuthenticatorLayer,
Expand Down
@@ -1,6 +1,7 @@
package io.iohk.atala.verification.controller

import io.iohk.atala.api.http.{ErrorResponse, RequestContext}
import io.iohk.atala.pollux.core.service.verification.VcVerificationServiceError
import io.iohk.atala.verification.controller
import zio.*

Expand All @@ -10,3 +11,11 @@ trait VcVerificationController {
rc: RequestContext
): IO[ErrorResponse, List[controller.http.VcVerificationResponse]]
}

object VcVerificationController {
def toHttpError(error: VcVerificationServiceError): ErrorResponse =
error match
case VcVerificationServiceError.UnexpectedError(error) =>
ErrorResponse.badRequest(detail = Some(s"VC Verification Failed: $error"))

}
@@ -1,19 +1,46 @@
package io.iohk.atala.verification.controller

import io.iohk.atala.api.http.{ErrorResponse, RequestContext}
import io.iohk.atala.pollux.core.service.verification.{VcVerification, VcVerificationRequest, VcVerificationService}
import io.iohk.atala.verification.controller
import zio.*

class VcVerificationControllerImpl extends VcVerificationController {
class VcVerificationControllerImpl(vcVerificationService: VcVerificationService) extends VcVerificationController {

override def verify(
request: List[controller.http.VcVerificationRequest]
requests: List[controller.http.VcVerificationRequest]
)(implicit rc: RequestContext): IO[ErrorResponse, List[controller.http.VcVerificationResponse]] = {
ZIO.succeed(List.empty)
val serviceRequests =
requests.map(request => {
val verifications =
if (request.verifications.isEmpty)
VcVerification.values.toList
else
request.verifications

VcVerificationRequest(
credential = request.credential,
verifications = verifications
)
})
for {
results <-
vcVerificationService
.verify(serviceRequests)
.mapError(error => VcVerificationController.toHttpError(error))
} yield results.map(result =>
controller.http.VcVerificationResponse(
result.credential,
result.checks,
result.successfulChecks,
result.failedChecks,
result.failedAsWarningChecks
)
)
}
}

object VcVerificationControllerImpl {
val layer: ULayer[VcVerificationController] =
ZLayer.succeed(VcVerificationControllerImpl())
val layer: URLayer[VcVerificationService, VcVerificationController] =
ZLayer.fromFunction(VcVerificationControllerImpl(_))
}

This file was deleted.

@@ -1,6 +1,7 @@
package io.iohk.atala.verification.controller.http

import io.iohk.atala.api.http.Annotation
import io.iohk.atala.pollux.core.service.verification.VcVerification
import sttp.tapir.Schema
import sttp.tapir.Schema.annotations.{description, encodedExample}
import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder}
Expand Down
@@ -1,6 +1,7 @@
package io.iohk.atala.verification.controller.http

import io.iohk.atala.api.http.Annotation
import io.iohk.atala.pollux.core.service.verification.VcVerification
import sttp.tapir.Schema
import sttp.tapir.Schema.annotations.{description, encodedExample}
import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder}
Expand Down

0 comments on commit 596f8ed

Please sign in to comment.