From db3c20eeb081256dbe6931c3b34e4cc53c2039f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Rib=C3=B3?= Date: Wed, 21 Jun 2023 12:25:27 +0200 Subject: [PATCH 1/2] fix(docs): Improve Generated documentation (#65) --- .github/workflows/release-docs.yml | 49 ++++ .gitignore | 3 +- .npmignore | 1 + README.md | 136 ++------- docs/Agent.md | 139 ---------- docs/Apollo.md | 100 ------- docs/Castor.md | 92 ------ docs/Pluto.md | 150 ---------- docs/index.md | 12 - docs/sidebars.js | 30 -- package-lock.json | 148 ++++++++++ package.json | 10 +- src/apollo/Apollo.ts | 154 ++++++++++- src/apollo/utils/Ed25519KeyCommon.ts | 4 + src/apollo/utils/Ed25519KeyPair.ts | 3 + src/apollo/utils/Ed25519PrivateKey.ts | 3 + src/apollo/utils/Ed25519PublicKey.ts | 3 + src/apollo/utils/Secp256k1KeyCommon.ts | 4 + src/apollo/utils/Secp256k1KeyPair.ts | 3 + src/apollo/utils/Secp256k1PrivateKey.ts | 6 + src/apollo/utils/Secp256k1PublicKey.ts | 6 + src/apollo/utils/X25519KeyCommon.ts | 3 + src/apollo/utils/X25519KeyPair.ts | 3 + src/apollo/utils/X25519PrivateKey.ts | 3 + src/apollo/utils/X25519PublicKey.ts | 3 + src/apollo/utils/jwt/JWT.ts | 21 +- src/castor/Castor.ts | 139 +++++++++- src/castor/did/prismDID/PrismDIDPublicKey.ts | 2 +- .../resolver/LongFormPrismDIDResolver.ts | 18 +- src/domain/buildingBlocks/Apollo.ts | 2 +- src/domain/buildingBlocks/Castor.ts | 2 +- src/domain/buildingBlocks/Mercury.ts | 2 +- src/domain/buildingBlocks/Pluto.ts | 40 +-- src/domain/buildingBlocks/Pollux.ts | 2 +- src/domain/models/PrivateKey.ts | 15 + src/domain/models/index.ts | 25 +- src/index.ts | 13 +- src/mercury/Mercury.ts | 51 +++- src/mercury/didcomm/Wrapper.ts | 4 + src/peer-did/PeerDID.ts | 3 + src/peer-did/PeerDIDCreate.ts | 21 ++ src/pluto/Pluto.ts | 261 ++++++++++++++++-- src/pollux/Pollux.ts | 23 +- src/prism-agent/Agent.Credentials.ts | 57 +++- src/prism-agent/Agent.DIDHigherFunctions.ts | 49 +++- src/prism-agent/Agent.Invitations.ts | 55 +++- src/prism-agent/Agent.MessageEvents.ts | 33 +++ src/prism-agent/Agent.ts | 184 +++++++++++- .../connectionsManager/ConnectionsManager.ts | 114 +++++++- src/prism-agent/helpers/ApiImpl.ts | 3 + .../mediator/BasicMediatorHandler.ts | 72 ++++- .../mediator/PlutoMediatorStore.ts | 29 +- .../connection/DIDCommConnectionRunner.ts | 2 +- .../invitation/v2/InvitationRunner.ts | 2 +- .../protocols/pickup/PickupRunner.ts | 2 +- src/prism-agent/types/index.ts | 6 +- tsconfig.json | 2 +- typedoc.json | 17 ++ 58 files changed, 1594 insertions(+), 745 deletions(-) create mode 100644 .github/workflows/release-docs.yml delete mode 100644 docs/Agent.md delete mode 100644 docs/Apollo.md delete mode 100644 docs/Castor.md delete mode 100644 docs/Pluto.md delete mode 100644 docs/index.md delete mode 100644 docs/sidebars.js create mode 100644 typedoc.json diff --git a/.github/workflows/release-docs.yml b/.github/workflows/release-docs.yml new file mode 100644 index 000000000..d7e2987e2 --- /dev/null +++ b/.github/workflows/release-docs.yml @@ -0,0 +1,49 @@ +--- +name: Release Documentation + +on: + workflow_dispatch: + push: + tags: + - "*" + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + docs: + name: build documentation and release + runs-on: ubuntu-latest + env: + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "lts/*" + registry-url: https://npm.pkg.github.com/ + scope: "@input-output-hk" + + - name: Install dependencies + run: npm install + + - name: Build project + run: npm run build + + - name: Build Docs + run: npm run docs + + - name: Push + uses: s0/git-publish-subdir-action@develop + env: + REPO: self + BRANCH: gh-pages # The branch name where you want to push the assets + FOLDER: docs # The directory where your assets are generated + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # GitHub will automatically add this - you don't need to bother getting a token + MESSAGE: "feat(docs): ({sha}) {msg}" # The commit message \ No newline at end of file diff --git a/.gitignore b/.gitignore index ac3c7e75c..821b86ecc 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* *.db -didcomm-pkg \ No newline at end of file +didcomm-pkg +generated-docs \ No newline at end of file diff --git a/.npmignore b/.npmignore index d36841e97..0d251bf36 100644 --- a/.npmignore +++ b/.npmignore @@ -21,6 +21,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +generated-docs # Development folders and files public diff --git a/README.md b/README.md index eb3a75aa9..6273062df 100644 --- a/README.md +++ b/README.md @@ -15,119 +15,24 @@ credentials, alongside tools and frameworks to help expand your ecosystem. The complete platform is separated in multiple repositories: * [atala-prism-wallet-sdk-swift](https://github.com/input-output-hk/atala-prism-wallet-sdk-swift) - Repo that implements Atala PRISM for Apple platforms in Swift. +* [atala-prism-wallet-sdk-kmm](https://github.com/input-output-hk/atala-prism-wallet-sdk-kmm) - Repo that implements Atala PRISM for Apple platforms in kmm, jvm. * [atala-prism-wallet-sdk-ts](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts) - Repo that implements Atala PRISM for Browser and NodeJS platforms in TypeScript. * [atala-prism-building-blocks](https://github.com/input-output-hk/atala-prism-building-blocks) - Repo that contains the platform Building Blocks. -### Modules / APIs -Atala PRISM TypeScript SDK provides the following building blocks: +### SDK Overview +* Apollo: Provides a suite of necessary cryptographic operations. +* Castor: Provides a suite of operations to create, manage and resolve decentralized identifiers. +* Pollux: Provides a suite of operations for handling [verifiable credentials](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#verifiable-credentials). +* Mercury: Provides a suite of operations for handling DIDComm V2 messages. +* Pluto: Provides an interface for storage operations in a portable, storage-agnostic manner. +* PrismAgent: PrismAgent, a component using all other building blocks, provides basic edge agent capabilities, including implementing DIDComm V2 protocols. -* **Apollo**: Provides a suite of necessary cryptographic operations. -* **Castor**: Provides a suite of operations to create, manage and resolve decentralized identifiers. -* **Pollux**: Provides a suite of operations for handling verifiable credentials. -* **Mercury**: Provides a suite of operations for handling DIDComm V2 messages. -* **Pluto**: Provides an interface for storage operations in a portable, storage-agnostic manner. -* **PrismAgent**: PrismAgent, a component using all other building blocks, provides a basic edge agent capabilities, including implementation of DIDComm V2 protocols. - -## DIDComm Protocol Support - -| Protocol | Supported | Notes | -| --- | :--: | -- | -| [Mediator Coordinator](https://didcomm.org/mediator-coordination/2.0/) | :white_check_mark: | -- | -| Connection | :white_check_mark: | Atala PRISM proprietary | -| [DIDComm V2 Issue Credential](https://github.com/decentralized-identity/waci-didcomm/tree/main/issue_credential) | :white_check_mark: | -- | -| [DIDComm V2 Present Proof](https://github.com/decentralized-identity/waci-didcomm/blob/main/present_proof/present-proof-v3.md) | :white_check_mark: | -- | - -## Getting Started - -### Supported platforms - -| Platform | Supported | Notes | -| --- | :--: | -- | -| Browser | :white_check_mark: | -- | -| Browser Extension | :white_check_mark: | -- | -| Node.js | :white_check_mark: | -- | -| React Native | :x: | -- | - -### Installing -Install the SDK using `npm` or `yarn`: - -`npm install @input-output-hk/atala-prism-wallet-sdk` - -`yarn add @input-output-hk/atala-prism-wallet-sdk` - -### Browser setup - -Some additional steps are needed to use the SDK in the browser. - -The library expects `didcomm_js_bg` WebAssembly file to be available in the route of -the project, so it need to be copied to the project's `public` folder. - -One way to do it could be to add the following command to the `postinstall`: - -```shell -cp node_modules/@input-output-hk/atala-prism-wallet-sdk/build/browser/didcomm_js_bg.wasm ./public/ -``` - -If you use Webpack or Rollup, appropriate plugin could be used to copy the file instead. - -The last needed step is to provide browser polyfills for `fs` and `path` modules. -We plan to remove this requirement in the future, but for now it is needed due to -`sql.js` dependency. Providing polyfills is highly dependent on the toolchain used, -so please refer to the documentation of your build tool for more information. - -### Usage -Once `@input-output-hk/atala-prism-wallet-sdk` is installed as a dependency, -package could be imported using both ES modules and CommonJS syntax. - -`import * as prismSDK from '@input-output-hk/atala-prism-wallet-sdk';` - -or - -`const prismSDK = require('@input-output-hk/atala-prism-wallet-sdk');` - -Then, provided modules could be used to set up an SSI Edge Agent: - -```ts -const apollo = new prismSDK.Apollo(); -const api = new prismSDK.ApiImpl(); -const castor = new prismSDK.Castor(apollo); -const pluto = new prismSDK.Pluto({ - type: "sql", -}); -const didcommWrapper = new prismSDK.DIDCommWrapper(apollo, castor, pluto); -const mercury = new prismSDK.Mercury(castor, didcommWrapper, api); -const mediatorDID = prismSDK.Domain.DID.fromString( - "did:peer:2.Ez6LSms555YhFthn1WV8ciDBpZm86hK9tp83WojJUmxPGk1hZ.Vz6MkmdBjMyB4TS5UbbQw54szm8yvMMf1ftGV2sQVYAxaeWhE.SeyJpZCI6Im5ldy1pZCIsInQiOiJkbSIsInMiOiJodHRwczovL21lZGlhdG9yLnJvb3RzaWQuY2xvdWQiLCJhIjpbImRpZGNvbW0vdjIiXX0" -); -const mediatorStore = new prismSDK.PublicMediatorStore(pluto); -const mediatorHandler = new prismSDK.BasicMediatorHandler(mediatorDID, mercury, mediatorStore); -const connectionsManager = new prismSDK.ConnectionsManager(castor, mercury, pluto, mediatorHandler); - -const seedWords = apollo.createRandomSeed(); - -const agent = new prismSDK.Agent( - apollo, - castor, - pluto, - mercury, - mediatorHandler, - connectionsManager, - seedWords.seed - ); - -await agent.start(); -``` - -### Running demos - -1. For Nodejs: -First build the sdk from root folder -```bash -npm i -npm run build -``` +### Getting started +This repository includes a browser and a nodejs demo application, and also a step by step documented process. +1. Running the DEMOS +For Nodejs: Now cd into the demo directory "demos/node" ```bash cd demos/node @@ -135,16 +40,10 @@ npm i node index.js ``` -2. For Browser: -First build the sdk from root folder -```bash -npm i -npm run build -``` - +For Browser: Now cd into the demo directory "demos/browser" ```bash -cd demos/node +cd demos/browser npm i npm run start ``` @@ -152,3 +51,10 @@ npm run start To run browser demo app, just run `npm run dev:browser` and browser will automatically open and load the demo app. To run Node.js demo app, run `npm run dev:node` to build the demo app and then run it with `node build/node-test/index.js`. + + +2. To see how the step by steps examples can guide you refer to each section inside docs folder, Apollo, Castor, Pollux, Mercury, Pluto, Agent + +3. Jump straight into the [SDK-REFERENCE](modules.html) + + diff --git a/docs/Agent.md b/docs/Agent.md deleted file mode 100644 index e7ba21490..000000000 --- a/docs/Agent.md +++ /dev/null @@ -1,139 +0,0 @@ -# Agent - -The Agent is a module which combines all the building blocks of the PRISM -Wallet SDK - Apollo, Castor, Pluto, Mercury, and Pollux - to provide a -streamlined experience for developers to build Edge Agents and applications on -top of it. Agent implements core capabilities of an Edge Agent, such as [DID](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#decentralized-identifer) management and support for a range of DIDComm protocols, including mediation, -proof presentation, issue credentials, and out-of-band messages. DIDComm-related -functionality comes from the [DIDComm V2](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#didcomm) specification. - -## DIDComm Protocol Support -| Protocol | Supported | Notes | -| --- | :--: | -- | -| [Mediator Coordinator](https://didcomm.org/mediator-coordination/2.0/) | :white_check_mark: | -- | -| Connection | :white_check_mark: | Atala PRISM proprietary | -| [DIDComm V2 Issue Credential](https://github.com/decentralized-identity/waci-didcomm/tree/main/issue_credential) | :white_check_mark: | -- | -| [DIDComm V2 Present Proof](https://github.com/decentralized-identity/waci-didcomm/blob/main/present_proof/present-proof-v3.md) | :white_check_mark: | -- | - -### How to use didcomm inside your webpack application -It is required for you to copy the wasm file "didcomm-rust/didcomm-browser/didcomm_js_bg.wasm" -inside the public folder that your react application has, usually "./public". -It is important also to keep the filename as it comes, without changing anything to it. - -## Agent Setup - -Before importing modules, ensure you have the DIDComm wasm file in the public directory of your app/website. You can copy using this command `cp ./node_modules/@input-output-hk/atala-prism-wallet-sdk/build/browser/index_bg.wasm ./public/index_bg.wasm`. - -Assuming the installation Wallet SDK is a dependency, and the wasm file exists in your public/static directory, -here's an example of -how to import and init Agent module: - -```ts -import { - Apollo, - Castor, - Pluto, - Mercury, - Agent, - Domain, - ApiImpl, - DidCommWrapper, - PublicMediatorStore, - BasicMediatorHandler, - ConnectionsManager -} from '@input-output-hk/atala-prism-wallet-sdk'; - -const apollo = new Apollo(); -const castor = new Castor(apollo); -const pluto = new Pluto({ - type: 'sqljs', -}); - -const api = new ApiImpl(); -const didCommWrapper = DidCommWrapper(apollo, castor, pluto); -const mercury = new Mercury(castor, didCommWrapper, api); - -const mediatorDID = Domain.DID.fromString( - "did:peer:2.Ez6LSms555YhFthn1WV8ciDBpZm86hK9tp83WojJUmxPGk1hZ.Vz6MkmdBjMyB4TS5UbbQw54szm8yvMMf1ftGV2sQVYAxaeWhE.SeyJpZCI6Im5ldy1pZCIsInQiOiJkbSIsInMiOiJodHRwczovL21lZGlhdG9yLnJvb3RzaWQuY2xvdWQiLCJhIjpbImRpZGNvbW0vdjIiXX0" -); -const mediatorStore = new PublicMediatorStore(pluto); -const mediatorHandler = new BasicMediatorHandler(mediatorDID, mercury, mediatorStore); -const connectionManager = new ConnectionsManager(castor, mercury, pluto, mediatorHandler); - -const seedAndMnemonics = apollo.createRandomSeed(); -const agent = new Agent( - apollo, - castor, - pluto, - mercury, - mediatorHandler, - connectionManager, - seedAndMnemonics.seed -); - -try { - await agent.start(); - console.info(`Welcome to Atala PRISM Edge Agent [state=${agent.state}]`); -} catch (e) { - console.error("Failed to start agent", e); -} -``` - -Quite a lot of things are happening here, so let's break it down: - -- [Apollo](/wallet-sdk-ts/apollo), [Castor](/wallet-sdk-ts/castor), [Pluto](/wallet-sdk-ts/pluto), Mercury, and Agent are the main building blocks of the SDK. The first three have already been covered in more detail in the previous sections, as they are user-facing modules usable independently. Other modules could be considered internal, and the intention is not to use them directly. -- Mercury is a module that deals with DIDComm V2 messaging and is used - primarily by the Agent to handle DIDComm messages. -- Domain is a set of domain-specific types, models, and utilities usable in different contexts. -- Edge Agents need help to provide highly-available service endpoints for providing public endpoints and mailboxes to agents. `PublicMediatorStore`, `BasicMediatorHandler`, and - `ConnectionsManager` are abstractions for interacting with mediators. -- Once an instance of Agent is prepared, call the `start` method to start the - agent and mediator services. - -## Establishing Connection - -In DIDComm Agent's world, a connection is nothing more than a pair of DIDs and -a label. The Agent creates a new `peer` DID for each connection and stores it in -the wallet storage (Pluto), along with the DID of the other agent and the -human-readable label used to help users navigate through the list of connections. - -High-level steps for establishing a connection are as follows: - -- An agent, typically a cloud agent representing an issuer or verifier, creates a - new DID for connection. -- New DID and, usually, a human-readable label, used to represent the inviter, are used as inputs to create an out-of-band invitation message. The invitation message is encoded appropriately (QR code, deep-link, etc.) and shared with the other party. -- Other agent, typically an edge agent representing a holder, receives the - invitation and, if accepted, creates a new DID for connection and sends a response - back to the inviter. -- Both agents have a pair of DIDs and can store the new connection for - future interactions. - -### Example code - -Here is an example of how to establish a connection with another agent assuming that the receipt of the invitation as a QR code and that agent has started: - -```ts -// ... QR code scaned and decoded -const qrCodeDecoded = "https://domain.com/path?_oob=eyJpZCI6ImUzNzZlZGYyLWVmNmQtNDk4ZS1hMTk3LWMwZTI2MGQxNTA2OCIsInR5cGUiOiJodHRwczovL2RpZGNvbW0ub3JnL291dC1vZi1iYW5kLzIuMC9pbnZpdGF0aW9uIiwiZnJvbSI6ImRpZDpwZWVyOjIuRXo2TFNoQUFxY1ZlZXRQNmlrdHk1bXl5OFFweE5wVlk3NEF0YUZuVmFrOFRwYnRkSy5WejZNa2dlYUVWZ0FVSHoyQWczaUZLRDIxMjZTR0tERnpIS28zSEFxYmM4eExOM1paLlNleUowSWpvaVpHMGlMQ0p6SWpvaWFIUjBjRG92TDJodmMzUXVaRzlqYTJWeUxtbHVkR1Z5Ym1Gc09qZ3dPREF2Wkdsa1kyOXRiU0lzSW5JaU9sdGRMQ0poSWpwYkltUnBaR052YlcwdmRqSWlYWDAiLCJib2R5Ijp7ImdvYWxfY29kZSI6ImNvbm5lY3QiLCJnb2FsIjoiRXN0YWJsaXNoIGEgdHJ1c3QgY29ubmVjdGlvbiBiZXR3ZWVuIHR3byBwZWVycyIsImFjY2VwdCI6W119fQ=="; -const oobMessage = await agent.parseOOBInvitation(qrCodeDecoded); - -// check if received message is a connection invitation -if ( - oobMessage.type === "https://didcomm.org/out-of-band/2.0/invitation" && - oobMessage.body.goal_code === "connect" -) { - // accept invitation: this will create a new DID for connection and send response messege to the other agent - await agent.acceptDIDCommInvitation(message); - console.info( - `Connection established with ${oobMessage.body.label}` - ); -} -``` - -## Receiving a credential - -Coming soon... - -## Presenting a proof in verification flow - -Coming soon... diff --git a/docs/Apollo.md b/docs/Apollo.md deleted file mode 100644 index 3c45c543a..000000000 --- a/docs/Apollo.md +++ /dev/null @@ -1,100 +0,0 @@ -# Apollo - -Apollo module provides a suite of cryptographic primitives designed to ensure the integrity, authenticity, and confidentiality of stored and processed data. Currently, Apollo offers primitives for generating mnemonics, seeds, and key pairs; and primitives for cryptographically signing data and verification of signatures. - -## Apollo setup - -Assuming the installation of the Wallet SDK as a dependency, here's an example of -how to import and init Apollo module: - -```ts -import { Apollo, Domain } from '@input-output-hk/atala-prism-wallet-sdk'; - -const apollo = new Apollo(); - -// use apollo... -``` - -`Domain` contains a domain-specific types and models used by Apollo and other modules in the SDK. - -## API Overview -Here's a brief explanation of the essential primitives: - -- `createRandomMnemonics`: This function creates a random mnemonic phrase whose usage is as a seed for generating a private key. - -```ts -const mnemonics = apollo.createRandomMnemonics(); -``` - -- `createSeed`: This function takes mnemonics and passphrases and creates a seed object to generate a private key. It may throw an error if the mnemonics are invalid. - -```ts -const seed = apollo.createSeed(mnemonics, "my-secret-passphrase"); -``` - -- `createRandomSeed`: This function creates a random mnemonic phrase and seed. - -```ts -const {mnemonics, seed} = apollo.createRandomSeed(); -``` - -- `createKeyPairFromKeyCurve`: This function creates a key pair (a private and public key) using a given seed and key curve. - -```ts -const keyPairSecp256K1 = apollo.createKeyPairFromKeyCurve({ - curve: Domain.Curve.SECP256K1 -}, seed); -``` - -- `createKeyPairFromPrivateKey`: This function creates a key pair (a private and -public key) using a given privateKey. - -In the following example, privateKey is of type PrivateKey - -```ts -const keyPairSecp256K1 = apollo.createKeyPairFromPrivateKey( - privateKey -); -``` - -Supported key curves are: `SECP256K1`, `ED25519` and `X25519`. `seed` is optional -param used only for `SECP256K1` keys. - -- `compressedPublicKeyFromPublicKey`: This function compresses a given public key into a shorter, more efficient form. - -```ts -let compressedPublicKey = apollo.compressedPublicKeyFromPublicKey(keyPairSecp256K1.publicKey); -``` - -> NOTE: This API works only with `SECP256K1` key curve. - -- `signStringMessage`, `signByteArrayMessage`: This function signs a message using a given private key, returning the signature. - -```ts -const message = "data to sign"; -const messageBytes = new TextEncoder().encode(message); - -const signatureSecp256K1 = apollo.signStringMessage(keyPairSecp256K1.privateKey, message); -const signatureEd25519 = apollo.signByteArrayMessage(keyPairEd25519.privateKey, messageBytes); -``` - -> **Note:** Signing data is possible only with `SECP256K1` and `ED25519` key curves. - -- `verifySignature`: This function verifies the authenticity of a signature using the corresponding public key, challenge, and signature. It returns a boolean value indicating whether the signature is valid or not. - -```ts -let isValid = apollo.verifySignature( - keyPairFromCurveSecp256K1.publicKey, - messageBytes, - signatureSecp256K1.value -); -``` - -- `apollo utils`: Specific operations can be applied with Public, Private and KeyPairs of the supported algorithms and keycurves (secp256k1, x25519 and ed25519) to import and export keys from any format used by the user into an instance we can manage. - -All private and public key instances can be exported into a buffer by calling public.getEncoded, private.getEncoded. -Also, the impport process should be similar using fromBytes as follows: - -```ts - const publicKey = Secp256k1PublicKey.secp256k1FromBytes(Buffer.from(keyInHex, 'hex')) -``` diff --git a/docs/Castor.md b/docs/Castor.md deleted file mode 100644 index b0bb55c75..000000000 --- a/docs/Castor.md +++ /dev/null @@ -1,92 +0,0 @@ -# Castor - -The Castor module provides a suite of primitives for working with [Decentralized Identifiers (DIDs)](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#decentralized-identifer). It allows developers to create and manage DIDs, associated keys, and service endpoints and resolve DIDs to retrieve corresponding [DID Documents](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#did-document). - -Castor currently supports the creation and resolution of `prism` and `peer` [DID methods](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#did-method). - -> **Note:** Castor depends on the Apollo module for cryptographic operations. - -## Castor setup - -Assuming the Wallet SDK installation, here's an example of -how to import and init Castor module: - -```ts -import { Apollo, Castor, Domain } from '@input-output-hk/atala-prism-wallet-sdk'; - -const apollo = new Apollo(); -const castor = new Castor(apollo); - -// use castor... -``` - -`Domain` contains domain-specific types and models used by Apollo and other modules in the SDK. - -## API Overview -Here's a brief explanation of the essential primitives: - -- `parseDID`: This function takes a string representation of a DID and returns an instance of `Domain.DID`. It may throw an error if the string is not a valid -DID. - -```ts -const parsedPrismDid = castor.parseDID( - "did:prism:b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k" -); -const parsedPeerDid = castor.parseDID( - "did:peer:2.Ez6LSjynBE8VfdyACrRPqX76s9mHKs2jYH9Z5KyXYjhFUZyEk.Vz6Mkm7jkKvcwBgDHP528ARtTYmBrqWmERFURP6p3casdekV2.SW10" -); -``` - -- `createPrismDID`: This function creates a new `prism` DID, using a given master public key and a list of services. It may throw an error if the master public key or services are invalid. - -```ts -const exampleServiceEndpoint = new Domain.Service("didcomm", ["DIDCommMessaging"], { - uri: "https://example.com/endpoint", - accept: ["didcomm/v2"], - routingKeys: ["did:example:somemediator#somekey"], -}); -``` - -```ts -const prismDid = await castor.createPrismDID( - keyPairFromCurveSecp256K1.publicKey, - [exampleServiceEndpoint] -); -``` - -- `createPeerDID`: This function creates new peer DID, using a given key agreement, authentication key pairs, and a list of services. It may throw an error if the key pairs or services are invalid. - -```ts -const peerDid = await castor.createPeerDID( - [keyPairFromCurveEd25519, keyPairFromCurveX25519], - [exampleService] -); -``` - -- `resolveDID`: This function asynchronously resolves a DID to its corresponding DID Document. It may throw an error if the DID is invalid or the document is unretrievable. - -> **Note:** only `prism` and `peer` DID methods are currently supported! - -```ts -const didDoc = await castor.resolveDID("did:prism:123456"); -``` - -- `verifySignature`: This function verifies the authenticity of a signature using given DID, challenge, and signature data. It returns a boolean value indicating whether the signature is valid or not. It may throw an error if the DID or signature data are invalid. - -```ts -const message = "data to sign"; -const messageBytes = new TextEncoder().encode(message); -const signatureSecp256K1 = apollo.signStringMessage(keyPairSecp256K1.privateKey, message); - -const did = castor.parseDID("did:prism:123456"); -const challenge = messageBytes -const signature = signatureSecp256K1.value; - -const isValid = castor.verifySignature( - castor.parseDID("did:prism:123456"), - challenge, // Uint8Array - signature // Uint8Array -); -``` - -> **Note:** This function is similar to the `verifySignature` function in the Apollo module, but it facilitates parsing the DID and extracting the right public key. diff --git a/docs/Pluto.md b/docs/Pluto.md deleted file mode 100644 index d468b5f8a..000000000 --- a/docs/Pluto.md +++ /dev/null @@ -1,150 +0,0 @@ -# Pluto - -Pluto defines PRISM's data storage interface for working with [SSI](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#self-sovereign-identity) artifacts such as [DIDs](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#decentralized-identifier), private keys, and [DIDComm](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#didcomm) messages. Depending on the platform and specific use case, it's up to the application to appropriately implement this interface. - -As part of TypeScript Wallet SDK, Pluto also provides a default implementation based on TypeORM supporting various drivers. Still, on the frontend, if the type is `sqljs`, it will preset to use `sqljs` together with indexedDB. Pluto is an example and can get used for prototyping and testing before investing in a more robust use-case-specific solution. In the future, we might provide one or more implementations we could recommend for production use. - -## Interface preview - -Here's the part of the Pluto interface to give you an idea of what it looks like. Please check the `Domain` module in the SDK for the full interface specification. - -```ts -interface Pluto { - /** - * A place to put initialization logic, if needed, for the particular implementation. - */ - start(): Promise; - - /** - * This method should implement a persistent mechanism given PRISM DID and its private key (SECP256K1). - */ - storePrismDID( - did: DID, - keyPathIndex: number, - privateKey: PrivateKey, - privateKeyMetaId: string | null, - alias?: string - ): Promise; - - /** - * This method should implement a mechanism persistent mechanism given Peer DID and its private keys (ED25519 and X25519). - */ - storePeerDID(did: DID, privateKeys: Array): Promise; - - /** - * This method should implement a mechanism to persist private keys (SECP256K1, ED25519, and X25519). - */ - storePrivateKeys( - privateKey: PrivateKey, - did: DID, - keyPathIndex: number, - metaId: string | null - ): Promise; - - /** - * This method should implement a mechanism to persist the given DIDComm message. - */ - storeMessage(message: Message): Promise; - - /** - * This method should implement a mechanism to persist given mediator data. - */ - storeMediator(mediator: DID, host: DID, routing: DID): Promise; - - /** - * This method should implement a mechanism to persist given Verifiable Credential. - */ - storeCredential(credential: VerifiableCredential): Promise; - - /** - * This method should implement a mechanism to retrieve all persisted PRISM DIDs. - */ - getAllPrismDIDs(): Promise; - - /** - * This method should implement a mechanism to retrieve a pair of DIDs (connection pairwise DIDs). - */ - getPairByName(name: string): Promise; - - /** - * This method should implement a mechanism to retrieve a DIDComm message by ID. - */ - getMessage(id: string): Promise; - - /** - * This method should implement a mechanism to retrieve all persisted DIDComm messages. - */ - getAllMessages(): Promise>; - - /** - * This method should implement a mechanism to retrieve all persisted mediators. - */ - getAllMediators(): Promise>; - - /** - * This method should implement a mechanism to retrieve all persisted credentials. - */ - getAllCredentials(): Promise>; -} -``` - -## Usage example (default implementation) - -Here's an example of how to use the default implementation of Pluto: - -```ts -import { - Pluto as PlutoDefault, - Apollo, - Castor, - Domain -} from '@input-output-hk/atala-prism-wallet-sdk'; - -const apollo = new Apollo(); -const castor = new Castor(apollo); - -async function createPrismDID() { - const {seed} = apollo.createRandomSeed(); - const keyPairFromCurveSecp256K1 = apollo.createKeyPairFromKeyCurve( - seed, - { - curve: Domain.Curve.SECP256K1, - } - ); - - const prismDid = await castor.createPrismDID( - keyPairFromCurveSecp256K1.publicKey, - [] - ); - - return {prismDid, privateKey: keyPairFromCurveSecp256K1.privateKey}; -} - -const plutoInstance = new PlutoDefault({ - type: 'sqljs', -}); - -try { - await plutoInstance.start(); - console.info("Pluto start success"); - // Create and store a new Prism DID - const {prismDid, privateKey} = await createPrismDID(); - const keyPathIndex = await plutoInstance.getPrismLastKeyPathIndex(); - await plutoInstance.storePrismDID( - prismDid, - keyPathIndex + 1, - privateKey, - null, - `DID from example - ${keyPathIndex}` // alias - ); -} catch (error) { - console.error("Pluto start failed", error); -} - -// Retrieve all persisted Prism DIDs at any time -async function getAllPrismDIDs() { - const prismDIDs = await pluto.getAllPrismDIDs(); - console.info("All Prism DIDs", prismDIDs); -} - -``` diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 4af66a889..000000000 --- a/docs/index.md +++ /dev/null @@ -1,12 +0,0 @@ -# Wallet SDK Typescript - -Atala PRISM TypeScript SDK provides a library and documentation for developers to build TypeScript-based [SSI](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#self-sovereign-identity) applications with Atala PRISM. It offers a set of utilities for building SSI Edge Agents speaking [DIDComm](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#didcomm) V2 protocols. - -Atala PRISM TypeScript SDK provides the following building blocks: - -* Apollo: Provides a suite of necessary cryptographic operations. -* Castor: Provides a suite of operations to create, manage and resolve decentralized identifiers. -* Pollux: Provides a suite of operations for handling [verifiable credentials](https://github.com/input-output-hk/atala-prism-docs/blob/main/documentation/docs/concepts/glossary.md#verifiable-credentials). -* Mercury: Provides a suite of operations for handling DIDComm V2 messages. -* Pluto: Provides an interface for storage operations in a portable, storage-agnostic manner. -* PrismAgent: PrismAgent, a component using all other building blocks, provides basic edge agent capabilities, including implementing DIDComm V2 protocols. diff --git a/docs/sidebars.js b/docs/sidebars.js deleted file mode 100644 index 4b9094102..000000000 --- a/docs/sidebars.js +++ /dev/null @@ -1,30 +0,0 @@ -// @ts-check - -/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ -const sidebars = { - // By default, Docusaurus generates a sidebar from the docs folder structure - // tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], - - // But you can create a sidebar manually - - walletSdkTsSidebar: [ - 'index', - { - type: 'category', - label: 'Building blocks', - link: { - type: 'generated-index', - title: 'Building blocks', - description: 'Overview of TS Wallet SDK building blocks' - }, - items: [ - 'Apollo', - 'Castor', - 'Agent', - 'Pluto' - ] - }, - ] -} - -module.exports = sidebars diff --git a/package-lock.json b/package-lock.json index 78a3ef0cb..3e45d4fee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -120,6 +120,11 @@ "stream-browserify": "^3.0.0", "style-loader": "^3.3.1", "terser-webpack-plugin": "^5.3.7", + "typedoc": "^0.24.8", + "typedoc-plugin-markdown": "3.15.3", + "typedoc-plugin-rename-defaults": "^0.6.5", + "typedoc-plugin-superstruct": "^1.0.0", + "typedoc-theme-hierarchy": "^4.0.0", "typescript": "^4.9.5", "url": "^0.11.0", "url-loader": "^4.1.1", @@ -6265,6 +6270,12 @@ "node": ">=8" } }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", + "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", + "dev": true + }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -16575,6 +16586,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -17009,6 +17026,12 @@ "yallist": "^3.0.2" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "node_modules/magic-string": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", @@ -26642,6 +26665,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shiki": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz", + "integrity": "sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==", + "dev": true, + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -28186,6 +28221,107 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typedoc": { + "version": "0.24.8", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", + "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.0", + "shiki": "^0.14.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" + } + }, + "node_modules/typedoc-plugin-markdown": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.15.3.tgz", + "integrity": "sha512-idntFYu3vfaY3eaD+w9DeRd0PmNGqGuNLKihPU9poxFGnATJYGn9dPtEhn2QrTdishFMg7jPXAhos+2T6YCWRQ==", + "dev": true, + "dependencies": { + "handlebars": "^4.7.7" + }, + "peerDependencies": { + "typedoc": ">=0.24.0" + } + }, + "node_modules/typedoc-plugin-rename-defaults": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.6.5.tgz", + "integrity": "sha512-DwkgwRMxgu3UrDR3VUAdnF9jYzM6p7rw6UcVIh4MD7yjEmFDR8WWyOlk6oYgELmRYHxTDx0f0GK6iSgoxSh/Qw==", + "dev": true, + "peerDependencies": { + "typedoc": "0.22.x || 0.23.x || 0.24.x" + } + }, + "node_modules/typedoc-plugin-superstruct": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-superstruct/-/typedoc-plugin-superstruct-1.0.0.tgz", + "integrity": "sha512-1kSzZ2fp8/d7iwczklKsCJqFopPAQzkS2t/WjLYo5RwfllwrfPsLIsVyqLdtKzks29n5SRs8N3dFu5oRfJtaMQ==", + "dev": true, + "peerDependencies": { + "typedoc": "0.23.x || 0.24.x" + } + }, + "node_modules/typedoc-theme-hierarchy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedoc-theme-hierarchy/-/typedoc-theme-hierarchy-4.0.0.tgz", + "integrity": "sha512-/y8QfmkLN+NS57hoxsS/vD1fdAPdkd7JtC7xWp2Lk3rE6/cRweFdEfaKD6GJCQMD3CuSD7Ldcc5vjwwrF4UqyQ==", + "dev": true, + "dependencies": { + "fs-extra": "^10.0.0" + }, + "peerDependencies": { + "typedoc": "^0.24.0" + } + }, + "node_modules/typedoc-theme-hierarchy/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/typeorm": { "version": "0.3.16", "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.16.tgz", @@ -28891,6 +29027,18 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/package.json b/package.json index 5d132f41a..360a9e8d9 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "dev:node": "rm -rf build && npm run types && webpack --watch --mode=development --config webpack/webpack.node.conf.js", "test": "jest", "coverage": "npm run test -- --coverage", - "lint": "npx eslint ." + "lint": "npx eslint .", + "docs": "npx typedoc --options typedoc.json --hideGenerator" }, "publishConfig": { "registry": "https://npm.pkg.github.com/" @@ -121,6 +122,11 @@ "stream-browserify": "^3.0.0", "style-loader": "^3.3.1", "terser-webpack-plugin": "^5.3.7", + "typedoc": "^0.24.8", + "typedoc-plugin-markdown": "3.15.3", + "typedoc-plugin-rename-defaults": "^0.6.5", + "typedoc-plugin-superstruct": "^1.0.0", + "typedoc-theme-hierarchy": "^4.0.0", "typescript": "^4.9.5", "url": "^0.11.0", "url-loader": "^4.1.1", @@ -146,8 +152,8 @@ "antlr4ts": "^0.5.0-alpha.4", "assert": "^2.0.0", "axios": "^1.3.4", - "buffer": "^6.0.3", "bn.js": "^5.2.1", + "buffer": "^6.0.3", "core-js": "^3.29.1", "did-jwt": "^6.11.5", "did-resolver": "^4.1.0", diff --git a/src/apollo/Apollo.ts b/src/apollo/Apollo.ts index cc258b09d..54633cd00 100644 --- a/src/apollo/Apollo.ts +++ b/src/apollo/Apollo.ts @@ -1,4 +1,4 @@ -import { default as ApolloInterface } from "../domain/buildingBlocks/Apollo"; +import { Apollo as ApolloInterface } from "../domain/buildingBlocks/Apollo"; import * as bip39 from "@scure/bip39"; import { wordlist } from "@scure/bip39/wordlists/english"; import { base64url } from "multiformats/bases/base64"; @@ -32,8 +32,25 @@ import { ApolloError } from "../domain/models/Errors"; import { OctetKeyPair } from "./models/OctetKeyPair"; import { X25519PrivateKey } from "./utils/X25519PrivateKey"; + const EC = elliptic.ec; + +/** + * Apollo defines the set of cryptographic operations that are used in the Atala PRISM. + * + * @export + * @class Apollo + * @typedef {Apollo} + */ export default class Apollo implements ApolloInterface { + /** + * getKeyPairForCurve: Method to generate a KeyPair from a seed or randomly + * + * @private + * @param {KeyCurve} curve + * @param {?Seed} [seed] + * @returns {KeyPair} + */ private getKeyPairForCurve(curve: KeyCurve, seed?: Seed): KeyPair { const derivationPath = DerivationPath.fromPath( `m/${curve.index || 0}'/0'/0'` @@ -87,9 +104,37 @@ export default class Apollo implements ApolloInterface { throw new Error("Method not implemented."); } } + + /** + * Creates a random set of mnemonic phrases that can be used as a seed for generating a private key. + * + * @example + * This function creates a random mnemonic phrase whose usage is as a seed for generating a private key. + * + * ```ts + * const mnemonics = apollo.createRandomMnemonics(); + * ``` + * + * @returns {MnemonicWordList} + */ createRandomMnemonics(): MnemonicWordList { return bip39.generateMnemonic(wordlist, 256).split(" ") as MnemonicWordList; } + + /** + * Takes in a set of mnemonics and a passphrase, and returns a seed object used to generate a private key. + * + * @example + * This function takes mnemonics and passphrases and creates a seed object to generate a private key. It may throw an error if the mnemonics are invalid. + * + * ```ts + * const seed = apollo.createSeed(mnemonics, "my-secret-passphrase"); + * ``` + * + * @param {MnemonicWordList} mnemonics + * @param {?string} [passphrase] + * @returns {Seed} + */ createSeed(mnemonics: MnemonicWordList, passphrase?: string): Seed { const mnemonicString = mnemonics.join(" "); @@ -108,6 +153,20 @@ export default class Apollo implements ApolloInterface { value: seed, }; } + + /** + * Creates a random seed and a corresponding set of mnemonic phrases. + * + * @example + * This function creates a random mnemonic phrase and seed. + * + * ```ts + * const {mnemonics, seed} = apollo.createRandomSeed(); + * ``` + * + * @param {?string} [passphrase] + * @returns {SeedWords} + */ createRandomSeed(passphrase?: string): SeedWords { const mnemonics = this.createRandomMnemonics(); const seed = this.createSeed(mnemonics, passphrase); @@ -116,9 +175,31 @@ export default class Apollo implements ApolloInterface { mnemonics: mnemonics, }; } + + /** + * Creates a key pair (a private and public key) using a given seed and key curve. + * + * @param {KeyCurve} curve + * @param {?Seed} [seed] + * @returns {KeyPair} + */ createKeyPairFromKeyCurve(curve: KeyCurve, seed?: Seed): KeyPair { return this.getKeyPairForCurve(curve, seed); } + + /** + * Creates a key pair (a private and public key) using a given private key, so only getting its public key + * + * @example + * This function creates a key pair (a private and public key) using a given privateKey. + * + * ```ts + * apollo.createKeyPairFromPrivateKey(privateKey); + * ``` + * + * @param {PrivateKey} privateKey + * @returns {KeyPair} + */ createKeyPairFromPrivateKey(privateKey: PrivateKey): KeyPair { const curve = privateKey.keyCurve; if (privateKey.keyCurve.curve == Curve.SECP256K1) { @@ -180,6 +261,12 @@ export default class Apollo implements ApolloInterface { throw new Error("Method not implemented."); } + /** + * Compresses a given Secp256k1 public key into a shorter, more efficient form. + * + * @param {PublicKey} publicKey + * @returns {CompressedPublicKey} + */ compressedPublicKeyFromPublicKey(publicKey: PublicKey): CompressedPublicKey { const secp256k1PublicKey = Secp256k1PublicKey.secp256k1FromBytes( Buffer.from(publicKey.value) @@ -194,6 +281,12 @@ export default class Apollo implements ApolloInterface { value: secp256k1PublicKey.getEncodedCompressed(), }; } + /** + * Decompresses a given compressed secp256k1 public key into its original form. + * + * @param {Uint8Array} compressedData + * @returns {CompressedPublicKey} + */ compressedPublicKeyFromCompressedData( compressedData: Uint8Array ): CompressedPublicKey { @@ -209,6 +302,14 @@ export default class Apollo implements ApolloInterface { value: secp256k1PublicKey.getEncodedCompressed(), }; } + /** + * Create a public key from byte coordinates. + * + * @param {KeyCurve} curve + * @param {Uint8Array} x + * @param {Uint8Array} y + * @returns {PublicKey} + */ publicKeyFromPoints( curve: KeyCurve, x: Uint8Array, @@ -220,6 +321,13 @@ export default class Apollo implements ApolloInterface { value: publicKey.getEncoded(), }; } + /** + * Create a public key from bytes. + * + * @param {KeyCurve} curve + * @param {Uint8Array} x + * @returns {PublicKey} + */ publicKeyFromPoint(curve: KeyCurve, x: Uint8Array): PublicKey { const publicKey = Secp256k1PublicKey.secp256k1FromBytes(x); return { @@ -227,6 +335,13 @@ export default class Apollo implements ApolloInterface { value: publicKey.getEncoded(), }; } + /** + * Signs a message using a given private key, returning the signature. + * + * @param {PrivateKey} privateKey + * @param {Uint8Array} message + * @returns {Signature} + */ signByteArrayMessage(privateKey: PrivateKey, message: Uint8Array): Signature { const messageBuffer = Buffer.from(message); if (privateKey.keyCurve.curve === Curve.ED25519) { @@ -250,12 +365,34 @@ export default class Apollo implements ApolloInterface { } throw new Error("Method not implemented."); } + /** + * Signs a message using a given private key, returning the signature. + * + * @param {PrivateKey} privateKey + * @param {string} message + * @returns {Signature} + */ signStringMessage(privateKey: PrivateKey, message: string): Signature { return this.signByteArrayMessage(privateKey, Buffer.from(message)); } + /** + * Return the correct Elliptic curve variation from a valid key curve + * + * @param {Curve} curve + * @returns {elliptic.ec} + */ getECInstanceByCurve(curve: Curve): elliptic.ec { return new EC(curve === Curve.SECP256K1 ? "secp256k1" : "curve25519"); } + /** + * Verifies the authenticity of a signature using the corresponding public key, challenge, and + * signature. This function returns a boolean value indicating whether the signature is valid or not. + * + * @param {PublicKey} publicKey + * @param {Uint8Array} challenge + * @param {Uint8Array} signature + * @returns {boolean} + */ verifySignature( publicKey: PublicKey, challenge: Uint8Array, @@ -279,10 +416,25 @@ export default class Apollo implements ApolloInterface { } return false; } + + /** + * Methods that facilitate the creation of a private key JWK + * + * @param {string} id + * @param {KeyPair} keyPair + * @returns {string} + */ getPrivateJWKJson(id: string, keyPair: KeyPair): string { const jsonString = new OctetKeyPair(id, keyPair).privateJson; return jsonString; } + /** + * Methods that facilitate the creation of a public key JWK + * + * @param {string} id + * @param {KeyPair} keyPair + * @returns {string} + */ getPublicJWKJson(id: string, keyPair: KeyPair): string { const jsonString = new OctetKeyPair(id, keyPair).publicJson; return jsonString; diff --git a/src/apollo/utils/Ed25519KeyCommon.ts b/src/apollo/utils/Ed25519KeyCommon.ts index 8fe9ed820..fbed54531 100644 --- a/src/apollo/utils/Ed25519KeyCommon.ts +++ b/src/apollo/utils/Ed25519KeyCommon.ts @@ -1,6 +1,10 @@ import elliptic from "elliptic"; const eddsa = new elliptic.eddsa("ed25519"); + +/** + * @ignore + */ export abstract class Ed25519KeyCommon { public static eddsa = eddsa; public eddsa = eddsa; diff --git a/src/apollo/utils/Ed25519KeyPair.ts b/src/apollo/utils/Ed25519KeyPair.ts index 557551349..9fbf79f81 100644 --- a/src/apollo/utils/Ed25519KeyPair.ts +++ b/src/apollo/utils/Ed25519KeyPair.ts @@ -5,6 +5,9 @@ import { Ed25519KeyCommon } from "./Ed25519KeyCommon"; import { Ed25519PrivateKey } from "./Ed25519PrivateKey"; import { Ed25519PublicKey } from "./Ed25519PublicKey"; +/** + * @ignore + */ export class Ed25519KeyPair extends Ed25519KeyCommon { private privateKey: Ed25519PrivateKey; private publicKey: Ed25519PublicKey; diff --git a/src/apollo/utils/Ed25519PrivateKey.ts b/src/apollo/utils/Ed25519PrivateKey.ts index 0c587dabd..c36717fe8 100644 --- a/src/apollo/utils/Ed25519PrivateKey.ts +++ b/src/apollo/utils/Ed25519PrivateKey.ts @@ -3,6 +3,9 @@ import { base64url } from "multiformats/bases/base64"; import { Ed25519KeyCommon } from "./Ed25519KeyCommon"; +/** + * @ignore + */ export class Ed25519PrivateKey extends Ed25519KeyCommon { private keyPair: elliptic.eddsa.KeyPair; diff --git a/src/apollo/utils/Ed25519PublicKey.ts b/src/apollo/utils/Ed25519PublicKey.ts index 134ba1f71..5c6605781 100644 --- a/src/apollo/utils/Ed25519PublicKey.ts +++ b/src/apollo/utils/Ed25519PublicKey.ts @@ -3,6 +3,9 @@ import { base64url } from "multiformats/bases/base64"; import { Ed25519KeyCommon } from "./Ed25519KeyCommon"; +/** + * @ignore + */ export class Ed25519PublicKey extends Ed25519KeyCommon { private keyPair: elliptic.eddsa.KeyPair; diff --git a/src/apollo/utils/Secp256k1KeyCommon.ts b/src/apollo/utils/Secp256k1KeyCommon.ts index 50a8131bc..83e3c3f34 100644 --- a/src/apollo/utils/Secp256k1KeyCommon.ts +++ b/src/apollo/utils/Secp256k1KeyCommon.ts @@ -1,6 +1,10 @@ import elliptic from "elliptic"; const ec = new elliptic.ec("secp256k1"); + +/** + * @ignore + */ export abstract class Secp256k1KeyCommon { public static ec = ec; public ec = ec; diff --git a/src/apollo/utils/Secp256k1KeyPair.ts b/src/apollo/utils/Secp256k1KeyPair.ts index 9e014e0a0..33997088b 100644 --- a/src/apollo/utils/Secp256k1KeyPair.ts +++ b/src/apollo/utils/Secp256k1KeyPair.ts @@ -5,6 +5,9 @@ import { Secp256k1KeyCommon } from "./Secp256k1KeyCommon"; import { Secp256k1PrivateKey } from "./Secp256k1PrivateKey"; import { Secp256k1PublicKey } from "./Secp256k1PublicKey"; +/** + * @ignore + */ export class Secp256k1KeyPair extends Secp256k1KeyCommon { constructor( public privateKey: Secp256k1PrivateKey, diff --git a/src/apollo/utils/Secp256k1PrivateKey.ts b/src/apollo/utils/Secp256k1PrivateKey.ts index 47d1a053a..0f5b06aae 100644 --- a/src/apollo/utils/Secp256k1PrivateKey.ts +++ b/src/apollo/utils/Secp256k1PrivateKey.ts @@ -5,10 +5,16 @@ import { Secp256k1KeyCommon } from "./Secp256k1KeyCommon"; import { Secp256k1PublicKey } from "./Secp256k1PublicKey"; import { ApolloError } from "../../domain/models/Errors"; +/** + * @ignore + */ abstract class Secp256k1PrivateKeyCommon { public abstract getPublicKey(): Secp256k1PublicKey; } +/** + * @ignore + */ export class Secp256k1PrivateKey extends Secp256k1KeyCommon implements Secp256k1PrivateKeyCommon diff --git a/src/apollo/utils/Secp256k1PublicKey.ts b/src/apollo/utils/Secp256k1PublicKey.ts index 886e5da72..75cc25ce3 100644 --- a/src/apollo/utils/Secp256k1PublicKey.ts +++ b/src/apollo/utils/Secp256k1PublicKey.ts @@ -8,11 +8,17 @@ import { ECPoint } from "./ec/ECPoint"; import { ApolloError } from "../../domain/models/Errors"; import { Secp256k1KeyCommon } from "./Secp256k1KeyCommon"; +/** + * @ignore + */ abstract class Secp256k1PublicKeyCommon { abstract getEncodedCompressed(): Uint8Array; abstract getCurvePoint(): ECPoint; } +/** + * @ignore + */ export class Secp256k1PublicKey extends Secp256k1KeyCommon implements Secp256k1PublicKeyCommon diff --git a/src/apollo/utils/X25519KeyCommon.ts b/src/apollo/utils/X25519KeyCommon.ts index e62331512..bd051f7ec 100644 --- a/src/apollo/utils/X25519KeyCommon.ts +++ b/src/apollo/utils/X25519KeyCommon.ts @@ -1,5 +1,8 @@ import * as x25519 from "@stablelib/x25519"; +/** + * @ignore + */ export abstract class X25519KeyCommon { public static ec = x25519; public ec = x25519; diff --git a/src/apollo/utils/X25519KeyPair.ts b/src/apollo/utils/X25519KeyPair.ts index 9a81f9cbb..48ed74994 100644 --- a/src/apollo/utils/X25519KeyPair.ts +++ b/src/apollo/utils/X25519KeyPair.ts @@ -5,6 +5,9 @@ import { X25519KeyCommon } from "./X25519KeyCommon"; import { X25519PrivateKey } from "./X25519PrivateKey"; import { X25519PublicKey } from "./X25519PublicKey"; +/** + * @ignore + */ export class X25519KeyPair extends X25519KeyCommon { private privateKey: X25519PrivateKey; private publicKey: X25519PublicKey; diff --git a/src/apollo/utils/X25519PrivateKey.ts b/src/apollo/utils/X25519PrivateKey.ts index 945e9e3a7..fbceadb7f 100644 --- a/src/apollo/utils/X25519PrivateKey.ts +++ b/src/apollo/utils/X25519PrivateKey.ts @@ -1,5 +1,8 @@ import { X25519KeyCommon } from "./X25519KeyCommon"; +/** + * @ignore + */ export class X25519PrivateKey extends X25519KeyCommon { constructor(private nativeValue: Uint8Array) { super(); diff --git a/src/apollo/utils/X25519PublicKey.ts b/src/apollo/utils/X25519PublicKey.ts index 9b21bcfa6..7c71d8b9b 100644 --- a/src/apollo/utils/X25519PublicKey.ts +++ b/src/apollo/utils/X25519PublicKey.ts @@ -1,5 +1,8 @@ import { X25519KeyCommon } from "./X25519KeyCommon"; +/** + * @ignore + */ export class X25519PublicKey extends X25519KeyCommon { constructor(private nativeValue: Uint8Array) { super(); diff --git a/src/apollo/utils/jwt/JWT.ts b/src/apollo/utils/jwt/JWT.ts index e2c01bd63..64febe01b 100644 --- a/src/apollo/utils/jwt/JWT.ts +++ b/src/apollo/utils/jwt/JWT.ts @@ -1,7 +1,7 @@ import * as didJWT from "did-jwt"; import didResolver from "did-resolver"; -import Castor from "../../../domain/buildingBlocks/Castor"; +import { Castor } from "../../../domain/buildingBlocks/Castor"; import { AlsoKnownAs, Controller, @@ -64,17 +64,18 @@ export class JWT { throw new Error("Invalid KeyType"); }) : [], - service: service?.values?.reduce((acc, service) => { - const type = service.type.at(0); + service: + service?.values?.reduce((acc, service) => { + const type = service.type.at(0); - if (type === undefined) return acc; + if (type === undefined) return acc; - return acc.concat({ - id: service.id, - type: type, - serviceEndpoint: service.serviceEndpoint, - }); - }, []) ?? [], + return acc.concat({ + id: service.id, + type: type, + serviceEndpoint: service.serviceEndpoint, + }); + }, []) ?? [], }, }; } diff --git a/src/castor/Castor.ts b/src/castor/Castor.ts index 3be89d531..b51d1f3d8 100644 --- a/src/castor/Castor.ts +++ b/src/castor/Castor.ts @@ -4,8 +4,8 @@ import { base64url } from "multiformats/bases/base64"; import * as base64 from "multiformats/bases/base64"; import * as base58 from "multiformats/bases/base58"; -import Apollo from "../domain/buildingBlocks/Apollo"; -import { default as CastorInterface } from "../domain/buildingBlocks/Castor"; +import { Apollo } from "../domain/buildingBlocks/Apollo"; +import { Castor as CastorInterface } from "../domain/buildingBlocks/Castor"; import { DID, PublicKey, @@ -43,10 +43,26 @@ import { VerificationMethodTypeAuthentication, } from "../peer-did/types"; import { Secp256k1PublicKey } from "../apollo/utils/Secp256k1PublicKey"; + +/** + * Castor is a powerful and flexible library for working with DIDs. Whether you are building a decentralised application + * or a more traditional system requiring secure and private identity management, Castor provides the tools and features + * you need to easily create, manage, and resolve DIDs. + * + * + * @class Castor + * @typedef {Castor} + */ export default class Castor implements CastorInterface { private apollo: Apollo; private resolvers: DIDResolver[]; + /** + * Creates an instance of Castor as soon as a valid cryptographic interface is provided (Apollo). + * + * @constructor + * @param {Apollo} apollo + */ constructor(apollo: Apollo) { this.apollo = apollo; this.resolvers = [ @@ -55,10 +71,50 @@ export default class Castor implements CastorInterface { ]; } + /** + * Parses a string representation of a Decentralized Identifier (DID) into a DID object. + * + * @example + * This function takes a string representation of a DID and returns an instance of `Domain.DID`. It may throw an error if the string is not a valid + * DID. + * + * ```ts + * const parsedPrismDid = castor.parseDID( + * "did:prism:b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k" + * ); + * ``` + * + * @param {string} did + * @returns {DID} + */ parseDID(did: string): DID { return DIDParser.parse(did); } + /** + * Creates a DID for a prism (a device or server that acts as a DID owner and controller) using a + * given master public key and list of services. + * + * @example + * This function creates a new `prism` DID, using a given master public key and a list of services. It may throw an error if the master public key or services are invalid. + * + * ```ts + * const exampleServiceEndpoint = new Domain.Service("didcomm", ["DIDCommMessaging"], { + * uri: "https://example.com/endpoint", + * accept: ["didcomm/v2"], + * routingKeys: ["did:example:somemediator#somekey"], + * }); + * const prismDid = await castor.createPrismDID( + * keyPairFromCurveSecp256K1.publicKey, + * [exampleServiceEndpoint] + * ); + * ``` + * + * @async + * @param {PublicKey} masterPublicKey + * @param {?(Service[] | undefined)} [services] + * @returns {Promise} + */ async createPrismDID( masterPublicKey: PublicKey, services?: Service[] | undefined @@ -107,12 +163,47 @@ export default class Castor implements CastorInterface { return new DID("did", "prism", methodSpecificId.toString()); } + /** + * Creates a DID for a peer (a device or server that acts as a DID subject) using given key agreement + * and authentication key pairs and a list of services. + * + * @example + * This function creates new peer DID, using a given key agreement, authentication key pairs, and a list of services. It may throw an error if the key pairs or services are invalid. + * + * ```ts + * const peerDid = await castor.createPeerDID( + * [keyPairFromCurveEd25519, keyPairFromCurveX25519], + * [exampleService] + * ); + * ``` + * + * @async + * @param {KeyPair[]} keyPairs + * @param {Service[]} services + * @returns {Promise} + */ async createPeerDID(keyPairs: KeyPair[], services: Service[]): Promise { const peerDIDOperation = new PeerDIDCreate(); const peerDID = peerDIDOperation.createPeerDID(keyPairs, services); return peerDID.did; } + /** + * Asynchronously resolves a DID to its corresponding DID Document. This function may throw an error if + * the DID is invalid or the document cannot be retrieved. + * **Note:** only `prism` and `peer` DID methods are currently supported! + * + * @example + * This function asynchronously resolves a DID to its corresponding DID Document. It may throw an error if the DID is invalid or the document is unretrievable. + * + * ```ts + * const didDocument = await castor.resolveDID("did:prism:123456") + * ``` + * + * @async + * @param {string} did + * @returns {Promise} + */ async resolveDID(did: string): Promise { const parsed = DID.fromString(did); const resolver = this.resolvers.find( @@ -124,6 +215,13 @@ export default class Castor implements CastorInterface { return resolver.resolve(did); } + /** + * Extracts the verificationMethods from an array of CoreProperties inside a DID Document + * + * @private + * @param {DIDDocumentCoreProperty[]} coreProperties + * @returns {DIDDocumentVerificationMethod[]} + */ private extractVerificationMethods( coreProperties: DIDDocumentCoreProperty[] ): DIDDocumentVerificationMethod[] { @@ -138,6 +236,36 @@ export default class Castor implements CastorInterface { ); } + /** + * Verifies the authenticity of a signature using the corresponding DID Document, challenge, and signature data. + * This function returns a boolean value indicating whether the signature is valid or not. This function may throw + * an error if the DID Document or signature data are invalid. + * + * @example + * This function verifies the authenticity of a signature using given DID, challenge, and signature data. It returns a boolean value indicating whether the signature is valid or not. It may throw an error if the DID or signature data are invalid. + * + * ```ts + * const message = "data to sign"; + * const messageBytes = new TextEncoder().encode(message); + * const signatureSecp256K1 = apollo.signStringMessage(keyPairSecp256K1.privateKey, message); + * + * const did = castor.parseDID("did:prism:123456"); + * const challenge = messageBytes + * const signature = signatureSecp256K1.value; + * + * const isValid = castor.verifySignature( + * castor.parseDID("did:prism:123456"), + * challenge, // Uint8Array + * signature // Uint8Array + * ); + * ``` + * + * @async + * @param {DID} did + * @param {Uint8Array} challenge + * @param {Uint8Array} signature + * @returns {Promise} + */ async verifySignature( did: DID, challenge: Uint8Array, @@ -230,6 +358,13 @@ export default class Castor implements CastorInterface { return false; } + /** + * Returns ecnumbasis from a valid DID and its related keyPair + * + * @param {DID} did + * @param {KeyPair} keyPair + * @returns {string} + */ getEcnumbasis(did: DID, keyPair: KeyPair): string { return new PeerDIDCreate().computeEncnumbasis(did, keyPair); } diff --git a/src/castor/did/prismDID/PrismDIDPublicKey.ts b/src/castor/did/prismDID/PrismDIDPublicKey.ts index 38f602b96..dde7ac899 100644 --- a/src/castor/did/prismDID/PrismDIDPublicKey.ts +++ b/src/castor/did/prismDID/PrismDIDPublicKey.ts @@ -1,5 +1,5 @@ import { Secp256k1PublicKey } from "../../../apollo/utils/Secp256k1PublicKey"; -import Apollo from "../../../domain/buildingBlocks/Apollo"; +import { Apollo } from "../../../domain/buildingBlocks/Apollo"; import { Curve, PublicKey } from "../../../domain/models"; import { CastorError } from "../../../domain/models/Errors"; diff --git a/src/castor/resolver/LongFormPrismDIDResolver.ts b/src/castor/resolver/LongFormPrismDIDResolver.ts index b4790c428..a762f1406 100644 --- a/src/castor/resolver/LongFormPrismDIDResolver.ts +++ b/src/castor/resolver/LongFormPrismDIDResolver.ts @@ -1,6 +1,6 @@ import { SHA256 } from "@stablelib/sha256"; import { CastorError } from "../../domain/models/Errors"; -import Apollo from "../../domain/buildingBlocks/Apollo"; +import { Apollo } from "../../domain/buildingBlocks/Apollo"; import { LongFormPrismDID } from "../../castor/did/prismDID/LongFormPrismDID"; import { DIDResolver, @@ -113,12 +113,16 @@ export class LongFormPrismDIDResolver implements DIDResolver { if (endpoint === undefined) return acc; - return acc.concat(new DIDDocumentService( - service.id, - [service.type], - new DIDDocumentServiceEndpoint(endpoint) - )); - }, []) ?? []; + return acc.concat( + new DIDDocumentService( + service.id, + [service.type], + new DIDDocumentServiceEndpoint(endpoint) + ) + ); + }, + [] + ) ?? []; const verificationMethods = publicKeys.reduce( (partialResult, publicKey) => { diff --git a/src/domain/buildingBlocks/Apollo.ts b/src/domain/buildingBlocks/Apollo.ts index 84dc6245e..8eacd9269 100644 --- a/src/domain/buildingBlocks/Apollo.ts +++ b/src/domain/buildingBlocks/Apollo.ts @@ -10,7 +10,7 @@ import { } from "../models"; import { MnemonicWordList } from "../models/WordList"; -export default interface Apollo { +export interface Apollo { createRandomMnemonics(): MnemonicWordList; createSeed(mnemonics: MnemonicWordList, passphrase: string): Seed; createRandomSeed(passphrase?: string): SeedWords; diff --git a/src/domain/buildingBlocks/Castor.ts b/src/domain/buildingBlocks/Castor.ts index 2e3d8ff17..8bdfc8bbc 100644 --- a/src/domain/buildingBlocks/Castor.ts +++ b/src/domain/buildingBlocks/Castor.ts @@ -6,7 +6,7 @@ import { Service as DIDDocumentService, } from "../models"; -export default interface Castor { +export interface Castor { parseDID(did: string): DID; createPrismDID( masterPublicKey: PublicKey, diff --git a/src/domain/buildingBlocks/Mercury.ts b/src/domain/buildingBlocks/Mercury.ts index 013099d32..338781860 100644 --- a/src/domain/buildingBlocks/Mercury.ts +++ b/src/domain/buildingBlocks/Mercury.ts @@ -1,6 +1,6 @@ import { Message } from "../models/Message"; -export default interface Mercury { +export interface Mercury { packMessage(message: Message): Promise; unpackMessage(message: string): Promise; sendMessage(message: Message): Promise; diff --git a/src/domain/buildingBlocks/Pluto.ts b/src/domain/buildingBlocks/Pluto.ts index 8c45fae35..a5ea6612a 100644 --- a/src/domain/buildingBlocks/Pluto.ts +++ b/src/domain/buildingBlocks/Pluto.ts @@ -1,16 +1,21 @@ -import {DID, PrivateKey} from "../models"; -import {DIDPair} from "../models/DIDPair"; -import {Mediator} from "../models/Mediator"; -import {Message} from "../models/Message"; -import {PeerDID} from "../models/PeerDID"; -import {PrismDIDInfo} from "../models/PrismDIDInfo"; -import {VerifiableCredential} from "../models/VerifiableCredential"; - - -export default interface Pluto { +import { DID, PrivateKey } from "../models"; +import { DIDPair } from "../models/DIDPair"; +import { Mediator } from "../models/Mediator"; +import { Message } from "../models/Message"; +import { PeerDID } from "../models/PeerDID"; +import { PrismDIDInfo } from "../models/PrismDIDInfo"; +import { VerifiableCredential } from "../models/VerifiableCredential"; + +export interface Pluto { start(): Promise; - storePrismDID(did: DID, keyPathIndex: number, privateKey: PrivateKey, privateKeyMetaId: string | null, alias?: string): Promise; + storePrismDID( + did: DID, + keyPathIndex: number, + privateKey: PrivateKey, + privateKeyMetaId: string | null, + alias?: string + ): Promise; storePeerDID(did: DID, privateKeys: Array): Promise; @@ -21,10 +26,10 @@ export default interface Pluto { storeMessages(messages: Array): Promise; storePrivateKeys( - privateKey: PrivateKey, - did: DID, - keyPathIndex: number, - metaId: string | null + privateKey: PrivateKey, + did: DID, + keyPathIndex: number, + metaId: string | null ): Promise; storeMediator(mediator: DID, host: DID, routing: DID): Promise; @@ -65,7 +70,10 @@ export default interface Pluto { getAllMessagesReceivedFrom(did: DID): Promise>; - getAllMessagesOfType(type: string, relatedWithDID?: DID): Promise>; + getAllMessagesOfType( + type: string, + relatedWithDID?: DID + ): Promise>; getAllMessagesByFromToDID(from: DID, to: DID): Promise>; diff --git a/src/domain/buildingBlocks/Pollux.ts b/src/domain/buildingBlocks/Pollux.ts index 53a2cf877..426188daf 100644 --- a/src/domain/buildingBlocks/Pollux.ts +++ b/src/domain/buildingBlocks/Pollux.ts @@ -1,5 +1,5 @@ import { VerifiableCredential } from "../models/VerifiableCredential"; -export default interface Pollux { +export interface Pollux { parseVerifiableCredential: (jwtString: string) => VerifiableCredential; } diff --git a/src/domain/models/PrivateKey.ts b/src/domain/models/PrivateKey.ts index c7ea93d8f..f638feaba 100644 --- a/src/domain/models/PrivateKey.ts +++ b/src/domain/models/PrivateKey.ts @@ -1,6 +1,21 @@ import { KeyCurve } from "./KeyCurve"; +/** + * Instance of a PrivateKey + * @interface PrivateKey + * @typedef {PrivateKey} + */ export interface PrivateKey { + /** + * Instance of a KeyCurve + * + * @type {KeyCurve} + */ keyCurve: KeyCurve; + /** + * Value as Uint8Array, buffer like + * + * @type {Uint8Array} + */ value: Uint8Array; } diff --git a/src/domain/models/index.ts b/src/domain/models/index.ts index 82d879fde..51de61314 100644 --- a/src/domain/models/index.ts +++ b/src/domain/models/index.ts @@ -1,21 +1,24 @@ +export * from "./Api"; +export * from "./DID"; +export * from "./DIDDocument"; +export * from "./DIDPair"; +export * from "./DIDResolver"; +export * from "./DIDUrl"; +export * from "./Errors"; +export * from "./JWTVerifiableCredential"; export * from "./KeyCurve"; export * from "./KeyPair"; +export * from "./Mediator"; +export * from "./Message"; +export * from "./MessageAttachment"; +export * from "./PeerDID"; +export * from "./PrismDIDInfo"; +export * from "./PrismDIDMethodId"; export * from "./PrivateKey"; export * from "./PublicKey"; export * from "./Seed"; export * from "./SeedWords"; export * from "./Signature"; -export * from "./DID"; -export * from "./DIDDocument"; -export * from "./DIDUrl"; -export * from "./PrismDIDMethodId"; -export * from "./DIDResolver"; -export * from "./PeerDID"; -export * from "./Message"; -export * from "./MessageAttachment"; -export * from "./Mediator"; -export * from "./Api"; export * from "./WordList"; export * from "./VerifiableCredential"; -export * from "./JWTVerifiableCredential"; export type JsonString = string; diff --git a/src/index.ts b/src/index.ts index 3f3051347..a8df5a382 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,7 +16,18 @@ export * from "./prism-agent/mediator/BasicMediatorHandler"; export * from "./prism-agent/mediator/PlutoMediatorStore"; export * from "./mercury/didcomm/Wrapper"; export * from "./prism-agent/helpers/ApiImpl"; -export { ListenerKey } from "./prism-agent/types"; +export type { + ListenerKey, + MediatorHandler, + ConnectionsManager as ConnectionsManagerInterface, + MediatorStore, + AgentCredentials, + AgentInvitations, + AgentDIDHigherFunctions, + AgentMessageEvents, +} from "./prism-agent/types"; +export type { DIDCommProtocol } from "./mercury/DIDCommProtocol"; +export * from "./prism-agent/protocols/types"; export * from "./apollo/utils/Secp256k1PrivateKey"; export * from "./apollo/utils/Secp256k1PublicKey"; export * from "./apollo/utils/Secp256k1KeyPair"; diff --git a/src/mercury/Mercury.ts b/src/mercury/Mercury.ts index 66246564f..992550212 100644 --- a/src/mercury/Mercury.ts +++ b/src/mercury/Mercury.ts @@ -1,19 +1,44 @@ import * as Domain from "../domain"; import { MercuryError } from "../domain/models/Errors"; -import { default as MercuryInterface } from "../domain/buildingBlocks/Mercury"; +import { Mercury as MercuryInterface } from "../domain/buildingBlocks/Mercury"; import { DIDCommProtocol } from "./DIDCommProtocol"; import { Api, DID } from "../domain"; import { MediaType } from "./helpers/MediaType"; -import Castor from "../domain/buildingBlocks/Castor"; +import { Castor } from "../domain/buildingBlocks/Castor"; import { ForwardMessage } from "./forward/ForwardMessage"; +/** + * Mercury is a powerful and flexible library for working with decentralized identifiers and secure communications + * protocols. Whether you are a developer looking to build a secure and private messaging app or a more complex + * decentralized system requiring trusted peer-to-peer connections, Mercury provides the tools and features you need to + * establish, manage, and secure your communications easily. + * + * @export + * @class Mercury + * @typedef {Mercury} + */ export default class Mercury implements MercuryInterface { + /** + * Creates an instance of Mercury. + * + * @constructor + * @param {Castor} castor + * @param {DIDCommProtocol} protocol + * @param {Api} api + */ constructor( public castor: Castor, public protocol: DIDCommProtocol, public api: Api ) {} + /** + * Asynchronously packs a given message object into a string representation. This function may throw an error if the + * message object is invalid. + * + * @param {Domain.Message} message + * @returns {Promise} + */ packMessage(message: Domain.Message): Promise { const toDid = message.to; const fromDid = message.from; @@ -23,10 +48,25 @@ export default class Mercury implements MercuryInterface { return this.protocol.packEncrypted(message, toDid, fromDid); } + /** + * Asynchronously unpacks a given string representation of a message into a message object. This + * function may throw an error if the string is not a valid message representation. + * + * @param {string} message + * @returns {Promise} + */ unpackMessage(message: string): Promise { return this.protocol.unpack(message); } + /** + * Asynchronously sends a given message and returns the response data. + * + * @async + * @template T + * @param {Domain.Message} message + * @returns {Promise} + */ async sendMessage(message: Domain.Message): Promise { const toDid = message.to; @@ -80,6 +120,13 @@ export default class Mercury implements MercuryInterface { return response.body; } + /** + * Asynchronously sends a given message and returns the response message object. + * + * @async + * @param {Domain.Message} message + * @returns {Promise} + */ async sendMessageParseMessage( message: Domain.Message ): Promise { diff --git a/src/mercury/didcomm/Wrapper.ts b/src/mercury/didcomm/Wrapper.ts index 601370600..13a57a7ec 100644 --- a/src/mercury/didcomm/Wrapper.ts +++ b/src/mercury/didcomm/Wrapper.ts @@ -18,6 +18,10 @@ import { MercuryError } from "../../domain/models/Errors"; import type * as DIDCommLibTypes from "../../../didcomm-rust/didcomm-browser/didcomm_js"; +/** + * @ignore + * @returns + */ export async function getDidcommLibInstance(): Promise { const DIDCommLib = await import( "../../../didcomm-rust/didcomm-browser/didcomm_js.js" diff --git a/src/peer-did/PeerDID.ts b/src/peer-did/PeerDID.ts index 19917c20a..2e0675384 100644 --- a/src/peer-did/PeerDID.ts +++ b/src/peer-did/PeerDID.ts @@ -8,6 +8,9 @@ export interface PeerDIDEncoded { a: string[]; } +/** + * Provides functionality to transfrom peerDIDServices from our interfaces into DIDComm module ones + */ export class PeerDIDService { readonly type: string; readonly serviceEndpoint: string; diff --git a/src/peer-did/PeerDIDCreate.ts b/src/peer-did/PeerDIDCreate.ts index e11c8edfc..45427281e 100644 --- a/src/peer-did/PeerDIDCreate.ts +++ b/src/peer-did/PeerDIDCreate.ts @@ -23,7 +23,21 @@ import { import { base58btc } from "multiformats/bases/base58"; +/** + * PeerDID Creation wrapper class + * + * @export + * @class PeerDIDCreate + * @typedef {PeerDIDCreate} + */ export class PeerDIDCreate { + /** + * Creates an instance of a PeerDID by providing a valid set of KeyPairs and DIDDocumentServices[] + * + * @param {KeyPair[]} keyPairs + * @param {DIDDocumentService[]} services + * @returns {PeerDID} + */ createPeerDID(keyPairs: KeyPair[], services: DIDDocumentService[]): PeerDID { const signingKeys = keyPairs .filter((keyPair) => keyPair.keyCurve.curve === Curve.ED25519) @@ -49,6 +63,13 @@ export class PeerDIDCreate { ); } + /** + * Computes Encnumbasis from a valid did and its keyPair + * + * @param {DID} did + * @param {KeyPair} keyPair + * @returns {string} + */ computeEncnumbasis(did: DID, keyPair: KeyPair): string { let material: | VerificationMaterialAgreement diff --git a/src/pluto/Pluto.ts b/src/pluto/Pluto.ts index 6ed62318c..0e3d9a3a7 100644 --- a/src/pluto/Pluto.ts +++ b/src/pluto/Pluto.ts @@ -9,7 +9,7 @@ import { } from "../domain"; import { PrismDIDInfo } from "../domain/models/PrismDIDInfo"; import { VerifiableCredential } from "../domain/models/VerifiableCredential"; -import { default as PlutoInterface } from "../domain/buildingBlocks/Pluto"; +import { Pluto as PlutoInterface } from "../domain/buildingBlocks/Pluto"; import { DataSource, Like, Repository } from "typeorm"; import * as entities from "./entities"; import Did from "./entities/DID"; @@ -52,6 +52,15 @@ export type PlutoConnectionProps = | Omit | Omit; +/** + * Our example implementation of storage interface PlutoInterface used + * as storage layer to store anything required by this edge agent, + * keyPairs, credentials, connections, and data it needs + * + * @export + * @class Pluto + * @typedef {Pluto} + */ export default class Pluto implements PlutoInterface { dataSource: DataSource; wasmUrl: string = @@ -59,6 +68,12 @@ export default class Pluto implements PlutoInterface { ? `https://sql.js.org` : `node_modules/sql.js`; + /** + * Creates an instance of Pluto. + * + * @constructor + * @param {PlutoConnectionProps} connection + */ constructor(connection: PlutoConnectionProps) { const presetSqlJSConfig = connection.type === "sqljs" @@ -100,6 +115,12 @@ export default class Pluto implements PlutoInterface { }; } + /** + * Asyncronously Starts an instance of the Database connection + * + * @async + * @returns {*} + */ async start() { if (this.dataSource.isInitialized) { throw new Error("Database is already initialised"); @@ -111,6 +132,17 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously Store a PrismDID by providing the DID, the privateKey, its keyPath index and an optional alias + * + * @async + * @param {DID} did + * @param {number} keyPathIndex + * @param {PrivateKey} privateKey + * @param {(string | null)} privateKeyMetaId + * @param {?string} [alias] + * @returns {*} + */ async storePrismDID( did: DID, keyPathIndex: number, @@ -133,6 +165,14 @@ export default class Pluto implements PlutoInterface { ); } + /** + * Asyncronously Store a peerDID just by providing the DID and an array of its privateKeys + * + * @async + * @param {DID} did + * @param {PrivateKey[]} privateKeys + * @returns {*} + */ async storePeerDID(did: DID, privateKeys: PrivateKey[]) { const didEntity = new entities.DID(); didEntity.did = did.toString(); @@ -153,15 +193,16 @@ export default class Pluto implements PlutoInterface { ); } + /** + * Asyncronously Store a DIDPair, a didcomm connection basically between 2 dids + * + * @async + * @param {DID} host + * @param {DID} receiver + * @param {string} name + * @returns {*} + */ async storeDIDPair(host: DID, receiver: DID, name: string) { - // const hostInfo = await this.getDIDInfoByDID(host); - // const receiverInfo = await this.getDIDInfoByDID(receiver); - // if (!hostInfo) { - // throw new Error("Your host DID is not stored, therefore can't store didPair"); - // } - // if (!receiverInfo) { - // throw new Error("Your receiver DID is not stored, therefore can't store didPair"); - // } const didPairEntity = new entities.DIDPair(); didPairEntity.id = `${host.toString()}${receiver.toString()}`; didPairEntity.name = name; @@ -171,6 +212,13 @@ export default class Pluto implements PlutoInterface { await this.dataSource.manager.save(didPairEntity); } + /** + * Asyncronously Store a didcomm Message + * + * @async + * @param {Message} message + * @returns {*} + */ async storeMessage(message: Message) { const messageEntity = new entities.Message(); messageEntity.createdTime = message.createdTime; @@ -183,10 +231,27 @@ export default class Pluto implements PlutoInterface { await this.dataSource.manager.save(messageEntity); } + /** + * Asyncronously Store an array of messages + * + * @async + * @param {Message[]} messages + * @returns {*} + */ async storeMessages(messages: Message[]) { await Promise.all(messages.map(this.storeMessage.bind(this))); } + /** + * Asyncronously store a did's privateKeys by prividing the privateKey and its keyPath index and the actual did + * + * @async + * @param {PrivateKey} privateKey + * @param {DID} did + * @param {number} keyPathIndex + * @param {(string | null)} metaId + * @returns {*} + */ async storePrivateKeys( privateKey: PrivateKey, did: DID, @@ -202,20 +267,16 @@ export default class Pluto implements PlutoInterface { await this.dataSource.manager.save(privateKeysEntity); } + /** + * Asyncronously Store the mediator + * + * @async + * @param {DID} mediator + * @param {DID} host + * @param {DID} routing + * @returns {*} + */ async storeMediator(mediator: DID, host: DID, routing: DID) { - // const mediatorInfo = await this.getDIDInfoByDID(mediator); - // const hostInfo = await this.getDIDInfoByDID(host); - // const routingInfo = await this.getDIDInfoByDID(routing); - // - // if (!hostInfo) { - // throw new Error("Your host DID is not stored, therefore can't store didPair"); - // } - // if (!mediatorInfo) { - // throw new Error("Your mediator DID is not stored, therefore can't store didPair"); - // } - // if (!routingInfo) { - // throw new Error("Your routing DID is not stored, therefore can't store didPair"); - // } const mediatorEntity = new entities.Mediator(); mediatorEntity.mediatorDidId = mediator.toString(); mediatorEntity.hostDidId = host.toString(); @@ -223,6 +284,12 @@ export default class Pluto implements PlutoInterface { await this.dataSource.manager.save(mediatorEntity); } + /** + * Asyncronously fetch all prismDIDS + * + * @async + * @returns {unknown} + */ async getAllPrismDIDs() { const didRepository = this.dataSource.manager.getRepository("did"); try { @@ -242,6 +309,13 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously get DID information by providing a DID instance + * + * @async + * @param {DID} did + * @returns {unknown} + */ async getDIDInfoByDID(did: DID) { const didRepository = this.dataSource.manager.getRepository("did"); try { @@ -276,6 +350,13 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously get the DID information by providing an Alias + * + * @async + * @param {string} alias + * @returns {unknown} + */ async getDIDInfoByAlias(alias: string) { const didRepository = this.dataSource.manager.getRepository("did"); try { @@ -306,6 +387,13 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously Get a PrismDID key path index by providing a did instance + * + * @async + * @param {DID} did + * @returns {unknown} + */ async getPrismDIDKeyPathIndex(did: DID) { const repository = this.dataSource.manager.getRepository("private_key"); try { @@ -323,6 +411,12 @@ export default class Pluto implements PlutoInterface { } } + /** + * Get the last Prism keyPath index + * + * @async + * @returns {unknown} + */ async getPrismLastKeyPathIndex() { const repository = this.dataSource.manager.getRepository("private_key"); try { @@ -347,6 +441,12 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously fetch all peerDIDs + * + * @async + * @returns {unknown} + */ async getAllPeerDIDs() { const didRepository: Repository = this.dataSource.manager.getRepository("did"); @@ -387,7 +487,14 @@ export default class Pluto implements PlutoInterface { } } - async getDIDPrivateKeysByDID(did: DID) { + /** + * Asyncronously get a dids privateKey by providing its instance + * + * @async + * @param {DID} did + * @returns {unknown} + */ + async getDIDPrivateKeysByDID(did: DID): Promise { const repository = this.dataSource.manager.getRepository("private_key"); try { const didString = did.toString(); @@ -403,6 +510,13 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously get a dids private key by providing its ID + * + * @async + * @param {string} id + * @returns {unknown} + */ async getDIDPrivateKeyByID(id: string) { const repository = this.dataSource.manager.getRepository("private_key"); @@ -424,6 +538,12 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously get did pairs, also known as didcomm connections + * + * @async + * @returns {unknown} + */ async getAllDidPairs() { const repository = this.dataSource.manager.getRepository("did_pair"); try { @@ -440,6 +560,13 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously get a didPair by providing one of the connected dids + * + * @async + * @param {DID} did + * @returns {unknown} + */ async getPairByDID(did: DID) { const repository = this.dataSource.manager.getRepository("did_pair"); try { @@ -462,6 +589,13 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously fetch a did pair by its name + * + * @async + * @param {string} name + * @returns {unknown} + */ async getPairByName(name: string) { const repository = this.dataSource.manager.getRepository("did_pair"); try { @@ -484,6 +618,12 @@ export default class Pluto implements PlutoInterface { } } + /** + * Asyncronously fetch all the messages + * + * @async + * @returns {unknown} + */ async getAllMessages() { const repository: Repository = this.dataSource.manager.getRepository("message"); @@ -492,6 +632,13 @@ export default class Pluto implements PlutoInterface { return data.map(Pluto.transformMessageDBToInterface); } + /** + * Asyncronously fetch all the messages from this DID + * + * @async + * @param {DID} did + * @returns {unknown} + */ async getAllMessagesByDID(did: DID) { const repository: Repository = this.dataSource.manager.getRepository("message"); @@ -504,6 +651,12 @@ export default class Pluto implements PlutoInterface { return data.map(Pluto.transformMessageDBToInterface); } + /** + * Asyncronously fetch all sent messages + * + * @async + * @returns {unknown} + */ async getAllMessagesSent() { const repository: Repository = this.dataSource.manager.getRepository("message"); @@ -515,6 +668,12 @@ export default class Pluto implements PlutoInterface { return data.map(Pluto.transformMessageDBToInterface); } + /** + * Asyncronously fetch all received messages + * + * @async + * @returns {unknown} + */ async getAllMessagesReceived() { const repository: Repository = this.dataSource.manager.getRepository("message"); @@ -526,6 +685,13 @@ export default class Pluto implements PlutoInterface { return data.map(Pluto.transformMessageDBToInterface); } + /** + * Asyncronously fetch all the messages that have been sent to a specific DID + * + * @async + * @param {DID} did + * @returns {unknown} + */ async getAllMessagesSentTo(did: DID) { const repository: Repository = this.dataSource.manager.getRepository("message"); @@ -537,6 +703,13 @@ export default class Pluto implements PlutoInterface { return data.map(Pluto.transformMessageDBToInterface); } + /** + * GEt all the Messages received on a specific DID + * + * @async + * @param {DID} did + * @returns {unknown} + */ async getAllMessagesReceivedFrom(did: DID) { const repository: Repository = this.dataSource.manager.getRepository("message"); @@ -548,6 +721,14 @@ export default class Pluto implements PlutoInterface { return data.map(Pluto.transformMessageDBToInterface); } + /** + * Asyncronously fetch all the messages by specifying the message type, and optionally if they are related to a DID + * + * @async + * @param {string} type + * @param {?DID} [relatedWithDID] + * @returns {unknown} + */ async getAllMessagesOfType(type: string, relatedWithDID?: DID) { const repository: Repository = this.dataSource.manager.getRepository("message"); @@ -563,6 +744,14 @@ export default class Pluto implements PlutoInterface { return data.map(Pluto.transformMessageDBToInterface); } + /** + * Asyncronously fetch all the messages by from or to + * + * @async + * @param {DID} from + * @param {DID} to + * @returns {unknown} + */ async getAllMessagesByFromToDID(from: DID, to: DID) { const repository: Repository = this.dataSource.manager.getRepository("message"); @@ -575,6 +764,13 @@ export default class Pluto implements PlutoInterface { return data.map(Pluto.transformMessageDBToInterface); } + /** + * Asyncronously get a message by ID + * + * @async + * @param {string} id + * @returns {unknown} + */ async getMessage(id: string) { const repository: Repository = this.dataSource.manager.getRepository("message"); @@ -589,6 +785,12 @@ export default class Pluto implements PlutoInterface { return Pluto.transformMessageDBToInterface(data); } + /** + * Asyncronously fetch all the mediators + * + * @async + * @returns {unknown} + */ async getAllMediators() { const repository: Repository = this.dataSource.manager.getRepository("mediator"); @@ -603,6 +805,12 @@ export default class Pluto implements PlutoInterface { })) as Mediator[]; } + /** + * Asyncronously get all the credentials + * + * @async + * @returns {unknown} + */ async getAllCredentials() { const repository: Repository = this.dataSource.manager.getRepository("verifiable_credential"); @@ -618,6 +826,13 @@ export default class Pluto implements PlutoInterface { }) as VerifiableCredential[]; } + /** + * Asyncronously store a Verifiable Credential + * + * @async + * @param {VerifiableCredential} credential + * @returns {*} + */ async storeCredential(credential: VerifiableCredential) { const verifiableCredentialEntity = new entities.VerifiableCredential(); verifiableCredentialEntity.credentialType = credential.credentialType; diff --git a/src/pollux/Pollux.ts b/src/pollux/Pollux.ts index a698af33d..4a77a124f 100644 --- a/src/pollux/Pollux.ts +++ b/src/pollux/Pollux.ts @@ -1,18 +1,37 @@ -import Castor from "../domain/buildingBlocks/Castor"; -import { default as PolluxInterface } from "../domain/buildingBlocks/Pollux"; +import { Castor } from "../domain/buildingBlocks/Castor"; +import { Pollux as PolluxInterface } from "../domain/buildingBlocks/Pollux"; import { InvalidJWTString } from "../domain/models/errors/Pollux"; import { VerifiableCredential } from "../domain/models/VerifiableCredential"; import { base64url } from "multiformats/bases/base64"; import { JWTCredential } from "./models/JWTCredential"; +/** + * Implementation of PolluxInterface and responsible of handling credential related tasks + * + * @export + * @class Pollux + * @typedef {Pollux} + */ export default class Pollux implements PolluxInterface { private castor: Castor; + /** + * Creates an instance of Pollux. + * + * @constructor + * @param {Castor} castor + */ constructor(castor: Castor) { this.castor = castor; } + /** + * Parses a verifiable credential in Json format as a string into an instance of a VerifiableCredential + * + * @param {string} jwtString + * @returns {VerifiableCredential} + */ parseVerifiableCredential(jwtString: string): VerifiableCredential { const parts = jwtString.split("."); const credentialString = parts.at(1); diff --git a/src/prism-agent/Agent.Credentials.ts b/src/prism-agent/Agent.Credentials.ts index 7dabb26e9..dd363350d 100644 --- a/src/prism-agent/Agent.Credentials.ts +++ b/src/prism-agent/Agent.Credentials.ts @@ -6,9 +6,9 @@ import { Curve, Seed, } from "../domain"; -import Apollo from "../domain/buildingBlocks/Apollo"; -import Castor from "../domain/buildingBlocks/Castor"; -import Pluto from "../domain/buildingBlocks/Pluto"; +import { Apollo } from "../domain/buildingBlocks/Apollo"; +import { Castor } from "../domain/buildingBlocks/Castor"; +import { Pluto } from "../domain/buildingBlocks/Pluto"; import { VerifiableCredential } from "../domain/models/VerifiableCredential"; import { OfferCredential } from "./protocols/issueCredential/OfferCredential"; import { @@ -18,14 +18,33 @@ import { import { AgentCredentials as AgentCredentialsClass } from "./types"; import { base64, base64url } from "multiformats/bases/base64"; import { IssueCredential } from "./protocols/issueCredential/IssueCredential"; -import Pollux from "../domain/buildingBlocks/Pollux"; +import { Pollux } from "../domain/buildingBlocks/Pollux"; import { createPresentationBody, Presentation, } from "./protocols/proofPresentation/Presentation"; import { RequestPresentation } from "./protocols/proofPresentation/RequestPresentation"; import { AgentError } from "../domain/models/Errors"; + +/** + * An extension for the Edge agents that groups all the tasks and flows related to credentials + * those incluse processing, parsing and signing credential requests that will be then send to an Agent or received from an agent + * + * @interface + * @class AgentCredentials + * @typedef {AgentCredentials} + */ export class AgentCredentials implements AgentCredentialsClass { + /** + * Creates an instance of AgentCredentials. + * + * @constructor + * @param {Apollo} apollo + * @param {Castor} castor + * @param {Pluto} pluto + * @param {Pollux} pollux + * @param {Seed} seed + */ constructor( protected apollo: Apollo, protected castor: Castor, @@ -34,10 +53,23 @@ export class AgentCredentials implements AgentCredentialsClass { protected seed: Seed ) {} + /** + * Asyncronously get all the stored verifiableCredentials + * + * @async + * @returns {Promise} + */ async verifiableCredentials(): Promise { return await this.pluto.getAllCredentials(); } + /** + * Extract the verifiableCredential object from the Issue credential message asyncronously + * + * @async + * @param {IssueCredential} message + * @returns {Promise} + */ async processIssuedCredentialMessage( message: IssueCredential ): Promise { @@ -72,6 +104,13 @@ export class AgentCredentials implements AgentCredentialsClass { } ); } + /** + * Asyncronously prepare a request credential message from a valid offerCredential for now supporting w3c verifiable credentials offers. + * + * @async + * @param {OfferCredential} offer + * @returns {Promise} + */ async prepareRequestCredentialWithIssuer( offer: OfferCredential ): Promise { @@ -138,6 +177,16 @@ export class AgentCredentials implements AgentCredentialsClass { return requestCredential; } + /** + * Asyncronously create a verifiablePresentation from a valid stored verifiableCredential + * This is used when the verified requests a specific verifiable credential, this will create the actual + * instance of the presentation which we can share with the verifier. + * + * @async + * @param {RequestPresentation} request + * @param {VerifiableCredential} credential + * @returns {Promise} + */ async createPresentationForRequestProof( request: RequestPresentation, credential: VerifiableCredential diff --git a/src/prism-agent/Agent.DIDHigherFunctions.ts b/src/prism-agent/Agent.DIDHigherFunctions.ts index c858dec59..929e7db3b 100644 --- a/src/prism-agent/Agent.DIDHigherFunctions.ts +++ b/src/prism-agent/Agent.DIDHigherFunctions.ts @@ -6,9 +6,9 @@ import { ServiceEndpoint, Signature, } from "../domain"; -import Apollo from "../domain/buildingBlocks/Apollo"; -import Castor from "../domain/buildingBlocks/Castor"; -import Pluto from "../domain/buildingBlocks/Pluto"; +import { Apollo } from "../domain/buildingBlocks/Apollo"; +import { Castor } from "../domain/buildingBlocks/Castor"; +import { Pluto } from "../domain/buildingBlocks/Pluto"; import { AgentError } from "../domain/models/Errors"; import { AgentDIDHigherFunctions as AgentDIDHigherFunctionsClass, @@ -16,7 +16,25 @@ import { MediatorHandler, } from "./types"; +/** + * An extension for the Edge agent that groups some DID related operations mainly used to expose the create did functionality + * + * @export + * @class AgentDIDHigherFunctions + * @typedef {AgentDIDHigherFunctions} + */ export class AgentDIDHigherFunctions implements AgentDIDHigherFunctionsClass { + /** + * Creates an instance of AgentDIDHigherFunctions. + * + * @constructor + * @param {Apollo} apollo + * @param {Castor} castor + * @param {Pluto} pluto + * @param {ConnectionsManager} manager + * @param {MediatorHandler} mediationHandler + * @param {Seed} seed + */ constructor( protected apollo: Apollo, protected castor: Castor, @@ -26,6 +44,14 @@ export class AgentDIDHigherFunctions implements AgentDIDHigherFunctionsClass { protected seed: Seed ) {} + /** + * Asyncronously sign with a DID + * + * @async + * @param {DID} did + * @param {Uint8Array} message + * @returns {Promise} + */ async signWith(did: DID, message: Uint8Array): Promise { const privateKeys = await this.pluto.getDIDPrivateKeysByDID(did); const privateKey = privateKeys.at(0); @@ -37,6 +63,14 @@ export class AgentDIDHigherFunctions implements AgentDIDHigherFunctionsClass { return this.apollo.signByteArrayMessage(privateKey, message); } + /** + * Asyncronously create and store a new peer did + * + * @async + * @param {Service[]} services + * @param {boolean} [updateMediator=false] + * @returns {Promise} + */ async createNewPeerDID( services: Service[], updateMediator = false @@ -90,6 +124,15 @@ export class AgentDIDHigherFunctions implements AgentDIDHigherFunctionsClass { return did; } + /** + * Asyncronously create and store a PrismDID + * + * @async + * @param {string} alias + * @param {Service[]} services + * @param {?number} [keyPathIndex] + * @returns {Promise} + */ async createNewPrismDID( alias: string, services: Service[], diff --git a/src/prism-agent/Agent.Invitations.ts b/src/prism-agent/Agent.Invitations.ts index 9f57c2871..d09921430 100644 --- a/src/prism-agent/Agent.Invitations.ts +++ b/src/prism-agent/Agent.Invitations.ts @@ -17,10 +17,27 @@ import { import { Api } from "../domain/models/Api"; import { ConnectionsManager } from "./connectionsManager/ConnectionsManager"; import { DIDCommConnectionRunner } from "./protocols/connection/DIDCommConnectionRunner"; -import Pluto from "../domain/buildingBlocks/Pluto"; +import { Pluto } from "../domain/buildingBlocks/Pluto"; import { DIDCommInvitationRunner } from "./protocols/invitation/v2/DIDCommInvitationRunner"; +/** + * An extension for the Edge agent that groups the functionality to parse, manage and + * respond to prism agent onboarding and didcomm v2 invitations + * + * @export + * @class AgentInvitations + * @typedef {AgentInvitations} + */ export class AgentInvitations implements AgentInvitationsClass { + /** + * Creates an instance of AgentInvitations. + * + * @constructor + * @param {Pluto} pluto + * @param {Api} api + * @param {AgentDIDHigherFunctions} agentDIDHigherFunctions + * @param {ConnectionsManager} connection + */ constructor( private pluto: Pluto, private api: Api, @@ -28,6 +45,13 @@ export class AgentInvitations implements AgentInvitationsClass { private connection: ConnectionsManager ) {} + /** + * Asyncronously parse an invitation from a valid json string + * + * @async + * @param {string} str + * @returns {Promise} + */ async parseInvitation(str: string): Promise { const json = JSON.parse(str); const typeString = findProtocolTypeByValue(json.type); @@ -42,6 +66,14 @@ export class AgentInvitations implements AgentInvitationsClass { throw new AgentError.UnknownInvitationTypeError(); } + /** + * Asyncronously accept a didcomm v2 invitation, will create a pair between the Agent + * its connecting with and the current owner's did + * + * @async + * @param {OutOfBandInvitation} invitation + * @returns {*} + */ async acceptDIDCommInvitation(invitation: OutOfBandInvitation) { if (!this.connection.mediationHandler.mediator) { throw new AgentError.NoMediatorAvailableError(); @@ -62,6 +94,13 @@ export class AgentInvitations implements AgentInvitationsClass { await this.connection.addConnection(pair); } + /** + * Asyncronously accept a prism onboarding invitation, used to onboard the current did in a prism agent. + * + * @async + * @param {PrismOnboardingInvitation} invitation + * @returns {Promise} + */ async acceptInvitation(invitation: PrismOnboardingInvitation): Promise { if (!invitation.from) { throw new AgentError.UnknownInvitationTypeError(); @@ -84,6 +123,13 @@ export class AgentInvitations implements AgentInvitationsClass { } } + /** + * Asyncronously parse a prismOnboarding invitation from a string + * + * @async + * @param {string} str + * @returns {Promise} + */ async parsePrismInvitation(str: string): Promise { try { const prismOnboarding = @@ -112,6 +158,13 @@ export class AgentInvitations implements AgentInvitationsClass { } } + /** + * Asyncronously parse an out of band invitation from a URI as the oob come in format of valid URL + * + * @async + * @param {URL} str + * @returns {Promise} + */ async parseOOBInvitation(str: URL): Promise { return new DIDCommInvitationRunner(str).run(); } diff --git a/src/prism-agent/Agent.MessageEvents.ts b/src/prism-agent/Agent.MessageEvents.ts index b8ce0b05f..ba36fbb5b 100644 --- a/src/prism-agent/Agent.MessageEvents.ts +++ b/src/prism-agent/Agent.MessageEvents.ts @@ -4,9 +4,27 @@ import { ListenerKey, } from "./types"; +/** + * An extension for the Edge agent that gives it capability of + * creating listeners for specific events and also emitting or notifying any listener available with the + * new event. + * + * @export + * @class AgentMessageEvents + * @typedef {AgentMessageEvents} + */ export class AgentMessageEvents implements AgentMessageEventsClass { private events: Map> = new Map(); + /** + * Just adds a new event listener by passing the event name and the callback function we want + * to be notified at + * + * @public + * @param {ListenerKey} eventName + * @param {EventCallback} callback + * @returns {number} + */ public addListener(eventName: ListenerKey, callback: EventCallback): number { if (!this.events.has(eventName)) { this.events.set(eventName, new Set()); @@ -17,12 +35,27 @@ export class AgentMessageEvents implements AgentMessageEventsClass { return callbacks.size - 1; } + /** + * Remove an existing event listener, used when the Agent is + * stopping to make sure no memory leaks are produced + * + * @public + * @param {ListenerKey} eventName + * @param {EventCallback} callback + */ public removeListener(eventName: ListenerKey, callback: EventCallback): void { const callbacks = this.events.get(eventName); if (!callbacks) return; callbacks.delete(callback); } + /** + * Emit some data to all the listeners of a specific event + * + * @public + * @param {ListenerKey} eventName + * @param {*} data + */ public emit(eventName: ListenerKey, data: any): void { const callbacks = this.events.get(eventName); if (!callbacks) return; diff --git a/src/prism-agent/Agent.ts b/src/prism-agent/Agent.ts index d324436c1..b2de5b806 100644 --- a/src/prism-agent/Agent.ts +++ b/src/prism-agent/Agent.ts @@ -1,4 +1,4 @@ -import Apollo from "../domain/buildingBlocks/Apollo"; +import { Apollo } from "../domain/buildingBlocks/Apollo"; import { DID, Message, @@ -6,9 +6,9 @@ import { Service as DIDDocumentService, Signature, } from "../domain"; -import Castor from "../domain/buildingBlocks/Castor"; -import Pluto from "../domain/buildingBlocks/Pluto"; -import Mercury from "../domain/buildingBlocks/Mercury"; +import { Castor } from "../domain/buildingBlocks/Castor"; +import { Pluto } from "../domain/buildingBlocks/Pluto"; +import { Mercury } from "../domain/buildingBlocks/Mercury"; import { Api } from "../domain/models/Api"; import { ApiImpl } from "./helpers/ApiImpl"; @@ -43,13 +43,27 @@ enum AgentState { STOPPING = "stopping", } +/** + * Edge agent implementation + * + * @export + * @class Agent + * @typedef {Agent} + */ export default class Agent implements AgentCredentialsClass, AgentDIDHigherFunctionsClass, AgentInvitationsClass { + /** + * Agent state + * + * @public + * @type {AgentState} + */ public state: AgentState = AgentState.STOPPED; + private agentCredentials: AgentCredentials; private agentDIDHigherFunctions: AgentDIDHigherFunctions; private agentInvitations: AgentInvitations; @@ -62,6 +76,19 @@ export default class Agent private seed: Seed; private api: Api; + /** + * Creates an instance of Agent. + * + * @constructor + * @param {Apollo} apollo + * @param {Castor} castor + * @param {Pluto} pluto + * @param {Mercury} mercury + * @param {MediatorHandler} mediationHandler + * @param {ConnectionsManager} connectionManager + * @param {Seed} [seed=apollo.createRandomSeed().seed] + * @param {Api} [api=new ApiImpl()] + */ constructor( apollo: Apollo, castor: Castor, @@ -108,10 +135,30 @@ export default class Agent ); } + /** + * Get current mediator DID if available or null + * + * @public + * @readonly + * @type {DID} + */ public get currentMediatorDID() { return this.mediationHandler.mediator?.mediatorDID; } + /** + * Mainly for testing porposed but instanciating the Agne tfrom a ConnectionManager directly + * + * @static + * @param {Apollo} apollo + * @param {Castor} castor + * @param {Pluto} pluto + * @param {Mercury} mercury + * @param {ConnectionsManager} connectionManager + * @param {?Seed} [seed] + * @param {?Api} [api] + * @returns {Agent} + */ static instanceFromConnectionManager( apollo: Apollo, castor: Castor, @@ -133,6 +180,12 @@ export default class Agent ); } + /** + * Asyncronously start the agent + * + * @async + * @returns {Promise} + */ async start(): Promise { if (this.state !== AgentState.STOPPED) { return this.state; @@ -156,6 +209,12 @@ export default class Agent return this.state; } + /** + * Asyncronously stop the agent and any side task that is running + * + * @async + * @returns {Promise} + */ async stop(): Promise { if (this.state !== AgentState.RUNNING) { return; @@ -166,6 +225,15 @@ export default class Agent this.state = AgentState.STOPPED; } + /** + * Asyncronously create a new PrismDID + * + * @async + * @param {string} alias + * @param {DIDDocumentService[]} [services=[]] + * @param {?number} [keyPathIndex] + * @returns {Promise} + */ async createNewPrismDID( alias: string, services: DIDDocumentService[] = [], @@ -178,6 +246,14 @@ export default class Agent ); } + /** + * Asyncronously Create a new PeerDID + * + * @async + * @param {DIDDocumentService[]} [services=[]] + * @param {boolean} [updateMediator=true] + * @returns {Promise} + */ async createNewPeerDID( services: DIDDocumentService[] = [], updateMediator = true @@ -188,68 +264,168 @@ export default class Agent ); } + /** + * Asyncronously parse an invitation from a valid json string + * + * @async + * @param {string} str + * @returns {Promise} + */ async parseInvitation(str: string): Promise { return this.agentInvitations.parseInvitation(str); } + /** + * Asyncronously accept a prism onboarding invitation, used to onboard the current did in a prism agent. + * + * @async + * @param {PrismOnboardingInvitation} invitation + * @returns {Promise} + */ async acceptInvitation(invitation: PrismOnboardingInvitation): Promise { return this.agentInvitations.acceptInvitation(invitation); } + /** + * Asyncronously sign a message with a DID + * + * @async + * @param {DID} did + * @param {Uint8Array} message + * @returns {Promise} + */ async signWith(did: DID, message: Uint8Array): Promise { return this.agentDIDHigherFunctions.signWith(did, message); } + /** + * Asyncronously parse a prismOnboarding invitation from a string + * + * @async + * @param {string} str + * @returns {Promise} + */ async parsePrismInvitation(str: string): Promise { return this.agentInvitations.parsePrismInvitation(str); } + /** + * Asyncronously parse an out of band invitation from a URI as the oob come in format of valid URL + * + * @async + * @param {URL} str + * @returns {Promise} + */ async parseOOBInvitation(str: URL): Promise { return this.agentInvitations.parseOOBInvitation(str); } + /** + * Asyncronously accept a didcomm v2 invitation, will create a pair between the Agent + * its connecting with and the current owner's did + * + * @async + * @param {OutOfBandInvitation} invitation + * @returns {*} + */ async acceptDIDCommInvitation( invitation: OutOfBandInvitation ): Promise { return this.agentInvitations.acceptDIDCommInvitation(invitation); } + /** + * Start fetching for new messages in such way that it can be stopped at any point in time without causing memory leaks + * + * @param {number} iterationPeriod + */ startFetchingMessages(iterationPeriod: number): void { this.connectionManager.startFetchingMessages(iterationPeriod); } + /** + * Stops fetching messages + */ stopFetchingMessages(): void { this.connectionManager.stopFetchingMessages(); } + /** + * Asyncronously send a didcomm Message + * + * @param {Message} message + * @returns {Promise} + */ sendMessage(message: Message): Promise { return this.connectionManager.sendMessage(message); } + /** + * Asyncronously get all verifiable credentials + * + * @returns {Promise} + */ verifiableCredentials(): Promise { return this.agentCredentials.verifiableCredentials(); } + /** + * Add an event listener to get notified from an Event "MESSAGE" + * + * @param {ListenerKey} eventName + * @param {EventCallback} callback + */ addListener(eventName: ListenerKey, callback: EventCallback): void { return this.connectionManager.events.addListener(eventName, callback); } + /** + * Remove event listener, used by stop procedure + * @date 20/06/2023 - 14:31:30 + * + * @param {ListenerKey} eventName + * @param {EventCallback} callback + */ removeListener(eventName: ListenerKey, callback: EventCallback): void { return this.connectionManager.events.removeListener(eventName, callback); } + /** + * Asyncronously prepare a request credential message from a valid offerCredential for now supporting w3c verifiable credentials offers. + * + * @async + * @param {OfferCredential} offer + * @returns {Promise} + */ async prepareRequestCredentialWithIssuer( offer: OfferCredential ): Promise { return this.agentCredentials.prepareRequestCredentialWithIssuer(offer); } + /** + * Extract the verifiableCredential object from the Issue credential message asyncronously + * + * @async + * @param {IssueCredential} message + * @returns {Promise} + */ async processIssuedCredentialMessage( message: IssueCredential ): Promise { return this.agentCredentials.processIssuedCredentialMessage(message); } + /** + * Asyncronously create a verifiablePresentation from a valid stored verifiableCredential + * This is used when the verified requests a specific verifiable credential, this will create the actual + * instance of the presentation which we can share with the verifier. + * + * @async + * @param {RequestPresentation} request + * @param {VerifiableCredential} credential + * @returns {Promise} + */ async createPresentationForRequestProof( request: RequestPresentation, credential: VerifiableCredential diff --git a/src/prism-agent/connectionsManager/ConnectionsManager.ts b/src/prism-agent/connectionsManager/ConnectionsManager.ts index 832e950a5..84a622c55 100644 --- a/src/prism-agent/connectionsManager/ConnectionsManager.ts +++ b/src/prism-agent/connectionsManager/ConnectionsManager.ts @@ -1,7 +1,7 @@ import { DID, Message, MessageDirection } from "../../domain"; -import Castor from "../../domain/buildingBlocks/Castor"; -import Mercury from "../../domain/buildingBlocks/Mercury"; -import Pluto from "../../domain/buildingBlocks/Pluto"; +import { Castor } from "../../domain/buildingBlocks/Castor"; +import { Mercury } from "../../domain/buildingBlocks/Mercury"; +import { Pluto } from "../../domain/buildingBlocks/Pluto"; import { DIDPair } from "../../domain/models/DIDPair"; import { AgentError } from "../../domain/models/Errors"; import { AgentMessageEvents } from "../Agent.MessageEvents"; @@ -13,13 +13,53 @@ import { MediatorHandler, } from "../types"; +/** + * ConnectionsManager is responsible of establishing didcomm connection and + * mediation process with other mediators through didcomm and is also + * responsible of managing the task to periodically fetch messages from the mediator once connection is established + * + * @class ConnectionsManager + * @typedef {ConnectionsManager} + */ export class ConnectionsManager implements ConnectionsManagerClass { + /** + * An array with cancellable tasks, mainly used to store one or multiple didcomm + * connections in storage implementation at the same time. All of them can be cancelled + * despite they run asyncronously when the Edge agent stops + * + * @public + * @type {CancellableTask[]} + */ // eslint-disable-next-line @typescript-eslint/no-explicit-any public cancellables: CancellableTask[] = []; + /** + * Cancellable task used to listen for new messages, stopping the Agent should also stop this + * from running and destroy the instance of the task until agent is started again + * + * @public + * @type {?CancellableTask} + */ public cancellable?: CancellableTask; + /** + * A list of public facing events which will notify the user interface when specific things happen, + * for now when new messages arrive or didcomm connections are established in order to make UI more reactive + * + * @public + * @type {AgentMessageEventsClass} + */ public events: AgentMessageEventsClass; + /** + * Creates an instance of ConnectionsManager. + * + * @constructor + * @param {Castor} castor + * @param {Mercury} mercury + * @param {Pluto} pluto + * @param {MediatorHandler} mediationHandler + * @param {DIDPair[]} [pairings=[]] + */ constructor( public castor: Castor, public mercury: Mercury, @@ -30,6 +70,13 @@ export class ConnectionsManager implements ConnectionsManagerClass { this.events = new AgentMessageEvents(); } + /** + * Asyncronously Start the mediator, just checking if we had one stored in Database and + * setting that one as default during the Agent start + * + * @async + * @returns {Promise} + */ async startMediator(): Promise { const mediationHandler = await this.mediationHandler.bootRegisteredMediator(); @@ -39,6 +86,9 @@ export class ConnectionsManager implements ConnectionsManagerClass { } } + /** + * Stops all the running events + */ stopAllEvents(): void { while (this.cancellables.length > 0) { const [task] = this.cancellables.splice(0, 1); @@ -48,6 +98,14 @@ export class ConnectionsManager implements ConnectionsManagerClass { } } + /** + * Asyncronously fetch unread messages from the mediator, if messages are found they will be stored + * and the mediator will be notified that they have been read. Mediator shouldn't return a read message again + * in next iteration. + * + * @async + * @returns {Promise} + */ async awaitMessages(): Promise { if (!this.mediationHandler.mediator) { throw new AgentError.NoMediatorAvailableError(); @@ -74,11 +132,25 @@ export class ConnectionsManager implements ConnectionsManagerClass { return messages; } + /** + * Asyncronously wait for a message response just by waiting for new messages that match the specified ID + * + * @async + * @param {string} id + * @returns {Promise} + */ async awaitMessageResponse(id: string): Promise { const messages = await this.awaitMessages(); return messages.find((message) => message.thid === id); } + /** + * Asyncronously add a didPair (didcomm connection) into pluto + * + * @async + * @param {DIDPair} paired + * @returns {Promise} + */ async addConnection(paired: DIDPair): Promise { if (this.findIndex(paired) !== -1) { return; @@ -95,6 +167,12 @@ export class ConnectionsManager implements ConnectionsManagerClass { storeDIDPairTask.callback((pair: DIDPair) => this.pairings.push(pair)); } + /** + * Find the specified did pair connection index + * + * @param {DIDPair} pair + * @returns {*} + */ findIndex(pair: DIDPair) { return this.pairings.findIndex( (pairing) => @@ -104,6 +182,14 @@ export class ConnectionsManager implements ConnectionsManagerClass { ); } + /** + * Remove a didPair or a didcomm connection, this does not mean the mediator will do + * this but just means the connection will be removed from the current storage + * + * @async + * @param {DIDPair} pair + * @returns {Promise} + */ async removeConnection(pair: DIDPair): Promise { const pairIndex = this.findIndex(pair); if (pairIndex !== -1) { @@ -111,15 +197,34 @@ export class ConnectionsManager implements ConnectionsManagerClass { } } + /** + * Asyncronously establish mediator with a mediator by providing the Host DID + * + * @async + * @param {DID} hostDID + * @returns {Promise} + */ async registerMediator(hostDID: DID): Promise { await this.mediationHandler.achieveMediation(hostDID); } + /** + * Asyncronously store a message and send it as didcomm message through the mercury implementation + * + * @async + * @param {Message} message + * @returns {Promise} + */ async sendMessage(message: Message): Promise { await this.pluto.storeMessage(message); return this.mercury.sendMessageParseMessage(message); } + /** + * Asyncronously start fetching new messages + * + * @param {number} iterationPeriod + */ startFetchingMessages(iterationPeriod: number): void { if (this.cancellable) { return; @@ -139,6 +244,9 @@ export class ConnectionsManager implements ConnectionsManagerClass { }); } + /** + * Asyncronously stop fetching messages + */ stopFetchingMessages(): void { this.cancellable?.cancel(); this.cancellable = undefined; diff --git a/src/prism-agent/helpers/ApiImpl.ts b/src/prism-agent/helpers/ApiImpl.ts index bddf9d274..b65ec6eb6 100644 --- a/src/prism-agent/helpers/ApiImpl.ts +++ b/src/prism-agent/helpers/ApiImpl.ts @@ -7,6 +7,9 @@ import axios, { import { Api, HttpResponse } from "../../domain/models/Api"; import { HttpError } from "./HttpError"; +/** + * @ignore + */ export class ApiImpl implements Api { client: AxiosStatic = axios; async request( diff --git a/src/prism-agent/mediator/BasicMediatorHandler.ts b/src/prism-agent/mediator/BasicMediatorHandler.ts index 6b8f2a24b..1cd158ea8 100644 --- a/src/prism-agent/mediator/BasicMediatorHandler.ts +++ b/src/prism-agent/mediator/BasicMediatorHandler.ts @@ -1,5 +1,5 @@ import { DID, Mediator, Message } from "../../domain"; -import Mercury from "../../domain/buildingBlocks/Mercury"; +import { Mercury } from "../../domain/buildingBlocks/Mercury"; import { AgentError } from "../../domain/models/Errors"; import { MediationGrant } from "../protocols/mediation/MediationGrant"; import { MediationKeysUpdateList } from "../protocols/mediation/MediationKeysUpdateList"; @@ -9,15 +9,47 @@ import { PickupRequest } from "../protocols/pickup/PickupRequest"; import { PickupRunner } from "../protocols/pickup/PickupRunner"; import { MediatorHandler, MediatorStore } from "../types"; +/** + * A basic implementation of our MediatorHandler Interface which is mainly used + * to establish mediation and get new messages using the mediation and pickup didcomm v2 protocols + * + * @class BasicMediatorHandler + * @typedef {BasicMediatorHandler} + */ export class BasicMediatorHandler implements MediatorHandler { + /** + * Optional instance of the mediator so that if the mediation was already + * established and recorded we don't need to mediate again with the same mediator + * + * @public + * @type {?Mediator} + */ public mediator?: Mediator; + /** + * Creates an instance of BasicMediatorHandler. + * + * @constructor + * @param {DID} mediatorDID + * @param {Mercury} mercury + * @param {MediatorStore} store + */ constructor( public mediatorDID: DID, public mercury: Mercury, public store: MediatorStore ) {} + /** + * Secondary constructor for BasicMediation Handler, to instanciate if from an existing Mediator + * instance. + * + * @static + * @param {Mediator} mediator + * @param {Mercury} mercury + * @param {MediatorStore} store + * @returns {BasicMediatorHandler} + */ static fromMediator( mediator: Mediator, mercury: Mercury, @@ -32,6 +64,12 @@ export class BasicMediatorHandler implements MediatorHandler { return mediatorHandler; } + /** + * Will asyncronously fetch the first mediator stored in database and set it as default mediator. + * + * @async + * @returns {Promise} + */ async bootRegisteredMediator(): Promise { if (!this.mediator) { const mediators = await this.store.getAllMediators(); @@ -43,6 +81,14 @@ export class BasicMediatorHandler implements MediatorHandler { return this.mediator; } + /** + * Asyncronously achieve mediation by specifying the HOST DID, this will + * exchange the mediation protocol messages between the user and the mediator until established + * + * @async + * @param {DID} host + * @returns {Promise} + */ async achieveMediation(host: DID): Promise { const mediator = await this.bootRegisteredMediator(); if (!mediator) { @@ -85,6 +131,13 @@ export class BasicMediatorHandler implements MediatorHandler { return mediator; } + /** + * Asyncronously update the mediator with the new keyList, used during the mediation process or during DID Rotation + * + * @async + * @param {DID[]} dids + * @returns {Promise} + */ async updateKeyListWithDIDs(dids: DID[]): Promise { if (!this.mediator) { throw new AgentError.NoMediatorAvailableError(); @@ -96,6 +149,16 @@ export class BasicMediatorHandler implements MediatorHandler { ).makeMessage(); await this.mercury.sendMessage(keyListUpdateMessage); } + + /** + * Asyncronously pickup unread messages from the mediator + * if new messages are found, because the messages from in form of attachments inside the pickup response + * we need to parse those and return the user a list of messages it can read and decode, this is done inside the pickup runner. + * + * @async + * @param {number} limit + * @returns {Promise>} + */ async pickupUnreadMessages( limit: number ): Promise> { @@ -114,6 +177,13 @@ export class BasicMediatorHandler implements MediatorHandler { } return new PickupRunner(message, this.mercury).run(); } + /** + * Asyncronously notify the current mediator that one or multiple message ID's have been read (or stored) + * + * @async + * @param {string[]} ids + * @returns {Promise} + */ async registerMessagesAsRead(ids: string[]): Promise { if (!this.mediator) { throw new AgentError.NoMediatorAvailableError(); diff --git a/src/prism-agent/mediator/PlutoMediatorStore.ts b/src/prism-agent/mediator/PlutoMediatorStore.ts index 5d634761b..ae86a2cbf 100644 --- a/src/prism-agent/mediator/PlutoMediatorStore.ts +++ b/src/prism-agent/mediator/PlutoMediatorStore.ts @@ -1,10 +1,31 @@ import { Mediator } from "../../domain"; -import Pluto from "../../domain/buildingBlocks/Pluto"; +import { Pluto } from "../../domain/buildingBlocks/Pluto"; import { MediatorStore } from "../types"; +/** + * PlutoMediationStore is used just to interface between the mediators and storage. + * It is mainly used to store + fetch mediator from current storage instance (pluto) + * + * @export + * @class PublicMediatorStore + * @typedef {PublicMediatorStore} + */ export class PublicMediatorStore implements MediatorStore { + /** + * Creates an instance of PublicMediatorStore. + * + * @constructor + * @param {Pluto} pluto + */ constructor(private pluto: Pluto) {} + /** + * Stores a mediator asyncronously in pluto + * + * @async + * @param {Mediator} mediator + * @returns {Promise} + */ async storeMediator(mediator: Mediator): Promise { const response = await this.pluto.storeMediator( mediator.mediatorDID, @@ -14,6 +35,12 @@ export class PublicMediatorStore implements MediatorStore { return response; } + /** + * Asyncronously fetch all the mediators from storage + * + * @async + * @returns {Promise} + */ async getAllMediators(): Promise { return this.pluto.getAllMediators(); } diff --git a/src/prism-agent/protocols/connection/DIDCommConnectionRunner.ts b/src/prism-agent/protocols/connection/DIDCommConnectionRunner.ts index 119c5c360..87c77be53 100644 --- a/src/prism-agent/protocols/connection/DIDCommConnectionRunner.ts +++ b/src/prism-agent/protocols/connection/DIDCommConnectionRunner.ts @@ -1,5 +1,5 @@ import { DID } from "../../../domain"; -import Pluto from "../../../domain/buildingBlocks/Pluto"; +import { Pluto } from "../../../domain/buildingBlocks/Pluto"; import { DIDPair } from "../../../domain/models/DIDPair"; import { ConnectionsManager } from "../../types"; import { OutOfBandInvitation } from "../invitation/v2/OutOfBandInvitation"; diff --git a/src/prism-agent/protocols/invitation/v2/InvitationRunner.ts b/src/prism-agent/protocols/invitation/v2/InvitationRunner.ts index f84fb30d9..54b732b18 100644 --- a/src/prism-agent/protocols/invitation/v2/InvitationRunner.ts +++ b/src/prism-agent/protocols/invitation/v2/InvitationRunner.ts @@ -1,5 +1,5 @@ import { Message } from "../../../../domain"; -import Mercury from "../../../../domain/buildingBlocks/Mercury"; +import { Mercury } from "../../../../domain/buildingBlocks/Mercury"; import { OutOfBandParser } from "./OutOfBandParser"; export class InvitationRunner { diff --git a/src/prism-agent/protocols/pickup/PickupRunner.ts b/src/prism-agent/protocols/pickup/PickupRunner.ts index 509c2e189..59ccc5407 100644 --- a/src/prism-agent/protocols/pickup/PickupRunner.ts +++ b/src/prism-agent/protocols/pickup/PickupRunner.ts @@ -1,5 +1,5 @@ import { AttachmentDescriptor, Message } from "../../../domain"; -import Mercury from "../../../domain/buildingBlocks/Mercury"; +import { Mercury } from "../../../domain/buildingBlocks/Mercury"; import { AgentError } from "../../../domain/models/Errors"; import { ProtocolType } from "../ProtocolTypes"; import { PickupAttachment } from "../types"; diff --git a/src/prism-agent/types/index.ts b/src/prism-agent/types/index.ts index b0e546ea5..b5e2e89d2 100644 --- a/src/prism-agent/types/index.ts +++ b/src/prism-agent/types/index.ts @@ -8,9 +8,9 @@ import { Signature, } from "../../domain"; import { DIDPair } from "../../domain/models/DIDPair"; -import Castor from "../../domain/buildingBlocks/Castor"; -import Mercury from "../../domain/buildingBlocks/Mercury"; -import Pluto from "../../domain/buildingBlocks/Pluto"; +import { Castor } from "../../domain/buildingBlocks/Castor"; +import { Mercury } from "../../domain/buildingBlocks/Mercury"; +import { Pluto } from "../../domain/buildingBlocks/Pluto"; import { CancellableTask } from "../helpers/Task"; import { OfferCredential } from "../protocols/issueCredential/OfferCredential"; import { RequestCredential } from "../protocols/issueCredential/RequestCredential"; diff --git a/tsconfig.json b/tsconfig.json index 1c128c0b0..b7da3efeb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "declarationDir": "build/typings", "module": "esnext", "target": "es2020", + "skipLibCheck": true, "resolveJsonModule": true, "isolatedModules": true, "allowJs": true, @@ -14,7 +15,6 @@ "emitDeclarationOnly": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, - "suppressImplicitAnyIndexErrors": true, "allowSyntheticDefaultImports": true, "lib": ["es2020", "dom", "dom.iterable", "esnext"], "moduleResolution": "node", diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 000000000..18db90706 --- /dev/null +++ b/typedoc.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["./src/index.ts"], + "out": "./docs", + "tsconfig": "tsconfig.json", + "name": "@input-output-hk/atala-prism-wallet-sdk", + "useTsLinkResolution": true, + "hideGenerator": true, + "entryPointStrategy": "resolve", + "excludePrivate": false, + "excludeReferences": false, + "excludeProtected": false, + "excludeInternal": false, + "excludeNotDocumented": false, + "theme": "default", + "plugin": ["typedoc-plugin-superstruct", "typedoc-plugin-rename-defaults"] +} From 807e7555e1722845537fff855469efa975372f80 Mon Sep 17 00:00:00 2001 From: atala-dev Date: Thu, 22 Jun 2023 16:04:12 +0000 Subject: [PATCH 2/2] chore(release): release 2.0.2 ## [2.0.2](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/compare/v2.0.1...v2.0.2) (2023-06-22) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Bug Fixes * **docs:** Correct the required commands to run the nodejs + browser … ([#64](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/issues/64)) ([fec65fe](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/commit/fec65fe0f77657fab99c6e817c8ed31d729f0d2a)) * **docs:** Improve Generated documentation ([#65](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/issues/65)) ([db3c20e](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/commit/db3c20eeb081256dbe6931c3b34e4cc53c2039f7)) * Documentation improvements ([#62](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/issues/62)) ([6d43d03](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/commit/6d43d033d2bb3019c9fe4fa000cde6afbdccc8e2)) --- CHANGELOG.md | 9 +++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95290111c..b3aee2f2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## [2.0.2](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/compare/v2.0.1...v2.0.2) (2023-06-22) + + +### Bug Fixes + +* **docs:** Correct the required commands to run the nodejs + browser … ([#64](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/issues/64)) ([fec65fe](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/commit/fec65fe0f77657fab99c6e817c8ed31d729f0d2a)) +* **docs:** Improve Generated documentation ([#65](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/issues/65)) ([db3c20e](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/commit/db3c20eeb081256dbe6931c3b34e4cc53c2039f7)) +* Documentation improvements ([#62](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/issues/62)) ([6d43d03](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/commit/6d43d033d2bb3019c9fe4fa000cde6afbdccc8e2)) + ## [2.0.1](https://github.com/input-output-hk/atala-prism-wallet-sdk-ts/compare/v2.0.0...v2.0.1) (2023-05-31) diff --git a/package-lock.json b/package-lock.json index 3e45d4fee..53d485a99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@input-output-hk/atala-prism-wallet-sdk", - "version": "2.0.1", + "version": "2.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@input-output-hk/atala-prism-wallet-sdk", - "version": "2.0.1", + "version": "2.0.2", "dependencies": { "@scure/bip32": "^1.3.0", "@scure/bip39": "^1.1.1", diff --git a/package.json b/package.json index 360a9e8d9..0ef5dde5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@input-output-hk/atala-prism-wallet-sdk", - "version": "2.0.1", + "version": "2.0.2", "description": "PRISM typescript SDK", "main": "build/node/index.js", "browser": "build/browser/index.js",