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

fix: Add unrevoke to the at_onboarding_cli #682

Merged
merged 22 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6380957
feat: introduce delete as auth_cli arg
srieteja Sep 12, 2024
62c1604
feat: impl to allow deletion of denied enrollments
srieteja Sep 12, 2024
7c2e2aa
Merge branch 'refs/heads/trunk' into at_activate_remove_denied
srieteja Sep 12, 2024
86bd8e5
Merge branch 'refs/heads/trunk' into at_activate_remove_denied
srieteja Sep 12, 2024
4225438
feat: remove logic to check if enrollment denied
srieteja Sep 12, 2024
b5cf56f
feat: replace manual commands with verb builders
srieteja Sep 12, 2024
7a5ff54
fix: Add unrevoke to the at_onboarding_cli
sitaram-kalluri Oct 2, 2024
ab38076
fix: Add log statements in test
sitaram-kalluri Oct 3, 2024
6ae45ea
Merge remote-tracking branch 'origin/trunk' into at_activate_remove_d…
sitaram-kalluri Oct 9, 2024
cd05d60
fix: Rename the methods names and updated the usage of deleteEnrollment
sitaram-kalluri Oct 9, 2024
fcdaae7
Merge remote-tracking branch 'origin/trunk' into at_activate_remove_d…
gkc Oct 9, 2024
29b5c7c
docs: at_onboarding_cli: add to CHANGELOG for `delete` command
gkc Oct 9, 2024
6de0496
Merge remote-tracking branch 'origin/trunk' into unrevoke_at_onboardi…
gkc Oct 9, 2024
5407f7f
docs: at_onboarding_cli: add to CHANGELOG for `unrevoke` command
gkc Oct 9, 2024
57a066c
chore: dart format
gkc Oct 9, 2024
18e37fa
fix: added parameter introduced by merge from trunk
gkc Oct 9, 2024
46833f3
fix: removed state check from `auth_cli.createAtClient` as it was cau…
gkc Oct 9, 2024
8795894
fix: use auth_cli.wrappedMain in enrollment_cli_commands_test.dart so…
gkc Oct 9, 2024
63eeb69
Merge remote-tracking branch 'origin/at_activate_remove_denied' into …
gkc Oct 9, 2024
0c16ffd
fix: replaced another `exit` statement with a `throw` - this time in …
gkc Oct 9, 2024
ba133dd
chore: dart format
gkc Oct 9, 2024
53c3288
build: update at_onboarding_cli version to 1.8.0 ready for publishing…
gkc Oct 9, 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
3 changes: 3 additions & 0 deletions packages/at_onboarding_cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.8.0
- feat: add `unrevoke` command to the activate CLI
- feat: add `delete` command to the activate CLI
## 1.7.0
- feat: add `auto` command to the activate CLI
## 1.6.4
Expand Down
123 changes: 84 additions & 39 deletions packages/at_onboarding_cli/lib/src/cli/auth_cli.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:args/args.dart';
import 'package:at_auth/at_auth.dart';
import 'package:at_cli_commons/at_cli_commons.dart';
import 'package:at_client/at_client.dart';
import 'package:at_commons/at_builders.dart';
import 'package:at_lookup/at_lookup.dart';
import 'package:at_onboarding_cli/at_onboarding_cli.dart';
import 'package:at_onboarding_cli/src/util/at_onboarding_exceptions.dart';
Expand Down Expand Up @@ -195,6 +196,14 @@ Future<int> wrappedMain(List<String> arguments) async {
// Write keys to @atSign_keys.atKeys IFF it doesn't already exist; if
// it does exist, then write to @atSign_appName_deviceName_keys.atKeys
await enroll(commandArgResults);

case AuthCliCommand.unrevoke:
await unrevoke(
commandArgResults, await createAtClient(commandArgResults));

case AuthCliCommand.delete:
await deleteEnrollment(
commandArgResults, await createAtClient(commandArgResults));
}
} on ArgumentError catch (e) {
stderr
Expand Down Expand Up @@ -272,10 +281,6 @@ Future<int> status(ArgResults ar) async {
}

Future<AtClient> createAtClient(ArgResults ar) async {
if (storageDir != null) {
throw StateError('AtClient has already been created');
}

String nameSpace = 'at_activate';
String atSign = AtUtils.fixAtSign(ar[AuthCliArgs.argNameAtSign]);
storageDir = standardAtClientStorageDir(
Expand Down Expand Up @@ -317,24 +322,27 @@ Future<void> onboard(ArgResults argResults, {AtOnboardingService? svc}) async {
'[Information] Onboarding your atSign. This may take up to 2 minutes.');
try {
await svc.onboard();
logger.finest('svc.onboard() has returned - will exit(0)');
exit(0);
return;
} on InvalidDataException catch (e) {
stderr.writeln(
'[Error] Onboarding failed. Invalid data provided by user. Please try again\nCause: ${e.message}');
exit(1);
throw AtEnrollmentException(
'Onboarding failed. Please try again. Cause: ${e.message}');
} on InvalidRequestException catch (e) {
stderr.writeln(
'[Error] Onboarding failed. Invalid data provided by user. Please try again\nCause: ${e.message}');
exit(1);
} on AtActivateException catch (e) {
stderr.writeln('[Error] ${e.message}');
exit(1);
} on Exception catch (e) {
stderr.writeln(
'[Error] Onboarding failed. It looks like something went wrong on our side.\n'
'Please try again or contact [email protected]\nCause: $e');
exit(1);
throw AtEnrollmentException(
'Onboarding failed. Please try again. Cause: ${e.message}');
} on AtActivateException {
rethrow;
} catch (e) {
throw ('Onboarding failed.'
' It looks like something went wrong on our side.'
' Please try again or contact [email protected]\nCause: $e');
}
}

String parseServerResponse(String? response) {
if (response != null && response.startsWith('data:')) {
return response.replaceFirst('data:', '');
} else {
throw ('Unexpected server response: $response');
}
}

Expand Down Expand Up @@ -535,6 +543,12 @@ Future<void> interactive(ArgResults argResults, AtClient atClient) async {

case AuthCliCommand.revoke:
await revoke(commandArgResults, atClient);

case AuthCliCommand.unrevoke:
await unrevoke(commandArgResults, atClient);

case AuthCliCommand.delete:
await deleteEnrollment(commandArgResults, atClient);
}
} on ArgumentError catch (e) {
stderr.writeln(
Expand Down Expand Up @@ -590,8 +604,7 @@ Future<Map> _list(
stdout.writeln("Found ${filtered.length} matching enrollment records");
return filtered;
} else {
stderr.writeln('Exiting: Unexpected server response: $rawResponse');
exit(1);
throw Exception('Unexpected server response: $rawResponse');
}
}

Expand Down Expand Up @@ -623,20 +636,14 @@ Future<void> list(ArgResults ar, AtClient atClient) async {
}

Future<Map?> _fetch(String eId, AtLookUp atLookup) async {
String rawResponse = (await atLookup.executeCommand(
'enroll:fetch:'
'{"enrollmentId":"$eId"}'
'\n',
auth: true))!;

if (rawResponse.startsWith('data:')) {
rawResponse = rawResponse.substring(rawResponse.indexOf('data:') + 5);
// response is a Map
return jsonDecode(rawResponse);
} else {
stderr.writeln('Exiting: Unexpected server response: $rawResponse');
exit(1);
}
EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder()
..operation = EnrollOperationEnum.fetch
..enrollmentId = eId;
String? response = await atLookup.executeVerb(enrollVerbBuilder);

response = parseServerResponse(response);
// response is a Map
return jsonDecode(response);
}

Future<void> fetch(ArgResults argResults, AtClient atClient) async {
Expand Down Expand Up @@ -853,9 +860,10 @@ Future<void> deny(ArgResults ar, AtClient atClient) async {
// Iterate through the requests, deny each one
for (String eId in toDeny.keys) {
stdout.writeln('Denying enrollmentId $eId');
// 'enroll:deny:{"enrollmentId":"$enrollmentId"}'
String? response = await atLookup
.executeCommand('enroll:deny:{"enrollmentId":"$eId"}\n', auth: true);
EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder()
..operation = EnrollOperationEnum.deny
..enrollmentId = eId;
String? response = await atLookup.executeVerb(enrollVerbBuilder);
stdout.writeln('Server response: $response');
}
}
Expand Down Expand Up @@ -886,6 +894,43 @@ Future<void> revoke(ArgResults ar, AtClient atClient) async {
}
}

Future<void> unrevoke(ArgResults ar, AtClient atClient) async {
AtLookUp atLookup = atClient.getRemoteSecondary()!.atLookUp;

Map toUnRevoke = await _fetchOrListAndFilter(
atLookup,
EnrollmentStatus.approved.name, // must be status approved
eId: ar[AuthCliArgs.argNameEnrollmentId],
arx: ar[AuthCliArgs.argNameAppNameRegex],
drx: ar[AuthCliArgs.argNameDeviceNameRegex],
);

if (toUnRevoke.isEmpty) {
stderr.writeln('No matching enrollment(s) found');
return;
}

for (String eId in toUnRevoke.keys) {
stdout.writeln('Un-Revoking enrollmentId $eId');
String? response = await atLookup.executeCommand(
'enroll:unrevoke:{"enrollmentId":"$eId"}\n',
auth: true);
stdout.writeln('Server response: $response');
}
}

Future<void> deleteEnrollment(ArgResults ar, AtClient atClient) async {
AtLookUp atLookup = atClient.getRemoteSecondary()!.atLookUp;
String eId = ar[AuthCliArgs.argNameEnrollmentId];
EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder()
..enrollmentId = eId
..operation = EnrollOperationEnum.delete;
stdout.writeln('Sending delete request');
String? response = await atLookup.executeVerb(enrollVerbBuilder);
response = parseServerResponse(response);
stdout.writeln('Server response: $response');
}

@visibleForTesting
AtOnboardingService createOnboardingService(ArgResults ar) {
String atSign = AtUtils.fixAtSign(ar[AuthCliArgs.argNameAtSign]);
Expand Down
38 changes: 34 additions & 4 deletions packages/at_onboarding_cli/lib/src/cli/auth_cli_args.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,16 @@ enum AuthCliCommand {
list(usage: 'List enrollment requests'),
fetch(usage: 'Fetch a specific enrollment request'),
approve(usage: 'Approve a pending enrollment request'),
auto(usage: 'Listen for new enrollment requests which match the parameters'
' supplied, and auto-approve them. Will exit after N (defaults to 1)'
' enrollment requests have been approved.'),
auto(
usage: 'Listen for new enrollment requests which match the parameters'
' supplied, and auto-approve them. Will exit after N (defaults to 1)'
' enrollment requests have been approved.'),
deny(usage: 'Deny a pending enrollment request'),
revoke(usage: 'Revoke approval of a previously-approved enrollment'),
unrevoke(usage: 'Restores access to the previously revoked enrollment'),
delete(
usage: 'Deletes an enrollment. Requires an enrollmentId to be provided'
'\nNOTE: Can ONLY delete denied and revoked enrollments'),
enroll(
usage: 'Enroll is used when a program needs to authenticate and'
' "atKeys" are not available, and "onboard" has already been run'
Expand Down Expand Up @@ -182,6 +187,12 @@ class AuthCliArgs {

case AuthCliCommand.revoke:
return createRevokeCommandParser();

case AuthCliCommand.unrevoke:
return createUnRevokeCommandParser();

case AuthCliCommand.delete:
return createDeleteCommandParser();
}
}

Expand Down Expand Up @@ -427,7 +438,7 @@ class AuthCliArgs {
@visibleForTesting
ArgParser createAutoApproveCommandParser() {
ArgParser p = createSharedArgParser(hide: true);
_addEnrollmentIdOption(p, hide:true);
_addEnrollmentIdOption(p, hide: true);
_addAppNameRegexOption(p, mandatory: true);
_addDeviceNameRegexOption(p, mandatory: true);
p.addOption(
Expand Down Expand Up @@ -467,4 +478,23 @@ class AuthCliArgs {
_addDeviceNameRegexOption(p, mandatory: false);
return p;
}

/// Restore the revoked enrollment Id.
@visibleForTesting
ArgParser createUnRevokeCommandParser() {
ArgParser p = createSharedArgParser(hide: true);
_addEnrollmentIdOption(p);
_addAppNameRegexOption(p, mandatory: false);
_addDeviceNameRegexOption(p, mandatory: false);
return p;
}

/// auth delete denied enrollment: requires enrollmentId and atKeysFile path
/// requires the enrollment to be denied
@visibleForTesting
ArgParser createDeleteCommandParser() {
ArgParser p = createSharedArgParser(hide: true);
_addEnrollmentIdOption(p, mandatory: true);
return p;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class OnboardingUtil {
'To register a new atSign to this email address, please log into the dashboard \'my.atsign.com/login\'.\n'
'Remove at least 1 atSign from your account and then try again.\n'
'Alternatively, you can retry this process with a different email address.');
exit(1);
throw at_client.AtClientException.message(jsonDecoded['message']);
} else {
throw at_client.AtClientException.message(
'${response.statusCode} ${jsonDecoded['message']}');
Expand Down
2 changes: 1 addition & 1 deletion packages/at_onboarding_cli/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: at_onboarding_cli
description: Dart tools for initial client onboarding, subsequent client enrollment, and enrollment management.
version: 1.7.0
version: 1.8.0
repository: https://github.com/atsign-foundation/at_libraries
homepage: https://atsign.com
documentation: https://docs.atsign.com/
Expand Down
Loading