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: Fix Update Schema and CredentialDef on Receive Credential #920

Merged
merged 1 commit into from
Mar 6, 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 @@ -67,6 +67,8 @@ trait CredentialRepository {
recordId: DidCommID,
issue: IssueCredential,
issuedRawCredential: String,
schemaUri: Option[String],
credentialDefinitionUri: Option[String],
protocolState: ProtocolState
): RIO[WalletAccessContext, Int]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ class CredentialRepositoryInMemory(
recordId: DidCommID,
issue: IssueCredential,
issuedRawCredential: String,
schemaUri: Option[String],
credentialDefinitionUri: Option[String],
protocolState: ProtocolState
): RIO[WalletAccessContext, Int] = {
for {
Expand All @@ -111,6 +113,8 @@ class CredentialRepositoryInMemory(
recordId,
record.copy(
updatedAt = Some(Instant.now),
schemaUri = schemaUri,
credentialDefinitionUri = credentialDefinitionUri,
issueCredentialData = Some(issue),
issuedCredentialRaw = Some(issuedRawCredential),
protocolState = protocolState,
Expand Down Expand Up @@ -149,7 +153,7 @@ class CredentialRepositoryInMemory(
rec.id
) && rec.issueCredentialData.isDefined
&& rec.schemaUri.isDefined
&& rec.credentialDefinitionId.isDefined
&& rec.credentialDefinitionUri.isDefined
&& rec.credentialFormat == CredentialFormat.AnonCreds
)
.map(rec =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,67 +607,86 @@ private class CredentialServiceImpl(

override def receiveCredentialIssue(
issueCredential: IssueCredential
): ZIO[WalletAccessContext, CredentialServiceError, IssueCredentialRecord] = {
for {
// TODO Move this type of generic/reusable code to a helper trait
record <- getRecordFromThreadIdWithState(
issueCredential.thid.map(DidCommID(_)),
ignoreWithZeroRetries = true,
ProtocolState.RequestPending,
ProtocolState.RequestSent
): ZIO[WalletAccessContext, CredentialServiceError, IssueCredentialRecord] = for {
// TODO Move this type of generic/reusable code to a helper trait
record <- getRecordFromThreadIdWithState(
issueCredential.thid.map(DidCommID(_)),
ignoreWithZeroRetries = true,
ProtocolState.RequestPending,
ProtocolState.RequestSent
)
attachment <- ZIO
.fromOption(issueCredential.attachments.headOption)
.mapError(_ => CredentialServiceError.UnexpectedError("Missing attachment in credential issued credential"))

_ <- {
val result = attachment match {
case AttachmentDescriptor(
id,
media_type,
Base64(v),
Some(IssueCredentialIssuedFormat.Anoncred.name),
_,
_,
_,
_
) =>
for {
processedCredential <- processAnonCredsCredential(record, java.util.Base64.getUrlDecoder.decode(v))
attachment = AttachmentDescriptor.buildBase64Attachment(
id = id,
mediaType = media_type,
format = Some(IssueCredentialIssuedFormat.Anoncred.name),
payload = processedCredential.data.getBytes
)
processedIssuedCredential = issueCredential.copy(attachments = Seq(attachment))
result <-
updateWithCredential(
processedIssuedCredential,
record,
attachment,
Some(processedCredential.getSchemaId),
Some(processedCredential.getCredDefId)
)
} yield result
case attachment =>
updateWithCredential(issueCredential, record, attachment, None, None)
}
result
}
record <- credentialRepository
.getIssueCredentialRecord(record.id)
.mapError(RepositoryError.apply)
.someOrFail(RecordIdNotFound(record.id))
} yield record

private def updateWithCredential(
issueCredential: IssueCredential,
record: IssueCredentialRecord,
attachment: AttachmentDescriptor,
schemaId: Option[String],
credDefId: Option[String]
) = {
credentialRepository
.updateWithIssuedRawCredential(
record.id,
issueCredential,
attachment.data.asJson.noSpaces,
schemaId,
credDefId,
ProtocolState.CredentialReceived
)
processedAttachments <- {
import IssueCredentialIssuedFormat.Anoncred
ZIO.collectAll(
issueCredential.attachments
.map {
case AttachmentDescriptor(
id,
media_type,
Base64(v),
Some(Anoncred.name),
_,
_,
_,
_
) =>
processAnonCredsCredential(record, java.util.Base64.getUrlDecoder.decode(v))
.map(processedCredential =>
AttachmentDescriptor.buildBase64Attachment(
id = id,
mediaType = media_type,
format = Some(IssueCredentialIssuedFormat.Anoncred.name),
payload = processedCredential
)
)
case attachment => ZIO.succeed(attachment)
}
)
.flatMap {
case 1 => ZIO.succeed(())
case n => ZIO.fail(UnexpectedException(s"Invalid row count result: $n"))
}
processedIssuedCredential = issueCredential.copy(attachments = processedAttachments)
_ <- credentialRepository
.updateWithIssuedRawCredential(
record.id,
processedIssuedCredential,
processedIssuedCredential.attachments.map(_.data.asJson.noSpaces).headOption.getOrElse("???"),
ProtocolState.CredentialReceived
)
.flatMap {
case 1 => ZIO.succeed(())
case n => ZIO.fail(UnexpectedException(s"Invalid row count result: $n"))
}
.mapError(RepositoryError.apply)
record <- credentialRepository
.getIssueCredentialRecord(record.id)
.mapError(RepositoryError.apply)
.someOrFail(RecordIdNotFound(record.id))
} yield record
.mapError(RepositoryError.apply)
}

private[this] def processAnonCredsCredential(
record: IssueCredentialRecord,
credentialBytes: Array[Byte]
): ZIO[WalletAccessContext, CredentialServiceError, Array[Byte]] = {
): ZIO[WalletAccessContext, CredentialServiceError, anoncreds.AnoncredCredential] = {
for {
credential <- ZIO.succeed(anoncreds.AnoncredCredential(new String(credentialBytes)))
credDefContent <- uriDereferencer
Expand All @@ -690,7 +709,7 @@ private class CredentialServiceImpl(
)
)
.mapError(error => UnexpectedError(s"AnonCreds credential processing error: ${error.getMessage}"))
} yield credential.data.getBytes()
} yield credential
}

override def markOfferSent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,15 +173,13 @@ object MockPresentationService extends Mock[PresentationService] {

override def createAnoncredPresentationPayloadFromRecord(
record: DidCommID,
issuer: Issuer,
anoncredCredentialProof: AnoncredCredentialProofsV1,
issuanceDate: Instant
): IO[PresentationError, AnoncredPresentation] = ???

override def createAnoncredPresentation(
requestPresentation: RequestPresentation,
recordId: DidCommID,
prover: Issuer,
anoncredCredentialProof: AnoncredCredentialProofsV1,
issuanceDate: Instant
): ZIO[WalletAccessContext, PresentationError, Presentation] = ???
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,13 @@ trait PresentationService {

def createAnoncredPresentationPayloadFromRecord(
record: DidCommID,
issuer: Issuer,
anoncredCredentialProof: AnoncredCredentialProofsV1,
issuanceDate: Instant
): ZIO[WalletAccessContext, PresentationError, AnoncredPresentation]

def createAnoncredPresentation(
requestPresentation: RequestPresentation,
recordId: DidCommID,
prover: Issuer,
anoncredCredentialProof: AnoncredCredentialProofsV1,
issuanceDate: Instant
): ZIO[WalletAccessContext, PresentationError, Presentation]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ private class PresentationServiceImpl(

override def createAnoncredPresentationPayloadFromRecord(
recordId: DidCommID,
prover: Issuer,
anoncredCredentialProof: AnoncredCredentialProofsV1,
issuanceDate: Instant
): ZIO[WalletAccessContext, PresentationError, AnoncredPresentation] = {
Expand Down Expand Up @@ -151,15 +150,13 @@ private class PresentationServiceImpl(
def createAnoncredPresentation(
requestPresentation: RequestPresentation,
recordId: DidCommID,
prover: Issuer,
anoncredCredentialProof: AnoncredCredentialProofsV1,
issuanceDate: Instant
): ZIO[WalletAccessContext, PresentationError, Presentation] = {
for {
presentationPayload <-
createAnoncredPresentationPayloadFromRecord(
recordId,
prover,
anoncredCredentialProof,
issuanceDate
)
Expand Down Expand Up @@ -605,10 +602,10 @@ private class PresentationServiceImpl(
issuedCredentials <- credentialRepository
.getValidIssuedCredentials(credentialsToUse.map(DidCommID(_)))
.mapError(RepositoryError.apply)
validatedCredentialsFormat <- validateCredentialsFormat(record, issuedCredentials)
_ <- validateCredentials(
s"No matching issued credentials found in prover db from the given: $credentialsToUse",
record,
issuedCredentials
validatedCredentialsFormat
)
count <- presentationRepository
.updatePresentationWithCredentialsToUse(recordId, Option(credentialsToUse), ProtocolState.PresentationPending)
Expand Down Expand Up @@ -641,13 +638,13 @@ private class PresentationServiceImpl(

for {
record <- getRecordWithState(recordId, ProtocolState.RequestReceived)
issuedCredentials <- credentialRepository
.getValidIssuedCredentials(
credentialsToUse.credentialProofs.map(credentialProof => DidCommID(credentialProof.credential))
)
.mapError(RepositoryError.apply)
_ <- validateCredentials(
s"No matching issued credentials found in prover db from the given: $credentialsToUse",
issuedCredentials <-
credentialRepository
.getValidAnoncredIssuedCredentials(
credentialsToUse.credentialProofs.map(credentialProof => DidCommID(credentialProof.credential))
)
.mapError(RepositoryError.apply)
_ <- validateFullCredentialsFormat(
record,
issuedCredentials
)
Expand Down Expand Up @@ -676,6 +673,23 @@ private class PresentationServiceImpl(

private def validateCredentials(
errorMessage: String,
issuedCredentials: Seq[ValidIssuedCredentialRecord]
) = {
val issuedCredentialRaw = issuedCredentials.flatMap(_.issuedCredentialRaw)
for {
_ <- ZIO.fromEither(
Either.cond(
issuedCredentialRaw.nonEmpty,
issuedCredentialRaw,
PresentationError.IssuedCredentialNotFoundError(
new Throwable(errorMessage)
)
)
)
} yield ()
}

private def validateCredentialsFormat(
record: PresentationRecord,
issuedCredentials: Seq[ValidIssuedCredentialRecord]
) = {
Expand All @@ -701,19 +715,17 @@ private class PresentationServiceImpl(
)
)
)
signedCredentials = validatedCredentials.flatMap(_.issuedCredentialRaw)
_ <- ZIO.fromEither(
Either.cond(
signedCredentials.nonEmpty,
signedCredentials,
PresentationError.IssuedCredentialNotFoundError(
new Throwable(errorMessage)
)
)
)
} yield ()
} yield validatedCredentials
}

private def validateFullCredentialsFormat(
record: PresentationRecord,
issuedCredentials: Seq[ValidFullIssuedCredentialRecord]
) = validateCredentialsFormat(
record,
issuedCredentials.map(cred => ValidIssuedCredentialRecord(cred.id, None, cred.credentialFormat, cred.subjectId))
)

override def acceptPresentation(
recordId: DidCommID
): ZIO[WalletAccessContext, PresentationError, PresentationRecord] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,20 +169,18 @@ class PresentationServiceNotifier(

override def createAnoncredPresentationPayloadFromRecord(
record: DidCommID,
issuer: Issuer,
anoncredCredentialProof: AnoncredCredentialProofsV1,
issuanceDate: Instant
): ZIO[WalletAccessContext, PresentationError, AnoncredPresentation] =
svc.createAnoncredPresentationPayloadFromRecord(record, issuer, anoncredCredentialProof, issuanceDate)
svc.createAnoncredPresentationPayloadFromRecord(record, anoncredCredentialProof, issuanceDate)

override def createAnoncredPresentation(
requestPresentation: RequestPresentation,
recordId: DidCommID,
prover: Issuer,
anoncredCredentialProof: AnoncredCredentialProofsV1,
issuanceDate: Instant
): ZIO[WalletAccessContext, PresentationError, Presentation] =
svc.createAnoncredPresentation(requestPresentation, recordId, prover, anoncredCredentialProof, issuanceDate)
svc.createAnoncredPresentation(requestPresentation, recordId, anoncredCredentialProof, issuanceDate)

override def getPresentationRecordsByStates(
ignoreWithZeroRetries: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,16 @@ object CredentialRepositorySpecSuite {
aRecord.id,
IssueCredential.makeIssueCredentialFromRequestCredential(requestCredential.makeMessage),
"RAW_CREDENTIAL_DATA",
None,
None,
ProtocolState.CredentialReceived
)
_ <- repo.updateWithIssuedRawCredential(
dRecord.id,
IssueCredential.makeIssueCredentialFromRequestCredential(requestCredential.makeMessage),
"RAW_CREDENTIAL_DATA",
None,
None,
ProtocolState.CredentialReceived
)
records <- repo.getValidIssuedCredentials(Seq(aRecord.id, bRecord.id, dRecord.id))
Expand Down Expand Up @@ -387,6 +391,8 @@ object CredentialRepositorySpecSuite {
aRecord.id,
issueCredential,
"RAW_CREDENTIAL_DATA",
Some("schemaUri"),
Some("credentialDefinitionUri"),
ProtocolState.CredentialReceived
)
updatedRecord <- repo.getIssueCredentialRecord(aRecord.id)
Expand All @@ -395,6 +401,8 @@ object CredentialRepositorySpecSuite {
assertTrue(record.get.issueCredentialData.isEmpty) &&
assertTrue(updatedRecord.get.issueCredentialData.contains(issueCredential)) &&
assertTrue(updatedRecord.get.issuedCredentialRaw.contains("RAW_CREDENTIAL_DATA"))
assertTrue(updatedRecord.get.credentialDefinitionUri.contains("credentialDefinitionUri"))
assertTrue(updatedRecord.get.schemaUri.contains("schemaUri"))
}
},
test("updateFail (fail one retry) updates record") {
Expand Down
Loading
Loading