Skip to content

Commit

Permalink
feat(prism-agent): implement Connect flow (#130)
Browse files Browse the repository at this point in the history
* Added first version of open api spec for connect

* Added first version of open api spec for connect

* Added protocol onnect

* updated the protocol connect

* Added the Agent for connect

* chore(prism-agent): update OAS for Connect

* feat(prism-agent): add mock implementation for Connect OAS

* chore(connect): Fix typo in class names

* chore(prism-agent): return '201' when creating new connection record

* chore(connect): bump mercury version to 0.7.0

* chore(pollux): bump version to 0.4.0-SNAPSHOT

* chore(pollux): bump mercury version to 0.7.0

* chore(prism-agent): add connect dependency

* chore(connect): Fix typo in class names

* chore(prism-agent): configure connect Api and DB layers

* chore(prism-agent): fix compilation warning

* chore(connect): implement all phases of the connection flow

* chore(connect): decode and parse raw invitation in ConnectionService

* chore(prism-agent): align connect OAS with DIDComm v2 OOB invitation format

* chore(prism-agent): execute connect db migrations at startup

* chore(prism-agent): add connect DB app config

* feat(prism-agent): implement create/get connection(s) + accept invitation

* chore(connect): disable Doobie log handler

* chore(connect): implement connection request acceptance by inviter

* chore(prism-agent): return 'myDid' and 'theirDid' in REST api reponse

* feat(prism-agent): implement background job for Connect protocol

* feat(prism-agent): implement DIDComm service endpoint for Connect protocol

* chore(prism-agent): improve code formatting

* chore(prism-agent): move connect API spec to server project

* chore(pollux): downgrade to shared 0.1.0

* chore(connect): downgrade to shared 0.1.0

* chore(prism-agent): add removed connect dependency

* chore(mercury): bump to pollux:0.4.0 & connect:1.0.0

* chore(prism-agent): use fixed release version of connect => 0.1.0

Co-authored-by: Benjamin Voiturier <[email protected]>
  • Loading branch information
mineme0110 and bvoiturier authored Nov 25, 2022
1 parent a01a6dd commit f7cba3b
Show file tree
Hide file tree
Showing 15 changed files with 678 additions and 23 deletions.
149 changes: 149 additions & 0 deletions prism-agent/service/api/http/connect/schemas.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
components:
parameters:
connectionId:
in: path
name: connectionId
required: true
description: Id of connection state record.
schema:
type: string
schemas:
CreateConnectionRequest:
type: object
properties:
label:
type: string
example: "Peter"

AcceptConnectionInvitationRequest:
type: object
required:
- invitation
properties:
invitation:
type: string
example: "eyJAaWQiOiIzZmE4NWY2NC01NzE3LTQ1NjItYjNmYy0yYzk2M2Y2NmFmYTYiLCJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvbXktZmFtaWx5LzEuMC9teS1tZXNzYWdlLXR5cGUiLCJkaWQiOiJXZ1d4cXp0ck5vb0c5MlJYdnhTVFd2IiwiaW1hZ2VVcmwiOiJodHRwOi8vMTkyLjE2OC41Ni4xMDEvaW1nL2xvZ28uanBnIiwibGFiZWwiOiJCb2IiLCJyZWNpcGllbnRLZXlzIjpbIkgzQzJBVnZMTXY2Z21NTmFtM3VWQWpacGZrY0pDd0R3blpuNnozd1htcVBWIl0sInJvdXRpbmdLZXlzIjpbIkgzQzJBVnZMTXY2Z21NTmFtM3VWQWpacGZrY0pDd0R3blpuNnozd1htcVBWIl0sInNlcnZpY2VFbmRwb2ludCI6Imh0dHA6Ly8xOTIuMTY4LjU2LjEwMTo4MDIwIn0="

Connection:
type: object
allOf:
- $ref: "#/components/schemas/CreateConnectionRequest"
- type: object
required:
- self
- kind
- connectionId
- state
- createdAt
- invitation
properties:
self:
type: string
example: https://atala-prism-products.io/connections/ABCD-1234
kind:
type: string
example: ConnectionState
connectionId:
type: string
format: uuid
example: "12345-9876"
myDid:
type: string
example: "did:prism:12345"
theirDid:
type: string
example: "did:peer:12345"
state:
type: string
enum: ["pending", "success", "failed"]
createdAt:
type: string
format: date-time
example: 2021-10-31T09:22:23Z
updatedAt:
type: string
format: date-time
example: 2021-12-31T13:59:60Z
invitation:
$ref: "#/components/schemas/ConnectionInvitation"

ConnectionCollection:
type: object
required:
- self
- kind
- contents
properties:
self:
type: string
example: https://atala-prism-products.io/connections
kind:
type: string
example: Collection
contents:
type: array
items:
$ref: "#/components/schemas/Connection"

ConnectionInvitation:
type: object
required:
- id
- type
- from
- invitationUrl
properties:
id:
type: string
format: uuid
description: The invitation identifier used as parent thread ID (pthid) for the response message that follows.
example: "3fa85f64-5717-4562-b3fc-2c963f66afa6"
type:
type: string
description: The DIDComm Message Type URI (MTURI) the invitation message coplies with.
example: "https://didcomm.org/out-of-band/2.0/invitation"
from:
type: string
description: The DID representing the sender to be used by recipients for future interactions.
example: "did:prism:1234457"
invitationUrl:
type: string
description: The invitation message encoded as a URL.
example: https://domain.com/path?_oob=eyJAaWQiOiIzZmE4NWY2NC01NzE3LTQ1NjItYjNmYy0yYzk2M2Y2NmFmYTYiLCJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvbXktZmFtaWx5LzEuMC9teS1tZXNzYWdlLXR5cGUiLCJkaWQiOiJXZ1d4cXp0ck5vb0c5MlJYdnhTVFd2IiwiaW1hZ2VVcmwiOiJodHRwOi8vMTkyLjE2OC41Ni4xMDEvaW1nL2xvZ28uanBnIiwibGFiZWwiOiJCb2IiLCJyZWNpcGllbnRLZXlzIjpbIkgzQzJBVnZMTXY2Z21NTmFtM3VWQWpacGZrY0pDd0R3blpuNnozd1htcVBWIl0sInJvdXRpbmdLZXlzIjpbIkgzQzJBVnZMTXY2Z21NTmFtM3VWQWpacGZrY0pDd0R3blpuNnozd1htcVBWIl0sInNlcnZpY2VFbmRwb2ludCI6Imh0dHA6Ly8xOTIuMTY4LjU2LjEwMTo4MDIwIn0=

ErrorResponse:
type: object
description: An RFC-7807 compliant data structure for reporting errors to the client
required:
- type
- title
- status
- instance
properties:
type:
type: string
description: A URI reference that identifies the problem type.
example: https://example.org/doc/#model-MalformedEmail
title:
type: string
example: "Malformed email"
description: |-
A short, human-readable summary of the problem type. It does not
change from occurrence to occurrence of the problem.
status:
type: integer
format: int32
example: 400
description: |-
The HTTP status code for this occurrence of the problem.
detail:
type: string
description: |-
A human-readable explanation specific to this occurrence of the problem.
example: "The received '{}à!è@!.b}' email does not conform to the email format"
instance:
type: string
example: "/problems/d914e"
description: |-
A URI reference that identifies the specific occurrence of the problem.
It may or may not yield further information if dereferenced.
116 changes: 116 additions & 0 deletions prism-agent/service/api/http/prism-agent-openapi-spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ tags:
description: Verifiable Credentials revocation REST API
- name: Present Proof
description: Present Proof REST API
# Connect
- name: Connections Management
description: API for driving connection process.


paths:
# ----------------------------------
Expand Down Expand Up @@ -926,3 +930,115 @@ paths:
application/json:
schema:
$ref: "./pollux/schemas.yaml#/components/schemas/W3CPresentation"

# ----------------------------------
# Connect
# ----------------------------------
/connections:
post:
tags: ["Connections Management"]
operationId: createConnection
summary: Creates new connection and returns an invitation.
description: |-
Returns new invitation object and creates new connection state record in `pending` state.
Content of invitation depends on DIDComm protocol used, here is an example of how it would look like for `AIP 1.0 connection/v1` protocol.
Once connection invitation is accepted, Agent should filter all additional attempts to accept it.
We consider mult-party connections as out of scope for now.
requestBody:
required: true
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/CreateConnectionRequest"

responses:
"201":
description: The connection record
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/Connection"
"422":
description: The connection record creation failed.
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/ErrorResponse"

get:
tags: ["Connections Management"]
operationId: getConnections
summary: Returns a list of connections.
responses:
"200":
description: List of connection state objects
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/ConnectionCollection"
"500":
description: Retrieving the connection records failed for an unexpected reason.
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/ErrorResponse"

/connections/{connectionId}:
get:
tags: ["Connections Management"]
parameters:
- $ref: "./connect/schemas.yaml#/components/parameters/connectionId"
operationId: getConnection
summary: Returns an existing connection record by id.
responses:
"200":
description: Connection state record
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/Connection"
"404":
description: There is no issue credential record matching the given 'recordId'.
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/ErrorResponse"
delete:
tags: ["Connections Management"]
parameters:
- $ref: "./connect/schemas.yaml#/components/parameters/connectionId"
operationId: deleteConnection
summary: Deletes existing connection record.
description: Just deletes connection state in the Agent, it does not include notifing other party that connection is deleted. We should consider this feature for the future. If additional action is attempted over deleted connection, it should thow error (no matter which side deleted connection).
responses:
"200":
description: Successful delete
"404":
description: Connection state record not found for given `connectionId`

/connection-invitations:
post:
tags: ["Connections Management"]
operationId: acceptConnectionInvitation
summary: Accepts externally received invitation.
description: Creates new connection state record in `pending` state. It is assumed that application would first decode and validate the invitation. When it is accepted in the application side, it should be submitted in raw format to this API.
requestBody:
required: true
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/AcceptConnectionInvitationRequest"

responses:
"200":
description: Invitation successfully accepted.
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/Connection"
"500":
description: Storing the connection invitation failed for an unexpected reason.
content:
application/json:
schema:
$ref: "./connect/schemas.yaml#/components/schemas/ErrorResponse"
10 changes: 8 additions & 2 deletions prism-agent/service/project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ object Dependencies {
val akka = "2.6.20"
val akkaHttp = "10.2.9"
val castor = "0.2.0"
val pollux = "0.3.0"
val pollux = "0.4.0"
val connect = "0.1.0"
val bouncyCastle = "1.70"
val logback = "1.4.4"
val mercury = "0.6.0"
val mercury = "0.7.0"
val zioJson = "0.3.0"
val tapir = "1.2.2"
}
Expand Down Expand Up @@ -41,6 +42,9 @@ object Dependencies {
private lazy val polluxCore = "io.iohk.atala" %% "pollux-core" % Versions.pollux
private lazy val polluxSqlDoobie = "io.iohk.atala" %% "pollux-sql-doobie" % Versions.pollux

private lazy val connectCore = "io.iohk.atala" %% "connect-core" % Versions.connect
private lazy val connectSqlDoobie = "io.iohk.atala" %% "connect-sql-doobie" % Versions.connect

private lazy val mercuryAgent = "io.iohk.atala" %% "mercury-agent-didcommx" % Versions.mercury

// Added here to make prism-crypto works.
Expand All @@ -66,6 +70,7 @@ object Dependencies {
private lazy val castorDependencies: Seq[ModuleID] = Seq(castorCore, castorSqlDoobie)
private lazy val polluxDependencies: Seq[ModuleID] = Seq(polluxCore, polluxSqlDoobie)
private lazy val mercuryDependencies: Seq[ModuleID] = Seq(mercuryAgent)
private lazy val connectDependencies: Seq[ModuleID] = Seq(connectCore, connectSqlDoobie)
private lazy val akkaHttpDependencies: Seq[ModuleID] =
Seq(akkaTyped, akkaStream, akkaHttp, akkaSprayJson).map(_.cross(CrossVersion.for3Use2_13))
private lazy val bouncyDependencies: Seq[ModuleID] = Seq(bouncyBcpkix, bouncyBcprov)
Expand All @@ -92,5 +97,6 @@ object Dependencies {
castorDependencies ++
polluxDependencies ++
mercuryDependencies ++
connectDependencies ++
tapirDependencies
}
15 changes: 15 additions & 0 deletions prism-agent/service/server/src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ pollux {
}
}

connect {
database {
host = "localhost"
host = ${?CONNECT_DB_HOST}
port = 5433
port = ${?CONNECT_DB_PORT}
databaseName = "connect"
databaseName = ${?CONNECT_DB_NAME}
username = "postgres"
username = ${?CONNECT_DB_USER}
password = "postgres"
password = ${?CONNECT_DB_PASSWORD}
}
}

agent {
httpEndpoint {
http {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.didcommx.didcomm.DIDComm
import io.iohk.atala.resolvers.UniversalDidResolver
import io.iohk.atala.castor.sql.repository.{Migrations => CastorMigrations}
import io.iohk.atala.pollux.sql.repository.{Migrations => PolluxMigrations}
import io.iohk.atala.connect.sql.repository.{Migrations => ConnectMigrations}

object Main extends ZIOAppDefault {
def agentLayer(peer: PeerDID): ZLayer[Any, Nothing, AgentServiceAny] = ZLayer.succeed(
Expand Down Expand Up @@ -54,6 +55,9 @@ object Main extends ZIOAppDefault {
_ <- ZIO
.serviceWithZIO[PolluxMigrations](_.migrate)
.provide(RepoModule.polluxDbConfigLayer >>> PolluxMigrations.layer)
_ <- ZIO
.serviceWithZIO[ConnectMigrations](_.migrate)
.provide(RepoModule.connectDbConfigLayer >>> ConnectMigrations.layer)

agentDID <- for {
peer <- ZIO.succeed(PeerDID.makePeerDid(serviceEndpoint = Some(s"http://localhost:$didCommServicePort")))
Expand All @@ -69,9 +73,14 @@ object Main extends ZIOAppDefault {
.debug
.fork

connectDidCommExchangesFiber <- Modules.connectDidCommExchangesJob
.provide(didCommLayer)
.debug
.fork

didCommServiceFiber <- Modules
.didCommServiceEndpoint(didCommServicePort)
.provide(didCommLayer, AppModule.credentialServiceLayer)
.provide(didCommLayer, AppModule.credentialServiceLayer, AppModule.connectionServiceLayer)
.debug
.fork

Expand Down
Loading

0 comments on commit f7cba3b

Please sign in to comment.