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: Split AFJ demo for two cases: Main and DidCommV2 #1470

Open
wants to merge 5 commits into
base: feat/didcomm-v2
Choose a base branch
from
Open
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
64 changes: 54 additions & 10 deletions demo/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
<h1 align="center"><b>DEMO</b></h1>

This is the Aries Framework Javascript demo. Walk through the AFJ flow yourself together with agents Alice and Faber.
This is the Aries Framework Javascript demos. Walk through the available AFJ flows yourself together with agents Alice and Faber.

Alice, a former student of Faber College, connects with the College, is issued a credential about her degree and then is asked by the College for a proof.
## Flows

## Features

- ✅ Creating a connection
- ✅ Offering a credential
- ✅ Requesting a proof
- ✅ Sending basic messages
- `Main` - General flow: Alice, a former student of Faber College, connects with the College, is issued a credential about her degree and then is asked by the College for a proof.
- ✅ Creating a connection
- ✅ Offering a credential
- ✅ Requesting a proof
- ✅ Sending basic messages
- `DidComm V2` - [DidComm v2 massaging](https://identity.foundation/didcomm-messaging/spec/) usage. In contrast to the `Main` this demo provides functionality limited to sending `ping` message after accepting out-of-band invitation from the invitee.
- ✅ Creating a connection
- ✅ Ping
> Integration of DidComm V2 protocols is currently under development! In the future, it will cover the same features as the `Main` flow.

## Getting Started

Expand All @@ -19,7 +22,7 @@ In order to use Aries Framework JavaScript some platform specific dependencies a

- [NodeJS](https://aries.js.org/guides/getting-started/installation/nodejs)

### Run the demo
### Preparation

These are the steps for running the AFJ demo:

Expand All @@ -41,6 +44,10 @@ Install the project in one of the terminals:
yarn install
```

### Run the demo

#### Main demo

In the left terminal run Alice:

```sh
Expand All @@ -53,7 +60,7 @@ In the right terminal run Faber:
yarn faber
```

### Usage
##### Usage

To set up a connection:

Expand Down Expand Up @@ -87,3 +94,40 @@ Exit:
Restart:

- Select 'restart', to shutdown the current agent and start a new one

#### DidComm V2 demo

In the left terminal run Alice:

```sh
yarn alice-didcommv2
```

In the right terminal run Faber:

```sh
yarn faber-didcommv2
```

##### Usage

To set up a connection:

- Select 'receive connection invitation' in Alice and 'create connection invitation' in Faber
- Faber will print a invitation link which you then copy and paste to Alice
- You have now set up a connection!

To send a ping message:

- Establish the connection first
- Select 'ping' in the Alice Agent
- Message sent!
- Faber Agent should print notification about received `ping` message and response with `ping response` message back to Alice.

Exit:

- Select 'exit' to shutdown the agent.

Restart:

- Select 'restart', to shutdown the current agent and start a new one
6 changes: 4 additions & 2 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
},
"license": "Apache-2.0",
"scripts": {
"alice": "ts-node src/AliceInquirer.ts",
"faber": "ts-node src/FaberInquirer.ts",
"alice": "ts-node src/main/AliceInquirer.ts",
"faber": "ts-node src/main/FaberInquirer.ts",
"alice-didcommv2": "ts-node src/didcomm-v2/AliceInquirer.ts",
"faber-didcommv2": "ts-node src/didcomm-v2/FaberInquirer.ts",
"refresh": "rm -rf ./node_modules ./yarn.lock && yarn"
},
"dependencies": {
Expand Down
90 changes: 0 additions & 90 deletions demo/src/Alice.ts

This file was deleted.

51 changes: 51 additions & 0 deletions demo/src/BaseAlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { ConnectionRecord } from '@aries-framework/core'

import { BaseAgent } from './BaseAgent'
import { greenText, Output, redText } from './OutputClass'

export class BaseAlice extends BaseAgent {
public connected: boolean
public connectionRecordFaberId?: string

public constructor(port: number, name: string) {
super({ port, name, useLegacyIndySdk: true })
this.connected = false
}

protected async getConnectionRecord() {
if (!this.connectionRecordFaberId) {
throw Error(redText(Output.MissingConnectionRecord))
}
return await this.agent.connections.getById(this.connectionRecordFaberId)
}

protected async receiveConnectionRequest(invitationUrl: string) {
const { connectionRecord } = await this.agent.oob.receiveInvitationFromUrl(invitationUrl)
if (!connectionRecord) {
throw new Error(redText(Output.NoConnectionRecordFromOutOfBand))
}
return connectionRecord
}

protected async waitForConnection(connectionRecord: ConnectionRecord) {
connectionRecord = await this.agent.connections.returnWhenIsConnected(connectionRecord.id, { timeoutMs: 200000 })
this.connected = true
console.log(greenText(Output.ConnectionEstablished))
return connectionRecord.id
}

public async acceptConnection(invitation_url: string) {
const connectionRecord = await this.receiveConnectionRequest(invitation_url)
this.connectionRecordFaberId = await this.waitForConnection(connectionRecord)
}

public async exit() {
console.log(Output.Exit)
await this.agent.shutdown()
process.exit(0)
}

public async restart() {
await this.agent.shutdown()
}
}
87 changes: 87 additions & 0 deletions demo/src/BaseFaber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import type { RegisterCredentialDefinitionReturnStateFinished } from '@aries-framework/anoncreds'
import type BottomBar from 'inquirer/lib/ui/bottom-bar'

import { KeyType, TypedArrayEncoder } from '@aries-framework/core'
import { ui } from 'inquirer'

import { BaseAgent, indyNetworkConfig } from './BaseAgent'
import { Output, redText } from './OutputClass'

export enum RegistryOptions {
indy = 'did:indy',
cheqd = 'did:cheqd',
}

export class BaseFaber extends BaseAgent {
public outOfBandId?: string
public credentialDefinition?: RegisterCredentialDefinitionReturnStateFinished
public anonCredsIssuerId?: string
public ui: BottomBar

public constructor(port: number, name: string) {
super({ port, name, useLegacyIndySdk: true })
this.ui = new ui.BottomBar()
}

public static async build(): Promise<BaseFaber> {
const faber = new BaseFaber(9001, 'faber')
await faber.initializeAgent()
return faber
}

public async importDid(registry: string) {
// NOTE: we assume the did is already registered on the ledger, we just store the private key in the wallet
// and store the existing did in the wallet
// indy did is based on private key (seed)
const unqualifiedIndyDid = '2jEvRuKmfBJTRa7QowDpNN'
const cheqdDid = 'did:cheqd:testnet:d37eba59-513d-42d3-8f9f-d1df0548b675'
const indyDid = `did:indy:${indyNetworkConfig.indyNamespace}:${unqualifiedIndyDid}`

const did = registry === RegistryOptions.indy ? indyDid : cheqdDid
await this.agent.dids.import({
did,
overwrite: true,
privateKeys: [
{
keyType: KeyType.Ed25519,
privateKey: TypedArrayEncoder.fromString('afjdemoverysercure00000000000000'),
},
],
})
this.anonCredsIssuerId = did
}

protected async getConnectionRecord() {
if (!this.outOfBandId) {
throw Error(redText(Output.MissingConnectionRecord))
}

const [connection] = await this.agent.connections.findAllByOutOfBandId(this.outOfBandId)

if (!connection) {
throw Error(redText(Output.MissingConnectionRecord))
}

return connection
}

protected async printConnectionInvite(version: 'v1' | 'v2') {
const outOfBandRecord = await this.agent.oob.createInvitation({ version })
this.outOfBandId = outOfBandRecord.id

const outOfBandInvitation = outOfBandRecord.outOfBandInvitation || outOfBandRecord.v2OutOfBandInvitation
if (outOfBandInvitation) {
console.log(Output.ConnectionLink, outOfBandInvitation.toUrl({ domain: `http://localhost:${this.port}` }), '\n')
}
}

public async exit() {
console.log(Output.Exit)
await this.agent.shutdown()
process.exit(0)
}

public async restart() {
await this.agent.shutdown()
}
}
21 changes: 21 additions & 0 deletions demo/src/BaseListener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type BottomBar from 'inquirer/lib/ui/bottom-bar'

import { ui } from 'inquirer'

export class BaseListener {
public on: boolean
protected ui: BottomBar

public constructor() {
this.on = false
this.ui = new ui.BottomBar()
}

protected turnListenerOn() {
this.on = true
}

protected turnListenerOff() {
this.on = false
}
}
18 changes: 18 additions & 0 deletions demo/src/didcomm-v2/Alice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { BaseAlice } from '../BaseAlice'

export class Alice extends BaseAlice {
public constructor(port: number, name: string) {
super(port, name)
}

public static async build(): Promise<Alice> {
const alice = new Alice(9000, 'alice')
await alice.initializeAgent()
return alice
}

public async ping() {
const connectionRecord = await this.getConnectionRecord()
await this.agent.connections.sendPing(connectionRecord.id, {})
}
}
Loading