Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor @web5/dids to support first class Key Management #393

Merged
merged 39 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
073c0f3
Update Web5 Test Vectors to latest
frankhinek Jan 10, 2024
22c001f
Fix issue with c8 not reporting code coverage and bump version
frankhinek Jan 10, 2024
e17d5e8
Remove unnecessary option in crypto tsconfig and enable strict mode f…
frankhinek Jan 10, 2024
09083b2
Add JWK Set to crypto package
frankhinek Jan 12, 2024
7b51b76
Add did:jwk and did:web implementations
frankhinek Jan 12, 2024
1187a09
Add utility type to @web5/common
frankhinek Jan 15, 2024
b8cd77e
Improve DID Utility functions
frankhinek Jan 15, 2024
b79dfff
Add FixedLengthArray utility type
frankhinek Jan 21, 2024
42bae59
Add support for Base32Z to Convert utility
frankhinek Jan 21, 2024
197181c
Improve JWK type
frankhinek Jan 21, 2024
2da26ee
Add InferKeyGeneratorAlgorithm utility type
frankhinek Jan 21, 2024
cf4cb33
Remove did-resolver dependency
frankhinek Jan 21, 2024
80ae0bd
Temporarily disable old implementations
frankhinek Jan 21, 2024
de2cf33
Update DID JWK and DHT implementations
frankhinek Jan 22, 2024
6eff583
Rename createFromKeys to fromKeys and change default publishing behavior
frankhinek Jan 22, 2024
fcc2796
Update JWK and DHT implementations
frankhinek Jan 24, 2024
0b0693f
Rename DidKeySet to PortableDid and add uri
frankhinek Jan 25, 2024
be13b71
Reorganize tests and reintroduce DidResolver
frankhinek Jan 25, 2024
d14076a
Update package-lock.json
frankhinek Jan 25, 2024
4148742
Rename P256 to Secp256r1 and add minimal tests
frankhinek Jan 25, 2024
53aa79b
Add docs for undocumented methods
frankhinek Jan 25, 2024
00700f7
Finish reintroducing DID resolvers
frankhinek Jan 25, 2024
cfb8a44
Support secp256k1 as an algorithm identifier for generateKey()
frankhinek Jan 26, 2024
43f2507
Improve support for secp256r1
frankhinek Jan 26, 2024
0bfbc5b
Rename to LocalKeyManager & AwsKeyManager and improve docs
frankhinek Jan 26, 2024
b7b8d79
Fix Ed25519.validatePublicKey method signature
frankhinek Jan 27, 2024
11b69ed
Refactor of DID Key
frankhinek Jan 27, 2024
7ec833e
Complete implementation of DID Key
frankhinek Jan 29, 2024
29a27ab
Add KeyCompressor type to @web5/crypto
frankhinek Jan 31, 2024
64120f0
Complete refactor of DidIon
frankhinek Jan 31, 2024
4464e53
Complete adding secp256r1 test vectors
frankhinek Jan 31, 2024
2ebbd77
Remove old dependencies and bump versions
frankhinek Jan 31, 2024
6cb1abb
Resolve package dependency issue
frankhinek Jan 31, 2024
c26d27e
Remove old test-vectors directory
frankhinek Jan 31, 2024
38ba056
Remove references to tags in the XChaCha20Poly1305 comments
frankhinek Jan 31, 2024
258446c
Remove duplication from DidDhtUtils.identifierToIdentityKey()
frankhinek Jan 31, 2024
53b6712
Correct typo in comments
frankhinek Jan 31, 2024
0a97f05
Update crypto README
frankhinek Feb 1, 2024
a3e4448
Correct typo, add DHT test, and remove unused file
frankhinek Feb 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 8 additions & 208 deletions packages/dids/src/did-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,208 +1,8 @@
import type {
DidResource,
DidResolverCache,
DidMethodResolver,
DidResolutionResult,
DidResolutionOptions,
DidDereferencingResult,
DidDereferencingOptions,
} from './types.js';

import { parseDid } from './utils.js';
import { DidResolverCacheNoop } from './resolver-cache-noop.js';

export type DidResolverOptions = {
didResolvers: DidMethodResolver[];
cache?: DidResolverCache;
}

/**
* The `DidResolver` class provides mechanisms for resolving Decentralized Identifiers (DIDs) to
* their corresponding DID documents.
*
* The class is designed to handle various DID methods by utilizing an array of `DidMethodResolver`
* instances, each responsible for a specific DID method. It also employs a caching mechanism to
* store and retrieve previously resolved DID documents for efficiency.
*
* Usage:
* - Construct the `DidResolver` with an array of `DidMethodResolver` instances and an optional cache.
* - Use `resolve` to resolve a DID to its DID Resolution Result.
* - Use `dereference` to extract specific resources from a DID URL, like service endpoints or verification methods.
*
* @example
* ```ts
* const resolver = new DidResolver({
* didResolvers: [<array of DidMethodResolver instances>],
* cache: new DidResolverCacheNoop()
* });
*
* const resolutionResult = await resolver.resolve('did:example:123456');
* const dereferenceResult = await resolver.dereference({ didUrl: 'did:example:123456#key-1' });
* ```
*/
export class DidResolver {
/**
* A cache for storing resolved DID documents.
*/
private cache: DidResolverCache;

/**
* A map to store method resolvers against method names.
*/
private didResolvers: Map<string, DidMethodResolver> = new Map();

/**
* Constructs a new `DidResolver`.
*
* @param options - The options for constructing the `DidResolver`.
* @param options.didResolvers - An array of `DidMethodResolver` instances.
* @param options.cache - Optional. A cache for storing resolved DID documents. If not provided, a no-operation cache is used.
*/
constructor(options: DidResolverOptions) {
this.cache = options.cache || DidResolverCacheNoop;

for (const resolver of options.didResolvers) {
this.didResolvers.set(resolver.methodName, resolver);
}
}

/**
* Resolves a DID to a DID Resolution Result.
* If the DID Resolution Result is present in the cache, it returns the cached
* result. Otherwise, it uses the appropriate method resolver to resolve
* the DID, stores the resolution result in the cache, and returns the
* resolultion result.
*
* Note: The method signature for resolve() in this implementation must match
* the `DidResolver` implementation in
* {@link https://github.com/TBD54566975/dwn-sdk-js | dwn-sdk-js} so that
* Web5 apps and the underlying DWN instance can share the same DID
* resolution cache.
*
* @param didUrl - The DID or DID URL to resolve.
* @returns A promise that resolves to the DID Resolution Result.
*/
async resolve(didUrl: string, resolutionOptions?: DidResolutionOptions): Promise<DidResolutionResult> {

const parsedDid = parseDid({ didUrl });
if (!parsedDid) {
return {
'@context' : 'https://w3id.org/did-resolution/v1',
didDocument : undefined,
didDocumentMetadata : {},
didResolutionMetadata : {
error : 'invalidDid',
errorMessage : `Cannot parse DID: ${didUrl}`
}
};
}

const resolver = this.didResolvers.get(parsedDid.method);
if (!resolver) {
return {
'@context' : 'https://w3id.org/did-resolution/v1',
didDocument : undefined,
didDocumentMetadata : {},
didResolutionMetadata : {
error : 'methodNotSupported',
errorMessage : `Method not supported: ${parsedDid.method}`
}
};
}

const cachedResolutionResult = await this.cache.get(parsedDid.did);

if (cachedResolutionResult) {
return cachedResolutionResult;
} else {
const resolutionResult = await resolver.resolve({
didUrl: parsedDid.did,
resolutionOptions
});

await this.cache.set(parsedDid.did, resolutionResult);

return resolutionResult;
}
}

/**
* Dereferences a DID (Decentralized Identifier) URL to a corresponding DID resource. This method
* interprets the DID URL's components, which include the DID method, method-specific identifier,
* path, query, and fragment, and retrieves the related resource as per the DID Core specifications.
* The dereferencing process involves resolving the DID contained in the DID URL to a DID document,
* and then extracting the specific part of the document identified by the fragment in the DID URL.
* If no fragment is specified, the entire DID document is returned.
*
* This method supports resolution of different components within a DID document such as service
* endpoints and verification methods, based on their IDs. It accommodates both full and
* DID URLs as specified in the DID Core specification.
*
* More information on DID URL dereferencing can be found in the
* {@link https://www.w3.org/TR/did-core/#did-url-dereferencing | DID Core specification}.
*
* @param didUrl - The DID URL string to dereference.
* @param [dereferenceOptions] - Input options to the dereference function. Optional.
* @returns a {@link DidDereferencingResult}
*/
async dereference({ didUrl }: {
didUrl: string,
dereferenceOptions?: DidDereferencingOptions
}): Promise<DidDereferencingResult> {
const { didDocument, didResolutionMetadata = {}, didDocumentMetadata = {} } = await this.resolve(didUrl);
if (didResolutionMetadata.error) {
return {
dereferencingMetadata : { error: 'invalidDidUrl' },
contentStream : null,
contentMetadata : {}
};
}

const parsedDid = parseDid({ didUrl });

// Return the entire DID Document if no fragment is present on the did url
if (!parsedDid.fragment) {
return {
dereferencingMetadata : { contentType: 'application/did+json' },
contentStream : didDocument,
contentMetadata : didDocumentMetadata
};
}

const { service = [], verificationMethod = [] } = didDocument;

// Create a set of possible id matches. The DID spec allows for an id to be the entire
// did#fragment or just #fragment.
// @see {@link }https://www.w3.org/TR/did-core/#relative-did-urls | Section 3.2.2, Relative DID URLs}.
// Using a Set for fast string comparison since some DID methods have long identifiers.
const idSet = new Set([didUrl, parsedDid.fragment, `#${parsedDid.fragment}`]);

let didResource: DidResource;
for (let vm of verificationMethod) {
if (idSet.has(vm.id)) {
didResource = vm;
break;
}
}

for (let svc of service) {
if (idSet.has(svc.id)) {
didResource = svc;
break;
}
}
if (didResource) {
return {
dereferencingMetadata : { contentType: 'application/did+json' },
contentStream : didResource,
contentMetadata : didResolutionMetadata
};
} else {
return {
dereferencingMetadata : { error: 'notFound' },
contentStream : null,
contentMetadata : {},
};
}
}
}
import type { DidResolutionResult } from './types/did-core.js';

export const EMPTY_DID_RESOLUTION_RESULT: DidResolutionResult = {
'@context' : 'https://w3id.org/did-resolution/v1',
didResolutionMetadata : {},
didDocument : null,
didDocumentMetadata : {},
};
Loading