From 7ae9046aa061bce7737169c1fb70a42346713f07 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Fri, 29 Mar 2024 15:22:23 -0700 Subject: [PATCH 01/13] removed duplicate decoded jwt --- packages/web5/lib/src/jwt/jwt_decoded.dart | 26 ---------------------- 1 file changed, 26 deletions(-) delete mode 100644 packages/web5/lib/src/jwt/jwt_decoded.dart diff --git a/packages/web5/lib/src/jwt/jwt_decoded.dart b/packages/web5/lib/src/jwt/jwt_decoded.dart deleted file mode 100644 index 77ff57f..0000000 --- a/packages/web5/lib/src/jwt/jwt_decoded.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:web5/src/jwt/jwt_claims.dart'; -import 'package:web5/src/jwt/jwt_header.dart'; - -/// Represents a decoded JWT, including both its header and payload. -/// -/// **Note**: Signature not included because its decoded form would be bytes -class JwtDecoded { - final JwtHeader header; - final JwtClaims payload; - - JwtDecoded({required this.header, required this.payload}); - - factory JwtDecoded.fromJson(Map json) { - return JwtDecoded( - header: JwtHeader.fromJson(json['header']), - payload: JwtClaims.fromJson(json['payload']), - ); - } - - Map toJson() { - return { - 'header': header.toJson(), - 'payload': payload.toJson(), - }; - } -} From de8e5920e95e3f4b3d341b4f2c8324c71414c5a0 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Fri, 29 Mar 2024 15:23:10 -0700 Subject: [PATCH 02/13] updated keymanager class to contain all helper methods --- .../lib/src/crypto/in_memory_key_manager.dart | 2 +- packages/web5/lib/src/crypto/key_manager.dart | 20 ++++++++----------- packages/web5/lib/src/dids/bearer_did.dart | 9 +++------ 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/packages/web5/lib/src/crypto/in_memory_key_manager.dart b/packages/web5/lib/src/crypto/in_memory_key_manager.dart index ad4ff07..36fd921 100644 --- a/packages/web5/lib/src/crypto/in_memory_key_manager.dart +++ b/packages/web5/lib/src/crypto/in_memory_key_manager.dart @@ -20,7 +20,7 @@ import 'package:web5/src/crypto/crypto.dart'; /// final signatureBytes = await keyManager.sign(keyAlias, Uint8List.fromList([20, 32])); /// ``` /// -class InMemoryKeyManager implements KeyManager, KeyImporter, KeyExporter { +class InMemoryKeyManager implements KeyManager { final Map _keyStore = {}; @override diff --git a/packages/web5/lib/src/crypto/key_manager.dart b/packages/web5/lib/src/crypto/key_manager.dart index b90c52d..268aebe 100644 --- a/packages/web5/lib/src/crypto/key_manager.dart +++ b/packages/web5/lib/src/crypto/key_manager.dart @@ -3,24 +3,15 @@ import 'dart:typed_data'; import 'package:web5/src/crypto/algorithm_id.dart'; import 'package:web5/src/crypto/jwk.dart'; -abstract interface class KeyImporter { - /// Imports a private key. Returns - /// a unique id that can be utilized to reference the imported key for - /// future operations. - Future import(Jwk jwk); -} - -abstract interface class KeyExporter { - /// Exports the private key with the provided id. - Future export(String keyId); -} - /// A key management interface that provides functionality for generating, /// storing, and utilizing private keys and their associated public keys. /// Implementations of this interface should handle the secure generation and /// storage of keys, providing mechanisms for utilizing them in cryptographic /// operations like signing. abstract interface class KeyManager { + /// Exports the private key with the provided id. + Future export(String keyId); + /// Generates and securely stores a private key based on the provided /// algorithm. Returns a unique alias that can be utilized to reference the /// generated key for future operations. @@ -30,6 +21,11 @@ abstract interface class KeyManager { /// identified by the provided alias. Future getPublicKey(String keyId); + /// Imports a private key. Returns + /// a unique id that can be utilized to reference the imported key for + /// future operations. + Future import(Jwk jwk); + /// Signs the provided payload using the private key identified by the /// provided alias. Future sign(String keyId, Uint8List payload); diff --git a/packages/web5/lib/src/dids/bearer_did.dart b/packages/web5/lib/src/dids/bearer_did.dart index 78ab336..69326a3 100644 --- a/packages/web5/lib/src/dids/bearer_did.dart +++ b/packages/web5/lib/src/dids/bearer_did.dart @@ -20,11 +20,13 @@ class BearerDid { String uri; KeyManager keyManager; DidDocument document; + DidDocumentMetadata metadata; BearerDid({ required this.uri, required this.keyManager, required this.document, + this.metadata = const DidDocumentMetadata(), }); Future export() async { @@ -33,15 +35,10 @@ class BearerDid { document: document, ); - if (keyManager is! KeyExporter) { - return Future.value(portableDid); - } - - final keyExporter = keyManager as KeyExporter; for (final vm in document.verificationMethod!) { final publicKeyJwk = vm.publicKeyJwk!; final keyId = publicKeyJwk.computeThumbprint(); - final jwk = await keyExporter.export(keyId); + final jwk = await keyManager.export(keyId); portableDid.privateKeys.add(jwk); } From 771584a98f6cf838c48f74b0ca83e2930982c470 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Fri, 29 Mar 2024 15:23:37 -0700 Subject: [PATCH 03/13] added missing did resolution results --- .../dids/did_core/did_resolution_result.dart | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/packages/web5/lib/src/dids/did_core/did_resolution_result.dart b/packages/web5/lib/src/dids/did_core/did_resolution_result.dart index 40eab5b..f068b76 100644 --- a/packages/web5/lib/src/dids/did_core/did_resolution_result.dart +++ b/packages/web5/lib/src/dids/did_core/did_resolution_result.dart @@ -61,13 +61,36 @@ class DidResolutionResult { didResolutionMetadata ?? DidResolutionMetadata(), didDocumentMetadata = didDocumentMetadata ?? DidDocumentMetadata(); - /// A convenience constructor for creating a [DidResolutionResult] representing + /// A factory constructor for creating a [DidResolutionResult] representing /// an invalid DID scenario. This sets the resolution metadata error to 'invalidDid' /// and leaves the DID document as `null`. - DidResolutionResult.invalidDid() - : didResolutionMetadata = DidResolutionMetadata(error: 'invalidDid'), - didDocument = null, - didDocumentMetadata = DidDocumentMetadata(); + factory DidResolutionResult.invalidDid() { + return DidResolutionResult( + didResolutionMetadata: DidResolutionMetadata(error: 'invalidDid'), + didDocument: null, + didDocumentMetadata: DidDocumentMetadata(), + ); + } + + factory DidResolutionResult.notFound() { + return DidResolutionResult( + didResolutionMetadata: DidResolutionMetadata( + error: 'notFound', + ), + didDocument: null, + didDocumentMetadata: DidDocumentMetadata(), + ); + } + + factory DidResolutionResult.representationNotSupported() { + return DidResolutionResult( + didResolutionMetadata: DidResolutionMetadata( + error: 'representationNotSupported', + ), + didDocument: null, + didDocumentMetadata: DidDocumentMetadata(), + ); + } /// Converts this [DidResolutionResult] instance to a JSON map. /// From 17bd37e329f836c4320d56bdb745c3b44ccf1dd2 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Fri, 29 Mar 2024 15:24:05 -0700 Subject: [PATCH 04/13] updated portable did naming convention to use map instead of json --- packages/web5/lib/src/dids/portable_did.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/web5/lib/src/dids/portable_did.dart b/packages/web5/lib/src/dids/portable_did.dart index 3657d61..427d361 100644 --- a/packages/web5/lib/src/dids/portable_did.dart +++ b/packages/web5/lib/src/dids/portable_did.dart @@ -12,16 +12,16 @@ class PortableDid { List? privateKeys, }) : privateKeys = privateKeys ?? []; - factory PortableDid.fromJson(Map json) { + factory PortableDid.fromMap(Map map) { return PortableDid( - uri: json['uri'], - document: DidDocument.fromJson(json['document']), + uri: map['uri'], + document: DidDocument.fromJson(map['document']), privateKeys: - (json['privateKeys'] as List).map((e) => Jwk.fromJson(e)).toList(), + (map['privateKeys'] as List).map((e) => Jwk.fromJson(e)).toList(), ); } - Map toJson() { + Map get map { return { 'uri': uri, 'document': document.toJson(), From 0d9d590c4d390d43d35a4f039833a0b488b572a1 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Fri, 29 Mar 2024 15:25:42 -0700 Subject: [PATCH 05/13] added web create method and updated the resolver and tests --- .../web5/lib/src/dids/did_web/did_web.dart | 118 ++++++++++++++---- packages/web5/test/dids/did_web_test.dart | 28 +++-- 2 files changed, 112 insertions(+), 34 deletions(-) diff --git a/packages/web5/lib/src/dids/did_web/did_web.dart b/packages/web5/lib/src/dids/did_web/did_web.dart index db55f1c..ebf025e 100644 --- a/packages/web5/lib/src/dids/did_web/did_web.dart +++ b/packages/web5/lib/src/dids/did_web/did_web.dart @@ -1,49 +1,117 @@ import 'dart:convert'; import 'dart:io'; +import 'package:web5/src/crypto.dart'; +import 'package:web5/src/dids/bearer_did.dart'; +import 'package:web5/src/dids/did.dart'; import 'package:web5/src/dids/did_core.dart'; import 'package:web5/src/dids/did_method_resolver.dart'; -import 'package:web5/src/dids/did.dart'; class DidWeb { static const String methodName = 'web'; - static final resolver = DidMethodResolver(name: methodName, resolve: resolve); + + static final DidMethodResolver resolver = DidMethodResolver( + name: methodName, + resolve: resolve, + ); + + static Future create({ + required AlgorithmId algorithm, + required KeyManager keyManager, + required String url, + List? alsoKnownAs, + List? controllers, + List? services, + List? verificationMethods, + DidDocumentMetadata? metadata, + }) async { + final parsed = Uri.tryParse(url); + if (parsed == null) throw 'Unable to parse url $url'; + final String didId = + 'did:web:${parsed.host}${parsed.pathSegments.join(':')}'; + + final DidDocument doc = DidDocument( + id: didId, + alsoKnownAs: alsoKnownAs, + controller: controllers ?? didId, + ); + + final List defaultMethods = [ + DidCreateVerificationMethod( + id: '0', + type: 'JsonWebKey', + controller: didId, + purposes: [ + VerificationPurpose.authentication, + VerificationPurpose.assertionMethod, + VerificationPurpose.capabilityDelegation, + VerificationPurpose.capabilityInvocation, + ], + ), + ]; + + final List methodsToAdd = + verificationMethods ?? defaultMethods; + + for (final DidCreateVerificationMethod vm in methodsToAdd) { + final Jwk privateKey = await Crypto.generatePrivateKey(algorithm); + final Jwk publicKey = await Crypto.computePublicKey(privateKey); + + keyManager.import(privateKey); + + final String methodId = '$didId#${vm.id}'; + doc.addVerificationMethod( + DidVerificationMethod( + id: methodId, + type: vm.type, + controller: vm.controller, + publicKeyJwk: publicKey, + ), + ); + + for (final VerificationPurpose purpose in vm.purposes) { + doc.addVerificationPurpose(purpose, methodId); + } + } + + for (final DidService service in (services ?? [])) { + doc.addService(service); + } + + return BearerDid( + uri: didId, + keyManager: keyManager, + document: doc, + metadata: metadata ?? DidDocumentMetadata(), + ); + } static Future resolve( Did did, { HttpClient? client, }) async { - if (did.method != methodName) { - return DidResolutionResult.invalidDid(); - } + if (did.method != methodName) return DidResolutionResult.invalidDid(); - // TODO: http technically not supported. remove after temp use - var resolutionUrl = did.id.replaceAll(':', '/'); - if (resolutionUrl.contains('localhost')) { - resolutionUrl = 'http://$resolutionUrl'; - } else { - resolutionUrl = 'https://$resolutionUrl'; - } + final String documentUrl = Uri.decodeFull(did.id.replaceAll(':', '/')); + Uri? didUri = Uri.tryParse('https://$documentUrl'); - if (Uri.parse(resolutionUrl).path.isEmpty) { - resolutionUrl = '$resolutionUrl/.well-known'; - } + if (didUri == null) throw 'Unable to parse DID document Url $documentUrl'; - resolutionUrl = Uri.decodeFull('$resolutionUrl/did.json'); - final parsedUrl = Uri.parse(resolutionUrl); + // If none was specified, use the default path. + if (didUri.path.isEmpty) didUri = didUri.replace(path: '/.well-known'); + didUri = didUri.replace(pathSegments: [...didUri.pathSegments, 'did.json']); - final httpClient = client ??= HttpClient(); - final request = await httpClient.getUrl(parsedUrl); - final response = await request.close(); + final HttpClient httpClient = client ??= HttpClient(); + final HttpClientRequest request = await httpClient.getUrl(didUri); + final HttpClientResponse response = await request.close(); if (response.statusCode != 200) { - // TODO: change this to something more appropriate - return DidResolutionResult.invalidDid(); + return DidResolutionResult.notFound(); } - final str = await response.transform(utf8.decoder).join(); - final jsonParsed = json.decode(str); - final doc = DidDocument.fromJson(jsonParsed); + final String str = await response.transform(utf8.decoder).join(); + final dynamic jsonParsed = json.decode(str); + final DidDocument doc = DidDocument.fromJson(jsonParsed); return DidResolutionResult(didDocument: doc); } diff --git a/packages/web5/test/dids/did_web_test.dart b/packages/web5/test/dids/did_web_test.dart index f10487f..49d7150 100644 --- a/packages/web5/test/dids/did_web_test.dart +++ b/packages/web5/test/dids/did_web_test.dart @@ -3,9 +3,7 @@ import 'dart:io'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; -import 'package:web5/src/dids/did.dart'; -import 'package:web5/src/dids/did_core/did_resolution_result.dart'; -import 'package:web5/src/dids/did_web/did_web.dart'; +import 'package:web5/web5.dart'; class MockHttpClient extends Mock implements HttpClient {} @@ -78,20 +76,31 @@ void main() { }); group('DidWeb', () { + test('should be created successfully', () async { + final BearerDid did = await DidWeb.create( + algorithm: AlgorithmId.ed25519, + keyManager: InMemoryKeyManager(), + url: 'www.linkedin.com/user123', + ); + + expect('did:web:www.linkedin.com:user123', did.document.id); + }); + test('should return invalid did with wrong method', () async { final did = Did.parse('did:bad:www.linkedin.com'); final result = await DidWeb.resolve(did); expect(result, DidResolutionResult.invalidDid()); }); - test('should return invalid did with failed http request', () async { + test('should return did with failed http request', () async { when(() => response.statusCode).thenReturn(400); when(() => request.close()).thenAnswer((_) async => response); when(() => mockClient.getUrl(any())).thenAnswer((_) async => request); final did = Did.parse('did:web:www.linkedin.com'); final result = await DidWeb.resolve(did, client: mockClient); - expect(result, DidResolutionResult.invalidDid()); + + expect(result, DidResolutionResult.notFound()); }); test('should resolve successfully', () async { @@ -124,11 +133,11 @@ void main() { when(() => request.close()).thenAnswer((_) async => response); when( () => mockClient.getUrl( - Uri.parse('http://localhost:8892/ingress/did.json'), + Uri.parse('https://www.remotehost.com:8892/ingress/did.json'), ), ).thenAnswer((_) async => request); - final did = Did.parse('did:web:localhost%3A8892:ingress'); + final did = Did.parse('did:web:www.remotehost.com%3A8892:ingress'); final result = await DidWeb.resolve( did, client: mockClient, @@ -136,8 +145,9 @@ void main() { expect(result.didDocument, isNotNull); verify( - () => mockClient - .getUrl(Uri.parse('http://localhost:8892/ingress/did.json')), + () => mockClient.getUrl( + Uri.parse('https://www.remotehost.com:8892/ingress/did.json'), + ), ); }); }); From 8d29d66ce25f86a3bc07e1bb903cdbaa71133539 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Mon, 1 Apr 2024 07:56:09 -0700 Subject: [PATCH 06/13] missing classes --- .../src/dids/did_core/did_document_metadata.dart | 2 +- .../dids/did_core/did_verification_method.dart | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/web5/lib/src/dids/did_core/did_document_metadata.dart b/packages/web5/lib/src/dids/did_core/did_document_metadata.dart index f866252..6843099 100644 --- a/packages/web5/lib/src/dids/did_core/did_document_metadata.dart +++ b/packages/web5/lib/src/dids/did_core/did_document_metadata.dart @@ -51,7 +51,7 @@ class DidDocumentMetadata { /// the scope of the containing DID document. final String? canonicalId; - DidDocumentMetadata({ + const DidDocumentMetadata({ this.created, this.updated, this.deactivated, diff --git a/packages/web5/lib/src/dids/did_core/did_verification_method.dart b/packages/web5/lib/src/dids/did_core/did_verification_method.dart index 5d5a2f5..5558269 100644 --- a/packages/web5/lib/src/dids/did_core/did_verification_method.dart +++ b/packages/web5/lib/src/dids/did_core/did_verification_method.dart @@ -1,5 +1,6 @@ import 'package:web5/src/crypto.dart'; import 'package:web5/src/dids/did_core/did_resource.dart'; +import 'package:web5/src/dids/did_core/did_verification_relationship.dart'; /// A DID document can express verification methods, such as cryptographic /// public keys, which can be used to authenticate or authorize interactions @@ -52,3 +53,17 @@ class DidVerificationMethod implements DidResource { ); } } + +class DidCreateVerificationMethod { + DidCreateVerificationMethod({ + required this.controller, + this.id, + required this.purposes, + required this.type, + }); + + final String controller; + final String? id; + final List purposes; + final String type; +} From 543747b76e6239826750f4688d5c08d324491d7e Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Mon, 1 Apr 2024 08:26:02 -0700 Subject: [PATCH 07/13] added per verification method private key creation --- .../lib/src/dids/did_core/did_verification_method.dart | 2 ++ packages/web5/lib/src/dids/did_web/did_web.dart | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/web5/lib/src/dids/did_core/did_verification_method.dart b/packages/web5/lib/src/dids/did_core/did_verification_method.dart index 5558269..f747d1f 100644 --- a/packages/web5/lib/src/dids/did_core/did_verification_method.dart +++ b/packages/web5/lib/src/dids/did_core/did_verification_method.dart @@ -56,12 +56,14 @@ class DidVerificationMethod implements DidResource { class DidCreateVerificationMethod { DidCreateVerificationMethod({ + required this.algorithm, required this.controller, this.id, required this.purposes, required this.type, }); + final AlgorithmId algorithm; final String controller; final String? id; final List purposes; diff --git a/packages/web5/lib/src/dids/did_web/did_web.dart b/packages/web5/lib/src/dids/did_web/did_web.dart index ebf025e..bfc5fee 100644 --- a/packages/web5/lib/src/dids/did_web/did_web.dart +++ b/packages/web5/lib/src/dids/did_web/did_web.dart @@ -16,15 +16,18 @@ class DidWeb { ); static Future create({ - required AlgorithmId algorithm, - required KeyManager keyManager, required String url, + AlgorithmId? algorithm, + KeyManager? keyManager, List? alsoKnownAs, List? controllers, List? services, List? verificationMethods, DidDocumentMetadata? metadata, }) async { + algorithm ??= AlgorithmId.ed25519; + keyManager ??= InMemoryKeyManager(); + final parsed = Uri.tryParse(url); if (parsed == null) throw 'Unable to parse url $url'; final String didId = @@ -38,6 +41,7 @@ class DidWeb { final List defaultMethods = [ DidCreateVerificationMethod( + algorithm: algorithm, id: '0', type: 'JsonWebKey', controller: didId, @@ -54,7 +58,7 @@ class DidWeb { verificationMethods ?? defaultMethods; for (final DidCreateVerificationMethod vm in methodsToAdd) { - final Jwk privateKey = await Crypto.generatePrivateKey(algorithm); + final Jwk privateKey = await Crypto.generatePrivateKey(vm.algorithm); final Jwk publicKey = await Crypto.computePublicKey(privateKey); keyManager.import(privateKey); From 9e4d54d6d7229eafb67932ab023d8a2c801f9f3e Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Mon, 1 Apr 2024 08:39:27 -0700 Subject: [PATCH 08/13] combined did resolution result error factorys into single --- .../dids/did_core/did_resolution_result.dart | 45 ++++++++++--------- .../web5/lib/src/dids/did_dht/did_dht.dart | 8 ++-- .../web5/lib/src/dids/did_jwk/did_jwk.dart | 10 ++--- packages/web5/lib/src/dids/did_resolver.dart | 4 +- .../web5/lib/src/dids/did_web/did_web.dart | 6 ++- packages/web5/test/dids/did_web_test.dart | 10 ++++- 6 files changed, 47 insertions(+), 36 deletions(-) diff --git a/packages/web5/lib/src/dids/did_core/did_resolution_result.dart b/packages/web5/lib/src/dids/did_core/did_resolution_result.dart index f068b76..2290cd1 100644 --- a/packages/web5/lib/src/dids/did_core/did_resolution_result.dart +++ b/packages/web5/lib/src/dids/did_core/did_resolution_result.dart @@ -2,6 +2,27 @@ import 'package:web5/src/dids/did_core/did_document.dart'; import 'package:web5/src/dids/did_core/did_document_metadata.dart'; import 'package:web5/src/dids/did_core/did_resolution_metadata.dart'; +enum DidResolutionError { + invalidDid, + notFound, + representationNotSupported, +} + +extension ResolutionErrorValue on DidResolutionError { + String get value { + switch (this) { + case DidResolutionError.invalidDid: + return 'invalidDid'; + case DidResolutionError.notFound: + return 'notFound'; + case DidResolutionError.representationNotSupported: + return 'representationNotSupported'; + default: + return 'unknown'; + } + } +} + /// A class representing the result of a DID (Decentralized Identifier) /// resolution. /// @@ -64,29 +85,9 @@ class DidResolutionResult { /// A factory constructor for creating a [DidResolutionResult] representing /// an invalid DID scenario. This sets the resolution metadata error to 'invalidDid' /// and leaves the DID document as `null`. - factory DidResolutionResult.invalidDid() { - return DidResolutionResult( - didResolutionMetadata: DidResolutionMetadata(error: 'invalidDid'), - didDocument: null, - didDocumentMetadata: DidDocumentMetadata(), - ); - } - - factory DidResolutionResult.notFound() { - return DidResolutionResult( - didResolutionMetadata: DidResolutionMetadata( - error: 'notFound', - ), - didDocument: null, - didDocumentMetadata: DidDocumentMetadata(), - ); - } - - factory DidResolutionResult.representationNotSupported() { + factory DidResolutionResult.withError(DidResolutionError err) { return DidResolutionResult( - didResolutionMetadata: DidResolutionMetadata( - error: 'representationNotSupported', - ), + didResolutionMetadata: DidResolutionMetadata(error: err.value), didDocument: null, didDocumentMetadata: DidDocumentMetadata(), ); diff --git a/packages/web5/lib/src/dids/did_dht/did_dht.dart b/packages/web5/lib/src/dids/did_dht/did_dht.dart index 292c67d..2607502 100644 --- a/packages/web5/lib/src/dids/did_dht/did_dht.dart +++ b/packages/web5/lib/src/dids/did_dht/did_dht.dart @@ -19,7 +19,7 @@ class DidDht { String relayUrl = 'https://diddht.tbddev.org', }) async { if (did.method != methodName) { - return DidResolutionResult.invalidDid(); + return DidResolutionResult.withError(DidResolutionError.invalidDid); } final parsedRelayUrl = Uri.parse(relayUrl); @@ -42,7 +42,7 @@ class DidDht { // final seq = bytes.sublist(64, 72); if (bytes.length < 72) { - return DidResolutionResult.invalidDid(); + return DidResolutionResult.withError(DidResolutionError.invalidDid); } final v = bytes.sublist(72); @@ -68,7 +68,7 @@ class DidDht { if (rootRecord == null) { // TODO: figure out more appopriate resolution error to use. - return DidResolutionResult.invalidDid(); + return DidResolutionResult.withError(DidResolutionError.invalidDid); } final Map> relationshipsMap = {}; @@ -77,7 +77,7 @@ class DidDht { if (splitEntry.length != 2) { // TODO: figure out more appopriate resolution error to use. - return DidResolutionResult.invalidDid(); + return DidResolutionResult.withError(DidResolutionError.invalidDid); } final [property, values] = splitEntry; diff --git a/packages/web5/lib/src/dids/did_jwk/did_jwk.dart b/packages/web5/lib/src/dids/did_jwk/did_jwk.dart index c4b0034..4d15a98 100644 --- a/packages/web5/lib/src/dids/did_jwk/did_jwk.dart +++ b/packages/web5/lib/src/dids/did_jwk/did_jwk.dart @@ -60,9 +60,9 @@ class DidJwk { /// an invalid [DidResolutionResult]. /// /// Throws [FormatException] if the JWK parsing fails. - static Future resolve(Did did) { + static Future resolve(Did did) async { if (did.method != methodName) { - return Future.value(DidResolutionResult.invalidDid()); + return DidResolutionResult.withError(DidResolutionError.invalidDid); } final dynamic jwk; @@ -70,7 +70,7 @@ class DidJwk { try { jwk = json.fromBase64Url(did.id); } on FormatException { - return Future.value(DidResolutionResult.invalidDid()); + return DidResolutionResult.withError(DidResolutionError.invalidDid); } final Jwk parsedJwk; @@ -78,13 +78,13 @@ class DidJwk { try { parsedJwk = Jwk.fromJson(jwk); } on Exception { - return Future.value(DidResolutionResult.invalidDid()); + return DidResolutionResult.withError(DidResolutionError.invalidDid); } final didDocument = _createDidDocument(did, parsedJwk); final didResolutionResult = DidResolutionResult(didDocument: didDocument); - return Future.value(didResolutionResult); + return didResolutionResult; } static DidDocument _createDidDocument(Did did, Jwk jwk) { diff --git a/packages/web5/lib/src/dids/did_resolver.dart b/packages/web5/lib/src/dids/did_resolver.dart index 452b372..7c35850 100644 --- a/packages/web5/lib/src/dids/did_resolver.dart +++ b/packages/web5/lib/src/dids/did_resolver.dart @@ -52,7 +52,9 @@ class DidResolver { try { did = Did.parse(uri); } catch (e) { - return Future.value(DidResolutionResult.invalidDid()); + return Future.value( + DidResolutionResult.withError(DidResolutionError.invalidDid), + ); } final resolver = methodResolvers[did.method]; diff --git a/packages/web5/lib/src/dids/did_web/did_web.dart b/packages/web5/lib/src/dids/did_web/did_web.dart index bfc5fee..f6db5bf 100644 --- a/packages/web5/lib/src/dids/did_web/did_web.dart +++ b/packages/web5/lib/src/dids/did_web/did_web.dart @@ -94,7 +94,9 @@ class DidWeb { Did did, { HttpClient? client, }) async { - if (did.method != methodName) return DidResolutionResult.invalidDid(); + if (did.method != methodName) { + return DidResolutionResult.withError(DidResolutionError.invalidDid); + } final String documentUrl = Uri.decodeFull(did.id.replaceAll(':', '/')); Uri? didUri = Uri.tryParse('https://$documentUrl'); @@ -110,7 +112,7 @@ class DidWeb { final HttpClientResponse response = await request.close(); if (response.statusCode != 200) { - return DidResolutionResult.notFound(); + return DidResolutionResult.withError(DidResolutionError.notFound); } final String str = await response.transform(utf8.decoder).join(); diff --git a/packages/web5/test/dids/did_web_test.dart b/packages/web5/test/dids/did_web_test.dart index 49d7150..16c7435 100644 --- a/packages/web5/test/dids/did_web_test.dart +++ b/packages/web5/test/dids/did_web_test.dart @@ -89,7 +89,10 @@ void main() { test('should return invalid did with wrong method', () async { final did = Did.parse('did:bad:www.linkedin.com'); final result = await DidWeb.resolve(did); - expect(result, DidResolutionResult.invalidDid()); + expect( + result, + DidResolutionResult.withError(DidResolutionError.invalidDid), + ); }); test('should return did with failed http request', () async { @@ -100,7 +103,10 @@ void main() { final did = Did.parse('did:web:www.linkedin.com'); final result = await DidWeb.resolve(did, client: mockClient); - expect(result, DidResolutionResult.notFound()); + expect( + result, + DidResolutionResult.withError(DidResolutionError.notFound), + ); }); test('should resolve successfully', () async { From 890f8b5eef56e9f6b5f14ecd5b585d21da065780 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Wed, 3 Apr 2024 07:19:43 -0700 Subject: [PATCH 09/13] reverted bearer --- packages/web5/lib/src/dids/bearer_did.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/web5/lib/src/dids/bearer_did.dart b/packages/web5/lib/src/dids/bearer_did.dart index 69326a3..78ab336 100644 --- a/packages/web5/lib/src/dids/bearer_did.dart +++ b/packages/web5/lib/src/dids/bearer_did.dart @@ -20,13 +20,11 @@ class BearerDid { String uri; KeyManager keyManager; DidDocument document; - DidDocumentMetadata metadata; BearerDid({ required this.uri, required this.keyManager, required this.document, - this.metadata = const DidDocumentMetadata(), }); Future export() async { @@ -35,10 +33,15 @@ class BearerDid { document: document, ); + if (keyManager is! KeyExporter) { + return Future.value(portableDid); + } + + final keyExporter = keyManager as KeyExporter; for (final vm in document.verificationMethod!) { final publicKeyJwk = vm.publicKeyJwk!; final keyId = publicKeyJwk.computeThumbprint(); - final jwk = await keyManager.export(keyId); + final jwk = await keyExporter.export(keyId); portableDid.privateKeys.add(jwk); } From 1fa7f903fb153e5cc48248c81ffdfe5d06e196d3 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Wed, 3 Apr 2024 07:20:38 -0700 Subject: [PATCH 10/13] reverted key manager --- packages/web5/lib/src/crypto/key_manager.dart | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/web5/lib/src/crypto/key_manager.dart b/packages/web5/lib/src/crypto/key_manager.dart index 268aebe..b90c52d 100644 --- a/packages/web5/lib/src/crypto/key_manager.dart +++ b/packages/web5/lib/src/crypto/key_manager.dart @@ -3,15 +3,24 @@ import 'dart:typed_data'; import 'package:web5/src/crypto/algorithm_id.dart'; import 'package:web5/src/crypto/jwk.dart'; +abstract interface class KeyImporter { + /// Imports a private key. Returns + /// a unique id that can be utilized to reference the imported key for + /// future operations. + Future import(Jwk jwk); +} + +abstract interface class KeyExporter { + /// Exports the private key with the provided id. + Future export(String keyId); +} + /// A key management interface that provides functionality for generating, /// storing, and utilizing private keys and their associated public keys. /// Implementations of this interface should handle the secure generation and /// storage of keys, providing mechanisms for utilizing them in cryptographic /// operations like signing. abstract interface class KeyManager { - /// Exports the private key with the provided id. - Future export(String keyId); - /// Generates and securely stores a private key based on the provided /// algorithm. Returns a unique alias that can be utilized to reference the /// generated key for future operations. @@ -21,11 +30,6 @@ abstract interface class KeyManager { /// identified by the provided alias. Future getPublicKey(String keyId); - /// Imports a private key. Returns - /// a unique id that can be utilized to reference the imported key for - /// future operations. - Future import(Jwk jwk); - /// Signs the provided payload using the private key identified by the /// provided alias. Future sign(String keyId, Uint8List payload); From d693984b0c013c9b612ee435226ea62de91dd3af Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Wed, 3 Apr 2024 07:21:40 -0700 Subject: [PATCH 11/13] reverted in memory key manager --- packages/web5/lib/src/crypto/in_memory_key_manager.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web5/lib/src/crypto/in_memory_key_manager.dart b/packages/web5/lib/src/crypto/in_memory_key_manager.dart index 36fd921..ad4ff07 100644 --- a/packages/web5/lib/src/crypto/in_memory_key_manager.dart +++ b/packages/web5/lib/src/crypto/in_memory_key_manager.dart @@ -20,7 +20,7 @@ import 'package:web5/src/crypto/crypto.dart'; /// final signatureBytes = await keyManager.sign(keyAlias, Uint8List.fromList([20, 32])); /// ``` /// -class InMemoryKeyManager implements KeyManager { +class InMemoryKeyManager implements KeyManager, KeyImporter, KeyExporter { final Map _keyStore = {}; @override From f5feeead72f06d00eebf709777443602402c1f62 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Wed, 3 Apr 2024 07:24:13 -0700 Subject: [PATCH 12/13] updated web create --- packages/web5/lib/src/dids/did_web/did_web.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/web5/lib/src/dids/did_web/did_web.dart b/packages/web5/lib/src/dids/did_web/did_web.dart index f6db5bf..b3408e5 100644 --- a/packages/web5/lib/src/dids/did_web/did_web.dart +++ b/packages/web5/lib/src/dids/did_web/did_web.dart @@ -58,10 +58,8 @@ class DidWeb { verificationMethods ?? defaultMethods; for (final DidCreateVerificationMethod vm in methodsToAdd) { - final Jwk privateKey = await Crypto.generatePrivateKey(vm.algorithm); - final Jwk publicKey = await Crypto.computePublicKey(privateKey); - - keyManager.import(privateKey); + final String alias = await keyManager.generatePrivateKey(vm.algorithm); + final Jwk publicKey = await keyManager.getPublicKey(alias); final String methodId = '$didId#${vm.id}'; doc.addVerificationMethod( From b6520d8eeb41697189a6612ac138320ef02d6098 Mon Sep 17 00:00:00 2001 From: Stone Pack Date: Wed, 3 Apr 2024 07:25:21 -0700 Subject: [PATCH 13/13] redo part of an undo --- packages/web5/lib/src/dids/bearer_did.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/web5/lib/src/dids/bearer_did.dart b/packages/web5/lib/src/dids/bearer_did.dart index 78ab336..c871880 100644 --- a/packages/web5/lib/src/dids/bearer_did.dart +++ b/packages/web5/lib/src/dids/bearer_did.dart @@ -20,11 +20,13 @@ class BearerDid { String uri; KeyManager keyManager; DidDocument document; + DidDocumentMetadata metadata; BearerDid({ required this.uri, required this.keyManager, required this.document, + this.metadata = const DidDocumentMetadata(), }); Future export() async {