From ef84ad0fde3690bf70957f1c7270b9f83516e634 Mon Sep 17 00:00:00 2001 From: Wes Date: Mon, 12 Feb 2024 15:44:32 -0700 Subject: [PATCH] fix: rename to didcore and fix failing http tests --- packages/web5/lib/src/dids.dart | 2 +- packages/web5/lib/src/dids/data_models.dart | 11 -- packages/web5/lib/src/dids/did_core.dart | 11 ++ .../did_dereference_metadata.dart | 0 .../did_dereference_options.dart | 0 .../did_dereference_result.dart | 6 +- .../did_document.dart | 8 +- .../did_document_metadata.dart | 29 ++++ .../did_resolution_metadata.dart | 12 ++ .../did_resolution_result.dart | 25 +++- .../did_resource.dart | 0 .../{structures => did_core}/did_service.dart | 2 +- .../did_verification_method.dart | 2 +- .../did_verification_relationship.dart | 0 .../web5/lib/src/dids/did_dht/did_dht.dart | 2 +- .../web5/lib/src/dids/did_jwk/did_jwk.dart | 2 +- .../lib/src/dids/did_method_resolver.dart | 2 +- packages/web5/lib/src/dids/did_resolver.dart | 2 +- .../web5/lib/src/dids/did_web/did_web.dart | 9 +- packages/web5/pubspec.yaml | 1 + packages/web5/test/dids/did_web_test.dart | 138 +++++++++++++++++- 21 files changed, 228 insertions(+), 36 deletions(-) delete mode 100644 packages/web5/lib/src/dids/data_models.dart create mode 100644 packages/web5/lib/src/dids/did_core.dart rename packages/web5/lib/src/dids/{structures => did_core}/did_dereference_metadata.dart (100%) rename packages/web5/lib/src/dids/{structures => did_core}/did_dereference_options.dart (100%) rename packages/web5/lib/src/dids/{structures => did_core}/did_dereference_result.dart (86%) rename packages/web5/lib/src/dids/{structures => did_core}/did_document.dart (96%) rename packages/web5/lib/src/dids/{structures => did_core}/did_document_metadata.dart (83%) rename packages/web5/lib/src/dids/{structures => did_core}/did_resolution_metadata.dart (82%) rename packages/web5/lib/src/dids/{structures => did_core}/did_resolution_result.dart (84%) rename packages/web5/lib/src/dids/{structures => did_core}/did_resource.dart (100%) rename packages/web5/lib/src/dids/{structures => did_core}/did_service.dart (95%) rename packages/web5/lib/src/dids/{structures => did_core}/did_verification_method.dart (96%) rename packages/web5/lib/src/dids/{structures => did_core}/did_verification_relationship.dart (100%) diff --git a/packages/web5/lib/src/dids.dart b/packages/web5/lib/src/dids.dart index f6ade2a..3a17016 100644 --- a/packages/web5/lib/src/dids.dart +++ b/packages/web5/lib/src/dids.dart @@ -1,6 +1,6 @@ export './dids/did.dart'; export './dids/did_uri.dart'; -export './dids/data_models.dart'; +export 'dids/did_core.dart'; export './dids/did_resolver.dart'; export './dids/did_dht/did_dht.dart'; export './dids/did_jwk/did_jwk.dart'; diff --git a/packages/web5/lib/src/dids/data_models.dart b/packages/web5/lib/src/dids/data_models.dart deleted file mode 100644 index 400d1c9..0000000 --- a/packages/web5/lib/src/dids/data_models.dart +++ /dev/null @@ -1,11 +0,0 @@ -export 'structures/did_service.dart'; -export 'structures/did_resource.dart'; -export 'structures/did_document.dart'; -export 'structures/did_resolution_result.dart'; -export 'structures/did_dereference_result.dart'; -export 'structures/did_verification_method.dart'; -export 'structures/did_resolution_metadata.dart'; -export 'structures/did_dereference_options.dart'; -export 'structures/did_dereference_metadata.dart'; -export 'structures/did_document_metadata.dart'; -export 'structures/did_verification_relationship.dart'; diff --git a/packages/web5/lib/src/dids/did_core.dart b/packages/web5/lib/src/dids/did_core.dart new file mode 100644 index 0000000..d900830 --- /dev/null +++ b/packages/web5/lib/src/dids/did_core.dart @@ -0,0 +1,11 @@ +export 'did_core/did_service.dart'; +export 'did_core/did_resource.dart'; +export 'did_core/did_document.dart'; +export 'did_core/did_resolution_result.dart'; +export 'did_core/did_dereference_result.dart'; +export 'did_core/did_verification_method.dart'; +export 'did_core/did_resolution_metadata.dart'; +export 'did_core/did_dereference_options.dart'; +export 'did_core/did_dereference_metadata.dart'; +export 'did_core/did_document_metadata.dart'; +export 'did_core/did_verification_relationship.dart'; diff --git a/packages/web5/lib/src/dids/structures/did_dereference_metadata.dart b/packages/web5/lib/src/dids/did_core/did_dereference_metadata.dart similarity index 100% rename from packages/web5/lib/src/dids/structures/did_dereference_metadata.dart rename to packages/web5/lib/src/dids/did_core/did_dereference_metadata.dart diff --git a/packages/web5/lib/src/dids/structures/did_dereference_options.dart b/packages/web5/lib/src/dids/did_core/did_dereference_options.dart similarity index 100% rename from packages/web5/lib/src/dids/structures/did_dereference_options.dart rename to packages/web5/lib/src/dids/did_core/did_dereference_options.dart diff --git a/packages/web5/lib/src/dids/structures/did_dereference_result.dart b/packages/web5/lib/src/dids/did_core/did_dereference_result.dart similarity index 86% rename from packages/web5/lib/src/dids/structures/did_dereference_result.dart rename to packages/web5/lib/src/dids/did_core/did_dereference_result.dart index 62b4381..4ca00f2 100644 --- a/packages/web5/lib/src/dids/structures/did_dereference_result.dart +++ b/packages/web5/lib/src/dids/did_core/did_dereference_result.dart @@ -1,8 +1,8 @@ import 'dart:convert'; -import 'package:web5/src/dids/structures/did_dereference_metadata.dart'; -import 'package:web5/src/dids/structures/did_document_metadata.dart'; -import 'package:web5/src/dids/structures/did_resource.dart'; +import 'package:web5/src/dids/did_core/did_dereference_metadata.dart'; +import 'package:web5/src/dids/did_core/did_document_metadata.dart'; +import 'package:web5/src/dids/did_core/did_resource.dart'; class DidDereferenceResult { DidDereferenceMetadata dereferencingMetadata; diff --git a/packages/web5/lib/src/dids/structures/did_document.dart b/packages/web5/lib/src/dids/did_core/did_document.dart similarity index 96% rename from packages/web5/lib/src/dids/structures/did_document.dart rename to packages/web5/lib/src/dids/did_core/did_document.dart index e347c1f..feb4362 100644 --- a/packages/web5/lib/src/dids/structures/did_document.dart +++ b/packages/web5/lib/src/dids/did_core/did_document.dart @@ -1,8 +1,8 @@ import 'package:collection/collection.dart'; -import 'package:web5/src/dids/structures/did_service.dart'; -import 'package:web5/src/dids/structures/did_resource.dart'; -import 'package:web5/src/dids/structures/did_verification_method.dart'; -import 'package:web5/src/dids/structures/did_verification_relationship.dart'; +import 'package:web5/src/dids/did_core/did_service.dart'; +import 'package:web5/src/dids/did_core/did_resource.dart'; +import 'package:web5/src/dids/did_core/did_verification_method.dart'; +import 'package:web5/src/dids/did_core/did_verification_relationship.dart'; /// A set of data describing the DID subject including mechanisms such as: /// * cryptographic public keys - used to authenticate itself and prove diff --git a/packages/web5/lib/src/dids/structures/did_document_metadata.dart b/packages/web5/lib/src/dids/did_core/did_document_metadata.dart similarity index 83% rename from packages/web5/lib/src/dids/structures/did_document_metadata.dart rename to packages/web5/lib/src/dids/did_core/did_document_metadata.dart index c979564..f866252 100644 --- a/packages/web5/lib/src/dids/structures/did_document_metadata.dart +++ b/packages/web5/lib/src/dids/did_core/did_document_metadata.dart @@ -78,4 +78,33 @@ class DidDocumentMetadata { return json; } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is DidDocumentMetadata && + other.created == created && + other.updated == updated && + other.deactivated == deactivated && + other.versionId == versionId && + other.nextUpdate == nextUpdate && + other.nextVersionId == nextVersionId && + other.equivalentId == equivalentId && + other.canonicalId == canonicalId; + } + + @override + int get hashCode { + return Object.hash( + created, + updated, + deactivated, + versionId, + nextUpdate, + nextVersionId, + equivalentId, + canonicalId, + ); + } } diff --git a/packages/web5/lib/src/dids/structures/did_resolution_metadata.dart b/packages/web5/lib/src/dids/did_core/did_resolution_metadata.dart similarity index 82% rename from packages/web5/lib/src/dids/structures/did_resolution_metadata.dart rename to packages/web5/lib/src/dids/did_core/did_resolution_metadata.dart index 55beb04..092044d 100644 --- a/packages/web5/lib/src/dids/structures/did_resolution_metadata.dart +++ b/packages/web5/lib/src/dids/did_core/did_resolution_metadata.dart @@ -36,4 +36,16 @@ class DidResolutionMetadata { return json; } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is DidResolutionMetadata && + other.contentType == contentType && + other.error == error; + } + + @override + int get hashCode => Object.hash(contentType, error); } diff --git a/packages/web5/lib/src/dids/structures/did_resolution_result.dart b/packages/web5/lib/src/dids/did_core/did_resolution_result.dart similarity index 84% rename from packages/web5/lib/src/dids/structures/did_resolution_result.dart rename to packages/web5/lib/src/dids/did_core/did_resolution_result.dart index 9b81483..40eab5b 100644 --- a/packages/web5/lib/src/dids/structures/did_resolution_result.dart +++ b/packages/web5/lib/src/dids/did_core/did_resolution_result.dart @@ -1,6 +1,6 @@ -import 'package:web5/src/dids/structures/did_document.dart'; -import 'package:web5/src/dids/structures/did_document_metadata.dart'; -import 'package:web5/src/dids/structures/did_resolution_metadata.dart'; +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'; /// A class representing the result of a DID (Decentralized Identifier) /// resolution. @@ -86,4 +86,23 @@ class DidResolutionResult { bool hasError() { return didResolutionMetadata.error != null; } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is DidResolutionResult && + other.didResolutionMetadata == didResolutionMetadata && + other.didDocument == didDocument && + other.didDocumentMetadata == didDocumentMetadata; + } + + @override + int get hashCode { + return Object.hash( + didResolutionMetadata, + didDocument, + didDocumentMetadata, + ); + } } diff --git a/packages/web5/lib/src/dids/structures/did_resource.dart b/packages/web5/lib/src/dids/did_core/did_resource.dart similarity index 100% rename from packages/web5/lib/src/dids/structures/did_resource.dart rename to packages/web5/lib/src/dids/did_core/did_resource.dart diff --git a/packages/web5/lib/src/dids/structures/did_service.dart b/packages/web5/lib/src/dids/did_core/did_service.dart similarity index 95% rename from packages/web5/lib/src/dids/structures/did_service.dart rename to packages/web5/lib/src/dids/did_core/did_service.dart index b436923..dab8b62 100644 --- a/packages/web5/lib/src/dids/structures/did_service.dart +++ b/packages/web5/lib/src/dids/did_core/did_service.dart @@ -1,4 +1,4 @@ -import 'package:web5/src/dids/structures/did_resource.dart'; +import 'package:web5/src/dids/did_core/did_resource.dart'; /// Services are used in DID documents to express ways of communicating with /// the DID subject or associated entities. diff --git a/packages/web5/lib/src/dids/structures/did_verification_method.dart b/packages/web5/lib/src/dids/did_core/did_verification_method.dart similarity index 96% rename from packages/web5/lib/src/dids/structures/did_verification_method.dart rename to packages/web5/lib/src/dids/did_core/did_verification_method.dart index 2f6172d..5d5a2f5 100644 --- a/packages/web5/lib/src/dids/structures/did_verification_method.dart +++ b/packages/web5/lib/src/dids/did_core/did_verification_method.dart @@ -1,5 +1,5 @@ import 'package:web5/src/crypto.dart'; -import 'package:web5/src/dids/structures/did_resource.dart'; +import 'package:web5/src/dids/did_core/did_resource.dart'; /// A DID document can express verification methods, such as cryptographic /// public keys, which can be used to authenticate or authorize interactions diff --git a/packages/web5/lib/src/dids/structures/did_verification_relationship.dart b/packages/web5/lib/src/dids/did_core/did_verification_relationship.dart similarity index 100% rename from packages/web5/lib/src/dids/structures/did_verification_relationship.dart rename to packages/web5/lib/src/dids/did_core/did_verification_relationship.dart 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 0ad2f95..c156d84 100644 --- a/packages/web5/lib/src/dids/did_dht/did_dht.dart +++ b/packages/web5/lib/src/dids/did_dht/did_dht.dart @@ -5,7 +5,7 @@ import 'package:web5/src/crypto.dart'; import 'package:web5/src/dids/did.dart'; import 'package:web5/src/extensions.dart'; import 'package:web5/src/dids/did_uri.dart'; -import 'package:web5/src/dids/data_models.dart'; +import 'package:web5/src/dids/did_core.dart'; import 'package:web5/src/dids/did_dht/dns_packet.dart'; import 'package:web5/src/dids/did_method_resolver.dart'; 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 7485dc2..f1c2e52 100644 --- a/packages/web5/lib/src/dids/did_jwk/did_jwk.dart +++ b/packages/web5/lib/src/dids/did_jwk/did_jwk.dart @@ -4,7 +4,7 @@ import 'package:web5/src/crypto.dart'; import 'package:web5/src/dids/did.dart'; import 'package:web5/src/extensions.dart'; import 'package:web5/src/dids/did_uri.dart'; -import 'package:web5/src/dids/data_models.dart'; +import 'package:web5/src/dids/did_core.dart'; import 'package:web5/src/dids/did_method_resolver.dart'; final base64UrlEncoder = Base64Codec.urlSafe().encoder; diff --git a/packages/web5/lib/src/dids/did_method_resolver.dart b/packages/web5/lib/src/dids/did_method_resolver.dart index 2ac89be..88f2e44 100644 --- a/packages/web5/lib/src/dids/did_method_resolver.dart +++ b/packages/web5/lib/src/dids/did_method_resolver.dart @@ -1,4 +1,4 @@ -import 'package:web5/src/dids/data_models.dart'; +import 'package:web5/src/dids/did_core.dart'; /// Represents a method resolver for a specific DID method. class DidMethodResolver { diff --git a/packages/web5/lib/src/dids/did_resolver.dart b/packages/web5/lib/src/dids/did_resolver.dart index 9badebd..8320da9 100644 --- a/packages/web5/lib/src/dids/did_resolver.dart +++ b/packages/web5/lib/src/dids/did_resolver.dart @@ -1,5 +1,5 @@ import 'package:web5/src/dids/did_uri.dart'; -import 'package:web5/src/dids/data_models.dart'; +import 'package:web5/src/dids/did_core.dart'; import 'package:web5/src/dids/did_method_resolver.dart'; /// A resolver for Decentralized Identifiers (DIDs). 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 74ef0fe..df22cf6 100644 --- a/packages/web5/lib/src/dids/did_web/did_web.dart +++ b/packages/web5/lib/src/dids/did_web/did_web.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:web5/src/crypto/key_manager.dart'; -import 'package:web5/src/dids/data_models.dart'; +import 'package:web5/src/dids/did_core.dart'; import 'package:web5/src/dids/did.dart'; import 'package:web5/src/dids/did_method_resolver.dart'; import 'package:web5/src/dids/did_uri.dart'; @@ -20,7 +20,10 @@ class DidWeb implements Did { static final resolver = DidMethodResolver(name: methodName, resolve: resolve); - static Future resolve(String didUri) async { + static Future resolve( + String didUri, { + HttpClient? client, + }) async { final DidUri parsedDidUri; try { @@ -48,7 +51,7 @@ class DidWeb implements Did { resolutionUrl = Uri.decodeFull('$resolutionUrl/did.json'); final parsedUrl = Uri.parse(resolutionUrl); - final httpClient = HttpClient(); + final httpClient = client ??= HttpClient(); final request = await httpClient.getUrl(parsedUrl); final response = await request.close(); diff --git a/packages/web5/pubspec.yaml b/packages/web5/pubspec.yaml index 8d64765..37ad2a3 100644 --- a/packages/web5/pubspec.yaml +++ b/packages/web5/pubspec.yaml @@ -14,4 +14,5 @@ dependencies: dev_dependencies: lints: ^3.0.0 + mocktail: ^1.0.3 test: ^1.21.0 diff --git a/packages/web5/test/dids/did_web_test.dart b/packages/web5/test/dids/did_web_test.dart index c882032..741ad9b 100644 --- a/packages/web5/test/dids/did_web_test.dart +++ b/packages/web5/test/dids/did_web_test.dart @@ -1,20 +1,148 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; +import 'package:web5/src/dids/did_core/did_resolution_result.dart'; import 'package:web5/src/dids/did_web/did_web.dart'; +class MockHttpClient extends Mock implements HttpClient {} + +class MockHttpRequest extends Mock implements HttpClientRequest {} + +class MockHttpResponse extends Mock implements HttpClientResponse {} + +const validDidWebDocument = '''{ + "id": "did:web:www.linkedin.com", + "@context": [ + "https://www.w3.org/ns/did/v1", + { + "@base": "did:web:www.linkedin.com" + } + ], + "service": [ + { + "id": "#linkeddomains", + "type": "LinkedDomains", + "serviceEndpoint": { + "origins": [ + "https://www.linkedin.com/" + ] + } + }, + { + "id": "#hub", + "type": "IdentityHub", + "serviceEndpoint": { + "instances": [ + "https://hub.did.msidentity.com/v1.0/658728e7-1632-412a-9815-fe53f53ec58b" + ] + } + } + ], + "verificationMethod": [ + { + "id": "#074cfbf193f046bcba5841ac4751e91bvcSigningKey-46682", + "controller": "did:web:www.linkedin.com", + "type": "EcdsaSecp256k1VerificationKey2019", + "publicKeyJwk": { + "crv": "secp256k1", + "kty": "EC", + "x": "NHIQivVR0HX7c0flpxgWQ7vRtbWDvr0UPN1nJ--0lyU", + "y": "hYiIldgLRShym7vzflFrEkg6NYkayUHkDpV0RMjUEYE" + } + } + ], + "authentication": [ + "#074cfbf193f046bcba5841ac4751e91bvcSigningKey-46682" + ], + "assertionMethod": [ + "#074cfbf193f046bcba5841ac4751e91bvcSigningKey-46682" + ] + }'''; + void main() { + final MockHttpClient mockClient = MockHttpClient(); + final MockHttpRequest request = MockHttpRequest(); + final MockHttpResponse response = MockHttpResponse(); + + setUpAll(() { + registerFallbackValue(Uri()); + }); + + setUp(() { + reset(mockClient); + reset(request); + reset(response); + }); + group('DidWeb', () { + test('should return invalid did with bad data', () async { + final result = await DidWeb.resolve('bogus'); + expect(result, DidResolutionResult.invalidDid()); + }); + + test('should return invalid did with wrong method', () async { + final result = await DidWeb.resolve('did:bad:www.linkedin.com'); + expect(result, DidResolutionResult.invalidDid()); + }); + + test('should return invalid 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 result = await DidWeb.resolve( + 'did:web:www.linkedin.com', + client: mockClient, + ); + expect(result, DidResolutionResult.invalidDid()); + }); + test('should resolve successfully', () async { - final result = await DidWeb.resolve('did:web:www.linkedin.com'); - expect(result.didDocument, isNotNull); + when(() => response.statusCode).thenReturn(200); + when(() => response.transform(utf8.decoder)) + .thenAnswer((_) => Stream.value(validDidWebDocument)); + when(() => request.close()).thenAnswer((_) async => response); + when( + () => mockClient.getUrl( + Uri.parse('https://www.linkedin.com/.well-known/did.json'), + ), + ).thenAnswer((_) async => request); + + final result = + await DidWeb.resolve('did:web:www.linkedin.com', client: mockClient); + expect(result.didDocument, isNotNull); expect('did:web:www.linkedin.com', result.didDocument!.id); + + verify( + () => mockClient + .getUrl(Uri.parse('https://www.linkedin.com/.well-known/did.json')), + ); }); - test('should resolve with paths', () async { - final result = await DidWeb.resolve('did:web:localhost%3A8892:ingress'); + test('should resolve successfully with paths', () async { + when(() => response.statusCode).thenReturn(200); + when(() => response.transform(utf8.decoder)) + .thenAnswer((_) => Stream.value(validDidWebDocument)); + when(() => request.close()).thenAnswer((_) async => response); + when( + () => mockClient.getUrl( + Uri.parse('http://localhost:8892/ingress/did.json'), + ), + ).thenAnswer((_) async => request); + + final result = await DidWeb.resolve( + 'did:web:localhost%3A8892:ingress', + client: mockClient, + ); expect(result.didDocument, isNotNull); - expect('did:web:localhost%3A8892:ingress', result.didDocument!.id); + verify( + () => mockClient + .getUrl(Uri.parse('http://localhost:8892/ingress/did.json')), + ); }); }); }