diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/auth_plugin_impl.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/auth_plugin_impl.dart index 608fd09bf0..2c2c788f5a 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/auth_plugin_impl.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/auth_plugin_impl.dart @@ -31,6 +31,7 @@ import 'package:amplify_auth_cognito_dart/src/sdk/cognito_identity_provider.dart ForgotPasswordRequest, GetUserAttributeVerificationCodeRequest, GetUserRequest, + GetDeviceRequest, ListDevicesRequest, ResendConfirmationCodeRequest, UserContextDataType, @@ -39,6 +40,7 @@ import 'package:amplify_auth_cognito_dart/src/sdk/cognito_identity_provider.dart VerifyUserAttributeRequest; import 'package:amplify_auth_cognito_dart/src/sdk/sdk_bridge.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/analytics_metadata_type.dart'; +import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/get_device_response.dart'; import 'package:amplify_auth_cognito_dart/src/state/cognito_state_machine.dart'; import 'package:amplify_auth_cognito_dart/src/state/state.dart'; import 'package:amplify_auth_cognito_dart/src/util/cognito_iam_auth_provider.dart'; @@ -97,6 +99,7 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface late CognitoAuthStateMachine _stateMachine = CognitoAuthStateMachine( dependencyManager: dependencies, ); + StreamSubscription? _stateMachineSubscription; /// The underlying state machine, for use in subclasses. @@ -993,6 +996,46 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface .result; } + @override + Future fetchCurrentDevice() async { + final tokens = await stateMachine.getUserPoolTokens(); + final deviceSecrets = await _deviceRepo.get(tokens.username); + final deviceKey = deviceSecrets?.deviceKey; + if (deviceSecrets == null || deviceKey == null) { + throw const DeviceNotTrackedException(); + } + + late GetDeviceResponse response; + + try { + response = await _cognitoIdp + .getDevice( + cognito.GetDeviceRequest( + deviceKey: deviceKey, + accessToken: tokens.accessToken.raw, + ), + ) + .result; + } on Exception catch (error) { + throw AuthException.fromException(error); + } + + final device = response.device; + final attributes = + device.deviceAttributes ?? const []; + + return CognitoDevice( + id: deviceKey, + attributes: { + for (final attribute in attributes) + attribute.name: attribute.value ?? '', + }, + createdDate: device.deviceCreateDate, + lastAuthenticatedDate: device.deviceLastAuthenticatedDate, + lastModifiedDate: device.deviceLastModifiedDate, + ); + } + @override Future> fetchDevices() async { final allDevices = []; diff --git a/packages/auth/amplify_auth_cognito_test/test/plugin/fetch_current_device_test.dart b/packages/auth/amplify_auth_cognito_test/test/plugin/fetch_current_device_test.dart new file mode 100644 index 0000000000..7337899eac --- /dev/null +++ b/packages/auth/amplify_auth_cognito_test/test/plugin/fetch_current_device_test.dart @@ -0,0 +1,96 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_cognito_dart/amplify_auth_cognito_dart.dart'; +import 'package:amplify_auth_cognito_dart/src/credentials/cognito_keys.dart'; +import 'package:amplify_auth_cognito_dart/src/credentials/device_metadata_repository.dart'; +import 'package:amplify_auth_cognito_dart/src/sdk/cognito_identity_provider.dart'; +import 'package:amplify_auth_cognito_test/common/mock_clients.dart'; +import 'package:amplify_auth_cognito_test/common/mock_config.dart'; +import 'package:amplify_auth_cognito_test/common/mock_secure_storage.dart'; +import 'package:amplify_core/amplify_core.dart'; +import 'package:test/test.dart'; + +void main() { + AmplifyLogger().logLevel = LogLevel.verbose; + + final userPoolKeys = CognitoUserPoolKeys(userPoolConfig); + final identityPoolKeys = CognitoIdentityPoolKeys(identityPoolConfig); + final testAuthRepo = AmplifyAuthProviderRepository(); + final mockDevice = DeviceType(deviceKey: deviceKey); + final mockDeviceResponse = GetDeviceResponse(device: mockDevice); + + late DeviceMetadataRepository repo; + late AmplifyAuthCognitoDart plugin; + + group('fetchCurrentDevice', () { + setUp(() async { + final secureStorage = MockSecureStorage(); + seedStorage( + secureStorage, + userPoolKeys: userPoolKeys, + identityPoolKeys: identityPoolKeys, + deviceKeys: CognitoDeviceKeys(userPoolConfig, username), + ); + plugin = AmplifyAuthCognitoDart( + secureStorageFactory: (_) => secureStorage, + ); + await plugin.configure( + config: mockConfig, + authProviderRepo: testAuthRepo, + ); + repo = plugin.stateMachine.getOrCreate(); + }); + + group('should successfully', () { + setUp(() async { + final mockIdp = MockCognitoIdentityProviderClient( + getDevice: () async => mockDeviceResponse, + forgetDevice: () async {}, + ); + plugin.stateMachine.addInstance(mockIdp); + }); + + test( + 'return the current device where the current device id is equal to the local device id', + () async { + final secrets = await repo.get(username); + final currentDeviceKey = secrets?.deviceKey; + expect(currentDeviceKey, isNotNull); + final currentDevice = await plugin.fetchCurrentDevice(); + expect(currentDeviceKey, currentDevice.id); + }); + + test('throw a DeviceNotTrackedException when current device key is null', + () async { + await plugin.forgetDevice(); + await expectLater( + plugin.fetchCurrentDevice, + throwsA(isA()), + ); + }); + }); + + group('should throw', () { + setUp(() async { + final mockIdp = MockCognitoIdentityProviderClient( + getDevice: () async => throw AWSHttpException( + AWSHttpRequest.get(Uri.parse('https://aws.amazon.com/cognito/')), + ), + ); + plugin.stateMachine.addInstance(mockIdp); + }); + + test('a NetworkException', () async { + await expectLater( + plugin.fetchCurrentDevice, + throwsA(isA()), + ); + }); + }); + + tearDown(() async { + await plugin.close(); + }); + }); +}