diff --git a/packages/credential-eip712/src/agent/CredentialEIP712.ts b/packages/credential-eip712/src/agent/CredentialEIP712.ts index 408d9defa..9a86bf527 100644 --- a/packages/credential-eip712/src/agent/CredentialEIP712.ts +++ b/packages/credential-eip712/src/agent/CredentialEIP712.ts @@ -29,7 +29,7 @@ import { IRequiredContext, IVerifyCredentialEIP712Args, IVerifyPresentationEIP712Args, -} from '../types/ICredentialEIP712' +} from '../types/ICredentialEIP712.js' import { getEthTypesFromInputDoc } from 'eip-712-types-generation' diff --git a/packages/credential-status/package.json b/packages/credential-status/package.json index 0cfae1f20..a99059e1c 100644 --- a/packages/credential-status/package.json +++ b/packages/credential-status/package.json @@ -12,7 +12,7 @@ "dependencies": { "@veramo/core-types": "workspace:^", "@veramo/utils": "workspace:^", - "credential-status": "^2.0.5", + "credential-status": "^3.0.0", "did-jwt": "^8.0.0", "did-resolver": "^4.1.0" }, diff --git a/packages/did-discovery/src/action-handler.ts b/packages/did-discovery/src/action-handler.ts index 5b39b1f26..84afecb59 100644 --- a/packages/did-discovery/src/action-handler.ts +++ b/packages/did-discovery/src/action-handler.ts @@ -5,7 +5,7 @@ import { IDIDDiscoveryDiscoverDidArgs, IDIDDiscoveryProviderResult, IDIDDiscoveryDiscoverDidResult, -} from './types' +} from './types.js' import { AbstractDidDiscoveryProvider } from './abstract-did-discovery-provider.js' import { schema } from './plugin.schema.js' import Debug from 'debug' diff --git a/packages/did-provider-key/package.json b/packages/did-provider-key/package.json index fbcd78953..dfac1c27b 100644 --- a/packages/did-provider-key/package.json +++ b/packages/did-provider-key/package.json @@ -10,9 +10,6 @@ "extract-api": "node ../cli/bin/veramo.js dev extract-api" }, "dependencies": { - "@transmute/did-key-ed25519": "^0.3.0-unstable.10", - "@transmute/did-key-secp256k1": "^0.3.0-unstable.10", - "@transmute/did-key-x25519": "^0.3.0-unstable.10", "@veramo/core-types": "workspace:^", "@veramo/did-manager": "workspace:^", "@veramo/utils": "workspace:^", diff --git a/packages/did-provider-key/src/__tests__/key.resolver.test.ts b/packages/did-provider-key/src/__tests__/key.resolver.test.ts new file mode 100644 index 000000000..a53523f11 --- /dev/null +++ b/packages/did-provider-key/src/__tests__/key.resolver.test.ts @@ -0,0 +1,526 @@ +import { Resolver } from 'did-resolver' +import { getDidKeyResolver } from '../resolver.js' + +const resolver = new Resolver(getDidKeyResolver()) + +describe('did:key resolver', () => { + describe('Ed25519', () => { + it('should resolve with defaults', async () => { + const sigMultibase = 'z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK' + const encMultibase = 'z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'JsonWebKey2020', + controller: did, + publicKeyJwk: { + alg: 'EdDSA', + crv: 'Ed25519', + kty: 'OKP', + use: 'sig', + x: 'Lm_M42cB3HkUiODQsXRcweM6TByfzEHGO9ND274JcOY', + }, + }, + { + id: `${did}#${encMultibase}`, + type: 'JsonWebKey2020', + controller: did, + publicKeyJwk: { + alg: 'ECDH-ES', + crv: 'X25519', + kty: 'OKP', + use: 'enc', + x: 'bl_3kgKpz9jgsg350CNuHa_kQL3B60Gi-98WmdQW2h8', + }, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + keyAgreement: [`${did}#${encMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/jws-2020/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with Multikey', async () => { + const sigMultibase = 'z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK' + const encMultibase = 'z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'Multikey' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'Multikey', + controller: did, + publicKeyMultibase: sigMultibase, + }, + { + id: `${did}#${encMultibase}`, + type: 'Multikey', + controller: did, + publicKeyMultibase: encMultibase, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + keyAgreement: [`${did}#${encMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/multikey/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with 2020 suite', async () => { + const sigMultibase = 'z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK' + const encMultibase = 'z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'Ed25519VerificationKey2020' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'Ed25519VerificationKey2020', + controller: did, + publicKeyMultibase: sigMultibase, + }, + { + id: `${did}#${encMultibase}`, + type: 'X25519KeyAgreementKey2020', + controller: did, + publicKeyMultibase: encMultibase, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + keyAgreement: [`${did}#${encMultibase}`], + '@context': [ + 'https://www.w3.org/ns/did/v1', + 'https://w3id.org/security/suites/ed25519-2020/v1', + 'https://w3id.org/security/suites/x25519-2020/v1', + ], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with 2018 suite', async () => { + const sigMultibase = 'z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK' + const encMultibase = 'z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'Ed25519VerificationKey2018' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'Ed25519VerificationKey2018', + controller: did, + publicKeyBase58: '48GdbJyVULjHDaBNS6ct9oAGtckZUS5v8asrPzvZ7R1w', + }, + { + id: `${did}#${encMultibase}`, + type: 'X25519KeyAgreementKey2019', + controller: did, + publicKeyBase58: '8RrinpnzRDqzUjzZuHsmNJUYbzsK1eqkQB5e5SgCvKP4', + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + keyAgreement: [`${did}#${encMultibase}`], + '@context': [ + 'https://www.w3.org/ns/did/v1', + 'https://w3id.org/security/suites/ed25519-2018/v1', + 'https://w3id.org/security/suites/x25519-2019/v1', + ], + }, + } + + expect(result).toEqual(expectedResult) + }) + }) + + describe('X25519', () => { + it('should resolve with defaults', async () => { + const encMultibase = 'z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p' + const did = `did:key:${encMultibase}` + const result = await resolver.resolve(did) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${encMultibase}`, + type: 'JsonWebKey2020', + controller: did, + publicKeyJwk: { + alg: 'ECDH-ES', + crv: 'X25519', + kty: 'OKP', + use: 'enc', + x: 'bl_3kgKpz9jgsg350CNuHa_kQL3B60Gi-98WmdQW2h8', + }, + }, + ], + keyAgreement: [`${did}#${encMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/jws-2020/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with Multikey', async () => { + const encMultibase = 'z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p' + const did = `did:key:${encMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'Multikey' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${encMultibase}`, + type: 'Multikey', + controller: did, + publicKeyMultibase: encMultibase, + }, + ], + keyAgreement: [`${did}#${encMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/multikey/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with 2020 suite', async () => { + const encMultibase = 'z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p' + const did = `did:key:${encMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'X25519KeyAgreementKey2020' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${encMultibase}`, + type: 'X25519KeyAgreementKey2020', + controller: did, + publicKeyMultibase: encMultibase, + }, + ], + keyAgreement: [`${did}#${encMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/x25519-2020/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with 2019 suite', async () => { + const encMultibase = 'z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p' + const did = `did:key:${encMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'X25519KeyAgreementKey2019' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${encMultibase}`, + type: 'X25519KeyAgreementKey2019', + controller: did, + publicKeyBase58: '8RrinpnzRDqzUjzZuHsmNJUYbzsK1eqkQB5e5SgCvKP4', + }, + ], + keyAgreement: [`${did}#${encMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/x25519-2019/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + }) + + describe('Secp256k1', () => { + it('should resolve with defaults', async () => { + const sigMultibase = 'zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'JsonWebKey2020', + controller: did, + publicKeyJwk: { + alg: 'ES256K', + crv: 'secp256k1', + kty: 'EC', + use: 'sig', + x: 'h0wVx_2iDlOcblulc8E5iEw1EYh5n1RYtLQfeSTyNc0', + y: 'O2EATIGbu6DezKFptj5scAIRntgfecanVNXxat1rnwE', + }, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/jws-2020/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with Multikey', async () => { + const sigMultibase = 'zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'Multikey' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'Multikey', + controller: did, + publicKeyMultibase: sigMultibase, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/multikey/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with 2020 suite', async () => { + const sigMultibase = 'zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'EcdsaSecp256k1VerificationKey2020' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'EcdsaSecp256k1VerificationKey2020', + controller: did, + publicKeyMultibase: sigMultibase, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/secp256k1-2020/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with 2019 suite', async () => { + const sigMultibase = 'zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'EcdsaSecp256k1VerificationKey2019' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'EcdsaSecp256k1VerificationKey2019', + controller: did, + publicKeyMultibase: sigMultibase, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/secp256k1-2019/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + }) + + describe('P-256', () => { + it('should resolve with defaults', async () => { + const sigMultibase = 'zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'JsonWebKey2020', + controller: did, + publicKeyJwk: { + alg: 'ES256', + crv: 'P-256', + kty: 'EC', + use: 'sig', + x: 'fyNYMN0976ci7xqiSdag3buk-ZCwgXU4kz9XNkBlNUI', + y: 'hW2ojTNfH7Jbi8--CJUo3OCbH3y5n91g-IMA9MLMbTU', + }, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/jws-2020/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with Multikey', async () => { + const sigMultibase = 'zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'Multikey' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'Multikey', + controller: did, + publicKeyMultibase: sigMultibase, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/multikey/v1'], + }, + } + + expect(result).toEqual(expectedResult) + }) + + it('should resolve with 2019 suite', async () => { + const sigMultibase = 'zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169' + const did = `did:key:${sigMultibase}` + const result = await resolver.resolve(did, { publicKeyFormat: 'EcdsaSecp256r1VerificationKey2019' }) + + const expectedResult = { + didDocumentMetadata: { contentType: 'application/did+ld+json' }, + didResolutionMetadata: {}, + didDocument: { + id: did, + verificationMethod: [ + { + id: `${did}#${sigMultibase}`, + type: 'EcdsaSecp256r1VerificationKey2019', + controller: did, + publicKeyJwk: { + alg: 'ES256', + crv: 'P-256', + kty: 'EC', + use: 'sig', + x: 'fyNYMN0976ci7xqiSdag3buk-ZCwgXU4kz9XNkBlNUI', + y: 'hW2ojTNfH7Jbi8--CJUo3OCbH3y5n91g-IMA9MLMbTU', + }, + }, + ], + authentication: [`${did}#${sigMultibase}`], + assertionMethod: [`${did}#${sigMultibase}`], + capabilityDelegation: [`${did}#${sigMultibase}`], + capabilityInvocation: [`${did}#${sigMultibase}`], + '@context': [ + 'https://www.w3.org/ns/did/v1', + { + EcdsaSecp256r1VerificationKey2019: + 'https://w3id.org/security#EcdsaSecp256r1VerificationKey2019', + publicKeyJwk: { + '@id': 'https://w3id.org/security#publicKeyJwk', + '@type': '@json', + }, + }, + ], + }, + } + + expect(result).toEqual(expectedResult) + }) + }) +}) diff --git a/packages/did-provider-key/src/resolver.ts b/packages/did-provider-key/src/resolver.ts index b374f6f8f..9d45bf2b1 100644 --- a/packages/did-provider-key/src/resolver.ts +++ b/packages/did-provider-key/src/resolver.ts @@ -1,28 +1,290 @@ -import { resolve as resolveED25519 } from '@transmute/did-key-ed25519' -import { resolve as resolveX25519 } from '@transmute/did-key-x25519' -import { resolve as resolveSecp256k1 } from '@transmute/did-key-secp256k1' -import { DIDResolutionOptions, DIDResolutionResult, DIDResolver, ParsedDID, Resolvable } from 'did-resolver' +import { + DIDDocument, + DIDResolutionOptions, + DIDResolutionResult, + DIDResolver, + ParsedDID, + Resolvable, + VerificationMethod, +} from 'did-resolver' +import { + bytesToBase58, + bytesToMultibase, + convertEd25519PublicKeyToX25519, + createJWK, + multibaseToBytes, +} from '@veramo/utils' -export const startsWithMap: Record = { - 'did:key:z6Mk': resolveED25519, +enum SupportedVerificationMethods { + 'JsonWebKey2020', + 'Multikey', + 'EcdsaSecp256k1VerificationKey2019', // deprecated, + 'EcdsaSecp256k1VerificationKey2020', + 'Ed25519VerificationKey2020', + 'Ed25519VerificationKey2018', // deprecated, + 'X25519KeyAgreementKey2020', + 'X25519KeyAgreementKey2019', // deprecated, + 'EcdsaSecp256r1VerificationKey2019', +} + +export type DIDKeyResolverOptions = DIDResolutionOptions & { + enableEncryptionKeyDerivation?: boolean // defaults to true + publicKeyFormat?: keyof typeof SupportedVerificationMethods // defaults to 'JsonWebKey2020' + // experimentalPublicKeyFormat?: false // not supported + // defaultContext?: string[] // not supported +} + +const contextFromKeyFormat: Record = { + JsonWebKey2020: 'https://w3id.org/security/suites/jws-2020/v1', + Multikey: 'https://w3id.org/security/multikey/v1', + EcdsaSecp256k1VerificationKey2020: 'https://w3id.org/security/suites/secp256k1-2020/v1', + EcdsaSecp256k1VerificationKey2019: 'https://w3id.org/security/suites/secp256k1-2019/v1', // deprecated + Ed25519VerificationKey2020: 'https://w3id.org/security/suites/ed25519-2020/v1', + Ed25519VerificationKey2018: 'https://w3id.org/security/suites/ed25519-2018/v1', // deprecated + X25519KeyAgreementKey2020: 'https://w3id.org/security/suites/x25519-2020/v1', + X25519KeyAgreementKey2019: 'https://w3id.org/security/suites/x25519-2019/v1', // deprecated + EcdsaSecp256r1VerificationKey2019: { + EcdsaSecp256r1VerificationKey2019: 'https://w3id.org/security#EcdsaSecp256r1VerificationKey2019', + publicKeyJwk: { + '@id': 'https://w3id.org/security#publicKeyJwk', + '@type': '@json', + }, + }, +} + +function resolveECDSA(did: string, options: DIDKeyResolverOptions) { + const publicKeyFormat = options?.publicKeyFormat ?? 'JsonWebKey2020' + const keyMultibase = did.substring(8) + const { keyBytes, keyType } = multibaseToBytes(keyMultibase) + + if (!keyType) { + throw new Error(`invalidDid: the key type cannot be deduced for ${did}`) + } + + const jwkKeyType = keyType === 'P-256' ? 'Secp256r1' : keyType + + let verificationMethod: VerificationMethod = { + id: `${did}#${keyMultibase}`, + type: publicKeyFormat, + controller: did, + } + switch (publicKeyFormat) { + case 'JsonWebKey2020': + case 'EcdsaSecp256r1VerificationKey2019': + verificationMethod.publicKeyJwk = createJWK(jwkKeyType as any, keyBytes, 'sig') + break + case 'Multikey': + case 'EcdsaSecp256k1VerificationKey2019': + case 'EcdsaSecp256k1VerificationKey2020': + verificationMethod.publicKeyMultibase = keyMultibase + break + default: + throw new Error(`invalidPublicKeyType: Unsupported public key format ${publicKeyFormat}`) + } + let ldContext = {} + const acceptedFormat = options.accept ?? 'application/did+ld+json' + if (options.accept === 'application/did+json') { + ldContext = {} + } else if (acceptedFormat === 'application/did+ld+json') { + ldContext = { + '@context': ['https://www.w3.org/ns/did/v1', contextFromKeyFormat[publicKeyFormat]], + } + } else { + throw new Error( + `unsupportedFormat: The DID resolver does not support the requested 'accept' format: ${options.accept}`, + ) + } + + return { + didResolutionMetadata: {}, + didDocumentMetadata: { contentType: options.accept ?? 'application/did+ld+json' }, + didDocument: { + ...ldContext, + id: did, + verificationMethod: [verificationMethod], + authentication: [verificationMethod.id], + assertionMethod: [verificationMethod.id], + capabilityDelegation: [verificationMethod.id], + capabilityInvocation: [verificationMethod.id], + }, + } +} + +function resolveEDDSA(did: string, options: DIDKeyResolverOptions) { + const publicKeyFormat = options?.publicKeyFormat ?? 'JsonWebKey2020' + const keyMultibase = did.substring(8) + const { keyBytes, keyType } = multibaseToBytes(keyMultibase) + + if (!keyType || keyType !== 'Ed25519') { + throw new Error(`invalidDid: the key type cannot be deduced for ${did}`) + } + + let verificationMethod: VerificationMethod = { + id: `${did}#${keyMultibase}`, + type: publicKeyFormat, + controller: did, + } + let keyAgreementKeyFormat: keyof typeof SupportedVerificationMethods = publicKeyFormat + + switch (publicKeyFormat) { + case 'JsonWebKey2020': + verificationMethod.publicKeyJwk = createJWK(keyType as any, keyBytes, 'sig') + break + case 'Multikey': + verificationMethod.publicKeyMultibase = keyMultibase + break + case 'Ed25519VerificationKey2020': + keyAgreementKeyFormat = 'X25519KeyAgreementKey2020' + verificationMethod.publicKeyMultibase = keyMultibase + break + case 'Ed25519VerificationKey2018': + keyAgreementKeyFormat = 'X25519KeyAgreementKey2019' + verificationMethod.publicKeyBase58 = bytesToBase58(keyBytes) + break + default: + throw new Error(`invalidPublicKeyType: Unsupported public key format ${publicKeyFormat}`) + } + const ldContextArray: any[] = ['https://www.w3.org/ns/did/v1', contextFromKeyFormat[publicKeyFormat]] + + const result: DIDResolutionResult = { + didResolutionMetadata: {}, + didDocumentMetadata: { contentType: options.accept ?? 'application/did+ld+json' }, + didDocument: { + id: did, + verificationMethod: [verificationMethod], + authentication: [verificationMethod.id], + assertionMethod: [verificationMethod.id], + capabilityDelegation: [verificationMethod.id], + capabilityInvocation: [verificationMethod.id], + }, + } + + const useEncryptionKey = options.enableEncryptionKeyDerivation ?? true + + if (useEncryptionKey) { + const encryptionKeyBytes = convertEd25519PublicKeyToX25519(keyBytes) + const encryptionKeyMultibase = bytesToMultibase(encryptionKeyBytes, 'base58btc', 'x25519-pub') + const encryptionKey: VerificationMethod = { + id: `${did}#${encryptionKeyMultibase}`, + type: keyAgreementKeyFormat, + controller: did, + } + if (keyAgreementKeyFormat === 'JsonWebKey2020') { + encryptionKey.publicKeyJwk = createJWK('X25519', encryptionKeyBytes, 'enc') + } else if (keyAgreementKeyFormat === 'X25519KeyAgreementKey2019') { + ldContextArray.push(contextFromKeyFormat[keyAgreementKeyFormat]) + encryptionKey.publicKeyBase58 = bytesToBase58(encryptionKeyBytes) + } else { + if (keyAgreementKeyFormat === 'X25519KeyAgreementKey2020') { + ldContextArray.push(contextFromKeyFormat[keyAgreementKeyFormat]) + } + encryptionKey.publicKeyMultibase = encryptionKeyMultibase + } + result.didDocument?.verificationMethod?.push(encryptionKey) + result.didDocument!.keyAgreement = [encryptionKey.id] + } + + let ldContext = {} + const acceptedFormat = options.accept ?? 'application/did+ld+json' + if (options.accept === 'application/did+json') { + ldContext = {} + } else if (acceptedFormat === 'application/did+ld+json') { + ldContext = { + '@context': ldContextArray, + } + } else { + throw new Error( + `unsupportedFormat: The DID resolver does not support the requested 'accept' format: ${options.accept}`, + ) + } + + result.didDocument = { ...result.didDocument, ...ldContext } as DIDDocument + + return result +} + +function resolveX25519(did: string, options: DIDKeyResolverOptions) { + const publicKeyFormat = options?.publicKeyFormat ?? 'JsonWebKey2020' + const keyMultibase = did.substring(8) + const { keyBytes, keyType } = multibaseToBytes(keyMultibase) + + if (!keyType || keyType !== 'X25519') { + throw new Error(`invalidDid: the key type cannot be deduced for ${did}`) + } + + let verificationMethod: VerificationMethod = { + id: `${did}#${keyMultibase}`, + type: publicKeyFormat, + controller: did, + } + + switch (publicKeyFormat) { + case 'JsonWebKey2020': + verificationMethod.publicKeyJwk = createJWK(keyType as any, keyBytes, 'enc') + break + case 'Multikey': + case 'X25519KeyAgreementKey2020': + verificationMethod.publicKeyMultibase = keyMultibase + break + case 'X25519KeyAgreementKey2019': + verificationMethod.publicKeyBase58 = bytesToBase58(keyBytes) + break + default: + throw new Error(`invalidPublicKeyType: Unsupported public key format ${publicKeyFormat}`) + } + const ldContextArray = ['https://www.w3.org/ns/did/v1', contextFromKeyFormat[publicKeyFormat]] + + const result = { + didResolutionMetadata: {}, + didDocumentMetadata: { contentType: options.accept ?? 'application/did+ld+json' }, + didDocument: { + id: did, + verificationMethod: [verificationMethod], + keyAgreement: [verificationMethod.id], + }, + } + + let ldContext = {} + const acceptedFormat = options.accept ?? 'application/did+ld+json' + if (options.accept === 'application/did+json') { + ldContext = {} + } else if (acceptedFormat === 'application/did+ld+json') { + ldContext = { + '@context': ldContextArray, + } + } else { + throw new Error( + `unsupportedFormat: The DID resolver does not support the requested 'accept' format: ${options.accept}`, + ) + } + + result.didDocument = { ...result.didDocument, ...ldContext } + + return result +} + +export const didPrefixMap: Record = { + 'did:key:z6Mk': resolveEDDSA, 'did:key:z6LS': resolveX25519, - 'did:key:zQ3s': resolveSecp256k1, // compressed Secp256k1 keys - 'did:key:z7r8': resolveSecp256k1, // uncompressed Secp256k1 keys + 'did:key:zQ3s': resolveECDSA, // compressed Secp256k1 keys + 'did:key:z7r8': resolveECDSA, // uncompressed Secp256k1 keys + 'did:key:zDn': resolveECDSA, // compressed P-256 keys + // 'did:key:z82': resolveP384, // compressed P-384 keys - not supported yet + // 'did:key:zUC7': resolveBLS12381, // BLS12381 keys - not supported yet } const resolveDidKey: DIDResolver = async ( didUrl: string, _parsed: ParsedDID, _resolver: Resolvable, - options: DIDResolutionOptions, + options: DIDKeyResolverOptions, ): Promise => { try { - const startsWith = _parsed.did.substring(0, 12) - if (startsWithMap[startsWith] !== undefined) { - const didResolution = await startsWithMap[startsWith](didUrl, { - ...options, - enableEncryptionKeyDerivation: true, - }) + const matchedResolver = Object.keys(didPrefixMap) + .filter((prefix) => didUrl.startsWith(prefix)) + .shift() + if (matchedResolver) { + const didResolution = await didPrefixMap[matchedResolver](didUrl, options) return { didDocumentMetadata: {}, didResolutionMetadata: {}, diff --git a/packages/did-provider-peer/src/resolver.ts b/packages/did-provider-peer/src/resolver.ts index 099029b38..ae34ccfe3 100644 --- a/packages/did-provider-peer/src/resolver.ts +++ b/packages/did-provider-peer/src/resolver.ts @@ -1,6 +1,5 @@ -import { DIDDocument, DIDResolutionResult, DIDResolver, ParsedDID } from 'did-resolver' +import { DIDDocument, DIDResolutionResult, DIDResolver, ParsedDID, Service } from 'did-resolver' import { resolve } from '@aviarytech/did-peer' -import { IDIDDocumentServiceDescriptor } from '@aviarytech/did-peer/interfaces.js' /** * Creates a DID Resolver that can resolve Peer DIDs (for the 0 and 2 num_algo values) @@ -24,7 +23,7 @@ export function getResolver(): Record { assertionMethod: doc.assertionMethod, capabilityInvocation: doc.capabilityInvocation, capabilityDelegation: doc.capabilityDelegation, - service: doc.service as IDIDDocumentServiceDescriptor[], + service: doc.service as Service[], } if (doc.alsoKnownAs) { didDocument.alsoKnownAs = [doc.alsoKnownAs] diff --git a/packages/mediation-manager/src/mediation-manager.ts b/packages/mediation-manager/src/mediation-manager.ts index 0af381510..85bdc53f2 100644 --- a/packages/mediation-manager/src/mediation-manager.ts +++ b/packages/mediation-manager/src/mediation-manager.ts @@ -12,7 +12,7 @@ import type { IMediationManagerAddRecipientDidArgs, RecipientDid, IMediationManagerListRecipientDidsArgs, -} from './types/IMediationManager' +} from './types/IMediationManager.js' import type { IAgentPlugin } from '@veramo/core-types' import type { KeyValueStore } from '@veramo/kv-store' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72d9387a7..1350ec704 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -510,8 +510,8 @@ importers: specifier: workspace:^ version: link:../utils credential-status: - specifier: ^2.0.5 - version: 2.0.5 + specifier: ^3.0.0 + version: 3.0.0 did-jwt: specifier: ^8.0.0 version: 8.0.0 @@ -899,15 +899,6 @@ importers: packages/did-provider-key: dependencies: - '@transmute/did-key-ed25519': - specifier: ^0.3.0-unstable.10 - version: 0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0) - '@transmute/did-key-secp256k1': - specifier: ^0.3.0-unstable.10 - version: 0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0) - '@transmute/did-key-x25519': - specifier: ^0.3.0-unstable.10 - version: 0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0) '@veramo/core-types': specifier: workspace:^ version: link:../core-types @@ -7247,27 +7238,6 @@ packages: uri-js: 4.4.1 dev: false - /@did-core/data-model@0.1.1-unstable.15: - resolution: {integrity: sha512-l7gxLxegcXW7389G+j6o+S24lS8uasmJx5txWpW3QadNvOawKwvWn8bV59SdHSK806xNzIZaCLKmXKxebs8yAQ==} - engines: {node: '>=10'} - dependencies: - factory.ts: 0.5.2 - dev: false - - /@did-core/did-ld-json@0.1.1-unstable.15(expo@49.0.21)(react-native@0.73.0): - resolution: {integrity: sha512-p2jKRxSU+eJJqd+ewCklYp/XZ6ysISk8VU2/kANCoB/WwUy/kVgw2rUNScRDXw2utr9Qj36P8EZTYi4aj7vRCQ==} - engines: {node: '>=10'} - dependencies: - '@transmute/did-context': 0.6.1-unstable.37 - jsonld-checker: 0.1.8(expo@49.0.21)(react-native@0.73.0) - transitivePeerDependencies: - - domexception - - encoding - - expo - - react-native - - web-streams-polyfill - dev: false - /@digitalbazaar/bitstring@3.1.0: resolution: {integrity: sha512-Cii+Sl++qaexOvv3vchhgZFfSmtHPNIPzGegaq4ffPnflVXFu+V2qrJ17aL2+gfLxrlC/zazZFuAltyKTPq7eg==} engines: {node: '>=16'} @@ -10599,78 +10569,6 @@ packages: resolution: {integrity: sha512-2cB6UcMKeEK6kqvl5Uhpoe5iUUAcVURlRHl9nVa/Xx2JymNHyBvyXi+CGjIwf/eEk7hsgMIwDfGqq5Mcnbk5cw==} dev: true - /@transmute/did-context@0.6.1-unstable.37: - resolution: {integrity: sha512-p/QnG3QKS4218hjIDgdvJOFATCXsAnZKgy4egqRrJLlo3Y6OaDBg7cA73dixOwUPoEKob0K6rLIGcsCI/L1acw==} - dev: false - - /@transmute/did-key-common@0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0): - resolution: {integrity: sha512-Iryh/HcGIvmTtWFTRaG/JEgbUsqI5OqKqkR2676yQWK4ajLMsyNattz5n0ZfFQk/4U7Ee6pJvvKRduFDAqqV0Q==} - engines: {node: '>=14'} - dependencies: - '@did-core/data-model': 0.1.1-unstable.15 - '@did-core/did-ld-json': 0.1.1-unstable.15(expo@49.0.21)(react-native@0.73.0) - '@transmute/did-context': 0.6.1-unstable.37 - '@transmute/ld-key-pair': 0.6.1-unstable.37 - '@transmute/security-context': 0.6.1-unstable.37 - transitivePeerDependencies: - - domexception - - encoding - - expo - - react-native - - web-streams-polyfill - dev: false - - /@transmute/did-key-ed25519@0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0): - resolution: {integrity: sha512-9QdXl58DjwqBuOJBx6DtvaNW2bZLmVBxMSq2En4RAQcGIz1GGulyEQ1NB7PLIAgnam3LIFxiK6RiQGQTfJmmJg==} - engines: {node: '>=14'} - dependencies: - '@transmute/did-key-common': 0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0) - '@transmute/ed25519-key-pair': 0.6.1-unstable.37 - transitivePeerDependencies: - - domexception - - encoding - - expo - - react-native - - web-streams-polyfill - dev: false - - /@transmute/did-key-secp256k1@0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0): - resolution: {integrity: sha512-C/Gyu2U3NQZ9Gxu4WVwUk8h0ERbY9Z4Kjk0P49p3IQFrWK19XmVXjA+b1RiqffhYzWJ6fH5TPYIt2LW5MRQmUA==} - engines: {node: '>=14'} - dependencies: - '@transmute/did-key-common': 0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0) - '@transmute/secp256k1-key-pair': 0.7.0-unstable.79 - transitivePeerDependencies: - - domexception - - encoding - - expo - - react-native - - web-streams-polyfill - dev: false - - /@transmute/did-key-x25519@0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0): - resolution: {integrity: sha512-Jm5UxwI9EhlfVQ9D0Clj9RlMvhOi8nqAgQG30KMzjFMVGfWqIPwQNZFvmL+XsQ7g3dfTo5iQwXBY0de/f+RoMA==} - engines: {node: '>=14'} - dependencies: - '@transmute/did-key-common': 0.3.0-unstable.10(expo@49.0.21)(react-native@0.73.0) - '@transmute/x25519-key-pair': 0.7.0-unstable.79 - transitivePeerDependencies: - - domexception - - encoding - - expo - - react-native - - web-streams-polyfill - dev: false - - /@transmute/ed25519-key-pair@0.6.1-unstable.37: - resolution: {integrity: sha512-l34yzE/QnQwmdk5xY9g2kD55e4XPp/jTZQzPu7I6J4Ar+bMaL/0RLL/pgvwyI7qUpsddxRf4WPZCCcZveqPcdA==} - engines: {node: '>=10'} - dependencies: - '@stablelib/ed25519': 1.0.3 - '@transmute/ld-key-pair': 0.6.1-unstable.37 - '@transmute/x25519-key-pair': 0.6.1-unstable.37 - dev: false - /@transmute/ed25519-key-pair@0.7.0-unstable.2: resolution: {integrity: sha512-B0jg348Z8F0+lGWQic28xVxBZiXOJYbisWp6EfP4fQdMV3G4sES9YubpdiuoZHjesDZrf6xZ7cEB81mjGJMUkA==} engines: {node: '>=10'} @@ -10747,10 +10645,6 @@ packages: - web-streams-polyfill dev: false - /@transmute/ld-key-pair@0.6.1-unstable.37: - resolution: {integrity: sha512-DcTpEruAQBfOd2laZkg3uCQ+67Y7dw2hsvo42NAQ5tItCIx5AClP7zccri7T2JUcfDUFaE32z/BLTMEKYt3XZQ==} - dev: false - /@transmute/ld-key-pair@0.7.0-unstable.79: resolution: {integrity: sha512-QWpzTQStsoD1Bpif1rMWDGlYq0zzsHExw3As8piy3U+MtJpOYIOUJ60L6NSyFBB8Zq+XNeFJq0/puwzMV2lKog==} engines: {node: '>=16'} @@ -10761,15 +10655,6 @@ packages: engines: {node: '>=16'} dev: false - /@transmute/secp256k1-key-pair@0.7.0-unstable.79: - resolution: {integrity: sha512-Sg9SYya/WMYYT9BDgAS1/wJITJpS1UluUBMk/n3it4YFFqGRrDSDEK9dcEWDHXakv1GfQePpqtuvS2Uv24YgKA==} - engines: {node: '>=16'} - dependencies: - '@bitauth/libauth': 1.19.1 - '@transmute/ld-key-pair': 0.7.0-unstable.79 - secp256k1: 4.0.3 - dev: false - /@transmute/secp256k1-key-pair@0.7.0-unstable.81: resolution: {integrity: sha512-kofomMOOLkdTOAV2bQAEZAC0REuiI/RDqxYJJg/qpXnguyGTtv5DVHD8UXmUDKJLJkAql1lbksfs/roYYVBN7g==} engines: {node: '>=16'} @@ -10779,10 +10664,6 @@ packages: secp256k1: 4.0.3 dev: false - /@transmute/security-context@0.6.1-unstable.37: - resolution: {integrity: sha512-GtLmG65qlORrz/2S4I74DT+vA4+qXsFxrMr0cNOXjUqZBd/AW1PTrFnryLF9907BfoiD58HC9qb1WVGWjSlBYw==} - dev: false - /@transmute/security-context@0.7.0-unstable.81: resolution: {integrity: sha512-5y7N/LIGPl1LtSCWyAlkIK/nDofsxM+AV0GoXuIIXFfgN8jnP9vuCRaMxsUCnoNQ+Aihe0fVNH7PkEm5y9HlKg==} dev: false @@ -10796,14 +10677,6 @@ packages: big-integer: 1.6.51 dev: false - /@transmute/x25519-key-pair@0.6.1-unstable.37: - resolution: {integrity: sha512-j6zR9IoJmgVhUCVH8YVGpsgQf99SxPKZ00LGnUheBAQzgj2lULGBQ44G+GqBCdzfT0qweptTfp1RjqqHEpizeA==} - engines: {node: '>=10'} - dependencies: - '@stablelib/x25519': 1.0.3 - '@transmute/ld-key-pair': 0.6.1-unstable.37 - dev: false - /@transmute/x25519-key-pair@0.7.0-unstable.79: resolution: {integrity: sha512-dcWvq9DgbWpAprS0gosHvifYnmhEotqx9MyYzXLe/EntZFjJcsHffl+KSrRPBupVE82B5NxQnGZKCQeW5E20gA==} engines: {node: '>=16'} @@ -14343,6 +14216,13 @@ packages: did-resolver: 4.1.0 dev: true + /credential-status@3.0.0: + resolution: {integrity: sha512-kCHyxp+dtFVV1wy0auNZXwWWLIUmQTuw6uFLfdm5aRaN5JUWyR2Bv6aHLszB8sxEwRYgL6bqfQAUVCXTWo61jw==} + dependencies: + did-jwt: 8.0.0 + did-resolver: 4.1.0 + dev: false + /credentials-context@2.0.0: resolution: {integrity: sha512-/mFKax6FK26KjgV2KW2D4YqKgoJ5DVJpNt87X2Jc9IxT2HBMy7nEIlc+n7pEi+YFFe721XqrvZPd+jbyyBjsvQ==} dev: false @@ -16358,14 +16238,6 @@ packages: - supports-color dev: true - /factory.ts@0.5.2: - resolution: {integrity: sha512-I4YDKuyMW+s2PocnWh/Ekv9wSStt/MNN1ZRb1qhy0Kv056ndlzbLHDsW9KEmTAqMpLI3BtjSqEdZ7ZfdnaXn9w==} - engines: {node: '>= 14'} - dependencies: - clone-deep: 4.0.1 - source-map-support: 0.5.21 - dev: false - /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -20015,20 +19887,6 @@ packages: optionalDependencies: graceful-fs: 4.2.11 - /jsonld-checker@0.1.8(expo@49.0.21)(react-native@0.73.0): - resolution: {integrity: sha512-jclmnPRrm5SEpaIV6IiSTJxplRAqIWHduQLsUfrYpZM41Ng48m1RN2/aUyHze/ynfO0D2UhlJBt8SdObsH5GBw==} - engines: {node: '>=10'} - dependencies: - jsonld: /@digitalcredentials/jsonld@6.0.0(expo@49.0.21)(react-native@0.73.0) - node-fetch: 2.6.12 - transitivePeerDependencies: - - domexception - - encoding - - expo - - react-native - - web-streams-polyfill - dev: false - /jsonld-signatures@11.2.1(expo@49.0.21)(react-native@0.73.0): resolution: {integrity: sha512-RNaHTEeRrX0jWeidPCwxMq/E/Ze94zFyEZz/v267ObbCHQlXhPO7GtkY6N5PSHQfQhZPXa8NlMBg5LiDF4dNbA==} engines: {node: '>=14'}