From c624971af80ffb02802ebc9ae83b8880572a680c Mon Sep 17 00:00:00 2001 From: Mircea Nistor Date: Thu, 28 Jul 2022 11:36:43 +0200 Subject: [PATCH] feat(data-store): use DataSource instead of Connection fixes #947 --- __tests__/initial.migration.test.ts | 13 +-- __tests__/localAgent.test.ts | 20 +++-- __tests__/localJsonStoreAgent.test.ts | 13 +-- __tests__/localMemoryStoreAgent.test.ts | 51 ++++++----- __tests__/restAgent.test.ts | 27 +++--- __tests__/shared/credentialStatus.ts | 53 ++++++----- __tests__/shared/dbInitOptions.ts | 4 +- __tests__/shared/didCommPacking.ts | 4 +- __tests__/shared/didCommWithEthrDidFlow.ts | 2 + __tests__/shared/didCommWithFakeDidFlow.ts | 2 + __tests__/shared/didDiscovery.ts | 20 ++--- __tests__/shared/didManager.ts | 2 + __tests__/shared/documentationExamples.ts | 5 +- __tests__/shared/handleSdrMessage.ts | 2 + __tests__/shared/keyManager.ts | 19 ++-- __tests__/shared/messageHandler.ts | 2 + __tests__/shared/resolveDid.ts | 2 + __tests__/shared/saveClaims.ts | 2 + __tests__/shared/utils.ts | 42 ++++----- __tests__/shared/verifiableDataEIP712.ts | 26 +++--- __tests__/shared/verifiableDataJWT.ts | 2 + __tests__/shared/verifiableDataLD.ts | 2 + __tests__/shared/web3.ts | 49 ++++++----- __tests__/shared/webDidFlow.ts | 2 + __tests__/utils/ganache-provider.ts | 2 +- __tests__/utils/json-file-store.ts | 10 ++- packages/cli/default/default.yml | 2 +- .../src/__tests__/data-store-orm.test.ts | 10 ++- .../data-store/src/__tests__/entities.test.ts | 8 +- packages/data-store/src/data-store-orm.ts | 18 ++-- packages/data-store/src/data-store.ts | 87 +++++++++---------- .../data-store/src/identifier/did-store.ts | 32 +++---- .../data-store/src/identifier/key-store.ts | 16 ++-- .../src/identifier/private-key-store.ts | 16 ++-- .../src/migrations/2.simplifyRelations.ts | 1 - .../migrations/4.allowNullVPIssuanceDate.ts | 2 +- packages/data-store/src/utils.ts | 17 ++++ packages/test-utils/package.json | 1 + .../test-utils/src/broken-did-discovery.ts | 23 +++++ packages/test-utils/src/index.ts | 1 + packages/test-utils/tsconfig.json | 2 + 41 files changed, 358 insertions(+), 256 deletions(-) create mode 100644 packages/data-store/src/utils.ts create mode 100644 packages/test-utils/src/broken-did-discovery.ts diff --git a/__tests__/initial.migration.test.ts b/__tests__/initial.migration.test.ts index 12c5cab90..6e982f1fb 100644 --- a/__tests__/initial.migration.test.ts +++ b/__tests__/initial.migration.test.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + /** * This suite runs through a few agent operations using data that was created before * TypeORM migrations were available (before Veramo 3.0.0) @@ -32,7 +34,7 @@ import { KeyManager } from '../packages/key-manager/src' import { DIDManager } from '../packages/did-manager/src' import { FakeDidProvider, FakeDidResolver } from '../packages/test-utils/src' -import { Connection, ConnectionOptions, createConnection } from 'typeorm' +import { DataSourceOptions, DataSource } from 'typeorm' import { Resolver } from 'did-resolver' import { getResolver as ethrDidResolver } from 'ethr-did-resolver' import { getResolver as webDidResolver } from 'web-did-resolver' @@ -58,18 +60,19 @@ describe('database initial migration tests', () => { function createTestsUsingOptions( databaseBeforeFile: string, - connectionOverrides: Partial, + connectionOverrides: Partial, ) { describe('using pre-migration database fixture', () => { const databaseFile = databaseBeforeFile + '.tmp' type TestingAgentPlugins = IDIDManager & IKeyManager & IDataStore & IDataStoreORM & IResolver & IDIDComm let agent: TAgent - let dbConnection: Promise + let dbConnection: DataSource beforeAll(async () => { fs.copyFileSync(databaseBeforeFile, databaseFile) - dbConnection = createConnection({ + // intentionally using DataSource instead of Promise to test compatibility + dbConnection = new DataSource({ name: 'test', type: 'sqlite', database: databaseFile, @@ -79,7 +82,7 @@ describe('database initial migration tests', () => { logging: false, entities: Entities, ...connectionOverrides, - } as ConnectionOptions) + } as DataSourceOptions) agent = createAgent({ context: { diff --git a/__tests__/localAgent.test.ts b/__tests__/localAgent.test.ts index 637b7b2f8..2ebe90a24 100644 --- a/__tests__/localAgent.test.ts +++ b/__tests__/localAgent.test.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + /** * This runs a suite of ./shared tests using an agent configured for local operations, * using a SQLite db for storage of credentials, presentations, messages as well as keys and DIDs. @@ -45,17 +47,17 @@ import { DIDDiscovery, IDIDDiscovery } from '../packages/did-discovery/src' import { DataStore, + DataStoreDiscoveryProvider, DataStoreORM, DIDStore, Entities, KeyStore, migrations, PrivateKeyStore, - DataStoreDiscoveryProvider, } from '../packages/data-store/src' -import { FakeDidProvider, FakeDidResolver } from '../packages/test-utils/src' +import { BrokenDiscoveryProvider, FakeDidProvider, FakeDidResolver } from '../packages/test-utils/src' -import { Connection, createConnection } from 'typeorm' +import { DataSource } from 'typeorm' import { createGanacheProvider } from './utils/ganache-provider' import { createEthersProvider } from './utils/ethers-provider' import { Resolver } from 'did-resolver' @@ -102,13 +104,13 @@ let agent: TAgent< ISelectiveDisclosure & IDIDDiscovery > -let dbConnection: Promise +let dbConnection: Promise let databaseFile: string const setup = async (options?: IAgentOptions): Promise => { databaseFile = options?.context?.databaseFile || `./tmp/local-database-${Math.random().toPrecision(5)}.sqlite` - dbConnection = createConnection({ + dbConnection = new DataSource({ name: options?.context?.['dbName'] || 'test', type: 'sqlite', database: databaseFile, @@ -119,7 +121,7 @@ const setup = async (options?: IAgentOptions): Promise => { entities: Entities, // allow shared tests to override connection options ...options?.context?.dbConnectionOptions, - }) + }).initialize() const { provider, registry } = await createGanacheProvider() const ethersProvider = createEthersProvider() @@ -228,7 +230,11 @@ const setup = async (options?: IAgentOptions): Promise => { }), new SelectiveDisclosure(), new DIDDiscovery({ - providers: [new AliasDiscoveryProvider(), new DataStoreDiscoveryProvider()], + providers: [ + new AliasDiscoveryProvider(), + new DataStoreDiscoveryProvider(), + new BrokenDiscoveryProvider(), + ], }), ...(options?.plugins || []), ], diff --git a/__tests__/localJsonStoreAgent.test.ts b/__tests__/localJsonStoreAgent.test.ts index 70cd0ead6..83c64107e 100644 --- a/__tests__/localJsonStoreAgent.test.ts +++ b/__tests__/localJsonStoreAgent.test.ts @@ -34,19 +34,10 @@ import { EthrDIDProvider } from '../packages/did-provider-ethr/src' import { WebDIDProvider } from '../packages/did-provider-web/src' import { getDidKeyResolver, KeyDIDProvider } from '../packages/did-provider-key/src' import { DIDComm, DIDCommMessageHandler, IDIDComm } from '../packages/did-comm/src' -import { - ISelectiveDisclosure, - SdrMessageHandler, - SelectiveDisclosure, -} from '../packages/selective-disclosure/src' +import { ISelectiveDisclosure, SdrMessageHandler, SelectiveDisclosure, } from '../packages/selective-disclosure/src' import { KeyManagementSystem, SecretBox } from '../packages/kms-local/src' import { Web3KeyManagementSystem } from '../packages/kms-web3/src' -import { - DataStoreJson, - DIDStoreJson, - KeyStoreJson, - PrivateKeyStoreJson, -} from '../packages/data-store-json/src' +import { DataStoreJson, DIDStoreJson, KeyStoreJson, PrivateKeyStoreJson, } from '../packages/data-store-json/src' import { FakeDidProvider, FakeDidResolver } from '../packages/test-utils/src' import { Resolver } from 'did-resolver' diff --git a/__tests__/localMemoryStoreAgent.test.ts b/__tests__/localMemoryStoreAgent.test.ts index c0b2d8fc0..7f41bced5 100644 --- a/__tests__/localMemoryStoreAgent.test.ts +++ b/__tests__/localMemoryStoreAgent.test.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + /** * This runs a suite of ./shared tests using an agent configured for local operations, * using a SQLite db for storage of credentials and an in-memory store for keys and DIDs. @@ -17,7 +19,7 @@ import { import { MessageHandler } from '../packages/message-handler/src' import { KeyManager, MemoryKeyStore, MemoryPrivateKeyStore } from '../packages/key-manager/src' import { DIDManager, MemoryDIDStore } from '../packages/did-manager/src' -import { Connection, createConnection } from 'typeorm' +import { DataSource } from 'typeorm' import { DIDResolverPlugin } from '../packages/did-resolver/src' import { JwtMessageHandler } from '../packages/did-jwt/src' import { CredentialIssuer, ICredentialIssuer, W3cMessageHandler } from '../packages/credential-w3c/src' @@ -71,21 +73,22 @@ const infuraProjectId = '3586660d179141e3801c3895de1c2eba' let agent: TAgent< IDIDManager & - IKeyManager & - IDataStore & - IDataStoreORM & - IResolver & - IMessageHandler & - IDIDComm & - ICredentialIssuer & - ICredentialIssuerLD & - ICredentialIssuerEIP712 & - ISelectiveDisclosure + IKeyManager & + IDataStore & + IDataStoreORM & + IResolver & + IMessageHandler & + IDIDComm & + ICredentialIssuer & + ICredentialIssuerLD & + ICredentialIssuerEIP712 & + ISelectiveDisclosure > -let dbConnection: Promise +let dbConnection: DataSource const setup = async (options?: IAgentOptions): Promise => { - dbConnection = createConnection({ + // intentionally not initializing here to test compatibility + dbConnection = new DataSource({ name: 'test', type: 'sqlite', database: databaseFile, @@ -98,16 +101,16 @@ const setup = async (options?: IAgentOptions): Promise => { agent = createAgent< IDIDManager & - IKeyManager & - IDataStore & - IDataStoreORM & - IResolver & - IMessageHandler & - IDIDComm & - ICredentialIssuer & - ICredentialIssuerLD & - ICredentialIssuerEIP712 & - ISelectiveDisclosure + IKeyManager & + IDataStore & + IDataStoreORM & + IResolver & + IMessageHandler & + IDIDComm & + ICredentialIssuer & + ICredentialIssuerLD & + ICredentialIssuerEIP712 & + ISelectiveDisclosure >({ ...options, context: { @@ -218,6 +221,6 @@ describe('Local in-memory integration tests', () => { didManager(testContext) messageHandler(testContext) didCommPacking(testContext) - utils(testContext) + utils(testContext) credentialStatus(testContext) }) diff --git a/__tests__/restAgent.test.ts b/__tests__/restAgent.test.ts index cab24c36e..5e5b3623b 100644 --- a/__tests__/restAgent.test.ts +++ b/__tests__/restAgent.test.ts @@ -1,6 +1,9 @@ +// noinspection ES6PreferShortImport + /** * This runs a suite of ./shared tests using an agent configured for remote operations. - * There is a local agent that only uses @veramo/remove-client and a remote agent that provides the actual functionality. + * There is a local agent that only uses @veramo/remove-client and a remote agent that provides the actual + * functionality. * * This suite also runs a messaging server to run through some examples of DIDComm using did:fake identifiers. * See didWithFakeDidFlow() for more details. @@ -46,20 +49,20 @@ import { KeyManagementSystem, SecretBox } from '../packages/kms-local/src' import { Web3KeyManagementSystem } from '../packages/kms-web3/src' import { DataStore, + DataStoreDiscoveryProvider, DataStoreORM, DIDStore, Entities, KeyStore, migrations, PrivateKeyStore, - DataStoreDiscoveryProvider, } from '../packages/data-store/src' -import { Connection, createConnection } from 'typeorm' import { AgentRestClient } from '../packages/remote-client/src' import { AgentRouter, MessagingRouter, RequestWithAgentRouter } from '../packages/remote-server/src' import { DIDDiscovery, IDIDDiscovery } from '../packages/did-discovery/src' -import { FakeDidProvider, FakeDidResolver } from '../packages/test-utils/src' +import { BrokenDiscoveryProvider, FakeDidProvider, FakeDidResolver } from '../packages/test-utils/src' +import { DataSource } from 'typeorm' import { Resolver } from 'did-resolver' import { getResolver as ethrDidResolver } from 'ethr-did-resolver' import { getResolver as webDidResolver } from 'web-did-resolver' @@ -93,7 +96,7 @@ const secretKey = '29739248cad1bd1a0fc4d9b75cd4d2990de535baf5caadfdf8d8f86664aa8 const port = 3002 const basePath = '/agent' -let dbConnection: Promise +let dbConnection: Promise let serverAgent: IAgent let restServer: Server @@ -123,7 +126,7 @@ const getAgent = (options?: IAgentOptions) => }) const setup = async (options?: IAgentOptions): Promise => { - dbConnection = createConnection({ + dbConnection = new DataSource({ name: options?.context?.['dbName'] || 'sqlite-test', type: 'sqlite', database: databaseFile, @@ -132,7 +135,7 @@ const setup = async (options?: IAgentOptions): Promise => { migrationsRun: true, logging: false, entities: Entities, - }) + }).initialize() serverAgent = new Agent({ ...options, @@ -141,7 +144,7 @@ const setup = async (options?: IAgentOptions): Promise => { store: new KeyStore(dbConnection), kms: { local: new KeyManagementSystem(new PrivateKeyStore(dbConnection, new SecretBox(secretKey))), - web3: new Web3KeyManagementSystem({}) + web3: new Web3KeyManagementSystem({}), }, }), new DIDManager({ @@ -205,7 +208,11 @@ const setup = async (options?: IAgentOptions): Promise => { }), new SelectiveDisclosure(), new DIDDiscovery({ - providers: [new AliasDiscoveryProvider(), new DataStoreDiscoveryProvider()], + providers: [ + new AliasDiscoveryProvider(), + new DataStoreDiscoveryProvider(), + new BrokenDiscoveryProvider(), + ], }), ...(options?.plugins || []), ], @@ -267,6 +274,6 @@ describe('REST integration tests', () => { didCommPacking(testContext) didWithFakeDidFlow(testContext) didDiscovery(testContext) - utils(testContext) + utils(testContext) credentialStatus(testContext) }) diff --git a/__tests__/shared/credentialStatus.ts b/__tests__/shared/credentialStatus.ts index 1798086ba..5763d966e 100644 --- a/__tests__/shared/credentialStatus.ts +++ b/__tests__/shared/credentialStatus.ts @@ -1,46 +1,47 @@ +// noinspection ES6PreferShortImport + import { CredentialStatus } from 'credential-status' import { - CredentialPayload, IAgentOptions, + CredentialPayload, + IAgentOptions, IDataStore, IDataStoreORM, IDIDManager, IIdentifier, - TAgent + TAgent, } from '../../packages/core/src' -import { CredentialStatusPlugin } from '../../packages/credential-status/src/credential-status' +import { CredentialStatusPlugin } from '../../packages/credential-status/src' import { ICredentialIssuer } from '../../packages/credential-w3c/src' type ConfiguredAgent = TAgent // Constant used to simulate exception flows -const simulateStatusVerificationFailure = "Any unexpected failure during status verification."; +const simulateStatusVerificationFailure = 'Any unexpected failure during status verification.' // Constant used to simulate revoked credentials -const simulateRevokedCredential = "A revoked credential."; +const simulateRevokedCredential = 'A revoked credential.' // Constant used to simulate revoked credentials -const simulateNotRevokedCredential = "A NOT revoked credential."; +const simulateNotRevokedCredential = 'A NOT revoked credential.' -const callsCounter = jest.fn(); +const callsCounter = jest.fn() const checkStatus = async (credential: any): Promise => { - callsCounter(); + callsCounter() if (credential.credentialStatus.id === simulateStatusVerificationFailure) { - // Simulates the exception flows where the credential status verification + // Simulates the exception flows where the credential status verification // can't be executed for and unexpected reason, like network failures. throw new Error(simulateStatusVerificationFailure) } - const revoked = credential.credentialStatus.id === simulateRevokedCredential; + const revoked = credential.credentialStatus.id === simulateRevokedCredential if (!revoked && credential.credentialStatus.id !== simulateNotRevokedCredential) { - throw new Error("Invalid state.") + throw new Error('Invalid state.') } return revoked ? { revoked } : {} -}; - - +} export default (testContext: { getAgent: () => ConfiguredAgent @@ -125,7 +126,9 @@ export default (testContext: { }) expect(vc).toHaveProperty('proof.jwt') - await expect(agent.verifyCredential({ credential: vc })).rejects.toThrow(simulateStatusVerificationFailure); + await expect(agent.verifyCredential({ credential: vc })).rejects.toThrow( + simulateStatusVerificationFailure, + ) expect(callsCounter).toHaveBeenCalledTimes(1) }) @@ -136,7 +139,9 @@ export default (testContext: { }) expect(vc).toHaveProperty('proof.jwt') - await expect(agent.verifyCredential({ credential: vc })).rejects.toThrow(`unknown_method: credentialStatus method UnknownType unknown. Validity can not be determined.`) + await expect(agent.verifyCredential({ credential: vc })).rejects.toThrow( + `unknown_method: credentialStatus method UnknownType unknown. Validity can not be determined.`, + ) expect(callsCounter).toHaveBeenCalledTimes(0) }) @@ -189,7 +194,6 @@ export default (testContext: { }) }) - describe('Credential status verification (revocation) without status plugin', () => { let agent: ConfiguredAgent let identifier: IIdentifier @@ -216,7 +220,7 @@ export default (testContext: { credentialStatus: { type: 'ExoticStatusMethod2022', id: simulateNotRevokedCredential, - } + }, } }) @@ -230,13 +234,17 @@ export default (testContext: { expect(vc).toHaveProperty('proof.jwt') // TODO It`s an exception flow an it'd be better to throw an exception instead of returning false - await expect(agent.verifyCredential({ credential: vc })).rejects.toThrow(`The credential status can't be verified by the agent`) + await expect(agent.verifyCredential({ credential: vc })).rejects.toThrow( + `The credential status can't be verified by the agent`, + ) }) - }) } -function buildCredential(identifier: IIdentifier, credentialStatus: { type: string; id: string }): CredentialPayload { +function buildCredential( + identifier: IIdentifier, + credentialStatus: { type: string; id: string }, +): CredentialPayload { return { issuer: { id: identifier.did }, '@context': ['https://www.w3.org/2018/credentials/v1', 'https://veramo.io/contexts/profile/v1'], @@ -245,7 +253,6 @@ function buildCredential(identifier: IIdentifier, credentialStatus: { type: stri credentialSubject: { name: 'Better trust layers with Veramo!', }, - credentialStatus + credentialStatus, } } - diff --git a/__tests__/shared/dbInitOptions.ts b/__tests__/shared/dbInitOptions.ts index 6d5b3ecdf..afb052db2 100644 --- a/__tests__/shared/dbInitOptions.ts +++ b/__tests__/shared/dbInitOptions.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IAgentOptions, IDataStore, @@ -12,7 +14,7 @@ import { } from '../../packages/core/src' import { ICredentialIssuer } from '../../packages/credential-w3c/src' import { IDIDComm, IPackedDIDCommMessage } from '../../packages/did-comm/src' -import { extractIssuer } from '../../packages/utils' +import { extractIssuer } from '../../packages/utils/src' type ConfiguredAgent = TAgent< IDataStoreORM & diff --git a/__tests__/shared/didCommPacking.ts b/__tests__/shared/didCommPacking.ts index 7da4106f0..1aa2dea4f 100644 --- a/__tests__/shared/didCommPacking.ts +++ b/__tests__/shared/didCommPacking.ts @@ -1,4 +1,6 @@ -import { TAgent, IDIDManager, IKeyManager, IIdentifier, IResolver } from '../../packages/core/src' +// noinspection ES6PreferShortImport + +import { IDIDManager, IIdentifier, IKeyManager, IResolver, TAgent } from '../../packages/core/src' import { IDIDComm } from '../../packages/did-comm/src' type ConfiguredAgent = TAgent diff --git a/__tests__/shared/didCommWithEthrDidFlow.ts b/__tests__/shared/didCommWithEthrDidFlow.ts index 036a017ad..5da42fe1f 100644 --- a/__tests__/shared/didCommWithEthrDidFlow.ts +++ b/__tests__/shared/didCommWithEthrDidFlow.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IAgentOptions, IDIDManager, diff --git a/__tests__/shared/didCommWithFakeDidFlow.ts b/__tests__/shared/didCommWithFakeDidFlow.ts index 29b0af21a..998339fa0 100644 --- a/__tests__/shared/didCommWithFakeDidFlow.ts +++ b/__tests__/shared/didCommWithFakeDidFlow.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IAgentOptions, IDIDManager, diff --git a/__tests__/shared/didDiscovery.ts b/__tests__/shared/didDiscovery.ts index b5747568c..c582ca6bb 100644 --- a/__tests__/shared/didDiscovery.ts +++ b/__tests__/shared/didDiscovery.ts @@ -1,7 +1,8 @@ +// noinspection ES6PreferShortImport + import { IDIDDiscovery } from '../../packages/did-discovery/src' import { IAgentOptions, IDataStoreORM, IDIDManager, TAgent } from '../../packages/core/src' import { ICredentialIssuer } from '../../packages/credential-w3c/src' -import { getConnection } from 'typeorm' type ConfiguredAgent = TAgent @@ -105,26 +106,23 @@ export default (testContext: { }, }) - const byDIDFragmentResult = await agent.discoverDid({ query: identifier.did.substring(3, identifier.did.length - 3)}) + const byDIDFragmentResult = await agent.discoverDid({ + query: identifier.did.substring(3, identifier.did.length - 3), + }) expect(byDIDFragmentResult.results).toHaveLength(1) expect(byDIDFragmentResult.results[0].matches).toHaveLength(2) expect(byDIDFragmentResult.results[0].matches[1]).toEqual({ did: identifier.did, metaData: { - alias: 'bob' - } + alias: 'bob', + }, }) }) - // THIS HAS TO BE THE LAST TEST IN THIS FILE! it('should return errors', async () => { - const connection = getConnection('did-discovery-test') - await connection.close() - const result = await agent.discoverDid({ query: 'bob' }) - expect(result!.errors!['data-store-discovery']).toMatch( - /(Connection with sqlite database is not established)|(Cannot read property 'connect' of undefined)/, - ) + const result = await agent.discoverDid({ query: 'broken' }) + expect(result!.errors!['broken-discovery']).toMatch(/test_error/) }) }) } diff --git a/__tests__/shared/didManager.ts b/__tests__/shared/didManager.ts index 559b99290..9cacadc14 100644 --- a/__tests__/shared/didManager.ts +++ b/__tests__/shared/didManager.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IDIDManager, IIdentifier, IKeyManager, TAgent } from '../../packages/core/src' type ConfiguredAgent = TAgent diff --git a/__tests__/shared/documentationExamples.ts b/__tests__/shared/documentationExamples.ts index 708095293..1ef8f98c4 100644 --- a/__tests__/shared/documentationExamples.ts +++ b/__tests__/shared/documentationExamples.ts @@ -1,8 +1,11 @@ +// noinspection ES6PreferShortImport + /** * This test suite runs the examples from the documentation in various test contexts. * * Documentation examples are extracted from the tsdoc of the relevant source code. - * To document a new package, add it to docsconfig.json array and have it processed with `extract-api` or `generate-plugin-schema`. + * To document a new package, add it to docsconfig.json array and have it processed with `extract-api` or + * `generate-plugin-schema`. */ import { IDataStore, IDataStoreORM, IDIDManager, IMessageHandler, TAgent } from '../../packages/core/src' diff --git a/__tests__/shared/handleSdrMessage.ts b/__tests__/shared/handleSdrMessage.ts index 00fcf9ef5..915bdd0db 100644 --- a/__tests__/shared/handleSdrMessage.ts +++ b/__tests__/shared/handleSdrMessage.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IDataStore, IDataStoreORM, diff --git a/__tests__/shared/keyManager.ts b/__tests__/shared/keyManager.ts index 899fede4b..1be85b60c 100644 --- a/__tests__/shared/keyManager.ts +++ b/__tests__/shared/keyManager.ts @@ -1,8 +1,9 @@ -import { IAgentOptions, IDIDManager, IKeyManager, TAgent, TKeyType } from '../../packages/core/src' +// noinspection ES6PreferShortImport + +import { IAgentOptions, IDIDManager, IKeyManager, IResolver, TAgent, TKeyType } from '../../packages/core/src' import { computeAddress, serialize } from '@ethersproject/transactions' import { mapIdentifierKeysToDoc } from '../../packages/utils/src' -import { IResolver } from '../../packages/core/src' -import { recoverTypedSignature, normalize, SignTypedDataVersion } from '@metamask/eth-sig-util' +import { recoverTypedSignature, SignTypedDataVersion } from '@metamask/eth-sig-util' type ConfiguredAgent = TAgent @@ -482,7 +483,7 @@ export default (testContext: { ...msgParams.types, EIP712Domain: [ // Order of these elements matters! - // https://github.com/ethers-io/ethers.js/blob/a71f51825571d1ea0fa997c1352d5b4d85643416/packages/hash/src.ts/typed-data.ts#L385 + // https://github.com/ethers-io/ethers.js/blob/a71f51825571d1ea0fa997c1352d5b4d85643416/packages/hash/src.ts/typed-data.ts#L385 { name: 'name', type: 'string' }, { name: 'version', type: 'string' }, { name: 'chainId', type: 'uint256' }, @@ -562,20 +563,20 @@ export default (testContext: { } } } - + const identifier = await agent.didManagerCreate({ kms: 'local' }) - + const extendedKeys = await mapIdentifierKeysToDoc(identifier, 'verificationMethod', { agent }) const extendedKey = extendedKeys[0] - + const signature = await agent.keyManagerSign({ data: JSON.stringify(msgParams), keyRef: extendedKey.kid, algorithm: 'eth_signTypedData' }) - + const address = extendedKey.meta.ethereumAddress - + const data = { ...msgParams, primaryType: 'VerifiableCredential', diff --git a/__tests__/shared/messageHandler.ts b/__tests__/shared/messageHandler.ts index 1edf4585e..eee57d6ea 100644 --- a/__tests__/shared/messageHandler.ts +++ b/__tests__/shared/messageHandler.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IDataStore, IDataStoreORM, IMessage, IMessageHandler, TAgent } from '../../packages/core/src' type ConfiguredAgent = TAgent diff --git a/__tests__/shared/resolveDid.ts b/__tests__/shared/resolveDid.ts index e45c77cda..882bf3b87 100644 --- a/__tests__/shared/resolveDid.ts +++ b/__tests__/shared/resolveDid.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IAgentOptions, IDIDManager, IResolver, TAgent } from '../../packages/core/src' type ConfiguredAgent = TAgent diff --git a/__tests__/shared/saveClaims.ts b/__tests__/shared/saveClaims.ts index a84f992b0..09003be29 100644 --- a/__tests__/shared/saveClaims.ts +++ b/__tests__/shared/saveClaims.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { FindCredentialsArgs, IDataStore, diff --git a/__tests__/shared/utils.ts b/__tests__/shared/utils.ts index 56da45e7e..eb6aa7055 100644 --- a/__tests__/shared/utils.ts +++ b/__tests__/shared/utils.ts @@ -1,5 +1,7 @@ +// noinspection ES6PreferShortImport + import { IAgentOptions, IDIDManager, IResolver, MinimalImportableKey, TAgent } from '../../packages/core/src' -import { getChainIdForDidEthr, resolveDidOrThrow, mapIdentifierKeysToDoc } from '../../packages/utils/src' +import { getChainIdForDidEthr, mapIdentifierKeysToDoc, resolveDidOrThrow } from '../../packages/utils/src' type ConfiguredAgent = TAgent @@ -20,7 +22,7 @@ export default (testContext: { it('should get chainId for ethr did', async () => { const didUrl = 'did:ethr:rinkeby:0xb09b66026ba5909a7cfe99b76875431d2b8d5190' - const didDoc = await resolveDidOrThrow(didUrl, {agent}) + const didDoc = await resolveDidOrThrow(didUrl, { agent }) if (didDoc.verificationMethod) { const chainId = getChainIdForDidEthr(didDoc.verificationMethod[0]) expect(chainId).toEqual(4) @@ -35,27 +37,27 @@ export default (testContext: { did, provider: 'did:ethr:rinkeby', controllerKeyId, - keys: [{ - kid: controllerKeyId, - type: 'Secp256k1', - kms: 'web3', - privateKeyHex: '', - publicKeyHex: '', - meta: { - account, - provider: 'metamask', - algorithms: [ - 'eth_signMessage', - 'eth_signTypedData', - ] - }, - } as MinimalImportableKey], + keys: [ + { + kid: controllerKeyId, + type: 'Secp256k1', + kms: 'web3', + privateKeyHex: '', + publicKeyHex: '', + meta: { + account, + provider: 'metamask', + algorithms: ['eth_signMessage', 'eth_signTypedData'], + }, + } as MinimalImportableKey, + ], }) const identifier = await agent.didManagerGet({ did }) const extendedKeys = await mapIdentifierKeysToDoc(identifier, 'verificationMethod', { agent }) - expect(extendedKeys[0].meta.verificationMethod?.blockchainAccountId?.toLocaleLowerCase()).toEqual(`eip155:4:${account}`) - + expect(extendedKeys[0].meta.verificationMethod?.blockchainAccountId?.toLocaleLowerCase()).toEqual( + `eip155:4:${account}`, + ) }) }) -} \ No newline at end of file +} diff --git a/__tests__/shared/verifiableDataEIP712.ts b/__tests__/shared/verifiableDataEIP712.ts index e6e0cba4b..28069f0d3 100644 --- a/__tests__/shared/verifiableDataEIP712.ts +++ b/__tests__/shared/verifiableDataEIP712.ts @@ -1,15 +1,20 @@ +// noinspection ES6PreferShortImport + import { IDataStore, IDataStoreORM, IDIDManager, IIdentifier, TAgent, + VerifiableCredential, + VerifiablePresentation, } from '../../packages/core/src' import { ICredentialIssuer } from '../../packages/credential-w3c/src' -import { VerifiableCredential, VerifiablePresentation } from '../../packages/core' import { ICredentialIssuerEIP712 } from '../../packages/credential-eip712/src' -type ConfiguredAgent = TAgent +type ConfiguredAgent = TAgent< + IDIDManager & ICredentialIssuer & ICredentialIssuerEIP712 & IDataStore & IDataStoreORM +> export default (testContext: { getAgent: () => ConfiguredAgent @@ -44,7 +49,7 @@ export default (testContext: { credentialSubject: { id: 'did:web:example.com', you: 'Rock', - } + }, }, proofFormat: 'EthereumEip712Signature2021', }) @@ -61,20 +66,19 @@ export default (testContext: { const verifiableCredential2 = await agent.dataStoreGetVerifiableCredential({ hash }) expect(verifiableCredential).toEqual(verifiableCredential2) - }) it('should verify credential with EthereumEip712Signature2021 proof type', async () => { const result = await agent.verifyCredentialEIP712({ - credential: verifiableCredential + credential: verifiableCredential, }) expect(result).toEqual(true) }) it('should create verifiable presentation with EthereumEip712Signature2021 proof type', async () => { - - const jwt_vc = 'eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiRGlzY29yZFJvbGUiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsiZGlzY29yZFVzZXJJZCI6IjQxMjgxNDQ4NjMzMjg5OTMzOCIsImRpc2NvcmRVc2VyTmFtZSI6IkFnbmVzIHwgQ29sbGFiLkxhbmQjMjYyMyIsImRpc2NvcmRVc2VyQXZhdGFyIjoiaHR0cHM6Ly9jZG4uZGlzY29yZGFwcC5jb20vYXZhdGFycy80MTI4MTQ0ODYzMzI4OTkzMzgvMTRmMDIwZWY3NTZhMzcyODQyODFlYmJiYThlYTg0YTkud2VicCIsImRpc2NvcmRHdWlsZElkIjoiOTQzMjU2MzA4MTcyMzQ1NDA1IiwiZGlzY29yZEd1aWxkTmFtZSI6IkNvbGxhYkxhbmQgVkMgR2F0ZWQgU2VydmVyIiwiZGlzY29yZEd1aWxkQXZhdGFyIjoiaHR0cHM6Ly9jZG4uZGlzY29yZGFwcC5jb20vaWNvbnMvOTQzMjU2MzA4MTcyMzQ1NDA1L2ZlMmVhMzBkZWIyZTMzMjQyNjVhZGY0Y2U3N2NjZWU2LndlYnAiLCJkaXNjb3JkUm9sZUlkIjoiOTQzMjU4OTY3MDUwNzAyODY5IiwiZGlzY29yZFJvbGVOYW1lIjoiQ29sbGFiTGFuZCBQYXRyb24iLCJkZXNjcmlwdGlvbiI6IkFnbmVzIHwgQ29sbGFiLkxhbmQjMjYyMyBoYXMgcm9sZSBDb2xsYWJMYW5kIFBhdHJvbiBpbiBEaXNjb3JkIGNvbW11bml0eSBDb2xsYWJMYW5kIFZDIEdhdGVkIFNlcnZlciJ9fSwic3ViIjoiNDEyODE0NDg2MzMyODk5MzM4IiwianRpIjoiMDIwMDQ0ZWQtMzkyYi00YjIwLThmY2MtYzgxYWNkNjQzYjc4IiwibmJmIjoxNjQ3MDE5MDgzLCJpc3MiOiJkaWQ6ZXRocjpyaW5rZWJ5OjB4MDJlM2RhMGFjN2VkZmJkNzViYjU1M2Y0YzYxODAxODVjNjQ2ODVkYzhjOWI1ZDBiOTBiZTlmMzdhNzE2MzkzZjNhIn0.N0j805D0Wiwv3hnd8S5sHdRpketHHCmth7G5bVuU4QFX03iwH1dclFD01bbmI3TXnfcLANpQhCINSJDAd9My5g' + const jwt_vc = + 'eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiRGlzY29yZFJvbGUiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsiZGlzY29yZFVzZXJJZCI6IjQxMjgxNDQ4NjMzMjg5OTMzOCIsImRpc2NvcmRVc2VyTmFtZSI6IkFnbmVzIHwgQ29sbGFiLkxhbmQjMjYyMyIsImRpc2NvcmRVc2VyQXZhdGFyIjoiaHR0cHM6Ly9jZG4uZGlzY29yZGFwcC5jb20vYXZhdGFycy80MTI4MTQ0ODYzMzI4OTkzMzgvMTRmMDIwZWY3NTZhMzcyODQyODFlYmJiYThlYTg0YTkud2VicCIsImRpc2NvcmRHdWlsZElkIjoiOTQzMjU2MzA4MTcyMzQ1NDA1IiwiZGlzY29yZEd1aWxkTmFtZSI6IkNvbGxhYkxhbmQgVkMgR2F0ZWQgU2VydmVyIiwiZGlzY29yZEd1aWxkQXZhdGFyIjoiaHR0cHM6Ly9jZG4uZGlzY29yZGFwcC5jb20vaWNvbnMvOTQzMjU2MzA4MTcyMzQ1NDA1L2ZlMmVhMzBkZWIyZTMzMjQyNjVhZGY0Y2U3N2NjZWU2LndlYnAiLCJkaXNjb3JkUm9sZUlkIjoiOTQzMjU4OTY3MDUwNzAyODY5IiwiZGlzY29yZFJvbGVOYW1lIjoiQ29sbGFiTGFuZCBQYXRyb24iLCJkZXNjcmlwdGlvbiI6IkFnbmVzIHwgQ29sbGFiLkxhbmQjMjYyMyBoYXMgcm9sZSBDb2xsYWJMYW5kIFBhdHJvbiBpbiBEaXNjb3JkIGNvbW11bml0eSBDb2xsYWJMYW5kIFZDIEdhdGVkIFNlcnZlciJ9fSwic3ViIjoiNDEyODE0NDg2MzMyODk5MzM4IiwianRpIjoiMDIwMDQ0ZWQtMzkyYi00YjIwLThmY2MtYzgxYWNkNjQzYjc4IiwibmJmIjoxNjQ3MDE5MDgzLCJpc3MiOiJkaWQ6ZXRocjpyaW5rZWJ5OjB4MDJlM2RhMGFjN2VkZmJkNzViYjU1M2Y0YzYxODAxODVjNjQ2ODVkYzhjOWI1ZDBiOTBiZTlmMzdhNzE2MzkzZjNhIn0.N0j805D0Wiwv3hnd8S5sHdRpketHHCmth7G5bVuU4QFX03iwH1dclFD01bbmI3TXnfcLANpQhCINSJDAd9My5g' verifiablePresentation = await agent.createVerifiablePresentation({ presentation: { @@ -82,7 +86,7 @@ export default (testContext: { '@context': ['https://www.w3.org/2018/credentials/v1', 'https://example.com/1/2/3'], type: ['VerifiablePresentation', 'Custom'], issuanceDate: new Date().toISOString(), - verifiableCredential: [jwt_vc] + verifiableCredential: [jwt_vc], }, proofFormat: 'EthereumEip712Signature2021', }) @@ -99,18 +103,16 @@ export default (testContext: { const vp2 = await agent.dataStoreGetVerifiablePresentation({ hash }) expect(verifiablePresentation).toEqual(vp2) - - }) + }) it.todo('should throw error when trying to sign presentation with unsuported attributes') it('should verify presentation with EthereumEip712Signature2021 proof type', async () => { const result = await agent.verifyPresentationEIP712({ - presentation: verifiablePresentation + presentation: verifiablePresentation, }) expect(result).toEqual(true) }) - }) } diff --git a/__tests__/shared/verifiableDataJWT.ts b/__tests__/shared/verifiableDataJWT.ts index 7ef85c67d..70f61c359 100644 --- a/__tests__/shared/verifiableDataJWT.ts +++ b/__tests__/shared/verifiableDataJWT.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IDataStore, IDataStoreORM, diff --git a/__tests__/shared/verifiableDataLD.ts b/__tests__/shared/verifiableDataLD.ts index f80b3327e..778221f89 100644 --- a/__tests__/shared/verifiableDataLD.ts +++ b/__tests__/shared/verifiableDataLD.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IDataStore, IDataStoreORM, IDIDManager, IIdentifier, TAgent } from '../../packages/core/src' import { ICredentialIssuer } from '../../packages/credential-w3c/src' import { IDIDComm } from '../../packages/did-comm/src' diff --git a/__tests__/shared/web3.ts b/__tests__/shared/web3.ts index 9eb2a2ff4..a49d0e54f 100644 --- a/__tests__/shared/web3.ts +++ b/__tests__/shared/web3.ts @@ -1,4 +1,15 @@ -import { IAgentOptions, IDIDManager, IIdentifier, IKeyManager, IResolver, MinimalImportableKey, TAgent, VerifiableCredential } from '../../packages/core/src' +// noinspection ES6PreferShortImport + +import { + IAgentOptions, + IDIDManager, + IIdentifier, + IKeyManager, + IResolver, + MinimalImportableKey, + TAgent, + VerifiableCredential, +} from '../../packages/core/src' type ConfiguredAgent = TAgent @@ -27,21 +38,20 @@ export default (testContext: { did, provider: 'did:ethr', controllerKeyId, - keys: [{ - kid: controllerKeyId, - type: 'Secp256k1', - kms: 'web3', - privateKeyHex: '', - publicKeyHex: '', - meta: { - account, - provider: 'ethers', - algorithms: [ - 'eth_signMessage', - 'eth_signTypedData', - ] - }, - } as MinimalImportableKey], + keys: [ + { + kid: controllerKeyId, + type: 'Secp256k1', + kms: 'web3', + privateKeyHex: '', + publicKeyHex: '', + meta: { + account, + provider: 'ethers', + algorithms: ['eth_signMessage', 'eth_signTypedData'], + }, + } as MinimalImportableKey, + ], }) }) @@ -50,7 +60,7 @@ export default (testContext: { const signature = await agent.keyManagerSign({ data: 'Hello world', keyRef: identifier.controllerKeyId, - algorithm: 'eth_signMessage' + algorithm: 'eth_signMessage', }) expect(signature).toBeTruthy() } @@ -66,7 +76,7 @@ export default (testContext: { credentialSubject: { id: 'did:web:example.com', you: 'Rock', - } + }, }, proofFormat: 'EthereumEip712Signature2021', }) @@ -83,7 +93,6 @@ export default (testContext: { const verifiableCredential2 = await agent.dataStoreGetVerifiableCredential({ hash }) expect(verifiableCredential).toEqual(verifiableCredential2) - }) }) -} \ No newline at end of file +} diff --git a/__tests__/shared/webDidFlow.ts b/__tests__/shared/webDidFlow.ts index 47afba924..3bd86ace1 100644 --- a/__tests__/shared/webDidFlow.ts +++ b/__tests__/shared/webDidFlow.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { IDIDManager, IIdentifier, IKey, TAgent } from '../../packages/core/src' import { ICredentialIssuer } from '../../packages/credential-w3c/src' diff --git a/__tests__/utils/ganache-provider.ts b/__tests__/utils/ganache-provider.ts index 4534d5935..9448585a4 100644 --- a/__tests__/utils/ganache-provider.ts +++ b/__tests__/utils/ganache-provider.ts @@ -1,4 +1,4 @@ -import { JsonRpcProvider, Web3Provider, ExternalProvider } from '@ethersproject/providers' +import { Web3Provider } from '@ethersproject/providers' import { Contract, ContractFactory } from '@ethersproject/contracts' // @ts-ignore import DidRegistryContract from 'ethr-did-registry' diff --git a/__tests__/utils/json-file-store.ts b/__tests__/utils/json-file-store.ts index 7a928842d..7e1c731fa 100644 --- a/__tests__/utils/json-file-store.ts +++ b/__tests__/utils/json-file-store.ts @@ -1,14 +1,16 @@ +// noinspection ES6PreferShortImport + import { - DiffCallback, - VeramoJsonCache, ClaimTableEntry, CredentialTableEntry, + DiffCallback, PresentationTableEntry, + VeramoJsonCache, VeramoJsonStore, } from '../../packages/data-store-json/src' import * as fs from 'fs' -import { IIdentifier, IMessage, ManagedKeyInfo } from '../../packages/core' -import { ManagedPrivateKey } from '../../packages/key-manager' +import { IIdentifier, IMessage, ManagedKeyInfo } from '../../packages/core/src' +import { ManagedPrivateKey } from '../../packages/key-manager/src' /** * A utility class that shows how a File based JSON storage system could work. diff --git a/packages/cli/default/default.yml b/packages/cli/default/default.yml index dc09495b4..f2eaa5beb 100644 --- a/packages/cli/default/default.yml +++ b/packages/cli/default/default.yml @@ -64,7 +64,7 @@ constants: # Data base dbConnection: - $require: typeorm?t=function#createConnection + $require: typeorm#DataSource $args: - type: sqlite database: diff --git a/packages/data-store/src/__tests__/data-store-orm.test.ts b/packages/data-store/src/__tests__/data-store-orm.test.ts index 9afaea935..0a58dc362 100644 --- a/packages/data-store/src/__tests__/data-store-orm.test.ts +++ b/packages/data-store/src/__tests__/data-store-orm.test.ts @@ -1,3 +1,5 @@ +// noinspection ES6PreferShortImport + import { Agent, FindArgs, @@ -11,7 +13,7 @@ import { VerifiableCredential, VerifiablePresentation, } from '../../../core/src' -import { Connection, createConnection } from 'typeorm' +import { DataSource } from 'typeorm' import { DataStoreORM } from '../data-store-orm' import { DataStore } from '../data-store' import { Entities } from '../index' @@ -113,7 +115,7 @@ async function populateDB(agent: TAgent) { } describe('@veramo/data-store queries', () => { - let dbConnection: Promise + let dbConnection: Promise const databaseFile = './tmp/test-db2.sqlite' function makeAgent(context?: Record): TAgent { @@ -125,11 +127,11 @@ describe('@veramo/data-store queries', () => { } beforeAll(async () => { - dbConnection = createConnection({ + dbConnection = new DataSource({ type: 'sqlite', database: databaseFile, entities: Entities, - }) + }).initialize() }) beforeEach(async () => { diff --git a/packages/data-store/src/__tests__/entities.test.ts b/packages/data-store/src/__tests__/entities.test.ts index 7c55006d5..57f41eda7 100644 --- a/packages/data-store/src/__tests__/entities.test.ts +++ b/packages/data-store/src/__tests__/entities.test.ts @@ -1,22 +1,22 @@ import { Credential, createCredentialEntity } from '../entities/credential' import { createPresentationEntity } from '../entities/presentation' -import { createConnection, Connection, In } from 'typeorm' +import { DataSource, In } from 'typeorm' import { Identifier, Message, Claim } from '../index' import { Entities } from '../index' import { blake2bHex } from 'blakejs' import * as fs from 'fs' describe('DB entities test', () => { - let connection: Connection + let connection: DataSource const databaseFile = './tmp/test-db.sqlite' beforeAll( async () => - (connection = await createConnection({ + (connection = await new DataSource({ type: 'sqlite', database: databaseFile, entities: Entities, - })), + }).initialize()), ) beforeEach(async () => { diff --git a/packages/data-store/src/data-store-orm.ts b/packages/data-store/src/data-store-orm.ts index 75f3b6b31..dbd864db4 100644 --- a/packages/data-store/src/data-store-orm.ts +++ b/packages/data-store/src/data-store-orm.ts @@ -25,7 +25,7 @@ import { Any, Between, Brackets, - Connection, + DataSource, Equal, In, IsNull, @@ -37,6 +37,8 @@ import { Not, SelectQueryBuilder, } from 'typeorm' +import { getConnectedDb } from "./utils"; +import { OrPromise } from "@veramo/utils"; /** * This class implements the {@link @veramo/core#IDataStoreORM} query interface using a TypeORM compatible database. @@ -56,9 +58,9 @@ import { export class DataStoreORM implements IAgentPlugin { readonly methods: IDataStoreORM readonly schema = schema.IDataStoreORM - private dbConnection: Promise + private dbConnection: OrPromise - constructor(dbConnection: Promise) { + constructor(dbConnection: OrPromise) { this.dbConnection = dbConnection this.methods = { @@ -85,7 +87,7 @@ export class DataStoreORM implements IAgentPlugin { context: AuthorizedDIDContext, ): Promise> { const where = createWhereObject(args) - let qb = (await this.dbConnection) + let qb = (await getConnectedDb(this.dbConnection)) .getRepository(Identifier) .createQueryBuilder('identifier') .leftJoinAndSelect('identifier.keys', 'keys') @@ -129,7 +131,7 @@ export class DataStoreORM implements IAgentPlugin { context: AuthorizedDIDContext, ): Promise> { const where = createWhereObject(args) - let qb = (await this.dbConnection) + let qb = (await getConnectedDb(this.dbConnection)) .getRepository(Message) .createQueryBuilder('message') .leftJoinAndSelect('message.from', 'from') @@ -172,7 +174,7 @@ export class DataStoreORM implements IAgentPlugin { context: AuthorizedDIDContext, ): Promise> { const where = createWhereObject(args) - let qb = (await this.dbConnection) + let qb = (await getConnectedDb(this.dbConnection)) .getRepository(Claim) .createQueryBuilder('claim') .leftJoinAndSelect('claim.issuer', 'issuer') @@ -221,7 +223,7 @@ export class DataStoreORM implements IAgentPlugin { context: AuthorizedDIDContext, ): Promise> { const where = createWhereObject(args) - let qb = (await this.dbConnection) + let qb = (await getConnectedDb(this.dbConnection)) .getRepository(Credential) .createQueryBuilder('credential') .leftJoinAndSelect('credential.issuer', 'issuer') @@ -268,7 +270,7 @@ export class DataStoreORM implements IAgentPlugin { context: AuthorizedDIDContext, ): Promise> { const where = createWhereObject(args) - let qb = (await this.dbConnection) + let qb = (await getConnectedDb(this.dbConnection)) .getRepository(Presentation) .createQueryBuilder('presentation') .leftJoinAndSelect('presentation.holder', 'holder') diff --git a/packages/data-store/src/data-store.ts b/packages/data-store/src/data-store.ts index ff27a0b8e..c485b49c5 100644 --- a/packages/data-store/src/data-store.ts +++ b/packages/data-store/src/data-store.ts @@ -1,6 +1,7 @@ import { IAgentPlugin, IDataStore, + IDataStoreDeleteVerifiableCredentialArgs, IDataStoreGetMessageArgs, IDataStoreGetVerifiableCredentialArgs, IDataStoreGetVerifiablePresentationArgs, @@ -8,16 +9,17 @@ import { IDataStoreSaveVerifiableCredentialArgs, IDataStoreSaveVerifiablePresentationArgs, IMessage, + schema, VerifiableCredential, VerifiablePresentation, - schema, - IDataStoreDeleteVerifiableCredentialArgs, } from '@veramo/core' -import { Message, createMessageEntity, createMessage } from './entities/message' -import { Credential, createCredentialEntity } from './entities/credential' +import { createMessage, createMessageEntity, Message } from './entities/message' +import { createCredentialEntity, Credential } from './entities/credential' import { Claim } from './entities/claim' -import { Presentation, createPresentationEntity } from './entities/presentation' -import { Connection } from 'typeorm' +import { createPresentationEntity, Presentation } from './entities/presentation' +import { DataSource } from 'typeorm' +import { getConnectedDb } from './utils' +import { OrPromise } from '@veramo/utils' /** * This class implements the {@link @veramo/core#IDataStore} interface using a TypeORM compatible database. @@ -35,9 +37,9 @@ import { Connection } from 'typeorm' export class DataStore implements IAgentPlugin { readonly methods: IDataStore readonly schema = schema.IDataStore - private dbConnection: Promise + private dbConnection: OrPromise - constructor(dbConnection: Promise) { + constructor(dbConnection: OrPromise) { this.dbConnection = dbConnection this.methods = { @@ -52,48 +54,45 @@ export class DataStore implements IAgentPlugin { } async dataStoreSaveMessage(args: IDataStoreSaveMessageArgs): Promise { - const message = await (await this.dbConnection) + const message = await (await getConnectedDb(this.dbConnection)) .getRepository(Message) .save(createMessageEntity(args.message)) return message.id } async dataStoreGetMessage(args: IDataStoreGetMessageArgs): Promise { - try { - const messageEntity = await (await this.dbConnection).getRepository(Message).findOne({ - where: { id: args.id }, - relations: ['credentials', 'presentations'], - }) - if (!messageEntity) throw new Error('Message not found') - - return createMessage(messageEntity) - } catch (e) { - throw Error('Message not found') - } + const messageEntity = await (await getConnectedDb(this.dbConnection)).getRepository(Message).findOne({ + where: { id: args.id }, + relations: ['credentials', 'presentations'], + }) + if (!messageEntity) throw new Error('not_found: Message not found') + + return createMessage(messageEntity) } async dataStoreDeleteVerifiableCredential( args: IDataStoreDeleteVerifiableCredentialArgs, ): Promise { - const credentialEntity = await (await this.dbConnection) + const credentialEntity = await (await getConnectedDb(this.dbConnection)) .getRepository(Credential) .findOneBy({ hash: args.hash }) - if (!credentialEntity) throw new Error('Verifiable credential not found') + if (!credentialEntity) { + return false + } - const claims = await (await this.dbConnection) + const claims = await (await getConnectedDb(this.dbConnection)) .getRepository(Claim) .find({ where: { credential: { id: credentialEntity.id } } }) - // .find({ where: [{ column: 'credential', value: [credentialEntity.id] }] }) - await (await this.dbConnection).getRepository(Claim).remove(claims) + await (await getConnectedDb(this.dbConnection)).getRepository(Claim).remove(claims) - await (await this.dbConnection).getRepository(Credential).remove(credentialEntity) + await (await getConnectedDb(this.dbConnection)).getRepository(Credential).remove(credentialEntity) return true } async dataStoreSaveVerifiableCredential(args: IDataStoreSaveVerifiableCredentialArgs): Promise { - const verifiableCredential = await (await this.dbConnection) + const verifiableCredential = await (await getConnectedDb(this.dbConnection)) .getRepository(Credential) .save(createCredentialEntity(args.verifiableCredential)) return verifiableCredential.hash @@ -102,20 +101,16 @@ export class DataStore implements IAgentPlugin { async dataStoreGetVerifiableCredential( args: IDataStoreGetVerifiableCredentialArgs, ): Promise { - try { - const credentialEntity = await (await this.dbConnection) - .getRepository(Credential) - .findOneBy({ hash: args.hash }) - if (!credentialEntity) throw new Error('Verifiable credential not found') - - return credentialEntity.raw - } catch (e) { - throw Error('Verifiable credential not found') - } + const credentialEntity = await (await getConnectedDb(this.dbConnection)) + .getRepository(Credential) + .findOneBy({ hash: args.hash }) + if (!credentialEntity) throw new Error('not_found: Verifiable credential not found') + + return credentialEntity.raw } async dataStoreSaveVerifiablePresentation(args: IDataStoreSaveVerifiablePresentationArgs): Promise { - const verifiablePresentation = await (await this.dbConnection) + const verifiablePresentation = await (await getConnectedDb(this.dbConnection)) .getRepository(Presentation) .save(createPresentationEntity(args.verifiablePresentation)) return verifiablePresentation.hash @@ -124,15 +119,11 @@ export class DataStore implements IAgentPlugin { async dataStoreGetVerifiablePresentation( args: IDataStoreGetVerifiablePresentationArgs, ): Promise { - try { - const presentationEntity = await (await this.dbConnection) - .getRepository(Presentation) - .findOneBy({ hash: args.hash }) - if (!presentationEntity) throw new Error('Verifiable presentation not found') - - return presentationEntity.raw - } catch (e) { - throw Error('Verifiable presentation not found') - } + const presentationEntity = await (await getConnectedDb(this.dbConnection)) + .getRepository(Presentation) + .findOneBy({ hash: args.hash }) + if (!presentationEntity) throw new Error('not_found: Verifiable presentation not found') + + return presentationEntity.raw } } diff --git a/packages/data-store/src/identifier/did-store.ts b/packages/data-store/src/identifier/did-store.ts index bbb50aad1..5d8310644 100644 --- a/packages/data-store/src/identifier/did-store.ts +++ b/packages/data-store/src/identifier/did-store.ts @@ -4,10 +4,12 @@ import { Identifier } from '../entities/identifier' import { Credential } from '../entities/credential' import { Key } from '../entities/key' import { Service } from '../entities/service' -import { Connection, In, IsNull, Not } from 'typeorm' +import { DataSource, IsNull, Not } from 'typeorm' import Debug from 'debug' import { Presentation } from '../entities/presentation' +import { OrPromise } from "@veramo/utils"; +import { getConnectedDb } from "../utils"; const debug = Debug('veramo:typeorm:identifier-store') @@ -24,15 +26,15 @@ const debug = Debug('veramo:typeorm:identifier-store') * @public */ export class DIDStore extends AbstractDIDStore { - constructor(private dbConnection: Promise) { + constructor(private dbConnection: OrPromise) { super() } async get({ - did, - alias, - provider, - }: { + did, + alias, + provider, + }: { did: string alias: string provider: string @@ -46,7 +48,7 @@ export class DIDStore extends AbstractDIDStore { throw Error('[veramo:data-store:identifier-store] Get requires did or (alias and provider)') } - const identifier = await (await this.dbConnection).getRepository(Identifier).findOne({ + const identifier = await (await getConnectedDb(this.dbConnection)).getRepository(Identifier).findOne({ where, relations: ['keys', 'services'], }) @@ -75,7 +77,7 @@ export class DIDStore extends AbstractDIDStore { } async delete({ did }: { did: string }) { - const identifier = await (await this.dbConnection).getRepository(Identifier).findOne({ + const identifier = await (await getConnectedDb(this.dbConnection)).getRepository(Identifier).findOne({ where: { did }, relations: ['keys', 'services', 'issuedCredentials', 'issuedPresentations'], }) @@ -89,23 +91,23 @@ export class DIDStore extends AbstractDIDStore { delete key.identifier return key }) - await (await this.dbConnection).getRepository(Key).save(existingKeys) + await (await getConnectedDb(this.dbConnection)).getRepository(Key).save(existingKeys) if (identifier.issuedCredentials || typeof identifier.issuedCredentials !== 'undefined') { - await (await this.dbConnection).getRepository(Credential).remove(identifier.issuedCredentials) + await (await getConnectedDb(this.dbConnection)).getRepository(Credential).remove(identifier.issuedCredentials) } if (identifier.issuedPresentations || typeof identifier.issuedPresentations !== 'undefined') { - await (await this.dbConnection).getRepository(Presentation).remove(identifier.issuedPresentations) + await (await getConnectedDb(this.dbConnection)).getRepository(Presentation).remove(identifier.issuedPresentations) } //delete existing services that are no longer tied to this identifier let oldServices = identifier.services - const srvRepo = await (await this.dbConnection).getRepository(Service).remove(oldServices) + const srvRepo = await (await getConnectedDb(this.dbConnection)).getRepository(Service).remove(oldServices) if (!identifier) throw Error('Identifier not found') debug('Deleting', did) - await (await this.dbConnection).getRepository(Identifier).remove(identifier) + await (await getConnectedDb(this.dbConnection)).getRepository(Identifier).remove(identifier) return true } @@ -141,7 +143,7 @@ export class DIDStore extends AbstractDIDStore { identifier.services.push(service) } - await (await this.dbConnection).getRepository(Identifier).save(identifier) + await (await getConnectedDb(this.dbConnection)).getRepository(Identifier).save(identifier) debug('Saving', args.did) return true @@ -152,7 +154,7 @@ export class DIDStore extends AbstractDIDStore { if (args?.alias) { where['alias'] = args.alias } - const identifiers = await (await this.dbConnection).getRepository(Identifier).find({ + const identifiers = await (await getConnectedDb(this.dbConnection)).getRepository(Identifier).find({ where, relations: ['keys', 'services'], }) diff --git a/packages/data-store/src/identifier/key-store.ts b/packages/data-store/src/identifier/key-store.ts index a3c7a4b8d..e545e0ffb 100644 --- a/packages/data-store/src/identifier/key-store.ts +++ b/packages/data-store/src/identifier/key-store.ts @@ -1,10 +1,12 @@ import { IKey, ManagedKeyInfo } from '@veramo/core' import { AbstractKeyStore } from '@veramo/key-manager' -import { Connection } from 'typeorm' +import { DataSource } from 'typeorm' import { Key } from '../entities/key' import Debug from 'debug' +import { OrPromise } from "@veramo/utils"; +import { getConnectedDb } from "../utils"; const debug = Debug('veramo:typeorm:key-store') /** @@ -21,21 +23,21 @@ const debug = Debug('veramo:typeorm:key-store') * @public */ export class KeyStore extends AbstractKeyStore { - constructor(private dbConnection: Promise) { + constructor(private dbConnection: OrPromise) { super() } async get({ kid }: { kid: string }): Promise { - const key = await (await this.dbConnection).getRepository(Key).findOneBy({ kid }) + const key = await (await getConnectedDb(this.dbConnection)).getRepository(Key).findOneBy({ kid }) if (!key) throw Error('Key not found') return key as IKey } async delete({ kid }: { kid: string }) { - const key = await (await this.dbConnection).getRepository(Key).findOneBy({ kid }) + const key = await (await getConnectedDb(this.dbConnection)).getRepository(Key).findOneBy({ kid }) if (!key) throw Error('Key not found') debug('Deleting key', kid) - await (await this.dbConnection).getRepository(Key).remove(key) + await (await getConnectedDb(this.dbConnection)).getRepository(Key).remove(key) return true } @@ -47,12 +49,12 @@ export class KeyStore extends AbstractKeyStore { key.kms = args.kms key.meta = args.meta debug('Saving key', args.kid) - await (await this.dbConnection).getRepository(Key).save(key) + await (await getConnectedDb(this.dbConnection)).getRepository(Key).save(key) return true } async list(args: {} = {}): Promise { - const keys = await (await this.dbConnection).getRepository(Key).find() + const keys = await (await getConnectedDb(this.dbConnection)).getRepository(Key).find() const managedKeys: ManagedKeyInfo[] = keys.map((key) => { const { kid, publicKeyHex, type, meta, kms } = key return { kid, publicKeyHex, type, meta, kms } as IKey diff --git a/packages/data-store/src/identifier/private-key-store.ts b/packages/data-store/src/identifier/private-key-store.ts index c14c0bc51..1880c1d8e 100644 --- a/packages/data-store/src/identifier/private-key-store.ts +++ b/packages/data-store/src/identifier/private-key-store.ts @@ -1,9 +1,11 @@ import { AbstractSecretBox, AbstractPrivateKeyStore } from '@veramo/key-manager' -import { Connection } from 'typeorm' +import { DataSource } from 'typeorm' import { ImportablePrivateKey, ManagedPrivateKey } from '@veramo/key-manager' import { PrivateKey } from '../entities/private-key' import { v4 as uuid4 } from 'uuid' import Debug from 'debug' +import { OrPromise } from "@veramo/utils"; +import { getConnectedDb } from "../utils"; const debug = Debug('veramo:typeorm:key-store') @@ -17,7 +19,7 @@ const debug = Debug('veramo:typeorm:key-store') * @public */ export class PrivateKeyStore extends AbstractPrivateKeyStore { - constructor(private dbConnection: Promise, private secretBox?: AbstractSecretBox) { + constructor(private dbConnection: OrPromise, private secretBox?: AbstractSecretBox) { super() if (!secretBox) { console.warn('Please provide SecretBox to the KeyStore') @@ -25,7 +27,7 @@ export class PrivateKeyStore extends AbstractPrivateKeyStore { } async get({ alias }: { alias: string }): Promise { - const key = await (await this.dbConnection).getRepository(PrivateKey).findOneBy({ alias }) + const key = await (await getConnectedDb(this.dbConnection)).getRepository(PrivateKey).findOneBy({ alias }) if (!key) throw Error('Key not found') if (this.secretBox && key.privateKeyHex) { key.privateKeyHex = await this.secretBox.decrypt(key.privateKeyHex) @@ -34,10 +36,10 @@ export class PrivateKeyStore extends AbstractPrivateKeyStore { } async delete({ alias }: { alias: string }) { - const key = await (await this.dbConnection).getRepository(PrivateKey).findOneBy({ alias }) + const key = await (await getConnectedDb(this.dbConnection)).getRepository(PrivateKey).findOneBy({ alias }) if (!key) throw Error(`not_found: Private Key data not found for alias=${alias}`) debug('Deleting private key data', alias) - await (await this.dbConnection).getRepository(PrivateKey).remove(key) + await (await getConnectedDb(this.dbConnection)).getRepository(PrivateKey).remove(key) return true } @@ -50,7 +52,7 @@ export class PrivateKeyStore extends AbstractPrivateKeyStore { } key.type = args.type debug('Saving private key data', args.alias) - const keyRepo = await (await this.dbConnection).getRepository(PrivateKey) + const keyRepo = await (await getConnectedDb(this.dbConnection)).getRepository(PrivateKey) const existingKey = await keyRepo.findOneBy({ alias: key.alias }) if (existingKey && existingKey.privateKeyHex !== key.privateKeyHex) { throw new Error( @@ -62,7 +64,7 @@ export class PrivateKeyStore extends AbstractPrivateKeyStore { } async list(): Promise> { - const keys = await (await this.dbConnection).getRepository(PrivateKey).find() + const keys = await (await getConnectedDb(this.dbConnection)).getRepository(PrivateKey).find() return keys } } diff --git a/packages/data-store/src/migrations/2.simplifyRelations.ts b/packages/data-store/src/migrations/2.simplifyRelations.ts index e85857e44..9e353fb27 100644 --- a/packages/data-store/src/migrations/2.simplifyRelations.ts +++ b/packages/data-store/src/migrations/2.simplifyRelations.ts @@ -1,6 +1,5 @@ import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm' import Debug from 'debug' -const debug = Debug('veramo:data-store:initial-migration') /** * Fix inconsistencies between Entity data and column data. diff --git a/packages/data-store/src/migrations/4.allowNullVPIssuanceDate.ts b/packages/data-store/src/migrations/4.allowNullVPIssuanceDate.ts index b0b5962e5..bfe134393 100644 --- a/packages/data-store/src/migrations/4.allowNullVPIssuanceDate.ts +++ b/packages/data-store/src/migrations/4.allowNullVPIssuanceDate.ts @@ -1,4 +1,4 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm' +import { MigrationInterface, QueryRunner } from 'typeorm' import { Presentation } from '..' import Debug from 'debug' diff --git a/packages/data-store/src/utils.ts b/packages/data-store/src/utils.ts new file mode 100644 index 000000000..0eed31a00 --- /dev/null +++ b/packages/data-store/src/utils.ts @@ -0,0 +1,17 @@ +import { DataSource } from 'typeorm' +import { OrPromise } from "@veramo/utils"; + +/** + * Ensures that the provided DataSource is connected. + * + * @param dbConnection - a TypeORM DataSource or a Promise that resolves to a DataSource + */ +export async function getConnectedDb(dbConnection: OrPromise): Promise { + if (dbConnection instanceof Promise) { + return await dbConnection + } else if (!dbConnection.isInitialized) { + return await (dbConnection).initialize() + } else { + return dbConnection + } +} diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index b6593bdbe..065f722a5 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -11,6 +11,7 @@ "dependencies": { "@veramo/core": "^3.1.0", "@veramo/data-store-json": "^3.1.0", + "@veramo/did-discovery": "^3.1.0", "@veramo/did-manager": "^3.1.0", "@veramo/key-manager": "^3.1.0", "@veramo/utils": "^3.1.0", diff --git a/packages/test-utils/src/broken-did-discovery.ts b/packages/test-utils/src/broken-did-discovery.ts new file mode 100644 index 000000000..9b0d2a862 --- /dev/null +++ b/packages/test-utils/src/broken-did-discovery.ts @@ -0,0 +1,23 @@ +import { IAgentContext, } from '@veramo/core' +import { + AbstractDidDiscoveryProvider, + IDIDDiscoveryDiscoverDidArgs, + IDIDDiscoveryProviderResult +} from "@veramo/did-discovery"; + +/** + * A DID Discovery provider that throws an error for a particular query, used to test error handling. + */ +export class BrokenDiscoveryProvider implements AbstractDidDiscoveryProvider { + readonly name = 'broken-discovery' + + async discoverDid( + args: IDIDDiscoveryDiscoverDidArgs, + context: IAgentContext, + ): Promise { + if (args.query.match(/broken/)) { + throw new Error(`test_error: let's see how the plugin handles provider errors`) + } + return { matches: [], provider: this.name } + } +} diff --git a/packages/test-utils/src/index.ts b/packages/test-utils/src/index.ts index e117ba8f3..9c848fa45 100644 --- a/packages/test-utils/src/index.ts +++ b/packages/test-utils/src/index.ts @@ -7,3 +7,4 @@ */ export * from './fake-did' +export * from './broken-did-discovery' diff --git a/packages/test-utils/tsconfig.json b/packages/test-utils/tsconfig.json index e81205398..abe4d041d 100644 --- a/packages/test-utils/tsconfig.json +++ b/packages/test-utils/tsconfig.json @@ -8,7 +8,9 @@ "references": [ { "path": "../core" }, { "path": "../data-store-json" }, + { "path": "../did-discovery" }, { "path": "../did-manager" }, { "path": "../key-manager" }, + { "path": "../utils" }, ] }