From fb5d2d06efa71d196031f6573ef1e38d8e52e899 Mon Sep 17 00:00:00 2001 From: Sri Teja T Date: Thu, 12 Sep 2024 20:34:47 +0530 Subject: [PATCH 1/6] fix: update AtLookup.executeVerb to consume enroll verb handler --- packages/at_lookup/lib/src/at_lookup_impl.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/at_lookup/lib/src/at_lookup_impl.dart b/packages/at_lookup/lib/src/at_lookup_impl.dart index f5cfc668..db070f92 100644 --- a/packages/at_lookup/lib/src/at_lookup_impl.dart +++ b/packages/at_lookup/lib/src/at_lookup_impl.dart @@ -179,7 +179,8 @@ class AtLookupImpl implements AtLookUp { logger.finer('value: $value dataSignature:$dataSignature'); var isDataValid = publicKey.verifySHA256Signature( // ignore: unnecessary_cast - utf8.encode(value) as Uint8List, base64Decode(dataSignature)); + utf8.encode(value) as Uint8List, + base64Decode(dataSignature)); logger.finer('data verify result: $isDataValid'); return 'data:$value'; } on Exception catch (e) { @@ -296,6 +297,8 @@ class AtLookupImpl implements AtLookUp { verbResult = await _notifyRemove(builder); } else if (builder is NotifyFetchVerbBuilder) { verbResult = await _notifyFetch(builder); + } else if (builder is EnrollVerbBuilder){ + verbResult = await _enroll(builder); } } on Exception catch (e) { logger.severe('Error in remote verb execution ${e.toString()}'); @@ -336,7 +339,7 @@ class AtLookupImpl implements AtLookUp { // TODO: Can we remove the below catch block in next release once all the servers are migrated to new version. if (verbResult.contains('-')) { errorCode = verbResult.substring(0, verbResult.indexOf('-')); - errorDescription = verbResult.substring(verbResult.indexOf('-')+1); + errorDescription = verbResult.substring(verbResult.indexOf('-') + 1); } else { errorDescription += ": $verbResult"; } @@ -407,6 +410,11 @@ class AtLookupImpl implements AtLookUp { return await _process(atCommand, auth: true); } + Future _enroll(EnrollVerbBuilder builder) async { + var atCommand = builder.buildCommand(); + return await _process(atCommand, auth: true); + } + @override Future executeCommand(String atCommand, {bool auth = false}) async { String verbResponse = await _process(atCommand, auth: auth); From 2b14893402333f7a66ddb3e7053978f49ae3e290 Mon Sep 17 00:00:00 2001 From: Sri Teja T Date: Thu, 12 Sep 2024 20:37:04 +0530 Subject: [PATCH 2/6] docs: update pubspec and changelog --- packages/at_lookup/CHANGELOG.md | 3 +++ packages/at_lookup/pubspec.yaml | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/at_lookup/CHANGELOG.md b/packages/at_lookup/CHANGELOG.md index 7e310f80..eb585c31 100644 --- a/packages/at_lookup/CHANGELOG.md +++ b/packages/at_lookup/CHANGELOG.md @@ -1,3 +1,6 @@ +## 3.0.48 +- feat: consume EnrollVerbBuilder in AtLookup.executeVerb() +- chore: upgrade at_commons to v4.1.1 and at_Utils to v3.0.18 ## 3.0.47 - fix: Fixed legacy error handling so error message isn't truncated if it contains a hyphen diff --git a/packages/at_lookup/pubspec.yaml b/packages/at_lookup/pubspec.yaml index 9da24553..caf17e64 100644 --- a/packages/at_lookup/pubspec.yaml +++ b/packages/at_lookup/pubspec.yaml @@ -1,6 +1,6 @@ name: at_lookup description: A Dart library that contains the core commands that can be used with a secondary server (scan, update, lookup, llookup, plookup, etc.) -version: 3.0.47 +version: 3.0.48 repository: https://github.com/atsign-foundation/at_libraries homepage: https://atsign.com documentation: https://docs.atsign.com/ @@ -12,8 +12,8 @@ dependencies: path: ^1.8.0 crypton: ^2.0.1 crypto: ^3.0.1 - at_utils: ^3.0.16 - at_commons: ^4.0.0 + at_utils: ^3.0.18 + at_commons: ^4.1.1 mutex: ^3.0.0 meta: ^1.8.0 at_chops: ^2.0.0 From cdcea33b7a56f6a1c260ad9e014c7577e5ee37a3 Mon Sep 17 00:00:00 2001 From: Sri Teja T Date: Thu, 12 Sep 2024 22:48:16 +0530 Subject: [PATCH 3/6] fix: send enroll request on un-authed connection --- packages/at_lookup/lib/src/at_lookup_impl.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/at_lookup/lib/src/at_lookup_impl.dart b/packages/at_lookup/lib/src/at_lookup_impl.dart index db070f92..52cbd9af 100644 --- a/packages/at_lookup/lib/src/at_lookup_impl.dart +++ b/packages/at_lookup/lib/src/at_lookup_impl.dart @@ -412,6 +412,9 @@ class AtLookupImpl implements AtLookUp { Future _enroll(EnrollVerbBuilder builder) async { var atCommand = builder.buildCommand(); + if(builder.operation == EnrollOperationEnum.request){ + return _process(atCommand, auth: false); + } return await _process(atCommand, auth: true); } From bf70ac75fa3b22cd2f9dc2ac0e8a64cfbd63a9bb Mon Sep 17 00:00:00 2001 From: Sri Teja T Date: Thu, 12 Sep 2024 22:48:40 +0530 Subject: [PATCH 4/6] test: add unit tests to validate changes --- packages/at_lookup/test/at_lookup_test.dart | 156 +++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/packages/at_lookup/test/at_lookup_test.dart b/packages/at_lookup/test/at_lookup_test.dart index 2beb08f4..64a51af9 100644 --- a/packages/at_lookup/test/at_lookup_test.dart +++ b/packages/at_lookup/test/at_lookup_test.dart @@ -1,8 +1,13 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi'; import 'dart:io'; import 'package:at_chops/at_chops.dart'; +import 'package:at_commons/at_builders.dart'; import 'package:at_commons/at_commons.dart'; import 'package:at_lookup/at_lookup.dart'; +import 'package:at_lookup/src/connection/at_connection.dart'; import 'package:at_lookup/src/connection/outbound_message_listener.dart'; import 'package:test/test.dart'; import 'package:mocktail/mocktail.dart'; @@ -212,6 +217,7 @@ void main() { e is UnAuthenticatedException && e.message.contains('AT0401')))); }); }); + group('A group of tests to verify executeCommand method', () { test('executeCommand - from verb - auth false', () async { final atLookup = AtLookupImpl('@alice', atServerHost, 64, @@ -226,6 +232,7 @@ void main() { var result = await atLookup.executeCommand('from:@alice\n'); expect(result, fromResponse); }); + test('executeCommand -llookup verb - auth true - auth key not set', () async { final atLookup = AtLookupImpl('@alice', atServerHost, 64, @@ -292,7 +299,8 @@ void main() { outboundConnectionFactory: mockOutboundConnectionFactory); atLookup.atChops = mockAtChops; final llookupCommand = 'llookup:phone@alice\n'; - final llookupResponse = 'error:{"errorCode":"AT0015","errorDescription":"Exception: fubar"}'; + final llookupResponse = + 'error:{"errorCode":"AT0015","errorDescription":"Exception: fubar"}'; when(() => mockOutBoundConnection.write(llookupCommand)) .thenAnswer((invocation) { mockSecureSocket.write(llookupCommand); @@ -306,4 +314,150 @@ void main() { e is AtLookUpException && e.errorMessage == 'Exception: fubar'))); }); }); + + group('Validate executeVerb() behaviour', () { + test('validate EnrollVerbHandler behaviour - request', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + secureSocketFactory: mockSocketFactory, + socketListenerFactory: mockSecureSocketListenerFactory, + outboundConnectionFactory: mockOutboundConnectionFactory); + atLookup.atChops = mockAtChops; + + String appName = 'unit_test_1'; + String deviceName = 'test_device'; + String otp = 'ABCDEF'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.request + ..appName = appName + ..deviceName = deviceName + ..otp = otp; + String enrollCommand = + 'enroll:request:{"appName":"$appName","deviceName":"$deviceName","otp":"$otp"}\n'; + final enrollResponse = + 'data:{"enrollmentId":"1234567890","status":"pending"}'; + + when(() => mockOutBoundConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = OutboundConnectionMetadata() + ..isAuthenticated = false; + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + var result = await atLookup.executeVerb(enrollVerbBuilder); + expect(result, enrollResponse); + }); + + test('validate behaviour with EnrollVerbHandler - approve', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + secureSocketFactory: mockSocketFactory, + socketListenerFactory: mockSecureSocketListenerFactory, + outboundConnectionFactory: mockOutboundConnectionFactory); + atLookup.atChops = mockAtChops; + + String appName = 'unit_test_2'; + String deviceName = 'test_device'; + String otp = 'GHIJKL'; + String enrollmentId = '1357913579'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.approve + ..enrollmentId = '1357913579' + ..appName = appName + ..deviceName = deviceName; + String enrollCommand = + 'enroll:approve:{"enrollmentId":"$enrollmentId","appName":"$appName","deviceName":"$deviceName"}\n'; + final enrollResponse = + 'data:{"enrollmentId":"1357913579","status":"approved"}'; + + when(() => mockOutBoundConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = OutboundConnectionMetadata() + ..isAuthenticated = true; + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); + }); + + test('validate behaviour with EnrollVerbHandler - revoke', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + secureSocketFactory: mockSocketFactory, + socketListenerFactory: mockSecureSocketListenerFactory, + outboundConnectionFactory: mockOutboundConnectionFactory); + atLookup.atChops = mockAtChops; + String enrollmentId = '89213647826348'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.revoke + ..enrollmentId = enrollmentId; + String enrollCommand = + 'enroll:revoke:{"enrollmentId":"$enrollmentId"}\n'; + String enrollResponse = + 'data:{"enrollmentId":"$enrollmentId","status":"revoked"}'; + + when(() => mockOutBoundConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = OutboundConnectionMetadata() + ..isAuthenticated = true; + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); + }); + + test('validate behaviour with EnrollVerbHandler - deny', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + secureSocketFactory: mockSocketFactory, + socketListenerFactory: mockSecureSocketListenerFactory, + outboundConnectionFactory: mockOutboundConnectionFactory); + atLookup.atChops = mockAtChops; + String enrollmentId = '5754765754'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.deny + ..enrollmentId = enrollmentId; + String enrollCommand = + 'enroll:deny:{"enrollmentId":"$enrollmentId"}\n'; + String enrollResponse = + 'data:{"enrollmentId":"$enrollmentId","status":"denied"}'; + + when(() => mockOutBoundConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = OutboundConnectionMetadata() + ..isAuthenticated = true; + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); + }); + }); } From a293b1f2bb64475a43ed1bce3598f92ce828420c Mon Sep 17 00:00:00 2001 From: Sri Teja T Date: Thu, 12 Sep 2024 22:50:11 +0530 Subject: [PATCH 5/6] docs: fix typo in changelog --- packages/at_lookup/CHANGELOG.md | 2 +- packages/at_lookup/test/at_lookup_test.dart | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/at_lookup/CHANGELOG.md b/packages/at_lookup/CHANGELOG.md index eb585c31..8e9f15d9 100644 --- a/packages/at_lookup/CHANGELOG.md +++ b/packages/at_lookup/CHANGELOG.md @@ -1,6 +1,6 @@ ## 3.0.48 - feat: consume EnrollVerbBuilder in AtLookup.executeVerb() -- chore: upgrade at_commons to v4.1.1 and at_Utils to v3.0.18 +- chore: upgrade at_commons to v4.1.1 and at_utils to v3.0.18 ## 3.0.47 - fix: Fixed legacy error handling so error message isn't truncated if it contains a hyphen diff --git a/packages/at_lookup/test/at_lookup_test.dart b/packages/at_lookup/test/at_lookup_test.dart index 64a51af9..e16cc497 100644 --- a/packages/at_lookup/test/at_lookup_test.dart +++ b/packages/at_lookup/test/at_lookup_test.dart @@ -1,6 +1,4 @@ import 'dart:async'; -import 'dart:convert'; -import 'dart:ffi'; import 'dart:io'; import 'package:at_chops/at_chops.dart'; @@ -365,7 +363,6 @@ void main() { String appName = 'unit_test_2'; String deviceName = 'test_device'; - String otp = 'GHIJKL'; String enrollmentId = '1357913579'; EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() From 786e3c90fefc865806c6053f90f43f0d2dcd2fa3 Mon Sep 17 00:00:00 2001 From: Sri Teja T Date: Thu, 12 Sep 2024 22:58:52 +0530 Subject: [PATCH 6/6] chore: run dart formatter --- packages/at_lookup/example/bin/example.dart | 12 ++++++++---- packages/at_lookup/lib/src/at_lookup_impl.dart | 4 ++-- packages/at_lookup/test/at_lookup_test.dart | 7 ++----- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/at_lookup/example/bin/example.dart b/packages/at_lookup/example/bin/example.dart index 20588436..69c3a3b6 100644 --- a/packages/at_lookup/example/bin/example.dart +++ b/packages/at_lookup/example/bin/example.dart @@ -18,7 +18,8 @@ void main() async { /// To update a key into secondary server //Build update verb builder var updateVerbBuilder = UpdateVerbBuilder() - ..atKey = (AtKey.shared('phone', sharedBy: '@alice')..sharedWith('@bob')).build() + ..atKey = + (AtKey.shared('phone', sharedBy: '@alice')..sharedWith('@bob')).build() ..value = '+1 889 886 7879'; // Sends update command to secondary server @@ -38,12 +39,14 @@ void main() async { /// To retrieve the value of key created by self. var lLookupVerbBuilder = LLookupVerbBuilder() - ..atKey = (AtKey.shared('phone', sharedBy: '@alice')..sharedWith('@bob')).build(); + ..atKey = + (AtKey.shared('phone', sharedBy: '@alice')..sharedWith('@bob')).build(); await atLookupImpl.executeVerb(lLookupVerbBuilder); ///To remove a key from secondary server var deleteVerbBuilder = DeleteVerbBuilder() - ..atKey = (AtKey.shared('phone', sharedBy: '@alice')..sharedWith('@bob')).build(); + ..atKey = + (AtKey.shared('phone', sharedBy: '@alice')..sharedWith('@bob')).build(); await atLookupImpl.executeVerb(deleteVerbBuilder, sync: true); /// To retrieve keys from the secondary server @@ -52,7 +55,8 @@ void main() async { ///To notify key to another atSign var notifyVerbBuilder = NotifyVerbBuilder() - ..atKey = (AtKey.shared('phone', sharedBy: '@alice')..sharedWith('@bob')).build(); + ..atKey = + (AtKey.shared('phone', sharedBy: '@alice')..sharedWith('@bob')).build(); await atLookupImpl.executeVerb(notifyVerbBuilder); ///To retrieve the notifications received diff --git a/packages/at_lookup/lib/src/at_lookup_impl.dart b/packages/at_lookup/lib/src/at_lookup_impl.dart index 52cbd9af..550c1801 100644 --- a/packages/at_lookup/lib/src/at_lookup_impl.dart +++ b/packages/at_lookup/lib/src/at_lookup_impl.dart @@ -297,7 +297,7 @@ class AtLookupImpl implements AtLookUp { verbResult = await _notifyRemove(builder); } else if (builder is NotifyFetchVerbBuilder) { verbResult = await _notifyFetch(builder); - } else if (builder is EnrollVerbBuilder){ + } else if (builder is EnrollVerbBuilder) { verbResult = await _enroll(builder); } } on Exception catch (e) { @@ -412,7 +412,7 @@ class AtLookupImpl implements AtLookUp { Future _enroll(EnrollVerbBuilder builder) async { var atCommand = builder.buildCommand(); - if(builder.operation == EnrollOperationEnum.request){ + if (builder.operation == EnrollOperationEnum.request) { return _process(atCommand, auth: false); } return await _process(atCommand, auth: true); diff --git a/packages/at_lookup/test/at_lookup_test.dart b/packages/at_lookup/test/at_lookup_test.dart index e16cc497..c248089f 100644 --- a/packages/at_lookup/test/at_lookup_test.dart +++ b/packages/at_lookup/test/at_lookup_test.dart @@ -320,7 +320,6 @@ void main() { secureSocketFactory: mockSocketFactory, socketListenerFactory: mockSecureSocketListenerFactory, outboundConnectionFactory: mockOutboundConnectionFactory); - atLookup.atChops = mockAtChops; String appName = 'unit_test_1'; String deviceName = 'test_device'; @@ -403,8 +402,7 @@ void main() { EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() ..operation = EnrollOperationEnum.revoke ..enrollmentId = enrollmentId; - String enrollCommand = - 'enroll:revoke:{"enrollmentId":"$enrollmentId"}\n'; + String enrollCommand = 'enroll:revoke:{"enrollmentId":"$enrollmentId"}\n'; String enrollResponse = 'data:{"enrollmentId":"$enrollmentId","status":"revoked"}'; @@ -436,8 +434,7 @@ void main() { EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() ..operation = EnrollOperationEnum.deny ..enrollmentId = enrollmentId; - String enrollCommand = - 'enroll:deny:{"enrollmentId":"$enrollmentId"}\n'; + String enrollCommand = 'enroll:deny:{"enrollmentId":"$enrollmentId"}\n'; String enrollResponse = 'data:{"enrollmentId":"$enrollmentId","status":"denied"}';