From af384e8a92f877c647999f9356b72a8017308230 Mon Sep 17 00:00:00 2001 From: Timo Glastra Date: Sat, 18 Feb 2023 01:32:45 +0100 Subject: [PATCH 1/7] fix: loosen base64 validation (#1312) Signed-off-by: Timo Glastra --- .../core/src/decorators/attachment/Attachment.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/core/src/decorators/attachment/Attachment.ts b/packages/core/src/decorators/attachment/Attachment.ts index 50a91e8edb..53ea3caf9f 100644 --- a/packages/core/src/decorators/attachment/Attachment.ts +++ b/packages/core/src/decorators/attachment/Attachment.ts @@ -1,17 +1,7 @@ import type { JwsGeneralFormat } from '../../crypto/JwsTypes' import { Expose, Type } from 'class-transformer' -import { - IsBase64, - IsDate, - IsHash, - IsInstance, - IsInt, - IsMimeType, - IsOptional, - IsString, - ValidateNested, -} from 'class-validator' +import { IsDate, IsHash, IsInstance, IsInt, IsMimeType, IsOptional, IsString, ValidateNested } from 'class-validator' import { Jws } from '../../crypto/JwsTypes' import { AriesFrameworkError } from '../../error' @@ -44,7 +34,7 @@ export class AttachmentData { * Base64-encoded data, when representing arbitrary content inline instead of via links. Optional. */ @IsOptional() - @IsBase64() + @IsString() public base64?: string /** From ff5596d0631e93746494c017797d0191b6bdb0b1 Mon Sep 17 00:00:00 2001 From: Ariel Gentile Date: Fri, 17 Feb 2023 23:10:09 -0300 Subject: [PATCH 2/7] feat!: add data, cache and temp dirs to FileSystem (#1306) Signed-off-by: Ariel Gentile BREAKING CHANGE: Agent-produced files will now be divided in different system paths depending on their nature: data, temp and cache. Previously, they were located at a single location, defaulting to a temporary directory. If you specified a custom path in `FileSystem` object constructor, you now must provide an object containing `baseDataPath`, `baseTempPath` and `baseCachePath`. They can point to the same path, although it's recommended to specify different path to avoid future file clashes. --- packages/anoncreds/src/utils/tails.ts | 6 ++-- packages/askar/src/utils/askarWalletConfig.ts | 13 ++++++-- packages/askar/src/wallet/AskarWallet.ts | 4 +-- .../indy/services/IndyUtilitiesService.ts | 2 +- packages/core/src/modules/ledger/IndyPool.ts | 2 +- packages/core/src/storage/FileSystem.ts | 5 ++- .../src/storage/migration/UpdateAssistant.ts | 7 +++- .../storage/migration/__tests__/0.1.test.ts | 24 -------------- .../storage/migration/__tests__/0.2.test.ts | 19 ----------- .../storage/migration/__tests__/0.3.test.ts | 4 --- .../migration/__tests__/backup.test.ts | 15 ++++++--- packages/indy-sdk/src/ledger/IndySdkPool.ts | 2 +- packages/node/src/NodeFileSystem.ts | 33 +++++++++++++------ packages/node/tests/NodeFileSystem.test.ts | 2 +- packages/react-native/package.json | 4 +-- .../react-native/src/ReactNativeFileSystem.ts | 30 ++++++++++++++--- 16 files changed, 91 insertions(+), 81 deletions(-) diff --git a/packages/anoncreds/src/utils/tails.ts b/packages/anoncreds/src/utils/tails.ts index 9ae29aa8e4..e706f00914 100644 --- a/packages/anoncreds/src/utils/tails.ts +++ b/packages/anoncreds/src/utils/tails.ts @@ -2,11 +2,11 @@ import type { AgentContext, FileSystem } from '@aries-framework/core' import { TypedArrayEncoder, InjectionSymbols } from '@aries-framework/core' -const getTailsFilePath = (basePath: string, tailsHash: string) => `${basePath}/afj/anoncreds/tails/${tailsHash}` +const getTailsFilePath = (cachePath: string, tailsHash: string) => `${cachePath}/anoncreds/tails/${tailsHash}` export function tailsFileExists(agentContext: AgentContext, tailsHash: string): Promise { const fileSystem = agentContext.dependencyManager.resolve(InjectionSymbols.FileSystem) - const tailsFilePath = getTailsFilePath(fileSystem.basePath, tailsHash) + const tailsFilePath = getTailsFilePath(fileSystem.cachePath, tailsHash) return fileSystem.exists(tailsFilePath) } @@ -27,7 +27,7 @@ export async function downloadTailsFile( // hash is used as file identifier const tailsExists = await tailsFileExists(agentContext, tailsHashBase58) - const tailsFilePath = getTailsFilePath(fileSystem.basePath, tailsHashBase58) + const tailsFilePath = getTailsFilePath(fileSystem.cachePath, tailsHashBase58) agentContext.config.logger.debug( `Tails file for ${tailsLocation} ${tailsExists ? 'is stored' : 'is not stored'} at ${tailsFilePath}` ) diff --git a/packages/askar/src/utils/askarWalletConfig.ts b/packages/askar/src/utils/askarWalletConfig.ts index 2337988f26..b6e885ebe5 100644 --- a/packages/askar/src/utils/askarWalletConfig.ts +++ b/packages/askar/src/utils/askarWalletConfig.ts @@ -18,7 +18,16 @@ export const keyDerivationMethodToStoreKeyMethod = (keyDerivationMethod?: KeyDer return correspondenceTable[keyDerivationMethod] as StoreKeyMethod } -export const uriFromWalletConfig = (walletConfig: WalletConfig, basePath: string): { uri: string; path?: string } => { +/** + * Creates a proper askar wallet URI value based on walletConfig + * @param walletConfig WalletConfig object + * @param afjDataPath framework data path (used in case walletConfig.storage.path is undefined) + * @returns string containing the askar wallet URI + */ +export const uriFromWalletConfig = ( + walletConfig: WalletConfig, + afjDataPath: string +): { uri: string; path?: string } => { let uri = '' let path @@ -31,7 +40,7 @@ export const uriFromWalletConfig = (walletConfig: WalletConfig, basePath: string if (walletConfig.storage.inMemory) { uri = 'sqlite://:memory:' } else { - path = `${(walletConfig.storage.path as string) ?? basePath + '/wallet'}/${walletConfig.id}/sqlite.db` + path = (walletConfig.storage.path as string) ?? `${afjDataPath}/wallet/${walletConfig.id}/sqlite.db` uri = `sqlite://${path}` } } else if (walletConfig.storage.type === 'postgres') { diff --git a/packages/askar/src/wallet/AskarWallet.ts b/packages/askar/src/wallet/AskarWallet.ts index baa17838a4..38030c6ab7 100644 --- a/packages/askar/src/wallet/AskarWallet.ts +++ b/packages/askar/src/wallet/AskarWallet.ts @@ -289,7 +289,7 @@ export class AskarWallet implements Wallet { } try { - const { uri } = uriFromWalletConfig(this.walletConfig, this.fileSystem.basePath) + const { uri } = uriFromWalletConfig(this.walletConfig, this.fileSystem.dataPath) await Store.remove(uri) } catch (error) { const errorMessage = `Error deleting wallet '${this.walletConfig.id}': ${error.message}` @@ -689,7 +689,7 @@ export class AskarWallet implements Wallet { } private async getAskarWalletConfig(walletConfig: WalletConfig) { - const { uri, path } = uriFromWalletConfig(walletConfig, this.fileSystem.basePath) + const { uri, path } = uriFromWalletConfig(walletConfig, this.fileSystem.dataPath) // Make sure path exists before creating the wallet if (path) { diff --git a/packages/core/src/modules/indy/services/IndyUtilitiesService.ts b/packages/core/src/modules/indy/services/IndyUtilitiesService.ts index eef01ccfd2..44b9713352 100644 --- a/packages/core/src/modules/indy/services/IndyUtilitiesService.ts +++ b/packages/core/src/modules/indy/services/IndyUtilitiesService.ts @@ -63,7 +63,7 @@ export class IndyUtilitiesService { public async downloadTails(hash: string, tailsLocation: string): Promise { try { this.logger.debug(`Checking to see if tails file for URL ${tailsLocation} has been stored in the FileSystem`) - const filePath = `${this.fileSystem.basePath}/afj/tails/${hash}` + const filePath = `${this.fileSystem.cachePath}/tails/${hash}` const tailsExists = await this.fileSystem.exists(filePath) this.logger.debug(`Tails file for ${tailsLocation} ${tailsExists ? 'is stored' : 'is not stored'} at ${filePath}`) diff --git a/packages/core/src/modules/ledger/IndyPool.ts b/packages/core/src/modules/ledger/IndyPool.ts index c3d2249799..d8abffc113 100644 --- a/packages/core/src/modules/ledger/IndyPool.ts +++ b/packages/core/src/modules/ledger/IndyPool.ts @@ -181,7 +181,7 @@ export class IndyPool { if (this.poolConfig.genesisPath) return this.poolConfig.genesisPath // Determine the genesisPath - const genesisPath = this.fileSystem.basePath + `/afj/genesis-${this.poolConfig.id}.txn` + const genesisPath = this.fileSystem.tempPath + `/genesis-${this.poolConfig.id}.txn` // Store genesis data if provided if (this.poolConfig.genesisTransactions) { await this.fileSystem.write(genesisPath, this.poolConfig.genesisTransactions) diff --git a/packages/core/src/storage/FileSystem.ts b/packages/core/src/storage/FileSystem.ts index c5996e78b2..a6eeb08e48 100644 --- a/packages/core/src/storage/FileSystem.ts +++ b/packages/core/src/storage/FileSystem.ts @@ -5,11 +5,14 @@ export interface DownloadToFileOptions { } export interface FileSystem { - readonly basePath: string + readonly dataPath: string + readonly cachePath: string + readonly tempPath: string exists(path: string): Promise createDirectory(path: string): Promise write(path: string, data: string): Promise read(path: string): Promise + delete(path: string): Promise downloadToFile(url: string, path: string, options?: DownloadToFileOptions): Promise } diff --git a/packages/core/src/storage/migration/UpdateAssistant.ts b/packages/core/src/storage/migration/UpdateAssistant.ts index f4647d4891..3c08c2fe64 100644 --- a/packages/core/src/storage/migration/UpdateAssistant.ts +++ b/packages/core/src/storage/migration/UpdateAssistant.ts @@ -157,6 +157,8 @@ export class UpdateAssistant = BaseAgent> { `Successfully updated agent storage from version ${update.fromVersion} to version ${update.toVersion}` ) } + // Delete backup file, as it is not needed anymore + await this.fileSystem.delete(this.getBackupPath(updateIdentifier)) } catch (error) { this.agent.config.logger.fatal('An error occurred while updating the wallet. Restoring backup', { error, @@ -164,6 +166,9 @@ export class UpdateAssistant = BaseAgent> { // In the case of an error we want to restore the backup await this.restoreBackup(updateIdentifier) + // Delete backup file, as wallet was already restored (backup-error file will persist though) + await this.fileSystem.delete(this.getBackupPath(updateIdentifier)) + throw error } } catch (error) { @@ -192,7 +197,7 @@ export class UpdateAssistant = BaseAgent> { } private getBackupPath(backupIdentifier: string) { - return `${this.fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` + return `${this.fileSystem.dataPath}/migration/backup/${backupIdentifier}` } private async createBackup(backupIdentifier: string) { diff --git a/packages/core/src/storage/migration/__tests__/0.1.test.ts b/packages/core/src/storage/migration/__tests__/0.1.test.ts index ad2dd0b837..f38ba94a87 100644 --- a/packages/core/src/storage/migration/__tests__/0.1.test.ts +++ b/packages/core/src/storage/migration/__tests__/0.1.test.ts @@ -48,8 +48,6 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { dependencyManager ) - const fileSystem = agent.dependencyManager.resolve(InjectionSymbols.FileSystem) - const updateAssistant = new UpdateAssistant(agent, { v0_1ToV0_2: { mediationRoleUpdateStrategy, @@ -79,10 +77,6 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { delete storageService.records.MEDIATOR_ROUTING_RECORD expect(storageService.records).toMatchSnapshot(mediationRoleUpdateStrategy) - // Need to remove backupFiles after each run so we don't get IOErrors - const backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` - unlinkSync(backupPath) - await agent.shutdown() await agent.wallet.delete() } @@ -110,8 +104,6 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { dependencyManager ) - const fileSystem = agent.dependencyManager.resolve(InjectionSymbols.FileSystem) - const updateAssistant = new UpdateAssistant(agent, { v0_1ToV0_2: { mediationRoleUpdateStrategy: 'doNotChange', @@ -142,10 +134,6 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { delete storageService.records.MEDIATOR_ROUTING_RECORD expect(storageService.records).toMatchSnapshot() - // Need to remove backupFiles after each run so we don't get IOErrors - const backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` - unlinkSync(backupPath) - await agent.shutdown() await agent.wallet.delete() @@ -174,8 +162,6 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { dependencyManager ) - const fileSystem = agent.dependencyManager.resolve(InjectionSymbols.FileSystem) - const updateAssistant = new UpdateAssistant(agent, { v0_1ToV0_2: { mediationRoleUpdateStrategy: 'doNotChange', @@ -206,10 +192,6 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { delete storageService.records.MEDIATOR_ROUTING_RECORD expect(storageService.records).toMatchSnapshot() - // Need to remove backupFiles after each run so we don't get IOErrors - const backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` - unlinkSync(backupPath) - await agent.shutdown() await agent.wallet.delete() @@ -242,8 +224,6 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { dependencyManager ) - const fileSystem = agent.dependencyManager.resolve(InjectionSymbols.FileSystem) - const updateAssistant = new UpdateAssistant(agent, { v0_1ToV0_2: { mediationRoleUpdateStrategy: 'doNotChange', @@ -274,10 +254,6 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { delete storageService.records.MEDIATOR_ROUTING_RECORD expect(storageService.records).toMatchSnapshot() - // Need to remove backupFiles after each run so we don't get IOErrors - const backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` - unlinkSync(backupPath) - await agent.shutdown() await agent.wallet.delete() diff --git a/packages/core/src/storage/migration/__tests__/0.2.test.ts b/packages/core/src/storage/migration/__tests__/0.2.test.ts index 08ed9dce64..9fb991253b 100644 --- a/packages/core/src/storage/migration/__tests__/0.2.test.ts +++ b/packages/core/src/storage/migration/__tests__/0.2.test.ts @@ -13,7 +13,6 @@ import { UpdateAssistant } from '../UpdateAssistant' const backupDate = new Date('2022-01-21T22:50:20.522Z') jest.useFakeTimers().setSystemTime(backupDate) -const backupIdentifier = backupDate.getTime() const walletConfig = { id: `Wallet: 0.2 Update`, @@ -46,8 +45,6 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { dependencyManager ) - const fileSystem = agent.dependencyManager.resolve(InjectionSymbols.FileSystem) - const updateAssistant = new UpdateAssistant(agent, { v0_1ToV0_2: { mediationRoleUpdateStrategy: 'doNotChange', @@ -83,10 +80,6 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { delete storageService.records.MEDIATOR_ROUTING_RECORD expect(storageService.records).toMatchSnapshot() - // Need to remove backupFiles after each run so we don't get IOErrors - const backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` - unlinkSync(backupPath) - await agent.shutdown() await agent.wallet.delete() @@ -119,8 +112,6 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { dependencyManager ) - const fileSystem = agent.dependencyManager.resolve(InjectionSymbols.FileSystem) - // We need to manually initialize the wallet as we're using the in memory wallet service // When we call agent.initialize() it will create the wallet and store the current framework // version in the in memory storage service. We need to manually set the records between initializing @@ -137,10 +128,6 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { delete storageService.records.MEDIATOR_ROUTING_RECORD expect(storageService.records).toMatchSnapshot() - // Need to remove backupFiles after each run so we don't get IOErrors - const backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` - unlinkSync(backupPath) - await agent.shutdown() await agent.wallet.delete() @@ -170,8 +157,6 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { dependencyManager ) - const fileSystem = agent.dependencyManager.resolve(InjectionSymbols.FileSystem) - // We need to manually initialize the wallet as we're using the in memory wallet service // When we call agent.initialize() it will create the wallet and store the current framework // version in the in memory storage service. We need to manually set the records between initializing @@ -189,10 +174,6 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { expect(storageService.records).toMatchSnapshot() - // Need to remove backupFiles after each run so we don't get IOErrors - const backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` - unlinkSync(backupPath) - await agent.shutdown() await agent.wallet.delete() diff --git a/packages/core/src/storage/migration/__tests__/0.3.test.ts b/packages/core/src/storage/migration/__tests__/0.3.test.ts index b797fc7c97..124cdf0a88 100644 --- a/packages/core/src/storage/migration/__tests__/0.3.test.ts +++ b/packages/core/src/storage/migration/__tests__/0.3.test.ts @@ -75,10 +75,6 @@ describe('UpdateAssistant | v0.3 - v0.3.1', () => { delete storageService.records.MEDIATOR_ROUTING_RECORD expect(storageService.records).toMatchSnapshot() - // Need to remove backupFiles after each run so we don't get IOErrors - const backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` - unlinkSync(backupPath) - await agent.shutdown() await agent.wallet.delete() diff --git a/packages/core/src/storage/migration/__tests__/backup.test.ts b/packages/core/src/storage/migration/__tests__/backup.test.ts index 73aba5823f..8a8b351a38 100644 --- a/packages/core/src/storage/migration/__tests__/backup.test.ts +++ b/packages/core/src/storage/migration/__tests__/backup.test.ts @@ -32,7 +32,7 @@ describe('UpdateAssistant | Backup', () => { beforeEach(async () => { agent = new Agent(agentOptions) const fileSystem = agent.dependencyManager.resolve(InjectionSymbols.FileSystem) - backupPath = `${fileSystem.basePath}/afj/migration/backup/${backupIdentifier}` + backupPath = `${fileSystem.dataPath}/migration/backup/${backupIdentifier}` // If tests fail it's possible the cleanup has been skipped. So remove before running tests const doesFileSystemExist = await fileSystem.exists(backupPath) @@ -85,11 +85,16 @@ describe('UpdateAssistant | Backup', () => { // Backup should not exist before update expect(await fileSystem.exists(backupPath)).toBe(false) + const walletSpy = jest.spyOn(agent.wallet, 'export') + // Create update await updateAssistant.update() - // Backup should exist after update - expect(await fileSystem.exists(backupPath)).toBe(true) + // A wallet export should have been initiated + expect(walletSpy).toHaveBeenCalledWith({ key: agent.wallet.walletConfig?.key, path: backupPath }) + + // Backup should be cleaned after update + expect(await fileSystem.exists(backupPath)).toBe(false) expect( (await credentialRepository.getAll(agent.context)).sort((a, b) => a.id.localeCompare(b.id)) @@ -142,8 +147,8 @@ describe('UpdateAssistant | Backup', () => { expect(updateError?.cause?.message).toEqual("Uh oh I'm broken") - // Backup should exist after update - expect(await fileSystem.exists(backupPath)).toBe(true) + // Only backup error should exist after update + expect(await fileSystem.exists(backupPath)).toBe(false) expect(await fileSystem.exists(`${backupPath}-error`)).toBe(true) // Wallet should be same as when we started because of backup diff --git a/packages/indy-sdk/src/ledger/IndySdkPool.ts b/packages/indy-sdk/src/ledger/IndySdkPool.ts index bae9d8e17b..dfa25feb37 100644 --- a/packages/indy-sdk/src/ledger/IndySdkPool.ts +++ b/packages/indy-sdk/src/ledger/IndySdkPool.ts @@ -180,7 +180,7 @@ export class IndySdkPool { if (this.poolConfig.genesisPath) return this.poolConfig.genesisPath // Determine the genesisPath - const genesisPath = this.fileSystem.basePath + `/afj/genesis-${this.poolConfig.id}.txn` + const genesisPath = this.fileSystem.tempPath + `/genesis-${this.poolConfig.id}.txn` // Store genesis data if provided if (this.poolConfig.genesisTransactions) { await this.fileSystem.write(genesisPath, this.poolConfig.genesisTransactions) diff --git a/packages/node/src/NodeFileSystem.ts b/packages/node/src/NodeFileSystem.ts index a5caf0d070..75ebb01b73 100644 --- a/packages/node/src/NodeFileSystem.ts +++ b/packages/node/src/NodeFileSystem.ts @@ -5,21 +5,30 @@ import { createHash } from 'crypto' import fs, { promises } from 'fs' import http from 'http' import https from 'https' -import { tmpdir } from 'os' +import { tmpdir, homedir } from 'os' import { dirname } from 'path' -const { access, readFile, writeFile } = promises +const { access, readFile, writeFile, mkdir, rm, unlink } = promises export class NodeFileSystem implements FileSystem { - public readonly basePath + public readonly dataPath + public readonly cachePath + public readonly tempPath /** * Create new NodeFileSystem class instance. * - * @param basePath The base path to use for reading and writing files. process.cwd() if not specified + * @param baseDataPath The base path to use for reading and writing data files used within the framework. + * Files will be created under baseDataPath/.afj directory. If not specified, it will be set to homedir() + * @param baseCachePath The base path to use for reading and writing cache files used within the framework. + * Files will be created under baseCachePath/.afj directory. If not specified, it will be set to homedir() + * @param baseTempPath The base path to use for reading and writing temporary files within the framework. + * Files will be created under baseTempPath/.afj directory. If not specified, it will be set to tmpdir() */ - public constructor(basePath?: string) { - this.basePath = basePath ?? tmpdir() + public constructor(options?: { baseDataPath?: string; baseCachePath?: string; baseTempPath?: string }) { + this.dataPath = options?.baseDataPath ? `${options?.baseDataPath}/.afj` : `${homedir()}/.afj/data` + this.cachePath = options?.baseCachePath ? `${options?.baseCachePath}/.afj` : `${homedir()}/.afj/cache` + this.tempPath = `${options?.baseTempPath ?? tmpdir()}/.afj` } public async exists(path: string) { @@ -32,12 +41,12 @@ export class NodeFileSystem implements FileSystem { } public async createDirectory(path: string): Promise { - await promises.mkdir(dirname(path), { recursive: true }) + await mkdir(dirname(path), { recursive: true }) } public async write(path: string, data: string): Promise { // Make sure parent directories exist - await promises.mkdir(dirname(path), { recursive: true }) + await mkdir(dirname(path), { recursive: true }) return writeFile(path, data, { encoding: 'utf-8' }) } @@ -46,11 +55,15 @@ export class NodeFileSystem implements FileSystem { return readFile(path, { encoding: 'utf-8' }) } + public async delete(path: string): Promise { + await rm(path, { recursive: true, force: true }) + } + public async downloadToFile(url: string, path: string, options: DownloadToFileOptions) { const httpMethod = url.startsWith('https') ? https : http // Make sure parent directories exist - await promises.mkdir(dirname(path), { recursive: true }) + await mkdir(dirname(path), { recursive: true }) const file = fs.createWriteStream(path) const hash = options.verifyHash ? createHash('sha256') : undefined @@ -88,7 +101,7 @@ export class NodeFileSystem implements FileSystem { }) .on('error', async (error) => { // Handle errors - await fs.promises.unlink(path) // Delete the file async. (But we don't check the result) + await unlink(path) // Delete the file async. (But we don't check the result) reject(`Unable to download file from url: ${url}. ${error.message}`) }) }) diff --git a/packages/node/tests/NodeFileSystem.test.ts b/packages/node/tests/NodeFileSystem.test.ts index f031ee32e5..f62f4d8e00 100644 --- a/packages/node/tests/NodeFileSystem.test.ts +++ b/packages/node/tests/NodeFileSystem.test.ts @@ -28,7 +28,7 @@ describe('@aries-framework/file-system-node', () => { await fileSystem.downloadToFile( 'https://tails.prod.absa.africa/api/public/tails/4B1NxYuGxwYMe5BAyP9NXkUmbEkDATo4oGZCgjXQ3y1p', - `${fileSystem.basePath}/afj/tails/4B1NxYuGxwYMe5BAyP9NXkUmbEkDATo4oGZCgjXQ3y1p`, + `${fileSystem.dataPath}/tails/4B1NxYuGxwYMe5BAyP9NXkUmbEkDATo4oGZCgjXQ3y1p`, { verifyHash: { algorithm: 'sha256', diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 3fa303bf91..1da533811d 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -26,11 +26,11 @@ "dependencies": { "@aries-framework/core": "0.3.3", "@azure/core-asynciterator-polyfill": "^1.0.0", - "events": "^3.3.0" + "events": "^3.3.0", + "@types/react-native": "^0.64.10" }, "devDependencies": { "@types/indy-sdk-react-native": "npm:@types/indy-sdk@1.16.26", - "@types/react-native": "^0.64.10", "indy-sdk-react-native": "^0.3.1", "react": "17.0.1", "react-native": "0.64.2", diff --git a/packages/react-native/src/ReactNativeFileSystem.ts b/packages/react-native/src/ReactNativeFileSystem.ts index bf8e9fb353..48588fad88 100644 --- a/packages/react-native/src/ReactNativeFileSystem.ts +++ b/packages/react-native/src/ReactNativeFileSystem.ts @@ -1,20 +1,38 @@ import type { FileSystem, DownloadToFileOptions } from '@aries-framework/core' import { TypedArrayEncoder, AriesFrameworkError, getDirFromFilePath, Buffer } from '@aries-framework/core' +import { Platform } from 'react-native' import * as RNFS from 'react-native-fs' export class ReactNativeFileSystem implements FileSystem { - public readonly basePath + public readonly dataPath + public readonly cachePath + public readonly tempPath /** * Create new ReactNativeFileSystem class instance. * - * @param basePath The base path to use for reading and writing files. RNFS.TemporaryDirectoryPath if not specified + * @param baseDataPath The base path to use for reading and writing data files used within the framework. + * Files will be created under baseDataPath/.afj directory. If not specified, it will be set to + * RNFS.DocumentDirectoryPath + * @param baseCachePath The base path to use for reading and writing cache files used within the framework. + * Files will be created under baseCachePath/.afj directory. If not specified, it will be set to + * RNFS.CachesDirectoryPath + * @param baseTempPath The base path to use for reading and writing temporary files within the framework. + * Files will be created under baseTempPath/.afj directory. If not specified, it will be set to + * RNFS.TemporaryDirectoryPath * * @see https://github.com/itinance/react-native-fs#constants */ - public constructor(basePath?: string) { - this.basePath = basePath ?? RNFS.TemporaryDirectoryPath + public constructor(options?: { baseDataPath?: string; baseCachePath?: string; baseTempPath?: string }) { + this.dataPath = `${options?.baseDataPath ?? RNFS.DocumentDirectoryPath}/.afj` + // In Android, TemporaryDirectoryPath falls back to CachesDirectoryPath + this.cachePath = options?.baseCachePath + ? `${options?.baseCachePath}/.afj` + : `${RNFS.CachesDirectoryPath}/.afj${Platform.OS === 'android' ? '/cache' : ''}` + this.tempPath = options?.baseTempPath + ? `${options?.baseTempPath}/.afj` + : `${RNFS.TemporaryDirectoryPath}/.afj${Platform.OS === 'android' ? '/temp' : ''}` } public async exists(path: string): Promise { @@ -36,6 +54,10 @@ export class ReactNativeFileSystem implements FileSystem { return RNFS.readFile(path, 'utf8') } + public async delete(path: string): Promise { + await RNFS.unlink(path) + } + public async downloadToFile(url: string, path: string, options?: DownloadToFileOptions) { // Make sure parent directories exist await RNFS.mkdir(getDirFromFilePath(path)) From 64a5da937059d25e693e2491af329548b2975ef6 Mon Sep 17 00:00:00 2001 From: Ariel Gentile Date: Sat, 18 Feb 2023 16:54:25 -0300 Subject: [PATCH 3/7] fix(samples): dummy module response message type (#1321) Signed-off-by: Ariel Gentile --- samples/extension-module/dummy/messages/DummyResponseMessage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/extension-module/dummy/messages/DummyResponseMessage.ts b/samples/extension-module/dummy/messages/DummyResponseMessage.ts index 421243d516..560183d95c 100644 --- a/samples/extension-module/dummy/messages/DummyResponseMessage.ts +++ b/samples/extension-module/dummy/messages/DummyResponseMessage.ts @@ -19,5 +19,5 @@ export class DummyResponseMessage extends AgentMessage { @IsValidMessageType(DummyResponseMessage.type) public readonly type = DummyResponseMessage.type.messageTypeUri - public static readonly type = parseMessageType('https://2060.io/didcomm/dummy/1.0/response') + public static readonly type = parseMessageType('https://didcomm.org/dummy/1.0/response') } From 616b908a8e6788657f79dce3830dd498e14e7109 Mon Sep 17 00:00:00 2001 From: Ariel Gentile Date: Sun, 19 Feb 2023 13:27:16 -0300 Subject: [PATCH 4/7] feat(wallet)!: createKey from private key (#1301) Signed-off-by: Ariel Gentile --- packages/askar/src/wallet/AskarWallet.ts | 20 +++++--- .../src/wallet/__tests__/AskarWallet.test.ts | 47 ++++++++++++++----- .../src/Bls12381g2SigningProvider.ts | 9 ++-- .../tests/bbs-signatures.e2e.test.ts | 9 +++- .../tests/bbs-signing-provider.e2e.test.ts | 2 +- ...proof.credentials.propose-offerBbs.test.ts | 6 ++- .../src/crypto/__tests__/JwsService.test.ts | 12 +++-- .../signing-provider/SigningProvider.ts | 3 +- .../signature/SignatureDecoratorUtils.test.ts | 5 +- ...ldproof.connectionless-credentials.test.ts | 5 +- ...v2.ldproof.credentials-auto-accept.test.ts | 7 +-- ...f.credentials.propose-offerED25519.test.ts | 5 +- .../dids/__tests__/dids-registrar.e2e.test.ts | 22 +++++---- .../modules/dids/__tests__/peer-did.test.ts | 9 ++-- .../dids/methods/key/KeyDidRegistrar.ts | 22 +++++++-- .../key/__tests__/KeyDidRegistrar.test.ts | 19 ++++---- .../dids/methods/peer/PeerDidRegistrar.ts | 22 +++++++-- .../peer/__tests__/PeerDidRegistrar.test.ts | 17 +++---- .../methods/sov/IndySdkSovDidRegistrar.ts | 13 ++--- .../__tests__/IndySdkSovDidRegistrar.test.ts | 25 +++++----- .../vc/__tests__/W3cCredentialService.test.ts | 8 +++- packages/core/src/wallet/IndyWallet.test.ts | 19 +++++--- packages/core/src/wallet/IndyWallet.ts | 27 ++++++++--- packages/core/src/wallet/Wallet.ts | 3 +- .../src/dids/IndySdkSovDidRegistrar.ts | 12 ++--- packages/indy-sdk/src/wallet/IndySdkWallet.ts | 26 +++++++--- .../wallet/__tests__/IndySdkWallet.test.ts | 15 ++++-- .../src/dids/IndyVdrIndyDidRegistrar.ts | 29 +++++++++--- .../tests/indy-vdr-did-registrar.e2e.test.ts | 14 +++--- .../tests/indy-vdr-did-resolver.e2e.test.ts | 3 +- .../indy-vdr/tests/indy-vdr-pool.e2e.test.ts | 4 +- .../tests/openid4vc-client.e2e.test.ts | 4 +- 32 files changed, 300 insertions(+), 143 deletions(-) diff --git a/packages/askar/src/wallet/AskarWallet.ts b/packages/askar/src/wallet/AskarWallet.ts index 38030c6ab7..baa95e5324 100644 --- a/packages/askar/src/wallet/AskarWallet.ts +++ b/packages/askar/src/wallet/AskarWallet.ts @@ -346,7 +346,8 @@ export class AskarWallet implements Wallet { * Create a key with an optional seed and keyType. * The keypair is also automatically stored in the wallet afterwards * - * @param seed string The seed for creating a key + * @param privateKey Buffer Optional privateKey for creating a key + * @param seed string Optional seed for creating a key * @param keyType KeyType the type of key that should be created * * @returns a Key instance with a publicKeyBase58 @@ -354,13 +355,21 @@ export class AskarWallet implements Wallet { * @throws {WalletError} When an unsupported keytype is requested * @throws {WalletError} When the key could not be created */ - public async createKey({ seed, keyType }: WalletCreateKeyOptions): Promise { + public async createKey({ seed, privateKey, keyType }: WalletCreateKeyOptions): Promise { try { + if (seed && privateKey) { + throw new AriesFrameworkError('Only one of seed and privateKey can be set') + } + if (keyTypeSupportedByAskar(keyType)) { const algorithm = keyAlgFromString(keyType) - // Create key from seed - const key = seed ? AskarKey.fromSeed({ seed: Buffer.from(seed), algorithm }) : AskarKey.generate(algorithm) + // Create key + const key = privateKey + ? AskarKey.fromSecretBytes({ secretKey: privateKey, algorithm }) + : seed + ? AskarKey.fromSeed({ seed, algorithm }) + : AskarKey.generate(algorithm) // Store key await this.session.insertKey({ key, name: TypedArrayEncoder.toBase58(key.publicBytes) }) @@ -370,7 +379,7 @@ export class AskarWallet implements Wallet { if (this.signingKeyProviderRegistry.hasProviderForKeyType(keyType)) { const signingKeyProvider = this.signingKeyProviderRegistry.getProviderForKeyType(keyType) - const keyPair = await signingKeyProvider.createKeyPair({ seed }) + const keyPair = await signingKeyProvider.createKeyPair({ seed, privateKey }) await this.storeKeyPair(keyPair) return Key.fromPublicKeyBase58(keyPair.publicKeyBase58, keyType) } @@ -398,7 +407,6 @@ export class AskarWallet implements Wallet { if (!TypedArrayEncoder.isTypedArray(data)) { throw new WalletError(`Currently not supporting signing of multiple messages`) } - const keyEntry = await this.session.fetchKey({ name: key.publicKeyBase58 }) if (!keyEntry) { diff --git a/packages/askar/src/wallet/__tests__/AskarWallet.test.ts b/packages/askar/src/wallet/__tests__/AskarWallet.test.ts index 94732a15b0..40dea0cbc8 100644 --- a/packages/askar/src/wallet/__tests__/AskarWallet.test.ts +++ b/packages/askar/src/wallet/__tests__/AskarWallet.test.ts @@ -36,7 +36,8 @@ const walletConfig: WalletConfig = { describe('AskarWallet basic operations', () => { let askarWallet: AskarWallet - const seed = 'sample-seed' + const seed = TypedArrayEncoder.fromString('sample-seed') + const privateKey = TypedArrayEncoder.fromString('2103de41b4ae37e8e28586d84a342b67') const message = TypedArrayEncoder.fromString('sample-message') beforeEach(async () => { @@ -62,12 +63,36 @@ describe('AskarWallet basic operations', () => { expect(nonce).toMatch(/[0-9]+/) }) - test('Create ed25519 keypair', async () => { - await expect( - askarWallet.createKey({ seed: '2103de41b4ae37e8e28586d84a342b67', keyType: KeyType.Ed25519 }) - ).resolves.toMatchObject({ + test('Create ed25519 keypair from seed', async () => { + const key = await askarWallet.createKey({ + seed, + keyType: KeyType.Ed25519, + }) + + expect(key).toMatchObject({ + keyType: KeyType.Ed25519, + }) + }) + + test('Create ed25519 keypair from private key', async () => { + const key = await askarWallet.createKey({ + privateKey, keyType: KeyType.Ed25519, }) + + expect(key).toMatchObject({ + keyType: KeyType.Ed25519, + }) + }) + + test('Attempt to create ed25519 keypair from both seed and private key', async () => { + await expect( + askarWallet.createKey({ + privateKey, + seed, + keyType: KeyType.Ed25519, + }) + ).rejects.toThrowError() }) test('Create x25519 keypair', async () => { @@ -109,7 +134,7 @@ describe.skip('Currently, all KeyTypes are supported by Askar natively', () => { describe('AskarWallet with custom signing provider', () => { let askarWallet: AskarWallet - const seed = 'sample-seed' + const seed = TypedArrayEncoder.fromString('sample-seed') const message = TypedArrayEncoder.fromString('sample-message') class DummySigningProvider implements SigningProvider { @@ -117,7 +142,7 @@ describe.skip('Currently, all KeyTypes are supported by Askar natively', () => { public async createKeyPair(options: CreateKeyPairOptions): Promise { return { - publicKeyBase58: encodeToBase58(Buffer.from(options.seed || 'publicKeyBase58')), + publicKeyBase58: encodeToBase58(Buffer.from(options.seed || TypedArrayEncoder.fromString('publicKeyBase58'))), privateKeyBase58: 'privateKeyBase58', keyType: KeyType.Bls12381g1g2, } @@ -175,11 +200,11 @@ describe.skip('Currently, all KeyTypes are supported by Askar natively', () => { }) test('Attempt to create the same custom keypair twice', async () => { - await askarWallet.createKey({ seed: 'keybase58', keyType: KeyType.Bls12381g1g2 }) + await askarWallet.createKey({ seed: TypedArrayEncoder.fromString('keybase58'), keyType: KeyType.Bls12381g1g2 }) - await expect(askarWallet.createKey({ seed: 'keybase58', keyType: KeyType.Bls12381g1g2 })).rejects.toThrow( - WalletError - ) + await expect( + askarWallet.createKey({ seed: TypedArrayEncoder.fromString('keybase58'), keyType: KeyType.Bls12381g1g2 }) + ).rejects.toThrow(WalletError) }) }) }) diff --git a/packages/bbs-signatures/src/Bls12381g2SigningProvider.ts b/packages/bbs-signatures/src/Bls12381g2SigningProvider.ts index fd7c1de9cf..b74730af47 100644 --- a/packages/bbs-signatures/src/Bls12381g2SigningProvider.ts +++ b/packages/bbs-signatures/src/Bls12381g2SigningProvider.ts @@ -15,11 +15,12 @@ export class Bls12381g2SigningProvider implements SigningProvider { * * @throws {SigningProviderError} When a key could not be created */ - public async createKeyPair({ seed }: CreateKeyPairOptions): Promise { - // Generate bytes from the seed as required by the bbs-signatures libraries - const seedBytes = seed ? TypedArrayEncoder.fromString(seed) : undefined + public async createKeyPair({ seed, privateKey }: CreateKeyPairOptions): Promise { + if (privateKey) { + throw new SigningProviderError('Cannot create keypair from private key') + } - const blsKeyPair = await generateBls12381G2KeyPair(seedBytes) + const blsKeyPair = await generateBls12381G2KeyPair(seed) return { keyType: KeyType.Bls12381g2, diff --git a/packages/bbs-signatures/tests/bbs-signatures.e2e.test.ts b/packages/bbs-signatures/tests/bbs-signatures.e2e.test.ts index 936dfbe22e..efbc08027a 100644 --- a/packages/bbs-signatures/tests/bbs-signatures.e2e.test.ts +++ b/packages/bbs-signatures/tests/bbs-signatures.e2e.test.ts @@ -19,6 +19,7 @@ import { W3cVerifiablePresentation, IndyWallet, Ed25519Signature2018, + TypedArrayEncoder, } from '@aries-framework/core' import { SignatureSuiteRegistry } from '../../core/src/modules/vc/SignatureSuiteRegistry' @@ -62,7 +63,8 @@ describeSkipNode17And18('BBS W3cCredentialService', () => { let wallet: IndyWallet let agentContext: AgentContext let w3cCredentialService: W3cCredentialService - const seed = 'testseed000000000000000000000001' + const seed = TypedArrayEncoder.fromString('testseed000000000000000000000001') + const privateKey = TypedArrayEncoder.fromString('testseed000000000000000000000001') beforeAll(async () => { wallet = new IndyWallet(agentConfig.agentDependencies, agentConfig.logger, signingProviderRegistry) @@ -219,7 +221,10 @@ describeSkipNode17And18('BBS W3cCredentialService', () => { describe('signPresentation', () => { it('should sign the presentation successfully', async () => { - const signingKey = await wallet.createKey({ seed, keyType: KeyType.Ed25519 }) + const signingKey = await wallet.createKey({ + privateKey, + keyType: KeyType.Ed25519, + }) const signingDidKey = new DidKey(signingKey) const verificationMethod = `${signingDidKey.did}#${signingDidKey.key.fingerprint}` const presentation = JsonTransformer.fromJSON(BbsBlsSignature2020Fixtures.TEST_VP_DOCUMENT, W3cPresentation) diff --git a/packages/bbs-signatures/tests/bbs-signing-provider.e2e.test.ts b/packages/bbs-signatures/tests/bbs-signing-provider.e2e.test.ts index db67e0c5a1..d428dd65be 100644 --- a/packages/bbs-signatures/tests/bbs-signing-provider.e2e.test.ts +++ b/packages/bbs-signatures/tests/bbs-signing-provider.e2e.test.ts @@ -26,7 +26,7 @@ const walletConfig: WalletConfig = { describeSkipNode17And18('BBS Signing Provider', () => { let indyWallet: IndyWallet - const seed = 'sample-seed' + const seed = TypedArrayEncoder.fromString('sample-seed') const message = TypedArrayEncoder.fromString('sample-message') beforeEach(async () => { diff --git a/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts b/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts index a22408ce87..b445f0f24b 100644 --- a/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts +++ b/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts @@ -3,6 +3,8 @@ import type { JsonCredential, JsonLdCredentialDetailFormat } from '../../core/sr import type { Wallet } from '../../core/src/wallet' import type { CredentialTestsAgent } from '../../core/tests/helpers' +import { TypedArrayEncoder } from '@aries-framework/core' + import { InjectionSymbols } from '../../core/src/constants' import { KeyType } from '../../core/src/crypto' import { CredentialState } from '../../core/src/modules/credentials/models' @@ -29,14 +31,14 @@ describeSkipNode17And18('credentials, BBS+ signature', () => { let issuerDidKey: DidKey let didCommMessageRepository: DidCommMessageRepository let signCredentialOptions: JsonLdCredentialDetailFormat - const seed = 'testseed000000000000000000000001' + const seed = TypedArrayEncoder.fromString('testseed000000000000000000000001') beforeAll(async () => { ;({ faberAgent, aliceAgent, aliceConnection } = await setupCredentialTests( 'Faber Agent Credentials LD BBS+', 'Alice Agent Credentials LD BBS+' )) wallet = faberAgent.dependencyManager.resolve(InjectionSymbols.Wallet) - await wallet.createKey({ keyType: KeyType.Ed25519, seed }) + await wallet.createKey({ keyType: KeyType.Ed25519, privateKey: seed }) const key = await wallet.createKey({ keyType: KeyType.Bls12381g2, seed }) issuerDidKey = new DidKey(key) diff --git a/packages/core/src/crypto/__tests__/JwsService.test.ts b/packages/core/src/crypto/__tests__/JwsService.test.ts index 6b5d5fb258..4080ab2f24 100644 --- a/packages/core/src/crypto/__tests__/JwsService.test.ts +++ b/packages/core/src/crypto/__tests__/JwsService.test.ts @@ -3,7 +3,7 @@ import type { Key, Wallet } from '@aries-framework/core' import { getAgentConfig, getAgentContext } from '../../../tests/helpers' import { DidKey } from '../../modules/dids' -import { Buffer, JsonEncoder } from '../../utils' +import { Buffer, JsonEncoder, TypedArrayEncoder } from '../../utils' import { IndyWallet } from '../../wallet/IndyWallet' import { JwsService } from '../JwsService' import { KeyType } from '../KeyType' @@ -28,8 +28,14 @@ describe('JwsService', () => { await wallet.createAndOpen(config.walletConfig!) jwsService = new JwsService() - didJwsz6MkfKey = await wallet.createKey({ seed: didJwsz6Mkf.SEED, keyType: KeyType.Ed25519 }) - didJwsz6MkvKey = await wallet.createKey({ seed: didJwsz6Mkv.SEED, keyType: KeyType.Ed25519 }) + didJwsz6MkfKey = await wallet.createKey({ + privateKey: TypedArrayEncoder.fromString(didJwsz6Mkf.SEED), + keyType: KeyType.Ed25519, + }) + didJwsz6MkvKey = await wallet.createKey({ + privateKey: TypedArrayEncoder.fromString(didJwsz6Mkv.SEED), + keyType: KeyType.Ed25519, + }) }) afterAll(async () => { diff --git a/packages/core/src/crypto/signing-provider/SigningProvider.ts b/packages/core/src/crypto/signing-provider/SigningProvider.ts index 2f2c31e701..3e70d67694 100644 --- a/packages/core/src/crypto/signing-provider/SigningProvider.ts +++ b/packages/core/src/crypto/signing-provider/SigningProvider.ts @@ -20,7 +20,8 @@ export interface VerifyOptions { } export interface CreateKeyPairOptions { - seed?: string + seed?: Buffer + privateKey?: Buffer } export interface SigningProvider { diff --git a/packages/core/src/decorators/signature/SignatureDecoratorUtils.test.ts b/packages/core/src/decorators/signature/SignatureDecoratorUtils.test.ts index 894520edaf..5336162c59 100644 --- a/packages/core/src/decorators/signature/SignatureDecoratorUtils.test.ts +++ b/packages/core/src/decorators/signature/SignatureDecoratorUtils.test.ts @@ -1,6 +1,7 @@ import { getAgentConfig } from '../../../tests/helpers' import { KeyType } from '../../crypto' import { SigningProviderRegistry } from '../../crypto/signing-provider' +import { TypedArrayEncoder } from '../../utils' import { IndyWallet } from '../../wallet/IndyWallet' import { SignatureDecorator } from './SignatureDecorator' @@ -53,8 +54,8 @@ describe('Decorators | Signature | SignatureDecoratorUtils', () => { }) test('signData signs json object and returns SignatureDecorator', async () => { - const seed1 = '00000000000000000000000000000My1' - const key = await wallet.createKey({ seed: seed1, keyType: KeyType.Ed25519 }) + const privateKey = TypedArrayEncoder.fromString('00000000000000000000000000000My1') + const key = await wallet.createKey({ privateKey, keyType: KeyType.Ed25519 }) const result = await signData(data, wallet, key.publicKeyBase58) diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.connectionless-credentials.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.connectionless-credentials.test.ts index 2e40d6234f..ea148db552 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.connectionless-credentials.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.connectionless-credentials.test.ts @@ -13,6 +13,7 @@ import testLogger from '../../../../../../tests/logger' import { Agent } from '../../../../../agent/Agent' import { InjectionSymbols } from '../../../../../constants' import { KeyType } from '../../../../../crypto' +import { TypedArrayEncoder } from '../../../../../utils' import { JsonEncoder } from '../../../../../utils/JsonEncoder' import { W3cVcModule } from '../../../../vc' import { customDocumentLoader } from '../../../../vc/__tests__/documentLoader' @@ -62,7 +63,7 @@ describe('credentials', () => { let aliceAgent: Agent<(typeof aliceAgentOptions)['modules']> let faberReplay: ReplaySubject let aliceReplay: ReplaySubject - const seed = 'testseed000000000000000000000001' + const privateKey = TypedArrayEncoder.fromString('testseed000000000000000000000001') const TEST_LD_DOCUMENT: JsonCredential = { '@context': [CREDENTIALS_CONTEXT_V1_URL, 'https://www.w3.org/2018/credentials/examples/v1'], type: ['VerifiableCredential', 'UniversityDegreeCredential'], @@ -106,7 +107,7 @@ describe('credentials', () => { .subscribe(aliceReplay) wallet = faberAgent.dependencyManager.resolve(InjectionSymbols.Wallet) - await wallet.createKey({ seed, keyType: KeyType.Ed25519 }) + await wallet.createKey({ privateKey, keyType: KeyType.Ed25519 }) signCredentialOptions = { credential: TEST_LD_DOCUMENT, diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials-auto-accept.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials-auto-accept.test.ts index ad08852a17..d8a3521a27 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials-auto-accept.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials-auto-accept.test.ts @@ -8,6 +8,7 @@ import testLogger from '../../../../../../tests/logger' import { InjectionSymbols } from '../../../../../constants' import { KeyType } from '../../../../../crypto' import { AriesFrameworkError } from '../../../../../error/AriesFrameworkError' +import { TypedArrayEncoder } from '../../../../../utils' import { CREDENTIALS_CONTEXT_V1_URL } from '../../../../vc/constants' import { AutoAcceptCredential, CredentialState } from '../../../models' import { CredentialExchangeRecord } from '../../../repository/CredentialExchangeRecord' @@ -33,7 +34,7 @@ describe('credentials', () => { let aliceCredentialRecord: CredentialExchangeRecord let signCredentialOptions: JsonLdCredentialDetailFormat let wallet - const seed = 'testseed000000000000000000000001' + const privateKey = TypedArrayEncoder.fromString('testseed000000000000000000000001') describe('Auto accept on `always`', () => { beforeAll(async () => { @@ -44,7 +45,7 @@ describe('credentials', () => { )) wallet = faberAgent.dependencyManager.resolve(InjectionSymbols.Wallet) - await wallet.createKey({ seed, keyType: KeyType.Ed25519 }) + await wallet.createKey({ privateKey, keyType: KeyType.Ed25519 }) signCredentialOptions = { credential: TEST_LD_DOCUMENT, options: { @@ -143,7 +144,7 @@ describe('credentials', () => { AutoAcceptCredential.ContentApproved )) wallet = faberAgent.dependencyManager.resolve(InjectionSymbols.Wallet) - await wallet.createKey({ seed, keyType: KeyType.Ed25519 }) + await wallet.createKey({ privateKey, keyType: KeyType.Ed25519 }) signCredentialOptions = { credential: TEST_LD_DOCUMENT, options: { diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts index c8f9a64d20..98621d7a40 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts @@ -8,6 +8,7 @@ import testLogger from '../../../../../../tests/logger' import { InjectionSymbols } from '../../../../../constants' import { KeyType } from '../../../../../crypto' import { DidCommMessageRepository } from '../../../../../storage' +import { TypedArrayEncoder } from '../../../../../utils' import { JsonTransformer } from '../../../../../utils/JsonTransformer' import { CredentialState } from '../../../models' import { CredentialExchangeRecord } from '../../../repository/CredentialExchangeRecord' @@ -57,7 +58,7 @@ describe('credentials', () => { let signCredentialOptions: JsonLdCredentialDetailFormat let wallet - const seed = 'testseed000000000000000000000001' + const privateKey = TypedArrayEncoder.fromString('testseed000000000000000000000001') let credDefId: string beforeAll(async () => { @@ -66,7 +67,7 @@ describe('credentials', () => { 'Alice Agent Credentials LD' )) wallet = faberAgent.dependencyManager.resolve(InjectionSymbols.Wallet) - await wallet.createKey({ seed, keyType: KeyType.Ed25519 }) + await wallet.createKey({ privateKey, keyType: KeyType.Ed25519 }) signCredentialOptions = { credential: inputDocAsJson, options: { diff --git a/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts b/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts index 9599d06c92..ccd60edf71 100644 --- a/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts +++ b/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts @@ -47,7 +47,7 @@ describe('dids', () => { keyType: KeyType.Ed25519, }, secret: { - seed: '96213c3d7fc8d4d6754c7a0fd969598e', + privateKey: TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c7a0fd969598e'), }, }) @@ -97,7 +97,7 @@ describe('dids', () => { ], id: 'did:key:z6MkpGR4gs4Rc3Zph4vj8wRnjnAxgAPSxcR8MAVKutWspQzc', }, - secret: { seed: '96213c3d7fc8d4d6754c7a0fd969598e' }, + secret: { privateKey: '96213c3d7fc8d4d6754c7a0fd969598e' }, }, }) }) @@ -110,7 +110,7 @@ describe('dids', () => { numAlgo: PeerDidNumAlgo.InceptionKeyWithoutDoc, }, secret: { - seed: 'e008ef10b7c163114b3857542b3736eb', + privateKey: TypedArrayEncoder.fromString('e008ef10b7c163114b3857542b3736eb'), }, }) @@ -160,7 +160,7 @@ describe('dids', () => { ], id: 'did:peer:0z6Mkuo91yRhTWDrFkdNBcLXAbvtUiq2J9E4QQcfYZt4hevkh', }, - secret: { seed: 'e008ef10b7c163114b3857542b3736eb' }, + secret: { privateKey: 'e008ef10b7c163114b3857542b3736eb' }, }, }) }) @@ -168,11 +168,13 @@ describe('dids', () => { it('should create a did:sov did', async () => { // Generate a seed and the indy did. This allows us to create a new did every time // but still check if the created output document is as expected. - const seed = Array(32 + 1) - .join((Math.random().toString(36) + '00000000000000000').slice(2, 18)) - .slice(0, 32) + const privateKey = TypedArrayEncoder.fromString( + Array(32 + 1) + .join((Math.random().toString(36) + '00000000000000000').slice(2, 18)) + .slice(0, 32) + ) - const publicKeyEd25519 = generateKeyPairFromSeed(TypedArrayEncoder.fromString(seed)).publicKey + const publicKeyEd25519 = generateKeyPairFromSeed(privateKey).publicKey const x25519PublicKeyBase58 = TypedArrayEncoder.toBase58(convertPublicKeyToX25519(publicKeyEd25519)) const ed25519PublicKeyBase58 = TypedArrayEncoder.toBase58(publicKeyEd25519) const indyDid = indyDidFromPublicKeyBase58(ed25519PublicKeyBase58) @@ -193,7 +195,7 @@ describe('dids', () => { }, }, secret: { - seed, + privateKey, }, }) @@ -261,7 +263,7 @@ describe('dids', () => { id: `did:sov:${indyDid}`, }, secret: { - seed, + privateKey: privateKey.toString(), }, }, }) diff --git a/packages/core/src/modules/dids/__tests__/peer-did.test.ts b/packages/core/src/modules/dids/__tests__/peer-did.test.ts index 5467b601c9..c352fc0383 100644 --- a/packages/core/src/modules/dids/__tests__/peer-did.test.ts +++ b/packages/core/src/modules/dids/__tests__/peer-did.test.ts @@ -8,7 +8,7 @@ import { InjectionSymbols } from '../../../constants' import { Key, KeyType } from '../../../crypto' import { SigningProviderRegistry } from '../../../crypto/signing-provider' import { IndyStorageService } from '../../../storage/IndyStorageService' -import { JsonTransformer } from '../../../utils' +import { JsonTransformer, TypedArrayEncoder } from '../../../utils' import { IndyWallet } from '../../../wallet/IndyWallet' import { DidsModuleConfig } from '../DidsModuleConfig' import { DidCommV1Service, DidDocument, DidDocumentBuilder } from '../domain' @@ -62,9 +62,12 @@ describe('peer dids', () => { test('create a peer did method 1 document from ed25519 keys with a service', async () => { // The following scenario show how we could create a key and create a did document from it for DID Exchange - const ed25519Key = await wallet.createKey({ seed: 'astringoftotalin32characterslong', keyType: KeyType.Ed25519 }) + const ed25519Key = await wallet.createKey({ + privateKey: TypedArrayEncoder.fromString('astringoftotalin32characterslong'), + keyType: KeyType.Ed25519, + }) const mediatorEd25519Key = await wallet.createKey({ - seed: 'anotherstringof32characterslong1', + privateKey: TypedArrayEncoder.fromString('anotherstringof32characterslong1'), keyType: KeyType.Ed25519, }) diff --git a/packages/core/src/modules/dids/methods/key/KeyDidRegistrar.ts b/packages/core/src/modules/dids/methods/key/KeyDidRegistrar.ts index 6a4def3cd2..645deee3a1 100644 --- a/packages/core/src/modules/dids/methods/key/KeyDidRegistrar.ts +++ b/packages/core/src/modules/dids/methods/key/KeyDidRegistrar.ts @@ -1,5 +1,6 @@ import type { AgentContext } from '../../../../agent' import type { KeyType } from '../../../../crypto' +import type { Buffer } from '../../../../utils' import type { DidRegistrar } from '../../domain/DidRegistrar' import type { DidCreateOptions, DidCreateResult, DidDeactivateResult, DidUpdateResult } from '../../types' @@ -16,6 +17,7 @@ export class KeyDidRegistrar implements DidRegistrar { const keyType = options.options.keyType const seed = options.secret?.seed + const privateKey = options.secret?.privateKey if (!keyType) { return { @@ -28,7 +30,7 @@ export class KeyDidRegistrar implements DidRegistrar { } } - if (seed && (typeof seed !== 'string' || seed.length !== 32)) { + if (seed && (typeof seed !== 'object' || seed.length !== 32)) { return { didDocumentMetadata: {}, didRegistrationMetadata: {}, @@ -39,10 +41,22 @@ export class KeyDidRegistrar implements DidRegistrar { } } + if (privateKey && (typeof privateKey !== 'object' || privateKey.length !== 32)) { + return { + didDocumentMetadata: {}, + didRegistrationMetadata: {}, + didState: { + state: 'failed', + reason: 'Invalid private key provided', + }, + } + } + try { const key = await agentContext.wallet.createKey({ keyType, seed, + privateKey, }) const didKey = new DidKey(key) @@ -67,7 +81,8 @@ export class KeyDidRegistrar implements DidRegistrar { // we can only return it if the seed was passed in by the user. Once // we have a secure method for generating seeds we should use the same // approach - seed: options.secret?.seed, + seed: options.secret?.seed?.toString(), + privateKey: options.secret?.privateKey?.toString(), }, }, } @@ -115,7 +130,8 @@ export interface KeyDidCreateOptions extends DidCreateOptions { keyType: KeyType } secret?: { - seed?: string + seed?: Buffer + privateKey?: Buffer } } diff --git a/packages/core/src/modules/dids/methods/key/__tests__/KeyDidRegistrar.test.ts b/packages/core/src/modules/dids/methods/key/__tests__/KeyDidRegistrar.test.ts index e859dcf795..9f084a5b8d 100644 --- a/packages/core/src/modules/dids/methods/key/__tests__/KeyDidRegistrar.test.ts +++ b/packages/core/src/modules/dids/methods/key/__tests__/KeyDidRegistrar.test.ts @@ -3,6 +3,7 @@ import type { Wallet } from '../../../../../wallet' import { getAgentContext, mockFunction } from '../../../../../../tests/helpers' import { KeyType } from '../../../../../crypto' import { Key } from '../../../../../crypto/Key' +import { TypedArrayEncoder } from '../../../../../utils' import { JsonTransformer } from '../../../../../utils/JsonTransformer' import { DidDocumentRole } from '../../../domain/DidDocumentRole' import { DidRepository } from '../../../repository/DidRepository' @@ -32,7 +33,7 @@ describe('DidRegistrar', () => { describe('KeyDidRegistrar', () => { it('should correctly create a did:key document using Ed25519 key type', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') const result = await keyDidRegistrar.create(agentContext, { method: 'key', @@ -40,7 +41,7 @@ describe('DidRegistrar', () => { keyType: KeyType.Ed25519, }, secret: { - seed, + privateKey, }, }) @@ -52,12 +53,12 @@ describe('DidRegistrar', () => { did: 'did:key:z6MksLeew51QS6Ca6tVKM56LQNbxCNVcLHv4xXj4jMkAhPWU', didDocument: didKeyz6MksLeFixture, secret: { - seed: '96213c3d7fc8d4d6754c712fd969598e', + privateKey: '96213c3d7fc8d4d6754c712fd969598e', }, }, }) - expect(walletMock.createKey).toHaveBeenCalledWith({ keyType: KeyType.Ed25519, seed }) + expect(walletMock.createKey).toHaveBeenCalledWith({ keyType: KeyType.Ed25519, privateKey }) }) it('should return an error state if no key type is provided', async () => { @@ -77,7 +78,7 @@ describe('DidRegistrar', () => { }) }) - it('should return an error state if an invalid seed is provided', async () => { + it('should return an error state if an invalid private key is provided', async () => { const result = await keyDidRegistrar.create(agentContext, { method: 'key', @@ -85,7 +86,7 @@ describe('DidRegistrar', () => { keyType: KeyType.Ed25519, }, secret: { - seed: 'invalid', + privateKey: TypedArrayEncoder.fromString('invalid'), }, }) @@ -94,13 +95,13 @@ describe('DidRegistrar', () => { didRegistrationMetadata: {}, didState: { state: 'failed', - reason: 'Invalid seed provided', + reason: 'Invalid private key provided', }, }) }) it('should store the did document', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') const did = 'did:key:z6MksLeew51QS6Ca6tVKM56LQNbxCNVcLHv4xXj4jMkAhPWU' await keyDidRegistrar.create(agentContext, { @@ -110,7 +111,7 @@ describe('DidRegistrar', () => { keyType: KeyType.Ed25519, }, secret: { - seed, + privateKey, }, }) diff --git a/packages/core/src/modules/dids/methods/peer/PeerDidRegistrar.ts b/packages/core/src/modules/dids/methods/peer/PeerDidRegistrar.ts index 057ed96c9d..83b171e978 100644 --- a/packages/core/src/modules/dids/methods/peer/PeerDidRegistrar.ts +++ b/packages/core/src/modules/dids/methods/peer/PeerDidRegistrar.ts @@ -1,5 +1,6 @@ import type { AgentContext } from '../../../../agent' import type { KeyType } from '../../../../crypto' +import type { Buffer } from '../../../../utils' import type { DidRegistrar } from '../../domain/DidRegistrar' import type { DidCreateOptions, DidCreateResult, DidDeactivateResult, DidUpdateResult } from '../../types' @@ -27,6 +28,7 @@ export class PeerDidRegistrar implements DidRegistrar { if (isPeerDidNumAlgo0CreateOptions(options)) { const keyType = options.options.keyType const seed = options.secret?.seed + const privateKey = options.secret?.privateKey if (!keyType) { return { @@ -39,7 +41,7 @@ export class PeerDidRegistrar implements DidRegistrar { } } - if (seed && (typeof seed !== 'string' || seed.length !== 32)) { + if (seed && (typeof seed !== 'object' || seed.length !== 32)) { return { didDocumentMetadata: {}, didRegistrationMetadata: {}, @@ -50,9 +52,21 @@ export class PeerDidRegistrar implements DidRegistrar { } } + if (privateKey && (typeof privateKey !== 'object' || privateKey.length !== 32)) { + return { + didDocumentMetadata: {}, + didRegistrationMetadata: {}, + didState: { + state: 'failed', + reason: 'Invalid private key provided', + }, + } + } + const key = await agentContext.wallet.createKey({ keyType, seed, + privateKey, }) // TODO: validate did:peer document @@ -105,7 +119,8 @@ export class PeerDidRegistrar implements DidRegistrar { // we can only return it if the seed was passed in by the user. Once // we have a secure method for generating seeds we should use the same // approach - seed: options.secret?.seed, + seed: options.secret?.seed?.toString(), + privateKey: options.secret?.privateKey?.toString(), }, }, } @@ -170,7 +185,8 @@ export interface PeerDidNumAlgo0CreateOptions extends DidCreateOptions { numAlgo: PeerDidNumAlgo.InceptionKeyWithoutDoc } secret?: { - seed?: string + seed?: Buffer + privateKey?: Buffer } } diff --git a/packages/core/src/modules/dids/methods/peer/__tests__/PeerDidRegistrar.test.ts b/packages/core/src/modules/dids/methods/peer/__tests__/PeerDidRegistrar.test.ts index f20079cd4f..b974cff303 100644 --- a/packages/core/src/modules/dids/methods/peer/__tests__/PeerDidRegistrar.test.ts +++ b/packages/core/src/modules/dids/methods/peer/__tests__/PeerDidRegistrar.test.ts @@ -3,6 +3,7 @@ import type { Wallet } from '../../../../../wallet' import { getAgentContext, mockFunction } from '../../../../../../tests/helpers' import { KeyType } from '../../../../../crypto' import { Key } from '../../../../../crypto/Key' +import { TypedArrayEncoder } from '../../../../../utils' import { JsonTransformer } from '../../../../../utils/JsonTransformer' import { DidCommV1Service, DidDocumentBuilder } from '../../../domain' import { DidDocumentRole } from '../../../domain/DidDocumentRole' @@ -32,7 +33,7 @@ describe('DidRegistrar', () => { describe('PeerDidRegistrar', () => { describe('did:peer:0', () => { it('should correctly create a did:peer:0 document using Ed25519 key type', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') const result = await peerDidRegistrar.create(agentContext, { method: 'peer', @@ -41,7 +42,7 @@ describe('DidRegistrar', () => { numAlgo: PeerDidNumAlgo.InceptionKeyWithoutDoc, }, secret: { - seed, + privateKey, }, }) @@ -53,7 +54,7 @@ describe('DidRegistrar', () => { did: 'did:peer:0z6MksLeew51QS6Ca6tVKM56LQNbxCNVcLHv4xXj4jMkAhPWU', didDocument: didPeer0z6MksLeFixture, secret: { - seed: '96213c3d7fc8d4d6754c712fd969598e', + privateKey: '96213c3d7fc8d4d6754c712fd969598e', }, }, }) @@ -78,7 +79,7 @@ describe('DidRegistrar', () => { }) }) - it('should return an error state if an invalid seed is provided', async () => { + it('should return an error state if an invalid private key is provided', async () => { const result = await peerDidRegistrar.create(agentContext, { method: 'peer', options: { @@ -86,7 +87,7 @@ describe('DidRegistrar', () => { numAlgo: PeerDidNumAlgo.InceptionKeyWithoutDoc, }, secret: { - seed: 'invalid', + privateKey: TypedArrayEncoder.fromString('invalid'), }, }) @@ -95,13 +96,13 @@ describe('DidRegistrar', () => { didRegistrationMetadata: {}, didState: { state: 'failed', - reason: 'Invalid seed provided', + reason: 'Invalid private key provided', }, }) }) it('should store the did without the did document', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') const did = 'did:peer:0z6MksLeew51QS6Ca6tVKM56LQNbxCNVcLHv4xXj4jMkAhPWU' await peerDidRegistrar.create(agentContext, { @@ -111,7 +112,7 @@ describe('DidRegistrar', () => { numAlgo: PeerDidNumAlgo.InceptionKeyWithoutDoc, }, secret: { - seed, + privateKey, }, }) diff --git a/packages/core/src/modules/dids/methods/sov/IndySdkSovDidRegistrar.ts b/packages/core/src/modules/dids/methods/sov/IndySdkSovDidRegistrar.ts index 763f97b622..21781642ab 100644 --- a/packages/core/src/modules/dids/methods/sov/IndySdkSovDidRegistrar.ts +++ b/packages/core/src/modules/dids/methods/sov/IndySdkSovDidRegistrar.ts @@ -1,4 +1,5 @@ import type { AgentContext } from '../../../../agent' +import type { Buffer } from '../../../../utils' import type { IndyEndpointAttrib, IndyPool } from '../../../ledger' import type { DidRegistrar } from '../../domain/DidRegistrar' import type { DidCreateOptions, DidCreateResult, DidDeactivateResult, DidUpdateResult } from '../../types' @@ -24,15 +25,15 @@ export class IndySdkSovDidRegistrar implements DidRegistrar { const didRepository = agentContext.dependencyManager.resolve(DidRepository) const { alias, role, submitterDid, indyNamespace } = options.options - const seed = options.secret?.seed + const privateKey = options.secret?.privateKey - if (seed && (typeof seed !== 'string' || seed.length !== 32)) { + if (privateKey && (typeof privateKey !== 'object' || privateKey.length !== 32)) { return { didDocumentMetadata: {}, didRegistrationMetadata: {}, didState: { state: 'failed', - reason: 'Invalid seed provided', + reason: 'Invalid private key provided', }, } } @@ -56,7 +57,7 @@ export class IndySdkSovDidRegistrar implements DidRegistrar { // FIXME: once askar/indy-vdr is supported we need to adjust this to work with both indy-sdk and askar assertIndyWallet(agentContext.wallet) const [unqualifiedIndyDid, verkey] = await indy.createAndStoreMyDid(agentContext.wallet.handle, { - seed, + seed: privateKey?.toString(), }) const qualifiedSovDid = `did:sov:${unqualifiedIndyDid}` @@ -115,7 +116,7 @@ export class IndySdkSovDidRegistrar implements DidRegistrar { // we can only return it if the seed was passed in by the user. Once // we have a secure method for generating seeds we should use the same // approach - seed: options.secret?.seed, + privateKey: options.secret?.privateKey?.toString(), }, }, } @@ -237,7 +238,7 @@ export interface SovDidCreateOptions extends DidCreateOptions { submitterDid: string } secret?: { - seed?: string + privateKey?: Buffer } } diff --git a/packages/core/src/modules/dids/methods/sov/__tests__/IndySdkSovDidRegistrar.test.ts b/packages/core/src/modules/dids/methods/sov/__tests__/IndySdkSovDidRegistrar.test.ts index 761a2956b6..7837772932 100644 --- a/packages/core/src/modules/dids/methods/sov/__tests__/IndySdkSovDidRegistrar.test.ts +++ b/packages/core/src/modules/dids/methods/sov/__tests__/IndySdkSovDidRegistrar.test.ts @@ -5,6 +5,7 @@ import type * as Indy from 'indy-sdk' import { getAgentConfig, getAgentContext, mockFunction, mockProperty } from '../../../../../../tests/helpers' import { SigningProviderRegistry } from '../../../../../crypto/signing-provider' +import { TypedArrayEncoder } from '../../../../../utils' import { JsonTransformer } from '../../../../../utils/JsonTransformer' import { IndyWallet } from '../../../../../wallet/IndyWallet' import { IndyPoolService } from '../../../../ledger/services/IndyPoolService' @@ -52,7 +53,7 @@ describe('DidRegistrar', () => { jest.clearAllMocks() }) - it('should return an error state if an invalid seed is provided', async () => { + it('should return an error state if an invalid private key is provided', async () => { const result = await indySdkSovDidRegistrar.create(agentContext, { method: 'sov', @@ -61,7 +62,7 @@ describe('DidRegistrar', () => { alias: 'Hello', }, secret: { - seed: 'invalid', + privateKey: TypedArrayEncoder.fromString('invalid'), }, }) @@ -70,7 +71,7 @@ describe('DidRegistrar', () => { didRegistrationMetadata: {}, didState: { state: 'failed', - reason: 'Invalid seed provided', + reason: 'Invalid private key provided', }, }) }) @@ -89,7 +90,7 @@ describe('DidRegistrar', () => { alias: 'Hello', }, secret: { - seed: '12345678901234567890123456789012', + privateKey: TypedArrayEncoder.fromString('12345678901234567890123456789012'), }, }) @@ -123,7 +124,7 @@ describe('DidRegistrar', () => { }) it('should correctly create a did:sov document without services', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') const registerPublicDidSpy = jest.spyOn(indySdkSovDidRegistrar, 'registerPublicDid') registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve('R1xKJw17sUoXhejEpugMYJ')) @@ -136,7 +137,7 @@ describe('DidRegistrar', () => { role: 'STEWARD', }, secret: { - seed, + privateKey, }, }) @@ -191,14 +192,14 @@ describe('DidRegistrar', () => { keyAgreement: ['did:sov:R1xKJw17sUoXhejEpugMYJ#key-agreement-1'], }, secret: { - seed, + privateKey: privateKey.toString(), }, }, }) }) it('should correctly create a did:sov document with services', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') const registerPublicDidSpy = jest.spyOn(indySdkSovDidRegistrar, 'registerPublicDid') registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve('R1xKJw17sUoXhejEpugMYJ')) @@ -219,7 +220,7 @@ describe('DidRegistrar', () => { }, }, secret: { - seed, + privateKey, }, }) @@ -298,14 +299,14 @@ describe('DidRegistrar', () => { keyAgreement: ['did:sov:R1xKJw17sUoXhejEpugMYJ#key-agreement-1'], }, secret: { - seed, + privateKey: privateKey.toString(), }, }, }) }) it('should store the did document', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') const registerPublicDidSpy = jest.spyOn(indySdkSovDidRegistrar, 'registerPublicDid') registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve('did')) @@ -326,7 +327,7 @@ describe('DidRegistrar', () => { }, }, secret: { - seed, + privateKey, }, }) diff --git a/packages/core/src/modules/vc/__tests__/W3cCredentialService.test.ts b/packages/core/src/modules/vc/__tests__/W3cCredentialService.test.ts index d6f3eb266f..06e0b42245 100644 --- a/packages/core/src/modules/vc/__tests__/W3cCredentialService.test.ts +++ b/packages/core/src/modules/vc/__tests__/W3cCredentialService.test.ts @@ -3,6 +3,7 @@ import type { AgentContext } from '../../../agent' import { getAgentConfig, getAgentContext, mockFunction } from '../../../../tests/helpers' import { KeyType } from '../../../crypto' import { SigningProviderRegistry } from '../../../crypto/signing-provider' +import { TypedArrayEncoder } from '../../../utils' import { JsonTransformer } from '../../../utils/JsonTransformer' import { IndyWallet } from '../../../wallet/IndyWallet' import { WalletError } from '../../../wallet/error' @@ -67,7 +68,7 @@ describe('W3cCredentialService', () => { let agentContext: AgentContext let w3cCredentialService: W3cCredentialService let w3cCredentialRepository: W3cCredentialRepository - const seed = 'testseed000000000000000000000001' + const privateKey = TypedArrayEncoder.fromString('testseed000000000000000000000001') beforeAll(async () => { wallet = new IndyWallet(agentConfig.agentDependencies, agentConfig.logger, signingProviderRegistry) @@ -116,7 +117,10 @@ describe('W3cCredentialService', () => { let verificationMethod: string beforeAll(async () => { // TODO: update to use did registrar - const issuerKey = await wallet.createKey({ keyType: KeyType.Ed25519, seed }) + const issuerKey = await wallet.createKey({ + keyType: KeyType.Ed25519, + privateKey, + }) issuerDidKey = new DidKey(issuerKey) verificationMethod = `${issuerDidKey.did}#${issuerDidKey.key.fingerprint}` }) diff --git a/packages/core/src/wallet/IndyWallet.test.ts b/packages/core/src/wallet/IndyWallet.test.ts index 07c5e74978..8a600a2592 100644 --- a/packages/core/src/wallet/IndyWallet.test.ts +++ b/packages/core/src/wallet/IndyWallet.test.ts @@ -31,7 +31,7 @@ const walletConfigWithMasterSecretId: WalletConfig = { describe('IndyWallet', () => { let indyWallet: IndyWallet - const seed = 'sample-seed' + const privateKey = TypedArrayEncoder.fromString('sample-seed') const message = TypedArrayEncoder.fromString('sample-message') beforeEach(async () => { @@ -72,16 +72,23 @@ describe('IndyWallet', () => { await expect(indyWallet.generateNonce()).resolves.toEqual(expect.any(String)) }) - test('Create ed25519 keypair', async () => { - await expect( - indyWallet.createKey({ seed: '2103de41b4ae37e8e28586d84a342b67', keyType: KeyType.Ed25519 }) - ).resolves.toMatchObject({ + test('Create ed25519 keypair from private key', async () => { + const key = await indyWallet.createKey({ + privateKey: TypedArrayEncoder.fromString('2103de41b4ae37e8e28586d84a342b67'), keyType: KeyType.Ed25519, }) + + expect(key).toMatchObject({ + keyType: KeyType.Ed25519, + }) + }) + + test('Fail to create ed25519 keypair from seed', async () => { + await expect(indyWallet.createKey({ privateKey, keyType: KeyType.Ed25519 })).rejects.toThrowError(WalletError) }) test('Fail to create x25519 keypair', async () => { - await expect(indyWallet.createKey({ seed, keyType: KeyType.X25519 })).rejects.toThrowError(WalletError) + await expect(indyWallet.createKey({ privateKey, keyType: KeyType.X25519 })).rejects.toThrowError(WalletError) }) test('Create a signature with a ed25519 keypair', async () => { diff --git a/packages/core/src/wallet/IndyWallet.ts b/packages/core/src/wallet/IndyWallet.ts index 0bef6447d6..8c8e83d575 100644 --- a/packages/core/src/wallet/IndyWallet.ts +++ b/packages/core/src/wallet/IndyWallet.ts @@ -465,12 +465,12 @@ export class IndyWallet implements Wallet { } /** - * Create a key with an optional seed and keyType. + * Create a key with an optional private key and keyType. * The keypair is also automatically stored in the wallet afterwards * * Bls12381g1g2 and X25519 are not supported. * - * @param seed string The seed for creating a key + * @param privateKey Buffer Private key (formerly called 'seed') * @param keyType KeyType the type of key that should be created * * @returns a Key instance with a publicKeyBase58 @@ -478,13 +478,26 @@ export class IndyWallet implements Wallet { * @throws {WalletError} When an unsupported keytype is requested * @throws {WalletError} When the key could not be created */ - public async createKey({ seed, keyType }: WalletCreateKeyOptions): Promise { + public async createKey({ seed, privateKey, keyType }: WalletCreateKeyOptions): Promise { try { + if (seed && privateKey) { + throw new AriesFrameworkError('Only one of seed and privateKey can be set') + } + // Ed25519 is supported natively in Indy wallet if (keyType === KeyType.Ed25519) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore - const verkey = await this.indy.createKey(this.handle, { seed, crypto_type: 'ed25519' }) + if (seed) { + throw new AriesFrameworkError( + 'IndyWallet does not support seed. You may rather want to specify a private key for deterministic ed25519 key generation' + ) + } + + const verkey = await this.indy.createKey(this.handle, { + seed: privateKey?.toString(), + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore + crypto_type: 'ed25519', + }) return Key.fromPublicKeyBase58(verkey, keyType) } @@ -492,7 +505,7 @@ export class IndyWallet implements Wallet { if (this.signingKeyProviderRegistry.hasProviderForKeyType(keyType)) { const signingKeyProvider = this.signingKeyProviderRegistry.getProviderForKeyType(keyType) - const keyPair = await signingKeyProvider.createKeyPair({ seed }) + const keyPair = await signingKeyProvider.createKeyPair({ seed, privateKey }) await this.storeKeyPair(keyPair) return Key.fromPublicKeyBase58(keyPair.publicKeyBase58, keyType) } diff --git a/packages/core/src/wallet/Wallet.ts b/packages/core/src/wallet/Wallet.ts index 6c5cff6388..4fcf70f5c2 100644 --- a/packages/core/src/wallet/Wallet.ts +++ b/packages/core/src/wallet/Wallet.ts @@ -55,7 +55,8 @@ export interface DidInfo { export interface WalletCreateKeyOptions { keyType: KeyType - seed?: string + seed?: Buffer + privateKey?: Buffer } export interface WalletSignOptions { diff --git a/packages/indy-sdk/src/dids/IndySdkSovDidRegistrar.ts b/packages/indy-sdk/src/dids/IndySdkSovDidRegistrar.ts index 8553af9295..c043673cd1 100644 --- a/packages/indy-sdk/src/dids/IndySdkSovDidRegistrar.ts +++ b/packages/indy-sdk/src/dids/IndySdkSovDidRegistrar.ts @@ -40,15 +40,15 @@ export class IndySdkSovDidRegistrar implements DidRegistrar { public async create(agentContext: AgentContext, options: IndySdkSovDidCreateOptions): Promise { const { alias, role, submitterDid, indyNamespace } = options.options - const seed = options.secret?.seed + const privateKey = options.secret?.privateKey - if (seed && (typeof seed !== 'string' || seed.length !== 32)) { + if (privateKey && (typeof privateKey !== 'object' || privateKey.length !== 32)) { return { didDocumentMetadata: {}, didRegistrationMetadata: {}, didState: { state: 'failed', - reason: 'Invalid seed provided', + reason: 'Invalid private key provided', }, } } @@ -71,7 +71,7 @@ export class IndySdkSovDidRegistrar implements DidRegistrar { // to rely directly on the indy SDK, as we don't want to expose a createDid method just for. assertIndySdkWallet(agentContext.wallet) const [unqualifiedIndyDid, verkey] = await this.indySdk.createAndStoreMyDid(agentContext.wallet.handle, { - seed, + seed: privateKey?.toString(), }) const qualifiedSovDid = `did:sov:${unqualifiedIndyDid}` @@ -131,7 +131,7 @@ export class IndySdkSovDidRegistrar implements DidRegistrar { // we can only return it if the seed was passed in by the user. Once // we have a secure method for generating seeds we should use the same // approach - seed: options.secret?.seed, + privateKey: options.secret?.privateKey?.toString(), }, }, } @@ -256,7 +256,7 @@ export interface IndySdkSovDidCreateOptions extends DidCreateOptions { submitterDid: string } secret?: { - seed?: string + privateKey?: Buffer } } diff --git a/packages/indy-sdk/src/wallet/IndySdkWallet.ts b/packages/indy-sdk/src/wallet/IndySdkWallet.ts index 9230ed5f28..66d75e8933 100644 --- a/packages/indy-sdk/src/wallet/IndySdkWallet.ts +++ b/packages/indy-sdk/src/wallet/IndySdkWallet.ts @@ -461,12 +461,12 @@ export class IndySdkWallet implements Wallet { } /** - * Create a key with an optional seed and keyType. + * Create a key with an optional private key and keyType. * The keypair is also automatically stored in the wallet afterwards * * Bls12381g1g2 and X25519 are not supported. * - * @param seed string The seed for creating a key + * @param privateKey Buffer Private key (formerly called 'seed') * @param keyType KeyType the type of key that should be created * * @returns a Key instance with a publicKeyBase58 @@ -474,13 +474,25 @@ export class IndySdkWallet implements Wallet { * @throws {WalletError} When an unsupported keytype is requested * @throws {WalletError} When the key could not be created */ - public async createKey({ seed, keyType }: WalletCreateKeyOptions): Promise { + public async createKey({ seed, privateKey, keyType }: WalletCreateKeyOptions): Promise { try { + if (seed && privateKey) { + throw new AriesFrameworkError('Only one of seed and privateKey can be set') + } + // Ed25519 is supported natively in Indy wallet if (keyType === KeyType.Ed25519) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore - const verkey = await this.indySdk.createKey(this.handle, { seed, crypto_type: 'ed25519' }) + if (seed) { + throw new AriesFrameworkError( + 'IndySdkWallet does not support seed. You may rather want to specify a private key for deterministic ed25519 key generation' + ) + } + const verkey = await this.indySdk.createKey(this.handle, { + seed: privateKey?.toString(), + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore + crypto_type: 'ed25519', + }) return Key.fromPublicKeyBase58(verkey, keyType) } @@ -488,7 +500,7 @@ export class IndySdkWallet implements Wallet { if (this.signingKeyProviderRegistry.hasProviderForKeyType(keyType)) { const signingKeyProvider = this.signingKeyProviderRegistry.getProviderForKeyType(keyType) - const keyPair = await signingKeyProvider.createKeyPair({ seed }) + const keyPair = await signingKeyProvider.createKeyPair({ seed, privateKey }) await this.storeKeyPair(keyPair) return Key.fromPublicKeyBase58(keyPair.publicKeyBase58, keyType) } diff --git a/packages/indy-sdk/src/wallet/__tests__/IndySdkWallet.test.ts b/packages/indy-sdk/src/wallet/__tests__/IndySdkWallet.test.ts index 4b7f822f0e..1bb5447031 100644 --- a/packages/indy-sdk/src/wallet/__tests__/IndySdkWallet.test.ts +++ b/packages/indy-sdk/src/wallet/__tests__/IndySdkWallet.test.ts @@ -31,7 +31,7 @@ const walletConfigWithMasterSecretId: WalletConfig = { describe('IndySdkWallet', () => { let indySdkWallet: IndySdkWallet - const seed = 'sample-seed' + const privateKey = TypedArrayEncoder.fromString('sample-seed') const message = TypedArrayEncoder.fromString('sample-message') beforeEach(async () => { @@ -72,16 +72,23 @@ describe('IndySdkWallet', () => { await expect(indySdkWallet.generateNonce()).resolves.toEqual(expect.any(String)) }) - test('Create ed25519 keypair', async () => { + test('Create ed25519 keypair from private key', async () => { await expect( - indySdkWallet.createKey({ seed: '2103de41b4ae37e8e28586d84a342b67', keyType: KeyType.Ed25519 }) + indySdkWallet.createKey({ + privateKey: TypedArrayEncoder.fromString('2103de41b4ae37e8e28586d84a342b67'), + keyType: KeyType.Ed25519, + }) ).resolves.toMatchObject({ keyType: KeyType.Ed25519, }) }) + test('Fail to create ed25519 keypair from seed', async () => { + await expect(indySdkWallet.createKey({ privateKey, keyType: KeyType.Ed25519 })).rejects.toThrowError(WalletError) + }) + test('Fail to create x25519 keypair', async () => { - await expect(indySdkWallet.createKey({ seed, keyType: KeyType.X25519 })).rejects.toThrowError(WalletError) + await expect(indySdkWallet.createKey({ privateKey, keyType: KeyType.X25519 })).rejects.toThrowError(WalletError) }) test('Create a signature with a ed25519 keypair', async () => { diff --git a/packages/indy-vdr/src/dids/IndyVdrIndyDidRegistrar.ts b/packages/indy-vdr/src/dids/IndyVdrIndyDidRegistrar.ts index 7505c09280..cf41881cad 100644 --- a/packages/indy-vdr/src/dids/IndyVdrIndyDidRegistrar.ts +++ b/packages/indy-vdr/src/dids/IndyVdrIndyDidRegistrar.ts @@ -2,6 +2,7 @@ import type { IndyEndpointAttrib } from './didSovUtil' import type { IndyVdrPool } from '../pool' import type { AgentContext, + Buffer, DidRegistrar, DidCreateOptions, DidCreateResult, @@ -41,7 +42,20 @@ export class IndyVdrIndyDidRegistrar implements DidRegistrar { public async create(agentContext: AgentContext, options: IndyVdrDidCreateOptions): Promise { const seed = options.secret?.seed - if (seed && (typeof seed !== 'string' || seed.length !== 32)) { + const privateKey = options.secret?.privateKey + + if (privateKey && (typeof privateKey !== 'object' || privateKey.length !== 32)) { + return { + didDocumentMetadata: {}, + didRegistrationMetadata: {}, + didState: { + state: 'failed', + reason: 'Invalid privateKey provided', + }, + } + } + + if (seed && (typeof seed !== 'object' || seed.length !== 32)) { return { didDocumentMetadata: {}, didRegistrationMetadata: {}, @@ -57,13 +71,14 @@ export class IndyVdrIndyDidRegistrar implements DidRegistrar { let did = options.did let id - if (seed && did) { + const allowOne = [privateKey, seed, did].filter((e) => e !== undefined) + if (allowOne.length > 1) { return { didDocumentMetadata: {}, didRegistrationMetadata: {}, didState: { state: 'failed', - reason: `Only one of 'seed' and 'did' must be provided`, + reason: `Only one of 'seed', 'privateKey' and 'did' must be provided`, }, } } @@ -88,7 +103,7 @@ export class IndyVdrIndyDidRegistrar implements DidRegistrar { } } else { // Create a new key and calculate did according to the rules for indy did method - const key = await agentContext.wallet.createKey({ seed, keyType: KeyType.Ed25519 }) + const key = await agentContext.wallet.createKey({ privateKey, seed, keyType: KeyType.Ed25519 }) const buffer = Hasher.hash(key.publicKey, 'sha2-256') id = TypedArrayEncoder.toBase58(buffer.slice(0, 16)) @@ -187,7 +202,8 @@ export class IndyVdrIndyDidRegistrar implements DidRegistrar { // we can only return it if the seed was passed in by the user. Once // we have a secure method for generating seeds we should use the same // approach - seed: options.secret?.seed, + seed: options.secret?.seed?.toString(), + privateKey: options.secret?.privateKey?.toString(), }, }, } @@ -325,7 +341,8 @@ export interface IndyVdrDidCreateOptions extends DidCreateOptions { verkey?: string } secret?: { - seed?: string + seed?: Buffer + privateKey?: Buffer } } diff --git a/packages/indy-vdr/tests/indy-vdr-did-registrar.e2e.test.ts b/packages/indy-vdr/tests/indy-vdr-did-registrar.e2e.test.ts index 6b24cc5c82..d148744502 100644 --- a/packages/indy-vdr/tests/indy-vdr-did-registrar.e2e.test.ts +++ b/packages/indy-vdr/tests/indy-vdr-did-registrar.e2e.test.ts @@ -60,7 +60,7 @@ describe('Indy VDR registrar E2E', () => { } signerKey = await wallet.createKey({ - seed: '000000000000000000000000Trustee9', + privateKey: TypedArrayEncoder.fromString('000000000000000000000000Trustee9'), keyType: KeyType.Ed25519, }) }) @@ -224,13 +224,15 @@ describe('Indy VDR registrar E2E', () => { }) test('can register a did:indy with services - did and verkey specified - using attrib endpoint', async () => { - // Generate a seed and the indy did. This allows us to create a new did every time + // Generate a private key and the indy did. This allows us to create a new did every time // but still check if the created output document is as expected. - const seed = Array(32 + 1) - .join((Math.random().toString(36) + '00000000000000000').slice(2, 18)) - .slice(0, 32) + const privateKey = TypedArrayEncoder.fromString( + Array(32 + 1) + .join((Math.random().toString(36) + '00000000000000000').slice(2, 18)) + .slice(0, 32) + ) - const key = await wallet.createKey({ seed: seed, keyType: KeyType.Ed25519 }) + const key = await wallet.createKey({ privateKey, keyType: KeyType.Ed25519 }) const x25519PublicKeyBase58 = TypedArrayEncoder.toBase58(convertPublicKeyToX25519(key.publicKey)) const ed25519PublicKeyBase58 = TypedArrayEncoder.toBase58(key.publicKey) diff --git a/packages/indy-vdr/tests/indy-vdr-did-resolver.e2e.test.ts b/packages/indy-vdr/tests/indy-vdr-did-resolver.e2e.test.ts index c3b0eaacbe..a40d4f72b4 100644 --- a/packages/indy-vdr/tests/indy-vdr-did-resolver.e2e.test.ts +++ b/packages/indy-vdr/tests/indy-vdr-did-resolver.e2e.test.ts @@ -1,6 +1,7 @@ import type { Key } from '@aries-framework/core' import { + TypedArrayEncoder, IndyWallet, CacheModuleConfig, InMemoryLruCache, @@ -47,7 +48,7 @@ describe('indy-vdr DID Resolver E2E', () => { } signerKey = await wallet.createKey({ - seed: '000000000000000000000000Trustee9', + privateKey: TypedArrayEncoder.fromString('000000000000000000000000Trustee9'), keyType: KeyType.Ed25519, }) }) diff --git a/packages/indy-vdr/tests/indy-vdr-pool.e2e.test.ts b/packages/indy-vdr/tests/indy-vdr-pool.e2e.test.ts index 2ea85b5e04..ee1faad9dc 100644 --- a/packages/indy-vdr/tests/indy-vdr-pool.e2e.test.ts +++ b/packages/indy-vdr/tests/indy-vdr-pool.e2e.test.ts @@ -1,6 +1,6 @@ import type { Key } from '@aries-framework/core' -import { IndyWallet, KeyType, SigningProviderRegistry } from '@aries-framework/core' +import { TypedArrayEncoder, IndyWallet, KeyType, SigningProviderRegistry } from '@aries-framework/core' import { GetNymRequest, NymRequest, SchemaRequest, CredentialDefinitionRequest } from '@hyperledger/indy-vdr-shared' import { agentDependencies, genesisTransactions, getAgentConfig, getAgentContext } from '../../core/tests/helpers' @@ -35,7 +35,7 @@ describe('IndyVdrPoolService', () => { } signerKey = await wallet.createKey({ - seed: '000000000000000000000000Trustee9', + privateKey: TypedArrayEncoder.fromString('000000000000000000000000Trustee9'), keyType: KeyType.Ed25519, }) }) diff --git a/packages/openid4vc-client/tests/openid4vc-client.e2e.test.ts b/packages/openid4vc-client/tests/openid4vc-client.e2e.test.ts index 8b01c14c17..20b2898c84 100644 --- a/packages/openid4vc-client/tests/openid4vc-client.e2e.test.ts +++ b/packages/openid4vc-client/tests/openid4vc-client.e2e.test.ts @@ -1,6 +1,6 @@ import type { KeyDidCreateOptions } from '@aries-framework/core' -import { Agent, KeyType, W3cCredentialRecord, W3cVcModule } from '@aries-framework/core' +import { Agent, KeyType, W3cCredentialRecord, W3cVcModule, TypedArrayEncoder } from '@aries-framework/core' import nock, { cleanAll, enableNetConnect } from 'nock' import { didKeyToInstanceOfKey } from '../../core/src/modules/dids/helpers' @@ -76,7 +76,7 @@ describe('OpenId4VcClient', () => { keyType: KeyType.Ed25519, }, secret: { - seed: '96213c3d7fc8d4d6754c7a0fd969598e', + privateKey: TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c7a0fd969598e'), }, }) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion From 3fb4d844b5e338c91aa122047ebb7434050f3a04 Mon Sep 17 00:00:00 2001 From: Timo Glastra Date: Sun, 19 Feb 2023 18:31:31 +0100 Subject: [PATCH 5/7] fixes after merge Signed-off-by: Timo Glastra --- demo/src/Alice.ts | 2 +- demo/src/BaseAgent.ts | 25 +++++++++---------- demo/src/Faber.ts | 2 +- ...proof.credentials.propose-offerBbs.test.ts | 2 +- ...ldproof.connectionless-credentials.test.ts | 2 +- ...v2.ldproof.credentials-auto-accept.test.ts | 4 +-- ...f.credentials.propose-offerED25519.test.ts | 2 +- .../routing/__tests__/mediation.test.ts | 3 +++ .../__tests__/IndySdkSovDidRegistrar.test.ts | 25 ++++++++++--------- .../tests/sov-did-registrar.e2e.test.ts | 2 +- 10 files changed, 36 insertions(+), 33 deletions(-) diff --git a/demo/src/Alice.ts b/demo/src/Alice.ts index 9c53abbbc0..2de378d8c1 100644 --- a/demo/src/Alice.ts +++ b/demo/src/Alice.ts @@ -8,7 +8,7 @@ export class Alice extends BaseAgent { public connectionRecordFaberId?: string public constructor(port: number, name: string) { - super({ port, name, useSharedComponents: false }) + super({ port, name, useLegacyIndySdk: true }) this.connected = false } diff --git a/demo/src/BaseAgent.ts b/demo/src/BaseAgent.ts index d5b568297a..26429ca358 100644 --- a/demo/src/BaseAgent.ts +++ b/demo/src/BaseAgent.ts @@ -12,6 +12,7 @@ import { import { AnonCredsRsModule } from '@aries-framework/anoncreds-rs' import { AskarModule } from '@aries-framework/askar' import { + TypedArrayEncoder, KeyType, DidsModule, V2ProofProtocol, @@ -45,7 +46,7 @@ const indyNetworkConfig = { connectOnStartup: true, } satisfies IndySdkPoolConfig | IndyVdrPoolConfig -type DemoAgent = Agent | ReturnType> +type DemoAgent = Agent | ReturnType> export class BaseAgent { public port: number @@ -53,16 +54,16 @@ export class BaseAgent { public config: InitConfig public agent: DemoAgent public anonCredsIssuerId: string - public usesSharedComponents: boolean + public useLegacyIndySdk: boolean public constructor({ port, name, - useSharedComponents, + useLegacyIndySdk = false, }: { port: number name: string - useSharedComponents: boolean + useLegacyIndySdk?: boolean }) { this.name = name this.port = port @@ -82,12 +83,12 @@ export class BaseAgent { // TODO: do not hardcode this this.anonCredsIssuerId = '2jEvRuKmfBJTRa7QowDpNN' - this.usesSharedComponents = useSharedComponents + this.useLegacyIndySdk = useLegacyIndySdk this.agent = new Agent({ config, dependencies: agentDependencies, - modules: useSharedComponents ? getSharedComponentModules() : getIndySdkModules(), + modules: useLegacyIndySdk ? getLegacyIndySdkModules() : getAskarAnonCredsIndyModules(), }) this.agent.registerInboundTransport(new HttpInboundTransport({ port })) this.agent.registerOutboundTransport(new HttpOutboundTransport()) @@ -100,14 +101,12 @@ export class BaseAgent { // We need to make sure the key to submit transactions is created. We should update this to use the dids module, and allow // to add an existing did based on a seed/secretKey, and not register it on the the ledger. However for Indy SDK we currently // use the deprecated publicDidSeed property (which will register the did in the wallet), and for Askar we manually create the key - // in the wallet. Additional issue is that when creating a key in askar using the seed, it will give different results than indy-sdk - // but if we create the key in askar from the seed, but use it as the secret key, it will work. - // For IndySDK we can't call createKey as it won't allow to sign the transactions in that case, as it needs to be a did - if (this.usesSharedComponents) { + // in the wallet. + if (!this.useLegacyIndySdk) { try { await this.agent.context.wallet.createKey({ keyType: KeyType.Ed25519, - seed: 'afjdemoverysercure00000000000000', + privateKey: TypedArrayEncoder.fromString('afjdemoverysercure00000000000000'), }) } catch (error) { // We assume the key already exists, and that's why askar failed @@ -118,7 +117,7 @@ export class BaseAgent { } } -function getSharedComponentModules() { +function getAskarAnonCredsIndyModules() { const legacyIndyCredentialFormatService = new LegacyIndyCredentialFormatService() const legacyIndyProofFormatService = new LegacyIndyProofFormatService() @@ -159,7 +158,7 @@ function getSharedComponentModules() { } as const } -function getIndySdkModules() { +function getLegacyIndySdkModules() { const legacyIndyCredentialFormatService = new LegacyIndyCredentialFormatService() const legacyIndyProofFormatService = new LegacyIndyProofFormatService() diff --git a/demo/src/Faber.ts b/demo/src/Faber.ts index 655714d7d1..4585f82c7d 100644 --- a/demo/src/Faber.ts +++ b/demo/src/Faber.ts @@ -14,7 +14,7 @@ export class Faber extends BaseAgent { public ui: BottomBar public constructor(port: number, name: string) { - super({ port, name, useSharedComponents: true }) + super({ port, name }) this.ui = new ui.BottomBar() } diff --git a/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts b/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts index ce2a9b5010..2205fde9b0 100644 --- a/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts +++ b/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts @@ -67,7 +67,7 @@ describeSkipNode17And18('credentials, BBS+ signature', () => { await faberAgent.context.wallet.createKey({ keyType: KeyType.Ed25519, - seed: TypedArrayEncoder.fromString('testseed000000000000000000000001'), + privateKey: TypedArrayEncoder.fromString('testseed000000000000000000000001'), }) await faberAgent.context.wallet.createKey({ keyType: KeyType.Bls12381g2, diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.connectionless-credentials.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.connectionless-credentials.test.ts index f90e330d02..7472cca215 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.connectionless-credentials.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.connectionless-credentials.test.ts @@ -47,7 +47,7 @@ describe('credentials', () => { })) await faberAgent.context.wallet.createKey({ - seed: TypedArrayEncoder.fromString('testseed000000000000000000000001'), + privateKey: TypedArrayEncoder.fromString('testseed000000000000000000000001'), keyType: KeyType.Ed25519, }) }) diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials-auto-accept.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials-auto-accept.test.ts index ee25f722d3..84792602cd 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials-auto-accept.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials-auto-accept.test.ts @@ -49,7 +49,7 @@ describe('V2 Credentials - JSON-LD - Auto Accept Always', () => { })) await faberAgent.context.wallet.createKey({ - seed: TypedArrayEncoder.fromString('testseed000000000000000000000001'), + privateKey: TypedArrayEncoder.fromString('testseed000000000000000000000001'), keyType: KeyType.Ed25519, }) }) @@ -150,7 +150,7 @@ describe('V2 Credentials - JSON-LD - Auto Accept Always', () => { })) await faberAgent.context.wallet.createKey({ - seed: TypedArrayEncoder.fromString('testseed000000000000000000000001'), + privateKey: TypedArrayEncoder.fromString('testseed000000000000000000000001'), keyType: KeyType.Ed25519, }) }) diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts index 03bd652904..0c7bd46567 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts @@ -175,7 +175,7 @@ describe('V2 Credentials - JSON-LD - Ed25519', () => { credentialDefinitionId = credentialDefinition.credentialDefinitionId await faberAgent.context.wallet.createKey({ - seed: TypedArrayEncoder.fromString('testseed000000000000000000000001'), + privateKey: TypedArrayEncoder.fromString('testseed000000000000000000000001'), keyType: KeyType.Ed25519, }) }) diff --git a/packages/core/src/modules/routing/__tests__/mediation.test.ts b/packages/core/src/modules/routing/__tests__/mediation.test.ts index 975c07e467..e792d1c32c 100644 --- a/packages/core/src/modules/routing/__tests__/mediation.test.ts +++ b/packages/core/src/modules/routing/__tests__/mediation.test.ts @@ -10,6 +10,7 @@ import { SubjectOutboundTransport } from '../../../../../../tests/transport/Subj import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' import { getAgentOptions, waitForBasicMessage } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' +import { sleep } from '../../../utils/sleep' import { ConnectionRecord, HandshakeProtocol } from '../../connections' import { MediatorPickupStrategy } from '../MediatorPickupStrategy' import { MediationState } from '../models/MediationState' @@ -284,5 +285,7 @@ describe('mediator establishment', () => { }) expect(basicMessage.content).toBe(message) + + await recipientAgent.mediationRecipient.stopMessagePickup() }) }) diff --git a/packages/indy-sdk/src/dids/__tests__/IndySdkSovDidRegistrar.test.ts b/packages/indy-sdk/src/dids/__tests__/IndySdkSovDidRegistrar.test.ts index 2633352dbf..ab3f31bd4f 100644 --- a/packages/indy-sdk/src/dids/__tests__/IndySdkSovDidRegistrar.test.ts +++ b/packages/indy-sdk/src/dids/__tests__/IndySdkSovDidRegistrar.test.ts @@ -2,6 +2,7 @@ import type { IndySdkPool } from '../../ledger/IndySdkPool' import type { Wallet, DidRecord, RecordSavedEvent } from '@aries-framework/core' import { + TypedArrayEncoder, DidRepository, SigningProviderRegistry, JsonTransformer, @@ -54,7 +55,7 @@ describe('IndySdkSovDidRegistrar', () => { jest.clearAllMocks() }) - it('should return an error state if an invalid seed is provided', async () => { + it('should return an error state if an invalid private key is provided', async () => { const result = await indySdkSovDidRegistrar.create(agentContext, { method: 'sov', @@ -63,7 +64,7 @@ describe('IndySdkSovDidRegistrar', () => { alias: 'Hello', }, secret: { - seed: 'invalid', + privateKey: TypedArrayEncoder.fromString('invalid'), }, }) @@ -72,7 +73,7 @@ describe('IndySdkSovDidRegistrar', () => { didRegistrationMetadata: {}, didState: { state: 'failed', - reason: 'Invalid seed provided', + reason: 'Invalid private key provided', }, }) }) @@ -96,7 +97,7 @@ describe('IndySdkSovDidRegistrar', () => { alias: 'Hello', }, secret: { - seed: '12345678901234567890123456789012', + privateKey: TypedArrayEncoder.fromString('12345678901234567890123456789012'), }, }) @@ -130,7 +131,7 @@ describe('IndySdkSovDidRegistrar', () => { }) it('should correctly create a did:sov document without services', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = '96213c3d7fc8d4d6754c712fd969598e' const registerPublicDidSpy = jest.spyOn(indySdkSovDidRegistrar, 'registerPublicDid') registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve('R1xKJw17sUoXhejEpugMYJ')) @@ -143,7 +144,7 @@ describe('IndySdkSovDidRegistrar', () => { role: 'STEWARD', }, secret: { - seed, + privateKey: TypedArrayEncoder.fromString(privateKey), }, }) @@ -198,14 +199,14 @@ describe('IndySdkSovDidRegistrar', () => { keyAgreement: ['did:sov:R1xKJw17sUoXhejEpugMYJ#key-agreement-1'], }, secret: { - seed, + privateKey, }, }, }) }) it('should correctly create a did:sov document with services', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = '96213c3d7fc8d4d6754c712fd969598e' const registerPublicDidSpy = jest.spyOn(indySdkSovDidRegistrar, 'registerPublicDid') registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve('R1xKJw17sUoXhejEpugMYJ')) @@ -226,7 +227,7 @@ describe('IndySdkSovDidRegistrar', () => { }, }, secret: { - seed, + privateKey: TypedArrayEncoder.fromString(privateKey), }, }) @@ -305,14 +306,14 @@ describe('IndySdkSovDidRegistrar', () => { keyAgreement: ['did:sov:R1xKJw17sUoXhejEpugMYJ#key-agreement-1'], }, secret: { - seed, + privateKey, }, }, }) }) it('should store the did document', async () => { - const seed = '96213c3d7fc8d4d6754c712fd969598e' + const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') const registerPublicDidSpy = jest.spyOn(indySdkSovDidRegistrar, 'registerPublicDid') registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve('did')) @@ -336,7 +337,7 @@ describe('IndySdkSovDidRegistrar', () => { }, }, secret: { - seed, + privateKey, }, }) diff --git a/packages/indy-sdk/tests/sov-did-registrar.e2e.test.ts b/packages/indy-sdk/tests/sov-did-registrar.e2e.test.ts index eef3b5c8dd..de121b462d 100644 --- a/packages/indy-sdk/tests/sov-did-registrar.e2e.test.ts +++ b/packages/indy-sdk/tests/sov-did-registrar.e2e.test.ts @@ -117,7 +117,7 @@ describe('dids', () => { id: `did:sov:${indyDid}`, }, secret: { - privateKey, + privateKey: privateKey.toString(), }, }, }) From 804c938bcb5dcc416eac9080de0062f6edf7004f Mon Sep 17 00:00:00 2001 From: Timo Glastra Date: Sun, 19 Feb 2023 20:01:51 +0100 Subject: [PATCH 6/7] fix: broken postgres types Signed-off-by: Timo Glastra --- packages/core/tests/helpers.ts | 9 +++--- .../tests/postgres.e2e.test.ts | 29 +++++++++---------- packages/node/src/PostgresPlugin.ts | 19 +++++++----- packages/node/src/index.ts | 8 ++--- 4 files changed, 32 insertions(+), 33 deletions(-) rename packages/{core => indy-sdk}/tests/postgres.e2e.test.ts (75%) diff --git a/packages/core/tests/helpers.ts b/packages/core/tests/helpers.ts index f3c7f7306f..1ae3f39709 100644 --- a/packages/core/tests/helpers.ts +++ b/packages/core/tests/helpers.ts @@ -24,7 +24,7 @@ import path from 'path' import { lastValueFrom, firstValueFrom, ReplaySubject } from 'rxjs' import { catchError, filter, map, take, timeout } from 'rxjs/operators' -import { agentDependencies, WalletScheme } from '../../node/src' +import { agentDependencies, IndySdkPostgresWalletScheme } from '../../node/src' import { AgentConfig, AgentContext, @@ -91,18 +91,17 @@ export function getPostgresAgentOptions = {}, modules?: AgentModules ) { - const random = uuid().slice(0, 4) - const config: InitConfig = { label: `Agent: ${name}`, walletConfig: { - id: `Wallet: ${name} - ${random}`, + // NOTE: IndySDK Postgres database per wallet doesn't support special characters/spaces in the wallet name + id: `PostGresWallet${name}`, key: `Key${name}`, storage: { type: 'postgres_storage', config: { url: 'localhost:5432', - wallet_scheme: WalletScheme.DatabasePerWallet, + wallet_scheme: IndySdkPostgresWalletScheme.DatabasePerWallet, }, credentials: { account: 'postgres', diff --git a/packages/core/tests/postgres.e2e.test.ts b/packages/indy-sdk/tests/postgres.e2e.test.ts similarity index 75% rename from packages/core/tests/postgres.e2e.test.ts rename to packages/indy-sdk/tests/postgres.e2e.test.ts index 63dbd018f9..b8cda09b20 100644 --- a/packages/core/tests/postgres.e2e.test.ts +++ b/packages/indy-sdk/tests/postgres.e2e.test.ts @@ -1,18 +1,18 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { SubjectMessage } from '../../../tests/transport/SubjectInboundTransport' -import type { IndyPostgresStorageConfig } from '../../node/src' -import type { ConnectionRecord } from '../src/modules/connections' +import type { ConnectionRecord } from '../../core/src/modules/connections' +import type { IndySdkPostgresStorageConfig } from '../../node/src' import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' -import { getIndySdkModules } from '../../indy-sdk/tests/setupIndySdkModule' -import { loadPostgresPlugin, WalletScheme } from '../../node/src' -import { Agent } from '../src/agent/Agent' -import { HandshakeProtocol } from '../src/modules/connections' +import { Agent } from '../../core/src/agent/Agent' +import { HandshakeProtocol } from '../../core/src/modules/connections' +import { waitForBasicMessage, getPostgresAgentOptions } from '../../core/tests/helpers' +import { loadIndySdkPostgresPlugin, IndySdkPostgresWalletScheme } from '../../node/src' -import { waitForBasicMessage, getPostgresAgentOptions } from './helpers' +import { getIndySdkModules } from './setupIndySdkModule' const alicePostgresAgentOptions = getPostgresAgentOptions( 'AgentsAlice', @@ -21,6 +21,7 @@ const alicePostgresAgentOptions = getPostgresAgentOptions( }, getIndySdkModules() ) + const bobPostgresAgentOptions = getPostgresAgentOptions( 'AgentsBob', { @@ -33,7 +34,6 @@ describe('postgres agents', () => { let aliceAgent: Agent let bobAgent: Agent let aliceConnection: ConnectionRecord - let bobConnection: ConnectionRecord afterAll(async () => { await bobAgent.shutdown() @@ -51,11 +51,11 @@ describe('postgres agents', () => { 'rxjs:bob': bobMessages, } - const storageConfig: IndyPostgresStorageConfig = { + const storageConfig: IndySdkPostgresStorageConfig = { type: 'postgres_storage', config: { url: 'localhost:5432', - wallet_scheme: WalletScheme.DatabasePerWallet, + wallet_scheme: IndySdkPostgresWalletScheme.DatabasePerWallet, }, credentials: { account: 'postgres', @@ -66,7 +66,7 @@ describe('postgres agents', () => { } // loading the postgres wallet plugin - loadPostgresPlugin(storageConfig.config, storageConfig.credentials) + loadIndySdkPostgresPlugin(storageConfig.config, storageConfig.credentials) aliceAgent = new Agent(alicePostgresAgentOptions) aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) @@ -85,13 +85,10 @@ describe('postgres agents', () => { const { connectionRecord: bobConnectionAtBobAlice } = await bobAgent.oob.receiveInvitation( aliceBobOutOfBandRecord.outOfBandInvitation ) - bobConnection = await bobAgent.connections.returnWhenIsConnected(bobConnectionAtBobAlice!.id) + await bobAgent.connections.returnWhenIsConnected(bobConnectionAtBobAlice!.id) const [aliceConnectionAtAliceBob] = await aliceAgent.connections.findAllByOutOfBandId(aliceBobOutOfBandRecord.id) - aliceConnection = await aliceAgent.connections.returnWhenIsConnected(aliceConnectionAtAliceBob!.id) - - expect(aliceConnection).toBeConnectedWith(bobConnection) - expect(bobConnection).toBeConnectedWith(aliceConnection) + await aliceAgent.connections.returnWhenIsConnected(aliceConnectionAtAliceBob!.id) }) test('send a message to connection', async () => { diff --git a/packages/node/src/PostgresPlugin.ts b/packages/node/src/PostgresPlugin.ts index 4ad7dc5f37..2bcac4aae2 100644 --- a/packages/node/src/PostgresPlugin.ts +++ b/packages/node/src/PostgresPlugin.ts @@ -70,32 +70,35 @@ type NativeIndyPostgres = { let indyPostgresStorage: NativeIndyPostgres | undefined -export interface WalletStorageConfig { +export interface IndySdkPostgresWalletStorageConfig { url: string - wallet_scheme: WalletScheme + wallet_scheme: IndySdkPostgresWalletScheme path?: string } -export interface WalletStorageCredentials { +export interface IndySdkPostgresWalletStorageCredentials { account: string password: string admin_account: string admin_password: string } -export enum WalletScheme { +export enum IndySdkPostgresWalletScheme { DatabasePerWallet = 'DatabasePerWallet', MultiWalletSingleTable = 'MultiWalletSingleTable', MultiWalletSingleTableSharedPool = 'MultiWalletSingleTableSharedPool', } -export interface IndyPostgresStorageConfig { +export interface IndySdkPostgresStorageConfig { type: 'postgres_storage' - config: WalletStorageConfig - credentials: WalletStorageCredentials + config: IndySdkPostgresWalletStorageConfig + credentials: IndySdkPostgresWalletStorageCredentials } -export function loadPostgresPlugin(config: WalletStorageConfig, credentials: WalletStorageCredentials) { +export function loadIndySdkPostgresPlugin( + config: IndySdkPostgresWalletStorageConfig, + credentials: IndySdkPostgresWalletStorageCredentials +) { if (!indyPostgresStorage) { indyPostgresStorage = getLibrary() } diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index a693aa2f9c..fbe7ed0452 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -5,7 +5,7 @@ import fetch from 'node-fetch' import WebSocket from 'ws' import { NodeFileSystem } from './NodeFileSystem' -import { IndyPostgresStorageConfig, loadPostgresPlugin, WalletScheme } from './PostgresPlugin' +import { IndySdkPostgresStorageConfig, loadIndySdkPostgresPlugin, IndySdkPostgresWalletScheme } from './PostgresPlugin' import { HttpInboundTransport } from './transport/HttpInboundTransport' import { WsInboundTransport } from './transport/WsInboundTransport' @@ -20,7 +20,7 @@ export { agentDependencies, HttpInboundTransport, WsInboundTransport, - loadPostgresPlugin, - IndyPostgresStorageConfig, - WalletScheme, + loadIndySdkPostgresPlugin, + IndySdkPostgresStorageConfig, + IndySdkPostgresWalletScheme, } From 133fdcacc093e17ebf6cf4f3e54c9e909382998f Mon Sep 17 00:00:00 2001 From: Timo Glastra Date: Sun, 19 Feb 2023 22:45:07 +0100 Subject: [PATCH 7/7] test: fix broken test Signed-off-by: Timo Glastra --- packages/indy-sdk/tests/postgres.e2e.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/indy-sdk/tests/postgres.e2e.test.ts b/packages/indy-sdk/tests/postgres.e2e.test.ts index b8cda09b20..a59359f9d8 100644 --- a/packages/indy-sdk/tests/postgres.e2e.test.ts +++ b/packages/indy-sdk/tests/postgres.e2e.test.ts @@ -88,7 +88,7 @@ describe('postgres agents', () => { await bobAgent.connections.returnWhenIsConnected(bobConnectionAtBobAlice!.id) const [aliceConnectionAtAliceBob] = await aliceAgent.connections.findAllByOutOfBandId(aliceBobOutOfBandRecord.id) - await aliceAgent.connections.returnWhenIsConnected(aliceConnectionAtAliceBob!.id) + aliceConnection = await aliceAgent.connections.returnWhenIsConnected(aliceConnectionAtAliceBob!.id) }) test('send a message to connection', async () => {