Skip to content

Commit

Permalink
Merge pull request #1257 from atsign-foundation/apkam_onboarding_chan…
Browse files Browse the repository at this point in the history
…ges_with_enrollment_status
  • Loading branch information
gkc authored Apr 11, 2024
2 parents da80132 + be3cd10 commit 882c8d5
Show file tree
Hide file tree
Showing 38 changed files with 1,892 additions and 301 deletions.
39 changes: 20 additions & 19 deletions packages/at_client/lib/at_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,37 @@ library at_client;

import 'package:meta/meta.dart';

@experimental
export 'package:at_client/src/at_collection/at_collection_model.dart';
@experimental
export 'package:at_client/src/at_collection/at_collection_model_factory.dart';
export 'package:at_client/src/client/at_client_impl.dart';
export 'package:at_client/src/client/at_client_spec.dart';
export 'package:at_client/src/client/local_secondary.dart';
export 'package:at_client/src/client/remote_secondary.dart';
export 'package:at_client/src/client/request_options.dart';
export 'package:at_client/src/key_stream/key_stream.dart';
export 'package:at_client/src/listener/connectivity_listener.dart';
export 'package:at_client/src/listener/sync_progress_listener.dart';
export 'package:at_client/src/manager/at_client_manager.dart';
export 'package:at_client/src/preference/at_client_preference.dart';
export 'package:at_client/src/response/at_notification.dart';
export 'package:at_client/src/util/at_client_util.dart';
export 'package:at_client/src/util/encryption_util.dart';
export 'package:at_client/src/util/enrollment_request.dart';
export 'package:at_client/src/util/enroll_list_request_param.dart';
export 'package:at_client/src/response/pending_enrollment_request.dart';
@experimental
export 'package:at_client/src/rpc/at_rpc.dart';
@experimental
export 'package:at_client/src/rpc/at_rpc_types.dart';
export 'package:at_client/src/service/enrollment_service.dart';
export 'package:at_client/src/service/notification_service.dart';
export 'package:at_client/src/service/sync_service.dart';
export 'package:at_client/src/service/sync/sync_conflict.dart';
export 'package:at_client/src/service/sync/sync_result.dart';
export 'package:at_client/src/service/sync/sync_status.dart';
export 'package:at_client/src/service/sync_service.dart';
export 'package:at_client/src/service/sync_service_impl.dart'
show KeyInfo, SyncDirection;
export 'package:at_client/src/service/sync/sync_status.dart';
export 'package:at_client/src/key_stream/key_stream.dart';
export 'package:at_client/src/service/sync/sync_conflict.dart';
export 'package:at_commons/at_commons.dart';
export 'package:at_client/src/listener/sync_progress_listener.dart';
export 'package:at_client/src/client/request_options.dart';
@experimental
export 'package:at_client/src/telemetry/at_client_telemetry.dart';
@experimental
export 'package:at_client/src/rpc/at_rpc_types.dart';
@experimental
export 'package:at_client/src/rpc/at_rpc.dart';
@experimental
export 'package:at_client/src/at_collection/at_collection_model.dart';
@experimental
export 'package:at_client/src/at_collection/at_collection_model_factory.dart';
export 'package:at_client/src/util/at_client_util.dart';
export 'package:at_client/src/util/encryption_util.dart';
export 'package:at_client/src/util/enroll_list_request_param.dart';
export 'package:at_commons/at_commons.dart';
42 changes: 11 additions & 31 deletions packages/at_client/lib/src/client/at_client_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io';

import 'package:at_base2e15/at_base2e15.dart';
import 'package:at_chops/at_chops.dart';
import 'package:at_client/at_client.dart';
import 'package:at_client/src/client/secondary.dart';
import 'package:at_client/src/client/verb_builder_manager.dart';
Expand Down Expand Up @@ -31,7 +32,6 @@ import 'package:at_commons/at_builders.dart';
import 'package:at_lookup/at_lookup.dart';
import 'package:at_persistence_secondary_server/at_persistence_secondary_server.dart';
import 'package:at_utils/at_utils.dart';
import 'package:at_chops/at_chops.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart';
import 'package:uuid/uuid.dart';
Expand Down Expand Up @@ -104,6 +104,16 @@ class AtClientImpl implements AtClient, AtSignChangeListener {
_notificationService = notificationService;
}

late EnrollmentService _enrollmentService;

@override
set enrollmentService(EnrollmentService enrollmentService) {
_enrollmentService = enrollmentService;
}

@override
EnrollmentService get enrollmentService => _enrollmentService;

@override
NotificationService get notificationService => _notificationService;

Expand Down Expand Up @@ -663,36 +673,6 @@ class AtClientImpl implements AtClient, AtSignChangeListener {
return AtChopsImpl(atChopsKeys);
}

@override
Future<List<EnrollmentRequest>> fetchEnrollmentRequests(
EnrollListRequestParam enrollmentListRequestParams) async {
// enrollmentListRequestParams for now is not used
// A server side enhancement request is created. https://github.com/atsign-foundation/at_server/issues/1748
// On implementation of this enhancement/feature, the enrollListRequestParam object can be made use of
EnrollVerbBuilder enrollBuilder = EnrollVerbBuilder()
..operation = EnrollOperationEnum.list
..appName = enrollmentListRequestParams.appName
..deviceName = enrollmentListRequestParams.deviceName;

var response = await getRemoteSecondary()
?.executeCommand(enrollBuilder.buildCommand(), auth: true);

return _formatEnrollListResponse(response);
}

List<EnrollmentRequest> _formatEnrollListResponse(response) {
response = response?.replaceFirst('data:', '');
Map<String, dynamic> enrollRequests = jsonDecode(response!);
List<EnrollmentRequest> enrollRequestsFormatted = [];
EnrollmentRequest? enrollment;
for (var request in enrollRequests.entries) {
enrollment = EnrollmentRequest.fromJson(request.value);
enrollment.enrollmentKey = request.key;
enrollRequestsFormatted.add(enrollment);
}
return enrollRequestsFormatted;
}

@override
Future<AtStreamResponse> stream(String sharedWith, String filePath,
{String? namespace}) async {
Expand Down
20 changes: 5 additions & 15 deletions packages/at_client/lib/src/client/at_client_spec.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import 'dart:io';

import 'package:at_chops/at_chops.dart';
import 'package:at_client/at_client.dart';
import 'package:at_client/src/manager/sync_manager.dart';
import 'package:at_client/src/response/response.dart';
import 'package:at_client/src/service/encryption_service.dart';
import 'package:at_client/src/stream/at_stream_response.dart';
import 'package:at_client/src/stream/file_transfer_object.dart';
import 'package:at_chops/at_chops.dart';
import 'package:meta/meta.dart';

/// Interface for a client application that can communicate with a secondary server.
Expand Down Expand Up @@ -46,6 +46,10 @@ abstract class AtClient {

NotificationService get notificationService;

set enrollmentService(EnrollmentService enrollmentService);

EnrollmentService get enrollmentService;

/// Sets the preferences such as sync strategy, storage path etc., for the client.
void setPreferences(AtClientPreference preference);

Expand Down Expand Up @@ -612,18 +616,4 @@ abstract class AtClient {
String? getCurrentAtSign();

EncryptionService? get encryptionService;

/// Fetches all enrollment requests from the corresponding atServer; Formats the requests into a
/// List<[EnrollmentResponse]>
///
/// Responses can be filtered using params provided through [EnrollListRequestParam]
/// ```
/// e.g.
/// List<EnrollmentRequest> enrollmentRequests = fetchEnrollmentRequests(EnrollRequestParams());
/// enrollmentRequests now contains all the enrollment requests fetched from the server in the for of
/// EnrollmentRequest objects
/// ```
@experimental
Future<List<EnrollmentRequest>> fetchEnrollmentRequests(
EnrollListRequestParam enrollmentListRequest);
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import 'package:at_client/at_client.dart';
import 'package:at_chops/at_chops.dart';
import 'package:at_utils/at_logger.dart';
import 'package:at_client/at_client.dart';
import 'package:at_client/src/decryption_service/decryption.dart';
import 'package:at_client/src/response/default_response_parser.dart';
import 'package:at_utils/at_logger.dart';

/// Class responsible for decrypting the value of self key's
/// Example:
/// CurrentAtSign: @bob and
/// llookup:phone.wavi@bob
/// llookup:@bob:phone@bob
class SelfKeyDecryption implements AtKeyDecryption {
final AtClient _atClient;
late final AtSignLogger _logger;

final AtClient _atClient;

SelfKeyDecryption(this._atClient) {
_logger =
AtSignLogger('SelfKeyDecryption (${_atClient.getCurrentAtSign()})');
}

@override
Future<dynamic> decrypt(AtKey atKey, dynamic encryptedValue) async {
if (encryptedValue == null ||
Expand All @@ -26,15 +29,15 @@ class SelfKeyDecryption implements AtKeyDecryption {
exceptionScenario: ExceptionScenario.decryptionFailed);
}

var selfEncryptionKey =
await _atClient.getLocalSecondary()!.getEncryptionSelfKey();
if ((selfEncryptionKey == null || selfEncryptionKey.isEmpty) ||
selfEncryptionKey == 'data:null') {
throw SelfKeyNotFoundException('Empty or null SelfEncryptionKey found',
intent: Intent.fetchSelfEncryptionKey,
exceptionScenario: ExceptionScenario.fetchEncryptionKeys);
if (_atClient.atChops == null ||
_atClient.atChops!.atChopsKeys.selfEncryptionKey == null) {
throw SelfKeyNotFoundException(
'Failed to decrypt the key: ${atKey.toString()} caused by self encryption key not found');
}

var selfEncryptionKey =
_atClient.atChops!.atChopsKeys.selfEncryptionKey!.key;

InitialisationVector iV;
if (atKey.metadata.ivNonce != null) {
iV = AtChopsUtil.generateIVFromBase64String(atKey.metadata.ivNonce!);
Expand All @@ -50,7 +53,7 @@ class SelfKeyDecryption implements AtKeyDecryption {
encryptionAlgorithm: encryptionAlgo, iv: iV);
} on AtDecryptionException catch (e) {
_logger.severe(
'decryption exception during of key: ${atKey.key}. Reason: ${e.toString()}');
'decryption exception during decryption of key: ${atKey.key}. Reason: ${e.toString()}');
rethrow;
}
return decryptionResultFromAtChops.result;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import 'package:at_chops/at_chops.dart';
import 'package:at_client/src/client/at_client_spec.dart';
import 'package:at_client/src/client/local_secondary.dart';
import 'package:at_client/src/encryption_service/encryption.dart';
import 'package:at_client/src/response/default_response_parser.dart';
import 'package:at_client/src/util/at_client_util.dart';
import 'package:at_commons/at_commons.dart';
import 'package:at_chops/at_chops.dart';
import 'package:at_utils/at_logger.dart';

///Class responsible for encrypting the selfKey's
class SelfKeyEncryption implements AtKeyEncryption {
late final AtSignLogger _logger;

final AtClient _atClient;
final AtClient atClient;

SelfKeyEncryption(this._atClient) {
SelfKeyEncryption(this.atClient) {
_logger =
AtSignLogger('SelfKeyEncryption (${_atClient.getCurrentAtSign()})');
AtSignLogger('SelfKeyEncryption (${atClient.getCurrentAtSign()})');
}

@override
Expand All @@ -27,11 +24,16 @@ class SelfKeyEncryption implements AtKeyEncryption {
throw AtEncryptionException(
'Invalid value type found: ${value.runtimeType}. Valid value type is String');
}

if (atClient.atChops == null ||
atClient.atChops!.atChopsKeys.selfEncryptionKey == null) {
throw SelfKeyNotFoundException(
'Failed to encrypt the data caused by Self encryption key not found');
}
// Get AES key for current atSign
var selfEncryptionKey =
await _getSelfEncryptionKey(_atClient.getLocalSecondary()!);
selfEncryptionKey =
DefaultResponseParser().parse(selfEncryptionKey).response;
atClient.atChops?.atChopsKeys.selfEncryptionKey?.key;

AtEncryptionResult encryptionResultFromAtChops;
try {
InitialisationVector iV;
Expand All @@ -40,8 +42,8 @@ class SelfKeyEncryption implements AtKeyEncryption {
} else {
iV = AtChopsUtil.generateIVLegacy();
}
var encryptionAlgo = AESEncryptionAlgo(AESKey(selfEncryptionKey));
encryptionResultFromAtChops = _atClient.atChops!.encryptString(
var encryptionAlgo = AESEncryptionAlgo(AESKey(selfEncryptionKey!));
encryptionResultFromAtChops = atClient.atChops!.encryptString(
value, EncryptionKeyType.aes256,
encryptionAlgorithm: encryptionAlgo, iv: iV);
} on AtEncryptionException catch (e) {
Expand All @@ -51,24 +53,4 @@ class SelfKeyEncryption implements AtKeyEncryption {
}
return encryptionResultFromAtChops.result;
}

Future<String> _getSelfEncryptionKey(LocalSecondary localSecondary) async {
String? selfEncryptionKey;
try {
selfEncryptionKey = await localSecondary.getEncryptionSelfKey();
if (selfEncryptionKey.isNull) {
_logger.severe('Found a null value for self encryption key');
throw SelfKeyNotFoundException(
'Self encryption key is not set for current atSign',
intent: Intent.fetchSelfEncryptionKey,
exceptionScenario: ExceptionScenario.encryptionFailed);
}
} on KeyNotFoundException {
throw SelfKeyNotFoundException(
'Self encryption key is not set for current atSign',
intent: Intent.fetchSelfEncryptionKey,
exceptionScenario: ExceptionScenario.encryptionFailed);
}
return selfEncryptionKey!;
}
}
15 changes: 15 additions & 0 deletions packages/at_client/lib/src/manager/at_client_manager.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import 'package:at_auth/at_auth.dart';
import 'package:at_chops/at_chops.dart';
import 'package:at_client/at_client.dart';
import 'package:at_client/src/listener/at_sign_change_listener.dart';
import 'package:at_client/src/listener/switch_at_sign_event.dart';
import 'package:at_client/src/service/enrollment_service_impl.dart';
import 'package:at_client/src/service/notification_service_impl.dart';
import 'package:at_client/src/service/sync_service_impl.dart';
import 'package:at_lookup/at_lookup.dart';
Expand Down Expand Up @@ -94,6 +96,10 @@ class AtClientManager {
_currentAtClient!, this, notificationService);
_currentAtClient!.syncService = syncService;

EnrollmentService enrollmentService =
serviceFactory.enrollmentService(_currentAtClient!);
_currentAtClient!.enrollmentService = enrollmentService;

_logger.info("setCurrentAtSign complete");

return this;
Expand Down Expand Up @@ -151,6 +157,8 @@ abstract class AtServiceFactory {

Future<SyncService> syncService(AtClient atClient,
AtClientManager atClientManager, NotificationService notificationService);

EnrollmentService enrollmentService(AtClient atClient);
}

class DefaultAtServiceFactory implements AtServiceFactory {
Expand Down Expand Up @@ -180,4 +188,11 @@ class DefaultAtServiceFactory implements AtServiceFactory {
atClientManager: atClientManager,
notificationService: notificationService);
}

@override
EnrollmentService enrollmentService(AtClient atClient) {
AtEnrollmentBase atEnrollmentBase =
atAuthBase.atEnrollment(atClient.getCurrentAtSign()!);
return EnrollmentServiceImpl(atClient, atEnrollmentBase);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/// Class represents the enrollment details
class PendingEnrollmentRequest {
String? enrollmentId;
String? appName;
String? deviceName;
Map<String, dynamic>? namespace;
String? encryptedAPKAMSymmetricKey;

static PendingEnrollmentRequest fromJSON(Map<String, dynamic> json) {
return PendingEnrollmentRequest()
..appName = json['appName']
..deviceName = json['deviceName']
..namespace = json['namespace']
..encryptedAPKAMSymmetricKey = json['encryptedAPKAMSymmetricKey'];
}

Map<String, dynamic> toJson() {
Map<String, dynamic> map = {};

map['appName'] = appName;
map['deviceName'] = deviceName;
map['namespace'] = namespace;
map['encryptedAPKAMSymmetricKey'] = encryptedAPKAMSymmetricKey;

return map;
}

@override
String toString() {
return 'enrollmentId: $enrollmentId, appName: $appName, deviceName: $deviceName';
}
}
Loading

0 comments on commit 882c8d5

Please sign in to comment.