From 4fc587cf07a56b2065c7c6beec2345001f5a5f40 Mon Sep 17 00:00:00 2001 From: Mircea Nistor Date: Wed, 30 Jun 2021 18:17:07 +0300 Subject: [PATCH] feat: add fake did method usable in tests --- __tests__/localAgent.test.ts | 3 + __tests__/localMemoryStoreAgent.test.ts | 3 + __tests__/restAgent.test.ts | 6 +- __tests__/shared/didManager.ts | 2 +- __tests__/shared/resolveDid.ts | 66 +++++++++- __tests__/utils/fake-did.ts | 146 ++++++++++++++++++++++ packages/did-provider-key/src/resolver.ts | 1 - yarn.lock | 10 ++ 8 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 __tests__/utils/fake-did.ts diff --git a/__tests__/localAgent.test.ts b/__tests__/localAgent.test.ts index 803937b20..e76e9aeb7 100644 --- a/__tests__/localAgent.test.ts +++ b/__tests__/localAgent.test.ts @@ -55,6 +55,7 @@ import didManager from './shared/didManager' import didComm from './shared/didcomm' import messageHandler from './shared/messageHandler' import didDiscovery from './shared/didDiscovery' +import { FakeDidProvider, FakeDidResolver } from './utils/fake-did' const databaseFile = 'local-database.sqlite' const infuraProjectId = '5ffc47f65c4042ce847ef66a3fa70d4c' @@ -130,6 +131,7 @@ const setup = async (options?: IAgentOptions): Promise => { 'did:key': new KeyDIDProvider({ defaultKms: 'local', }), + 'did:fake': new FakeDidProvider(), }, }), new DIDResolverPlugin({ @@ -137,6 +139,7 @@ const setup = async (options?: IAgentOptions): Promise => { ...ethrDidResolver({ infuraProjectId }), ...webDidResolver(), ...getDidKeyResolver(), + ...new FakeDidResolver(() => agent).getDidFakeResolver(), }), }), new DataStore(dbConnection), diff --git a/__tests__/localMemoryStoreAgent.test.ts b/__tests__/localMemoryStoreAgent.test.ts index 9bb982a97..af56aa95c 100644 --- a/__tests__/localMemoryStoreAgent.test.ts +++ b/__tests__/localMemoryStoreAgent.test.ts @@ -45,6 +45,7 @@ import keyManager from './shared/keyManager' import didManager from './shared/didManager' import didComm from './shared/didcomm' import messageHandler from './shared/messageHandler' +import { FakeDidProvider, FakeDidResolver } from './utils/fake-did' const databaseFile = 'local-database2.sqlite' const infuraProjectId = '5ffc47f65c4042ce847ef66a3fa70d4c' @@ -118,6 +119,7 @@ const setup = async (options?: IAgentOptions): Promise => { 'did:key': new KeyDIDProvider({ defaultKms: 'local', }), + 'did:fake': new FakeDidProvider(), }, }), new DIDResolverPlugin({ @@ -125,6 +127,7 @@ const setup = async (options?: IAgentOptions): Promise => { ...ethrDidResolver({ infuraProjectId }), ...webDidResolver(), ...getDidKeyResolver(), + ...new FakeDidResolver(() => agent).getDidFakeResolver(), }), }), new DataStore(dbConnection), diff --git a/__tests__/restAgent.test.ts b/__tests__/restAgent.test.ts index d6581e128..ff0072b8c 100644 --- a/__tests__/restAgent.test.ts +++ b/__tests__/restAgent.test.ts @@ -9,6 +9,7 @@ import { IDataStore, IMessageHandler, IAgentOptions, + TAgent, } from '../packages/core/src' import { MessageHandler } from '../packages/message-handler/src' import { KeyManager } from '../packages/key-manager/src' @@ -45,6 +46,7 @@ import { getResolver as ethrDidResolver } from 'ethr-did-resolver' import { getResolver as webDidResolver } from 'web-did-resolver' import { IDIDDiscovery, DIDDiscovery } from '../packages/did-discovery' import { getUniversalResolver } from '../packages/did-resolver/src/universal-resolver' +import { FakeDidProvider, FakeDidResolver } from './utils/fake-did' import fs from 'fs' @@ -137,13 +139,15 @@ const setup = async (options?: IAgentOptions): Promise => { 'did:key': new KeyDIDProvider({ defaultKms: 'local', }), + 'did:fake': new FakeDidProvider(), }, }), new DIDResolverPlugin({ resolver: new Resolver({ ...ethrDidResolver({ infuraProjectId }), ...webDidResolver(), - key: getUniversalResolver(), // resolve using remote resolver + key: getUniversalResolver(), // resolve using remote resolver, + ...new FakeDidResolver(() => serverAgent as TAgent).getDidFakeResolver(), }), }), new DataStore(dbConnection), diff --git a/__tests__/shared/didManager.ts b/__tests__/shared/didManager.ts index 442001381..0b88d2e95 100644 --- a/__tests__/shared/didManager.ts +++ b/__tests__/shared/didManager.ts @@ -19,7 +19,7 @@ export default (testContext: { it('should get providers', async () => { const providers = await agent.didManagerGetProviders() - expect(providers).toEqual(['did:ethr', 'did:ethr:rinkeby', 'did:web', 'did:key']) + expect(providers).toEqual(['did:ethr', 'did:ethr:rinkeby', 'did:web', 'did:key', 'did:fake']) }) let identifier: IIdentifier diff --git a/__tests__/shared/resolveDid.ts b/__tests__/shared/resolveDid.ts index f430a7e0f..3c10e46ef 100644 --- a/__tests__/shared/resolveDid.ts +++ b/__tests__/shared/resolveDid.ts @@ -1,6 +1,7 @@ +import { IDIDManager } from '@veramo/core' import { TAgent, IResolver, IAgentOptions } from '../../packages/core/src' -type ConfiguredAgent = TAgent +type ConfiguredAgent = TAgent export default (testContext: { getAgent: (options?: IAgentOptions) => ConfiguredAgent @@ -30,6 +31,69 @@ export default (testContext: { expect(didDoc?.id).toEqual(didUrl) }) + it('should resolve imported fake did', async () => { + const did = 'did:fake:myfakedid' + const importedFakeDID = await agent.didManagerImport({ + did, + keys: [ + { + type: 'Ed25519', + kid: 'fake-key-1', + publicKeyHex: '1fe9b397c196ab33549041b29cf93be29b9f2bdd27322f05844112fad97ff92a', + privateKeyHex: + 'b57103882f7c66512dc96777cbafbeb2d48eca1e7a867f5a17a84e9a6740f7dc1fe9b397c196ab33549041b29cf93be29b9f2bdd27322f05844112fad97ff92a', + kms: 'local', + }, + ], + services: [ + { + id: 'fake-service-1', + type: 'fakeService', + serviceEndpoint: 'http://it.is.fake.all.the.way.down', + }, + ], + provider: 'did:fake', + alias: 'faker', + }) + const resolved = await agent.resolveDid({ didUrl: did }) + expect(resolved.didDocument).toEqual({ + id: 'did:fake:myfakedid', + service: [ + { + id: 'did:fake:myfakedid#fake-service-1', + type: 'fakeService', + serviceEndpoint: 'http://it.is.fake.all.the.way.down', + }, + ], + verificationMethod: [ + { + type: 'Ed25519VerificationKey2018', + publicKeyHex: '1fe9b397c196ab33549041b29cf93be29b9f2bdd27322f05844112fad97ff92a', + kms: 'local', + controller: 'did:fake:myfakedid', + id: 'did:fake:myfakedid#fake-key-1', + }, + ], + keyAgreement: ['did:fake:myfakedid#fake-key-1'], + authentication: ['did:fake:myfakedid#fake-key-1'], + assertionMethod: ['did:fake:myfakedid#fake-key-1'], + }) + }) + + it('should resolve created fake did', async () => { + const alias = 'allfake' + const did = `did:fake:${alias}` + const createdDID = await agent.didManagerCreate({ alias, provider: 'did:fake' }) + const modified = await agent.didManagerAddService({ + did, + service: { id: 'fake-service-x', type: 'FakeService', serviceEndpoint: 'none' }, + }) + const resolved = await agent.resolveDid({ didUrl: did }) + expect(resolved?.didDocument?.service).toEqual([ + { id: `${did}#fake-service-x`, type: 'FakeService', serviceEndpoint: 'none' }, + ]) + }) + it('should return an error for unsupported did methods', async () => { expect.assertions(1) await expect(agent.resolveDid({ didUrl: 'did:foo:bar' })).resolves.toEqual({ diff --git a/__tests__/utils/fake-did.ts b/__tests__/utils/fake-did.ts new file mode 100644 index 000000000..469ad5e16 --- /dev/null +++ b/__tests__/utils/fake-did.ts @@ -0,0 +1,146 @@ +import { IAgentContext, IKeyManager, IIdentifier, IKey, IService, IDIDManager } from '@veramo/core' +import { AbstractIdentifierProvider } from '../../packages/did-manager/src/index' +import { + DIDResolutionOptions, + DIDResolutionResult, + DIDResolver, + Resolvable, + ParsedDID, + VerificationMethod, +} from 'did-resolver' +import { TAgent } from '@veramo/core/src' +import { _NormalizedVerificationMethod } from '../../packages/did-comm/src' + +/** + * A DID method that uses the information stored by the DID manager to resolve + */ +export class FakeDidProvider extends AbstractIdentifierProvider { + private defaultKms: string + + constructor({ defaultKms }: { defaultKms: string } = { defaultKms: 'local' }) { + super() + this.defaultKms = defaultKms + } + + async createIdentifier( + { kms, alias, options }: { kms?: string; alias?: string; options?: any }, + context: IAgentContext, + ): Promise> { + const key = await context.agent.keyManagerCreate({ + kms: kms || this.defaultKms, + type: options?.type || 'Secp256k1', + }) + + const identifier: Omit = { + did: 'did:fake:' + alias, + controllerKeyId: key.kid, + keys: [key], + services: [], + } + return identifier + } + + async deleteIdentifier(identifier: IIdentifier, context: IAgentContext): Promise { + for (const { kid } of identifier.keys) { + await context.agent.keyManagerDelete({ kid }) + } + return true + } + + async addKey( + { identifier, key, options }: { identifier: IIdentifier; key: IKey; options?: any }, + context: IAgentContext, + ): Promise { + return { success: true } + } + + async addService( + { identifier, service, options }: { identifier: IIdentifier; service: IService; options?: any }, + context: IAgentContext, + ): Promise { + return { success: true } + } + + async removeKey( + args: { identifier: IIdentifier; kid: string; options?: any }, + context: IAgentContext, + ): Promise { + return { success: true } + } + + async removeService( + args: { identifier: IIdentifier; id: string; options?: any }, + context: IAgentContext, + ): Promise { + return { success: true } + } +} + +export class FakeDidResolver { + getAgent: () => TAgent + + constructor(getAgent: () => TAgent) { + this.getAgent = getAgent + } + + resolveFakeDid: DIDResolver = async ( + didUrl: string, + _parsed: ParsedDID, + _resolver: Resolvable, + options: DIDResolutionOptions, + ): Promise => { + try { + const agent = this.getAgent() + const identifier = await agent.didManagerGet({ did: _parsed.did }) + const did = _parsed.did + const verificationMethod: VerificationMethod[] = identifier.keys.map((key) => { + const vm: _NormalizedVerificationMethod = { ...key, controller: did, id: `${did}#${key.kid}` } + switch (key.type) { + case 'Secp256k1': + vm.type = 'EcdsaSecp256k1VerificationKey2019' + break + case 'Ed25519': + vm.type = 'Ed25519VerificationKey2018' + break + case 'X25519': + vm.type = 'X25519KeyAgreementKey2019' + break + default: + break + } + const { meta, description, kid, ...result } = vm as any + return result + }) + const vmIds = verificationMethod.map((vm) => vm.id) + const service = identifier.services.map(service => { + service.id = `${did}#${service.id}` + delete service.description + return service + }) + + const didResolution: DIDResolutionResult = { + didResolutionMetadata: {}, + didDocument: { + id: did, + service, + verificationMethod, + keyAgreement: vmIds, + authentication: vmIds, + assertionMethod: vmIds, + }, + didDocumentMetadata: {}, + } + return didResolution + } catch (err) { + return { + didDocumentMetadata: {}, + didResolutionMetadata: { error: 'invalidDid', message: err.toString() }, + didDocument: null, + } + } + } + + getDidFakeResolver() { + return { fake: this.resolveFakeDid.bind(this) } + } +} diff --git a/packages/did-provider-key/src/resolver.ts b/packages/did-provider-key/src/resolver.ts index 2b0378be8..ba4eefa07 100644 --- a/packages/did-provider-key/src/resolver.ts +++ b/packages/did-provider-key/src/resolver.ts @@ -1,5 +1,4 @@ import { resolver } from '@transmute/did-key.js' -import { DIDDocument } from '@veramo/core' import { DIDResolutionOptions, DIDResolutionResult, DIDResolver, ParsedDID, Resolvable } from 'did-resolver' const resolve: DIDResolver = async ( diff --git a/yarn.lock b/yarn.lock index 4447771a8..38dba91ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2926,6 +2926,11 @@ "@types/keygrip" "*" "@types/node" "*" +"@types/debug@4.1.5": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" + integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== + "@types/debug@4.1.6": version "4.1.6" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.6.tgz#0b7018723084918a865eff99249c490505df2163" @@ -11983,6 +11988,11 @@ typeorm@0.2.34: yargs "^16.2.0" zen-observable-ts "^1.0.0" +typescript@4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.4.tgz#3f85b986945bcf31071decdd96cf8bfa65f9dcbc" + integrity sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew== + typescript@4.3.5, typescript@~4.3.4: version "4.3.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"