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(indy-vdr): add indy-vdr package and indy vdr pool #1160

Merged
merged 25 commits into from
Jan 26, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module.exports = {
alwaysTryTypes: true,
},
},
'import/core-modules': ['indy-vdr-test-nodejs'],
},
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export type {
WalletConfigRekey,
WalletExportImportConfig,
} from './types'
export * from './cache'
export { DidCommMimeType, KeyDerivationMethod } from './types'
export type { FileSystem } from './storage/FileSystem'
export * from './storage/BaseRecord'
Expand Down
51 changes: 4 additions & 47 deletions packages/indy-vdr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
height="250px"
/>
</p>
<h1 align="center"><b>Aries Framework JavaScript Action Menu Plugin</b></h1>
<h1 align="center"><b>Aries Framework JavaScript - Indy Verifiable Data Registry (Indy-Vdr)</b></h1>
<p align="center">
<a
href="https://raw.githubusercontent.com/hyperledger/aries-framework-javascript/main/LICENSE"
Expand All @@ -19,60 +19,17 @@
alt="typescript"
src="https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg"
/></a>
<a href="https://www.npmjs.com/package/@aries-framework/action-menu"
<a href="https://www.npmjs.com/package/@aries-framework/indy-vdr"
><img
alt="@aries-framework/action-menu version"
src="https://img.shields.io/npm/v/@aries-framework/action-menu"
alt="@aries-framework/anoncreds version"
src="https://img.shields.io/npm/v/@aries-framework/indy-vdr"
/></a>

</p>
<br />

Action Menu plugin for [Aries Framework JavaScript](https://github.com/hyperledger/aries-framework-javascript.git). Implements [Aries RFC 0509](https://github.com/hyperledger/aries-rfcs/blob/1795d5c2d36f664f88f5e8045042ace8e573808c/features/0509-action-menu/README.md).

### Installation

Make sure you have set up the correct version of Aries Framework JavaScript according to the AFJ repository. To find out which version of AFJ you need to have installed you can run the following command. This will list the required peer dependency for `@aries-framework/core`.

```sh
npm info "@aries-framework/action-menu" peerDependencies
```

Then add the action-menu plugin to your project.

```sh
yarn add @aries-framework/action-menu
```

### Quick start

In order for this plugin to work, we have to inject it into the agent to access agent functionality. See the example for more information.

### Example of usage

```ts
import { ActionMenuModule } from '@aries-framework/action-menu'

const agent = new Agent({
config: {
/* config */
},
dependencies: agentDependencies,
modules: {
actionMenu: new ActionMenuModule(),
/* other custom modules */
},
})

await agent.initialize()

// To request root menu to a given connection (menu will be received
// asynchronously in a ActionMenuStateChangedEvent)
await agent.modules.actionMenu.requestMenu({ connectionId })

// To select an option from the action menu
await agent.modules.actionMenu.performAction({
connectionId,
performedAction: { name: 'option-1' },
})
```
24 changes: 10 additions & 14 deletions packages/indy-vdr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@aries-framework/indy-vdr",
"main": "build/index",
"types": "build/index",
"version": "0.2.5",
"version": "0.3.3",
"files": [
"build"
],
Expand All @@ -18,31 +18,27 @@
},
"scripts": {
"build": "yarn run clean && yarn run compile",
"clean": "rimraf -rf ./build",
"clean": "rimraf ./build",
"compile": "tsc -p tsconfig.build.json",
"prepublishOnly": "yarn run build",
"test": "jest"
},
"dependencies": {
"@aries-framework/core": "0.3.3",
"@types/express": "^4.17.13",
"@typescript-eslint/eslint-plugin": "^5.48.1",
"@typescript-eslint/parser": "^5.48.1",
"class-transformer": "0.5.1",
"indy-vdr-test-shared": "^0.1.3",
"class-validator": "0.13.1",
"eslint-plugin-import": "^2.23.4",
"indy-vdr-test-shared": "^0.1.3",
"rxjs": "^7.2.0"
},
"peerDependencies": {
"@aries-framework/core": "0.2.5",
"indy-vdr-test-nodejs": "^0.1.3"
},
"devDependencies": {
"@aries-framework/node": "0.2.5",
"@aries-framework/node": "0.3.3",
"indy-vdr-test-nodejs": "^0.1.3",
"reflect-metadata": "^0.1.13",
"rimraf": "~3.0.2",
"typescript": "~4.3.0"
},
"peerDependenciesMeta": {
"indy-vdr-test-nodejs": {
"optional": true
}
"typescript": "~4.9.4"
}
}
12 changes: 6 additions & 6 deletions packages/indy-vdr/src/error/IndyVdrNotConfiguredError.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {IndyVdrError} from './IndyVdrError'
import { IndyVdrError } from './IndyVdrError'

export class IndyVdrConfiguredError extends IndyVdrError {
public constructor(message: string, { cause }: { cause?: Error } = {}) {
super(message, { cause })
}
}
export class IndyVdrNotConfiguredError extends IndyVdrError {
public constructor(message: string, { cause }: { cause?: Error } = {}) {
super(message, { cause })
}
}
10 changes: 5 additions & 5 deletions packages/indy-vdr/src/error/IndyVdrNotFound.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IndyVdrError } from "./IndyVdrError"
import { IndyVdrError } from './IndyVdrError'

export class IndyVdrNotFoundError extends IndyVdrError {
public constructor(message: string, { cause }: { cause?: Error } = {}) {
super(message, { cause })
}
}
public constructor(message: string, { cause }: { cause?: Error } = {}) {
super(message, { cause })
}
}
2 changes: 1 addition & 1 deletion packages/indy-vdr/src/error/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './IndyVdrError'
export * from './IndyVdrNotFound'
export * from './IndyVdrNotConfiguredError'
export * from './IndyVdrNotConfiguredError'
6 changes: 2 additions & 4 deletions packages/indy-vdr/src/pool/IndyVdrPool.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Logger, AgentContext, Key } from '@aries-framework/core'
import type { IndyVdrRequest, IndyVdrPool as indyVdrPool } from 'indy-vdr-test-shared'

import { TypedArrayEncoder, AriesFrameworkError } from '@aries-framework/core'
import { TypedArrayEncoder } from '@aries-framework/core'
import {
GetTransactionAuthorAgreementRequest,
GetAcceptanceMechanismsRequest,
Expand Down Expand Up @@ -38,7 +38,6 @@ export interface IndyVdrPoolConfig {
}

export class IndyVdrPool {
// indyVdr?: typeof IndyVdr
private _pool?: indyVdrPool
private logger: Logger
private poolConfig: IndyVdrPoolConfig
Expand Down Expand Up @@ -69,8 +68,7 @@ export class IndyVdrPool {

private get pool(): indyVdrPool {
if (!this._pool) {
// TODO: create custom IndyVdrError
throw new AriesFrameworkError('Pool is not connected. Make sure to call .connect() first')
throw new IndyVdrError('Pool is not connected. Make sure to call .connect() first')
}

return this._pool
Expand Down
44 changes: 15 additions & 29 deletions packages/indy-vdr/src/pool/IndyVdrPoolService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@ import type { IndyVdrPoolConfig } from './IndyVdrPool'
import type { AgentContext } from '@aries-framework/core'
import type { GetNymResponse } from 'indy-vdr-test-shared'

import { Logger, InjectionSymbols, injectable, inject, CacheModuleConfig} from '@aries-framework/core'
import { Logger, InjectionSymbols, injectable, inject, CacheModuleConfig } from '@aries-framework/core'
import { GetNymRequest } from 'indy-vdr-test-shared'

import { IndyVdrError, IndyVdrNotFoundError, IndyVdrConfiguredError } from '../error'
import { IndyVdrError, IndyVdrNotFoundError, IndyVdrNotConfiguredError } from '../error'
import { isSelfCertifiedDid } from '../utils/did'
import { allSettled, onlyFulfilled, onlyRejected } from '../utils/promises'

import { DID_INDY_REGEX } from './DidIdentifier'
import { IndyVdrPool } from './IndyVdrPool'
import { DID_INDY_REGEX } from './didIdentifier'

export const INDY_VDR_LEGACY_DID_POOL_CACHE_ID = 'INDY_VDR_LEGACY_DID_POOL_CACHE'
export const DID_POOL_CACHE_LIMIT = 500
export interface CachedDidResponse {
nymResponse: {
did: string
Expand All @@ -26,9 +24,8 @@ export class IndyVdrPoolService {
public pools: IndyVdrPool[] = []
private logger: Logger

public constructor( @inject(InjectionSymbols.Logger) logger: Logger) {
public constructor(@inject(InjectionSymbols.Logger) logger: Logger) {
this.logger = logger

}

public setPools(poolConfigs: IndyVdrPoolConfig[]) {
Expand All @@ -52,7 +49,7 @@ export class IndyVdrPoolService {

/**
* Get the most appropriate pool for the given did.
* If the did is a qualified indy did, the pool will be determined based on the namespace.
* If the did is a qualified indy did, the pool will be determined based on the namespace.
* If it is a legacy unqualified indy did, the pool will be determined based on the algorithm as described in this document:
* https://docs.google.com/document/d/109C_eMsuZnTnYe2OAd02jAts1vC4axwEKIq7_4dnNVA/edit
*/
Expand All @@ -63,26 +60,21 @@ export class IndyVdrPoolService {
if (match) {
const [, namespace] = match

const pool = this.getPoolForNamespace(namespace);
const pool = this.getPoolForNamespace(namespace)

if (pool) return pool
if (pool) return pool

throw new IndyVdrNotFoundError('Pool not found')
throw new IndyVdrError(`Pool for indy namespace '${namespace}' not found`)
} else {
return await this.getPoolForLegacyDid(agentContext, did)
}


}

private async getPoolForLegacyDid(
agentContext: AgentContext,
did: string
): Promise<IndyVdrPool > {
private async getPoolForLegacyDid(agentContext: AgentContext, did: string): Promise<IndyVdrPool> {
const pools = this.pools

if (pools.length === 0) {
throw new IndyVdrConfiguredError(
throw new IndyVdrNotConfiguredError(
"No indy ledgers configured. Provide at least one pool configuration in the 'indyLedgers' agent configuration"
)
}
Expand All @@ -95,7 +87,7 @@ export class IndyVdrPoolService {
// If we have the nym response with associated pool in the cache, we'll use that
if (cachedNymResponse && pool) {
this.logger.trace(`Found ledger id '${pool.indyNamespace}' for did '${did}' in cache`)
return pool
return pool
}

const { successful, rejected } = await this.getSettledDidResponsesFromPools(did, pools)
Expand Down Expand Up @@ -143,7 +135,7 @@ export class IndyVdrPoolService {
},
indyNamespace: value.did.indyNamespace,
})
return value.pool
return value.pool
}

private async getSettledDidResponsesFromPools(did: string, pools: IndyVdrPool[]) {
Expand All @@ -166,20 +158,15 @@ export class IndyVdrPoolService {
*/
public getPoolForNamespace(indyNamespace: string) {
if (this.pools.length === 0) {
throw new IndyVdrConfiguredError(
throw new IndyVdrNotConfiguredError(
"No indy ledgers configured. Provide at least one pool configuration in the 'indyLedgers' agent configuration"
)
}

if (!indyNamespace) {
this.logger.warn('Not passing the indyNamespace is deprecated and will be removed in the future version.')
return this.pools[0]
}

const pool = this.pools.find((pool) => pool.indyNamespace === indyNamespace)

if (!pool) {
throw new IndyVdrNotFoundError(`No ledgers found for IndyNamespace '${indyNamespace}'.`)
throw new IndyVdrError(`No ledgers found for IndyNamespace '${indyNamespace}'.`)
}

return pool
Expand All @@ -194,8 +181,7 @@ export class IndyVdrPoolService {
const response = await pool.submitReadRequest(request)

if (!response.result.data) {
// TODO: Set a descriptive message
throw new IndyVdrError(`Did ${did} not found on indy pool with namespace ${pool.indyNamespace}`)
throw new IndyVdrNotFoundError(`Did ${did} not found on indy pool with namespace ${pool.indyNamespace}`)
}

const result = JSON.parse(response.result.data)
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const DID_INDY_REGEX = /^did:indy:((?:[a-z][_a-z0-9-]*)(?::[a-z][_a-z0-9-]*)):([1-9A-HJ-NP-Za-km-z]{21,22})$/
export const DID_INDY_REGEX = /^did:indy:((?:[a-z][_a-z0-9-]*)(?::[a-z][_a-z0-9-]*)):([1-9A-HJ-NP-Za-km-z]{21,22})$/
1 change: 0 additions & 1 deletion packages/indy-vdr/src/pool/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './IndyVdrPool'

5 changes: 0 additions & 5 deletions packages/indy-vdr/src/utils/did.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,9 @@
* https://github.com/hyperledger/aries-framework-dotnet/blob/f90eaf9db8548f6fc831abea917e906201755763/src/Hyperledger.Aries/Ledger/DefaultLedgerService.cs#L139-L147
*/


import { TypedArrayEncoder } from '@aries-framework/core'

export const FULL_VERKEY_REGEX = /^[1-9A-HJ-NP-Za-km-z]{43,44}$/
export const ABBREVIATED_VERKEY_REGEX = /^~[1-9A-HJ-NP-Za-km-z]{21,22}$/
export const VERKEY_REGEX = new RegExp(`${FULL_VERKEY_REGEX.source}|${ABBREVIATED_VERKEY_REGEX.source}`)
export const DID_REGEX = /^did:([a-z]+):([a-zA-z\d]+)/
export const DID_IDENTIFIER_REGEX = /^[a-zA-z\d-]+$/

/**
* Check whether the did is a self certifying did. If the verkey is abbreviated this method
Expand Down
Loading