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

feat: Consume enroll verb builder in AtLookup.executeVerb() #657

Merged
merged 6 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions packages/at_lookup/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
12 changes: 8 additions & 4 deletions packages/at_lookup/example/bin/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
15 changes: 13 additions & 2 deletions packages/at_lookup/lib/src/at_lookup_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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()}');
Expand Down Expand Up @@ -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";
}
Expand Down Expand Up @@ -407,6 +410,14 @@ class AtLookupImpl implements AtLookUp {
return await _process(atCommand, auth: true);
}

Future<String> _enroll(EnrollVerbBuilder builder) async {
srieteja marked this conversation as resolved.
Show resolved Hide resolved
var atCommand = builder.buildCommand();
if (builder.operation == EnrollOperationEnum.request) {
return _process(atCommand, auth: false);
}
return await _process(atCommand, auth: true);
srieteja marked this conversation as resolved.
Show resolved Hide resolved
}

@override
Future<String?> executeCommand(String atCommand, {bool auth = false}) async {
String verbResponse = await _process(atCommand, auth: auth);
Expand Down
6 changes: 3 additions & 3 deletions packages/at_lookup/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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/
Expand All @@ -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
Expand Down
150 changes: 149 additions & 1 deletion packages/at_lookup/test/at_lookup_test.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'dart:async';
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';
Expand Down Expand Up @@ -212,6 +215,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,
Expand All @@ -226,6 +230,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,
Expand Down Expand Up @@ -292,7 +297,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);
Expand All @@ -306,4 +312,146 @@ 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);

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;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set 'isAuthenticated' to false for enroll:request test to ensure 'auth : false' is working

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 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);
});
});
}