Skip to content

Commit

Permalink
Merge branch 'main' into ATL-3164-oas
Browse files Browse the repository at this point in the history
  • Loading branch information
yshyn-iohk authored Mar 13, 2023
2 parents 43c324e + 728aecb commit a2c8b84
Show file tree
Hide file tree
Showing 34 changed files with 542 additions and 557 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
- ".github/workflows/e2e-tests.yml"
- "infrastructure/shared/docker-compose.yml"
- "tests/e2e-tests/**"
- "prism-agent/service"
- "prism-agent/service/**"
push:
branches:
- "main"
Expand Down Expand Up @@ -161,7 +161,6 @@ jobs:
if: github.ref_name == 'main'
uses: rtCamp/action-slack-notify@v2
env:
SLACK_CHANNEL: atala-qa-results
SLACK_COLOR: ${{ steps.analyze_test_results.outputs.conclusion }}
SLACK_MESSAGE: |
Total: ${{ steps.analyze_test_results.outputs.tests }}
Expand Down
17 changes: 12 additions & 5 deletions docs/docusaurus/credentials/issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@ This section describes the Issuer role's available interactions with the PRISM A
To start the process, the issuer needs to create a credential offer.
To do this, make a `POST` request to the [`/issue-credentials/credential-offers`](/agent-api/#tag/Issue-Credentials-Protocol/operation/createCredentialOffer) endpoint with a JSON payload that includes the following information:

1. `subjectId`: This field represents the unique identifier for the subject of the verifiable credential. It is a DID (Decentralized Identifier) string, such as `did:prism:subjectIdentifier`.
2. `schemaId`: This is an identifier for a schema, which defines the structure and format of the data in a verifiable credential. The schema identifier must be unique and typically a URL or a URN.
3. `claims`: The data stored in a verifiable credential. Claims get expressed in a key-value format and must conform to the structure and format defined in the schema. The claims contain the data that the issuer attests to, such as name, address, date of birth, and so on.
1. `schemaId`: This is an identifier for a schema, which defines the structure and format of the data in a verifiable credential. The schema identifier must be unique and typically a URL or a URN.
2. `claims`: The data stored in a verifiable credential. Claims get expressed in a key-value format and must conform to the structure and format defined in the schema. The claims contain the data that the issuer attests to, such as name, address, date of birth, and so on.

Once the request initiates, a new credential record for the issuer gets created with a unique ID. The state of this record is now `OfferPending`.

Expand Down Expand Up @@ -147,11 +146,19 @@ curl "http://localhost:8090/prism-agent/issue-credentials/records" \

### Approving the VC Offer

To accept the offer, the **Holder** can make a `POST` request to the [`/issue-credentials/records/{recordId}/accept-offer`](/agent-api/#tag/Issue-Credentials-Protocol/operation/acceptCredentialOffer) endpoint:
To accept the offer, the **Holder** can make a `POST` request to the [`/issue-credentials/records/{recordId}/accept-offer`](/agent-api/#tag/Issue-Credentials-Protocol/operation/acceptCredentialOffer) endpoint with a JSON payload that includes the following information:

1. `holder_record_id`: The unique identifier of the issue credential record known by the holder PRISM Agent.
2. `subjectId`: This field represents the unique identifier for the subject of the verifiable credential. It is a short-form PRISM DID (Decentralized Identifier) string, such as `did:prism:subjectIdentifier`.

```shell
# Holder POST request to accept the credential offer
curl -X POST "http://localhost:8090/prism-agent/issue-credentials/records/$holder_record_id/accept-offer" \
-H "Content-Type: application/json"
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"subjectId": "did:prism:subjectIdentifier"
}'
```

This request will change the state of the record to `RequestPending`.
Expand Down
7 changes: 7 additions & 0 deletions pollux/lib/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# [pollux-v0.40.0](https://github.com/input-output-hk/atala-prism-building-blocks/compare/pollux-v0.39.0...pollux-v0.40.0) (2023-03-10)


### Features

* **pollux:** move subjectId field from issuer side to holder side ([#434](https://github.com/input-output-hk/atala-prism-building-blocks/issues/434)) ([434f1fd](https://github.com/input-output-hk/atala-prism-building-blocks/commit/434f1fd7616c5f538819b1a68f4bc5ed4eeb4b5d))

# [pollux-v0.39.0](https://github.com/input-output-hk/atala-prism-building-blocks/compare/pollux-v0.38.0...pollux-v0.39.0) (2023-03-08)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ package io.iohk.atala.pollux.core.model
import io.circe._
import io.circe.generic.semiauto._
import io.circe.syntax._
import io.iohk.atala.pollux.core.model.presentation.{Options, PresentationDefinition}

// FIXME: Fix the format according to some standard / RFC (ATL-3507)
// This is likely wrong and not conform to the standard.
// Until the format / flow is agreed, We need a workaround to make the issuing flow work.
// Here is just a temporary way to attach subjectId when sending CredentialOffer to the holder
final case class CredentialOfferAttachment(subjectId: String)
final case class CredentialOfferAttachment(options: Options, presentation_definition: PresentationDefinition)

object CredentialOfferAttachment {
given Encoder[CredentialOfferAttachment] = deriveEncoder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final case class IssueCredentialRecord(
thid: DidCommID,
schemaId: Option[String],
role: Role,
subjectId: String,
subjectId: Option[String],
validityPeriod: Option[Double] = None,
automaticIssuance: Option[Boolean],
awaitConfirmation: Option[Boolean],
Expand All @@ -34,7 +34,7 @@ final case class IssueCredentialRecord(
final case class ValidIssuedCredentialRecord(
id: DidCommID,
issuedCredentialRaw: Option[String],
subjectId: String
subjectId: Option[String]
)

object IssueCredentialRecord {
Expand All @@ -53,6 +53,8 @@ object IssueCredentialRecord {

// Holder has reviewed and approved the offer (in Holder DB)
case RequestPending extends ProtocolState
// Holder has generated the request that that includes the subjectID and proofs (in Holder DB)
case RequestGenerated extends ProtocolState
// Holder has sent a request to a an Issuer (in Holder DB)
case RequestSent extends ProtocolState
// Issuer has received a request from the holder (In Issuer DB)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ object CredentialServiceError {
final case class UnexpectedError(msg: String) extends CredentialServiceError
final case class UnsupportedDidFormat(did: String) extends CredentialServiceError
final case class CreateCredentialPayloadFromRecordError(cause: Throwable) extends CredentialServiceError
final case class CredentialRequestValidationError(error: String) extends CredentialServiceError
final case class CredentialIdNotDefined(credential: W3cCredentialPayload) extends CredentialServiceError
final case class IrisError(cause: Throwable) extends CredentialServiceError
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ object Jwt {
given Encoder[Jwt] = deriveEncoder[Jwt]
given Decoder[Jwt] = deriveDecoder[Jwt]
}
case class ClaimFormat(jwt: Jwt)
case class Ldp(proof_type: Seq[String])
object Ldp {
given Encoder[Ldp] = deriveEncoder[Ldp]
given Decoder[Ldp] = deriveDecoder[Ldp]
}
case class ClaimFormat(jwt: Option[Jwt] = None, ldp: Option[Ldp] = None)
object ClaimFormat {
given Encoder[ClaimFormat] = deriveEncoder[ClaimFormat]
given Decoder[ClaimFormat] = deriveDecoder[ClaimFormat]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,17 @@ trait CredentialRepository[F[_]] {
to: Option[IssueCredentialRecord.PublicationState]
): F[Int]

def updateWithRequestCredential(recordId: DidCommID, request: RequestCredential, protocolState: ProtocolState): F[Int]
def updateWithSubjectId(
recordId: DidCommID,
subjectId: String,
protocolState: ProtocolState
): F[Int]

def updateWithRequestCredential(
recordId: DidCommID,
request: RequestCredential,
protocolState: ProtocolState
): F[Int]

def updateWithIssueCredential(
recordId: DidCommID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,34 @@ class CredentialRepositoryInMemory(
} yield store.values.find(_.thid == thid)
}

override def updateWithSubjectId(
recordId: DidCommID,
subjectId: String,
protocolState: ProtocolState
): Task[Int] = {
for {
maybeRecord <- getIssueCredentialRecord(recordId)
count <- maybeRecord
.map(record =>
for {
_ <- storeRef.update(r =>
r.updated(
recordId,
record.copy(
updatedAt = Some(Instant.now),
protocolState = protocolState,
subjectId = Some(subjectId),
metaRetries = maxRetries,
metaLastFailure = None,
)
)
)
} yield 1
)
.getOrElse(ZIO.succeed(1))
} yield count
}

override def updateWithRequestCredential(
recordId: DidCommID,
request: RequestCredential,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import java.security.spec.ECGenParameterSpec
import java.time.Instant
import java.util.UUID
import io.iohk.atala.castor.core.model.did.CanonicalPrismDID
import io.iohk.atala.pollux.vc.jwt.{PresentationPayload, JWT}

trait CredentialService {

Expand Down Expand Up @@ -56,7 +57,6 @@ trait CredentialService {
pairwiseIssuerDID: DidId,
pairwiseHolderDID: DidId,
thid: DidCommID,
subjectId: String,
schemaId: Option[String],
claims: Map[String, String],
validityPeriod: Option[Double] = None,
Expand All @@ -83,7 +83,14 @@ trait CredentialService {

def receiveCredentialOffer(offer: OfferCredential): IO[CredentialServiceError, IssueCredentialRecord]

def acceptCredentialOffer(recordId: DidCommID): IO[CredentialServiceError, IssueCredentialRecord]
def acceptCredentialOffer(recordId: DidCommID, subjectId: String): IO[CredentialServiceError, IssueCredentialRecord]

def createPresentationPayload(recordId: DidCommID, subject: Issuer): IO[CredentialServiceError, PresentationPayload]

def generateCredentialRequest(
recordId: DidCommID,
signedPresentation: JWT
): IO[CredentialServiceError, IssueCredentialRecord]

def receiveCredentialRequest(request: RequestCredential): IO[CredentialServiceError, IssueCredentialRecord]

Expand All @@ -93,7 +100,7 @@ trait CredentialService {
record: IssueCredentialRecord,
issuer: Issuer,
issuanceDate: Instant
): IO[CreateCredentialPayloadFromRecordError, W3cCredentialPayload]
): IO[CredentialServiceError, W3cCredentialPayload]

def publishCredentialBatch(
credentials: Seq[W3cCredentialPayload],
Expand Down
Loading

0 comments on commit a2c8b84

Please sign in to comment.