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: connection less presentation expiration time #1294

Merged
merged 4 commits into from
Aug 20, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pollux {
syncRevocationStatusesBgJobProcessingParallelism = ${?SYNC_REVOCATION_STATUSES_BG_JOB_PROCESSING_PARALLELISM}
credential.sdJwt.expiry = 30 days
credential.sdJwt.expiry = ${?CREDENTIAL_SD_JWT_EXPIRY}
presentationInvitationExpiry = 300 seconds
presentationInvitationExpiry = ${?PRESENTATION_INVITATION_EXPIRY}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mineme0110, don't forget to add a new environment variable to the documentation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yshyn-iohk Yes I have ticket for documentation I will remember about this

}

connect {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ final case class PolluxConfig(
presentationBgJobProcessingParallelism: Int,
syncRevocationStatusesBgJobRecurrenceDelay: Duration,
syncRevocationStatusesBgJobProcessingParallelism: Int,
presentationInvitationExpiry: Duration,
)
final case class ConnectConfig(
database: DatabaseConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.hyperledger.identus.castor.core.model.error.DIDResolutionError as Cas
import org.hyperledger.identus.castor.core.service.DIDService
import org.hyperledger.identus.mercury.*
import org.hyperledger.identus.mercury.model.*
import org.hyperledger.identus.mercury.protocol.invitation.v2.Invitation
import org.hyperledger.identus.mercury.protocol.presentproof.*
import org.hyperledger.identus.mercury.protocol.reportproblem.v2.{ProblemCode, ReportProblem}
import org.hyperledger.identus.pollux.core.model.*
Expand Down Expand Up @@ -436,7 +437,7 @@ object PresentBackgroundJobs extends BackgroundJobsHelper {
_,
PresentationReceived,
credentialFormat,
_,
invitation,
Some(requestPresentation),
_,
Some(presentation),
Expand All @@ -450,7 +451,7 @@ object PresentBackgroundJobs extends BackgroundJobsHelper {
_
) => // Verifier
ZIO.logDebug("PresentationRecord: PresentationReceived") *> ZIO.unit
Verifier.PresentationReceived.handle(id, requestPresentation, presentation, credentialFormat)
Verifier.PresentationReceived.handle(id, requestPresentation, presentation, credentialFormat, invitation)

case PresentationRecord(
id,
Expand Down Expand Up @@ -893,29 +894,51 @@ object PresentBackgroundJobs extends BackgroundJobsHelper {
id: DidCommID,
requestPresentation: RequestPresentation,
presentation: Presentation,
credentialFormat: CredentialFormat
credentialFormat: CredentialFormat,
invitation: Option[Invitation]
): ZIO[
AppConfig & JwtDidResolver & COMMON_RESOURCES & MESSAGING_RESOURCES,
Failure,
Unit
] = {
val result =
credentialFormat match {
case CredentialFormat.JWT => handleJWT(id, requestPresentation, presentation)
case CredentialFormat.SDJWT => handleSDJWT(id, presentation)
case CredentialFormat.AnonCreds => handleAnoncred(id, requestPresentation, presentation)
case CredentialFormat.JWT => handleJWT(id, requestPresentation, presentation, invitation)
case CredentialFormat.SDJWT => handleSDJWT(id, presentation, invitation)
case CredentialFormat.AnonCreds => handleAnoncred(id, requestPresentation, presentation, invitation)
}
result @@ metric
}

private def handleJWT(id: DidCommID, requestPresentation: RequestPresentation, presentation: Presentation): ZIO[
private def checkInvitationExpiry(
id: DidCommID,
invitation: Option[Invitation]
): ZIO[PresentationService & WalletAccessContext, PresentationError, Unit] = {
invitation.flatMap(_.expires_time) match {
case Some(expiryTime) if Instant.now().getEpochSecond > expiryTime =>
for {
service <- ZIO.service[PresentationService]
_ <- service.markPresentationInvitationExpired(id)
_ <- ZIO.fail(PresentationError.InvitationExpired(s"Invitation has expired. Expiry time: $expiryTime"))
} yield ()
case _ => ZIO.unit
}
}

private def handleJWT(
id: DidCommID,
requestPresentation: RequestPresentation,
presentation: Presentation,
invitation: Option[Invitation]
): ZIO[
AppConfig & JwtDidResolver & COMMON_RESOURCES & MESSAGING_RESOURCES,
Failure,
Unit
] = {
val clock = java.time.Clock.system(ZoneId.systemDefault)
for {
walletAccessContext <- buildWalletAccessContextLayer(presentation.to)
_ <- checkInvitationExpiry(id, invitation).provideSomeLayer(ZLayer.succeed(walletAccessContext))
result <- for {
didResolverService <- ZIO.service[JwtDidResolver]
credentialsClaimsValidationResult <- presentation.attachments.head.data match {
Expand Down Expand Up @@ -1022,13 +1045,14 @@ object PresentBackgroundJobs extends BackgroundJobsHelper {
} yield result
}

private def handleSDJWT(id: DidCommID, presentation: Presentation): ZIO[
private def handleSDJWT(id: DidCommID, presentation: Presentation, invitation: Option[Invitation]): ZIO[
JwtDidResolver & COMMON_RESOURCES & MESSAGING_RESOURCES,
Failure,
Unit
] = {
for {
walletAccessContext <- buildWalletAccessContextLayer(presentation.to)
_ <- checkInvitationExpiry(id, invitation).provideSomeLayer(ZLayer.succeed(walletAccessContext))
result <- for {
didResolverService <- ZIO.service[JwtDidResolver]
credentialsClaimsValidationResult <- presentation.attachments.head.data match {
Expand Down Expand Up @@ -1090,20 +1114,22 @@ object PresentBackgroundJobs extends BackgroundJobsHelper {
private def handleAnoncred(
id: DidCommID,
requestPresentation: RequestPresentation,
presentation: Presentation
presentation: Presentation,
invitation: Option[Invitation]
): ZIO[
PresentationService & DIDNonSecretStorage & MESSAGING_RESOURCES,
PresentationError | DIDSecretStorageError,
Unit
] = {
for {
walletAccessContext <- buildWalletAccessContextLayer(presentation.to)
presReceivedToProcessedAspect = CustomMetricsAspect.endRecordingTime(
s"${id}_present_proof_flow_verifier_presentation_received_to_verification_success_or_failure_ms_gauge",
"present_proof_flow_verifier_presentation_received_to_verification_success_or_failure_ms_gauge"
)
_ <- checkInvitationExpiry(id, invitation).provideSomeLayer(ZLayer.succeed(walletAccessContext))
result <- for {
service <- ZIO.service[PresentationService]
presReceivedToProcessedAspect = CustomMetricsAspect.endRecordingTime(
s"${id}_present_proof_flow_verifier_presentation_received_to_verification_success_or_failure_ms_gauge",
"present_proof_flow_verifier_presentation_received_to_verification_success_or_failure_ms_gauge"
)
_ <- (service
.verifyAnoncredPresentation(presentation, requestPresentation, id)
.provideSomeLayer(ZLayer.succeed(walletAccessContext)) @@ presReceivedToProcessedAspect)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class PresentProofControllerImpl(
req.claims,
req.anoncredPresentationRequest,
None,
None,
None
)
case req: OOBRequestPresentationInput =>
Expand All @@ -92,7 +93,8 @@ class PresentProofControllerImpl(
req.claims,
req.anoncredPresentationRequest,
req.goalCode,
req.goal
req.goal,
Some(appConfig.pollux.presentationInvitationExpiry)
)
}
}
Expand All @@ -107,7 +109,8 @@ class PresentProofControllerImpl(
claims: Option[zio.json.ast.Json.Obj],
anoncredPresentationRequest: Option[AnoncredPresentationRequestV1],
goalCode: Option[String],
goal: Option[String]
goal: Option[String],
expirationDuration: Option[Duration],
): ZIO[WalletAccessContext, PresentationError, PresentationRecord] = {
val format = credentialFormat.map(CredentialFormat.valueOf).getOrElse(CredentialFormat.JWT)
format match {
Expand All @@ -126,7 +129,8 @@ class PresentProofControllerImpl(
},
options = options,
goalCode = goalCode,
goal = goal
goal = goal,
expirationDuration = expirationDuration,
)
case CredentialFormat.SDJWT =>
claims match {
Expand All @@ -146,7 +150,8 @@ class PresentProofControllerImpl(
claimsToDisclose = claimsToDisclose,
options = options,
goalCode = goalCode,
goal = goal
goal = goal,
expirationDuration = expirationDuration,
)
case None =>
ZIO.fail(
Expand All @@ -165,7 +170,8 @@ class PresentProofControllerImpl(
connectionId = connectionId,
presentationRequest = presentationRequest,
goalCode = goalCode,
goal = goal
goal = goal,
expirationDuration = expirationDuration,
)
case None =>
ZIO.fail(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ final case class Invitation(
`type`: PIURI = Invitation.`type`,
from: DidId,
body: Invitation.Body,
attachments: Option[Seq[AttachmentDescriptor]] = None
attachments: Option[Seq[AttachmentDescriptor]] = None,
created_time: Option[Long] = None,
expires_time: Option[Long] = None,
) {
assert(`type` == "https://didcomm.org/out-of-band/2.0/invitation")
def toBase64: String = java.util.Base64.getUrlEncoder.encodeToString(this.asJson.deepDropNullValues.noSpaces.getBytes)

}

object Invitation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,26 @@ package org.hyperledger.identus.mercury.protocol.presentproof

import org.hyperledger.identus.mercury.model.{AttachmentDescriptor, DidId}
import org.hyperledger.identus.mercury.protocol.invitation.v2.Invitation
import zio.Duration

import java.time.Instant

object PresentProofInvitation {
def makeInvitation(
from: DidId,
goalCode: Option[String],
goal: Option[String],
invitationId: String,
requestPresentation: RequestPresentation
requestPresentation: RequestPresentation,
expirationDuration: Option[Duration] = None,
): Invitation = {
val attachmentDescriptor = AttachmentDescriptor.buildJsonAttachment(payload = requestPresentation)
val now = Instant.now
Invitation(
id = invitationId,
from = from,
created_time = Some(now.getEpochSecond),
expires_time = expirationDuration.map(now.plus(_).getEpochSecond),
body = Invitation.Body(
goal_code = goalCode,
goal = goal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ object PresentationError {
cause
)

final case class InvitationExpired(msg: String)
extends PresentationError(
StatusCode.BadRequest,
msg
)

final case class InvitationAlreadyReceived(msg: String)
extends PresentationError(
StatusCode.BadRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ trait PresentationService {
options: Option[org.hyperledger.identus.pollux.core.model.presentation.Options],
goalCode: Option[String],
goal: Option[String],
expirationDuration: Option[Duration],
): ZIO[WalletAccessContext, PresentationError, PresentationRecord]

def createSDJWTPresentationRecord(
Expand All @@ -40,6 +41,7 @@ trait PresentationService {
options: Option[org.hyperledger.identus.pollux.core.model.presentation.Options],
goalCode: Option[String],
goal: Option[String],
expirationDuration: Option[Duration],
): ZIO[WalletAccessContext, PresentationError, PresentationRecord]

def createAnoncredPresentationRecord(
Expand All @@ -50,6 +52,7 @@ trait PresentationService {
presentationRequest: AnoncredPresentationRequestV1,
goalCode: Option[String],
goal: Option[String],
expirationDuration: Option[Duration],
): ZIO[WalletAccessContext, PresentationError, PresentationRecord]

def getPresentationRecords(
Expand Down Expand Up @@ -180,4 +183,8 @@ trait PresentationService {
pairwiseProverDID: DidId,
invitation: String
): ZIO[WalletAccessContext, PresentationError, RequestPresentation]

def markPresentationInvitationExpired(
recordId: DidCommID
): ZIO[WalletAccessContext, PresentationError, PresentationRecord]
}
Loading
Loading