From 1b5d2bd63548a9e67515f8afc22af1bf9fcaddb4 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 2 Aug 2024 16:32:25 -0700 Subject: [PATCH 001/159] chore: add mfaType enum values, --- .../lib/src/config/amplify_outputs/auth/mfa.dart | 5 ++++- packages/amplify_core/lib/src/config/auth/cognito/mfa.dart | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/amplify_core/lib/src/config/amplify_outputs/auth/mfa.dart b/packages/amplify_core/lib/src/config/amplify_outputs/auth/mfa.dart index e82d3327d7..92fee3d781 100644 --- a/packages/amplify_core/lib/src/config/amplify_outputs/auth/mfa.dart +++ b/packages/amplify_core/lib/src/config/amplify_outputs/auth/mfa.dart @@ -11,7 +11,10 @@ enum MfaMethod { sms, @JsonValue('TOTP') - totp; + totp, + + @JsonValue('EMAIL') + email; /// The value to pass to `Amplify.Auth.confirmSignIn` when /// selecting an MFA type. diff --git a/packages/amplify_core/lib/src/config/auth/cognito/mfa.dart b/packages/amplify_core/lib/src/config/auth/cognito/mfa.dart index 6d33bd00b3..292c5e184f 100644 --- a/packages/amplify_core/lib/src/config/auth/cognito/mfa.dart +++ b/packages/amplify_core/lib/src/config/auth/cognito/mfa.dart @@ -9,7 +9,10 @@ enum MfaType { sms, @JsonValue('TOTP') - totp; + totp, + + @JsonValue('EMAIL') + email; /// The value to pass to `Amplify.Auth.confirmSignIn` when /// selecting an MFA type. @@ -21,6 +24,7 @@ extension ToMfaMethod on MfaType { return switch (this) { MfaType.sms => MfaMethod.sms, MfaType.totp => MfaMethod.totp, + MfaType.email => MfaMethod.email, }; } } From a6492d7b46c465d3f559ca2198f25d69b886affb Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 2 Aug 2024 16:32:49 -0700 Subject: [PATCH 002/159] chore: add sign in step enums --- .../lib/src/types/auth/sign_in/auth_sign_in_step.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart b/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart index 7474f4be5e..b0d446dd8e 100644 --- a/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart +++ b/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart @@ -10,10 +10,17 @@ enum AuthSignInStep { /// an MFA method. continueSignInWithMfaSelection, + /// The sign-in is not complete and the user must set up and select an MFA method. + continueSignInWithMfaSetupSelection, + /// The sign-in is not complete and a TOTP authenticator app must be /// registered before continuing. continueSignInWithTotpSetup, + /// The sign-in is not complete and an Email MFA must be set up before + /// continuing. + continueSignInWithEmailMfaSetup, + /// The sign-in is not complete and must be confirmed with an SMS code. confirmSignInWithSmsMfaCode, @@ -21,6 +28,9 @@ enum AuthSignInStep { /// from a registered authenticator app. confirmSignInWithTotpMfaCode, + /// The sign-in is not complete and must be confirmed with an email code. + confirmSignInWithEmailMfaCode, + /// The sign-in is not complete and must be confirmed with the user's new /// password. confirmSignInWithNewPassword, From 755f30d6f0d339c945f31e0a2d58062edacaffd0 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 2 Aug 2024 16:33:08 -0700 Subject: [PATCH 003/159] chore: add ChallengeName --- .../model/challenge_name_type.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart index 16183b5270..7b8ba49818 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart @@ -74,6 +74,12 @@ class ChallengeNameType extends _i1.SmithyEnum { 'SOFTWARE_TOKEN_MFA', ); + static const emailMfa = ChallengeNameType._( + 10, + 'EMAIL_MFA', + 'EMAIL_MFA', + ); + /// All values of [ChallengeNameType]. static const values = [ ChallengeNameType.adminNoSrpAuth, @@ -86,6 +92,7 @@ class ChallengeNameType extends _i1.SmithyEnum { ChallengeNameType.selectMfaType, ChallengeNameType.smsMfa, ChallengeNameType.softwareTokenMfa, + ChallengeNameType.emailMfa, ]; static const List<_i1.SmithySerializer> serializers = [ From 95f658b55758caf963c2ed35c41f32bf12453cc8 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:46:40 -0700 Subject: [PATCH 004/159] Revert "chore: add ChallengeName" This reverts commit 04fbd0c4ebd073fe291d95abfb5f33aa8bfe1f50. --- .../model/challenge_name_type.dart | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart index 7b8ba49818..16183b5270 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart @@ -74,12 +74,6 @@ class ChallengeNameType extends _i1.SmithyEnum { 'SOFTWARE_TOKEN_MFA', ); - static const emailMfa = ChallengeNameType._( - 10, - 'EMAIL_MFA', - 'EMAIL_MFA', - ); - /// All values of [ChallengeNameType]. static const values = [ ChallengeNameType.adminNoSrpAuth, @@ -92,7 +86,6 @@ class ChallengeNameType extends _i1.SmithyEnum { ChallengeNameType.selectMfaType, ChallengeNameType.smsMfa, ChallengeNameType.softwareTokenMfa, - ChallengeNameType.emailMfa, ]; static const List<_i1.SmithySerializer> serializers = [ From 1f72acaf8cceb5494cd9c425d6fc263b32cd7532 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:19:18 -0700 Subject: [PATCH 005/159] Update packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart Co-authored-by: Elijah Quartey --- .../lib/src/types/auth/sign_in/auth_sign_in_step.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart b/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart index b0d446dd8e..9631ca1d94 100644 --- a/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart +++ b/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart @@ -10,7 +10,7 @@ enum AuthSignInStep { /// an MFA method. continueSignInWithMfaSelection, - /// The sign-in is not complete and the user must set up and select an MFA method. + /// The sign-in is not complete and the user must select an MFA method to setup. continueSignInWithMfaSetupSelection, /// The sign-in is not complete and a TOTP authenticator app must be From a5abb1eb7d0da20093370326ef71de595f3f87e1 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:46:47 -0700 Subject: [PATCH 006/159] chore add email mfa to sdk_bridge and state machine --- .../lib/src/sdk/sdk_bridge.dart | 33 +++++++++++++++---- .../state/machines/sign_in_state_machine.dart | 22 ++++++++++++- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index 5c81717008..593b38a583 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -32,6 +32,8 @@ extension ChallengeNameTypeBridge on ChallengeNameType { AuthSignInStep.continueSignInWithTotpSetup, ChallengeNameType.softwareTokenMfa => AuthSignInStep.confirmSignInWithTotpMfaCode, + // TODO(khatruong2009): confirm ChallengeNameType.emailMfa is added to SDK + ChallengeNameType.emailMfa => AuthSignInStep.confirmSignInWithEmailMfaCode, ChallengeNameType.adminNoSrpAuth || ChallengeNameType.passwordVerifier || ChallengeNameType.devicePasswordVerifier || @@ -795,6 +797,7 @@ extension MfaSettings on CognitoIdentityProviderClient { required String accessToken, MfaPreference? sms, MfaPreference? totp, + MfaPreference? email, }) async { final UserMfaPreference( enabled: currentEnabled, @@ -811,6 +814,7 @@ extension MfaSettings on CognitoIdentityProviderClient { final explicitlyDisabled = switch (mfaType) { MfaType.sms => sms == MfaPreference.disabled, MfaType.totp => totp == MfaPreference.disabled, + MfaType.email => email == MfaPreference.disabled, }; if (explicitlyDisabled) { return false; @@ -819,22 +823,25 @@ extension MfaSettings on CognitoIdentityProviderClient { final requestingEnabled = switch (mfaType) { MfaType.sms => enabledValues.contains(sms), MfaType.totp => enabledValues.contains(totp), + MfaType.email => enabledValues.contains(email), }; return currentlyEnabled || requestingEnabled; } - final preferred = switch ((currentPreference, sms: sms, totp: totp)) { + final preferred = switch ((currentPreference, sms: sms, totp: totp, email: email)) { // Prevent an invalid choice. - (_, sms: MfaPreference.preferred, totp: MfaPreference.preferred) => + (_, sms: MfaPreference.preferred, totp: MfaPreference.preferred, email: MfaPreference.preferred) => throw const InvalidParameterException( - 'Cannot assign both SMS and TOTP as preferred', + 'Cannot assign multiple MFA methods as preferred', ), // Setting one or the other as preferred overrides previous value. - (_, sms: MfaPreference.preferred, totp: != MfaPreference.preferred) => + (_, sms: MfaPreference.preferred, totp: != MfaPreference.preferred, email: != MfaPreference.preferred) => MfaType.sms, - (_, sms: != MfaPreference.preferred, totp: MfaPreference.preferred) => + (_, sms: != MfaPreference.preferred, totp: MfaPreference.preferred, email: != MfaPreference.preferred) => MfaType.totp, + (_, sms: != MfaPreference.preferred, totp: != MfaPreference.preferred, email: MfaPreference.preferred) => + MfaType.email, // Setting one or the other as disabled or not preferred removes current // preference if it matches. @@ -842,16 +849,24 @@ extension MfaSettings on CognitoIdentityProviderClient { MfaType.sms, sms: MfaPreference.notPreferred || MfaPreference.disabled, totp: _, + email: _, ) || ( MfaType.totp, sms: _, totp: MfaPreference.notPreferred || MfaPreference.disabled, + email: _, + ) || + ( + MfaType.email, + sms: _, + totp: _, + email: MfaPreference.notPreferred || MfaPreference.disabled, ) => null, // Ignore preference changes which do not affect the current preference. - (final currentPreference, sms: _, totp: _) => currentPreference, + (final currentPreference, sms: _, totp: _, email: _) => currentPreference, }; final smsMfaSettings = SmsMfaSettingsType( enabled: isEnabled(MfaType.sms), @@ -861,6 +876,11 @@ extension MfaSettings on CognitoIdentityProviderClient { enabled: isEnabled(MfaType.totp), preferredMfa: preferred == MfaType.totp, ); + // TODO(khatruong2009): confirm EmailMfaSettingsType is added to SDK + final emailMfaSettings = EmailMfaSettingsType( + enabled: isEnabled(MfaType.email), + preferredMfa: preferred == MfaType.email, + ); await setUserMfaPreference( SetUserMfaPreferenceRequest( accessToken: accessToken, @@ -876,6 +896,7 @@ extension on String { MfaType get mfaType => switch (this) { 'SOFTWARE_TOKEN_MFA' => MfaType.totp, 'SMS_MFA' => MfaType.sms, + 'EMAIL_MFA' => MfaType.email, final invalidType => throw StateError('Invalid MFA type: $invalidType'), }; } diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index cafeb1d3e7..46666c79fd 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -211,6 +211,7 @@ final class SignInStateMachine (type) => switch (type) { 'SOFTWARE_TOKEN_MFA' => MfaType.totp, 'SMS_MFA' => MfaType.sms, + 'EMAIL_MFA' => MfaType.email, _ => () { logger.error('Unrecognized MFA type: $type'); return null; @@ -449,6 +450,24 @@ final class SignInStateMachine }); } + /// Creates the response object for an Email MFA challenge. + @protected + Future createEmailMfaRequest( + SignInRespondToChallenge event, + ) async { + _enableMfaType = MfaType.email; + return RespondToAuthChallengeRequest.build((b) { + b + ..clientId = config.appClientId + ..challengeName = _challengeName + ..challengeResponses.addAll({ + CognitoConstants.challengeParamUsername: cognitoUsername, + CognitoConstants.challengeParamEmailMfaCode: event.answer, + }) + ..clientMetadata.addAll(event.clientMetadata); + }); + } + /// Creates the response object for a new password challenge. @protected Future createNewPasswordRequest( @@ -667,7 +686,8 @@ final class SignInStateMachine CognitoConstants.challengeParamAnswer: switch (selection) { 'sms' => 'SMS_MFA', 'totp' => 'SOFTWARE_TOKEN_MFA', - _ => throw ArgumentError('Must be either SMS or TOTP'), + 'email' => 'EMAIL_MFA', + _ => throw ArgumentError('Must be either SMS, Email, or TOTP'), }, }) ..clientId = _authOutputs.userPoolClientId From edaf99947b3c1b3e01849cf52e64c194eacf9156 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:47:52 -0700 Subject: [PATCH 007/159] chore: add email mfa to constants.dart --- .../amplify_auth_cognito_dart/lib/src/flows/constants.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart index 3ab6d376a5..ff49ec7974 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart @@ -57,6 +57,9 @@ abstract class CognitoConstants { /// The `SMS_MFA_CODE` parameter. static const challengeParamSmsMfaCode = 'SMS_MFA_CODE'; + /// The `EMAIL_MFA_CODE` parameter. + static const challengeParamEmailMfaCode = 'EMAIL_MFA_CODE'; + /// The `SOFTWARE_TOKEN_MFA_CODE` parameter. static const challengeParamSoftwareTokenMfaCode = 'SOFTWARE_TOKEN_MFA_CODE'; From 630adad3fc5deac35c9f63b6b12bc8419b191226 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:48:54 -0700 Subject: [PATCH 008/159] chore: add email to updateMfaPreference API --- .../amplify_auth_cognito_dart/lib/src/auth_plugin_impl.dart | 2 ++ 1 file changed, 2 insertions(+) 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 f458548642..f080f48fc2 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 @@ -892,6 +892,7 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface Future updateMfaPreference({ MfaPreference? sms, MfaPreference? totp, + MfaPreference? email, }) async { final tokens = await _stateMachine.getUserPoolTokens(); final accessToken = tokens.accessToken.raw; @@ -899,6 +900,7 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface accessToken: accessToken, sms: sms, totp: totp, + email: email, ); } From 3f4efce65dcdfc1efb60ec27967b9112eaa14a21 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:49:18 -0700 Subject: [PATCH 009/159] chore: generate code for mfa types/methods and sign in step --- .../lib/src/config/amplify_outputs/auth/auth_outputs.g.dart | 1 + .../amplify_core/lib/src/config/auth/cognito/auth.g.dart | 1 + .../src/types/auth/sign_in/auth_next_sign_in_step.g.dart | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/packages/amplify_core/lib/src/config/amplify_outputs/auth/auth_outputs.g.dart b/packages/amplify_core/lib/src/config/amplify_outputs/auth/auth_outputs.g.dart index f278972143..9c9639f654 100644 --- a/packages/amplify_core/lib/src/config/amplify_outputs/auth/auth_outputs.g.dart +++ b/packages/amplify_core/lib/src/config/amplify_outputs/auth/auth_outputs.g.dart @@ -128,4 +128,5 @@ const _$MfaEnforcementEnumMap = { const _$MfaMethodEnumMap = { MfaMethod.sms: 'SMS', MfaMethod.totp: 'TOTP', + MfaMethod.email: 'EMAIL', }; diff --git a/packages/amplify_core/lib/src/config/auth/cognito/auth.g.dart b/packages/amplify_core/lib/src/config/auth/cognito/auth.g.dart index 51926ead53..6bbb532080 100644 --- a/packages/amplify_core/lib/src/config/auth/cognito/auth.g.dart +++ b/packages/amplify_core/lib/src/config/auth/cognito/auth.g.dart @@ -119,4 +119,5 @@ const _$MfaConfigurationEnumMap = { const _$MfaTypeEnumMap = { MfaType.sms: 'SMS', MfaType.totp: 'TOTP', + MfaType.email: 'EMAIL', }; diff --git a/packages/amplify_core/lib/src/types/auth/sign_in/auth_next_sign_in_step.g.dart b/packages/amplify_core/lib/src/types/auth/sign_in/auth_next_sign_in_step.g.dart index 46d7e2de61..addf8e6b35 100644 --- a/packages/amplify_core/lib/src/types/auth/sign_in/auth_next_sign_in_step.g.dart +++ b/packages/amplify_core/lib/src/types/auth/sign_in/auth_next_sign_in_step.g.dart @@ -75,9 +75,14 @@ Map _$AuthNextSignInStepToJson(AuthNextSignInStep instance) { const _$AuthSignInStepEnumMap = { AuthSignInStep.continueSignInWithMfaSelection: 'continueSignInWithMfaSelection', + AuthSignInStep.continueSignInWithMfaSetupSelection: + 'continueSignInWithMfaSetupSelection', AuthSignInStep.continueSignInWithTotpSetup: 'continueSignInWithTotpSetup', + AuthSignInStep.continueSignInWithEmailMfaSetup: + 'continueSignInWithEmailMfaSetup', AuthSignInStep.confirmSignInWithSmsMfaCode: 'confirmSignInWithSmsMfaCode', AuthSignInStep.confirmSignInWithTotpMfaCode: 'confirmSignInWithTotpMfaCode', + AuthSignInStep.confirmSignInWithEmailMfaCode: 'confirmSignInWithEmailMfaCode', AuthSignInStep.confirmSignInWithNewPassword: 'confirmSignInWithNewPassword', AuthSignInStep.confirmSignInWithCustomChallenge: 'confirmSignInWithCustomChallenge', @@ -89,4 +94,5 @@ const _$AuthSignInStepEnumMap = { const _$MfaTypeEnumMap = { MfaType.sms: 'SMS', MfaType.totp: 'TOTP', + MfaType.email: 'EMAIL', }; From 438f800810f18b04f7b407217a6b67db2da48607 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 12 Sep 2024 16:45:05 -0700 Subject: [PATCH 010/159] chore: merge main (#5449) * chore(api): update endpoint config to use ApiOutputs instead of AWSApiConfig type (#5193) * feat: bump json_annotation dependency to v4.9 * chore: update actions workflow to run aft link * chore(secure_storage): Plugin Endorsement (#5208) * chore(infra): bump deps (#5221) * chore(test): use Amplify Gen 2 config in unit tests (#5205) * chore: add testUrlScheme back to test (#5223) * chore: add gen2 auth e2e infra (#5179) * chore(infra): Api migrate to Gen 2 E2E * fix: git update-index --chmod=+x * fix: code review * chore: port auth backend * chore: port lambda triggers for create user and custom email sender * chore: move utils to infra-common * chore: compile infra common to js * chore: update utils for js restructure, add missing deps * chore: fix confirmation code infra * chore: update tests to run for gen2 stacks * chore: remove alias from custom sender lambda * chore: fix deliveryMedium in reset password test * chore: add phone sign in infra * chore: rename email-sign-in * chore: add license header * chore: fix formatting in GH workflow * chore: update package-lock * chore: remove deleted file * chore: fix formatting * chore: update package lock * chore: remove dup function * chore: remove changes from merge conflicts * chore: fix build script * chore: fetch auth amplify_outputs * chore: remove libgit2dart * chore: add custom sms sender * chore: add stack name to infra resources * chore: pull gen2 backend for authenticator * chore: update package-lock * chore: move dependencies to dev_dependencies * chore: update fetch auth session tests * chore: separate reset pw and confirmation delivery medium * chore: fix hanging test * chore: rename test group * chore: update comments, remove unused type * chore: update package lock --------- Co-authored-by: Elijah Quartey * chore(auth): sign-up state machine to use AmplifyOutputs instead of AmplifyConfig types (#5230) * chore(auth): sign-in state machine to use AmplifyOutputs instead of AmplifyConfig types (#5231) * chore(auth): fetch auth session state machine to use AmplifyOutputs instead of AmplifyConfig types (#5234) * chore(auth): sign-out state machine to use AmplifyOutputs instead of AmplifConfig types (#5235) * chore(actions): android emulator to start with clear cache and data (#5245) * chore(actions): e2e android tests to run with API 34 (#5247) * chore(infra): bump deps (#5246) Updated @aws-sdk/client-amplify @aws-sdk/client-cognito-identity-provider @aws-crypto/client-node @aws-sdk/client-s3 * chore(auth): cognito keys to not use AmplifyConfig types (#5243) * chore(auth): hosted ui state machine to not use AmplifyConfig types (#5254) * fix(datastore): Clear subscriptions on Stop (#5253) * Chore/goldens flutter lint (#5271) * temp: generate goldens png * test: fixing context mounted issue * chore: add todo comment about deprecated member use --------- Co-authored-by: Andrew Hahn * chore(infra): analytics integ test gen 2 backend (#5104) * chore(auth): device metadata repository to use AuthOutputs instead of CognitoUserPoolConfig (#5289) * feat(Auth): Add fetchCurrentDevice API (#5251) feat(Auth): Add fetchCurrentDevice API (#5251) * chore(dependencies): bump package_info_plus (#5274) chore: bump package_info_plus * chore: migrate sms only MFA infra to Gen 2 (#5291) * chore: add new auth backend * chore: add auth extension * chore: add license headers * chore: add mfa to env * chore: add trigger to enable MFA * chore: add infra for sms required * chore: refactor tests for gen 2 backends * chore: add backends to deploy script * chore: package-lock for mfa-required-sms * chore: remove bundling of @aws-crypto/client-node * chore: fix formatting * fix(datastore): Restart Sync Engine when network on/off (#5218) * chore: update authenticator tests (#5296) * chore(auth): hosted ui platforms to use AmplifyOutputs types instead of AmplifyConfig (#5273) * chore(auth): asf context data provider to use AuthOutputs instead of CognitoUserPoolConfig (#5290) * chore(auth): fix fetch current device test (#5297) * fix: push notification flush events (#5215) fix: push notification flush events (#5215) * chore(dependencies): bump build_runner (#5300) * chore(dependencies): bump build_runner * chore(bump): checks package (#5305) * chore(bump): checks package * chore(version): Bump version chore(): Fixed Version Bumps chore: fixed change log chore: fixed change log chore: fixed change log chore: fixed change log * chore: manually bump amplify_db_common version * chore(infra): Extend API key expiration (#5336) * chore(dev): use ubuntu image from amazon ECR public gallery instead of docket hub (#5341) * fix(api): web socket error handling (#5359) * chore: update issue template (#5369) * fix(datastore): FlutterSerializedModel.extractJsonValue returns `.some(nil)` instead of `nil` (#5370) * chore: add GH actions for issue open, close, comment, label events (#5310) * fix(secure_storage): add missing macOS plugin (#5372) fix(secure_storage): add missing macos plugin it's fixing #5361 * chore: update plugin registrant for example apps that depend on secure storage (#5379) * chore(version): Bump version - fix(secure_storage): add missing macOS plugin ([#5372](https://github.com/aws-amplify/amplify-flutter/pull/5372)) Updated-Components: Secure Storage * chore(deps): Amplify Android 2.21.1 (#5376) * update amplify android to latest * update amplify android to latest in notifications * feat(aws_common): Generated new AWSService constructors (#5378) * chore(infra): regen lock file (#5374) * chore(auth): credential store state machine to use AuthOutputs instead of AmplifyConfig types (#5298) * chore(api): Remove Gen 1 API backend (#5393) * chore(datastore): Add multi auth integration tests (#5204) * feat: move App Sync subscription headers to protocol (#5301) * chore: move subscription headers to protocol * fix: remove `=` from encoded headers * chore: add comment * chore: `aft version-bump` test suite (#5424) * chore: add `--skip-build-version` option * chore: use `base-ref`/`head-ref` over env vars * chore: add new version bump test suite * chore: remove old version bump tests * chore: only include first change log entry * fix: sort change types before writing to the change log * chore: remove non essential info from diffs * chore: generate repo snapshot * chore: generate diff snapshots * chore: clean up tests and test output * chore: update `aft generate workflows`, regenerate dependabot.yaml (#5441) * chore: skip repo snapshot in dependabot generation * chore: regenerate dependabot.yaml * chore: fix `aft version-bump` (#5436) * fix: properly handle component propagation * chore: add test for multi package update with breaking common package --------- Co-authored-by: NikaHsn Co-authored-by: Jordan Nelson Co-authored-by: Elijah Quartey Co-authored-by: Elijah Quartey Co-authored-by: Tyler-Larkin Co-authored-by: Andrew Hahn Co-authored-by: Andrew Hahn <58017052+hahnandrew@users.noreply.github.com> Co-authored-by: Burak Karahan Co-authored-by: Jamil Saadeh --- infra-gen2/package-lock.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/infra-gen2/package-lock.json b/infra-gen2/package-lock.json index 806c800dd6..191c337b64 100644 --- a/infra-gen2/package-lock.json +++ b/infra-gen2/package-lock.json @@ -4462,6 +4462,18 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.624.0", + "@aws-sdk/client-sts": "3.624.0", + "@aws-sdk/core": "3.624.0", + "@aws-sdk/credential-provider-node": "3.624.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-sdk-ec2": "3.622.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", @@ -4474,9 +4486,27 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.624.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.14", + "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { @@ -4592,6 +4622,8 @@ "license": "Apache-2.0", "dependencies": { "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { @@ -4606,6 +4638,7 @@ "dependencies": { "@smithy/eventstream-serde-universal": "^3.0.5", "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" }, "engines": { From b4a8ceb1c8a1c68044c9f15ceb7d785d1aa113ad Mon Sep 17 00:00:00 2001 From: NikaHsn Date: Fri, 13 Sep 2024 16:17:54 -0700 Subject: [PATCH 011/159] chore(auth): re-generate auth cognito sdk for email mfa (#5455) * chore(api): update endpoint config to use ApiOutputs instead of AWSApiConfig type (#5193) * feat: bump json_annotation dependency to v4.9 * chore: update actions workflow to run aft link * chore(secure_storage): Plugin Endorsement (#5208) * chore(infra): bump deps (#5221) * chore(test): use Amplify Gen 2 config in unit tests (#5205) * chore: add testUrlScheme back to test (#5223) * chore: add gen2 auth e2e infra (#5179) * chore(infra): Api migrate to Gen 2 E2E * fix: git update-index --chmod=+x * fix: code review * chore: port auth backend * chore: port lambda triggers for create user and custom email sender * chore: move utils to infra-common * chore: compile infra common to js * chore: update utils for js restructure, add missing deps * chore: fix confirmation code infra * chore: update tests to run for gen2 stacks * chore: remove alias from custom sender lambda * chore: fix deliveryMedium in reset password test * chore: add phone sign in infra * chore: rename email-sign-in * chore: add license header * chore: fix formatting in GH workflow * chore: update package-lock * chore: remove deleted file * chore: fix formatting * chore: update package lock * chore: remove dup function * chore: remove changes from merge conflicts * chore: fix build script * chore: fetch auth amplify_outputs * chore: remove libgit2dart * chore: add custom sms sender * chore: add stack name to infra resources * chore: pull gen2 backend for authenticator * chore: update package-lock * chore: move dependencies to dev_dependencies * chore: update fetch auth session tests * chore: separate reset pw and confirmation delivery medium * chore: fix hanging test * chore: rename test group * chore: update comments, remove unused type * chore: update package lock --------- Co-authored-by: Elijah Quartey * chore(auth): sign-up state machine to use AmplifyOutputs instead of AmplifyConfig types (#5230) * chore(auth): sign-in state machine to use AmplifyOutputs instead of AmplifyConfig types (#5231) * chore(auth): fetch auth session state machine to use AmplifyOutputs instead of AmplifyConfig types (#5234) * chore(auth): sign-out state machine to use AmplifyOutputs instead of AmplifConfig types (#5235) * chore(actions): android emulator to start with clear cache and data (#5245) * chore(actions): e2e android tests to run with API 34 (#5247) * chore(infra): bump deps (#5246) Updated @aws-sdk/client-amplify @aws-sdk/client-cognito-identity-provider @aws-crypto/client-node @aws-sdk/client-s3 * chore(auth): cognito keys to not use AmplifyConfig types (#5243) * chore(auth): hosted ui state machine to not use AmplifyConfig types (#5254) * fix(datastore): Clear subscriptions on Stop (#5253) * Chore/goldens flutter lint (#5271) * temp: generate goldens png * test: fixing context mounted issue * chore: add todo comment about deprecated member use --------- Co-authored-by: Andrew Hahn * chore(infra): analytics integ test gen 2 backend (#5104) * chore(auth): device metadata repository to use AuthOutputs instead of CognitoUserPoolConfig (#5289) * feat(Auth): Add fetchCurrentDevice API (#5251) feat(Auth): Add fetchCurrentDevice API (#5251) * chore(dependencies): bump package_info_plus (#5274) chore: bump package_info_plus * chore: migrate sms only MFA infra to Gen 2 (#5291) * chore: add new auth backend * chore: add auth extension * chore: add license headers * chore: add mfa to env * chore: add trigger to enable MFA * chore: add infra for sms required * chore: refactor tests for gen 2 backends * chore: add backends to deploy script * chore: package-lock for mfa-required-sms * chore: remove bundling of @aws-crypto/client-node * chore: fix formatting * fix(datastore): Restart Sync Engine when network on/off (#5218) * chore: update authenticator tests (#5296) * chore(auth): hosted ui platforms to use AmplifyOutputs types instead of AmplifyConfig (#5273) * chore(auth): asf context data provider to use AuthOutputs instead of CognitoUserPoolConfig (#5290) * chore(auth): fix fetch current device test (#5297) * fix: push notification flush events (#5215) fix: push notification flush events (#5215) * chore(dependencies): bump build_runner (#5300) * chore(dependencies): bump build_runner * chore(bump): checks package (#5305) * chore(bump): checks package * chore(version): Bump version chore(): Fixed Version Bumps chore: fixed change log chore: fixed change log chore: fixed change log chore: fixed change log * chore: manually bump amplify_db_common version * chore(infra): Extend API key expiration (#5336) * chore(dev): use ubuntu image from amazon ECR public gallery instead of docket hub (#5341) * fix(api): web socket error handling (#5359) * chore: update issue template (#5369) * fix(datastore): FlutterSerializedModel.extractJsonValue returns `.some(nil)` instead of `nil` (#5370) * chore: add GH actions for issue open, close, comment, label events (#5310) * fix(secure_storage): add missing macOS plugin (#5372) fix(secure_storage): add missing macos plugin it's fixing #5361 * chore: update plugin registrant for example apps that depend on secure storage (#5379) * chore(version): Bump version ### Fixes - fix(secure_storage): add missing macOS plugin ([#5372](https://github.com/aws-amplify/amplify-flutter/pull/5372)) Updated-Components: Secure Storage * chore(deps): Amplify Android 2.21.1 (#5376) * update amplify android to latest * update amplify android to latest in notifications * feat(aws_common): Generated new AWSService constructors (#5378) * chore(infra): regen lock file (#5374) * chore(auth): credential store state machine to use AuthOutputs instead of AmplifyConfig types (#5298) * chore(api): Remove Gen 1 API backend (#5393) * chore(datastore): Add multi auth integration tests (#5204) * feat: move App Sync subscription headers to protocol (#5301) * chore: move subscription headers to protocol * fix: remove `=` from encoded headers * chore: add comment * chore: `aft version-bump` test suite (#5424) * chore: add `--skip-build-version` option * chore: use `base-ref`/`head-ref` over env vars * chore: add new version bump test suite * chore: remove old version bump tests * chore: only include first change log entry * fix: sort change types before writing to the change log * chore: remove non essential info from diffs * chore: generate repo snapshot * chore: generate diff snapshots * chore: clean up tests and test output * chore: update `aft generate workflows`, regenerate dependabot.yaml (#5441) * chore: skip repo snapshot in dependabot generation * chore: regenerate dependabot.yaml * chore: fix `aft version-bump` (#5436) * fix: properly handle component propagation * chore: add test for multi package update with breaking common package * chore(auth): re-generate auth cognito sdk for email mfa --------- Co-authored-by: Jordan Nelson Co-authored-by: Elijah Quartey Co-authored-by: Elijah Quartey Co-authored-by: Tyler-Larkin Co-authored-by: Andrew Hahn Co-authored-by: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Co-authored-by: Andrew Hahn <58017052+hahnandrew@users.noreply.github.com> Co-authored-by: Burak Karahan Co-authored-by: Jamil Saadeh Co-authored-by: Nika Hassani --- .../lib/src/sdk/cognito_identity.dart | 2 +- .../src/sdk/cognito_identity_provider.dart | 4 +- .../lib/src/sdk/sdk_exception.dart | 21 +++ .../cognito_identity_client.dart | 2 +- .../common/endpoint_resolver.dart | 2 +- .../cognito_identity/common/serializers.dart | 2 +- .../cognito_identity/model/credentials.dart | 4 +- .../model/external_service_exception.dart | 2 +- .../get_credentials_for_identity_input.dart | 2 +- ...get_credentials_for_identity_response.dart | 2 +- .../cognito_identity/model/get_id_input.dart | 2 +- .../model/get_id_response.dart | 2 +- .../model/internal_error_exception.dart | 2 +- ...identity_pool_configuration_exception.dart | 2 +- .../model/invalid_parameter_exception.dart | 2 +- .../model/limit_exceeded_exception.dart | 2 +- .../model/not_authorized_exception.dart | 2 +- .../model/resource_conflict_exception.dart | 2 +- .../model/resource_not_found_exception.dart | 2 +- .../model/too_many_requests_exception.dart | 2 +- ...et_credentials_for_identity_operation.dart | 4 +- .../operation/get_id_operation.dart | 4 +- .../cognito_identity_provider_client.dart | 18 +-- .../common/endpoint_resolver.dart | 2 +- .../common/serializers.dart | 6 +- .../model/alias_exists_exception.dart | 2 +- .../model/analytics_metadata_type.dart | 2 +- .../associate_software_token_request.dart | 2 +- .../associate_software_token_response.dart | 2 +- .../model/attribute_type.dart | 2 +- .../model/auth_flow_type.dart | 2 +- .../model/authentication_result_type.dart | 2 +- .../model/challenge_name_type.dart | 21 ++- .../model/change_password_request.dart | 2 +- .../model/change_password_response.dart | 2 +- .../model/code_delivery_details_type.dart | 2 +- .../code_delivery_failure_exception.dart | 2 +- .../model/code_mismatch_exception.dart | 2 +- .../concurrent_modification_exception.dart | 2 +- .../model/confirm_device_request.dart | 2 +- .../model/confirm_device_response.dart | 2 +- .../confirm_forgot_password_request.dart | 2 +- .../confirm_forgot_password_response.dart | 2 +- .../model/confirm_sign_up_request.dart | 2 +- .../model/confirm_sign_up_response.dart | 2 +- .../model/delete_user_request.dart | 2 +- .../model/delivery_medium_type.dart | 2 +- .../model/device_remembered_status_type.dart | 2 +- .../device_secret_verifier_config_type.dart | 2 +- .../model/device_type.dart | 2 +- .../model/email_mfa_settings_type.dart | 147 +++++++++++++++++ .../model/email_mfa_settings_type.g.dart | 106 +++++++++++++ .../enable_software_token_mfa_exception.dart | 2 +- .../model/expired_code_exception.dart | 2 +- .../model/forbidden_exception.dart | 2 +- .../model/forget_device_request.dart | 2 +- .../model/forgot_password_request.dart | 2 +- .../model/forgot_password_response.dart | 2 +- .../model/get_device_request.dart | 2 +- .../model/get_device_response.dart | 2 +- ...r_attribute_verification_code_request.dart | 2 +- ..._attribute_verification_code_response.dart | 2 +- .../model/get_user_request.dart | 2 +- .../model/get_user_response.dart | 4 +- .../model/global_sign_out_request.dart | 2 +- .../model/global_sign_out_response.dart | 2 +- .../model/initiate_auth_request.dart | 2 +- .../model/initiate_auth_response.dart | 6 +- .../model/internal_error_exception.dart | 2 +- ...id_email_role_access_policy_exception.dart | 2 +- .../invalid_lambda_response_exception.dart | 2 +- .../model/invalid_parameter_exception.dart | 2 +- .../model/invalid_password_exception.dart | 2 +- ...alid_sms_role_access_policy_exception.dart | 2 +- ...sms_role_trust_relationship_exception.dart | 2 +- ...lid_user_pool_configuration_exception.dart | 2 +- .../model/limit_exceeded_exception.dart | 2 +- .../model/list_devices_request.dart | 2 +- .../model/list_devices_response.dart | 2 +- .../model/mfa_method_not_found_exception.dart | 2 +- .../model/mfa_option_type.dart | 2 +- .../model/new_device_metadata_type.dart | 2 +- .../model/not_authorized_exception.dart | 2 +- ...rd_history_policy_violation_exception.dart | 148 ++++++++++++++++++ ..._history_policy_violation_exception.g.dart | 101 ++++++++++++ .../password_reset_required_exception.dart | 2 +- .../resend_confirmation_code_request.dart | 2 +- .../resend_confirmation_code_response.dart | 2 +- .../model/resource_not_found_exception.dart | 2 +- .../respond_to_auth_challenge_request.dart | 10 +- .../respond_to_auth_challenge_response.dart | 2 +- .../model/revoke_token_request.dart | 2 +- .../model/revoke_token_response.dart | 2 +- .../set_user_mfa_preference_request.dart | 31 +++- .../set_user_mfa_preference_request.g.dart | 15 ++ .../set_user_mfa_preference_response.dart | 2 +- .../model/sign_up_request.dart | 2 +- .../model/sign_up_response.dart | 4 +- .../model/sms_mfa_settings_type.dart | 4 +- ...oftware_token_mfa_not_found_exception.dart | 2 +- .../software_token_mfa_settings_type.dart | 2 +- .../too_many_failed_attempts_exception.dart | 2 +- .../model/too_many_requests_exception.dart | 2 +- .../model/unauthorized_exception.dart | 2 +- .../model/unexpected_lambda_exception.dart | 2 +- .../unsupported_operation_exception.dart | 2 +- .../unsupported_token_type_exception.dart | 2 +- .../model/update_device_status_request.dart | 2 +- .../model/update_device_status_response.dart | 2 +- .../model/update_user_attributes_request.dart | 2 +- .../update_user_attributes_response.dart | 2 +- .../model/user_context_data_type.dart | 2 +- .../user_lambda_validation_exception.dart | 2 +- .../model/user_not_confirmed_exception.dart | 2 +- .../model/user_not_found_exception.dart | 2 +- .../model/username_exists_exception.dart | 2 +- .../model/verify_software_token_request.dart | 2 +- .../model/verify_software_token_response.dart | 2 +- .../verify_software_token_response_type.dart | 2 +- .../model/verify_user_attribute_request.dart | 2 +- .../model/verify_user_attribute_response.dart | 2 +- .../associate_software_token_operation.dart | 8 +- .../operation/change_password_operation.dart | 16 +- .../operation/confirm_device_operation.dart | 4 +- .../confirm_forgot_password_operation.dart | 16 +- .../operation/confirm_sign_up_operation.dart | 4 +- .../operation/delete_user_operation.dart | 4 +- .../operation/forget_device_operation.dart | 4 +- .../operation/forgot_password_operation.dart | 8 +- .../operation/get_device_operation.dart | 4 +- ...attribute_verification_code_operation.dart | 8 +- .../operation/get_user_operation.dart | 4 +- .../operation/global_sign_out_operation.dart | 4 +- .../operation/initiate_auth_operation.dart | 20 ++- .../operation/list_devices_operation.dart | 4 +- .../resend_confirmation_code_operation.dart | 8 +- .../respond_to_auth_challenge_operation.dart | 32 +++- .../operation/revoke_token_operation.dart | 4 +- .../set_user_mfa_preference_operation.dart | 4 +- .../operation/sign_up_operation.dart | 8 +- .../update_device_status_operation.dart | 4 +- .../update_user_attributes_operation.dart | 8 +- .../verify_software_token_operation.dart | 4 +- .../verify_user_attribute_operation.dart | 4 +- 144 files changed, 845 insertions(+), 201 deletions(-) create mode 100644 packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.dart create mode 100644 packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.g.dart create mode 100644 packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.dart create mode 100644 packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.g.dart diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/cognito_identity.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/cognito_identity.dart index bcac91000f..d3b8223bdb 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/cognito_identity.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/cognito_identity.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas /// # Amazon Cognito Identity diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/cognito_identity_provider.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/cognito_identity_provider.dart index 7682084c1c..3bc1811bc4 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/cognito_identity_provider.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/cognito_identity_provider.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas /// # Amazon Cognito Identity Provider @@ -68,6 +68,7 @@ export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/ export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/device_remembered_status_type.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/device_secret_verifier_config_type.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/device_type.dart'; +export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/enable_software_token_mfa_exception.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/expired_code_exception.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/forbidden_exception.dart'; @@ -99,6 +100,7 @@ export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/ export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/mfa_option_type.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/new_device_metadata_type.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/not_authorized_exception.dart'; +export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/password_reset_required_exception.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_request.dart'; export 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_response.dart'; diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_exception.dart index fde039d5f1..78f5d3eaa8 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_exception.dart @@ -356,6 +356,22 @@ final class NotAuthorizedServiceException extends CognitoServiceException String get runtimeTypeName => 'NotAuthorizedServiceException'; } +/// {@template amplify_auth_cognito_dart.sdk_exception.password_history_policy_violation_exception} +/// The message returned when a user's new password matches a previous password and doesn't comply with the password-history policy. +/// {@endtemplate} +final class PasswordHistoryPolicyViolationException + extends CognitoServiceException { + /// {@macro amplify_auth_cognito_dart.sdk_exception.password_history_policy_violation_exception} + const PasswordHistoryPolicyViolationException( + super.message, { + super.recoverySuggestion, + super.underlyingException, + }); + + @override + String get runtimeTypeName => 'PasswordHistoryPolicyViolationException'; +} + /// {@template amplify_auth_cognito_dart.sdk_exception.password_reset_required_exception} /// This exception is thrown when a password reset is required. /// {@endtemplate} @@ -685,6 +701,11 @@ Object transformSdkException(Object e) { message, underlyingException: e, ), + 'PasswordHistoryPolicyViolationException' => + PasswordHistoryPolicyViolationException( + message, + underlyingException: e, + ), 'PasswordResetRequiredException' => PasswordResetRequiredException( message, underlyingException: e, diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/cognito_identity_client.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/cognito_identity_client.dart index 4fce991aac..49472116d5 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/cognito_identity_client.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/cognito_identity_client.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.cognito_identity_client; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/common/endpoint_resolver.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/common/endpoint_resolver.dart index 7cd37f555f..aabe87df7f 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/common/endpoint_resolver.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/common/endpoint_resolver.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.common.endpoint_resolver; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/common/serializers.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/common/serializers.dart index 53d9ea9022..13d2996e70 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/common/serializers.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/common/serializers.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.common.serializers; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/credentials.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/credentials.dart index 4a9768bec5..f907c481b8 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/credentials.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/credentials.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.credentials; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -67,7 +67,7 @@ abstract class Credentials ) ..add( 'secretKey', - secretKey, + '***SENSITIVE***', ) ..add( 'sessionToken', diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/external_service_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/external_service_exception.dart index 40fea8d03e..9e9500945b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/external_service_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/external_service_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.external_service_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_credentials_for_identity_input.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_credentials_for_identity_input.dart index 76881a5f20..1ef8ddd869 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_credentials_for_identity_input.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_credentials_for_identity_input.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.get_credentials_for_identity_input; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_credentials_for_identity_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_credentials_for_identity_response.dart index 3bda9069de..6f83f4cf28 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_credentials_for_identity_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_credentials_for_identity_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.get_credentials_for_identity_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_id_input.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_id_input.dart index 2469ffe450..15ed362231 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_id_input.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_id_input.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.get_id_input; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_id_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_id_response.dart index 17f61687d0..dfe391a845 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_id_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/get_id_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.get_id_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/internal_error_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/internal_error_exception.dart index c3aefa1100..4f5a7455e9 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/internal_error_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/internal_error_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.internal_error_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/invalid_identity_pool_configuration_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/invalid_identity_pool_configuration_exception.dart index 2e2b04cb49..c25b63d9fa 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/invalid_identity_pool_configuration_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/invalid_identity_pool_configuration_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.invalid_identity_pool_configuration_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/invalid_parameter_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/invalid_parameter_exception.dart index dd0e1bb993..881a613f75 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/invalid_parameter_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/invalid_parameter_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.invalid_parameter_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/limit_exceeded_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/limit_exceeded_exception.dart index d12231e2d3..4909ca0b94 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/limit_exceeded_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/limit_exceeded_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.limit_exceeded_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/not_authorized_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/not_authorized_exception.dart index 43841286cb..50add67fb4 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/not_authorized_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/not_authorized_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.not_authorized_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/resource_conflict_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/resource_conflict_exception.dart index 5e5f88ad77..cc4b2f9846 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/resource_conflict_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/resource_conflict_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.resource_conflict_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/resource_not_found_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/resource_not_found_exception.dart index 2061531b78..1ba7efb1b3 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/resource_not_found_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/resource_not_found_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.resource_not_found_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/too_many_requests_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/too_many_requests_exception.dart index 01a910e91a..e005c51ca2 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/too_many_requests_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/model/too_many_requests_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.model.too_many_requests_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/operation/get_credentials_for_identity_operation.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/operation/get_credentials_for_identity_operation.dart index 0a3319e2d0..a70ab6465f 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/operation/get_credentials_for_identity_operation.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/operation/get_credentials_for_identity_operation.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.operation.get_credentials_for_identity_operation; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -69,7 +69,7 @@ class GetCredentialsForIdentityOperation extends _i1.HttpOperation< credentialsProvider: _credentialsProvider, isOptional: true, ), - const _i1.WithUserAgent('aws-sdk-dart/0.3.1'), + const _i1.WithUserAgent('aws-sdk-dart/0.3.2'), const _i3.WithSdkInvocationId(), const _i3.WithSdkRequest(), ] + diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/operation/get_id_operation.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/operation/get_id_operation.dart index c7aa76e5c4..5a9ebaa5b3 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/operation/get_id_operation.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity/operation/get_id_operation.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity.operation.get_id_operation; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -64,7 +64,7 @@ class GetIdOperation extends _i1 credentialsProvider: _credentialsProvider, isOptional: true, ), - const _i1.WithUserAgent('aws-sdk-dart/0.3.1'), + const _i1.WithUserAgent('aws-sdk-dart/0.3.2'), const _i3.WithSdkInvocationId(), const _i3.WithSdkRequest(), ] + diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/cognito_identity_provider_client.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/cognito_identity_provider_client.dart index 5b504d64fd..77dc73bc98 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/cognito_identity_provider_client.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/cognito_identity_provider_client.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.cognito_identity_provider_client; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -178,7 +178,7 @@ class CognitoIdentityProviderClient { /// Begins setup of time-based one-time password (TOTP) multi-factor authentication (MFA) for a user, with a unique private key that Amazon Cognito generates and returns in the API response. You can authorize an `AssociateSoftwareToken` request with either the user's access token, or a session string from a challenge response that you received from Amazon Cognito. /// - /// Amazon Cognito disassociates an existing software token when you verify the new token in a [VerifySoftwareToken](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_VerifySoftwareToken.html) API request. If you don't verify the software token and your user pool doesn't require MFA, the user can then authenticate with user name and password credentials alone. If your user pool requires TOTP MFA, Amazon Cognito generates an `MFA_SETUP` or `SOFTWARE\_TOKEN\_SETUP` challenge each time your user signs. Complete setup with `AssociateSoftwareToken` and `VerifySoftwareToken`. + /// Amazon Cognito disassociates an existing software token when you verify the new token in a [VerifySoftwareToken](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_VerifySoftwareToken.html) API request. If you don't verify the software token and your user pool doesn't require MFA, the user can then authenticate with user name and password credentials alone. If your user pool requires TOTP MFA, Amazon Cognito generates an `MFA_SETUP` or `SOFTWARE\_TOKEN\_SETUP` challenge each time your user signs in. Complete setup with `AssociateSoftwareToken` and `VerifySoftwareToken`. /// /// After you set up software token MFA for your user, Amazon Cognito generates a `SOFTWARE\_TOKEN\_MFA` challenge when they authenticate. Respond to this challenge with your user's TOTP. /// @@ -340,7 +340,7 @@ class CognitoIdentityProviderClient { /// /// This action might generate an SMS text message. Starting June 1, 2021, US telecom carriers require you to register an origination phone number before you can send SMS messages to US phone numbers. If you use SMS text messages in Amazon Cognito, you must register a phone number with [Amazon Pinpoint](https://console.aws.amazon.com/pinpoint/home/). Amazon Cognito uses the registered number automatically. Otherwise, Amazon Cognito users who must receive SMS messages might not be able to sign up, activate their accounts, or sign in. /// - /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Service, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. + /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Servicesservice, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. _i3.SmithyOperation forgotPassword( ForgotPasswordRequest input, { _i1.AWSHttpClient? client, @@ -410,7 +410,7 @@ class CognitoIdentityProviderClient { /// /// This action might generate an SMS text message. Starting June 1, 2021, US telecom carriers require you to register an origination phone number before you can send SMS messages to US phone numbers. If you use SMS text messages in Amazon Cognito, you must register a phone number with [Amazon Pinpoint](https://console.aws.amazon.com/pinpoint/home/). Amazon Cognito uses the registered number automatically. Otherwise, Amazon Cognito users who must receive SMS messages might not be able to sign up, activate their accounts, or sign in. /// - /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Service, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. + /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Servicesservice, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. _i3.SmithyOperation getUserAttributeVerificationCode( GetUserAttributeVerificationCodeRequest input, { @@ -468,7 +468,7 @@ class CognitoIdentityProviderClient { /// /// This action might generate an SMS text message. Starting June 1, 2021, US telecom carriers require you to register an origination phone number before you can send SMS messages to US phone numbers. If you use SMS text messages in Amazon Cognito, you must register a phone number with [Amazon Pinpoint](https://console.aws.amazon.com/pinpoint/home/). Amazon Cognito uses the registered number automatically. Otherwise, Amazon Cognito users who must receive SMS messages might not be able to sign up, activate their accounts, or sign in. /// - /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Service, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. + /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Servicesservice, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. _i3.SmithyOperation initiateAuth( InitiateAuthRequest input, { _i1.AWSHttpClient? client, @@ -514,7 +514,7 @@ class CognitoIdentityProviderClient { /// /// This action might generate an SMS text message. Starting June 1, 2021, US telecom carriers require you to register an origination phone number before you can send SMS messages to US phone numbers. If you use SMS text messages in Amazon Cognito, you must register a phone number with [Amazon Pinpoint](https://console.aws.amazon.com/pinpoint/home/). Amazon Cognito uses the registered number automatically. Otherwise, Amazon Cognito users who must receive SMS messages might not be able to sign up, activate their accounts, or sign in. /// - /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Service, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. + /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Servicesservice, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. _i3.SmithyOperation resendConfirmationCode( ResendConfirmationCodeRequest input, { _i1.AWSHttpClient? client, @@ -540,7 +540,7 @@ class CognitoIdentityProviderClient { /// /// This action might generate an SMS text message. Starting June 1, 2021, US telecom carriers require you to register an origination phone number before you can send SMS messages to US phone numbers. If you use SMS text messages in Amazon Cognito, you must register a phone number with [Amazon Pinpoint](https://console.aws.amazon.com/pinpoint/home/). Amazon Cognito uses the registered number automatically. Otherwise, Amazon Cognito users who must receive SMS messages might not be able to sign up, activate their accounts, or sign in. /// - /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Service, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. + /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Servicesservice, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. _i3.SmithyOperation respondToAuthChallenge( RespondToAuthChallengeRequest input, { _i1.AWSHttpClient? client, @@ -606,7 +606,7 @@ class CognitoIdentityProviderClient { /// /// This action might generate an SMS text message. Starting June 1, 2021, US telecom carriers require you to register an origination phone number before you can send SMS messages to US phone numbers. If you use SMS text messages in Amazon Cognito, you must register a phone number with [Amazon Pinpoint](https://console.aws.amazon.com/pinpoint/home/). Amazon Cognito uses the registered number automatically. Otherwise, Amazon Cognito users who must receive SMS messages might not be able to sign up, activate their accounts, or sign in. /// - /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Service, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. + /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Servicesservice, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. _i3.SmithyOperation signUp( SignUpRequest input, { _i1.AWSHttpClient? client, @@ -654,7 +654,7 @@ class CognitoIdentityProviderClient { /// /// This action might generate an SMS text message. Starting June 1, 2021, US telecom carriers require you to register an origination phone number before you can send SMS messages to US phone numbers. If you use SMS text messages in Amazon Cognito, you must register a phone number with [Amazon Pinpoint](https://console.aws.amazon.com/pinpoint/home/). Amazon Cognito uses the registered number automatically. Otherwise, Amazon Cognito users who must receive SMS messages might not be able to sign up, activate their accounts, or sign in. /// - /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Service, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. + /// If you have never used SMS text messages with Amazon Cognito or any other Amazon Web Servicesservice, Amazon Simple Notification Service might place your account in the SMS sandbox. In _[sandbox mode](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox.html)_ , you can send messages only to verified phone numbers. After you test your app while in the sandbox environment, you can move out of the sandbox and into production. For more information, see [SMS message settings for Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-sms-settings.html) in the _Amazon Cognito Developer Guide_. _i3.SmithyOperation updateUserAttributes( UpdateUserAttributesRequest input, { _i1.AWSHttpClient? client, diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/common/endpoint_resolver.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/common/endpoint_resolver.dart index aa6948f01b..87bbaf7dc7 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/common/endpoint_resolver.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/common/endpoint_resolver.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.common.endpoint_resolver; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/common/serializers.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/common/serializers.dart index 4bd6e82ab8..45d3210bcb 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/common/serializers.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/common/serializers.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.common.serializers; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -28,6 +28,7 @@ import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/ import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/device_remembered_status_type.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/device_secret_verifier_config_type.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/device_type.dart'; +import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/enable_software_token_mfa_exception.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/expired_code_exception.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/forbidden_exception.dart'; @@ -59,6 +60,7 @@ import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/ import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/mfa_option_type.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/new_device_metadata_type.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/not_authorized_exception.dart'; +import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/password_reset_required_exception.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_request.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_response.dart'; @@ -112,6 +114,7 @@ const List<_i1.SmithySerializer> serializers = [ ...ChangePasswordResponse.serializers, ...InvalidPasswordException.serializers, ...LimitExceededException.serializers, + ...PasswordHistoryPolicyViolationException.serializers, ...PasswordResetRequiredException.serializers, ...TooManyRequestsException.serializers, ...UserNotConfirmedException.serializers, @@ -175,6 +178,7 @@ const List<_i1.SmithySerializer> serializers = [ ...UnsupportedTokenTypeException.serializers, ...SmsMfaSettingsType.serializers, ...SoftwareTokenMfaSettingsType.serializers, + ...EmailMfaSettingsType.serializers, ...SetUserMfaPreferenceRequest.serializers, ...SetUserMfaPreferenceResponse.serializers, ...SignUpRequest.serializers, diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/alias_exists_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/alias_exists_exception.dart index 6fe989ea5a..92daad3986 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/alias_exists_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/alias_exists_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.alias_exists_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/analytics_metadata_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/analytics_metadata_type.dart index 0c3b5e5cb1..3ce0fd64f0 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/analytics_metadata_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/analytics_metadata_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.analytics_metadata_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/associate_software_token_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/associate_software_token_request.dart index e85c27e777..68a490b537 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/associate_software_token_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/associate_software_token_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.associate_software_token_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/associate_software_token_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/associate_software_token_response.dart index 5d95699e30..c65a519903 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/associate_software_token_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/associate_software_token_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.associate_software_token_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/attribute_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/attribute_type.dart index c05750b94f..d6e81f84e6 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/attribute_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/attribute_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.attribute_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/auth_flow_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/auth_flow_type.dart index b72dedfb0e..63ef0d3e8b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/auth_flow_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/auth_flow_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.auth_flow_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/authentication_result_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/authentication_result_type.dart index e28c05e8f8..fe4c1436b2 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/authentication_result_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/authentication_result_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.authentication_result_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart index 16183b5270..245f07151e 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.challenge_name_type; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -38,38 +38,44 @@ class ChallengeNameType extends _i1.SmithyEnum { 'DEVICE_SRP_AUTH', ); - static const mfaSetup = ChallengeNameType._( + static const emailOtp = ChallengeNameType._( 4, + 'EMAIL_OTP', + 'EMAIL_OTP', + ); + + static const mfaSetup = ChallengeNameType._( + 5, 'MFA_SETUP', 'MFA_SETUP', ); static const newPasswordRequired = ChallengeNameType._( - 5, + 6, 'NEW_PASSWORD_REQUIRED', 'NEW_PASSWORD_REQUIRED', ); static const passwordVerifier = ChallengeNameType._( - 6, + 7, 'PASSWORD_VERIFIER', 'PASSWORD_VERIFIER', ); static const selectMfaType = ChallengeNameType._( - 7, + 8, 'SELECT_MFA_TYPE', 'SELECT_MFA_TYPE', ); static const smsMfa = ChallengeNameType._( - 8, + 9, 'SMS_MFA', 'SMS_MFA', ); static const softwareTokenMfa = ChallengeNameType._( - 9, + 10, 'SOFTWARE_TOKEN_MFA', 'SOFTWARE_TOKEN_MFA', ); @@ -80,6 +86,7 @@ class ChallengeNameType extends _i1.SmithyEnum { ChallengeNameType.customChallenge, ChallengeNameType.devicePasswordVerifier, ChallengeNameType.deviceSrpAuth, + ChallengeNameType.emailOtp, ChallengeNameType.mfaSetup, ChallengeNameType.newPasswordRequired, ChallengeNameType.passwordVerifier, diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/change_password_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/change_password_request.dart index 1bee4684cf..aca8f246fd 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/change_password_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/change_password_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.change_password_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/change_password_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/change_password_response.dart index 6d32ca2ee8..4dfb38ac75 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/change_password_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/change_password_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.change_password_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_delivery_details_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_delivery_details_type.dart index 34f7889f1f..2017a74f76 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_delivery_details_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_delivery_details_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.code_delivery_details_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_delivery_failure_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_delivery_failure_exception.dart index ce4d865c5c..f3a73bfb96 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_delivery_failure_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_delivery_failure_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.code_delivery_failure_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_mismatch_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_mismatch_exception.dart index 470c29a6b7..40d59d121e 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_mismatch_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/code_mismatch_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.code_mismatch_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/concurrent_modification_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/concurrent_modification_exception.dart index af4d648e10..a93d170315 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/concurrent_modification_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/concurrent_modification_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.concurrent_modification_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_device_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_device_request.dart index c9a359ad63..36ec585c57 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_device_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_device_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.confirm_device_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_device_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_device_response.dart index c4a56e3d20..742d7b7880 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_device_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_device_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.confirm_device_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_forgot_password_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_forgot_password_request.dart index 5ee0b35e9a..7d2eae3eb4 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_forgot_password_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_forgot_password_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.confirm_forgot_password_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_forgot_password_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_forgot_password_response.dart index 428faabe8b..a4bd14e09b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_forgot_password_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_forgot_password_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.confirm_forgot_password_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_sign_up_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_sign_up_request.dart index 674e4bf602..a3d08239b0 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_sign_up_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_sign_up_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.confirm_sign_up_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_sign_up_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_sign_up_response.dart index eb41e869cb..caba28a5c6 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_sign_up_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/confirm_sign_up_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.confirm_sign_up_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/delete_user_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/delete_user_request.dart index a1945ea8b1..6da56f6fad 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/delete_user_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/delete_user_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.delete_user_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/delivery_medium_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/delivery_medium_type.dart index 157cc2712f..f2d8b3b06b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/delivery_medium_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/delivery_medium_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.delivery_medium_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_remembered_status_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_remembered_status_type.dart index b7ec625425..6ea59d3c6e 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_remembered_status_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_remembered_status_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.device_remembered_status_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_secret_verifier_config_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_secret_verifier_config_type.dart index 69f90feee7..b001642117 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_secret_verifier_config_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_secret_verifier_config_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.device_secret_verifier_config_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_type.dart index f909f5c4cc..b48c396c5a 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/device_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.device_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.dart new file mode 100644 index 0000000000..f5871bb77d --- /dev/null +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.dart @@ -0,0 +1,147 @@ +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. +// ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas + +library amplify_auth_cognito_dart.cognito_identity_provider.model.email_mfa_settings_type; // ignore_for_file: no_leading_underscores_for_library_prefixes + +import 'package:aws_common/aws_common.dart' as _i1; +import 'package:built_value/built_value.dart'; +import 'package:built_value/serializer.dart'; +import 'package:smithy/smithy.dart' as _i2; + +part 'email_mfa_settings_type.g.dart'; + +/// User preferences for multi-factor authentication with email messages. Activates or deactivates email MFA and sets it as the preferred MFA method when multiple methods are available. To activate this setting, [advanced security features](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-advanced-security.html) must be active in your user pool. +abstract class EmailMfaSettingsType + with _i1.AWSEquatable + implements Built { + /// User preferences for multi-factor authentication with email messages. Activates or deactivates email MFA and sets it as the preferred MFA method when multiple methods are available. To activate this setting, [advanced security features](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-advanced-security.html) must be active in your user pool. + factory EmailMfaSettingsType({ + bool? enabled, + bool? preferredMfa, + }) { + enabled ??= false; + preferredMfa ??= false; + return _$EmailMfaSettingsType._( + enabled: enabled, + preferredMfa: preferredMfa, + ); + } + + /// User preferences for multi-factor authentication with email messages. Activates or deactivates email MFA and sets it as the preferred MFA method when multiple methods are available. To activate this setting, [advanced security features](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-advanced-security.html) must be active in your user pool. + factory EmailMfaSettingsType.build( + [void Function(EmailMfaSettingsTypeBuilder) updates]) = + _$EmailMfaSettingsType; + + const EmailMfaSettingsType._(); + + static const List<_i2.SmithySerializer> serializers = [ + EmailMfaSettingsTypeAwsJson11Serializer() + ]; + + @BuiltValueHook(initializeBuilder: true) + static void _init(EmailMfaSettingsTypeBuilder b) { + b + ..enabled = false + ..preferredMfa = false; + } + + /// Specifies whether email message MFA is active for a user. When the value of this parameter is `Enabled`, the user will be prompted for MFA during all sign-in attempts, unless device tracking is turned on and the device has been trusted. + bool get enabled; + + /// Specifies whether email message MFA is the user's preferred method. + bool get preferredMfa; + @override + List get props => [ + enabled, + preferredMfa, + ]; + + @override + String toString() { + final helper = newBuiltValueToStringHelper('EmailMfaSettingsType') + ..add( + 'enabled', + enabled, + ) + ..add( + 'preferredMfa', + preferredMfa, + ); + return helper.toString(); + } +} + +class EmailMfaSettingsTypeAwsJson11Serializer + extends _i2.StructuredSmithySerializer { + const EmailMfaSettingsTypeAwsJson11Serializer() + : super('EmailMfaSettingsType'); + + @override + Iterable get types => const [ + EmailMfaSettingsType, + _$EmailMfaSettingsType, + ]; + + @override + Iterable<_i2.ShapeId> get supportedProtocols => const [ + _i2.ShapeId( + namespace: 'aws.protocols', + shape: 'awsJson1_1', + ) + ]; + + @override + EmailMfaSettingsType deserialize( + Serializers serializers, + Iterable serialized, { + FullType specifiedType = FullType.unspecified, + }) { + final result = EmailMfaSettingsTypeBuilder(); + final iterator = serialized.iterator; + while (iterator.moveNext()) { + final key = iterator.current as String; + iterator.moveNext(); + final value = iterator.current; + if (value == null) { + continue; + } + switch (key) { + case 'Enabled': + result.enabled = (serializers.deserialize( + value, + specifiedType: const FullType(bool), + ) as bool); + case 'PreferredMfa': + result.preferredMfa = (serializers.deserialize( + value, + specifiedType: const FullType(bool), + ) as bool); + } + } + + return result.build(); + } + + @override + Iterable serialize( + Serializers serializers, + EmailMfaSettingsType object, { + FullType specifiedType = FullType.unspecified, + }) { + final result$ = []; + final EmailMfaSettingsType(:enabled, :preferredMfa) = object; + result$.addAll([ + 'Enabled', + serializers.serialize( + enabled, + specifiedType: const FullType(bool), + ), + 'PreferredMfa', + serializers.serialize( + preferredMfa, + specifiedType: const FullType(bool), + ), + ]); + return result$; + } +} diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.g.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.g.dart new file mode 100644 index 0000000000..9be203c737 --- /dev/null +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.g.dart @@ -0,0 +1,106 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'email_mfa_settings_type.dart'; + +// ************************************************************************** +// BuiltValueGenerator +// ************************************************************************** + +class _$EmailMfaSettingsType extends EmailMfaSettingsType { + @override + final bool enabled; + @override + final bool preferredMfa; + + factory _$EmailMfaSettingsType( + [void Function(EmailMfaSettingsTypeBuilder)? updates]) => + (new EmailMfaSettingsTypeBuilder()..update(updates))._build(); + + _$EmailMfaSettingsType._({required this.enabled, required this.preferredMfa}) + : super._() { + BuiltValueNullFieldError.checkNotNull( + enabled, r'EmailMfaSettingsType', 'enabled'); + BuiltValueNullFieldError.checkNotNull( + preferredMfa, r'EmailMfaSettingsType', 'preferredMfa'); + } + + @override + EmailMfaSettingsType rebuild( + void Function(EmailMfaSettingsTypeBuilder) updates) => + (toBuilder()..update(updates)).build(); + + @override + EmailMfaSettingsTypeBuilder toBuilder() => + new EmailMfaSettingsTypeBuilder()..replace(this); + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is EmailMfaSettingsType && + enabled == other.enabled && + preferredMfa == other.preferredMfa; + } + + @override + int get hashCode { + var _$hash = 0; + _$hash = $jc(_$hash, enabled.hashCode); + _$hash = $jc(_$hash, preferredMfa.hashCode); + _$hash = $jf(_$hash); + return _$hash; + } +} + +class EmailMfaSettingsTypeBuilder + implements Builder { + _$EmailMfaSettingsType? _$v; + + bool? _enabled; + bool? get enabled => _$this._enabled; + set enabled(bool? enabled) => _$this._enabled = enabled; + + bool? _preferredMfa; + bool? get preferredMfa => _$this._preferredMfa; + set preferredMfa(bool? preferredMfa) => _$this._preferredMfa = preferredMfa; + + EmailMfaSettingsTypeBuilder() { + EmailMfaSettingsType._init(this); + } + + EmailMfaSettingsTypeBuilder get _$this { + final $v = _$v; + if ($v != null) { + _enabled = $v.enabled; + _preferredMfa = $v.preferredMfa; + _$v = null; + } + return this; + } + + @override + void replace(EmailMfaSettingsType other) { + ArgumentError.checkNotNull(other, 'other'); + _$v = other as _$EmailMfaSettingsType; + } + + @override + void update(void Function(EmailMfaSettingsTypeBuilder)? updates) { + if (updates != null) updates(this); + } + + @override + EmailMfaSettingsType build() => _build(); + + _$EmailMfaSettingsType _build() { + final _$result = _$v ?? + new _$EmailMfaSettingsType._( + enabled: BuiltValueNullFieldError.checkNotNull( + enabled, r'EmailMfaSettingsType', 'enabled'), + preferredMfa: BuiltValueNullFieldError.checkNotNull( + preferredMfa, r'EmailMfaSettingsType', 'preferredMfa')); + replace(_$result); + return _$result; + } +} + +// ignore_for_file: deprecated_member_use_from_same_package,type=lint diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/enable_software_token_mfa_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/enable_software_token_mfa_exception.dart index ebfbade44b..dfbd457723 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/enable_software_token_mfa_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/enable_software_token_mfa_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.enable_software_token_mfa_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/expired_code_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/expired_code_exception.dart index 29f4dc36e5..f6ab049ad0 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/expired_code_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/expired_code_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.expired_code_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forbidden_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forbidden_exception.dart index 37ccbc6dcd..b97418f44b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forbidden_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forbidden_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.forbidden_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forget_device_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forget_device_request.dart index 57fa4dfe45..f716905bf4 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forget_device_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forget_device_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.forget_device_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forgot_password_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forgot_password_request.dart index 206bf31593..de772a3506 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forgot_password_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forgot_password_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.forgot_password_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forgot_password_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forgot_password_response.dart index 92fe7f3db7..2d77bdb4ac 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forgot_password_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/forgot_password_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.forgot_password_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_device_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_device_request.dart index 6f949ad858..d6068a3e65 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_device_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_device_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.get_device_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_device_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_device_response.dart index 62edc0d585..33bf747c39 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_device_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_device_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.get_device_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_attribute_verification_code_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_attribute_verification_code_request.dart index 183f2e2cb8..bc9f259d32 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_attribute_verification_code_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_attribute_verification_code_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.get_user_attribute_verification_code_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_attribute_verification_code_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_attribute_verification_code_response.dart index ab94635e1a..92e05abeac 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_attribute_verification_code_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_attribute_verification_code_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.get_user_attribute_verification_code_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_request.dart index eea378cd8a..61c037aa61 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.get_user_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_response.dart index eb690fbcbf..249a5a3fdf 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/get_user_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.get_user_response; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -66,7 +66,7 @@ abstract class GetUserResponse /// The user's preferred MFA setting. String? get preferredMfaSetting; - /// The MFA options that are activated for the user. The possible values in this list are `SMS_MFA` and `SOFTWARE\_TOKEN\_MFA`. + /// The MFA options that are activated for the user. The possible values in this list are `SMS_MFA`, `EMAIL_OTP`, and `SOFTWARE\_TOKEN\_MFA`. _i2.BuiltList? get userMfaSettingList; @override List get props => [ diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/global_sign_out_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/global_sign_out_request.dart index 924d17c3d0..a19ee40a56 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/global_sign_out_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/global_sign_out_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.global_sign_out_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/global_sign_out_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/global_sign_out_response.dart index 2941bae7c3..0cd0cad3ba 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/global_sign_out_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/global_sign_out_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.global_sign_out_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/initiate_auth_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/initiate_auth_request.dart index 299a26378f..d950158c01 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/initiate_auth_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/initiate_auth_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.initiate_auth_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/initiate_auth_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/initiate_auth_response.dart index b0d075afe3..b4d2d39b01 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/initiate_auth_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/initiate_auth_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.initiate_auth_response; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -58,7 +58,9 @@ abstract class InitiateAuthResponse /// /// All of the following challenges require `USERNAME` and `SECRET_HASH` (if applicable) in the parameters. /// - /// * `SMS_MFA`: Next challenge is to supply an `SMS\_MFA\_CODE`, delivered via SMS. + /// * `SMS_MFA`: Next challenge is to supply an `SMS\_MFA\_CODE`that your user pool delivered in an SMS message. + /// + /// * `EMAIL_OTP`: Next challenge is to supply an `EMAIL\_OTP\_CODE` that your user pool delivered in an email message. /// /// * `PASSWORD_VERIFIER`: Next challenge is to supply `PASSWORD\_CLAIM\_SIGNATURE`, `PASSWORD\_CLAIM\_SECRET_BLOCK`, and `TIMESTAMP` after the client-side SRP calculations. /// diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/internal_error_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/internal_error_exception.dart index deacb16eb0..ba19414e69 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/internal_error_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/internal_error_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.internal_error_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_email_role_access_policy_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_email_role_access_policy_exception.dart index f5c51b1a95..9593759c9c 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_email_role_access_policy_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_email_role_access_policy_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.invalid_email_role_access_policy_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_lambda_response_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_lambda_response_exception.dart index 265347fda5..dcfeb43424 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_lambda_response_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_lambda_response_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.invalid_lambda_response_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_parameter_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_parameter_exception.dart index ba0823619b..daed39aae1 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_parameter_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_parameter_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.invalid_parameter_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_password_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_password_exception.dart index 52c7699f17..e4f651a82b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_password_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_password_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.invalid_password_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_sms_role_access_policy_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_sms_role_access_policy_exception.dart index 15e2e29d4d..857cce6009 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_sms_role_access_policy_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_sms_role_access_policy_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.invalid_sms_role_access_policy_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_sms_role_trust_relationship_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_sms_role_trust_relationship_exception.dart index 515fc9d07d..cf52736fff 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_sms_role_trust_relationship_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_sms_role_trust_relationship_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.invalid_sms_role_trust_relationship_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_user_pool_configuration_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_user_pool_configuration_exception.dart index dbf2b347dc..62d8b0cec2 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_user_pool_configuration_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/invalid_user_pool_configuration_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.invalid_user_pool_configuration_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/limit_exceeded_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/limit_exceeded_exception.dart index c4ded607b3..fc3900ee8d 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/limit_exceeded_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/limit_exceeded_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.limit_exceeded_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/list_devices_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/list_devices_request.dart index 07201dab3d..3b2a6f0834 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/list_devices_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/list_devices_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.list_devices_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/list_devices_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/list_devices_response.dart index 50771c2b25..8de544538a 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/list_devices_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/list_devices_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.list_devices_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/mfa_method_not_found_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/mfa_method_not_found_exception.dart index d159df70a6..f223bc69b0 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/mfa_method_not_found_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/mfa_method_not_found_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.mfa_method_not_found_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/mfa_option_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/mfa_option_type.dart index c880f267c7..e6d103c6da 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/mfa_option_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/mfa_option_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.mfa_option_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/new_device_metadata_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/new_device_metadata_type.dart index 69a24a5ad4..56c8dc4549 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/new_device_metadata_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/new_device_metadata_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.new_device_metadata_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/not_authorized_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/not_authorized_exception.dart index 8b8c71a14f..667a4e4e7e 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/not_authorized_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/not_authorized_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.not_authorized_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.dart new file mode 100644 index 0000000000..8558e99e29 --- /dev/null +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.dart @@ -0,0 +1,148 @@ +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. +// ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas + +library amplify_auth_cognito_dart.cognito_identity_provider.model.password_history_policy_violation_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes + +import 'package:aws_common/aws_common.dart' as _i1; +import 'package:built_value/built_value.dart'; +import 'package:built_value/serializer.dart'; +import 'package:smithy/smithy.dart' as _i2; + +part 'password_history_policy_violation_exception.g.dart'; + +/// The message returned when a user's new password matches a previous password and doesn't comply with the password-history policy. +abstract class PasswordHistoryPolicyViolationException + with + _i1.AWSEquatable + implements + Built, + _i2.SmithyHttpException { + /// The message returned when a user's new password matches a previous password and doesn't comply with the password-history policy. + factory PasswordHistoryPolicyViolationException({String? message}) { + return _$PasswordHistoryPolicyViolationException._(message: message); + } + + /// The message returned when a user's new password matches a previous password and doesn't comply with the password-history policy. + factory PasswordHistoryPolicyViolationException.build( + [void Function(PasswordHistoryPolicyViolationExceptionBuilder) + updates]) = _$PasswordHistoryPolicyViolationException; + + const PasswordHistoryPolicyViolationException._(); + + /// Constructs a [PasswordHistoryPolicyViolationException] from a [payload] and [response]. + factory PasswordHistoryPolicyViolationException.fromResponse( + PasswordHistoryPolicyViolationException payload, + _i1.AWSBaseHttpResponse response, + ) => + payload.rebuild((b) { + b.headers = response.headers; + }); + + static const List< + _i2.SmithySerializer> + serializers = [ + PasswordHistoryPolicyViolationExceptionAwsJson11Serializer() + ]; + + @override + String? get message; + @override + _i2.ShapeId get shapeId => const _i2.ShapeId( + namespace: 'com.amazonaws.cognitoidentityprovider', + shape: 'PasswordHistoryPolicyViolationException', + ); + + @override + _i2.RetryConfig? get retryConfig => null; + + @override + @BuiltValueField(compare: false) + int get statusCode => 400; + + @override + @BuiltValueField(compare: false) + Map? get headers; + @override + Exception? get underlyingException => null; + + @override + List get props => [message]; + + @override + String toString() { + final helper = + newBuiltValueToStringHelper('PasswordHistoryPolicyViolationException') + ..add( + 'message', + message, + ); + return helper.toString(); + } +} + +class PasswordHistoryPolicyViolationExceptionAwsJson11Serializer extends _i2 + .StructuredSmithySerializer { + const PasswordHistoryPolicyViolationExceptionAwsJson11Serializer() + : super('PasswordHistoryPolicyViolationException'); + + @override + Iterable get types => const [ + PasswordHistoryPolicyViolationException, + _$PasswordHistoryPolicyViolationException, + ]; + + @override + Iterable<_i2.ShapeId> get supportedProtocols => const [ + _i2.ShapeId( + namespace: 'aws.protocols', + shape: 'awsJson1_1', + ) + ]; + + @override + PasswordHistoryPolicyViolationException deserialize( + Serializers serializers, + Iterable serialized, { + FullType specifiedType = FullType.unspecified, + }) { + final result = PasswordHistoryPolicyViolationExceptionBuilder(); + final iterator = serialized.iterator; + while (iterator.moveNext()) { + final key = iterator.current as String; + iterator.moveNext(); + final value = iterator.current; + if (value == null) { + continue; + } + switch (key) { + case 'message': + result.message = (serializers.deserialize( + value, + specifiedType: const FullType(String), + ) as String); + } + } + + return result.build(); + } + + @override + Iterable serialize( + Serializers serializers, + PasswordHistoryPolicyViolationException object, { + FullType specifiedType = FullType.unspecified, + }) { + final result$ = []; + final PasswordHistoryPolicyViolationException(:message) = object; + if (message != null) { + result$ + ..add('message') + ..add(serializers.serialize( + message, + specifiedType: const FullType(String), + )); + } + return result$; + } +} diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.g.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.g.dart new file mode 100644 index 0000000000..14462c7c57 --- /dev/null +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.g.dart @@ -0,0 +1,101 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'password_history_policy_violation_exception.dart'; + +// ************************************************************************** +// BuiltValueGenerator +// ************************************************************************** + +class _$PasswordHistoryPolicyViolationException + extends PasswordHistoryPolicyViolationException { + @override + final String? message; + @override + final Map? headers; + + factory _$PasswordHistoryPolicyViolationException( + [void Function(PasswordHistoryPolicyViolationExceptionBuilder)? + updates]) => + (new PasswordHistoryPolicyViolationExceptionBuilder()..update(updates)) + ._build(); + + _$PasswordHistoryPolicyViolationException._({this.message, this.headers}) + : super._(); + + @override + PasswordHistoryPolicyViolationException rebuild( + void Function(PasswordHistoryPolicyViolationExceptionBuilder) + updates) => + (toBuilder()..update(updates)).build(); + + @override + PasswordHistoryPolicyViolationExceptionBuilder toBuilder() => + new PasswordHistoryPolicyViolationExceptionBuilder()..replace(this); + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is PasswordHistoryPolicyViolationException && + message == other.message; + } + + @override + int get hashCode { + var _$hash = 0; + _$hash = $jc(_$hash, message.hashCode); + _$hash = $jf(_$hash); + return _$hash; + } +} + +class PasswordHistoryPolicyViolationExceptionBuilder + implements + Builder { + _$PasswordHistoryPolicyViolationException? _$v; + + String? _message; + String? get message => _$this._message; + set message(String? message) => _$this._message = message; + + Map? _headers; + Map? get headers => _$this._headers; + set headers(Map? headers) => _$this._headers = headers; + + PasswordHistoryPolicyViolationExceptionBuilder(); + + PasswordHistoryPolicyViolationExceptionBuilder get _$this { + final $v = _$v; + if ($v != null) { + _message = $v.message; + _headers = $v.headers; + _$v = null; + } + return this; + } + + @override + void replace(PasswordHistoryPolicyViolationException other) { + ArgumentError.checkNotNull(other, 'other'); + _$v = other as _$PasswordHistoryPolicyViolationException; + } + + @override + void update( + void Function(PasswordHistoryPolicyViolationExceptionBuilder)? updates) { + if (updates != null) updates(this); + } + + @override + PasswordHistoryPolicyViolationException build() => _build(); + + _$PasswordHistoryPolicyViolationException _build() { + final _$result = _$v ?? + new _$PasswordHistoryPolicyViolationException._( + message: message, headers: headers); + replace(_$result); + return _$result; + } +} + +// ignore_for_file: deprecated_member_use_from_same_package,type=lint diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_reset_required_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_reset_required_exception.dart index 3d93fd22a1..0e4500dc25 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_reset_required_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/password_reset_required_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.password_reset_required_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_request.dart index 4cf8678d2d..94ad518a90 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.resend_confirmation_code_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_response.dart index 808df308e4..6a214d00dc 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resend_confirmation_code_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.resend_confirmation_code_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resource_not_found_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resource_not_found_exception.dart index d54f471e9e..925645afe5 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resource_not_found_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/resource_not_found_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.resource_not_found_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/respond_to_auth_challenge_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/respond_to_auth_challenge_request.dart index 6d45689bc9..06ac52c376 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/respond_to_auth_challenge_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/respond_to_auth_challenge_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.respond_to_auth_challenge_request; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -79,10 +79,16 @@ abstract class RespondToAuthChallengeRequest /// /// SMS_MFA /// - /// `"ChallengeName": "SMS\_MFA", "ChallengeResponses": {"SMS\_MFA\_CODE": "\[SMS\_code\]", "USERNAME": "\[username\]"}` + /// `"ChallengeName": "SMS\_MFA", "ChallengeResponses": {"SMS\_MFA_CODE": "\[code\]", "USERNAME": "\[username\]"}` + /// + /// EMAIL_OTP + /// + /// `"ChallengeName": "EMAIL\_OTP", "ChallengeResponses": {"EMAIL\_OTP_CODE": "\[code\]", "USERNAME": "\[username\]"}` /// /// PASSWORD_VERIFIER /// + /// This challenge response is part of the SRP flow. Amazon Cognito requires that your application respond to this challenge within a few seconds. When the response time exceeds this period, your user pool returns a `NotAuthorizedException` error. + /// /// `"ChallengeName": "PASSWORD\_VERIFIER", "ChallengeResponses": {"PASSWORD\_CLAIM\_SIGNATURE": "\[claim\_signature\]", "PASSWORD\_CLAIM\_SECRET\_BLOCK": "\[secret\_block\]", "TIMESTAMP": \[timestamp\], "USERNAME": "\[username\]"}` /// /// Add `"DEVICE_KEY"` when you sign in with a remembered device. diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/respond_to_auth_challenge_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/respond_to_auth_challenge_response.dart index d2cef93d19..8ea2f06cec 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/respond_to_auth_challenge_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/respond_to_auth_challenge_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.respond_to_auth_challenge_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/revoke_token_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/revoke_token_request.dart index 7a46034d7d..423af9fabe 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/revoke_token_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/revoke_token_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.revoke_token_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/revoke_token_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/revoke_token_response.dart index 566e257c2a..d9e99039d3 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/revoke_token_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/revoke_token_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.revoke_token_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_request.dart index 6a541e339c..04bb1ad29b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_request.dart @@ -1,8 +1,9 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.set_user_mfa_preference_request; // ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/email_mfa_settings_type.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/sms_mfa_settings_type.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/software_token_mfa_settings_type.dart'; import 'package:aws_common/aws_common.dart' as _i2; @@ -21,11 +22,13 @@ abstract class SetUserMfaPreferenceRequest factory SetUserMfaPreferenceRequest({ SmsMfaSettingsType? smsMfaSettings, SoftwareTokenMfaSettingsType? softwareTokenMfaSettings, + EmailMfaSettingsType? emailMfaSettings, required String accessToken, }) { return _$SetUserMfaPreferenceRequest._( smsMfaSettings: smsMfaSettings, softwareTokenMfaSettings: softwareTokenMfaSettings, + emailMfaSettings: emailMfaSettings, accessToken: accessToken, ); } @@ -46,12 +49,15 @@ abstract class SetUserMfaPreferenceRequest static const List<_i1.SmithySerializer> serializers = [SetUserMfaPreferenceRequestAwsJson11Serializer()]; - /// The SMS text message multi-factor authentication (MFA) settings. + /// User preferences for SMS message MFA. Activates or deactivates SMS MFA and sets it as the preferred MFA method when multiple methods are available. SmsMfaSettingsType? get smsMfaSettings; - /// The time-based one-time password (TOTP) software token MFA settings. + /// User preferences for time-based one-time password (TOTP) MFA. Activates or deactivates TOTP MFA and sets it as the preferred MFA method when multiple methods are available. SoftwareTokenMfaSettingsType? get softwareTokenMfaSettings; + /// User preferences for email message MFA. Activates or deactivates email MFA and sets it as the preferred MFA method when multiple methods are available. To activate this setting, [advanced security features](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-advanced-security.html) must be active in your user pool. + EmailMfaSettingsType? get emailMfaSettings; + /// A valid access token that Amazon Cognito issued to the user whose MFA preference you want to set. String get accessToken; @override @@ -61,6 +67,7 @@ abstract class SetUserMfaPreferenceRequest List get props => [ smsMfaSettings, softwareTokenMfaSettings, + emailMfaSettings, accessToken, ]; @@ -75,6 +82,10 @@ abstract class SetUserMfaPreferenceRequest 'softwareTokenMfaSettings', softwareTokenMfaSettings, ) + ..add( + 'emailMfaSettings', + emailMfaSettings, + ) ..add( 'accessToken', '***SENSITIVE***', @@ -128,6 +139,11 @@ class SetUserMfaPreferenceRequestAwsJson11Serializer value, specifiedType: const FullType(SoftwareTokenMfaSettingsType), ) as SoftwareTokenMfaSettingsType)); + case 'EmailMfaSettings': + result.emailMfaSettings.replace((serializers.deserialize( + value, + specifiedType: const FullType(EmailMfaSettingsType), + ) as EmailMfaSettingsType)); case 'AccessToken': result.accessToken = (serializers.deserialize( value, @@ -149,6 +165,7 @@ class SetUserMfaPreferenceRequestAwsJson11Serializer final SetUserMfaPreferenceRequest( :smsMfaSettings, :softwareTokenMfaSettings, + :emailMfaSettings, :accessToken ) = object; result$.addAll([ @@ -174,6 +191,14 @@ class SetUserMfaPreferenceRequestAwsJson11Serializer specifiedType: const FullType(SoftwareTokenMfaSettingsType), )); } + if (emailMfaSettings != null) { + result$ + ..add('EmailMfaSettings') + ..add(serializers.serialize( + emailMfaSettings, + specifiedType: const FullType(EmailMfaSettingsType), + )); + } return result$; } } diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_request.g.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_request.g.dart index ca68a57587..fec5ce2c1e 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_request.g.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_request.g.dart @@ -12,6 +12,8 @@ class _$SetUserMfaPreferenceRequest extends SetUserMfaPreferenceRequest { @override final SoftwareTokenMfaSettingsType? softwareTokenMfaSettings; @override + final EmailMfaSettingsType? emailMfaSettings; + @override final String accessToken; factory _$SetUserMfaPreferenceRequest( @@ -21,6 +23,7 @@ class _$SetUserMfaPreferenceRequest extends SetUserMfaPreferenceRequest { _$SetUserMfaPreferenceRequest._( {this.smsMfaSettings, this.softwareTokenMfaSettings, + this.emailMfaSettings, required this.accessToken}) : super._() { BuiltValueNullFieldError.checkNotNull( @@ -42,6 +45,7 @@ class _$SetUserMfaPreferenceRequest extends SetUserMfaPreferenceRequest { return other is SetUserMfaPreferenceRequest && smsMfaSettings == other.smsMfaSettings && softwareTokenMfaSettings == other.softwareTokenMfaSettings && + emailMfaSettings == other.emailMfaSettings && accessToken == other.accessToken; } @@ -50,6 +54,7 @@ class _$SetUserMfaPreferenceRequest extends SetUserMfaPreferenceRequest { var _$hash = 0; _$hash = $jc(_$hash, smsMfaSettings.hashCode); _$hash = $jc(_$hash, softwareTokenMfaSettings.hashCode); + _$hash = $jc(_$hash, emailMfaSettings.hashCode); _$hash = $jc(_$hash, accessToken.hashCode); _$hash = $jf(_$hash); return _$hash; @@ -76,6 +81,12 @@ class SetUserMfaPreferenceRequestBuilder SoftwareTokenMfaSettingsTypeBuilder? softwareTokenMfaSettings) => _$this._softwareTokenMfaSettings = softwareTokenMfaSettings; + EmailMfaSettingsTypeBuilder? _emailMfaSettings; + EmailMfaSettingsTypeBuilder get emailMfaSettings => + _$this._emailMfaSettings ??= new EmailMfaSettingsTypeBuilder(); + set emailMfaSettings(EmailMfaSettingsTypeBuilder? emailMfaSettings) => + _$this._emailMfaSettings = emailMfaSettings; + String? _accessToken; String? get accessToken => _$this._accessToken; set accessToken(String? accessToken) => _$this._accessToken = accessToken; @@ -87,6 +98,7 @@ class SetUserMfaPreferenceRequestBuilder if ($v != null) { _smsMfaSettings = $v.smsMfaSettings?.toBuilder(); _softwareTokenMfaSettings = $v.softwareTokenMfaSettings?.toBuilder(); + _emailMfaSettings = $v.emailMfaSettings?.toBuilder(); _accessToken = $v.accessToken; _$v = null; } @@ -114,6 +126,7 @@ class SetUserMfaPreferenceRequestBuilder new _$SetUserMfaPreferenceRequest._( smsMfaSettings: _smsMfaSettings?.build(), softwareTokenMfaSettings: _softwareTokenMfaSettings?.build(), + emailMfaSettings: _emailMfaSettings?.build(), accessToken: BuiltValueNullFieldError.checkNotNull( accessToken, r'SetUserMfaPreferenceRequest', 'accessToken')); } catch (_) { @@ -123,6 +136,8 @@ class SetUserMfaPreferenceRequestBuilder _smsMfaSettings?.build(); _$failedField = 'softwareTokenMfaSettings'; _softwareTokenMfaSettings?.build(); + _$failedField = 'emailMfaSettings'; + _emailMfaSettings?.build(); } catch (e) { throw new BuiltValueNestedFieldError( r'SetUserMfaPreferenceRequest', _$failedField, e.toString()); diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_response.dart index 371c315986..bfb06d87f1 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/set_user_mfa_preference_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.set_user_mfa_preference_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sign_up_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sign_up_request.dart index c3363048cb..8709755f15 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sign_up_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sign_up_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.sign_up_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sign_up_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sign_up_response.dart index c20050a0b7..5c5dc0cf4c 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sign_up_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sign_up_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.sign_up_response; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -57,7 +57,7 @@ abstract class SignUpResponse /// The code delivery details returned by the server response to the user registration request. CodeDeliveryDetailsType? get codeDeliveryDetails; - /// The UUID of the authenticated user. This isn't the same as `username`. + /// The 128-bit ID of the authenticated user. This isn't the same as `username`. String get userSub; @override List get props => [ diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sms_mfa_settings_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sms_mfa_settings_type.dart index 5fbcc78d0a..c69f645d76 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sms_mfa_settings_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/sms_mfa_settings_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.sms_mfa_settings_type; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -45,7 +45,7 @@ abstract class SmsMfaSettingsType ..preferredMfa = false; } - /// Specifies whether SMS text message MFA is activated. If an MFA type is activated for a user, the user will be prompted for MFA during all sign-in attempts, unless device tracking is turned on and the device has been trusted. + /// Specifies whether SMS message MFA is activated. If an MFA type is activated for a user, the user will be prompted for MFA during all sign-in attempts, unless device tracking is turned on and the device has been trusted. bool get enabled; /// Specifies whether SMS is the preferred MFA method. diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/software_token_mfa_not_found_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/software_token_mfa_not_found_exception.dart index b886706039..b3e013dc50 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/software_token_mfa_not_found_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/software_token_mfa_not_found_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.software_token_mfa_not_found_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/software_token_mfa_settings_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/software_token_mfa_settings_type.dart index 25cfafd5a3..1aee62a4d4 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/software_token_mfa_settings_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/software_token_mfa_settings_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.software_token_mfa_settings_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/too_many_failed_attempts_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/too_many_failed_attempts_exception.dart index c487f39ff6..df9e4d77e4 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/too_many_failed_attempts_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/too_many_failed_attempts_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.too_many_failed_attempts_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/too_many_requests_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/too_many_requests_exception.dart index b1cb3aaa5f..dcf1d32175 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/too_many_requests_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/too_many_requests_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.too_many_requests_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unauthorized_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unauthorized_exception.dart index 50ecabe32d..e5c09b5106 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unauthorized_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unauthorized_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.unauthorized_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unexpected_lambda_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unexpected_lambda_exception.dart index 34a02e236b..474492765a 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unexpected_lambda_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unexpected_lambda_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.unexpected_lambda_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unsupported_operation_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unsupported_operation_exception.dart index c31068e2ae..0e4b511b26 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unsupported_operation_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unsupported_operation_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.unsupported_operation_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unsupported_token_type_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unsupported_token_type_exception.dart index 2979954ab5..acff97bd7d 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unsupported_token_type_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/unsupported_token_type_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.unsupported_token_type_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_device_status_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_device_status_request.dart index 1935e80768..3c50ce8453 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_device_status_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_device_status_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.update_device_status_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_device_status_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_device_status_response.dart index 970c2e9b97..81f5daaa34 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_device_status_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_device_status_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.update_device_status_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_user_attributes_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_user_attributes_request.dart index 49238c60f8..50c621fa40 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_user_attributes_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_user_attributes_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.update_user_attributes_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_user_attributes_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_user_attributes_response.dart index a8dbfabd2c..65a464efff 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_user_attributes_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/update_user_attributes_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.update_user_attributes_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_context_data_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_context_data_type.dart index 5f214b4004..f98d85cfd4 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_context_data_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_context_data_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.user_context_data_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_lambda_validation_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_lambda_validation_exception.dart index 225e45dbca..19a37c5299 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_lambda_validation_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_lambda_validation_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.user_lambda_validation_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_not_confirmed_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_not_confirmed_exception.dart index a75f0605f2..1ba1c2d2e8 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_not_confirmed_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_not_confirmed_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.user_not_confirmed_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_not_found_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_not_found_exception.dart index 9d0d33889c..060958dac4 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_not_found_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/user_not_found_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.user_not_found_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/username_exists_exception.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/username_exists_exception.dart index 0d1ad7b19b..6a5e063454 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/username_exists_exception.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/username_exists_exception.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.username_exists_exception; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_request.dart index 78199373a4..b880b6ff91 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.verify_software_token_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_response.dart index 706fc241fe..5084e7f717 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.verify_software_token_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_response_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_response_type.dart index 4fa5346f09..5de62aad58 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_response_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_software_token_response_type.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.verify_software_token_response_type; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_user_attribute_request.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_user_attribute_request.dart index 7603269bcb..0ab9eb603b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_user_attribute_request.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_user_attribute_request.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.verify_user_attribute_request; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_user_attribute_response.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_user_attribute_response.dart index 79883fe9ed..2bd2b4cd53 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_user_attribute_response.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/verify_user_attribute_response.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.model.verify_user_attribute_response; // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/associate_software_token_operation.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/associate_software_token_operation.dart index 8a63714d88..a59df7d709 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/associate_software_token_operation.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/associate_software_token_operation.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.operation.associate_software_token_operation; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -23,7 +23,7 @@ import 'package:smithy_aws/smithy_aws.dart' as _i3; /// Begins setup of time-based one-time password (TOTP) multi-factor authentication (MFA) for a user, with a unique private key that Amazon Cognito generates and returns in the API response. You can authorize an `AssociateSoftwareToken` request with either the user's access token, or a session string from a challenge response that you received from Amazon Cognito. /// -/// Amazon Cognito disassociates an existing software token when you verify the new token in a [VerifySoftwareToken](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_VerifySoftwareToken.html) API request. If you don't verify the software token and your user pool doesn't require MFA, the user can then authenticate with user name and password credentials alone. If your user pool requires TOTP MFA, Amazon Cognito generates an `MFA_SETUP` or `SOFTWARE\_TOKEN\_SETUP` challenge each time your user signs. Complete setup with `AssociateSoftwareToken` and `VerifySoftwareToken`. +/// Amazon Cognito disassociates an existing software token when you verify the new token in a [VerifySoftwareToken](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_VerifySoftwareToken.html) API request. If you don't verify the software token and your user pool doesn't require MFA, the user can then authenticate with user name and password credentials alone. If your user pool requires TOTP MFA, Amazon Cognito generates an `MFA_SETUP` or `SOFTWARE\_TOKEN\_SETUP` challenge each time your user signs in. Complete setup with `AssociateSoftwareToken` and `VerifySoftwareToken`. /// /// After you set up software token MFA for your user, Amazon Cognito generates a `SOFTWARE\_TOKEN\_MFA` challenge when they authenticate. Respond to this challenge with your user's TOTP. /// @@ -35,7 +35,7 @@ class AssociateSoftwareTokenOperation extends _i1.HttpOperation< AssociateSoftwareTokenResponse> { /// Begins setup of time-based one-time password (TOTP) multi-factor authentication (MFA) for a user, with a unique private key that Amazon Cognito generates and returns in the API response. You can authorize an `AssociateSoftwareToken` request with either the user's access token, or a session string from a challenge response that you received from Amazon Cognito. /// - /// Amazon Cognito disassociates an existing software token when you verify the new token in a [VerifySoftwareToken](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_VerifySoftwareToken.html) API request. If you don't verify the software token and your user pool doesn't require MFA, the user can then authenticate with user name and password credentials alone. If your user pool requires TOTP MFA, Amazon Cognito generates an `MFA_SETUP` or `SOFTWARE\_TOKEN\_SETUP` challenge each time your user signs. Complete setup with `AssociateSoftwareToken` and `VerifySoftwareToken`. + /// Amazon Cognito disassociates an existing software token when you verify the new token in a [VerifySoftwareToken](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_VerifySoftwareToken.html) API request. If you don't verify the software token and your user pool doesn't require MFA, the user can then authenticate with user name and password credentials alone. If your user pool requires TOTP MFA, Amazon Cognito generates an `MFA_SETUP` or `SOFTWARE\_TOKEN\_SETUP` challenge each time your user signs in. Complete setup with `AssociateSoftwareToken` and `VerifySoftwareToken`. /// /// After you set up software token MFA for your user, Amazon Cognito generates a `SOFTWARE\_TOKEN\_MFA` challenge when they authenticate. Respond to this challenge with your user's TOTP. /// @@ -76,7 +76,7 @@ class AssociateSoftwareTokenOperation extends _i1.HttpOperation< credentialsProvider: _credentialsProvider, isOptional: true, ), - const _i1.WithUserAgent('aws-sdk-dart/0.3.1'), + const _i1.WithUserAgent('aws-sdk-dart/0.3.2'), const _i3.WithSdkInvocationId(), const _i3.WithSdkRequest(), ] + diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/change_password_operation.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/change_password_operation.dart index 81918f776a..7b6f0b0a20 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/change_password_operation.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/change_password_operation.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.operation.change_password_operation; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -15,6 +15,7 @@ import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/ import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/invalid_password_exception.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/limit_exceeded_exception.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/not_authorized_exception.dart'; +import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/password_history_policy_violation_exception.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/password_reset_required_exception.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/resource_not_found_exception.dart'; import 'package:amplify_auth_cognito_dart/src/sdk/src/cognito_identity_provider/model/too_many_requests_exception.dart'; @@ -70,7 +71,7 @@ class ChangePasswordOperation extends _i1.HttpOperation( + _i1.ShapeId( + namespace: 'com.amazonaws.cognitoidentityprovider', + shape: 'PasswordHistoryPolicyViolationException', + ), + _i1.ErrorKind.client, + PasswordHistoryPolicyViolationException, + statusCode: 400, + builder: PasswordHistoryPolicyViolationException.fromResponse, + ), _i1.SmithyError( _i1.ShapeId( diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/confirm_device_operation.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/confirm_device_operation.dart index 27c5bc8073..5e6c9a0969 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/confirm_device_operation.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/confirm_device_operation.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.operation.confirm_device_operation; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -72,7 +72,7 @@ class ConfirmDeviceOperation extends _i1.HttpOperation( + _i1.ShapeId( + namespace: 'com.amazonaws.cognitoidentityprovider', + shape: 'PasswordHistoryPolicyViolationException', + ), + _i1.ErrorKind.client, + PasswordHistoryPolicyViolationException, + statusCode: 400, + builder: PasswordHistoryPolicyViolationException.fromResponse, + ), _i1.SmithyError( _i1.ShapeId( namespace: 'com.amazonaws.cognitoidentityprovider', diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/confirm_sign_up_operation.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/confirm_sign_up_operation.dart index 9d62149fbf..dd03525a4f 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/confirm_sign_up_operation.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/confirm_sign_up_operation.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.operation.confirm_sign_up_operation; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -74,7 +74,7 @@ class ConfirmSignUpOperation extends _i1.HttpOperation { /// Calling this API causes a message to be sent to the end user with a confirmation code that is required to change the user's password. For the `Username` parameter, you can use the username or user alias. The method used to send the confirmation code is sent according to the specified AccountRecoverySetting. For more information, see [Recovering User Accounts](https://docs.aws.amazon.com/cognito/latest/developerguide/how-to-recover-a-user-account.html) in the _Amazon Cognito Developer Guide_. To use the confirmation code for resetting the password, call [ConfirmForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmForgotPassword.html). @@ -52,7 +52,7 @@ class ForgotPasswordOperation extends _i1.HttpOperation { /// Initiates sign-in for a user in the Amazon Cognito user directory. You can't sign in a user with a federated IdP with `InitiateAuth`. For more information, see [Adding user pool sign-in through a third party](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-identity-federation.html). @@ -44,7 +45,7 @@ class InitiateAuthOperation extends _i1.HttpOperation( + _i1.ShapeId( + namespace: 'com.amazonaws.cognitoidentityprovider', + shape: 'InvalidEmailRoleAccessPolicyException', + ), + _i1.ErrorKind.client, + InvalidEmailRoleAccessPolicyException, + statusCode: 400, + builder: InvalidEmailRoleAccessPolicyException.fromResponse, + ), _i1.SmithyError( _i1.ShapeId( diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/list_devices_operation.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/list_devices_operation.dart index 3c17fd4b17..e9087a8151 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/list_devices_operation.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/list_devices_operation.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.operation.list_devices_operation; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -69,7 +69,7 @@ class ListDevicesOperation extends _i1.HttpOperation( + _i1.ShapeId( + namespace: 'com.amazonaws.cognitoidentityprovider', + shape: 'InvalidEmailRoleAccessPolicyException', + ), + _i1.ErrorKind.client, + InvalidEmailRoleAccessPolicyException, + statusCode: 400, + builder: InvalidEmailRoleAccessPolicyException.fromResponse, + ), _i1.SmithyError( _i1.ShapeId( @@ -274,6 +287,17 @@ class RespondToAuthChallengeOperation extends _i1.HttpOperation< statusCode: 403, builder: NotAuthorizedException.fromResponse, ), + _i1.SmithyError( + _i1.ShapeId( + namespace: 'com.amazonaws.cognitoidentityprovider', + shape: 'PasswordHistoryPolicyViolationException', + ), + _i1.ErrorKind.client, + PasswordHistoryPolicyViolationException, + statusCode: 400, + builder: PasswordHistoryPolicyViolationException.fromResponse, + ), _i1.SmithyError( _i1.ShapeId( diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/revoke_token_operation.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/revoke_token_operation.dart index 7ae9abe992..e7878fd5f7 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/revoke_token_operation.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/operation/revoke_token_operation.dart @@ -1,4 +1,4 @@ -// Generated with smithy-dart 0.3.1. DO NOT MODIFY. +// Generated with smithy-dart 0.3.2. DO NOT MODIFY. // ignore_for_file: avoid_unused_constructor_parameters,deprecated_member_use_from_same_package,non_constant_identifier_names,require_trailing_commas library amplify_auth_cognito_dart.cognito_identity_provider.operation.revoke_token_operation; // ignore_for_file: no_leading_underscores_for_library_prefixes @@ -62,7 +62,7 @@ class RevokeTokenOperation extends _i1.HttpOperation { /// Registers the user in the specified user pool and creates a user name, password, and user attributes. @@ -45,7 +45,7 @@ class SignUpOperation extends _i1.HttpOperation Date: Fri, 13 Sep 2024 16:38:52 -0700 Subject: [PATCH 012/159] chore: fix merge changes and sdk challenge name --- .../auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart | 2 +- .../lib/src/state/machines/sign_in_state_machine.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index 593b38a583..ec6a73d46c 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -33,7 +33,7 @@ extension ChallengeNameTypeBridge on ChallengeNameType { ChallengeNameType.softwareTokenMfa => AuthSignInStep.confirmSignInWithTotpMfaCode, // TODO(khatruong2009): confirm ChallengeNameType.emailMfa is added to SDK - ChallengeNameType.emailMfa => AuthSignInStep.confirmSignInWithEmailMfaCode, + ChallengeNameType.emailOtp => AuthSignInStep.confirmSignInWithEmailMfaCode, ChallengeNameType.adminNoSrpAuth || ChallengeNameType.passwordVerifier || ChallengeNameType.devicePasswordVerifier || diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 46666c79fd..024e39c875 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -458,7 +458,7 @@ final class SignInStateMachine _enableMfaType = MfaType.email; return RespondToAuthChallengeRequest.build((b) { b - ..clientId = config.appClientId + ..clientId = _authOutputs.userPoolClientId ..challengeName = _challengeName ..challengeResponses.addAll({ CognitoConstants.challengeParamUsername: cognitoUsername, From c98ce74a40684320b0fca2722d23a89c898ea773 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:40:46 -0700 Subject: [PATCH 013/159] chore: fix name of challenge to match with SDK changes and updated state machine --- .../lib/src/flows/constants.dart | 2 +- .../lib/src/state/machines/sign_in_state_machine.dart | 7 +++++-- .../lib/src/l10n/generated/input_localizations.dart | 6 ++++++ .../lib/src/l10n/generated/input_localizations_en.dart | 3 +++ .../lib/src/l10n/input_resolver.dart | 8 ++++++++ 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart index ff49ec7974..536c33c529 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart @@ -58,7 +58,7 @@ abstract class CognitoConstants { static const challengeParamSmsMfaCode = 'SMS_MFA_CODE'; /// The `EMAIL_MFA_CODE` parameter. - static const challengeParamEmailMfaCode = 'EMAIL_MFA_CODE'; + static const challengeParamEmailMfaCode = 'EMAIL_OTP_CODE'; /// The `SOFTWARE_TOKEN_MFA_CODE` parameter. static const challengeParamSoftwareTokenMfaCode = 'SOFTWARE_TOKEN_MFA_CODE'; diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 024e39c875..4dbc775736 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -211,7 +211,7 @@ final class SignInStateMachine (type) => switch (type) { 'SOFTWARE_TOKEN_MFA' => MfaType.totp, 'SMS_MFA' => MfaType.sms, - 'EMAIL_MFA' => MfaType.email, + 'EMAIL_OTP' => MfaType.email, _ => () { logger.error('Unrecognized MFA type: $type'); return null; @@ -326,6 +326,8 @@ final class SignInStateMachine createSmsMfaRequest(event), ChallengeNameType.softwareTokenMfa when hasUserResponse => createSoftwareTokenMfaRequest(event), + ChallengeNameType.emailOtp when hasUserResponse => + createEmailMfaRequest(event), ChallengeNameType.selectMfaType when hasUserResponse => createSelectMfaRequest(event), ChallengeNameType.mfaSetup when hasUserResponse => @@ -686,7 +688,7 @@ final class SignInStateMachine CognitoConstants.challengeParamAnswer: switch (selection) { 'sms' => 'SMS_MFA', 'totp' => 'SOFTWARE_TOKEN_MFA', - 'email' => 'EMAIL_MFA', + 'email' => 'EMAIL_OTP', _ => throw ArgumentError('Must be either SMS, Email, or TOTP'), }, }) @@ -954,6 +956,7 @@ final class SignInStateMachine accessToken: accessToken, sms: enableMfaType == MfaType.sms ? MfaPreference.enabled : null, totp: enableMfaType == MfaType.totp ? MfaPreference.enabled : null, + email: enableMfaType == MfaType.email ? MfaPreference.enabled : null, ); } on Exception catch (e, st) { logger.error( diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations.dart index 178e5b3eeb..c86a8a9ed4 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations.dart @@ -297,6 +297,12 @@ abstract class AuthenticatorInputLocalizations { /// **'Authenticator App (TOTP)'** String get selectTotp; + /// Label for the radio button to select email as the user's chosen MFA method. + /// + /// In en, this message translates to: + /// **'Email'** + String get selectEmail; + /// The instructional text for submitting a TOTP pass code /// /// In en, this message translates to: diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart index dcd9c0139c..6b6d42a494 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart @@ -153,6 +153,9 @@ class AuthenticatorInputLocalizationsEn @override String get selectTotp => 'Authenticator App (TOTP)'; + @override + String get selectEmail => 'Email'; + @override String get totpCodePrompt => 'Please enter the code from your registered Authenticator app'; diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart index ad9eed1b0c..4b04f86962 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart @@ -33,6 +33,7 @@ enum InputField { rememberDevice, selectSms, selectTotp, + selectEmail, totpCodePrompt, usernameType, } @@ -171,6 +172,11 @@ class InputResolverKey { field: InputField.selectSms, ); + static const selectEmail = InputResolverKey._( + InputResolverKeyType.title, + field: InputField.email, + ); + static const totpCodePrompt = InputResolverKey._( InputResolverKeyType.title, field: InputField.totpCodePrompt, @@ -456,6 +462,8 @@ class InputResolver extends Resolver { return AuthenticatorLocalizations.inputsOf(context).selectSms; case InputField.selectTotp: return AuthenticatorLocalizations.inputsOf(context).selectTotp; + case InputField.selectEmail: + return AuthenticatorLocalizations.inputsOf(context).selectEmail; case InputField.totpCodePrompt: return AuthenticatorLocalizations.inputsOf(context).totpCodePrompt; case InputField.usernameType: From c1d33e3ed83c407331594ce69c9322f1c1ee1301 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:47:32 -0700 Subject: [PATCH 014/159] chore: edit doc comment in auth_plugin_impl --- .../amplify_auth_cognito_dart/lib/src/auth_plugin_impl.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 f080f48fc2..02b5a8e2df 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 @@ -885,8 +885,8 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface /// {@template amplify_core.amplify_auth_category.update_mfa_preference} /// Updates the MFA preference for the current user. /// - /// If [sms] or [totp] is `null`, the preference for that MFA type is left - /// unchanged. Setting either [sms] or [totp] to [MfaPreference.preferred] + /// If [sms], [totp], or [email] is `null`, the preference for that MFA type is left + /// unchanged. Setting either [sms], [totp], or [email] to [MfaPreference.preferred] /// will mark the other as not preferred. /// {@endtemplate} Future updateMfaPreference({ From 18a531669533d484f3c09efdac6aad6f9560b683 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:52:31 -0700 Subject: [PATCH 015/159] chore: add emailMfaSettings to setMfaSettings --- .../auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index ec6a73d46c..b65f5d3dfc 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -886,6 +886,7 @@ extension MfaSettings on CognitoIdentityProviderClient { accessToken: accessToken, smsMfaSettings: smsMfaSettings, softwareTokenMfaSettings: softwareTokenSettings, + emailMfaSettings: emailMfaSettings, ), ).result; } From d484c55a713bceaff89e682585667dcd042d1282 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:40:31 -0700 Subject: [PATCH 016/159] chore: formatting --- .../lib/src/sdk/sdk_bridge.dart | 34 +++++++++++++++---- .../state/machines/sign_in_state_machine.dart | 3 +- .../l10n/generated/input_localizations.dart | 2 +- .../email_or_phone_config.dart | 2 +- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index b65f5d3dfc..f183fd1914 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -33,7 +33,8 @@ extension ChallengeNameTypeBridge on ChallengeNameType { ChallengeNameType.softwareTokenMfa => AuthSignInStep.confirmSignInWithTotpMfaCode, // TODO(khatruong2009): confirm ChallengeNameType.emailMfa is added to SDK - ChallengeNameType.emailOtp => AuthSignInStep.confirmSignInWithEmailMfaCode, + ChallengeNameType.emailOtp => + AuthSignInStep.confirmSignInWithEmailMfaCode, ChallengeNameType.adminNoSrpAuth || ChallengeNameType.passwordVerifier || ChallengeNameType.devicePasswordVerifier || @@ -828,19 +829,40 @@ extension MfaSettings on CognitoIdentityProviderClient { return currentlyEnabled || requestingEnabled; } - final preferred = switch ((currentPreference, sms: sms, totp: totp, email: email)) { + final preferred = + switch ((currentPreference, sms: sms, totp: totp, email: email)) { // Prevent an invalid choice. - (_, sms: MfaPreference.preferred, totp: MfaPreference.preferred, email: MfaPreference.preferred) => + ( + _, + sms: MfaPreference.preferred, + totp: MfaPreference.preferred, + email: MfaPreference.preferred + ) => throw const InvalidParameterException( 'Cannot assign multiple MFA methods as preferred', ), // Setting one or the other as preferred overrides previous value. - (_, sms: MfaPreference.preferred, totp: != MfaPreference.preferred, email: != MfaPreference.preferred) => + ( + _, + sms: MfaPreference.preferred, + totp: != MfaPreference.preferred, + email: != MfaPreference.preferred + ) => MfaType.sms, - (_, sms: != MfaPreference.preferred, totp: MfaPreference.preferred, email: != MfaPreference.preferred) => + ( + _, + sms: != MfaPreference.preferred, + totp: MfaPreference.preferred, + email: != MfaPreference.preferred + ) => MfaType.totp, - (_, sms: != MfaPreference.preferred, totp: != MfaPreference.preferred, email: MfaPreference.preferred) => + ( + _, + sms: != MfaPreference.preferred, + totp: != MfaPreference.preferred, + email: MfaPreference.preferred + ) => MfaType.email, // Setting one or the other as disabled or not preferred removes current diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 4dbc775736..7794b48c15 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -956,7 +956,8 @@ final class SignInStateMachine accessToken: accessToken, sms: enableMfaType == MfaType.sms ? MfaPreference.enabled : null, totp: enableMfaType == MfaType.totp ? MfaPreference.enabled : null, - email: enableMfaType == MfaType.email ? MfaPreference.enabled : null, + email: + enableMfaType == MfaType.email ? MfaPreference.enabled : null, ); } on Exception catch (e, st) { logger.error( diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations.dart index c86a8a9ed4..b34f12cf8e 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations.dart @@ -298,7 +298,7 @@ abstract class AuthenticatorInputLocalizations { String get selectTotp; /// Label for the radio button to select email as the user's chosen MFA method. - /// + /// /// In en, this message translates to: /// **'Email'** String get selectEmail; diff --git a/packages/authenticator/amplify_authenticator_test/lib/src/amplify_outputs/email_or_phone_config.dart b/packages/authenticator/amplify_authenticator_test/lib/src/amplify_outputs/email_or_phone_config.dart index ad5ef29355..a7cc4c93ac 100644 --- a/packages/authenticator/amplify_authenticator_test/lib/src/amplify_outputs/email_or_phone_config.dart +++ b/packages/authenticator/amplify_authenticator_test/lib/src/amplify_outputs/email_or_phone_config.dart @@ -29,4 +29,4 @@ const emailOrPhoneConfig = '''{ "SMS" ] } -}'''; \ No newline at end of file +}'''; From f604447dffd7c747c5bbebca38c8e6ed57b59a96 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:41:16 -0700 Subject: [PATCH 017/159] chore: update docs comment in constants --- .../auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart index 536c33c529..7a40ff446c 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart @@ -57,7 +57,7 @@ abstract class CognitoConstants { /// The `SMS_MFA_CODE` parameter. static const challengeParamSmsMfaCode = 'SMS_MFA_CODE'; - /// The `EMAIL_MFA_CODE` parameter. + /// The `EMAIL_OTP_CODE` parameter. static const challengeParamEmailMfaCode = 'EMAIL_OTP_CODE'; /// The `SOFTWARE_TOKEN_MFA_CODE` parameter. From b0c03b79a0fb9af10d25c31ee732a276d41a1fb1 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:42:46 -0700 Subject: [PATCH 018/159] chore: add docs and formatting --- packages/amplify_core/doc/lib/auth.dart | 7 ++++++- .../lib/src/types/auth/sign_in/auth_sign_in_step.dart | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/amplify_core/doc/lib/auth.dart b/packages/amplify_core/doc/lib/auth.dart index 6e48014a9b..d7a0fd803b 100644 --- a/packages/amplify_core/doc/lib/auth.dart +++ b/packages/amplify_core/doc/lib/auth.dart @@ -104,7 +104,7 @@ Future resendSignUpCode(String username) async { } // #enddocregion resend-signup-code -// #docregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code +// #docregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code, handle-confirm-signin-email Future _handleSignInResult(SignInResult result) async { switch (result.nextStep.signInStep) { // #enddocregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code @@ -129,6 +129,11 @@ Future _handleSignInResult(SignInResult result) async { final codeDeliveryDetails = result.nextStep.codeDeliveryDetails!; _handleCodeDelivery(codeDeliveryDetails); // #enddocregion handle-confirm-signin-sms + // #docregion handle-confirm-signin-email + case AuthSignInStep.confirmSignInWithEmailMfaCode: + final codeDeliveryDetails = result.nextStep.codeDeliveryDetails!; + _handleCodeDelivery(codeDeliveryDetails); + // #enddocregion handle-confirm-signin-email // #docregion handle-confirm-signin-new-password case AuthSignInStep.confirmSignInWithNewPassword: safePrint('Enter a new password to continue signing in'); diff --git a/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart b/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart index 9631ca1d94..eef001a650 100644 --- a/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart +++ b/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart @@ -10,7 +10,7 @@ enum AuthSignInStep { /// an MFA method. continueSignInWithMfaSelection, - /// The sign-in is not complete and the user must select an MFA method to setup. + /// The sign-in is not complete and the user must select an MFA method to setup. continueSignInWithMfaSetupSelection, /// The sign-in is not complete and a TOTP authenticator app must be From 515368315eb444e77a5a1bb37a1b244e0ed8446a Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:05:01 -0700 Subject: [PATCH 019/159] chore: revert package-lock.json changes --- infra-gen2/package-lock.json | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/infra-gen2/package-lock.json b/infra-gen2/package-lock.json index 191c337b64..806c800dd6 100644 --- a/infra-gen2/package-lock.json +++ b/infra-gen2/package-lock.json @@ -4462,18 +4462,6 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.624.0", - "@aws-sdk/client-sts": "3.624.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-sdk-ec2": "3.622.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", @@ -4486,27 +4474,9 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { @@ -4622,8 +4592,6 @@ "license": "Apache-2.0", "dependencies": { "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { @@ -4638,7 +4606,6 @@ "dependencies": { "@smithy/eventstream-serde-universal": "^3.0.5", "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" }, "engines": { From 1d37caec6868c93b0064a886975e18334d7f0fd2 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:14:17 -0700 Subject: [PATCH 020/159] chore: update mfaSetup to MfaSetupSelection --- .../auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index f183fd1914..171c2feac3 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -29,10 +29,9 @@ extension ChallengeNameTypeBridge on ChallengeNameType { ChallengeNameType.selectMfaType => AuthSignInStep.continueSignInWithMfaSelection, ChallengeNameType.mfaSetup => - AuthSignInStep.continueSignInWithTotpSetup, + AuthSignInStep.continueSignInWithMfaSetupSelection, ChallengeNameType.softwareTokenMfa => AuthSignInStep.confirmSignInWithTotpMfaCode, - // TODO(khatruong2009): confirm ChallengeNameType.emailMfa is added to SDK ChallengeNameType.emailOtp => AuthSignInStep.confirmSignInWithEmailMfaCode, ChallengeNameType.adminNoSrpAuth || From e69d96bb657c48989dacd952d233232726693804 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:16:29 -0700 Subject: [PATCH 021/159] chore: refactor setMfaSettings method to handle multiple mfa preferred scenarios --- .../lib/src/sdk/sdk_bridge.dart | 193 ++++++++---------- 1 file changed, 81 insertions(+), 112 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index 171c2feac3..a95acbe95b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -794,123 +794,92 @@ extension MfaSettings on CognitoIdentityProviderClient { /// Sets the MFA settings for the user. Future setMfaSettings({ - required String accessToken, - MfaPreference? sms, - MfaPreference? totp, - MfaPreference? email, - }) async { - final UserMfaPreference( - enabled: currentEnabled, - preferred: currentPreference - ) = await _getRawUserSettings( - accessToken: accessToken, - ); - const enabledValues = [ - MfaPreference.enabled, - MfaPreference.notPreferred, - MfaPreference.preferred, - ]; - bool isEnabled(MfaType mfaType) { - final explicitlyDisabled = switch (mfaType) { - MfaType.sms => sms == MfaPreference.disabled, - MfaType.totp => totp == MfaPreference.disabled, - MfaType.email => email == MfaPreference.disabled, - }; - if (explicitlyDisabled) { - return false; - } - final currentlyEnabled = currentEnabled.contains(mfaType); - final requestingEnabled = switch (mfaType) { - MfaType.sms => enabledValues.contains(sms), - MfaType.totp => enabledValues.contains(totp), - MfaType.email => enabledValues.contains(email), - }; - return currentlyEnabled || requestingEnabled; + required String accessToken, + MfaPreference? sms, + MfaPreference? totp, + MfaPreference? email, +}) async { + final UserMfaPreference( + enabled: currentEnabled, + preferred: currentPreference + ) = await _getRawUserSettings( + accessToken: accessToken, + ); + + const enabledValues = [ + MfaPreference.enabled, + MfaPreference.notPreferred, + MfaPreference.preferred, + ]; + + bool isEnabled(MfaType mfaType) { + final explicitlyDisabled = switch (mfaType) { + MfaType.sms => sms == MfaPreference.disabled, + MfaType.totp => totp == MfaPreference.disabled, + MfaType.email => email == MfaPreference.disabled, + }; + if (explicitlyDisabled) { + return false; } + final currentlyEnabled = currentEnabled.contains(mfaType); + final requestingEnabled = switch (mfaType) { + MfaType.sms => enabledValues.contains(sms), + MfaType.totp => enabledValues.contains(totp), + MfaType.email => enabledValues.contains(email), + }; + return currentlyEnabled || requestingEnabled; + } - final preferred = - switch ((currentPreference, sms: sms, totp: totp, email: email)) { - // Prevent an invalid choice. - ( - _, - sms: MfaPreference.preferred, - totp: MfaPreference.preferred, - email: MfaPreference.preferred - ) => - throw const InvalidParameterException( - 'Cannot assign multiple MFA methods as preferred', - ), + // Count the number of MFA methods set to preferred + final preferredMethods = [ + if (sms == MfaPreference.preferred) MfaType.sms, + if (totp == MfaPreference.preferred) MfaType.totp, + if (email == MfaPreference.preferred) MfaType.email, + ]; - // Setting one or the other as preferred overrides previous value. - ( - _, - sms: MfaPreference.preferred, - totp: != MfaPreference.preferred, - email: != MfaPreference.preferred - ) => - MfaType.sms, - ( - _, - sms: != MfaPreference.preferred, - totp: MfaPreference.preferred, - email: != MfaPreference.preferred - ) => - MfaType.totp, - ( - _, - sms: != MfaPreference.preferred, - totp: != MfaPreference.preferred, - email: MfaPreference.preferred - ) => - MfaType.email, - - // Setting one or the other as disabled or not preferred removes current - // preference if it matches. - ( - MfaType.sms, - sms: MfaPreference.notPreferred || MfaPreference.disabled, - totp: _, - email: _, - ) || - ( - MfaType.totp, - sms: _, - totp: MfaPreference.notPreferred || MfaPreference.disabled, - email: _, - ) || - ( - MfaType.email, - sms: _, - totp: _, - email: MfaPreference.notPreferred || MfaPreference.disabled, - ) => - null, - - // Ignore preference changes which do not affect the current preference. - (final currentPreference, sms: _, totp: _, email: _) => currentPreference, + if (preferredMethods.length > 1) { + throw const InvalidParameterException( + 'Cannot assign multiple MFA methods as preferred', + ); + } + + MfaType? preferred; + if (preferredMethods.isNotEmpty) { + preferred = preferredMethods.first; + } else { + // Check if the current preference needs to be removed + final isCurrentPreferenceDisabled = switch (currentPreference) { + MfaType.sms => sms == MfaPreference.disabled || sms == MfaPreference.notPreferred, + MfaType.totp => totp == MfaPreference.disabled || totp == MfaPreference.notPreferred, + MfaType.email => email == MfaPreference.disabled || email == MfaPreference.notPreferred, + _ => false, }; - final smsMfaSettings = SmsMfaSettingsType( - enabled: isEnabled(MfaType.sms), - preferredMfa: preferred == MfaType.sms, - ); - final softwareTokenSettings = SoftwareTokenMfaSettingsType( - enabled: isEnabled(MfaType.totp), - preferredMfa: preferred == MfaType.totp, - ); - // TODO(khatruong2009): confirm EmailMfaSettingsType is added to SDK - final emailMfaSettings = EmailMfaSettingsType( - enabled: isEnabled(MfaType.email), - preferredMfa: preferred == MfaType.email, - ); - await setUserMfaPreference( - SetUserMfaPreferenceRequest( - accessToken: accessToken, - smsMfaSettings: smsMfaSettings, - softwareTokenMfaSettings: softwareTokenSettings, - emailMfaSettings: emailMfaSettings, - ), - ).result; + preferred = isCurrentPreferenceDisabled ? null : currentPreference; } + + final smsMfaSettings = SmsMfaSettingsType( + enabled: isEnabled(MfaType.sms), + preferredMfa: preferred == MfaType.sms, + ); + final softwareTokenSettings = SoftwareTokenMfaSettingsType( + enabled: isEnabled(MfaType.totp), + preferredMfa: preferred == MfaType.totp, + ); + final emailMfaSettings = EmailMfaSettingsType( + enabled: isEnabled(MfaType.email), + preferredMfa: preferred == MfaType.email, + ); + + await setUserMfaPreference( + SetUserMfaPreferenceRequest( + accessToken: accessToken, + smsMfaSettings: smsMfaSettings, + softwareTokenMfaSettings: softwareTokenSettings, + emailMfaSettings: emailMfaSettings, + ), + ).result; +} + } extension on String { From 764f16d4ec6a0f4b2e396159f1bdf2692fa11440 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:49:08 -0700 Subject: [PATCH 022/159] chore: fix mfaType switch statement to reflect new name --- .../auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index a95acbe95b..db8e3c856f 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -887,7 +887,7 @@ extension on String { MfaType get mfaType => switch (this) { 'SOFTWARE_TOKEN_MFA' => MfaType.totp, 'SMS_MFA' => MfaType.sms, - 'EMAIL_MFA' => MfaType.email, + 'EMAIL_OTP' => MfaType.email, final invalidType => throw StateError('Invalid MFA type: $invalidType'), }; } From 26bececf5457135fc2120e7b07e86ea7611cb1b5 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:39:48 -0700 Subject: [PATCH 023/159] chore: refactor setMfaSettings method --- .../lib/src/sdk/sdk_bridge.dart | 141 ++++++++---------- 1 file changed, 63 insertions(+), 78 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index db8e3c856f..8ea47761ed 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -794,92 +794,77 @@ extension MfaSettings on CognitoIdentityProviderClient { /// Sets the MFA settings for the user. Future setMfaSettings({ - required String accessToken, - MfaPreference? sms, - MfaPreference? totp, - MfaPreference? email, -}) async { - final UserMfaPreference( - enabled: currentEnabled, - preferred: currentPreference - ) = await _getRawUserSettings( - accessToken: accessToken, - ); - - const enabledValues = [ - MfaPreference.enabled, - MfaPreference.notPreferred, - MfaPreference.preferred, - ]; - - bool isEnabled(MfaType mfaType) { - final explicitlyDisabled = switch (mfaType) { - MfaType.sms => sms == MfaPreference.disabled, - MfaType.totp => totp == MfaPreference.disabled, - MfaType.email => email == MfaPreference.disabled, - }; - if (explicitlyDisabled) { - return false; + required String accessToken, + MfaPreference? sms, + MfaPreference? totp, + MfaPreference? email, + }) async { + final UserMfaPreference( + enabled: currentEnabled, + preferred: currentPreference, + ) = await _getRawUserSettings(accessToken: accessToken); + + final newPreferredMethods = [ + if (sms == MfaPreference.preferred) MfaType.sms, + if (totp == MfaPreference.preferred) MfaType.totp, + if (email == MfaPreference.preferred) MfaType.email, + ]; + + if (newPreferredMethods.length > 1) { + throw const InvalidParameterException( + 'Cannot assign multiple MFA methods as preferred', + ); } - final currentlyEnabled = currentEnabled.contains(mfaType); - final requestingEnabled = switch (mfaType) { - MfaType.sms => enabledValues.contains(sms), - MfaType.totp => enabledValues.contains(totp), - MfaType.email => enabledValues.contains(email), - }; - return currentlyEnabled || requestingEnabled; - } - // Count the number of MFA methods set to preferred - final preferredMethods = [ - if (sms == MfaPreference.preferred) MfaType.sms, - if (totp == MfaPreference.preferred) MfaType.totp, - if (email == MfaPreference.preferred) MfaType.email, - ]; + var preferred = newPreferredMethods.isNotEmpty + ? newPreferredMethods.first + : currentPreference; - if (preferredMethods.length > 1) { - throw const InvalidParameterException( - 'Cannot assign multiple MFA methods as preferred', - ); - } - - MfaType? preferred; - if (preferredMethods.isNotEmpty) { - preferred = preferredMethods.first; - } else { - // Check if the current preference needs to be removed final isCurrentPreferenceDisabled = switch (currentPreference) { - MfaType.sms => sms == MfaPreference.disabled || sms == MfaPreference.notPreferred, - MfaType.totp => totp == MfaPreference.disabled || totp == MfaPreference.notPreferred, - MfaType.email => email == MfaPreference.disabled || email == MfaPreference.notPreferred, + MfaType.sms => + sms == MfaPreference.disabled || sms == MfaPreference.notPreferred, + MfaType.totp => + totp == MfaPreference.disabled || totp == MfaPreference.notPreferred, + MfaType.email => + email == MfaPreference.disabled || email == MfaPreference.notPreferred, _ => false, }; - preferred = isCurrentPreferenceDisabled ? null : currentPreference; - } + preferred = isCurrentPreferenceDisabled ? null : preferred; + + const enabledValues = [ + MfaPreference.enabled, + MfaPreference.notPreferred, + MfaPreference.preferred, + ]; + + bool isMfaEnabled(MfaType mfaType, MfaPreference? preference) { + if (preference == MfaPreference.disabled) return false; + return currentEnabled.contains(mfaType) || + enabledValues.contains(preference); + } - final smsMfaSettings = SmsMfaSettingsType( - enabled: isEnabled(MfaType.sms), - preferredMfa: preferred == MfaType.sms, - ); - final softwareTokenSettings = SoftwareTokenMfaSettingsType( - enabled: isEnabled(MfaType.totp), - preferredMfa: preferred == MfaType.totp, - ); - final emailMfaSettings = EmailMfaSettingsType( - enabled: isEnabled(MfaType.email), - preferredMfa: preferred == MfaType.email, - ); - - await setUserMfaPreference( - SetUserMfaPreferenceRequest( - accessToken: accessToken, - smsMfaSettings: smsMfaSettings, - softwareTokenMfaSettings: softwareTokenSettings, - emailMfaSettings: emailMfaSettings, - ), - ).result; -} + final smsMfaSettings = SmsMfaSettingsType( + enabled: isMfaEnabled(MfaType.sms, sms), + preferredMfa: preferred == MfaType.sms, + ); + final softwareTokenSettings = SoftwareTokenMfaSettingsType( + enabled: isMfaEnabled(MfaType.totp, totp), + preferredMfa: preferred == MfaType.totp, + ); + final emailMfaSettings = EmailMfaSettingsType( + enabled: isMfaEnabled(MfaType.email, email), + preferredMfa: preferred == MfaType.email, + ); + await setUserMfaPreference( + SetUserMfaPreferenceRequest( + accessToken: accessToken, + smsMfaSettings: smsMfaSettings, + softwareTokenMfaSettings: softwareTokenSettings, + emailMfaSettings: emailMfaSettings, + ), + ).result; + } } extension on String { From 86a322877de0a91627fe49ecfcedd649e61a227d Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:50:52 -0700 Subject: [PATCH 024/159] chore: mark sdk_exception file as generated --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 3fcc994970..ab23572ce9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -74,6 +74,7 @@ ## Generated SDK files packages/**/lib/src/sdk/src/** linguist-generated +packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_exception.dart linguist-generated ## Generated Swift Plugins packages/amplify_datastore/ios/internal/** linguist-generated From 13e60c4f4f5d718ff9502a3a96ef30c316a867fe Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 20 Sep 2024 10:47:39 -0700 Subject: [PATCH 025/159] chore: update core docs --- packages/amplify_core/doc/lib/auth.dart | 31 +++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/amplify_core/doc/lib/auth.dart b/packages/amplify_core/doc/lib/auth.dart index d7a0fd803b..384845b9c2 100644 --- a/packages/amplify_core/doc/lib/auth.dart +++ b/packages/amplify_core/doc/lib/auth.dart @@ -104,22 +104,32 @@ Future resendSignUpCode(String username) async { } // #enddocregion resend-signup-code -// #docregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code, handle-confirm-signin-email +// #docregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code, handle-confirm-signin-email-code, handle-confirm-signin-mfa-setup-selection, handle-confirm-signin-email-setup Future _handleSignInResult(SignInResult result) async { switch (result.nextStep.signInStep) { - // #enddocregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code + // #enddocregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-email-code, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code, handle-confirm-signin-mfa-setup-selection, handle-confirm-signin-email-setup // #docregion handle-confirm-signin-mfa-selection case AuthSignInStep.continueSignInWithMfaSelection: final allowedMfaTypes = result.nextStep.allowedMfaTypes!; final selection = await _promptUserPreference(allowedMfaTypes); return _handleMfaSelection(selection); // #enddocregion handle-confirm-signin-mfa-selection + // #docregion handle-confirm-signin-mfa-setup-selection + case AuthSignInStep.continueSignInWithMfaSetupSelection: + final allowedMfaTypes = result.nextStep.allowedMfaTypes!; + final selection = await _promptUserPreference(allowedMfaTypes); + return _handleMfaSetupSelection(selection); + // #enddocregion handle-confirm-signin-mfa-setup-selection // #docregion handle-confirm-signin-totp-setup case AuthSignInStep.continueSignInWithTotpSetup: final totpSetupDetails = result.nextStep.totpSetupDetails!; final setupUri = totpSetupDetails.getSetupUri(appName: 'MyApp'); safePrint('Open URI to complete setup: $setupUri'); // #enddocregion handle-confirm-signin-totp-setup + // #docregion handle-confirm-signin-email-setup + case AuthSignInStep.continueSignInWithEmailMfaSetup: + safePrint('A confirmation code has been sent to your email'); + // #enddocregion handle-confirm-signin-email-setup // #docregion handle-confirm-signin-totp-code case AuthSignInStep.confirmSignInWithTotpMfaCode: safePrint('Enter a one-time code from your registered Authenticator app'); @@ -163,10 +173,10 @@ Future _handleSignInResult(SignInResult result) async { case AuthSignInStep.done: safePrint('Sign in is complete'); // #enddocregion handle-confirm-signin-done - // #docregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code + // #docregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code, handle-confirm-signin-email-code, handle-confirm-signin-mfa-setup-selection, handle-confirm-signin-email-setup } } -// #enddocregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code +// #enddocregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code, handle-confirm-signin-email-code, handle-confirm-signin-mfa-setup-selection, handle-confirm-signin-email-setup // #docregion signin Future signInUser(String username, String password) async { @@ -241,6 +251,19 @@ Future _handleMfaSelection(MfaType selection) async { } // #enddocregion handle-mfa-selection +// #docregion handle-mfa-setup-selection +Future _handleMfaSetupSelection(MfaType selection) async { + try { + final result = await Amplify.Auth.confirmSignIn( + confirmationValue: selection.confirmationValue, + ); + return _handleSignInResult(result); + } on AuthException catch (e) { + safePrint('Error resending code: ${e.message}'); + } +} +// #enddocregion handle-mfa-setup-selection + // #docregion signout Future signOutCurrentUser() async { final result = await Amplify.Auth.signOut(); From 0d725dc204d945e6150e75d38f3657776ecde27e Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:38:35 -0700 Subject: [PATCH 026/159] chore: update integ tests Update integ tests to change expected state from continueSignInWithTotpSetup to continueSignInWithMfaSetupSelection --- .../example/integration_test/mfa_sms_totp_required_test.dart | 2 +- .../example/integration_test/mfa_totp_required_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_totp_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_totp_required_test.dart index 32862bf0bb..2f5c1422e3 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_totp_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_totp_required_test.dart @@ -35,7 +35,7 @@ void main() { signInRes.nextStep.signInStep, because: 'MFA is required, and TOTP is chosen when ' 'no phone number is registered', - ).equals(AuthSignInStep.continueSignInWithTotpSetup); + ).equals(AuthSignInStep.continueSignInWithMfaSetupSelection); final sharedSecret = signInRes.nextStep.totpSetupDetails!.sharedSecret; final setupRes = await Amplify.Auth.confirmSignIn( diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_totp_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_totp_required_test.dart index 84370b665c..323700b9f6 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_totp_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_totp_required_test.dart @@ -34,7 +34,7 @@ void main() { signInRes.nextStep.signInStep, because: "TOTP MFA is automatically enabled when it's the only option", - ).equals(AuthSignInStep.continueSignInWithTotpSetup); + ).equals(AuthSignInStep.continueSignInWithMfaSetupSelection); final sharedSecret = signInRes.nextStep.totpSetupDetails!.sharedSecret; final setupRes = await Amplify.Auth.confirmSignIn( From 69abe75023998122a5286c2e868e9a20b128b80f Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 4 Oct 2024 12:52:32 -0700 Subject: [PATCH 027/159] chore: update core docs example --- packages/amplify_core/doc/lib/auth.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/amplify_core/doc/lib/auth.dart b/packages/amplify_core/doc/lib/auth.dart index 384845b9c2..6364ceb84a 100644 --- a/packages/amplify_core/doc/lib/auth.dart +++ b/packages/amplify_core/doc/lib/auth.dart @@ -117,6 +117,9 @@ Future _handleSignInResult(SignInResult result) async { // #docregion handle-confirm-signin-mfa-setup-selection case AuthSignInStep.continueSignInWithMfaSetupSelection: final allowedMfaTypes = result.nextStep.allowedMfaTypes!; + if (allowedMfaTypes.length == 1) { + return _handleMfaSetupSelection(allowedMfaTypes.first); + } final selection = await _promptUserPreference(allowedMfaTypes); return _handleMfaSetupSelection(selection); // #enddocregion handle-confirm-signin-mfa-setup-selection From 970bf15dd1df3b1ce8b40ccfb1a9e7bae8b75394 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:00:06 -0700 Subject: [PATCH 028/159] chore: add authenticator state/step enums --- .../lib/src/enums/authenticator_step.dart | 11 ++++++++++ .../lib/src/state/auth_state.dart | 21 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/enums/authenticator_step.dart b/packages/authenticator/amplify_authenticator/lib/src/enums/authenticator_step.dart index a90f0f8b0a..5ef325081a 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/enums/authenticator_step.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/enums/authenticator_step.dart @@ -61,18 +61,29 @@ enum AuthenticatorStep { /// an MFA method. continueSignInWithMfaSelection, + /// The user is on the Continue Sign In with MFA Setup Selection step. + /// The sign-in is not complete and the user must select an MFA method to setup. + continueSignInWithMfaSetupSelection, + /// The user is on the Continue Sign In with TOTP setup step. /// /// The sign-in is not complete and a TOTP authenticator app must be /// registered before continuing. continueSignInWithTotpSetup, + /// The sign-in is not complete and an Email MFA must be set up before + /// continuing. + continueSignInWithEmailMfaSetup, + /// The user is on the Confirm Sign In with TOTP MFA step. /// /// The sign-in is not complete and must be confirmed with a TOTP code /// from a registered authenticator app. confirmSignInWithTotpMfaCode, + /// The sign-in is not complete and must be confirmed with an email code. + confirmSignInWithEmailMfaCode, + /// The user is on the Reset Password step. resetPassword, diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/auth_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/auth_state.dart index 5a948e05bf..834afbe683 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/auth_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/auth_state.dart @@ -46,6 +46,12 @@ class UnauthenticatedState extends AuthState static const confirmSignInWithTotpMfaCode = UnauthenticatedState( step: AuthenticatorStep.confirmSignInWithTotpMfaCode, ); + static const continueSignInWithEmailMfaSetup = UnauthenticatedState( + step: AuthenticatorStep.continueSignInWithEmailMfaSetup, + ); + static const confirmSignInWithEmailMfaCode = UnauthenticatedState( + step: AuthenticatorStep.confirmSignInWithEmailMfaCode, + ); static const resetPassword = UnauthenticatedState(step: AuthenticatorStep.resetPassword); static const confirmResetPassword = @@ -111,6 +117,21 @@ class ContinueSignInWithMfaSelection extends UnauthenticatedState { String get runtimeTypeName => 'ContinueSignInWithMfaSelection'; } +class ContinueSignInWithMfaSetupSelection extends UnauthenticatedState { + const ContinueSignInWithMfaSetupSelection({ + Set? allowedMfaTypes, + }) : allowedMfaTypes = allowedMfaTypes ?? const {}, + super(step: AuthenticatorStep.continueSignInWithMfaSetupSelection); + + final Set allowedMfaTypes; + + @override + List get props => [step, allowedMfaTypes]; + + @override + String get runtimeTypeName => 'ContinueSignInWithMfaSetupSelection'; +} + class ContinueSignInTotpSetup extends UnauthenticatedState { const ContinueSignInTotpSetup(this.totpSetupDetails, this.totpSetupUri) : super(step: AuthenticatorStep.continueSignInWithTotpSetup); From 5586c16043a67a1d2de1e7bf43d72ce1c4fb035a Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:01:09 -0700 Subject: [PATCH 029/159] chore: change state machine and auth bloc to automatically move states if only one mfa method is allowed --- .../state/machines/sign_in_state_machine.dart | 70 ++++++++++++++++++- .../lib/src/blocs/auth/auth_bloc.dart | 48 +++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 7794b48c15..03fc0c3edb 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -330,8 +330,56 @@ final class SignInStateMachine createEmailMfaRequest(event), ChallengeNameType.selectMfaType when hasUserResponse => createSelectMfaRequest(event), - ChallengeNameType.mfaSetup when hasUserResponse => - createMfaSetupRequest(event), + ChallengeNameType.mfaSetup => + (() async { + final allowedMfaTypes = _allowedMfaTypes; + if (allowedMfaTypes == null || allowedMfaTypes.isEmpty) { + throw const InvalidUserPoolConfigurationException( + 'No MFA types are allowed for setup.', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + // Exclude MfaType.sms from consideration + final mfaTypesForSetup = allowedMfaTypes.difference({MfaType.sms}); + if (mfaTypesForSetup.isEmpty) { + throw const InvalidUserPoolConfigurationException( + 'No eligible MFA types are available for setup.', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + if (mfaTypesForSetup.length == 1) { + final mfaType = mfaTypesForSetup.first; + if (mfaType == MfaType.totp) { + _enableMfaType = MfaType.totp; + _totpSetupResult ??= await associateSoftwareToken(); + if (hasUserResponse) { + return createMfaSetupRequest(event); + } else { + // Need to prompt user for the TOTP code + return null; + } + } else if (mfaType == MfaType.email) { + _enableMfaType = MfaType.email; + if (hasUserResponse) { + return createEmailMfaSetupRequest(event); + } else { + // Need to prompt user for the email verification code + return null; + } + } else { + throw InvalidUserPoolConfigurationException( + 'Unsupported MFA type: ${mfaType.name}', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + } else if (hasUserResponse) { + // Handle user's selection + return createMfaSetupRequest(event); + } else { + // Need to prompt user to select an MFA type + return null; + } + })(), ChallengeNameType.newPasswordRequired when hasUserResponse => createNewPasswordRequest(event), _ => null, @@ -674,6 +722,24 @@ final class SignInStateMachine }); } + /// Compeletes set up of an email MFA. + @protected + Future createEmailMfaSetupRequest( + SignInRespondToChallenge event, + ) async { + _enableMfaType = MfaType.email; + return RespondToAuthChallengeRequest.build((b) { + b + ..challengeName = ChallengeNameType.emailOtp + ..challengeResponses.addAll({ + CognitoConstants.challengeParamUsername: cognitoUsername, + CognitoConstants.challengeParamEmailMfaCode: event.answer, + }) + ..clientId = _authOutputs.userPoolClientId + ..clientMetadata.addAll(event.clientMetadata); + }); + } + /// Selects an MFA type to use for sign-in. @protected Future createSelectMfaRequest( diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 4c729b9078..41dcfe410e 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -227,10 +227,16 @@ class StateMachineBloc yield UnauthenticatedState.confirmSignInNewPassword; case AuthSignInStep.confirmSignInWithTotpMfaCode: yield UnauthenticatedState.confirmSignInWithTotpMfaCode; + case AuthSignInStep.confirmSignInWithEmailMfaCode: + yield UnauthenticatedState.confirmSignInWithEmailMfaCode; case AuthSignInStep.continueSignInWithMfaSelection: yield ContinueSignInWithMfaSelection( allowedMfaTypes: result.nextStep.allowedMfaTypes, ); + case AuthSignInStep.continueSignInWithMfaSetupSelection: + yield ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: result.nextStep.allowedMfaTypes, + ); case AuthSignInStep.continueSignInWithTotpSetup: assert( result.nextStep.totpSetupDetails != null, @@ -333,6 +339,43 @@ class StateMachineBloc allowedMfaTypes: result.nextStep.allowedMfaTypes, ), ); + case AuthSignInStep.continueSignInWithMfaSetupSelection: + final allowedMfaTypes = result.nextStep.allowedMfaTypes; + if (allowedMfaTypes != null) { + final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); + if (mfaTypesForSetup.length == 1) { + final mfaType = mfaTypesForSetup.first; + if (mfaType == MfaType.totp) { + assert( + result.nextStep.totpSetupDetails != null, + 'Sign In Result should have totpSetupDetails', + ); + _emit(await ContinueSignInTotpSetup.setupURI( + result.nextStep.totpSetupDetails!, + totpOptions, + ),); + } else if (mfaType == MfaType.email) { + _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); + } else { + throw InvalidUserPoolConfigurationException( + 'Unsupported MFA type: ${mfaType.name}', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + } else { + _emit( + ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: result.nextStep.allowedMfaTypes, + ), + ); + } + } else { + _emit( + ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: result.nextStep.allowedMfaTypes, + ), + ); + } case AuthSignInStep.continueSignInWithTotpSetup: assert( result.nextStep.totpSetupDetails != null, @@ -344,8 +387,13 @@ class StateMachineBloc totpOptions, ), ); + case AuthSignInStep.continueSignInWithEmailMfaSetup: + _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); case AuthSignInStep.confirmSignInWithTotpMfaCode: _emit(UnauthenticatedState.confirmSignInWithTotpMfaCode); + case AuthSignInStep.confirmSignInWithEmailMfaCode: + _notifyCodeSent(result.nextStep.codeDeliveryDetails?.destination); + _emit(UnauthenticatedState.confirmSignInWithEmailMfaCode); case AuthSignInStep.resetPassword: _emit(UnauthenticatedState.confirmResetPassword); case AuthSignInStep.confirmSignUp: From 472507467d8e031c5d87606355d0bddac5e944fe Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:01:26 -0700 Subject: [PATCH 030/159] chore: add email mfa to test_runner --- .../amplify_auth_integration_test/lib/src/test_runner.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/test/amplify_auth_integration_test/lib/src/test_runner.dart b/packages/test/amplify_auth_integration_test/lib/src/test_runner.dart index 1401bc4fd6..9654971cdd 100644 --- a/packages/test/amplify_auth_integration_test/lib/src/test_runner.dart +++ b/packages/test/amplify_auth_integration_test/lib/src/test_runner.dart @@ -145,6 +145,7 @@ class MfaInfo { this.required = false, this.smsEnabled = false, this.totpEnabled = false, + this.emailEnabled = false, }); /// Whether MFA is required (`true`) or optional (`false`). @@ -155,6 +156,9 @@ class MfaInfo { /// Whether TOTP MFA is available. final bool totpEnabled; + + /// Whether email MFA is available. + final bool emailEnabled; } /// A test environment descriptor. From f0b69a392fa98c6c261a408a96fe0a2e14351199 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:58:09 -0700 Subject: [PATCH 031/159] chore: dart format --- .../state/machines/sign_in_state_machine.dart | 91 +++++++++---------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 03fc0c3edb..39c6314a07 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -330,56 +330,55 @@ final class SignInStateMachine createEmailMfaRequest(event), ChallengeNameType.selectMfaType when hasUserResponse => createSelectMfaRequest(event), - ChallengeNameType.mfaSetup => - (() async { - final allowedMfaTypes = _allowedMfaTypes; - if (allowedMfaTypes == null || allowedMfaTypes.isEmpty) { - throw const InvalidUserPoolConfigurationException( - 'No MFA types are allowed for setup.', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - // Exclude MfaType.sms from consideration - final mfaTypesForSetup = allowedMfaTypes.difference({MfaType.sms}); - if (mfaTypesForSetup.isEmpty) { - throw const InvalidUserPoolConfigurationException( - 'No eligible MFA types are available for setup.', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - if (mfaTypesForSetup.length == 1) { - final mfaType = mfaTypesForSetup.first; - if (mfaType == MfaType.totp) { - _enableMfaType = MfaType.totp; - _totpSetupResult ??= await associateSoftwareToken(); - if (hasUserResponse) { - return createMfaSetupRequest(event); - } else { - // Need to prompt user for the TOTP code - return null; - } - } else if (mfaType == MfaType.email) { - _enableMfaType = MfaType.email; - if (hasUserResponse) { - return createEmailMfaSetupRequest(event); + ChallengeNameType.mfaSetup => (() async { + final allowedMfaTypes = _allowedMfaTypes; + if (allowedMfaTypes == null || allowedMfaTypes.isEmpty) { + throw const InvalidUserPoolConfigurationException( + 'No MFA types are allowed for setup.', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + // Exclude MfaType.sms from consideration + final mfaTypesForSetup = allowedMfaTypes.difference({MfaType.sms}); + if (mfaTypesForSetup.isEmpty) { + throw const InvalidUserPoolConfigurationException( + 'No eligible MFA types are available for setup.', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + if (mfaTypesForSetup.length == 1) { + final mfaType = mfaTypesForSetup.first; + if (mfaType == MfaType.totp) { + _enableMfaType = MfaType.totp; + _totpSetupResult ??= await associateSoftwareToken(); + if (hasUserResponse) { + return createMfaSetupRequest(event); + } else { + // Need to prompt user for the TOTP code + return null; + } + } else if (mfaType == MfaType.email) { + _enableMfaType = MfaType.email; + if (hasUserResponse) { + return createEmailMfaSetupRequest(event); + } else { + // Need to prompt user for the email verification code + return null; + } } else { - // Need to prompt user for the email verification code - return null; + throw InvalidUserPoolConfigurationException( + 'Unsupported MFA type: ${mfaType.name}', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); } + } else if (hasUserResponse) { + // Handle user's selection + return createMfaSetupRequest(event); } else { - throw InvalidUserPoolConfigurationException( - 'Unsupported MFA type: ${mfaType.name}', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); + // Need to prompt user to select an MFA type + return null; } - } else if (hasUserResponse) { - // Handle user's selection - return createMfaSetupRequest(event); - } else { - // Need to prompt user to select an MFA type - return null; - } - })(), + })(), ChallengeNameType.newPasswordRequired when hasUserResponse => createNewPasswordRequest(event), _ => null, From afeddae984792eefee194181de972e5304a1d8a9 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 2 Aug 2024 16:33:08 -0700 Subject: [PATCH 032/159] chore: add ChallengeName --- .../model/challenge_name_type.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart index 245f07151e..29df69b192 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart @@ -80,6 +80,12 @@ class ChallengeNameType extends _i1.SmithyEnum { 'SOFTWARE_TOKEN_MFA', ); + static const emailMfa = ChallengeNameType._( + 10, + 'EMAIL_MFA', + 'EMAIL_MFA', + ); + /// All values of [ChallengeNameType]. static const values = [ ChallengeNameType.adminNoSrpAuth, @@ -93,6 +99,7 @@ class ChallengeNameType extends _i1.SmithyEnum { ChallengeNameType.selectMfaType, ChallengeNameType.smsMfa, ChallengeNameType.softwareTokenMfa, + ChallengeNameType.emailMfa, ]; static const List<_i1.SmithySerializer> serializers = [ From 67658ec8e4bb2b71dc07493f35607546fc2a0293 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:46:40 -0700 Subject: [PATCH 033/159] Revert "chore: add ChallengeName" This reverts commit 04fbd0c4ebd073fe291d95abfb5f33aa8bfe1f50. --- .../model/challenge_name_type.dart | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart index 29df69b192..245f07151e 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart @@ -80,12 +80,6 @@ class ChallengeNameType extends _i1.SmithyEnum { 'SOFTWARE_TOKEN_MFA', ); - static const emailMfa = ChallengeNameType._( - 10, - 'EMAIL_MFA', - 'EMAIL_MFA', - ); - /// All values of [ChallengeNameType]. static const values = [ ChallengeNameType.adminNoSrpAuth, @@ -99,7 +93,6 @@ class ChallengeNameType extends _i1.SmithyEnum { ChallengeNameType.selectMfaType, ChallengeNameType.smsMfa, ChallengeNameType.softwareTokenMfa, - ChallengeNameType.emailMfa, ]; static const List<_i1.SmithySerializer> serializers = [ From 4f28b4895fd124e41dfffe894295c4df2b70e0e5 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 12 Sep 2024 16:45:05 -0700 Subject: [PATCH 034/159] chore: merge main (#5449) * chore(api): update endpoint config to use ApiOutputs instead of AWSApiConfig type (#5193) * feat: bump json_annotation dependency to v4.9 * chore: update actions workflow to run aft link * chore(secure_storage): Plugin Endorsement (#5208) * chore(infra): bump deps (#5221) * chore(test): use Amplify Gen 2 config in unit tests (#5205) * chore: add testUrlScheme back to test (#5223) * chore: add gen2 auth e2e infra (#5179) * chore(infra): Api migrate to Gen 2 E2E * fix: git update-index --chmod=+x * fix: code review * chore: port auth backend * chore: port lambda triggers for create user and custom email sender * chore: move utils to infra-common * chore: compile infra common to js * chore: update utils for js restructure, add missing deps * chore: fix confirmation code infra * chore: update tests to run for gen2 stacks * chore: remove alias from custom sender lambda * chore: fix deliveryMedium in reset password test * chore: add phone sign in infra * chore: rename email-sign-in * chore: add license header * chore: fix formatting in GH workflow * chore: update package-lock * chore: remove deleted file * chore: fix formatting * chore: update package lock * chore: remove dup function * chore: remove changes from merge conflicts * chore: fix build script * chore: fetch auth amplify_outputs * chore: remove libgit2dart * chore: add custom sms sender * chore: add stack name to infra resources * chore: pull gen2 backend for authenticator * chore: update package-lock * chore: move dependencies to dev_dependencies * chore: update fetch auth session tests * chore: separate reset pw and confirmation delivery medium * chore: fix hanging test * chore: rename test group * chore: update comments, remove unused type * chore: update package lock --------- Co-authored-by: Elijah Quartey * chore(auth): sign-up state machine to use AmplifyOutputs instead of AmplifyConfig types (#5230) * chore(auth): sign-in state machine to use AmplifyOutputs instead of AmplifyConfig types (#5231) * chore(auth): fetch auth session state machine to use AmplifyOutputs instead of AmplifyConfig types (#5234) * chore(auth): sign-out state machine to use AmplifyOutputs instead of AmplifConfig types (#5235) * chore(actions): android emulator to start with clear cache and data (#5245) * chore(actions): e2e android tests to run with API 34 (#5247) * chore(infra): bump deps (#5246) Updated @aws-sdk/client-amplify @aws-sdk/client-cognito-identity-provider @aws-crypto/client-node @aws-sdk/client-s3 * chore(auth): cognito keys to not use AmplifyConfig types (#5243) * chore(auth): hosted ui state machine to not use AmplifyConfig types (#5254) * fix(datastore): Clear subscriptions on Stop (#5253) * Chore/goldens flutter lint (#5271) * temp: generate goldens png * test: fixing context mounted issue * chore: add todo comment about deprecated member use --------- Co-authored-by: Andrew Hahn * chore(infra): analytics integ test gen 2 backend (#5104) * chore(auth): device metadata repository to use AuthOutputs instead of CognitoUserPoolConfig (#5289) * feat(Auth): Add fetchCurrentDevice API (#5251) feat(Auth): Add fetchCurrentDevice API (#5251) * chore(dependencies): bump package_info_plus (#5274) chore: bump package_info_plus * chore: migrate sms only MFA infra to Gen 2 (#5291) * chore: add new auth backend * chore: add auth extension * chore: add license headers * chore: add mfa to env * chore: add trigger to enable MFA * chore: add infra for sms required * chore: refactor tests for gen 2 backends * chore: add backends to deploy script * chore: package-lock for mfa-required-sms * chore: remove bundling of @aws-crypto/client-node * chore: fix formatting * fix(datastore): Restart Sync Engine when network on/off (#5218) * chore: update authenticator tests (#5296) * chore(auth): hosted ui platforms to use AmplifyOutputs types instead of AmplifyConfig (#5273) * chore(auth): asf context data provider to use AuthOutputs instead of CognitoUserPoolConfig (#5290) * chore(auth): fix fetch current device test (#5297) * fix: push notification flush events (#5215) fix: push notification flush events (#5215) * chore(dependencies): bump build_runner (#5300) * chore(dependencies): bump build_runner * chore(bump): checks package (#5305) * chore(bump): checks package * chore(version): Bump version chore(): Fixed Version Bumps chore: fixed change log chore: fixed change log chore: fixed change log chore: fixed change log * chore: manually bump amplify_db_common version * chore(infra): Extend API key expiration (#5336) * chore(dev): use ubuntu image from amazon ECR public gallery instead of docket hub (#5341) * fix(api): web socket error handling (#5359) * chore: update issue template (#5369) * fix(datastore): FlutterSerializedModel.extractJsonValue returns `.some(nil)` instead of `nil` (#5370) * chore: add GH actions for issue open, close, comment, label events (#5310) * fix(secure_storage): add missing macOS plugin (#5372) fix(secure_storage): add missing macos plugin it's fixing #5361 * chore: update plugin registrant for example apps that depend on secure storage (#5379) * chore(version): Bump version - fix(secure_storage): add missing macOS plugin ([#5372](https://github.com/aws-amplify/amplify-flutter/pull/5372)) Updated-Components: Secure Storage * chore(deps): Amplify Android 2.21.1 (#5376) * update amplify android to latest * update amplify android to latest in notifications * feat(aws_common): Generated new AWSService constructors (#5378) * chore(infra): regen lock file (#5374) * chore(auth): credential store state machine to use AuthOutputs instead of AmplifyConfig types (#5298) * chore(api): Remove Gen 1 API backend (#5393) * chore(datastore): Add multi auth integration tests (#5204) * feat: move App Sync subscription headers to protocol (#5301) * chore: move subscription headers to protocol * fix: remove `=` from encoded headers * chore: add comment * chore: `aft version-bump` test suite (#5424) * chore: add `--skip-build-version` option * chore: use `base-ref`/`head-ref` over env vars * chore: add new version bump test suite * chore: remove old version bump tests * chore: only include first change log entry * fix: sort change types before writing to the change log * chore: remove non essential info from diffs * chore: generate repo snapshot * chore: generate diff snapshots * chore: clean up tests and test output * chore: update `aft generate workflows`, regenerate dependabot.yaml (#5441) * chore: skip repo snapshot in dependabot generation * chore: regenerate dependabot.yaml * chore: fix `aft version-bump` (#5436) * fix: properly handle component propagation * chore: add test for multi package update with breaking common package --------- Co-authored-by: NikaHsn Co-authored-by: Jordan Nelson Co-authored-by: Elijah Quartey Co-authored-by: Elijah Quartey Co-authored-by: Tyler-Larkin Co-authored-by: Andrew Hahn Co-authored-by: Andrew Hahn <58017052+hahnandrew@users.noreply.github.com> Co-authored-by: Burak Karahan Co-authored-by: Jamil Saadeh --- infra-gen2/package-lock.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/infra-gen2/package-lock.json b/infra-gen2/package-lock.json index 806c800dd6..191c337b64 100644 --- a/infra-gen2/package-lock.json +++ b/infra-gen2/package-lock.json @@ -4462,6 +4462,18 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.624.0", + "@aws-sdk/client-sts": "3.624.0", + "@aws-sdk/core": "3.624.0", + "@aws-sdk/credential-provider-node": "3.624.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-sdk-ec2": "3.622.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", @@ -4474,9 +4486,27 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.624.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.14", + "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { @@ -4592,6 +4622,8 @@ "license": "Apache-2.0", "dependencies": { "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { @@ -4606,6 +4638,7 @@ "dependencies": { "@smithy/eventstream-serde-universal": "^3.0.5", "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" }, "engines": { From 5159b962180b9e2f250c086befacef14833ce1ae Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:05:01 -0700 Subject: [PATCH 035/159] chore: revert package-lock.json changes --- infra-gen2/package-lock.json | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/infra-gen2/package-lock.json b/infra-gen2/package-lock.json index 191c337b64..806c800dd6 100644 --- a/infra-gen2/package-lock.json +++ b/infra-gen2/package-lock.json @@ -4462,18 +4462,6 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.624.0", - "@aws-sdk/client-sts": "3.624.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-sdk-ec2": "3.622.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", @@ -4486,27 +4474,9 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { @@ -4622,8 +4592,6 @@ "license": "Apache-2.0", "dependencies": { "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { @@ -4638,7 +4606,6 @@ "dependencies": { "@smithy/eventstream-serde-universal": "^3.0.5", "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" }, "engines": { From 5008f098de5f14bfdf43c1762055b17ac0275de9 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:37:00 -0700 Subject: [PATCH 036/159] chore: add new AuthenticatorStep to switch statements in screen --- .../lib/src/screens/authenticator_screen.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index 181816a0ba..f01f3111fd 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -91,6 +91,9 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { case AuthenticatorStep.confirmResetPassword: case AuthenticatorStep.verifyUser: case AuthenticatorStep.confirmVerifyUser: + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + case AuthenticatorStep.continueSignInWithMfaSetupSelection: child = _FormWrapperView(step: step); case AuthenticatorStep.loading: throw StateError('Invalid step: $this'); @@ -299,6 +302,9 @@ extension on AuthenticatorStep { case AuthenticatorStep.verifyUser: case AuthenticatorStep.confirmVerifyUser: case AuthenticatorStep.loading: + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + case AuthenticatorStep.continueSignInWithMfaSetupSelection: throw StateError('Invalid step: $this'); } } From 28c81c5fdf7f801048470bb6843489cfe5eb40ba Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:00:12 -0700 Subject: [PATCH 037/159] chore: add input resolvers and localizations --- .../generated/input_localizations_en.dart | 3 +++ .../l10n/generated/title_localizations.dart | 18 ++++++++++++++ .../lib/src/l10n/input_resolver.dart | 2 +- .../lib/src/l10n/title_resolver.dart | 24 +++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart index 6b6d42a494..300acbc706 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart @@ -159,4 +159,7 @@ class AuthenticatorInputLocalizationsEn @override String get totpCodePrompt => 'Please enter the code from your registered Authenticator app'; + + @override + String get selectEmail => 'Email'; } diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart index 6d69ec3571..96b09f3830 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart @@ -141,6 +141,24 @@ abstract class AuthenticatorTitleLocalizations { /// **'Enter your one-time passcode'** String get confirmSignInWithTotpMfaCode; + /// Title of the Confirm Sign In with Email MFA Code step and form + /// + /// In en, this message translates to: + /// **'Enter your one-time passcode'** + String get confirmSignInWithEmailMfaCode; + + /// Title of the Continue Sign In with Email MFA Setup step and form + /// + /// In en, this message translates to: + /// **'Set up Email Two-Factor Auth'** + String get continueSignInWithEmailMfaSetup; + + /// Title of the Continue Sign In with MFA Setup Selection step and form + /// + /// In en, this message translates to: + /// **'Select a Two-Factor Auth method to set up'** + String get continueSignInWithMfaSetupSelection; + /// Title of the Reset Password step and form /// /// In en, this message translates to: diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart index 4b04f86962..0eb96b26f1 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart @@ -174,7 +174,7 @@ class InputResolverKey { static const selectEmail = InputResolverKey._( InputResolverKeyType.title, - field: InputField.email, + field: InputField.selectEmail, ); static const totpCodePrompt = InputResolverKey._( diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart index bbbf34925c..e5c1b19480 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart @@ -49,6 +49,24 @@ class TitleResolver extends Resolver { .confirmSignInWithTotpMfaCode; } + /// The title for the confirm sign in (email MFA code) Widget. + String confirmSignInWithEmailMfaCode(BuildContext context) { + return AuthenticatorLocalizations.titlesOf(context) + .confirmSignInWithEmailMfaCode; + } + + /// The title for the continue sign in (email MFA setup) Widget. + String continueSignInWithEmailMfaSetup(BuildContext context) { + return AuthenticatorLocalizations.titlesOf(context) + .continueSignInWithEmailMfaSetup; + } + + /// The title for the continue sign in (mfa setup selection) Widget. + String continueSignInWithMfaSetupSelection(BuildContext context) { + return AuthenticatorLocalizations.titlesOf(context) + .continueSignInWithMfaSetupSelection; + } + /// The title for the reset password Widget. String resetPassword(BuildContext context) { return AuthenticatorLocalizations.titlesOf(context).resetPassword; @@ -81,6 +99,12 @@ class TitleResolver extends Resolver { return continueSignInWithTotpSetup(context); case AuthenticatorStep.confirmSignInWithTotpMfaCode: return confirmSignInWithTotpMfaCode(context); + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + return confirmSignInWithEmailMfaCode(context); + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + return continueSignInWithEmailMfaSetup(context); + case AuthenticatorStep.continueSignInWithMfaSetupSelection: + return continueSignInWithMfaSetupSelection(context); case AuthenticatorStep.resetPassword: return resetPassword(context); case AuthenticatorStep.confirmResetPassword: From 7636a9cc6159f0532510988fe0f84b2d4575ab70 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:00:58 -0700 Subject: [PATCH 038/159] chore: add keys and enums --- .../amplify_authenticator/lib/src/enums/enums.dart | 1 + .../amplify_authenticator/lib/src/keys.dart | 5 +++++ .../lib/src/l10n/generated/title_localizations_en.dart | 10 ++++++++++ .../lib/src/l10n/src/inputs/inputs_en.arb | 6 +++++- .../amplify_authenticator/lib/src/widgets/form.dart | 2 +- 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/enums/enums.dart b/packages/authenticator/amplify_authenticator/lib/src/enums/enums.dart index f523de2aa8..3a4b577678 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/enums/enums.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/enums/enums.dart @@ -4,6 +4,7 @@ export 'authenticator_step.dart'; export 'confirm_signin_types.dart'; export 'confirm_signup_types.dart'; +export 'email_setup_types.dart'; export 'gender.dart'; export 'reset_password_field.dart'; export 'signin_types.dart'; diff --git a/packages/authenticator/amplify_authenticator/lib/src/keys.dart b/packages/authenticator/amplify_authenticator/lib/src/keys.dart index 49510ea7cf..bdc58969a1 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/keys.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/keys.dart @@ -140,3 +140,8 @@ const keyAuthenticatorBanner = Key('authenticatorBanner'); const keyQrCodeTotpSetupFormField = Key('qrCodeTotpSetupFormField'); const keyCopyKeyTotpSetupFormField = Key('copyKeyTotpSetupFormField'); const keyTotpSetupFormField = Key('totpSetupFormField'); + +// Email setup form keys +const keyEmailSetupFormField = Key('emailSetupFormField'); +const keyVerificationCodeEmailSetupFormField = + Key('verificationCodeEmailSetupFormField'); diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart index 02fb43da7d..3f3ca2b794 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart @@ -30,6 +30,16 @@ class AuthenticatorTitleLocalizationsEn @override String get confirmSignInWithTotpMfaCode => 'Enter your one-time passcode'; + @override + String get confirmSignInWithEmailMfaCode => 'Enter your one-time passcode'; + + @override + String get continueSignInWithEmailMfaSetup => 'Set up Email Two-Factor Auth'; + + @override + String get continueSignInWithMfaSetupSelection => + 'Select a Two-Factor Auth method to set up'; + @override String get resetPassword => 'Send Code'; diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/src/inputs/inputs_en.arb b/packages/authenticator/amplify_authenticator/lib/src/l10n/src/inputs/inputs_en.arb index 90399598d1..e32dd76731 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/src/inputs/inputs_en.arb +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/src/inputs/inputs_en.arb @@ -216,5 +216,9 @@ "totpCodePrompt": "Please enter the code from your registered Authenticator app", "@totpCodePrompt": { "description": "The instructional text for submitting a TOTP pass code" - } + }, + "selectEmail": "Email", + "@selectEmail": { + "description": "Label for the radio button to select email as the user's chosen MFA method." + }, } diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index 301b61177c..59aa9f2689 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -544,7 +544,7 @@ class ConfirmSignInCustomAuthForm extends AuthenticatorForm { /// {@category Prebuilt Widgets} /// {@template amplify_authenticator.confirm_sign_in_mfa_form} /// A prebuilt form for completing the sign in process with an MFA code, from -/// either SMS or TOTP. +/// either SMS, TOTP, or Email. /// {@endtemplate} class ConfirmSignInMFAForm extends AuthenticatorForm { /// {@macro amplify_authenticator.confirm_sign_in_mfa_form} From b0dd395433d81e1976e0cd5f4a96cc7beba831b9 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:02:06 -0700 Subject: [PATCH 039/159] chore: add select email input resolver --- .../amplify_authenticator/lib/src/l10n/input_resolver.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart index 0eb96b26f1..27626a8a6f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart @@ -466,6 +466,8 @@ class InputResolver extends Resolver { return AuthenticatorLocalizations.inputsOf(context).selectEmail; case InputField.totpCodePrompt: return AuthenticatorLocalizations.inputsOf(context).totpCodePrompt; + case InputField.selectEmail: + return AuthenticatorLocalizations.inputsOf(context).selectEmail; case InputField.usernameType: return AuthenticatorLocalizations.inputsOf(context).usernameType; } From 775a34c5724431d724bcdf90be6a68c11a988a71 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:35:17 -0700 Subject: [PATCH 040/159] chore: add EmailSetupField type for authenticator --- .../lib/src/enums/email_setup_types.dart | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart diff --git a/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart b/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart new file mode 100644 index 0000000000..a5f608d04b --- /dev/null +++ b/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +enum EmailSetupField { + email, + code, +} From 2fab8ed259ff84f134166dea2cb71c05d457a077 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:03:41 -0700 Subject: [PATCH 041/159] chore: add switch cases for future implementations of the forms --- .../lib/src/state/inherited_forms.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index a2a0dfa5ae..6511ba682f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -55,10 +55,16 @@ class InheritedForms extends InheritedWidget { return confirmSignInNewPasswordForm; case AuthenticatorStep.continueSignInWithMfaSelection: return continueSignInWithMfaSelectionForm; + case AuthenticatorStep.continueSignInWithMfaSetupSelection: + // TODO(khatruong2009): Implement this form case AuthenticatorStep.continueSignInWithTotpSetup: return continueSignInWithTotpSetupForm; case AuthenticatorStep.confirmSignInWithTotpMfaCode: return confirmSignInWithTotpMfaCodeForm; + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + // TODO(khatruong2009): Implement this form + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + // TODO(khatruong2009): Implement this form case AuthenticatorStep.resetPassword: return resetPasswordForm; case AuthenticatorStep.confirmResetPassword: From 29ab2d4c0684859fbaee0caff81b76bb4c961e57 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:53:46 -0700 Subject: [PATCH 042/159] chore: add authenticator step cases for sign in with email mfa --- .../amplify_authenticator/lib/src/widgets/form_field.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index f53a94b831..e8ba9fe1ae 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -28,6 +28,7 @@ import 'package:qr_flutter/qr_flutter.dart'; part 'form_fields/confirm_sign_in_form_field.dart'; part 'form_fields/confirm_sign_up_form_field.dart'; +part 'form_fields/email_setup_form_field.dart'; part 'form_fields/mfa_selection_form_field.dart'; part 'form_fields/phone_number_field.dart'; part 'form_fields/reset_password_form_field.dart'; @@ -228,12 +229,15 @@ abstract class AuthenticatorFormFieldState< case AuthenticatorStep.confirmSignInCustomAuth: state.confirmSignInCustomAuth(); case AuthenticatorStep.confirmSignInMfa: + case AuthenticatorStep.confirmSignInWithEmailMfaCode: state.confirmSignInMFA(); case AuthenticatorStep.confirmSignInNewPassword: state.confirmSignInNewPassword(); case AuthenticatorStep.confirmSignInWithTotpMfaCode: case AuthenticatorStep.continueSignInWithTotpSetup: state.confirmTotp(); + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + state.continueEmailMfaSetup(); case AuthenticatorStep.resetPassword: state.resetPassword(); case AuthenticatorStep.confirmResetPassword: From 759cc42584844862d469d228cdcdd32176dd0e40 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:56:31 -0700 Subject: [PATCH 043/159] chore: remove code from email setup field because only email is needed --- .../amplify_authenticator/lib/src/enums/email_setup_types.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart b/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart index a5f608d04b..88252cb4e5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart @@ -3,5 +3,4 @@ enum EmailSetupField { email, - code, } From 308621245ad6ab498387be22851e06e2da34e91a Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:14:55 -0700 Subject: [PATCH 044/159] chore: add mfa email to authenticator state --- .../lib/src/state/authenticator_state.dart | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart index 10bdef835b..38c630da49 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart @@ -160,6 +160,18 @@ class AuthenticatorState extends ChangeNotifier { notifyListeners(); } + /// The value for the email MFA setup form field + /// + /// This value will be used during continue email MFA setup + String get mfaEmail => _mfaEmail; + + set mfaEmail(String value) { + _mfaEmail = value.trim(); + notifyListeners(); + } + + String _mfaEmail = ''; + MfaType? _selectedMfaMethod; TotpSetupDetails? get totpSetupDetails { @@ -414,6 +426,23 @@ class AuthenticatorState extends ChangeNotifier { _setIsBusy(false); } + /// Complete MFA setup using the values for [confirmationCode] + Future continueEmailMfaSetup() async { + if (!_formKey.currentState!.validate()) { + return; + } + + _setIsBusy(true); + + final confirm = AuthConfirmSignInData( + confirmationValue: _mfaEmail.trim(), + ); + + _authBloc.add(AuthConfirmSignIn(confirm)); + await nextBlocEvent(); + _setIsBusy(false); + } + /// Complete the force password change with [newPassword] Future confirmSignInNewPassword() async { if (!_formKey.currentState!.validate()) { From 6e2c8e336dbee6baea4f4b769f849709ddb18594 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:35:24 -0700 Subject: [PATCH 045/159] chore: add email mfa setup form and form field --- .../lib/amplify_authenticator.dart | 2 + .../lib/src/state/inherited_forms.dart | 8 ++ .../lib/src/widgets/form.dart | 22 +++++ .../form_fields/email_setup_form_field.dart | 90 +++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart diff --git a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart index bd71bfdf0b..8cfaf5ab79 100644 --- a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart +++ b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart @@ -77,6 +77,7 @@ export 'src/widgets/form.dart' ConfirmSignInNewPasswordForm, ContinueSignInWithMfaSelectionForm, ContinueSignInWithTotpSetupForm, + ContinueSignInWithEmailMfaSetupForm, ConfirmSignUpForm, ResetPasswordForm, ConfirmResetPasswordForm, @@ -712,6 +713,7 @@ class _AuthenticatorState extends State { ContinueSignInWithMfaSelectionForm(), continueSignInWithTotpSetupForm: ContinueSignInWithTotpSetupForm(), + continueSignInWithEmailMfaSetupForm: ContinueSignInWithEmailMfaSetupForm(), confirmSignInWithTotpMfaCodeForm: ConfirmSignInMFAForm(), verifyUserForm: VerifyUserForm(), confirmVerifyUserForm: ConfirmVerifyUserForm(), diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index 6511ba682f..ad3c0f93a4 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -17,6 +17,7 @@ class InheritedForms extends InheritedWidget { required this.confirmSignInNewPasswordForm, required this.continueSignInWithMfaSelectionForm, required this.continueSignInWithTotpSetupForm, + required this.continueSignInWithEmailMfaSetupForm, required this.confirmSignInWithTotpMfaCodeForm, required this.verifyUserForm, required this.confirmVerifyUserForm, @@ -31,6 +32,7 @@ class InheritedForms extends InheritedWidget { final ConfirmSignInNewPasswordForm confirmSignInNewPasswordForm; final ContinueSignInWithMfaSelectionForm continueSignInWithMfaSelectionForm; final ContinueSignInWithTotpSetupForm continueSignInWithTotpSetupForm; + final ContinueSignInWithEmailMfaSetupForm continueSignInWithEmailMfaSetupForm; final ConfirmSignInMFAForm confirmSignInWithTotpMfaCodeForm; final ResetPasswordForm resetPasswordForm; final ConfirmResetPasswordForm confirmResetPasswordForm; @@ -112,6 +114,12 @@ class InheritedForms extends InheritedWidget { oldWidget.confirmSignInWithTotpMfaCodeForm != confirmSignInWithTotpMfaCodeForm; } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('continueSignInWithEmailMfaSetupForm', continueSignInWithEmailMfaSetupForm)); + } } // ignore_for_file: prefer_asserts_with_message diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index 59aa9f2689..9c91c3fb0d 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -646,6 +646,28 @@ class ContinueSignInWithTotpSetupForm extends AuthenticatorForm { AuthenticatorFormState(); } +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.continue_sign_in_with_email_mfa_setup_form} +/// A prebuilt form for completing the email mfa setup process. +/// {@endtemplate} +class ContinueSignInWithEmailMfaSetupForm extends AuthenticatorForm { + ContinueSignInWithEmailMfaSetupForm({ + super.key, + }) : super._( + fields: [ + EmailSetupFormField.email(), + ], + actions: const [ + ConfirmSignInMFAButton(), + BackToSignInButton(), + ], + ); + + @override + AuthenticatorFormState createState() => + AuthenticatorFormState(); +} + /// {@category Prebuilt Widgets} /// {@template amplify_authenticator.send_code_form} /// A prebuilt form for initiating the reset password flow. diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart new file mode 100644 index 0000000000..06647ee4f9 --- /dev/null +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart @@ -0,0 +1,90 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +part of '../form_field.dart'; + +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.email_setup_form_field} +/// A prebuilt form field widget for use on the Email MFA setup step. +/// {@endtemplate} +abstract class EmailSetupFormField + extends AuthenticatorFormField { + /// {@macro amplify_authenticator.email_setup_form_field} + /// + /// Either [titleKey] or [title] is required. + const EmailSetupFormField._({ + super.key, + required super.field, + super.titleKey, + super.hintTextKey, + super.title, + super.hintText, + super.validator, + super.autofillHints, + }) : super._(); + + /// Creates an email component. + static EmailSetupFormField email({ + Key? key, + FormFieldValidator? validator, + Iterable? autofillHints, + }) => + _EmailSetupTextField( + key: key ?? keyEmailSetupFormField, + titleKey: InputResolverKey.emailTitle, + hintTextKey: InputResolverKey.emailHint, + field: EmailSetupField.email, + validator: validator, + autofillHints: autofillHints, + ); +} + +abstract class _EmailSetupFormFieldState + extends AuthenticatorFormFieldState> { + @override + TextInputType get keyboardType { + return TextInputType.emailAddress; + } + + @override + Iterable? get autofillHints { + return [AutofillHints.email]; + } + + @override + bool get required { + switch (widget.field) { + case EmailSetupField.email: + return true; + } + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('required', required)); + } +} + +class _EmailSetupTextField extends EmailSetupFormField { + const _EmailSetupTextField({ + super.key, + required super.field, + super.titleKey, + super.hintTextKey, + super.validator, + super.autofillHints, + }) : super._(); + + @override + _EmailSetupTextFieldState createState() => _EmailSetupTextFieldState(); +} + +class _EmailSetupTextFieldState extends _EmailSetupFormFieldState + with AuthenticatorTextField { + @override + bool get obscureText { + return false; + } +} From 8209373a5d0fe5661fe4b969ea061fc8706c7925 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:36:41 -0700 Subject: [PATCH 046/159] chore: adding steps to authenticator state machine --- .../amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 41dcfe410e..bbb05464e6 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -218,6 +218,7 @@ class StateMachineBloc switch (result.nextStep.signInStep) { case AuthSignInStep.confirmSignInWithSmsMfaCode: + case AuthSignInStep.confirmSignInWithEmailMfaCode: yield UnauthenticatedState.confirmSignInMfa; case AuthSignInStep.confirmSignInWithCustomChallenge: yield ConfirmSignInCustom( @@ -323,6 +324,7 @@ class StateMachineBloc }) async { switch (result.nextStep.signInStep) { case AuthSignInStep.confirmSignInWithSmsMfaCode: + case AuthSignInStep.confirmSignInWithEmailMfaCode: _notifyCodeSent(result.nextStep.codeDeliveryDetails?.destination); _emit(UnauthenticatedState.confirmSignInMfa); case AuthSignInStep.confirmSignInWithCustomChallenge: From dfecc73de4fe0ed091feb2a82da2202f238dc9ab Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:21:38 -0700 Subject: [PATCH 047/159] chore: remove this verification code form field key since we already have keyCodeConfirmSignInFormField --- packages/authenticator/amplify_authenticator/lib/src/keys.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/keys.dart b/packages/authenticator/amplify_authenticator/lib/src/keys.dart index bdc58969a1..7900366e37 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/keys.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/keys.dart @@ -143,5 +143,3 @@ const keyTotpSetupFormField = Key('totpSetupFormField'); // Email setup form keys const keyEmailSetupFormField = Key('emailSetupFormField'); -const keyVerificationCodeEmailSetupFormField = - Key('verificationCodeEmailSetupFormField'); From 1fd23c470cc2893c2f46104cd897520ea5b208cf Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:51:27 -0700 Subject: [PATCH 048/159] chore: add authenticator screen keys for new screens --- .../lib/src/screens/authenticator_screen.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index f01f3111fd..8ffbc61622 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -39,6 +39,12 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.confirmSignInWithTotpMfaCode({Key? key}) : this(key: key, step: AuthenticatorStep.confirmSignInWithTotpMfaCode); + + const AuthenticatorScreen.continueSignInWithEmailMfaSetup({Key? key}) + : this(key: key, step: AuthenticatorStep.continueSignInWithEmailMfaSetup); + + const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) + : this(key: key, step: AuthenticatorStep.continueSignInWithMfaSetupSelection); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); From c1140a137bf7b2ea5315f3936630d5e1cbc21967 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:07:41 -0700 Subject: [PATCH 049/159] chore: remove dart auto formatted code --- .../lib/src/state/inherited_forms.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index ad3c0f93a4..7a292bc8f0 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -114,12 +114,6 @@ class InheritedForms extends InheritedWidget { oldWidget.confirmSignInWithTotpMfaCodeForm != confirmSignInWithTotpMfaCodeForm; } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('continueSignInWithEmailMfaSetupForm', continueSignInWithEmailMfaSetupForm)); - } } // ignore_for_file: prefer_asserts_with_message From a73932a215b741f194d083f66eaebf1e2114abb7 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:24:33 -0700 Subject: [PATCH 050/159] chore: add new email mfa setup form to inherited forms switch statement --- .../lib/src/state/inherited_forms.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index 7a292bc8f0..ff42f558ee 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -58,15 +58,15 @@ class InheritedForms extends InheritedWidget { case AuthenticatorStep.continueSignInWithMfaSelection: return continueSignInWithMfaSelectionForm; case AuthenticatorStep.continueSignInWithMfaSetupSelection: - // TODO(khatruong2009): Implement this form + // TODO(khatruong2009): Implement this form case AuthenticatorStep.continueSignInWithTotpSetup: return continueSignInWithTotpSetupForm; case AuthenticatorStep.confirmSignInWithTotpMfaCode: return confirmSignInWithTotpMfaCodeForm; case AuthenticatorStep.continueSignInWithEmailMfaSetup: - // TODO(khatruong2009): Implement this form + return continueSignInWithEmailMfaSetupForm; case AuthenticatorStep.confirmSignInWithEmailMfaCode: - // TODO(khatruong2009): Implement this form + return confirmSignInMFAForm; case AuthenticatorStep.resetPassword: return resetPasswordForm; case AuthenticatorStep.confirmResetPassword: From 988bb2a8ee80c7ca0dd49fac4193de1e27658676 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:26:56 -0700 Subject: [PATCH 051/159] chore: add cases to oldWidget --- .../lib/src/state/inherited_forms.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index ff42f558ee..d83d7b850d 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -112,7 +112,11 @@ class InheritedForms extends InheritedWidget { oldWidget.continueSignInWithTotpSetupForm != continueSignInWithTotpSetupForm || oldWidget.confirmSignInWithTotpMfaCodeForm != - confirmSignInWithTotpMfaCodeForm; + confirmSignInWithTotpMfaCodeForm || + oldWidget.continueSignInWithEmailMfaSetupForm != + continueSignInWithEmailMfaSetupForm || + oldWidget.continueSignInWithMfaSelectionForm != + continueSignInWithMfaSelectionForm; } } From 334ba5f054f47819e9022ad0c94c085c682f2efc Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:28:54 -0700 Subject: [PATCH 052/159] chore: add todo to add case for continueSignInWithMfaSetupSelection --- .../amplify_authenticator/lib/src/widgets/form_field.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index e8ba9fe1ae..caa1d7151f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -238,6 +238,7 @@ abstract class AuthenticatorFormFieldState< state.confirmTotp(); case AuthenticatorStep.continueSignInWithEmailMfaSetup: state.continueEmailMfaSetup(); + // TODO(khatruong2009): add case for AuthenticatorStep.continueSignInWithMfaSetupSelection case AuthenticatorStep.resetPassword: state.resetPassword(); case AuthenticatorStep.confirmResetPassword: From 987361d8bce4e9804051603c59485432dab0570f Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:23:37 -0700 Subject: [PATCH 053/159] chore: remove duplicate localization and fix docs comments --- .../lib/src/l10n/generated/input_localizations_en.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart index 300acbc706..bdf428025e 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart @@ -160,6 +160,4 @@ class AuthenticatorInputLocalizationsEn String get totpCodePrompt => 'Please enter the code from your registered Authenticator app'; - @override - String get selectEmail => 'Email'; } From dd7d7852f1682be8533d18cff07be90320cc17fb Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:24:10 -0700 Subject: [PATCH 054/159] chore: add continueSignInWithMfaSetupSelectionForm --- .../lib/amplify_authenticator.dart | 3 + .../lib/src/state/inherited_forms.dart | 5 +- .../lib/src/widgets/form.dart | 23 +++++++ .../lib/src/widgets/form_field.dart | 1 + .../form_fields/mfa_selection_form_field.dart | 5 ++ .../mfa_setup_selection_form_field.dart | 63 +++++++++++++++++++ 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_setup_selection_form_field.dart diff --git a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart index 8cfaf5ab79..dc852fce19 100644 --- a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart +++ b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart @@ -76,6 +76,7 @@ export 'src/widgets/form.dart' ConfirmSignInMFAForm, ConfirmSignInNewPasswordForm, ContinueSignInWithMfaSelectionForm, + ContinueSignInWithMfaSetupSelectionForm, ContinueSignInWithTotpSetupForm, ContinueSignInWithEmailMfaSetupForm, ConfirmSignUpForm, @@ -711,6 +712,8 @@ class _AuthenticatorState extends State { confirmSignInMFAForm: ConfirmSignInMFAForm(), continueSignInWithMfaSelectionForm: ContinueSignInWithMfaSelectionForm(), + continueSignInWithMfaSetupSelectionForm: + ContinueSignInWithMfaSetupSelectionForm(), continueSignInWithTotpSetupForm: ContinueSignInWithTotpSetupForm(), continueSignInWithEmailMfaSetupForm: ContinueSignInWithEmailMfaSetupForm(), diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index d83d7b850d..876164b22a 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -16,6 +16,7 @@ class InheritedForms extends InheritedWidget { required this.confirmResetPasswordForm, required this.confirmSignInNewPasswordForm, required this.continueSignInWithMfaSelectionForm, + required this.continueSignInWithMfaSetupSelectionForm, required this.continueSignInWithTotpSetupForm, required this.continueSignInWithEmailMfaSetupForm, required this.confirmSignInWithTotpMfaCodeForm, @@ -31,6 +32,8 @@ class InheritedForms extends InheritedWidget { final ConfirmSignInMFAForm confirmSignInMFAForm; final ConfirmSignInNewPasswordForm confirmSignInNewPasswordForm; final ContinueSignInWithMfaSelectionForm continueSignInWithMfaSelectionForm; + final ContinueSignInWithMfaSetupSelectionForm + continueSignInWithMfaSetupSelectionForm; final ContinueSignInWithTotpSetupForm continueSignInWithTotpSetupForm; final ContinueSignInWithEmailMfaSetupForm continueSignInWithEmailMfaSetupForm; final ConfirmSignInMFAForm confirmSignInWithTotpMfaCodeForm; @@ -58,7 +61,7 @@ class InheritedForms extends InheritedWidget { case AuthenticatorStep.continueSignInWithMfaSelection: return continueSignInWithMfaSelectionForm; case AuthenticatorStep.continueSignInWithMfaSetupSelection: - // TODO(khatruong2009): Implement this form + return continueSignInWithMfaSetupSelectionForm; case AuthenticatorStep.continueSignInWithTotpSetup: return continueSignInWithTotpSetupForm; case AuthenticatorStep.confirmSignInWithTotpMfaCode: diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index 9c91c3fb0d..a114fbb65c 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -623,6 +623,29 @@ class ContinueSignInWithMfaSelectionForm extends AuthenticatorForm { AuthenticatorFormState(); } +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.continue_sign_in_with__mfa_setup_selection_form} +/// A prebuilt form for selecting an MFA method during setup. +/// {@endtemplate} +class ContinueSignInWithMfaSetupSelectionForm extends AuthenticatorForm { + /// {@macro amplify_authenticator.continue_sign_in_with__mfa_setup_selection_form} + ContinueSignInWithMfaSetupSelectionForm({ + super.key, + }) : super._( + fields: [ + ConfirmSignInFormField.mfaSelection(), + ], + actions: const [ + ContinueSignInMFASelectionButton(), + BackToSignInButton(), + ], + ); + + @override + AuthenticatorFormState createState() => + AuthenticatorFormState(); +} + /// {@category Prebuilt Widgets} /// {@template amplify_authenticator.continue_sign_in_with_totp_setup_form} /// A prebuilt form for completing the totp setup process. diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index caa1d7151f..1c4477b91b 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -30,6 +30,7 @@ part 'form_fields/confirm_sign_in_form_field.dart'; part 'form_fields/confirm_sign_up_form_field.dart'; part 'form_fields/email_setup_form_field.dart'; part 'form_fields/mfa_selection_form_field.dart'; +part 'form_fields/mfa_setup_selection_form_field.dart'; part 'form_fields/phone_number_field.dart'; part 'form_fields/reset_password_form_field.dart'; part 'form_fields/sign_in_form_field.dart'; diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_selection_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_selection_form_field.dart index f5587071d0..8d73d1aae2 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_selection_form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_selection_form_field.dart @@ -41,6 +41,11 @@ class _MfaSelectionFieldState extends _ConfirmSignInFormFieldState label: InputResolverKey.selectSms, value: MfaType.sms, ), + if (_allowedMfaTypes.contains(MfaType.email)) + const InputSelection( + label: InputResolverKey.selectEmail, + value: MfaType.email, + ), ]; @override diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_setup_selection_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_setup_selection_form_field.dart new file mode 100644 index 0000000000..76b4084337 --- /dev/null +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_setup_selection_form_field.dart @@ -0,0 +1,63 @@ +// mfa_setup_selection_form_field.dart + +// Copyright Amazon.com, Inc. or its affiliates. +// All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +part of '../form_field.dart'; + +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.mfa_setup_selection_form_field} +/// A prebuilt form widget for use on the MFA setup selection step. +/// {@endtemplate} +class _MfaSetupMethodRadioField extends ConfirmSignInFormField { + const _MfaSetupMethodRadioField({ + super.key, + required super.field, + }) : super._(); + + @override + _MfaSetupSelectionFieldState createState() => _MfaSetupSelectionFieldState(); +} + +class _MfaSetupSelectionFieldState extends _ConfirmSignInFormFieldState + with AuthenticatorRadioField { + Set get _allowedMfaTypes { + final state = InheritedAuthBloc.of(context).currentState; + assert( + state is ContinueSignInWithMfaSetupSelection, + 'Expected ContinueSignInWithMfaSetupSelection for current screen', + ); + return (state as ContinueSignInWithMfaSetupSelection).allowedMfaTypes; + } + + @override + List> get selections => [ + if (_allowedMfaTypes.contains(MfaType.totp)) + const InputSelection( + label: InputResolverKey.selectTotp, + value: MfaType.totp, + ), + if (_allowedMfaTypes.contains(MfaType.email)) + const InputSelection( + label: InputResolverKey.selectEmail, + value: MfaType.email, + ), + ]; + + @override + MfaType get initialValue => selections.first.value; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + state.selectedMfaMethod = initialValue; + }); + } + + @override + ValueChanged get onChanged { + return (MfaType method) => state.selectedMfaMethod = method; + } +} From a15898f2002c44e4cc26daedc4bb75f02f8e0339 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:40:20 -0700 Subject: [PATCH 055/159] chore: dart format and fix typos --- .../amplify_authenticator/lib/amplify_authenticator.dart | 3 ++- .../lib/src/l10n/generated/input_localizations_en.dart | 1 - .../lib/src/l10n/generated/title_localizations.dart | 6 +++--- .../lib/src/screens/authenticator_screen.dart | 6 ++++-- .../lib/src/state/authenticator_state.dart | 4 ++-- .../src/widgets/form_fields/confirm_sign_in_form_field.dart | 2 +- .../lib/src/widgets/form_fields/email_setup_form_field.dart | 5 ++--- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart index dc852fce19..f83b9b84c4 100644 --- a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart +++ b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart @@ -716,7 +716,8 @@ class _AuthenticatorState extends State { ContinueSignInWithMfaSetupSelectionForm(), continueSignInWithTotpSetupForm: ContinueSignInWithTotpSetupForm(), - continueSignInWithEmailMfaSetupForm: ContinueSignInWithEmailMfaSetupForm(), + continueSignInWithEmailMfaSetupForm: + ContinueSignInWithEmailMfaSetupForm(), confirmSignInWithTotpMfaCodeForm: ConfirmSignInMFAForm(), verifyUserForm: VerifyUserForm(), confirmVerifyUserForm: ConfirmVerifyUserForm(), diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart index bdf428025e..6b6d42a494 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart @@ -159,5 +159,4 @@ class AuthenticatorInputLocalizationsEn @override String get totpCodePrompt => 'Please enter the code from your registered Authenticator app'; - } diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart index 96b09f3830..05d73ef2a4 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart @@ -142,19 +142,19 @@ abstract class AuthenticatorTitleLocalizations { String get confirmSignInWithTotpMfaCode; /// Title of the Confirm Sign In with Email MFA Code step and form - /// + /// /// In en, this message translates to: /// **'Enter your one-time passcode'** String get confirmSignInWithEmailMfaCode; /// Title of the Continue Sign In with Email MFA Setup step and form - /// + /// /// In en, this message translates to: /// **'Set up Email Two-Factor Auth'** String get continueSignInWithEmailMfaSetup; /// Title of the Continue Sign In with MFA Setup Selection step and form - /// + /// /// In en, this message translates to: /// **'Select a Two-Factor Auth method to set up'** String get continueSignInWithMfaSetupSelection; diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index 8ffbc61622..b5d48988b1 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -39,12 +39,14 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.confirmSignInWithTotpMfaCode({Key? key}) : this(key: key, step: AuthenticatorStep.confirmSignInWithTotpMfaCode); - + const AuthenticatorScreen.continueSignInWithEmailMfaSetup({Key? key}) : this(key: key, step: AuthenticatorStep.continueSignInWithEmailMfaSetup); const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) - : this(key: key, step: AuthenticatorStep.continueSignInWithMfaSetupSelection); + : this( + key: key, + step: AuthenticatorStep.continueSignInWithMfaSetupSelection); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart index 38c630da49..8e4b5542e4 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart @@ -161,7 +161,7 @@ class AuthenticatorState extends ChangeNotifier { } /// The value for the email MFA setup form field - /// + /// /// This value will be used during continue email MFA setup String get mfaEmail => _mfaEmail; @@ -169,7 +169,7 @@ class AuthenticatorState extends ChangeNotifier { _mfaEmail = value.trim(); notifyListeners(); } - + String _mfaEmail = ''; MfaType? _selectedMfaMethod; diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart index d4b39d1d22..ce8bf33081 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart @@ -79,7 +79,7 @@ abstract class ConfirmSignInFormField autofillHints: autofillHints, ); - /// Creates a mfa preference selection component. + /// Creates an mfa preference selection component. static ConfirmSignInFormField mfaSelection({ Key? key, }) => diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart index 06647ee4f9..47951cbe8f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart @@ -7,7 +7,7 @@ part of '../form_field.dart'; /// {@template amplify_authenticator.email_setup_form_field} /// A prebuilt form field widget for use on the Email MFA setup step. /// {@endtemplate} -abstract class EmailSetupFormField +abstract class EmailSetupFormField extends AuthenticatorFormField { /// {@macro amplify_authenticator.email_setup_form_field} /// @@ -52,7 +52,6 @@ abstract class _EmailSetupFormFieldState return [AutofillHints.email]; } - @override bool get required { switch (widget.field) { case EmailSetupField.email: @@ -76,7 +75,7 @@ class _EmailSetupTextField extends EmailSetupFormField { super.validator, super.autofillHints, }) : super._(); - + @override _EmailSetupTextFieldState createState() => _EmailSetupTextFieldState(); } From 8b69fe6d6aa2f1312684b38e1ed2b027c64f6438 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:40:48 -0700 Subject: [PATCH 056/159] chore: fix mfaSetup fields and input_resolver duplicate --- .../amplify_authenticator/lib/src/keys.dart | 2 ++ .../lib/src/l10n/input_resolver.dart | 2 -- .../amplify_authenticator/lib/src/widgets/form.dart | 7 ++++--- .../widgets/form_fields/confirm_sign_in_form_field.dart | 9 +++++++++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/keys.dart b/packages/authenticator/amplify_authenticator/lib/src/keys.dart index 7900366e37..2f0665814e 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/keys.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/keys.dart @@ -52,6 +52,8 @@ const keyCustomChallengeConfirmSignInFormField = Key('customChallengeConfirmSignInFormField'); const keyMfaMethodRadioConfirmSignInFormField = Key('mfaMethodRadioConfirmSignInFormField'); +const keyMfaSetupMethodRadioConfirmSignInFormField = + Key('mfaSetupMethodRadioConfirmSignInFormField'); const keyUsernameConfirmSignInFormField = Key('usernameConfirmSignInFormField'); const keyPasswordConfirmSignInFormField = Key('passwordConfirmSignInFormField'); const keyNewPasswordConfirmSignInFormField = diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart index 27626a8a6f..0eb96b26f1 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart @@ -466,8 +466,6 @@ class InputResolver extends Resolver { return AuthenticatorLocalizations.inputsOf(context).selectEmail; case InputField.totpCodePrompt: return AuthenticatorLocalizations.inputsOf(context).totpCodePrompt; - case InputField.selectEmail: - return AuthenticatorLocalizations.inputsOf(context).selectEmail; case InputField.usernameType: return AuthenticatorLocalizations.inputsOf(context).usernameType; } diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index a114fbb65c..c79d308f84 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -633,7 +633,7 @@ class ContinueSignInWithMfaSetupSelectionForm extends AuthenticatorForm { super.key, }) : super._( fields: [ - ConfirmSignInFormField.mfaSelection(), + ConfirmSignInFormField.mfaSetupSelection(), ], actions: const [ ContinueSignInMFASelectionButton(), @@ -642,8 +642,9 @@ class ContinueSignInWithMfaSetupSelectionForm extends AuthenticatorForm { ); @override - AuthenticatorFormState createState() => - AuthenticatorFormState(); + AuthenticatorFormState + createState() => + AuthenticatorFormState(); } /// {@category Prebuilt Widgets} diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart index ce8bf33081..22d1253f39 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart @@ -88,6 +88,15 @@ abstract class ConfirmSignInFormField field: ConfirmSignInField.mfaMethod, ); + /// creates an mfa preference setup selection component. + static ConfirmSignInFormField mfaSetupSelection({ + Key? key, + }) => + _MfaSetupMethodRadioField( + key: key ?? keyMfaSetupMethodRadioConfirmSignInFormField, + field: ConfirmSignInField.mfaMethod, + ); + /// Creates a verification code component. static ConfirmSignInFormField verificationCode({ Key? key, From 59cc900bee74fab0ec6d687dadc05ccff68acc2d Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:56:31 -0700 Subject: [PATCH 057/159] chore: remove duplicate analytics backend section --- infra-gen2/tool/deploy_gen2.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/infra-gen2/tool/deploy_gen2.dart b/infra-gen2/tool/deploy_gen2.dart index 15ffcf10f4..e5f8cf1a1e 100644 --- a/infra-gen2/tool/deploy_gen2.dart +++ b/infra-gen2/tool/deploy_gen2.dart @@ -19,11 +19,6 @@ import 'package:path/path.dart' as p; /// 3. Add the backend to a category or create a new category /// 4. Run `dart tool/deploy_gen2.dart` to deploy the backend const List infraConfig = [ - AmplifyBackendGroup( - category: Category.analytics, - defaultOutput: '', - backends: [], - ), AmplifyBackendGroup( category: Category.api, defaultOutput: 'packages/api/amplify_api/example/lib', From ceb0564638be14e279f265bc570907ee0501dd86 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:33:17 -0700 Subject: [PATCH 058/159] chore: use confirmSignInWithEmailMfaCode instead of confirmSignInMfa --- .../lib/amplify_authenticator.dart | 1 + .../lib/src/blocs/auth/auth_bloc.dart | 2 -- .../src/l10n/generated/title_localizations.dart | 4 ++-- .../l10n/generated/title_localizations_en.dart | 4 ++-- .../lib/src/screens/authenticator_screen.dart | 7 ++++--- .../lib/src/state/authenticator_state.dart | 17 +++++++++++++++++ .../lib/src/state/inherited_forms.dart | 6 +++++- .../lib/src/widgets/form_field.dart | 3 ++- 8 files changed, 33 insertions(+), 11 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart index f83b9b84c4..55abb9c220 100644 --- a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart +++ b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart @@ -719,6 +719,7 @@ class _AuthenticatorState extends State { continueSignInWithEmailMfaSetupForm: ContinueSignInWithEmailMfaSetupForm(), confirmSignInWithTotpMfaCodeForm: ConfirmSignInMFAForm(), + confirmSignInWithEmailMfaCodeForm: ConfirmSignInMFAForm(), verifyUserForm: VerifyUserForm(), confirmVerifyUserForm: ConfirmVerifyUserForm(), child: widget.child, diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index bbb05464e6..41dcfe410e 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -218,7 +218,6 @@ class StateMachineBloc switch (result.nextStep.signInStep) { case AuthSignInStep.confirmSignInWithSmsMfaCode: - case AuthSignInStep.confirmSignInWithEmailMfaCode: yield UnauthenticatedState.confirmSignInMfa; case AuthSignInStep.confirmSignInWithCustomChallenge: yield ConfirmSignInCustom( @@ -324,7 +323,6 @@ class StateMachineBloc }) async { switch (result.nextStep.signInStep) { case AuthSignInStep.confirmSignInWithSmsMfaCode: - case AuthSignInStep.confirmSignInWithEmailMfaCode: _notifyCodeSent(result.nextStep.codeDeliveryDetails?.destination); _emit(UnauthenticatedState.confirmSignInMfa); case AuthSignInStep.confirmSignInWithCustomChallenge: diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart index 05d73ef2a4..852f8e4d7b 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart @@ -150,13 +150,13 @@ abstract class AuthenticatorTitleLocalizations { /// Title of the Continue Sign In with Email MFA Setup step and form /// /// In en, this message translates to: - /// **'Set up Email Two-Factor Auth'** + /// **'Add Email for Two-Factor Authentication'** String get continueSignInWithEmailMfaSetup; /// Title of the Continue Sign In with MFA Setup Selection step and form /// /// In en, this message translates to: - /// **'Select a Two-Factor Auth method to set up'** + /// **'Choose your preferred two-factor authentication method to set up'** String get continueSignInWithMfaSetupSelection; /// Title of the Reset Password step and form diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart index 3f3ca2b794..f547339bf5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart @@ -34,11 +34,11 @@ class AuthenticatorTitleLocalizationsEn String get confirmSignInWithEmailMfaCode => 'Enter your one-time passcode'; @override - String get continueSignInWithEmailMfaSetup => 'Set up Email Two-Factor Auth'; + String get continueSignInWithEmailMfaSetup => 'Add Email for Two-Factor Authentication'; @override String get continueSignInWithMfaSetupSelection => - 'Select a Two-Factor Auth method to set up'; + 'Choose your preferred two-factor authentication method to set up'; @override String get resetPassword => 'Send Code'; diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index b5d48988b1..e547dfd9f0 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -40,13 +40,14 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.confirmSignInWithTotpMfaCode({Key? key}) : this(key: key, step: AuthenticatorStep.confirmSignInWithTotpMfaCode); + const AuthenticatorScreen.confirmSignInWithEmailMfaCode({Key? key}) + : this(key: key, step: AuthenticatorStep.confirmSignInWithEmailMfaCode); + const AuthenticatorScreen.continueSignInWithEmailMfaSetup({Key? key}) : this(key: key, step: AuthenticatorStep.continueSignInWithEmailMfaSetup); const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) - : this( - key: key, - step: AuthenticatorStep.continueSignInWithMfaSetupSelection); + : this(key: key, step: AuthenticatorStep.continueSignInWithMfaSetupSelection); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart index 8e4b5542e4..bf434aba5c 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart @@ -426,6 +426,23 @@ class AuthenticatorState extends ChangeNotifier { _setIsBusy(false); } + /// complete Email MFA setup using the values for [confirmationCode] + Future confirmEmailMfa() async { + if (!_formKey.currentState!.validate()) { + return; + } + + _setIsBusy(true); + + final confirm = AuthConfirmSignInData( + confirmationValue: _confirmationCode.trim(), + ); + + _authBloc.add(AuthConfirmSignIn(confirm)); + await nextBlocEvent(); + _setIsBusy(false); + } + /// Complete MFA setup using the values for [confirmationCode] Future continueEmailMfaSetup() async { if (!_formKey.currentState!.validate()) { diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index 876164b22a..121f81bd0d 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -20,6 +20,7 @@ class InheritedForms extends InheritedWidget { required this.continueSignInWithTotpSetupForm, required this.continueSignInWithEmailMfaSetupForm, required this.confirmSignInWithTotpMfaCodeForm, + required this.confirmSignInWithEmailMfaCodeForm, required this.verifyUserForm, required this.confirmVerifyUserForm, required super.child, @@ -37,6 +38,7 @@ class InheritedForms extends InheritedWidget { final ContinueSignInWithTotpSetupForm continueSignInWithTotpSetupForm; final ContinueSignInWithEmailMfaSetupForm continueSignInWithEmailMfaSetupForm; final ConfirmSignInMFAForm confirmSignInWithTotpMfaCodeForm; + final ConfirmSignInMFAForm confirmSignInWithEmailMfaCodeForm; final ResetPasswordForm resetPasswordForm; final ConfirmResetPasswordForm confirmResetPasswordForm; final VerifyUserForm verifyUserForm; @@ -69,7 +71,7 @@ class InheritedForms extends InheritedWidget { case AuthenticatorStep.continueSignInWithEmailMfaSetup: return continueSignInWithEmailMfaSetupForm; case AuthenticatorStep.confirmSignInWithEmailMfaCode: - return confirmSignInMFAForm; + return confirmSignInWithEmailMfaCodeForm; case AuthenticatorStep.resetPassword: return resetPasswordForm; case AuthenticatorStep.confirmResetPassword: @@ -116,6 +118,8 @@ class InheritedForms extends InheritedWidget { continueSignInWithTotpSetupForm || oldWidget.confirmSignInWithTotpMfaCodeForm != confirmSignInWithTotpMfaCodeForm || + oldWidget.confirmSignInWithEmailMfaCodeForm != + confirmSignInWithEmailMfaCodeForm || oldWidget.continueSignInWithEmailMfaSetupForm != continueSignInWithEmailMfaSetupForm || oldWidget.continueSignInWithMfaSelectionForm != diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index 1c4477b91b..a9824be8c5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -230,8 +230,9 @@ abstract class AuthenticatorFormFieldState< case AuthenticatorStep.confirmSignInCustomAuth: state.confirmSignInCustomAuth(); case AuthenticatorStep.confirmSignInMfa: - case AuthenticatorStep.confirmSignInWithEmailMfaCode: state.confirmSignInMFA(); + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + state.confirmEmailMfa(); case AuthenticatorStep.confirmSignInNewPassword: state.confirmSignInNewPassword(); case AuthenticatorStep.confirmSignInWithTotpMfaCode: From 215dd2e78f86277be230c55888cb3d6737a39b76 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:49:16 -0700 Subject: [PATCH 059/159] chore: dart format --- .../lib/src/l10n/generated/title_localizations_en.dart | 3 ++- .../lib/src/screens/authenticator_screen.dart | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart index f547339bf5..692f579fa5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart @@ -34,7 +34,8 @@ class AuthenticatorTitleLocalizationsEn String get confirmSignInWithEmailMfaCode => 'Enter your one-time passcode'; @override - String get continueSignInWithEmailMfaSetup => 'Add Email for Two-Factor Authentication'; + String get continueSignInWithEmailMfaSetup => + 'Add Email for Two-Factor Authentication'; @override String get continueSignInWithMfaSetupSelection => diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index e547dfd9f0..2eeebb2f8b 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -47,7 +47,9 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { : this(key: key, step: AuthenticatorStep.continueSignInWithEmailMfaSetup); const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) - : this(key: key, step: AuthenticatorStep.continueSignInWithMfaSetupSelection); + : this( + key: key, + step: AuthenticatorStep.continueSignInWithMfaSetupSelection); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); From e16d6af0dd47830b2729eb726d093f5bae5ee5b6 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:57:21 -0700 Subject: [PATCH 060/159] chore: add trailing comma --- .../lib/src/screens/authenticator_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index 2eeebb2f8b..fd99bc74ba 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -49,7 +49,7 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) : this( key: key, - step: AuthenticatorStep.continueSignInWithMfaSetupSelection); + step: AuthenticatorStep.continueSignInWithMfaSetupSelection,); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); From b0023ac7e52af0fa0050912bdcdcec5e08d0491c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 1 Oct 2024 23:02:55 -0700 Subject: [PATCH 061/159] chore: dart format --- .../lib/src/screens/authenticator_screen.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index fd99bc74ba..e405a6a812 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -48,8 +48,9 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) : this( - key: key, - step: AuthenticatorStep.continueSignInWithMfaSetupSelection,); + key: key, + step: AuthenticatorStep.continueSignInWithMfaSetupSelection, + ); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); From 7b901af8e6f44923a9b658d127a98e3a3ec4afe4 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 7 Oct 2024 12:07:51 -0700 Subject: [PATCH 062/159] chore: fix auth.dart docs --- packages/amplify_core/doc/lib/auth.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/amplify_core/doc/lib/auth.dart b/packages/amplify_core/doc/lib/auth.dart index 6364ceb84a..5573052fba 100644 --- a/packages/amplify_core/doc/lib/auth.dart +++ b/packages/amplify_core/doc/lib/auth.dart @@ -107,7 +107,7 @@ Future resendSignUpCode(String username) async { // #docregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code, handle-confirm-signin-email-code, handle-confirm-signin-mfa-setup-selection, handle-confirm-signin-email-setup Future _handleSignInResult(SignInResult result) async { switch (result.nextStep.signInStep) { - // #enddocregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-email-code, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code, handle-confirm-signin-mfa-setup-selection, handle-confirm-signin-email-setup + // #enddocregion handle-signin, handle-confirm-signin-sms, handle-confirm-signin-new-password, handle-confirm-signin-custom-challenge, handle-confirm-signin-reset-password, handle-confirm-signin-confirm-signup, handle-confirm-signin-done, handle-confirm-signin-mfa-selection, handle-confirm-signin-totp-setup, handle-confirm-signin-totp-code, handle-confirm-signin-email-code, handle-confirm-signin-mfa-setup-selection, handle-confirm-signin-email-setup // #docregion handle-confirm-signin-mfa-selection case AuthSignInStep.continueSignInWithMfaSelection: final allowedMfaTypes = result.nextStep.allowedMfaTypes!; @@ -121,6 +121,7 @@ Future _handleSignInResult(SignInResult result) async { return _handleMfaSetupSelection(allowedMfaTypes.first); } final selection = await _promptUserPreference(allowedMfaTypes); + safePrint('Selected MFA type: $selection'); return _handleMfaSetupSelection(selection); // #enddocregion handle-confirm-signin-mfa-setup-selection // #docregion handle-confirm-signin-totp-setup @@ -262,7 +263,7 @@ Future _handleMfaSetupSelection(MfaType selection) async { ); return _handleSignInResult(result); } on AuthException catch (e) { - safePrint('Error resending code: ${e.message}'); + safePrint('Error selecting MFA method: ${e.message}'); } } // #enddocregion handle-mfa-setup-selection From 66097f2af8fdad60c6be8ac5d2428431138c675b Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:15:51 -0700 Subject: [PATCH 063/159] chore: moved ChallengeNameType.mfaSetup switch statement logic to a helper method --- .../state/machines/sign_in_state_machine.dart | 108 ++++++++++-------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 39c6314a07..6e6a121ceb 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -330,55 +330,8 @@ final class SignInStateMachine createEmailMfaRequest(event), ChallengeNameType.selectMfaType when hasUserResponse => createSelectMfaRequest(event), - ChallengeNameType.mfaSetup => (() async { - final allowedMfaTypes = _allowedMfaTypes; - if (allowedMfaTypes == null || allowedMfaTypes.isEmpty) { - throw const InvalidUserPoolConfigurationException( - 'No MFA types are allowed for setup.', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - // Exclude MfaType.sms from consideration - final mfaTypesForSetup = allowedMfaTypes.difference({MfaType.sms}); - if (mfaTypesForSetup.isEmpty) { - throw const InvalidUserPoolConfigurationException( - 'No eligible MFA types are available for setup.', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - if (mfaTypesForSetup.length == 1) { - final mfaType = mfaTypesForSetup.first; - if (mfaType == MfaType.totp) { - _enableMfaType = MfaType.totp; - _totpSetupResult ??= await associateSoftwareToken(); - if (hasUserResponse) { - return createMfaSetupRequest(event); - } else { - // Need to prompt user for the TOTP code - return null; - } - } else if (mfaType == MfaType.email) { - _enableMfaType = MfaType.email; - if (hasUserResponse) { - return createEmailMfaSetupRequest(event); - } else { - // Need to prompt user for the email verification code - return null; - } - } else { - throw InvalidUserPoolConfigurationException( - 'Unsupported MFA type: ${mfaType.name}', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - } else if (hasUserResponse) { - // Handle user's selection - return createMfaSetupRequest(event); - } else { - // Need to prompt user to select an MFA type - return null; - } - })(), + ChallengeNameType.mfaSetup => + handleMfaSetup(event: event, hasUserResponse: hasUserResponse), ChallengeNameType.newPasswordRequired when hasUserResponse => createNewPasswordRequest(event), _ => null, @@ -698,6 +651,63 @@ final class SignInStateMachine } } + /// Handles the MFA setup challenge. + @protected + Future handleMfaSetup({ + SignInEvent? event, + required bool hasUserResponse, + }) async { + final allowedMfaTypes = _allowedMfaTypes; + if (allowedMfaTypes == null || allowedMfaTypes.isEmpty) { + throw const InvalidUserPoolConfigurationException( + 'No MFA types are allowed for setup.', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + + // Exclude MfaType.sms from consideration + final mfaTypesForSetup = allowedMfaTypes.difference({MfaType.sms}); + if (mfaTypesForSetup.isEmpty) { + throw const InvalidUserPoolConfigurationException( + 'No eligible MFA types are available for setup.', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + + if (mfaTypesForSetup.length == 1) { + final mfaType = mfaTypesForSetup.first; + if (mfaType == MfaType.totp) { + _enableMfaType = MfaType.totp; + _totpSetupResult ??= await associateSoftwareToken(); + if (hasUserResponse) { + return createMfaSetupRequest(event as SignInRespondToChallenge); + } else { + // Need to prompt user for the TOTP code + return null; + } + } else if (mfaType == MfaType.email) { + _enableMfaType = MfaType.email; + if (hasUserResponse) { + return createEmailMfaSetupRequest(event as SignInRespondToChallenge); + } else { + // Need to prompt user for the email verification code + return null; + } + } else { + throw InvalidUserPoolConfigurationException( + 'Unsupported MFA type: ${mfaType.name}', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + } else if (hasUserResponse) { + // Handle user's selection + return createMfaSetupRequest(event as SignInRespondToChallenge); + } else { + // Need to prompt user to select an MFA type + return null; + } + } + /// Completes set up of a TOTP MFA. @protected Future createMfaSetupRequest( From 0fdcc15bbfe8784656e4b3df4c3b072a5240ea11 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:27:53 -0700 Subject: [PATCH 064/159] chore: flatten an if statement in the helper method by adding mfaTypesForSetup in the first if statement --- .../src/state/machines/sign_in_state_machine.dart | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 6e6a121ceb..948a68cb2c 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -658,18 +658,11 @@ final class SignInStateMachine required bool hasUserResponse, }) async { final allowedMfaTypes = _allowedMfaTypes; - if (allowedMfaTypes == null || allowedMfaTypes.isEmpty) { - throw const InvalidUserPoolConfigurationException( - 'No MFA types are allowed for setup.', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - // Exclude MfaType.sms from consideration - final mfaTypesForSetup = allowedMfaTypes.difference({MfaType.sms}); - if (mfaTypesForSetup.isEmpty) { + final mfaTypesForSetup = allowedMfaTypes?.difference({MfaType.sms}); + if (allowedMfaTypes == null || allowedMfaTypes.isEmpty || mfaTypesForSetup == null || mfaTypesForSetup.isEmpty) { throw const InvalidUserPoolConfigurationException( - 'No eligible MFA types are available for setup.', + 'No eligible MFA types are allowed for setup.', recoverySuggestion: 'Check your user pool MFA configuration.', ); } From e630a30c59947125ac3dd053e42f756f1c36283d Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:39:24 -0700 Subject: [PATCH 065/159] chore: dart format --- .../lib/src/state/machines/sign_in_state_machine.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 948a68cb2c..c0311d1f78 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -660,7 +660,10 @@ final class SignInStateMachine final allowedMfaTypes = _allowedMfaTypes; // Exclude MfaType.sms from consideration final mfaTypesForSetup = allowedMfaTypes?.difference({MfaType.sms}); - if (allowedMfaTypes == null || allowedMfaTypes.isEmpty || mfaTypesForSetup == null || mfaTypesForSetup.isEmpty) { + if (allowedMfaTypes == null || + allowedMfaTypes.isEmpty || + mfaTypesForSetup == null || + mfaTypesForSetup.isEmpty) { throw const InvalidUserPoolConfigurationException( 'No eligible MFA types are allowed for setup.', recoverySuggestion: 'Check your user pool MFA configuration.', From 334e8b3dead6cec863fb96d478cc77d5016c904a Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:04:16 -0700 Subject: [PATCH 066/159] chore: remove extra if checks and add null check --- .../lib/src/state/machines/sign_in_state_machine.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index c0311d1f78..5d65b00f8e 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -661,16 +661,14 @@ final class SignInStateMachine // Exclude MfaType.sms from consideration final mfaTypesForSetup = allowedMfaTypes?.difference({MfaType.sms}); if (allowedMfaTypes == null || - allowedMfaTypes.isEmpty || - mfaTypesForSetup == null || - mfaTypesForSetup.isEmpty) { + allowedMfaTypes.isEmpty) { throw const InvalidUserPoolConfigurationException( 'No eligible MFA types are allowed for setup.', recoverySuggestion: 'Check your user pool MFA configuration.', ); } - if (mfaTypesForSetup.length == 1) { + if (mfaTypesForSetup!.length == 1) { final mfaType = mfaTypesForSetup.first; if (mfaType == MfaType.totp) { _enableMfaType = MfaType.totp; From 87bb72ba66bceb674f4d40aba82d73dbf198379c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:16:16 -0700 Subject: [PATCH 067/159] chore: dart format --- .../lib/src/state/machines/sign_in_state_machine.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 5d65b00f8e..b5ee708705 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -660,8 +660,7 @@ final class SignInStateMachine final allowedMfaTypes = _allowedMfaTypes; // Exclude MfaType.sms from consideration final mfaTypesForSetup = allowedMfaTypes?.difference({MfaType.sms}); - if (allowedMfaTypes == null || - allowedMfaTypes.isEmpty) { + if (allowedMfaTypes == null || allowedMfaTypes.isEmpty) { throw const InvalidUserPoolConfigurationException( 'No eligible MFA types are allowed for setup.', recoverySuggestion: 'Check your user pool MFA configuration.', From c4ee27de24f33b497a917e590885304df9f78d18 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:21:05 -0700 Subject: [PATCH 068/159] chore: add back in mfaTypesForSetup instead of allowedMfaTypes --- .../lib/src/state/machines/sign_in_state_machine.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index b5ee708705..725f66b9d1 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -660,14 +660,14 @@ final class SignInStateMachine final allowedMfaTypes = _allowedMfaTypes; // Exclude MfaType.sms from consideration final mfaTypesForSetup = allowedMfaTypes?.difference({MfaType.sms}); - if (allowedMfaTypes == null || allowedMfaTypes.isEmpty) { + if (mfaTypesForSetup == null || mfaTypesForSetup.isEmpty) { throw const InvalidUserPoolConfigurationException( 'No eligible MFA types are allowed for setup.', recoverySuggestion: 'Check your user pool MFA configuration.', ); } - if (mfaTypesForSetup!.length == 1) { + if (mfaTypesForSetup.length == 1) { final mfaType = mfaTypesForSetup.first; if (mfaType == MfaType.totp) { _enableMfaType = MfaType.totp; From c89773baa292995abd11beca1afe6cdeb94fcb8c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 2 Aug 2024 16:33:08 -0700 Subject: [PATCH 069/159] chore: add ChallengeName --- .../model/challenge_name_type.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart index 245f07151e..29df69b192 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart @@ -80,6 +80,12 @@ class ChallengeNameType extends _i1.SmithyEnum { 'SOFTWARE_TOKEN_MFA', ); + static const emailMfa = ChallengeNameType._( + 10, + 'EMAIL_MFA', + 'EMAIL_MFA', + ); + /// All values of [ChallengeNameType]. static const values = [ ChallengeNameType.adminNoSrpAuth, @@ -93,6 +99,7 @@ class ChallengeNameType extends _i1.SmithyEnum { ChallengeNameType.selectMfaType, ChallengeNameType.smsMfa, ChallengeNameType.softwareTokenMfa, + ChallengeNameType.emailMfa, ]; static const List<_i1.SmithySerializer> serializers = [ From 255aaa64701052e38f369e537f6f355ac8eb8488 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:46:40 -0700 Subject: [PATCH 070/159] Revert "chore: add ChallengeName" This reverts commit 04fbd0c4ebd073fe291d95abfb5f33aa8bfe1f50. --- .../model/challenge_name_type.dart | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart index 29df69b192..245f07151e 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/src/cognito_identity_provider/model/challenge_name_type.dart @@ -80,12 +80,6 @@ class ChallengeNameType extends _i1.SmithyEnum { 'SOFTWARE_TOKEN_MFA', ); - static const emailMfa = ChallengeNameType._( - 10, - 'EMAIL_MFA', - 'EMAIL_MFA', - ); - /// All values of [ChallengeNameType]. static const values = [ ChallengeNameType.adminNoSrpAuth, @@ -99,7 +93,6 @@ class ChallengeNameType extends _i1.SmithyEnum { ChallengeNameType.selectMfaType, ChallengeNameType.smsMfa, ChallengeNameType.softwareTokenMfa, - ChallengeNameType.emailMfa, ]; static const List<_i1.SmithySerializer> serializers = [ From d7a5700d4e4e17a3a25beaa3c7fbf062455fd0bb Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 12 Sep 2024 16:45:05 -0700 Subject: [PATCH 071/159] chore: merge main (#5449) * chore(api): update endpoint config to use ApiOutputs instead of AWSApiConfig type (#5193) * feat: bump json_annotation dependency to v4.9 * chore: update actions workflow to run aft link * chore(secure_storage): Plugin Endorsement (#5208) * chore(infra): bump deps (#5221) * chore(test): use Amplify Gen 2 config in unit tests (#5205) * chore: add testUrlScheme back to test (#5223) * chore: add gen2 auth e2e infra (#5179) * chore(infra): Api migrate to Gen 2 E2E * fix: git update-index --chmod=+x * fix: code review * chore: port auth backend * chore: port lambda triggers for create user and custom email sender * chore: move utils to infra-common * chore: compile infra common to js * chore: update utils for js restructure, add missing deps * chore: fix confirmation code infra * chore: update tests to run for gen2 stacks * chore: remove alias from custom sender lambda * chore: fix deliveryMedium in reset password test * chore: add phone sign in infra * chore: rename email-sign-in * chore: add license header * chore: fix formatting in GH workflow * chore: update package-lock * chore: remove deleted file * chore: fix formatting * chore: update package lock * chore: remove dup function * chore: remove changes from merge conflicts * chore: fix build script * chore: fetch auth amplify_outputs * chore: remove libgit2dart * chore: add custom sms sender * chore: add stack name to infra resources * chore: pull gen2 backend for authenticator * chore: update package-lock * chore: move dependencies to dev_dependencies * chore: update fetch auth session tests * chore: separate reset pw and confirmation delivery medium * chore: fix hanging test * chore: rename test group * chore: update comments, remove unused type * chore: update package lock --------- Co-authored-by: Elijah Quartey * chore(auth): sign-up state machine to use AmplifyOutputs instead of AmplifyConfig types (#5230) * chore(auth): sign-in state machine to use AmplifyOutputs instead of AmplifyConfig types (#5231) * chore(auth): fetch auth session state machine to use AmplifyOutputs instead of AmplifyConfig types (#5234) * chore(auth): sign-out state machine to use AmplifyOutputs instead of AmplifConfig types (#5235) * chore(actions): android emulator to start with clear cache and data (#5245) * chore(actions): e2e android tests to run with API 34 (#5247) * chore(infra): bump deps (#5246) Updated @aws-sdk/client-amplify @aws-sdk/client-cognito-identity-provider @aws-crypto/client-node @aws-sdk/client-s3 * chore(auth): cognito keys to not use AmplifyConfig types (#5243) * chore(auth): hosted ui state machine to not use AmplifyConfig types (#5254) * fix(datastore): Clear subscriptions on Stop (#5253) * Chore/goldens flutter lint (#5271) * temp: generate goldens png * test: fixing context mounted issue * chore: add todo comment about deprecated member use --------- Co-authored-by: Andrew Hahn * chore(infra): analytics integ test gen 2 backend (#5104) * chore(auth): device metadata repository to use AuthOutputs instead of CognitoUserPoolConfig (#5289) * feat(Auth): Add fetchCurrentDevice API (#5251) feat(Auth): Add fetchCurrentDevice API (#5251) * chore(dependencies): bump package_info_plus (#5274) chore: bump package_info_plus * chore: migrate sms only MFA infra to Gen 2 (#5291) * chore: add new auth backend * chore: add auth extension * chore: add license headers * chore: add mfa to env * chore: add trigger to enable MFA * chore: add infra for sms required * chore: refactor tests for gen 2 backends * chore: add backends to deploy script * chore: package-lock for mfa-required-sms * chore: remove bundling of @aws-crypto/client-node * chore: fix formatting * fix(datastore): Restart Sync Engine when network on/off (#5218) * chore: update authenticator tests (#5296) * chore(auth): hosted ui platforms to use AmplifyOutputs types instead of AmplifyConfig (#5273) * chore(auth): asf context data provider to use AuthOutputs instead of CognitoUserPoolConfig (#5290) * chore(auth): fix fetch current device test (#5297) * fix: push notification flush events (#5215) fix: push notification flush events (#5215) * chore(dependencies): bump build_runner (#5300) * chore(dependencies): bump build_runner * chore(bump): checks package (#5305) * chore(bump): checks package * chore(version): Bump version chore(): Fixed Version Bumps chore: fixed change log chore: fixed change log chore: fixed change log chore: fixed change log * chore: manually bump amplify_db_common version * chore(infra): Extend API key expiration (#5336) * chore(dev): use ubuntu image from amazon ECR public gallery instead of docket hub (#5341) * fix(api): web socket error handling (#5359) * chore: update issue template (#5369) * fix(datastore): FlutterSerializedModel.extractJsonValue returns `.some(nil)` instead of `nil` (#5370) * chore: add GH actions for issue open, close, comment, label events (#5310) * fix(secure_storage): add missing macOS plugin (#5372) fix(secure_storage): add missing macos plugin it's fixing #5361 * chore: update plugin registrant for example apps that depend on secure storage (#5379) * chore(version): Bump version - fix(secure_storage): add missing macOS plugin ([#5372](https://github.com/aws-amplify/amplify-flutter/pull/5372)) Updated-Components: Secure Storage * chore(deps): Amplify Android 2.21.1 (#5376) * update amplify android to latest * update amplify android to latest in notifications * feat(aws_common): Generated new AWSService constructors (#5378) * chore(infra): regen lock file (#5374) * chore(auth): credential store state machine to use AuthOutputs instead of AmplifyConfig types (#5298) * chore(api): Remove Gen 1 API backend (#5393) * chore(datastore): Add multi auth integration tests (#5204) * feat: move App Sync subscription headers to protocol (#5301) * chore: move subscription headers to protocol * fix: remove `=` from encoded headers * chore: add comment * chore: `aft version-bump` test suite (#5424) * chore: add `--skip-build-version` option * chore: use `base-ref`/`head-ref` over env vars * chore: add new version bump test suite * chore: remove old version bump tests * chore: only include first change log entry * fix: sort change types before writing to the change log * chore: remove non essential info from diffs * chore: generate repo snapshot * chore: generate diff snapshots * chore: clean up tests and test output * chore: update `aft generate workflows`, regenerate dependabot.yaml (#5441) * chore: skip repo snapshot in dependabot generation * chore: regenerate dependabot.yaml * chore: fix `aft version-bump` (#5436) * fix: properly handle component propagation * chore: add test for multi package update with breaking common package --------- Co-authored-by: NikaHsn Co-authored-by: Jordan Nelson Co-authored-by: Elijah Quartey Co-authored-by: Elijah Quartey Co-authored-by: Tyler-Larkin Co-authored-by: Andrew Hahn Co-authored-by: Andrew Hahn <58017052+hahnandrew@users.noreply.github.com> Co-authored-by: Burak Karahan Co-authored-by: Jamil Saadeh --- infra-gen2/package-lock.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/infra-gen2/package-lock.json b/infra-gen2/package-lock.json index 806c800dd6..191c337b64 100644 --- a/infra-gen2/package-lock.json +++ b/infra-gen2/package-lock.json @@ -4462,6 +4462,18 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.624.0", + "@aws-sdk/client-sts": "3.624.0", + "@aws-sdk/core": "3.624.0", + "@aws-sdk/credential-provider-node": "3.624.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-sdk-ec2": "3.622.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", @@ -4474,9 +4486,27 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.624.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.14", + "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { @@ -4592,6 +4622,8 @@ "license": "Apache-2.0", "dependencies": { "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { @@ -4606,6 +4638,7 @@ "dependencies": { "@smithy/eventstream-serde-universal": "^3.0.5", "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" }, "engines": { From 479a034eecf5da12c9c3f7937ab659d90b10d06b Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:05:01 -0700 Subject: [PATCH 072/159] chore: revert package-lock.json changes --- infra-gen2/package-lock.json | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/infra-gen2/package-lock.json b/infra-gen2/package-lock.json index 191c337b64..806c800dd6 100644 --- a/infra-gen2/package-lock.json +++ b/infra-gen2/package-lock.json @@ -4462,18 +4462,6 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.624.0", - "@aws-sdk/client-sts": "3.624.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-sdk-ec2": "3.622.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", @@ -4486,27 +4474,9 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { @@ -4622,8 +4592,6 @@ "license": "Apache-2.0", "dependencies": { "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { @@ -4638,7 +4606,6 @@ "dependencies": { "@smithy/eventstream-serde-universal": "^3.0.5", "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" }, "engines": { From 1eefc27c3285b780400434c359eedebcdd991608 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:37:00 -0700 Subject: [PATCH 073/159] chore: add new AuthenticatorStep to switch statements in screen --- .../lib/src/screens/authenticator_screen.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index 181816a0ba..f01f3111fd 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -91,6 +91,9 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { case AuthenticatorStep.confirmResetPassword: case AuthenticatorStep.verifyUser: case AuthenticatorStep.confirmVerifyUser: + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + case AuthenticatorStep.continueSignInWithMfaSetupSelection: child = _FormWrapperView(step: step); case AuthenticatorStep.loading: throw StateError('Invalid step: $this'); @@ -299,6 +302,9 @@ extension on AuthenticatorStep { case AuthenticatorStep.verifyUser: case AuthenticatorStep.confirmVerifyUser: case AuthenticatorStep.loading: + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + case AuthenticatorStep.continueSignInWithMfaSetupSelection: throw StateError('Invalid step: $this'); } } From fd0db6f561c20583b58a85c6a06a819ec4107993 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:00:12 -0700 Subject: [PATCH 074/159] chore: add input resolvers and localizations --- .../generated/input_localizations_en.dart | 3 +++ .../l10n/generated/title_localizations.dart | 18 ++++++++++++++ .../lib/src/l10n/input_resolver.dart | 2 +- .../lib/src/l10n/title_resolver.dart | 24 +++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart index 6b6d42a494..300acbc706 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart @@ -159,4 +159,7 @@ class AuthenticatorInputLocalizationsEn @override String get totpCodePrompt => 'Please enter the code from your registered Authenticator app'; + + @override + String get selectEmail => 'Email'; } diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart index 6d69ec3571..96b09f3830 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart @@ -141,6 +141,24 @@ abstract class AuthenticatorTitleLocalizations { /// **'Enter your one-time passcode'** String get confirmSignInWithTotpMfaCode; + /// Title of the Confirm Sign In with Email MFA Code step and form + /// + /// In en, this message translates to: + /// **'Enter your one-time passcode'** + String get confirmSignInWithEmailMfaCode; + + /// Title of the Continue Sign In with Email MFA Setup step and form + /// + /// In en, this message translates to: + /// **'Set up Email Two-Factor Auth'** + String get continueSignInWithEmailMfaSetup; + + /// Title of the Continue Sign In with MFA Setup Selection step and form + /// + /// In en, this message translates to: + /// **'Select a Two-Factor Auth method to set up'** + String get continueSignInWithMfaSetupSelection; + /// Title of the Reset Password step and form /// /// In en, this message translates to: diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart index 4b04f86962..0eb96b26f1 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart @@ -174,7 +174,7 @@ class InputResolverKey { static const selectEmail = InputResolverKey._( InputResolverKeyType.title, - field: InputField.email, + field: InputField.selectEmail, ); static const totpCodePrompt = InputResolverKey._( diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart index bbbf34925c..e5c1b19480 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart @@ -49,6 +49,24 @@ class TitleResolver extends Resolver { .confirmSignInWithTotpMfaCode; } + /// The title for the confirm sign in (email MFA code) Widget. + String confirmSignInWithEmailMfaCode(BuildContext context) { + return AuthenticatorLocalizations.titlesOf(context) + .confirmSignInWithEmailMfaCode; + } + + /// The title for the continue sign in (email MFA setup) Widget. + String continueSignInWithEmailMfaSetup(BuildContext context) { + return AuthenticatorLocalizations.titlesOf(context) + .continueSignInWithEmailMfaSetup; + } + + /// The title for the continue sign in (mfa setup selection) Widget. + String continueSignInWithMfaSetupSelection(BuildContext context) { + return AuthenticatorLocalizations.titlesOf(context) + .continueSignInWithMfaSetupSelection; + } + /// The title for the reset password Widget. String resetPassword(BuildContext context) { return AuthenticatorLocalizations.titlesOf(context).resetPassword; @@ -81,6 +99,12 @@ class TitleResolver extends Resolver { return continueSignInWithTotpSetup(context); case AuthenticatorStep.confirmSignInWithTotpMfaCode: return confirmSignInWithTotpMfaCode(context); + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + return confirmSignInWithEmailMfaCode(context); + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + return continueSignInWithEmailMfaSetup(context); + case AuthenticatorStep.continueSignInWithMfaSetupSelection: + return continueSignInWithMfaSetupSelection(context); case AuthenticatorStep.resetPassword: return resetPassword(context); case AuthenticatorStep.confirmResetPassword: From 2f466d75bb71f2d55b8332e56ab409a35c7cab3b Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:00:58 -0700 Subject: [PATCH 075/159] chore: add keys and enums --- .../amplify_authenticator/lib/src/enums/enums.dart | 1 + .../amplify_authenticator/lib/src/keys.dart | 5 +++++ .../lib/src/l10n/generated/title_localizations_en.dart | 10 ++++++++++ .../lib/src/l10n/src/inputs/inputs_en.arb | 6 +++++- .../amplify_authenticator/lib/src/widgets/form.dart | 2 +- 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/enums/enums.dart b/packages/authenticator/amplify_authenticator/lib/src/enums/enums.dart index f523de2aa8..3a4b577678 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/enums/enums.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/enums/enums.dart @@ -4,6 +4,7 @@ export 'authenticator_step.dart'; export 'confirm_signin_types.dart'; export 'confirm_signup_types.dart'; +export 'email_setup_types.dart'; export 'gender.dart'; export 'reset_password_field.dart'; export 'signin_types.dart'; diff --git a/packages/authenticator/amplify_authenticator/lib/src/keys.dart b/packages/authenticator/amplify_authenticator/lib/src/keys.dart index 49510ea7cf..bdc58969a1 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/keys.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/keys.dart @@ -140,3 +140,8 @@ const keyAuthenticatorBanner = Key('authenticatorBanner'); const keyQrCodeTotpSetupFormField = Key('qrCodeTotpSetupFormField'); const keyCopyKeyTotpSetupFormField = Key('copyKeyTotpSetupFormField'); const keyTotpSetupFormField = Key('totpSetupFormField'); + +// Email setup form keys +const keyEmailSetupFormField = Key('emailSetupFormField'); +const keyVerificationCodeEmailSetupFormField = + Key('verificationCodeEmailSetupFormField'); diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart index 02fb43da7d..3f3ca2b794 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart @@ -30,6 +30,16 @@ class AuthenticatorTitleLocalizationsEn @override String get confirmSignInWithTotpMfaCode => 'Enter your one-time passcode'; + @override + String get confirmSignInWithEmailMfaCode => 'Enter your one-time passcode'; + + @override + String get continueSignInWithEmailMfaSetup => 'Set up Email Two-Factor Auth'; + + @override + String get continueSignInWithMfaSetupSelection => + 'Select a Two-Factor Auth method to set up'; + @override String get resetPassword => 'Send Code'; diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/src/inputs/inputs_en.arb b/packages/authenticator/amplify_authenticator/lib/src/l10n/src/inputs/inputs_en.arb index 90399598d1..e32dd76731 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/src/inputs/inputs_en.arb +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/src/inputs/inputs_en.arb @@ -216,5 +216,9 @@ "totpCodePrompt": "Please enter the code from your registered Authenticator app", "@totpCodePrompt": { "description": "The instructional text for submitting a TOTP pass code" - } + }, + "selectEmail": "Email", + "@selectEmail": { + "description": "Label for the radio button to select email as the user's chosen MFA method." + }, } diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index 301b61177c..59aa9f2689 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -544,7 +544,7 @@ class ConfirmSignInCustomAuthForm extends AuthenticatorForm { /// {@category Prebuilt Widgets} /// {@template amplify_authenticator.confirm_sign_in_mfa_form} /// A prebuilt form for completing the sign in process with an MFA code, from -/// either SMS or TOTP. +/// either SMS, TOTP, or Email. /// {@endtemplate} class ConfirmSignInMFAForm extends AuthenticatorForm { /// {@macro amplify_authenticator.confirm_sign_in_mfa_form} From 69fa04e846ef5723ee63040cdcf9e737334d47e7 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:02:06 -0700 Subject: [PATCH 076/159] chore: add select email input resolver --- .../amplify_authenticator/lib/src/l10n/input_resolver.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart index 0eb96b26f1..27626a8a6f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart @@ -466,6 +466,8 @@ class InputResolver extends Resolver { return AuthenticatorLocalizations.inputsOf(context).selectEmail; case InputField.totpCodePrompt: return AuthenticatorLocalizations.inputsOf(context).totpCodePrompt; + case InputField.selectEmail: + return AuthenticatorLocalizations.inputsOf(context).selectEmail; case InputField.usernameType: return AuthenticatorLocalizations.inputsOf(context).usernameType; } From 059213dae2e8c608293090b96bed30513e76f738 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:35:17 -0700 Subject: [PATCH 077/159] chore: add EmailSetupField type for authenticator --- .../lib/src/enums/email_setup_types.dart | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart diff --git a/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart b/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart new file mode 100644 index 0000000000..a5f608d04b --- /dev/null +++ b/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +enum EmailSetupField { + email, + code, +} From 111f35ee500215e3f50e3e14bbe661724f83e981 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:03:41 -0700 Subject: [PATCH 078/159] chore: add switch cases for future implementations of the forms --- .../lib/src/state/inherited_forms.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index a2a0dfa5ae..6511ba682f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -55,10 +55,16 @@ class InheritedForms extends InheritedWidget { return confirmSignInNewPasswordForm; case AuthenticatorStep.continueSignInWithMfaSelection: return continueSignInWithMfaSelectionForm; + case AuthenticatorStep.continueSignInWithMfaSetupSelection: + // TODO(khatruong2009): Implement this form case AuthenticatorStep.continueSignInWithTotpSetup: return continueSignInWithTotpSetupForm; case AuthenticatorStep.confirmSignInWithTotpMfaCode: return confirmSignInWithTotpMfaCodeForm; + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + // TODO(khatruong2009): Implement this form + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + // TODO(khatruong2009): Implement this form case AuthenticatorStep.resetPassword: return resetPasswordForm; case AuthenticatorStep.confirmResetPassword: From 8f2ccdfcd1f24afe4abef38d27bd86c0170e0425 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:53:46 -0700 Subject: [PATCH 079/159] chore: add authenticator step cases for sign in with email mfa --- .../amplify_authenticator/lib/src/widgets/form_field.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index f53a94b831..e8ba9fe1ae 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -28,6 +28,7 @@ import 'package:qr_flutter/qr_flutter.dart'; part 'form_fields/confirm_sign_in_form_field.dart'; part 'form_fields/confirm_sign_up_form_field.dart'; +part 'form_fields/email_setup_form_field.dart'; part 'form_fields/mfa_selection_form_field.dart'; part 'form_fields/phone_number_field.dart'; part 'form_fields/reset_password_form_field.dart'; @@ -228,12 +229,15 @@ abstract class AuthenticatorFormFieldState< case AuthenticatorStep.confirmSignInCustomAuth: state.confirmSignInCustomAuth(); case AuthenticatorStep.confirmSignInMfa: + case AuthenticatorStep.confirmSignInWithEmailMfaCode: state.confirmSignInMFA(); case AuthenticatorStep.confirmSignInNewPassword: state.confirmSignInNewPassword(); case AuthenticatorStep.confirmSignInWithTotpMfaCode: case AuthenticatorStep.continueSignInWithTotpSetup: state.confirmTotp(); + case AuthenticatorStep.continueSignInWithEmailMfaSetup: + state.continueEmailMfaSetup(); case AuthenticatorStep.resetPassword: state.resetPassword(); case AuthenticatorStep.confirmResetPassword: From db1409aab7d2ea9e1aef405c997ee5e93e3d8986 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:56:31 -0700 Subject: [PATCH 080/159] chore: remove code from email setup field because only email is needed --- .../amplify_authenticator/lib/src/enums/email_setup_types.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart b/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart index a5f608d04b..88252cb4e5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/enums/email_setup_types.dart @@ -3,5 +3,4 @@ enum EmailSetupField { email, - code, } From bafad94b6818137e8392f651df95eef1d7a9d354 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:14:55 -0700 Subject: [PATCH 081/159] chore: add mfa email to authenticator state --- .../lib/src/state/authenticator_state.dart | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart index 10bdef835b..38c630da49 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart @@ -160,6 +160,18 @@ class AuthenticatorState extends ChangeNotifier { notifyListeners(); } + /// The value for the email MFA setup form field + /// + /// This value will be used during continue email MFA setup + String get mfaEmail => _mfaEmail; + + set mfaEmail(String value) { + _mfaEmail = value.trim(); + notifyListeners(); + } + + String _mfaEmail = ''; + MfaType? _selectedMfaMethod; TotpSetupDetails? get totpSetupDetails { @@ -414,6 +426,23 @@ class AuthenticatorState extends ChangeNotifier { _setIsBusy(false); } + /// Complete MFA setup using the values for [confirmationCode] + Future continueEmailMfaSetup() async { + if (!_formKey.currentState!.validate()) { + return; + } + + _setIsBusy(true); + + final confirm = AuthConfirmSignInData( + confirmationValue: _mfaEmail.trim(), + ); + + _authBloc.add(AuthConfirmSignIn(confirm)); + await nextBlocEvent(); + _setIsBusy(false); + } + /// Complete the force password change with [newPassword] Future confirmSignInNewPassword() async { if (!_formKey.currentState!.validate()) { From c4b809bdd54f63c65206c73503e304ec21db7c28 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:35:24 -0700 Subject: [PATCH 082/159] chore: add email mfa setup form and form field --- .../lib/amplify_authenticator.dart | 2 + .../lib/src/state/inherited_forms.dart | 8 ++ .../lib/src/widgets/form.dart | 22 +++++ .../form_fields/email_setup_form_field.dart | 90 +++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart diff --git a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart index bd71bfdf0b..8cfaf5ab79 100644 --- a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart +++ b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart @@ -77,6 +77,7 @@ export 'src/widgets/form.dart' ConfirmSignInNewPasswordForm, ContinueSignInWithMfaSelectionForm, ContinueSignInWithTotpSetupForm, + ContinueSignInWithEmailMfaSetupForm, ConfirmSignUpForm, ResetPasswordForm, ConfirmResetPasswordForm, @@ -712,6 +713,7 @@ class _AuthenticatorState extends State { ContinueSignInWithMfaSelectionForm(), continueSignInWithTotpSetupForm: ContinueSignInWithTotpSetupForm(), + continueSignInWithEmailMfaSetupForm: ContinueSignInWithEmailMfaSetupForm(), confirmSignInWithTotpMfaCodeForm: ConfirmSignInMFAForm(), verifyUserForm: VerifyUserForm(), confirmVerifyUserForm: ConfirmVerifyUserForm(), diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index 6511ba682f..ad3c0f93a4 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -17,6 +17,7 @@ class InheritedForms extends InheritedWidget { required this.confirmSignInNewPasswordForm, required this.continueSignInWithMfaSelectionForm, required this.continueSignInWithTotpSetupForm, + required this.continueSignInWithEmailMfaSetupForm, required this.confirmSignInWithTotpMfaCodeForm, required this.verifyUserForm, required this.confirmVerifyUserForm, @@ -31,6 +32,7 @@ class InheritedForms extends InheritedWidget { final ConfirmSignInNewPasswordForm confirmSignInNewPasswordForm; final ContinueSignInWithMfaSelectionForm continueSignInWithMfaSelectionForm; final ContinueSignInWithTotpSetupForm continueSignInWithTotpSetupForm; + final ContinueSignInWithEmailMfaSetupForm continueSignInWithEmailMfaSetupForm; final ConfirmSignInMFAForm confirmSignInWithTotpMfaCodeForm; final ResetPasswordForm resetPasswordForm; final ConfirmResetPasswordForm confirmResetPasswordForm; @@ -112,6 +114,12 @@ class InheritedForms extends InheritedWidget { oldWidget.confirmSignInWithTotpMfaCodeForm != confirmSignInWithTotpMfaCodeForm; } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('continueSignInWithEmailMfaSetupForm', continueSignInWithEmailMfaSetupForm)); + } } // ignore_for_file: prefer_asserts_with_message diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index 59aa9f2689..9c91c3fb0d 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -646,6 +646,28 @@ class ContinueSignInWithTotpSetupForm extends AuthenticatorForm { AuthenticatorFormState(); } +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.continue_sign_in_with_email_mfa_setup_form} +/// A prebuilt form for completing the email mfa setup process. +/// {@endtemplate} +class ContinueSignInWithEmailMfaSetupForm extends AuthenticatorForm { + ContinueSignInWithEmailMfaSetupForm({ + super.key, + }) : super._( + fields: [ + EmailSetupFormField.email(), + ], + actions: const [ + ConfirmSignInMFAButton(), + BackToSignInButton(), + ], + ); + + @override + AuthenticatorFormState createState() => + AuthenticatorFormState(); +} + /// {@category Prebuilt Widgets} /// {@template amplify_authenticator.send_code_form} /// A prebuilt form for initiating the reset password flow. diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart new file mode 100644 index 0000000000..06647ee4f9 --- /dev/null +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart @@ -0,0 +1,90 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +part of '../form_field.dart'; + +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.email_setup_form_field} +/// A prebuilt form field widget for use on the Email MFA setup step. +/// {@endtemplate} +abstract class EmailSetupFormField + extends AuthenticatorFormField { + /// {@macro amplify_authenticator.email_setup_form_field} + /// + /// Either [titleKey] or [title] is required. + const EmailSetupFormField._({ + super.key, + required super.field, + super.titleKey, + super.hintTextKey, + super.title, + super.hintText, + super.validator, + super.autofillHints, + }) : super._(); + + /// Creates an email component. + static EmailSetupFormField email({ + Key? key, + FormFieldValidator? validator, + Iterable? autofillHints, + }) => + _EmailSetupTextField( + key: key ?? keyEmailSetupFormField, + titleKey: InputResolverKey.emailTitle, + hintTextKey: InputResolverKey.emailHint, + field: EmailSetupField.email, + validator: validator, + autofillHints: autofillHints, + ); +} + +abstract class _EmailSetupFormFieldState + extends AuthenticatorFormFieldState> { + @override + TextInputType get keyboardType { + return TextInputType.emailAddress; + } + + @override + Iterable? get autofillHints { + return [AutofillHints.email]; + } + + @override + bool get required { + switch (widget.field) { + case EmailSetupField.email: + return true; + } + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('required', required)); + } +} + +class _EmailSetupTextField extends EmailSetupFormField { + const _EmailSetupTextField({ + super.key, + required super.field, + super.titleKey, + super.hintTextKey, + super.validator, + super.autofillHints, + }) : super._(); + + @override + _EmailSetupTextFieldState createState() => _EmailSetupTextFieldState(); +} + +class _EmailSetupTextFieldState extends _EmailSetupFormFieldState + with AuthenticatorTextField { + @override + bool get obscureText { + return false; + } +} From a07f13b1f6998ae3143aa88ddab5c50a679c3f87 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:36:41 -0700 Subject: [PATCH 083/159] chore: adding steps to authenticator state machine --- .../amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 41dcfe410e..bbb05464e6 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -218,6 +218,7 @@ class StateMachineBloc switch (result.nextStep.signInStep) { case AuthSignInStep.confirmSignInWithSmsMfaCode: + case AuthSignInStep.confirmSignInWithEmailMfaCode: yield UnauthenticatedState.confirmSignInMfa; case AuthSignInStep.confirmSignInWithCustomChallenge: yield ConfirmSignInCustom( @@ -323,6 +324,7 @@ class StateMachineBloc }) async { switch (result.nextStep.signInStep) { case AuthSignInStep.confirmSignInWithSmsMfaCode: + case AuthSignInStep.confirmSignInWithEmailMfaCode: _notifyCodeSent(result.nextStep.codeDeliveryDetails?.destination); _emit(UnauthenticatedState.confirmSignInMfa); case AuthSignInStep.confirmSignInWithCustomChallenge: From 0b09af1ec866603f49b753901f90cdd56a32f8b0 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:21:38 -0700 Subject: [PATCH 084/159] chore: remove this verification code form field key since we already have keyCodeConfirmSignInFormField --- packages/authenticator/amplify_authenticator/lib/src/keys.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/keys.dart b/packages/authenticator/amplify_authenticator/lib/src/keys.dart index bdc58969a1..7900366e37 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/keys.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/keys.dart @@ -143,5 +143,3 @@ const keyTotpSetupFormField = Key('totpSetupFormField'); // Email setup form keys const keyEmailSetupFormField = Key('emailSetupFormField'); -const keyVerificationCodeEmailSetupFormField = - Key('verificationCodeEmailSetupFormField'); From 362f97caa92cbd67207e5ca77ae5b2d440dd2570 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:51:27 -0700 Subject: [PATCH 085/159] chore: add authenticator screen keys for new screens --- .../lib/src/screens/authenticator_screen.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index f01f3111fd..8ffbc61622 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -39,6 +39,12 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.confirmSignInWithTotpMfaCode({Key? key}) : this(key: key, step: AuthenticatorStep.confirmSignInWithTotpMfaCode); + + const AuthenticatorScreen.continueSignInWithEmailMfaSetup({Key? key}) + : this(key: key, step: AuthenticatorStep.continueSignInWithEmailMfaSetup); + + const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) + : this(key: key, step: AuthenticatorStep.continueSignInWithMfaSetupSelection); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); From 6dfa933f01580df246ae4c659a417385dc0dd74c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:07:41 -0700 Subject: [PATCH 086/159] chore: remove dart auto formatted code --- .../lib/src/state/inherited_forms.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index ad3c0f93a4..7a292bc8f0 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -114,12 +114,6 @@ class InheritedForms extends InheritedWidget { oldWidget.confirmSignInWithTotpMfaCodeForm != confirmSignInWithTotpMfaCodeForm; } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('continueSignInWithEmailMfaSetupForm', continueSignInWithEmailMfaSetupForm)); - } } // ignore_for_file: prefer_asserts_with_message From 49d1d28c9ad7cdc10bbeab42d0b8bfd16494ff6a Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:24:33 -0700 Subject: [PATCH 087/159] chore: add new email mfa setup form to inherited forms switch statement --- .../lib/src/state/inherited_forms.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index 7a292bc8f0..ff42f558ee 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -58,15 +58,15 @@ class InheritedForms extends InheritedWidget { case AuthenticatorStep.continueSignInWithMfaSelection: return continueSignInWithMfaSelectionForm; case AuthenticatorStep.continueSignInWithMfaSetupSelection: - // TODO(khatruong2009): Implement this form + // TODO(khatruong2009): Implement this form case AuthenticatorStep.continueSignInWithTotpSetup: return continueSignInWithTotpSetupForm; case AuthenticatorStep.confirmSignInWithTotpMfaCode: return confirmSignInWithTotpMfaCodeForm; case AuthenticatorStep.continueSignInWithEmailMfaSetup: - // TODO(khatruong2009): Implement this form + return continueSignInWithEmailMfaSetupForm; case AuthenticatorStep.confirmSignInWithEmailMfaCode: - // TODO(khatruong2009): Implement this form + return confirmSignInMFAForm; case AuthenticatorStep.resetPassword: return resetPasswordForm; case AuthenticatorStep.confirmResetPassword: From 845892ef9af3e671792f58153379866be3a3960d Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:26:56 -0700 Subject: [PATCH 088/159] chore: add cases to oldWidget --- .../lib/src/state/inherited_forms.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index ff42f558ee..d83d7b850d 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -112,7 +112,11 @@ class InheritedForms extends InheritedWidget { oldWidget.continueSignInWithTotpSetupForm != continueSignInWithTotpSetupForm || oldWidget.confirmSignInWithTotpMfaCodeForm != - confirmSignInWithTotpMfaCodeForm; + confirmSignInWithTotpMfaCodeForm || + oldWidget.continueSignInWithEmailMfaSetupForm != + continueSignInWithEmailMfaSetupForm || + oldWidget.continueSignInWithMfaSelectionForm != + continueSignInWithMfaSelectionForm; } } From 8000bec28c0cfa7326b11f6a8314dd7adce4b948 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:28:54 -0700 Subject: [PATCH 089/159] chore: add todo to add case for continueSignInWithMfaSetupSelection --- .../amplify_authenticator/lib/src/widgets/form_field.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index e8ba9fe1ae..caa1d7151f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -238,6 +238,7 @@ abstract class AuthenticatorFormFieldState< state.confirmTotp(); case AuthenticatorStep.continueSignInWithEmailMfaSetup: state.continueEmailMfaSetup(); + // TODO(khatruong2009): add case for AuthenticatorStep.continueSignInWithMfaSetupSelection case AuthenticatorStep.resetPassword: state.resetPassword(); case AuthenticatorStep.confirmResetPassword: From d6cd99578f622efc52183a1930ee9c1079ac5743 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:23:37 -0700 Subject: [PATCH 090/159] chore: remove duplicate localization and fix docs comments --- .../lib/src/l10n/generated/input_localizations_en.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart index 300acbc706..bdf428025e 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart @@ -160,6 +160,4 @@ class AuthenticatorInputLocalizationsEn String get totpCodePrompt => 'Please enter the code from your registered Authenticator app'; - @override - String get selectEmail => 'Email'; } From 9af619d2962b6504d900f85d157e754976f7761f Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:24:10 -0700 Subject: [PATCH 091/159] chore: add continueSignInWithMfaSetupSelectionForm --- .../lib/amplify_authenticator.dart | 3 + .../lib/src/state/inherited_forms.dart | 5 +- .../lib/src/widgets/form.dart | 23 +++++++ .../lib/src/widgets/form_field.dart | 1 + .../form_fields/mfa_selection_form_field.dart | 5 ++ .../mfa_setup_selection_form_field.dart | 63 +++++++++++++++++++ 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_setup_selection_form_field.dart diff --git a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart index 8cfaf5ab79..dc852fce19 100644 --- a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart +++ b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart @@ -76,6 +76,7 @@ export 'src/widgets/form.dart' ConfirmSignInMFAForm, ConfirmSignInNewPasswordForm, ContinueSignInWithMfaSelectionForm, + ContinueSignInWithMfaSetupSelectionForm, ContinueSignInWithTotpSetupForm, ContinueSignInWithEmailMfaSetupForm, ConfirmSignUpForm, @@ -711,6 +712,8 @@ class _AuthenticatorState extends State { confirmSignInMFAForm: ConfirmSignInMFAForm(), continueSignInWithMfaSelectionForm: ContinueSignInWithMfaSelectionForm(), + continueSignInWithMfaSetupSelectionForm: + ContinueSignInWithMfaSetupSelectionForm(), continueSignInWithTotpSetupForm: ContinueSignInWithTotpSetupForm(), continueSignInWithEmailMfaSetupForm: ContinueSignInWithEmailMfaSetupForm(), diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index d83d7b850d..876164b22a 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -16,6 +16,7 @@ class InheritedForms extends InheritedWidget { required this.confirmResetPasswordForm, required this.confirmSignInNewPasswordForm, required this.continueSignInWithMfaSelectionForm, + required this.continueSignInWithMfaSetupSelectionForm, required this.continueSignInWithTotpSetupForm, required this.continueSignInWithEmailMfaSetupForm, required this.confirmSignInWithTotpMfaCodeForm, @@ -31,6 +32,8 @@ class InheritedForms extends InheritedWidget { final ConfirmSignInMFAForm confirmSignInMFAForm; final ConfirmSignInNewPasswordForm confirmSignInNewPasswordForm; final ContinueSignInWithMfaSelectionForm continueSignInWithMfaSelectionForm; + final ContinueSignInWithMfaSetupSelectionForm + continueSignInWithMfaSetupSelectionForm; final ContinueSignInWithTotpSetupForm continueSignInWithTotpSetupForm; final ContinueSignInWithEmailMfaSetupForm continueSignInWithEmailMfaSetupForm; final ConfirmSignInMFAForm confirmSignInWithTotpMfaCodeForm; @@ -58,7 +61,7 @@ class InheritedForms extends InheritedWidget { case AuthenticatorStep.continueSignInWithMfaSelection: return continueSignInWithMfaSelectionForm; case AuthenticatorStep.continueSignInWithMfaSetupSelection: - // TODO(khatruong2009): Implement this form + return continueSignInWithMfaSetupSelectionForm; case AuthenticatorStep.continueSignInWithTotpSetup: return continueSignInWithTotpSetupForm; case AuthenticatorStep.confirmSignInWithTotpMfaCode: diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index 9c91c3fb0d..a114fbb65c 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -623,6 +623,29 @@ class ContinueSignInWithMfaSelectionForm extends AuthenticatorForm { AuthenticatorFormState(); } +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.continue_sign_in_with__mfa_setup_selection_form} +/// A prebuilt form for selecting an MFA method during setup. +/// {@endtemplate} +class ContinueSignInWithMfaSetupSelectionForm extends AuthenticatorForm { + /// {@macro amplify_authenticator.continue_sign_in_with__mfa_setup_selection_form} + ContinueSignInWithMfaSetupSelectionForm({ + super.key, + }) : super._( + fields: [ + ConfirmSignInFormField.mfaSelection(), + ], + actions: const [ + ContinueSignInMFASelectionButton(), + BackToSignInButton(), + ], + ); + + @override + AuthenticatorFormState createState() => + AuthenticatorFormState(); +} + /// {@category Prebuilt Widgets} /// {@template amplify_authenticator.continue_sign_in_with_totp_setup_form} /// A prebuilt form for completing the totp setup process. diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index caa1d7151f..1c4477b91b 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -30,6 +30,7 @@ part 'form_fields/confirm_sign_in_form_field.dart'; part 'form_fields/confirm_sign_up_form_field.dart'; part 'form_fields/email_setup_form_field.dart'; part 'form_fields/mfa_selection_form_field.dart'; +part 'form_fields/mfa_setup_selection_form_field.dart'; part 'form_fields/phone_number_field.dart'; part 'form_fields/reset_password_form_field.dart'; part 'form_fields/sign_in_form_field.dart'; diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_selection_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_selection_form_field.dart index f5587071d0..8d73d1aae2 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_selection_form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_selection_form_field.dart @@ -41,6 +41,11 @@ class _MfaSelectionFieldState extends _ConfirmSignInFormFieldState label: InputResolverKey.selectSms, value: MfaType.sms, ), + if (_allowedMfaTypes.contains(MfaType.email)) + const InputSelection( + label: InputResolverKey.selectEmail, + value: MfaType.email, + ), ]; @override diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_setup_selection_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_setup_selection_form_field.dart new file mode 100644 index 0000000000..76b4084337 --- /dev/null +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/mfa_setup_selection_form_field.dart @@ -0,0 +1,63 @@ +// mfa_setup_selection_form_field.dart + +// Copyright Amazon.com, Inc. or its affiliates. +// All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +part of '../form_field.dart'; + +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.mfa_setup_selection_form_field} +/// A prebuilt form widget for use on the MFA setup selection step. +/// {@endtemplate} +class _MfaSetupMethodRadioField extends ConfirmSignInFormField { + const _MfaSetupMethodRadioField({ + super.key, + required super.field, + }) : super._(); + + @override + _MfaSetupSelectionFieldState createState() => _MfaSetupSelectionFieldState(); +} + +class _MfaSetupSelectionFieldState extends _ConfirmSignInFormFieldState + with AuthenticatorRadioField { + Set get _allowedMfaTypes { + final state = InheritedAuthBloc.of(context).currentState; + assert( + state is ContinueSignInWithMfaSetupSelection, + 'Expected ContinueSignInWithMfaSetupSelection for current screen', + ); + return (state as ContinueSignInWithMfaSetupSelection).allowedMfaTypes; + } + + @override + List> get selections => [ + if (_allowedMfaTypes.contains(MfaType.totp)) + const InputSelection( + label: InputResolverKey.selectTotp, + value: MfaType.totp, + ), + if (_allowedMfaTypes.contains(MfaType.email)) + const InputSelection( + label: InputResolverKey.selectEmail, + value: MfaType.email, + ), + ]; + + @override + MfaType get initialValue => selections.first.value; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + state.selectedMfaMethod = initialValue; + }); + } + + @override + ValueChanged get onChanged { + return (MfaType method) => state.selectedMfaMethod = method; + } +} From a8b41e93cc393c01715189ecd077fe07ef9dd2b9 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:40:20 -0700 Subject: [PATCH 092/159] chore: dart format and fix typos --- .../amplify_authenticator/lib/amplify_authenticator.dart | 3 ++- .../lib/src/l10n/generated/input_localizations_en.dart | 1 - .../lib/src/l10n/generated/title_localizations.dart | 6 +++--- .../lib/src/screens/authenticator_screen.dart | 6 ++++-- .../lib/src/state/authenticator_state.dart | 4 ++-- .../src/widgets/form_fields/confirm_sign_in_form_field.dart | 2 +- .../lib/src/widgets/form_fields/email_setup_form_field.dart | 5 ++--- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart index dc852fce19..f83b9b84c4 100644 --- a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart +++ b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart @@ -716,7 +716,8 @@ class _AuthenticatorState extends State { ContinueSignInWithMfaSetupSelectionForm(), continueSignInWithTotpSetupForm: ContinueSignInWithTotpSetupForm(), - continueSignInWithEmailMfaSetupForm: ContinueSignInWithEmailMfaSetupForm(), + continueSignInWithEmailMfaSetupForm: + ContinueSignInWithEmailMfaSetupForm(), confirmSignInWithTotpMfaCodeForm: ConfirmSignInMFAForm(), verifyUserForm: VerifyUserForm(), confirmVerifyUserForm: ConfirmVerifyUserForm(), diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart index bdf428025e..6b6d42a494 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/input_localizations_en.dart @@ -159,5 +159,4 @@ class AuthenticatorInputLocalizationsEn @override String get totpCodePrompt => 'Please enter the code from your registered Authenticator app'; - } diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart index 96b09f3830..05d73ef2a4 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart @@ -142,19 +142,19 @@ abstract class AuthenticatorTitleLocalizations { String get confirmSignInWithTotpMfaCode; /// Title of the Confirm Sign In with Email MFA Code step and form - /// + /// /// In en, this message translates to: /// **'Enter your one-time passcode'** String get confirmSignInWithEmailMfaCode; /// Title of the Continue Sign In with Email MFA Setup step and form - /// + /// /// In en, this message translates to: /// **'Set up Email Two-Factor Auth'** String get continueSignInWithEmailMfaSetup; /// Title of the Continue Sign In with MFA Setup Selection step and form - /// + /// /// In en, this message translates to: /// **'Select a Two-Factor Auth method to set up'** String get continueSignInWithMfaSetupSelection; diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index 8ffbc61622..b5d48988b1 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -39,12 +39,14 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.confirmSignInWithTotpMfaCode({Key? key}) : this(key: key, step: AuthenticatorStep.confirmSignInWithTotpMfaCode); - + const AuthenticatorScreen.continueSignInWithEmailMfaSetup({Key? key}) : this(key: key, step: AuthenticatorStep.continueSignInWithEmailMfaSetup); const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) - : this(key: key, step: AuthenticatorStep.continueSignInWithMfaSetupSelection); + : this( + key: key, + step: AuthenticatorStep.continueSignInWithMfaSetupSelection); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart index 38c630da49..8e4b5542e4 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart @@ -161,7 +161,7 @@ class AuthenticatorState extends ChangeNotifier { } /// The value for the email MFA setup form field - /// + /// /// This value will be used during continue email MFA setup String get mfaEmail => _mfaEmail; @@ -169,7 +169,7 @@ class AuthenticatorState extends ChangeNotifier { _mfaEmail = value.trim(); notifyListeners(); } - + String _mfaEmail = ''; MfaType? _selectedMfaMethod; diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart index d4b39d1d22..ce8bf33081 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart @@ -79,7 +79,7 @@ abstract class ConfirmSignInFormField autofillHints: autofillHints, ); - /// Creates a mfa preference selection component. + /// Creates an mfa preference selection component. static ConfirmSignInFormField mfaSelection({ Key? key, }) => diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart index 06647ee4f9..47951cbe8f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart @@ -7,7 +7,7 @@ part of '../form_field.dart'; /// {@template amplify_authenticator.email_setup_form_field} /// A prebuilt form field widget for use on the Email MFA setup step. /// {@endtemplate} -abstract class EmailSetupFormField +abstract class EmailSetupFormField extends AuthenticatorFormField { /// {@macro amplify_authenticator.email_setup_form_field} /// @@ -52,7 +52,6 @@ abstract class _EmailSetupFormFieldState return [AutofillHints.email]; } - @override bool get required { switch (widget.field) { case EmailSetupField.email: @@ -76,7 +75,7 @@ class _EmailSetupTextField extends EmailSetupFormField { super.validator, super.autofillHints, }) : super._(); - + @override _EmailSetupTextFieldState createState() => _EmailSetupTextFieldState(); } From 3b50a1b1307b2aec26df958dbb1911b5cdd4817c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:40:48 -0700 Subject: [PATCH 093/159] chore: fix mfaSetup fields and input_resolver duplicate --- .../amplify_authenticator/lib/src/keys.dart | 2 ++ .../lib/src/l10n/input_resolver.dart | 2 -- .../amplify_authenticator/lib/src/widgets/form.dart | 7 ++++--- .../widgets/form_fields/confirm_sign_in_form_field.dart | 9 +++++++++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/keys.dart b/packages/authenticator/amplify_authenticator/lib/src/keys.dart index 7900366e37..2f0665814e 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/keys.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/keys.dart @@ -52,6 +52,8 @@ const keyCustomChallengeConfirmSignInFormField = Key('customChallengeConfirmSignInFormField'); const keyMfaMethodRadioConfirmSignInFormField = Key('mfaMethodRadioConfirmSignInFormField'); +const keyMfaSetupMethodRadioConfirmSignInFormField = + Key('mfaSetupMethodRadioConfirmSignInFormField'); const keyUsernameConfirmSignInFormField = Key('usernameConfirmSignInFormField'); const keyPasswordConfirmSignInFormField = Key('passwordConfirmSignInFormField'); const keyNewPasswordConfirmSignInFormField = diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart index 27626a8a6f..0eb96b26f1 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/input_resolver.dart @@ -466,8 +466,6 @@ class InputResolver extends Resolver { return AuthenticatorLocalizations.inputsOf(context).selectEmail; case InputField.totpCodePrompt: return AuthenticatorLocalizations.inputsOf(context).totpCodePrompt; - case InputField.selectEmail: - return AuthenticatorLocalizations.inputsOf(context).selectEmail; case InputField.usernameType: return AuthenticatorLocalizations.inputsOf(context).usernameType; } diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index a114fbb65c..c79d308f84 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -633,7 +633,7 @@ class ContinueSignInWithMfaSetupSelectionForm extends AuthenticatorForm { super.key, }) : super._( fields: [ - ConfirmSignInFormField.mfaSelection(), + ConfirmSignInFormField.mfaSetupSelection(), ], actions: const [ ContinueSignInMFASelectionButton(), @@ -642,8 +642,9 @@ class ContinueSignInWithMfaSetupSelectionForm extends AuthenticatorForm { ); @override - AuthenticatorFormState createState() => - AuthenticatorFormState(); + AuthenticatorFormState + createState() => + AuthenticatorFormState(); } /// {@category Prebuilt Widgets} diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart index ce8bf33081..22d1253f39 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/confirm_sign_in_form_field.dart @@ -88,6 +88,15 @@ abstract class ConfirmSignInFormField field: ConfirmSignInField.mfaMethod, ); + /// creates an mfa preference setup selection component. + static ConfirmSignInFormField mfaSetupSelection({ + Key? key, + }) => + _MfaSetupMethodRadioField( + key: key ?? keyMfaSetupMethodRadioConfirmSignInFormField, + field: ConfirmSignInField.mfaMethod, + ); + /// Creates a verification code component. static ConfirmSignInFormField verificationCode({ Key? key, From dab8ff46ea17d8160b75b86051ab3ed685bb82d7 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:56:31 -0700 Subject: [PATCH 094/159] chore: remove duplicate analytics backend section --- infra-gen2/tool/deploy_gen2.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/infra-gen2/tool/deploy_gen2.dart b/infra-gen2/tool/deploy_gen2.dart index 15ffcf10f4..e5f8cf1a1e 100644 --- a/infra-gen2/tool/deploy_gen2.dart +++ b/infra-gen2/tool/deploy_gen2.dart @@ -19,11 +19,6 @@ import 'package:path/path.dart' as p; /// 3. Add the backend to a category or create a new category /// 4. Run `dart tool/deploy_gen2.dart` to deploy the backend const List infraConfig = [ - AmplifyBackendGroup( - category: Category.analytics, - defaultOutput: '', - backends: [], - ), AmplifyBackendGroup( category: Category.api, defaultOutput: 'packages/api/amplify_api/example/lib', From 8b7771d4e19ee18101ca4063f868b81877a47e81 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:33:17 -0700 Subject: [PATCH 095/159] chore: use confirmSignInWithEmailMfaCode instead of confirmSignInMfa --- .../lib/amplify_authenticator.dart | 1 + .../lib/src/blocs/auth/auth_bloc.dart | 2 -- .../src/l10n/generated/title_localizations.dart | 4 ++-- .../l10n/generated/title_localizations_en.dart | 4 ++-- .../lib/src/screens/authenticator_screen.dart | 7 ++++--- .../lib/src/state/authenticator_state.dart | 17 +++++++++++++++++ .../lib/src/state/inherited_forms.dart | 6 +++++- .../lib/src/widgets/form_field.dart | 3 ++- 8 files changed, 33 insertions(+), 11 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart index f83b9b84c4..55abb9c220 100644 --- a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart +++ b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart @@ -719,6 +719,7 @@ class _AuthenticatorState extends State { continueSignInWithEmailMfaSetupForm: ContinueSignInWithEmailMfaSetupForm(), confirmSignInWithTotpMfaCodeForm: ConfirmSignInMFAForm(), + confirmSignInWithEmailMfaCodeForm: ConfirmSignInMFAForm(), verifyUserForm: VerifyUserForm(), confirmVerifyUserForm: ConfirmVerifyUserForm(), child: widget.child, diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index bbb05464e6..41dcfe410e 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -218,7 +218,6 @@ class StateMachineBloc switch (result.nextStep.signInStep) { case AuthSignInStep.confirmSignInWithSmsMfaCode: - case AuthSignInStep.confirmSignInWithEmailMfaCode: yield UnauthenticatedState.confirmSignInMfa; case AuthSignInStep.confirmSignInWithCustomChallenge: yield ConfirmSignInCustom( @@ -324,7 +323,6 @@ class StateMachineBloc }) async { switch (result.nextStep.signInStep) { case AuthSignInStep.confirmSignInWithSmsMfaCode: - case AuthSignInStep.confirmSignInWithEmailMfaCode: _notifyCodeSent(result.nextStep.codeDeliveryDetails?.destination); _emit(UnauthenticatedState.confirmSignInMfa); case AuthSignInStep.confirmSignInWithCustomChallenge: diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart index 05d73ef2a4..852f8e4d7b 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart @@ -150,13 +150,13 @@ abstract class AuthenticatorTitleLocalizations { /// Title of the Continue Sign In with Email MFA Setup step and form /// /// In en, this message translates to: - /// **'Set up Email Two-Factor Auth'** + /// **'Add Email for Two-Factor Authentication'** String get continueSignInWithEmailMfaSetup; /// Title of the Continue Sign In with MFA Setup Selection step and form /// /// In en, this message translates to: - /// **'Select a Two-Factor Auth method to set up'** + /// **'Choose your preferred two-factor authentication method to set up'** String get continueSignInWithMfaSetupSelection; /// Title of the Reset Password step and form diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart index 3f3ca2b794..f547339bf5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart @@ -34,11 +34,11 @@ class AuthenticatorTitleLocalizationsEn String get confirmSignInWithEmailMfaCode => 'Enter your one-time passcode'; @override - String get continueSignInWithEmailMfaSetup => 'Set up Email Two-Factor Auth'; + String get continueSignInWithEmailMfaSetup => 'Add Email for Two-Factor Authentication'; @override String get continueSignInWithMfaSetupSelection => - 'Select a Two-Factor Auth method to set up'; + 'Choose your preferred two-factor authentication method to set up'; @override String get resetPassword => 'Send Code'; diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index b5d48988b1..e547dfd9f0 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -40,13 +40,14 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.confirmSignInWithTotpMfaCode({Key? key}) : this(key: key, step: AuthenticatorStep.confirmSignInWithTotpMfaCode); + const AuthenticatorScreen.confirmSignInWithEmailMfaCode({Key? key}) + : this(key: key, step: AuthenticatorStep.confirmSignInWithEmailMfaCode); + const AuthenticatorScreen.continueSignInWithEmailMfaSetup({Key? key}) : this(key: key, step: AuthenticatorStep.continueSignInWithEmailMfaSetup); const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) - : this( - key: key, - step: AuthenticatorStep.continueSignInWithMfaSetupSelection); + : this(key: key, step: AuthenticatorStep.continueSignInWithMfaSetupSelection); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart index 8e4b5542e4..bf434aba5c 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart @@ -426,6 +426,23 @@ class AuthenticatorState extends ChangeNotifier { _setIsBusy(false); } + /// complete Email MFA setup using the values for [confirmationCode] + Future confirmEmailMfa() async { + if (!_formKey.currentState!.validate()) { + return; + } + + _setIsBusy(true); + + final confirm = AuthConfirmSignInData( + confirmationValue: _confirmationCode.trim(), + ); + + _authBloc.add(AuthConfirmSignIn(confirm)); + await nextBlocEvent(); + _setIsBusy(false); + } + /// Complete MFA setup using the values for [confirmationCode] Future continueEmailMfaSetup() async { if (!_formKey.currentState!.validate()) { diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index 876164b22a..121f81bd0d 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -20,6 +20,7 @@ class InheritedForms extends InheritedWidget { required this.continueSignInWithTotpSetupForm, required this.continueSignInWithEmailMfaSetupForm, required this.confirmSignInWithTotpMfaCodeForm, + required this.confirmSignInWithEmailMfaCodeForm, required this.verifyUserForm, required this.confirmVerifyUserForm, required super.child, @@ -37,6 +38,7 @@ class InheritedForms extends InheritedWidget { final ContinueSignInWithTotpSetupForm continueSignInWithTotpSetupForm; final ContinueSignInWithEmailMfaSetupForm continueSignInWithEmailMfaSetupForm; final ConfirmSignInMFAForm confirmSignInWithTotpMfaCodeForm; + final ConfirmSignInMFAForm confirmSignInWithEmailMfaCodeForm; final ResetPasswordForm resetPasswordForm; final ConfirmResetPasswordForm confirmResetPasswordForm; final VerifyUserForm verifyUserForm; @@ -69,7 +71,7 @@ class InheritedForms extends InheritedWidget { case AuthenticatorStep.continueSignInWithEmailMfaSetup: return continueSignInWithEmailMfaSetupForm; case AuthenticatorStep.confirmSignInWithEmailMfaCode: - return confirmSignInMFAForm; + return confirmSignInWithEmailMfaCodeForm; case AuthenticatorStep.resetPassword: return resetPasswordForm; case AuthenticatorStep.confirmResetPassword: @@ -116,6 +118,8 @@ class InheritedForms extends InheritedWidget { continueSignInWithTotpSetupForm || oldWidget.confirmSignInWithTotpMfaCodeForm != confirmSignInWithTotpMfaCodeForm || + oldWidget.confirmSignInWithEmailMfaCodeForm != + confirmSignInWithEmailMfaCodeForm || oldWidget.continueSignInWithEmailMfaSetupForm != continueSignInWithEmailMfaSetupForm || oldWidget.continueSignInWithMfaSelectionForm != diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index 1c4477b91b..a9824be8c5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -230,8 +230,9 @@ abstract class AuthenticatorFormFieldState< case AuthenticatorStep.confirmSignInCustomAuth: state.confirmSignInCustomAuth(); case AuthenticatorStep.confirmSignInMfa: - case AuthenticatorStep.confirmSignInWithEmailMfaCode: state.confirmSignInMFA(); + case AuthenticatorStep.confirmSignInWithEmailMfaCode: + state.confirmEmailMfa(); case AuthenticatorStep.confirmSignInNewPassword: state.confirmSignInNewPassword(); case AuthenticatorStep.confirmSignInWithTotpMfaCode: From 93a8b758e77b4aaaa98e6c473b0461aea6f5cecc Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:49:16 -0700 Subject: [PATCH 096/159] chore: dart format --- .../lib/src/l10n/generated/title_localizations_en.dart | 3 ++- .../lib/src/screens/authenticator_screen.dart | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart index f547339bf5..692f579fa5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart @@ -34,7 +34,8 @@ class AuthenticatorTitleLocalizationsEn String get confirmSignInWithEmailMfaCode => 'Enter your one-time passcode'; @override - String get continueSignInWithEmailMfaSetup => 'Add Email for Two-Factor Authentication'; + String get continueSignInWithEmailMfaSetup => + 'Add Email for Two-Factor Authentication'; @override String get continueSignInWithMfaSetupSelection => diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index e547dfd9f0..2eeebb2f8b 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -47,7 +47,9 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { : this(key: key, step: AuthenticatorStep.continueSignInWithEmailMfaSetup); const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) - : this(key: key, step: AuthenticatorStep.continueSignInWithMfaSetupSelection); + : this( + key: key, + step: AuthenticatorStep.continueSignInWithMfaSetupSelection); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); From 64f25ad8c8eab09cfca4538755c862aea4718222 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:57:21 -0700 Subject: [PATCH 097/159] chore: add trailing comma --- .../lib/src/screens/authenticator_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index 2eeebb2f8b..fd99bc74ba 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -49,7 +49,7 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) : this( key: key, - step: AuthenticatorStep.continueSignInWithMfaSetupSelection); + step: AuthenticatorStep.continueSignInWithMfaSetupSelection,); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); From 7fd3b39b3ff1d2011cbf481e7da5c1868a29dabd Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 1 Oct 2024 23:02:55 -0700 Subject: [PATCH 098/159] chore: dart format --- .../lib/src/screens/authenticator_screen.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index fd99bc74ba..e405a6a812 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -48,8 +48,9 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.continueSignInWithMfaSetupSelection({Key? key}) : this( - key: key, - step: AuthenticatorStep.continueSignInWithMfaSetupSelection,); + key: key, + step: AuthenticatorStep.continueSignInWithMfaSetupSelection, + ); const AuthenticatorScreen.resetPassword({Key? key}) : this(key: key, step: AuthenticatorStep.resetPassword); From dd769423b1d5f611f008416577771f3a02b39616 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:08:21 -0700 Subject: [PATCH 099/159] chore: doc fixes --- packages/amplify_core/doc/lib/auth.dart | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/packages/amplify_core/doc/lib/auth.dart b/packages/amplify_core/doc/lib/auth.dart index 5573052fba..d2bd9da534 100644 --- a/packages/amplify_core/doc/lib/auth.dart +++ b/packages/amplify_core/doc/lib/auth.dart @@ -118,11 +118,11 @@ Future _handleSignInResult(SignInResult result) async { case AuthSignInStep.continueSignInWithMfaSetupSelection: final allowedMfaTypes = result.nextStep.allowedMfaTypes!; if (allowedMfaTypes.length == 1) { - return _handleMfaSetupSelection(allowedMfaTypes.first); + return _handleMfaSelection(allowedMfaTypes.first); } final selection = await _promptUserPreference(allowedMfaTypes); safePrint('Selected MFA type: $selection'); - return _handleMfaSetupSelection(selection); + return _handleMfaSelection(selection); // #enddocregion handle-confirm-signin-mfa-setup-selection // #docregion handle-confirm-signin-totp-setup case AuthSignInStep.continueSignInWithTotpSetup: @@ -132,7 +132,7 @@ Future _handleSignInResult(SignInResult result) async { // #enddocregion handle-confirm-signin-totp-setup // #docregion handle-confirm-signin-email-setup case AuthSignInStep.continueSignInWithEmailMfaSetup: - safePrint('A confirmation code has been sent to your email'); + safePrint('Enter the email address you want to use for two-factor authentication'); // #enddocregion handle-confirm-signin-email-setup // #docregion handle-confirm-signin-totp-code case AuthSignInStep.confirmSignInWithTotpMfaCode: @@ -255,19 +255,6 @@ Future _handleMfaSelection(MfaType selection) async { } // #enddocregion handle-mfa-selection -// #docregion handle-mfa-setup-selection -Future _handleMfaSetupSelection(MfaType selection) async { - try { - final result = await Amplify.Auth.confirmSignIn( - confirmationValue: selection.confirmationValue, - ); - return _handleSignInResult(result); - } on AuthException catch (e) { - safePrint('Error selecting MFA method: ${e.message}'); - } -} -// #enddocregion handle-mfa-setup-selection - // #docregion signout Future signOutCurrentUser() async { final result = await Amplify.Auth.signOut(); From d602beffa9942964dbbec4bf9f4864d27f709fc4 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:02:05 -0700 Subject: [PATCH 100/159] chore: fixed else statement circular loop --- .../lib/src/blocs/auth/auth_bloc.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 41dcfe410e..2e879f38af 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -370,10 +370,9 @@ class StateMachineBloc ); } } else { - _emit( - ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: result.nextStep.allowedMfaTypes, - ), + throw const InvalidUserPoolConfigurationException( + 'Allowed MFA types are null', + recoverySuggestion: 'Check your user pool MFA configuration.', ); } case AuthSignInStep.continueSignInWithTotpSetup: From e98a31c95cff8d2d3a04a4b9cb1624923e18d80b Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:08:34 -0700 Subject: [PATCH 101/159] chore: dart format --- packages/amplify_core/doc/lib/auth.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify_core/doc/lib/auth.dart b/packages/amplify_core/doc/lib/auth.dart index d2bd9da534..5480d2aa1e 100644 --- a/packages/amplify_core/doc/lib/auth.dart +++ b/packages/amplify_core/doc/lib/auth.dart @@ -132,7 +132,8 @@ Future _handleSignInResult(SignInResult result) async { // #enddocregion handle-confirm-signin-totp-setup // #docregion handle-confirm-signin-email-setup case AuthSignInStep.continueSignInWithEmailMfaSetup: - safePrint('Enter the email address you want to use for two-factor authentication'); + safePrint( + 'Enter the email address you want to use for two-factor authentication'); // #enddocregion handle-confirm-signin-email-setup // #docregion handle-confirm-signin-totp-code case AuthSignInStep.confirmSignInWithTotpMfaCode: From d7ebd261b33748b3518c9eb5aabd43e30be1e51f Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:08:57 -0700 Subject: [PATCH 102/159] chore: dart format authenticator --- .../lib/src/blocs/auth/auth_bloc.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 2e879f38af..d0cbff9fe8 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -350,10 +350,12 @@ class StateMachineBloc result.nextStep.totpSetupDetails != null, 'Sign In Result should have totpSetupDetails', ); - _emit(await ContinueSignInTotpSetup.setupURI( - result.nextStep.totpSetupDetails!, - totpOptions, - ),); + _emit( + await ContinueSignInTotpSetup.setupURI( + result.nextStep.totpSetupDetails!, + totpOptions, + ), + ); } else if (mfaType == MfaType.email) { _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); } else { From aad98830d60b5e744c95cbcf3f136dd7c53a8d0f Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:14:35 -0700 Subject: [PATCH 103/159] chore: add trailing comma --- packages/amplify_core/doc/lib/auth.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify_core/doc/lib/auth.dart b/packages/amplify_core/doc/lib/auth.dart index 5480d2aa1e..cdd3b872c5 100644 --- a/packages/amplify_core/doc/lib/auth.dart +++ b/packages/amplify_core/doc/lib/auth.dart @@ -133,7 +133,7 @@ Future _handleSignInResult(SignInResult result) async { // #docregion handle-confirm-signin-email-setup case AuthSignInStep.continueSignInWithEmailMfaSetup: safePrint( - 'Enter the email address you want to use for two-factor authentication'); + 'Enter the email address you want to use for two-factor authentication',); // #enddocregion handle-confirm-signin-email-setup // #docregion handle-confirm-signin-totp-code case AuthSignInStep.confirmSignInWithTotpMfaCode: From 9d9abe864efea05e1b7f0a3fcc991160ecca27cf Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:35:36 -0700 Subject: [PATCH 104/159] chore: dart format --- packages/amplify_core/doc/lib/auth.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify_core/doc/lib/auth.dart b/packages/amplify_core/doc/lib/auth.dart index cdd3b872c5..79cc4e0858 100644 --- a/packages/amplify_core/doc/lib/auth.dart +++ b/packages/amplify_core/doc/lib/auth.dart @@ -133,7 +133,8 @@ Future _handleSignInResult(SignInResult result) async { // #docregion handle-confirm-signin-email-setup case AuthSignInStep.continueSignInWithEmailMfaSetup: safePrint( - 'Enter the email address you want to use for two-factor authentication',); + 'Enter the email address you want to use for two-factor authentication', + ); // #enddocregion handle-confirm-signin-email-setup // #docregion handle-confirm-signin-totp-code case AuthSignInStep.confirmSignInWithTotpMfaCode: From 0641f334b0e26e5a5214255139d6c566ac113f1b Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:21:52 -0700 Subject: [PATCH 105/159] temp state machine changes --- .../lib/src/auth_plugin_impl.dart | 83 +++++++------ .../lib/src/flows/constants.dart | 3 + .../state/machines/sign_in_state_machine.dart | 117 ++++++++++++++---- .../lib/src/blocs/auth/auth_bloc.dart | 2 + .../amplify_authenticator/lib/src/keys.dart | 2 + .../lib/src/state/authenticator_state.dart | 23 ++++ .../lib/src/widgets/button.dart | 21 ++++ .../lib/src/widgets/form.dart | 2 +- 8 files changed, 191 insertions(+), 62 deletions(-) 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 02b5a8e2df..8ccd19262a 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 @@ -481,45 +481,54 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface } CognitoSignInResult _processSignInResult(SignInState result) { - return switch (result) { - SignInNotStarted _ || - SignInInitiating _ => - // This should never happen. - throw UnknownException( - 'Sign in could not be completed', - underlyingException: result, - ), - SignInCancelling _ => throw const UserCancelledException( - 'The user canceled the sign-in flow', - ), - SignInChallenge( - :final challengeName, - :final challengeParameters, - :final codeDeliveryDetails, - :final requiredAttributes, - :final allowedMfaTypes, - :final totpSetupResult, - ) => - CognitoSignInResult( - isSignedIn: false, - nextStep: AuthNextSignInStep( - signInStep: challengeName.signInStep, - codeDeliveryDetails: codeDeliveryDetails, - additionalInfo: challengeParameters, - missingAttributes: requiredAttributes, - allowedMfaTypes: allowedMfaTypes, - totpSetupDetails: totpSetupResult, - ), + switch (result) { + case SignInNotStarted(): + case SignInInitiating(): + // This should never happen. + throw UnknownException( + 'Sign in could not be completed', + underlyingException: result, + ); + + case SignInCancelling(): + throw const UserCancelledException( + 'The user canceled the sign-in flow', + ); + + case final SignInChallenge challenge: + // Print all properties of SignInChallenge + safePrint('Challenge name: ${challenge.challengeName}'); + safePrint('Sign in Step: ${challenge.challengeName.signInStep}'); + safePrint('Challenge parameters: ${challenge.challengeParameters}'); + safePrint('Code delivery details: ${challenge.codeDeliveryDetails}'); + safePrint('Required attributes: ${challenge.requiredAttributes}'); + safePrint('Allowed MFA types: ${challenge.allowedMfaTypes}'); + safePrint('TOTP setup result: ${challenge.totpSetupResult}'); + + return CognitoSignInResult( + isSignedIn: false, + nextStep: AuthNextSignInStep( + signInStep: challenge.challengeName.signInStep, + codeDeliveryDetails: challenge.codeDeliveryDetails, + additionalInfo: challenge.challengeParameters, + missingAttributes: challenge.requiredAttributes, + allowedMfaTypes: challenge.allowedMfaTypes, + totpSetupDetails: challenge.totpSetupResult, ), - SignInSuccess _ => const CognitoSignInResult( - isSignedIn: true, - nextStep: AuthNextSignInStep( - signInStep: AuthSignInStep.done, - ), + ); + + case SignInSuccess(): + return const CognitoSignInResult( + isSignedIn: true, + nextStep: AuthNextSignInStep( + signInStep: AuthSignInStep.done, ), - SignInFailure(:final exception, :final stackTrace) => - Error.throwWithStackTrace(exception, stackTrace), - }; + ); + + case final SignInFailure failure: + Error.throwWithStackTrace(failure.exception, failure.stackTrace); +// To satisfy Dart's requirements, even if unreachable + } } @override diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart index 7a40ff446c..361ac6ccb8 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart @@ -11,6 +11,9 @@ abstract class CognitoConstants { /// The `USERNAME` parameter. static const challengeParamUsername = 'USERNAME'; + /// The `EMAIL` parameter. + static const challengeParamEmail = 'EMAIL'; + /// The `SRP_A` parameter. static const challengeParamSrpA = 'SRP_A'; diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 725f66b9d1..3858159fd7 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -667,38 +667,65 @@ final class SignInStateMachine ); } - if (mfaTypesForSetup.length == 1) { - final mfaType = mfaTypesForSetup.first; - if (mfaType == MfaType.totp) { - _enableMfaType = MfaType.totp; - _totpSetupResult ??= await associateSoftwareToken(); - if (hasUserResponse) { - return createMfaSetupRequest(event as SignInRespondToChallenge); - } else { - // Need to prompt user for the TOTP code - return null; + // if (mfaTypesForSetup.length == 1) { + // // Only one MFA type is allowed for setup + // _enableMfaType = mfaTypesForSetup.first; + // if (_enableMfaType == MfaType.totp) { + // _totpSetupResult = await associateSoftwareToken(); + // return createMfaSetupRequest(event as SignInRespondToChallenge); + // } else if (_enableMfaType == MfaType.email) { + // return createEmailMfaSetupRequest(event as SignInRespondToChallenge); + // } + // } + + if (hasUserResponse) { + if (_enableMfaType == null) { + // User has just selected the MFA type + if (event == null) { + throw StateError('Event cannot be null when there is user response.'); + } + if (event is! SignInRespondToChallenge) { + throw StateError('Expected SignInRespondToChallenge event.'); } - } else if (mfaType == MfaType.email) { - _enableMfaType = MfaType.email; - if (hasUserResponse) { - return createEmailMfaSetupRequest(event as SignInRespondToChallenge); - } else { - // Need to prompt user for the email verification code + final selection = event.answer.toLowerCase(); + _enableMfaType = switch (selection) { + 'totp' => MfaType.totp, + 'email' => MfaType.email, + _ => + throw const InvalidParameterException('Invalid MFA type selected'), + }; + + if (_enableMfaType == MfaType.totp) { + final challengeResponses = { + CognitoConstants.challengeParamMfasCanSetup: + '["SOFTWARE_TOKEN_MFA"]', + }; + final builtMap = BuiltMap(challengeResponses); + _challengeParameters = builtMap; + // await _processChallenge(event); return null; + } else if (_enableMfaType == MfaType.email) { + await _processChallenge(event); } } else { - throw InvalidUserPoolConfigurationException( - 'Unsupported MFA type: ${mfaType.name}', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); + // User has provided the verification code + if (event == null) { + throw StateError('Event cannot be null when there is user response.'); + } + if (event is! SignInRespondToChallenge) { + throw StateError('Expected SignInRespondToChallenge event.'); + } + if (_enableMfaType == MfaType.totp) { + return createMfaSetupRequest(event); + } else if (_enableMfaType == MfaType.email) { + return createEmailMfaSetupRequest(event); + } } - } else if (hasUserResponse) { - // Handle user's selection - return createMfaSetupRequest(event as SignInRespondToChallenge); } else { // Need to prompt user to select an MFA type return null; } + return null; } /// Completes set up of a TOTP MFA. @@ -988,6 +1015,9 @@ final class SignInStateMachine Future _processChallenge([SignInEvent? event]) async { // There can be an indefinite amount of challenges which need responses. // Only when authenticationResult is set is the flow considered complete. + if (event is SignInRespondToChallenge) { + safePrint('EVENT ANSWER: ${event.answer}'); + } final authenticationResult = _authenticationResult; if (authenticationResult != null) { final accessToken = await _saveAuthResult(authenticationResult); @@ -1042,6 +1072,14 @@ final class SignInStateMachine return SignInState.success(_user.build().authUser); } + if (event is SignInRespondToChallenge && event.answer == 'totp') { + safePrint('TOTP ANSWER: ${event.answer}'); + _challengeParameters = BuiltMap({ + CognitoConstants.challengeParamMfasCanSetup: '["SOFTWARE_TOKEN_MFA"]', + }); + return _processChallenge(); + } + await _updateUser(_challengeParameters); // Configure TOTP authentication if allowed. @@ -1055,9 +1093,40 @@ final class SignInStateMachine 'Contact an administrator to enable SMS MFA or allow TOTP MFA', ); } - _totpSetupResult ??= await associateSoftwareToken(); + final allowedMfaTypes1 = [...?_allowedMfaTypes]; + allowedMfaTypes1.remove(MfaType.sms); + if (allowedMfaTypes1.length == 1) { + if (allowedMfaTypes1.first == MfaType.totp) { + // If TOTP is the only MFA type allowed, automatically set it up. + _totpSetupResult ??= await associateSoftwareToken(); + } else if (allowedMfaTypes1.first == MfaType.email) { + _enableMfaType = MfaType.email; + } + } + // _totpSetupResult ??= await associateSoftwareToken(); } + // safePrint('_authenticationResult: $_authenticationResult'); + // safePrint('----------------------------------------'); + + // safePrint('_challengeName: $_challengeName'); + // safePrint('----------------------------------------'); + + // safePrint('_challengeParameters: $_challengeParameters'); + // safePrint('----------------------------------------'); + + // safePrint('_session: $_session'); + // safePrint('----------------------------------------'); + + // safePrint('_attributesNeedingUpdate: $_attributesNeedingUpdate'); + // safePrint('----------------------------------------'); + + // safePrint('_totpSetupResult: $_totpSetupResult'); + // safePrint('----------------------------------------'); + + // safePrint('_enableMfaType: $_enableMfaType'); + // safePrint('----------------------------------------'); + // Query the state machine for a response given potential user input in // `event`. final respondRequest = await createRespondToAuthChallengeRequest( diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 41dcfe410e..e0568dc897 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -246,6 +246,8 @@ class StateMachineBloc result.nextStep.totpSetupDetails!, totpOptions, ); + case AuthSignInStep.continueSignInWithEmailMfaSetup: + yield UnauthenticatedState.continueSignInWithEmailMfaSetup; case AuthSignInStep.resetPassword: yield UnauthenticatedState.resetPassword; case AuthSignInStep.confirmSignUp: diff --git a/packages/authenticator/amplify_authenticator/lib/src/keys.dart b/packages/authenticator/amplify_authenticator/lib/src/keys.dart index 2f0665814e..8cb32f3fba 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/keys.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/keys.dart @@ -109,6 +109,8 @@ const keyGoToSignInButton = Key('goToSignInButton'); const keyConfirmSignInButton = Key('confirmSignInButton'); const keyConfirmSignInMfaSelectionButton = Key('confirmSignInMfaSelectionButton'); +const keyConfirmSignInMfaSetupSelectionButton = + Key('confirmSignInMfaSetupSelectionButton'); const keyConfirmSignInCustomButton = Key('confirmSignInCustomButton'); const keyLostCodeButton = Key('lostCodeButton'); const keySendCodeButton = Key('sendCodeButton'); diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart index bf434aba5c..45145d6084 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart @@ -407,6 +407,29 @@ class AuthenticatorState extends ChangeNotifier { _setIsBusy(false); } + /// Select MFA setup preference using the values for [selectedMfaMethod] + Future continueSignInWithMfaSetupSelection() async { + if (!_formKey.currentState!.validate()) { + return; + } + + _setIsBusy(true); + + final confirm = AuthConfirmSignInData( + confirmationValue: _selectedMfaMethod!.name, + ); + + // if (_selectedMfaMethod == MfaType.totp) { + // _authBloc.add(const AuthChangeScreen(AuthenticatorStep.continueSignInWithTotpSetup)); + // } else { + // _authBloc.add(AuthConfirmSignIn(confirm)); + // } + + _authBloc.add(AuthConfirmSignIn(confirm)); + await nextBlocEvent(); + _setIsBusy(false); + } + /// Complete TOTP setup using the values for [confirmationCode] /// and any user attributes. Future confirmTotp() async { diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart index c2c92e87bb..de0ea61761 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart @@ -253,6 +253,27 @@ class ContinueSignInMFASelectionButton extends AuthenticatorElevatedButton { state.continueSignInWithMfaSelection(); } +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.continue_sign_in_mfa_setup_selection_button} +/// A prebuilt button for Sign In with MFA setup selection. +/// +/// Uses [ButtonResolverKey.confirm] for localization +/// {@endtemplate} +class ContinueSignInMFASetupSelectionButton extends AuthenticatorElevatedButton { + /// {@macro amplify_authenticator.continue_sign_in_mfa_setup_selection_button} + const ContinueSignInMFASetupSelectionButton({Key? key}) + : super( + key: key ?? keyConfirmSignInMfaSetupSelectionButton, + ); + + @override + ButtonResolverKey get labelKey => ButtonResolverKey.continueLabel; + + @override + void onPressed(BuildContext context, AuthenticatorState state) => + state.continueSignInWithMfaSetupSelection(); +} + /// {@category Prebuilt Widgets} /// {@template amplify_authenticator.confirm_sign_in_mfa_button} /// A prebuilt button for completing Sign In with and MFA code. diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index c79d308f84..812a89c6ab 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -636,7 +636,7 @@ class ContinueSignInWithMfaSetupSelectionForm extends AuthenticatorForm { ConfirmSignInFormField.mfaSetupSelection(), ], actions: const [ - ContinueSignInMFASelectionButton(), + ContinueSignInMFASetupSelectionButton(), BackToSignInButton(), ], ); From d7dc6bc3f63c1315684a685ab76c7545e442fe3f Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 10 Oct 2024 22:14:21 -0700 Subject: [PATCH 106/159] chore: fix inherited_forms steps --- .../amplify_authenticator/lib/src/state/inherited_forms.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index 121f81bd0d..2b75184038 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -122,8 +122,8 @@ class InheritedForms extends InheritedWidget { confirmSignInWithEmailMfaCodeForm || oldWidget.continueSignInWithEmailMfaSetupForm != continueSignInWithEmailMfaSetupForm || - oldWidget.continueSignInWithMfaSelectionForm != - continueSignInWithMfaSelectionForm; + oldWidget.continueSignInWithMfaSetupSelectionForm != + continueSignInWithMfaSetupSelectionForm; } } From 2cd215bd0177806b20dccab0f39fc57b19b8df30 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 11 Oct 2024 00:01:42 -0700 Subject: [PATCH 107/159] chore: adjust continue sign in with email mfa setup form --- .../amplify_authenticator/lib/src/keys.dart | 2 ++ .../lib/src/state/authenticator_state.dart | 7 +----- .../lib/src/widgets/button.dart | 23 ++++++++++++++++++- .../lib/src/widgets/form.dart | 2 +- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/keys.dart b/packages/authenticator/amplify_authenticator/lib/src/keys.dart index 8cb32f3fba..2ad76b7c01 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/keys.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/keys.dart @@ -111,6 +111,8 @@ const keyConfirmSignInMfaSelectionButton = Key('confirmSignInMfaSelectionButton'); const keyConfirmSignInMfaSetupSelectionButton = Key('confirmSignInMfaSetupSelectionButton'); +const keyConfirmSignInWithEmailMfaSetupButton = + Key('confirmSignInWithEmailMfaSetupButton'); const keyConfirmSignInCustomButton = Key('confirmSignInCustomButton'); const keyLostCodeButton = Key('lostCodeButton'); const keySendCodeButton = Key('sendCodeButton'); diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart index 45145d6084..836c4f1a01 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/authenticator_state.dart @@ -419,12 +419,6 @@ class AuthenticatorState extends ChangeNotifier { confirmationValue: _selectedMfaMethod!.name, ); - // if (_selectedMfaMethod == MfaType.totp) { - // _authBloc.add(const AuthChangeScreen(AuthenticatorStep.continueSignInWithTotpSetup)); - // } else { - // _authBloc.add(AuthConfirmSignIn(confirm)); - // } - _authBloc.add(AuthConfirmSignIn(confirm)); await nextBlocEvent(); _setIsBusy(false); @@ -713,6 +707,7 @@ class AuthenticatorState extends ChangeNotifier { authAttributes.clear(); _publicChallengeParams.clear(); _selectedMfaMethod = null; + _mfaEmail = ''; } void _resetFormKey() { diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart index de0ea61761..a288a9e2e3 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart @@ -257,7 +257,7 @@ class ContinueSignInMFASelectionButton extends AuthenticatorElevatedButton { /// {@template amplify_authenticator.continue_sign_in_mfa_setup_selection_button} /// A prebuilt button for Sign In with MFA setup selection. /// -/// Uses [ButtonResolverKey.confirm] for localization +/// Uses [ButtonResolverKey.continueLabel] for localization /// {@endtemplate} class ContinueSignInMFASetupSelectionButton extends AuthenticatorElevatedButton { /// {@macro amplify_authenticator.continue_sign_in_mfa_setup_selection_button} @@ -274,6 +274,27 @@ class ContinueSignInMFASetupSelectionButton extends AuthenticatorElevatedButton state.continueSignInWithMfaSetupSelection(); } +/// {@category Prebuilt Widgets} +/// {@template amplify_authenticator.continue_sign_in_with_email_mfa_setup_button} +/// A prebuilt button for Sign In with Email MFA setup. +/// +/// Uses [ButtonResolverKey.continueLabel] for localization +/// {@endtemplate} +class ContinueSignInWithEmailMfaSetupButton extends AuthenticatorElevatedButton { + /// {@macro amplify_authenticator.continue_sign_in_with_email_mfa_setup_button} + const ContinueSignInWithEmailMfaSetupButton({Key? key}) + : super( + key: key ?? keyConfirmSignInWithEmailMfaSetupButton, + ); + + @override + ButtonResolverKey get labelKey => ButtonResolverKey.continueLabel; + + @override + void onPressed(BuildContext context, AuthenticatorState state) => + state.continueEmailMfaSetup(); +} + /// {@category Prebuilt Widgets} /// {@template amplify_authenticator.confirm_sign_in_mfa_button} /// A prebuilt button for completing Sign In with and MFA code. diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index 812a89c6ab..b8a7bd15b1 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -682,7 +682,7 @@ class ContinueSignInWithEmailMfaSetupForm extends AuthenticatorForm { EmailSetupFormField.email(), ], actions: const [ - ConfirmSignInMFAButton(), + ContinueSignInWithEmailMfaSetupButton(), BackToSignInButton(), ], ); From 495ff1e14fca974b3dacbe3a9025762642962b32 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 11 Oct 2024 00:02:10 -0700 Subject: [PATCH 108/159] chore: refactor large nested if statement blocks in state machine --- .../state/machines/sign_in_state_machine.dart | 147 +++++------------- 1 file changed, 41 insertions(+), 106 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 3858159fd7..55ea5cd602 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -667,67 +667,43 @@ final class SignInStateMachine ); } - // if (mfaTypesForSetup.length == 1) { - // // Only one MFA type is allowed for setup - // _enableMfaType = mfaTypesForSetup.first; - // if (_enableMfaType == MfaType.totp) { - // _totpSetupResult = await associateSoftwareToken(); - // return createMfaSetupRequest(event as SignInRespondToChallenge); - // } else if (_enableMfaType == MfaType.email) { - // return createEmailMfaSetupRequest(event as SignInRespondToChallenge); - // } - // } - - if (hasUserResponse) { - if (_enableMfaType == null) { - // User has just selected the MFA type - if (event == null) { - throw StateError('Event cannot be null when there is user response.'); - } - if (event is! SignInRespondToChallenge) { - throw StateError('Expected SignInRespondToChallenge event.'); - } - final selection = event.answer.toLowerCase(); - _enableMfaType = switch (selection) { - 'totp' => MfaType.totp, - 'email' => MfaType.email, - _ => - throw const InvalidParameterException('Invalid MFA type selected'), - }; - - if (_enableMfaType == MfaType.totp) { - final challengeResponses = { - CognitoConstants.challengeParamMfasCanSetup: - '["SOFTWARE_TOKEN_MFA"]', - }; - final builtMap = BuiltMap(challengeResponses); - _challengeParameters = builtMap; - // await _processChallenge(event); - return null; - } else if (_enableMfaType == MfaType.email) { - await _processChallenge(event); - } - } else { - // User has provided the verification code - if (event == null) { - throw StateError('Event cannot be null when there is user response.'); - } - if (event is! SignInRespondToChallenge) { - throw StateError('Expected SignInRespondToChallenge event.'); - } - if (_enableMfaType == MfaType.totp) { - return createMfaSetupRequest(event); - } else if (_enableMfaType == MfaType.email) { - return createEmailMfaSetupRequest(event); - } - } - } else { - // Need to prompt user to select an MFA type - return null; - } + if (!hasUserResponse) { + // Need to prompt user to select an MFA type + return null; + } + + if (event == null) { + throw StateError('Event cannot be null when there is user response.'); + } + if (event is! SignInRespondToChallenge) { + throw StateError('Expected SignInRespondToChallenge event.'); + } + + if (_enableMfaType == null) { + // User has just selected the MFA type + final selection = event.answer.toLowerCase(); + _enableMfaType = switch (selection) { + 'totp' => MfaType.totp, + 'email' => MfaType.email, + _ => throw const InvalidParameterException('Invalid MFA type selected'), + }; + + final challengeResponses = { + CognitoConstants.challengeParamMfasCanSetup: _enableMfaType == MfaType.totp + ? '["SOFTWARE_TOKEN_MFA"]' + : '["EMAIL_OTP"]', + }; + _challengeParameters = BuiltMap(challengeResponses); + await _processChallenge(); return null; } + // User has provided the verification code + return _enableMfaType == MfaType.totp + ? createMfaSetupRequest(event) + : createEmailMfaSetupRequest(event); + } + /// Completes set up of a TOTP MFA. @protected Future createMfaSetupRequest( @@ -759,10 +735,10 @@ final class SignInStateMachine _enableMfaType = MfaType.email; return RespondToAuthChallengeRequest.build((b) { b - ..challengeName = ChallengeNameType.emailOtp + ..challengeName = ChallengeNameType.mfaSetup ..challengeResponses.addAll({ CognitoConstants.challengeParamUsername: cognitoUsername, - CognitoConstants.challengeParamEmailMfaCode: event.answer, + CognitoConstants.challengeParamEmail: event.answer, }) ..clientId = _authOutputs.userPoolClientId ..clientMetadata.addAll(event.clientMetadata); @@ -1015,9 +991,6 @@ final class SignInStateMachine Future _processChallenge([SignInEvent? event]) async { // There can be an indefinite amount of challenges which need responses. // Only when authenticationResult is set is the flow considered complete. - if (event is SignInRespondToChallenge) { - safePrint('EVENT ANSWER: ${event.answer}'); - } final authenticationResult = _authenticationResult; if (authenticationResult != null) { final accessToken = await _saveAuthResult(authenticationResult); @@ -1072,61 +1045,23 @@ final class SignInStateMachine return SignInState.success(_user.build().authUser); } - if (event is SignInRespondToChallenge && event.answer == 'totp') { - safePrint('TOTP ANSWER: ${event.answer}'); - _challengeParameters = BuiltMap({ - CognitoConstants.challengeParamMfasCanSetup: '["SOFTWARE_TOKEN_MFA"]', - }); - return _processChallenge(); - } - await _updateUser(_challengeParameters); // Configure TOTP authentication if allowed. if (_allowedMfaTypes case final allowedMfaTypes? when _challengeParameters .containsKey(CognitoConstants.challengeParamMfasCanSetup)) { - if (!allowedMfaTypes.contains(MfaType.totp)) { + if (!allowedMfaTypes.contains(MfaType.totp) && !allowedMfaTypes.contains(MfaType.email)) { throw const InvalidUserPoolConfigurationException( - 'Cannot enable SMS MFA and TOTP MFA is not allowed', + 'Cannot enable SMS MFA and TOTP or EMAIL MFA is not allowed', recoverySuggestion: - 'Contact an administrator to enable SMS MFA or allow TOTP MFA', + 'Contact an administrator to enable SMS MFA or allow TOTP or EMAIL MFA', ); } - final allowedMfaTypes1 = [...?_allowedMfaTypes]; - allowedMfaTypes1.remove(MfaType.sms); - if (allowedMfaTypes1.length == 1) { - if (allowedMfaTypes1.first == MfaType.totp) { - // If TOTP is the only MFA type allowed, automatically set it up. - _totpSetupResult ??= await associateSoftwareToken(); - } else if (allowedMfaTypes1.first == MfaType.email) { - _enableMfaType = MfaType.email; - } - } - // _totpSetupResult ??= await associateSoftwareToken(); + final allowedMfaSetupTypes = [...?_allowedMfaTypes]..remove(MfaType.sms); + if (allowedMfaSetupTypes.length == 1 && allowedMfaSetupTypes.first == MfaType.totp) _totpSetupResult = await associateSoftwareToken(accessToken: _session); } - // safePrint('_authenticationResult: $_authenticationResult'); - // safePrint('----------------------------------------'); - - // safePrint('_challengeName: $_challengeName'); - // safePrint('----------------------------------------'); - - // safePrint('_challengeParameters: $_challengeParameters'); - // safePrint('----------------------------------------'); - - // safePrint('_session: $_session'); - // safePrint('----------------------------------------'); - - // safePrint('_attributesNeedingUpdate: $_attributesNeedingUpdate'); - // safePrint('----------------------------------------'); - - // safePrint('_totpSetupResult: $_totpSetupResult'); - // safePrint('----------------------------------------'); - - // safePrint('_enableMfaType: $_enableMfaType'); - // safePrint('----------------------------------------'); - // Query the state machine for a response given potential user input in // `event`. final respondRequest = await createRespondToAuthChallengeRequest( From e1bf813f39ecb73023b23513494020a4409ad14c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 11 Oct 2024 00:08:51 -0700 Subject: [PATCH 109/159] chore: auth_bloc refactor to separate logic into a helper function and simplify the code --- .../lib/src/blocs/auth/auth_bloc.dart | 94 +++++++++---------- 1 file changed, 44 insertions(+), 50 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index e0568dc897..bfb49dbbc5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -234,9 +234,7 @@ class StateMachineBloc allowedMfaTypes: result.nextStep.allowedMfaTypes, ); case AuthSignInStep.continueSignInWithMfaSetupSelection: - yield ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: result.nextStep.allowedMfaTypes, - ); + await _handleMfaSetupSelection(result); case AuthSignInStep.continueSignInWithTotpSetup: assert( result.nextStep.totpSetupDetails != null, @@ -342,53 +340,7 @@ class StateMachineBloc ), ); case AuthSignInStep.continueSignInWithMfaSetupSelection: - final allowedMfaTypes = result.nextStep.allowedMfaTypes; - if (allowedMfaTypes != null) { - final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); - if (mfaTypesForSetup.length == 1) { - final mfaType = mfaTypesForSetup.first; - if (mfaType == MfaType.totp) { - assert( - result.nextStep.totpSetupDetails != null, - 'Sign In Result should have totpSetupDetails', - ); - _emit(await ContinueSignInTotpSetup.setupURI( - result.nextStep.totpSetupDetails!, - totpOptions, - ),); - } else if (mfaType == MfaType.email) { - _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); - } else { - throw InvalidUserPoolConfigurationException( - 'Unsupported MFA type: ${mfaType.name}', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - } else { - _emit( - ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: result.nextStep.allowedMfaTypes, - ), - ); - } - } else { - _emit( - ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: result.nextStep.allowedMfaTypes, - ), - ); - } - case AuthSignInStep.continueSignInWithTotpSetup: - assert( - result.nextStep.totpSetupDetails != null, - 'Sign In Result should have totpSetupDetails', - ); - _emit( - await ContinueSignInTotpSetup.setupURI( - result.nextStep.totpSetupDetails!, - totpOptions, - ), - ); + await _handleMfaSetupSelection(result); case AuthSignInStep.continueSignInWithEmailMfaSetup: _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); case AuthSignInStep.confirmSignInWithTotpMfaCode: @@ -591,6 +543,48 @@ class StateMachineBloc yield* const Stream.empty(); } +Future _handleMfaSetupSelection(SignInResult result) async { + final allowedMfaTypes = result.nextStep.allowedMfaTypes; + if (allowedMfaTypes != null) { + final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); + if (mfaTypesForSetup.length == 1) { + final mfaType = mfaTypesForSetup.first; + if (mfaType == MfaType.totp) { + assert( + result.nextStep.totpSetupDetails != null, + 'Sign In Result should have totpSetupDetails', + ); + _emit( + await ContinueSignInTotpSetup.setupURI( + result.nextStep.totpSetupDetails!, + totpOptions, + ), + ); + } else if (mfaType == MfaType.email) { + _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); + } else { + throw InvalidUserPoolConfigurationException( + 'Unsupported MFA type: ${mfaType.name}', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + } else { + _emit( + ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: result.nextStep.allowedMfaTypes, + ), + ); + } + } else { + _emit( + ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: result.nextStep.allowedMfaTypes, + ), + ); + } +} + + @override Future close() async { await Future.wait([ From cd610eac7d13eebc01d5ef056610a4b11e0f5c54 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 14 Oct 2024 10:54:40 -0700 Subject: [PATCH 110/159] chore: fix the email setup form field --- .../lib/src/blocs/auth/auth_bloc.dart | 57 +++++++------- .../lib/src/widgets/button.dart | 8 +- .../form_fields/email_setup_form_field.dart | 74 ++++++++----------- 3 files changed, 62 insertions(+), 77 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index bfb49dbbc5..6bf58c0493 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -543,30 +543,37 @@ class StateMachineBloc yield* const Stream.empty(); } -Future _handleMfaSetupSelection(SignInResult result) async { - final allowedMfaTypes = result.nextStep.allowedMfaTypes; - if (allowedMfaTypes != null) { - final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); - if (mfaTypesForSetup.length == 1) { - final mfaType = mfaTypesForSetup.first; - if (mfaType == MfaType.totp) { - assert( - result.nextStep.totpSetupDetails != null, - 'Sign In Result should have totpSetupDetails', - ); + Future _handleMfaSetupSelection(SignInResult result) async { + final allowedMfaTypes = result.nextStep.allowedMfaTypes; + if (allowedMfaTypes != null) { + final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); + if (mfaTypesForSetup.length == 1) { + final mfaType = mfaTypesForSetup.first; + if (mfaType == MfaType.totp) { + assert( + result.nextStep.totpSetupDetails != null, + 'Sign In Result should have totpSetupDetails', + ); + _emit( + await ContinueSignInTotpSetup.setupURI( + result.nextStep.totpSetupDetails!, + totpOptions, + ), + ); + } else if (mfaType == MfaType.email) { + _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); + } else { + throw InvalidUserPoolConfigurationException( + 'Unsupported MFA type: ${mfaType.name}', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + } else { _emit( - await ContinueSignInTotpSetup.setupURI( - result.nextStep.totpSetupDetails!, - totpOptions, + ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: result.nextStep.allowedMfaTypes, ), ); - } else if (mfaType == MfaType.email) { - _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); - } else { - throw InvalidUserPoolConfigurationException( - 'Unsupported MFA type: ${mfaType.name}', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); } } else { _emit( @@ -575,15 +582,7 @@ Future _handleMfaSetupSelection(SignInResult result) async { ), ); } - } else { - _emit( - ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: result.nextStep.allowedMfaTypes, - ), - ); } -} - @override Future close() async { diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart index a288a9e2e3..ccd43114da 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/button.dart @@ -259,7 +259,8 @@ class ContinueSignInMFASelectionButton extends AuthenticatorElevatedButton { /// /// Uses [ButtonResolverKey.continueLabel] for localization /// {@endtemplate} -class ContinueSignInMFASetupSelectionButton extends AuthenticatorElevatedButton { +class ContinueSignInMFASetupSelectionButton + extends AuthenticatorElevatedButton { /// {@macro amplify_authenticator.continue_sign_in_mfa_setup_selection_button} const ContinueSignInMFASetupSelectionButton({Key? key}) : super( @@ -277,10 +278,11 @@ class ContinueSignInMFASetupSelectionButton extends AuthenticatorElevatedButton /// {@category Prebuilt Widgets} /// {@template amplify_authenticator.continue_sign_in_with_email_mfa_setup_button} /// A prebuilt button for Sign In with Email MFA setup. -/// +/// /// Uses [ButtonResolverKey.continueLabel] for localization /// {@endtemplate} -class ContinueSignInWithEmailMfaSetupButton extends AuthenticatorElevatedButton { +class ContinueSignInWithEmailMfaSetupButton + extends AuthenticatorElevatedButton { /// {@macro amplify_authenticator.continue_sign_in_with_email_mfa_setup_button} const ContinueSignInWithEmailMfaSetupButton({Key? key}) : super( diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart index 47951cbe8f..9884b69122 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_fields/email_setup_form_field.dart @@ -7,8 +7,8 @@ part of '../form_field.dart'; /// {@template amplify_authenticator.email_setup_form_field} /// A prebuilt form field widget for use on the Email MFA setup step. /// {@endtemplate} -abstract class EmailSetupFormField - extends AuthenticatorFormField { +class EmailSetupFormField + extends AuthenticatorFormField { /// {@macro amplify_authenticator.email_setup_form_field} /// /// Either [titleKey] or [title] is required. @@ -23,25 +23,30 @@ abstract class EmailSetupFormField super.autofillHints, }) : super._(); - /// Creates an email component. - static EmailSetupFormField email({ + /// Creates an email FormField for the email setup step. + const EmailSetupFormField.email({ Key? key, FormFieldValidator? validator, Iterable? autofillHints, - }) => - _EmailSetupTextField( - key: key ?? keyEmailSetupFormField, - titleKey: InputResolverKey.emailTitle, - hintTextKey: InputResolverKey.emailHint, - field: EmailSetupField.email, - validator: validator, - autofillHints: autofillHints, - ); + }) : this._( + key: key ?? keyEmailSetupFormField, + field: EmailSetupField.email, + titleKey: InputResolverKey.emailTitle, + hintTextKey: InputResolverKey.emailHint, + validator: validator, + autofillHints: autofillHints, + ); + + @override + bool get required => true; + + @override + AuthenticatorFormFieldState + createState() => _EmailSetupFormFieldState(); } -abstract class _EmailSetupFormFieldState - extends AuthenticatorFormFieldState> { +class _EmailSetupFormFieldState extends AuthenticatorFormFieldState< + EmailSetupField, String, EmailSetupFormField> with AuthenticatorTextField { @override TextInputType get keyboardType { return TextInputType.emailAddress; @@ -52,38 +57,17 @@ abstract class _EmailSetupFormFieldState return [AutofillHints.email]; } - bool get required { - switch (widget.field) { - case EmailSetupField.email: - return true; - } - } - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('required', required)); + ValueChanged get onChanged { + return (v) => state.mfaEmail = v; } -} - -class _EmailSetupTextField extends EmailSetupFormField { - const _EmailSetupTextField({ - super.key, - required super.field, - super.titleKey, - super.hintTextKey, - super.validator, - super.autofillHints, - }) : super._(); - - @override - _EmailSetupTextFieldState createState() => _EmailSetupTextFieldState(); -} -class _EmailSetupTextFieldState extends _EmailSetupFormFieldState - with AuthenticatorTextField { @override - bool get obscureText { - return false; + FormFieldValidator get validator { + return validateEmail( + isOptional: isOptional, + context: context, + inputResolver: stringResolver.inputs, + ); } } From 1d44a2ef9d23f75a4fa60134a5af5c2aaea4ea14 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:31:23 -0700 Subject: [PATCH 111/159] chore: fix totp selection flow --- .../lib/src/state/machines/sign_in_state_machine.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 55ea5cd602..bd3f16ad88 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -679,7 +679,7 @@ final class SignInStateMachine throw StateError('Expected SignInRespondToChallenge event.'); } - if (_enableMfaType == null) { + if (_enableMfaType == null && _totpSetupResult == null) { // User has just selected the MFA type final selection = event.answer.toLowerCase(); _enableMfaType = switch (selection) { @@ -698,6 +698,11 @@ final class SignInStateMachine return null; } + // totp mfa method was already selected + if (mfaTypesForSetup.length == 1 && mfaTypesForSetup.contains(MfaType.totp) && _totpSetupResult != null) { + createSoftwareTokenMfaRequest(event); + } + // User has provided the verification code return _enableMfaType == MfaType.totp ? createMfaSetupRequest(event) @@ -1059,7 +1064,7 @@ final class SignInStateMachine ); } final allowedMfaSetupTypes = [...?_allowedMfaTypes]..remove(MfaType.sms); - if (allowedMfaSetupTypes.length == 1 && allowedMfaSetupTypes.first == MfaType.totp) _totpSetupResult = await associateSoftwareToken(accessToken: _session); + if (allowedMfaSetupTypes.length == 1 && allowedMfaSetupTypes.first == MfaType.totp && _totpSetupResult == null) _totpSetupResult = await associateSoftwareToken(accessToken: _session); } // Query the state machine for a response given potential user input in From 02fb1a6b55783106906d7b48fb3829e25c6742e9 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:17:34 -0700 Subject: [PATCH 112/159] chore: remove safePrint --- .../lib/src/auth_plugin_impl.dart | 9 --------- 1 file changed, 9 deletions(-) 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 8ccd19262a..24f8ba145c 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 @@ -496,15 +496,6 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface ); case final SignInChallenge challenge: - // Print all properties of SignInChallenge - safePrint('Challenge name: ${challenge.challengeName}'); - safePrint('Sign in Step: ${challenge.challengeName.signInStep}'); - safePrint('Challenge parameters: ${challenge.challengeParameters}'); - safePrint('Code delivery details: ${challenge.codeDeliveryDetails}'); - safePrint('Required attributes: ${challenge.requiredAttributes}'); - safePrint('Allowed MFA types: ${challenge.allowedMfaTypes}'); - safePrint('TOTP setup result: ${challenge.totpSetupResult}'); - return CognitoSignInResult( isSignedIn: false, nextStep: AuthNextSignInStep( From 85368f16f1c956cf27ada88502d3f4cd18e40561 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:17:58 -0700 Subject: [PATCH 113/159] chore: dart format --- .../lib/src/auth_plugin_impl.dart | 66 +++++++-------- .../state/machines/sign_in_state_machine.dart | 83 ++++++++++--------- 2 files changed, 78 insertions(+), 71 deletions(-) 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 24f8ba145c..e6a848919e 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 @@ -481,43 +481,43 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface } CognitoSignInResult _processSignInResult(SignInState result) { - switch (result) { - case SignInNotStarted(): - case SignInInitiating(): - // This should never happen. - throw UnknownException( - 'Sign in could not be completed', - underlyingException: result, - ); + switch (result) { + case SignInNotStarted(): + case SignInInitiating(): + // This should never happen. + throw UnknownException( + 'Sign in could not be completed', + underlyingException: result, + ); - case SignInCancelling(): - throw const UserCancelledException( - 'The user canceled the sign-in flow', - ); + case SignInCancelling(): + throw const UserCancelledException( + 'The user canceled the sign-in flow', + ); - case final SignInChallenge challenge: - return CognitoSignInResult( - isSignedIn: false, - nextStep: AuthNextSignInStep( - signInStep: challenge.challengeName.signInStep, - codeDeliveryDetails: challenge.codeDeliveryDetails, - additionalInfo: challenge.challengeParameters, - missingAttributes: challenge.requiredAttributes, - allowedMfaTypes: challenge.allowedMfaTypes, - totpSetupDetails: challenge.totpSetupResult, - ), - ); + case final SignInChallenge challenge: + return CognitoSignInResult( + isSignedIn: false, + nextStep: AuthNextSignInStep( + signInStep: challenge.challengeName.signInStep, + codeDeliveryDetails: challenge.codeDeliveryDetails, + additionalInfo: challenge.challengeParameters, + missingAttributes: challenge.requiredAttributes, + allowedMfaTypes: challenge.allowedMfaTypes, + totpSetupDetails: challenge.totpSetupResult, + ), + ); - case SignInSuccess(): - return const CognitoSignInResult( - isSignedIn: true, - nextStep: AuthNextSignInStep( - signInStep: AuthSignInStep.done, - ), - ); + case SignInSuccess(): + return const CognitoSignInResult( + isSignedIn: true, + nextStep: AuthNextSignInStep( + signInStep: AuthSignInStep.done, + ), + ); - case final SignInFailure failure: - Error.throwWithStackTrace(failure.exception, failure.stackTrace); + case final SignInFailure failure: + Error.throwWithStackTrace(failure.exception, failure.stackTrace); // To satisfy Dart's requirements, even if unreachable } } diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index bd3f16ad88..e1d4f45101 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -667,46 +667,49 @@ final class SignInStateMachine ); } - if (!hasUserResponse) { - // Need to prompt user to select an MFA type - return null; - } - - if (event == null) { - throw StateError('Event cannot be null when there is user response.'); - } - if (event is! SignInRespondToChallenge) { - throw StateError('Expected SignInRespondToChallenge event.'); - } + if (!hasUserResponse) { + // Need to prompt user to select an MFA type + return null; + } - if (_enableMfaType == null && _totpSetupResult == null) { - // User has just selected the MFA type - final selection = event.answer.toLowerCase(); - _enableMfaType = switch (selection) { - 'totp' => MfaType.totp, - 'email' => MfaType.email, - _ => throw const InvalidParameterException('Invalid MFA type selected'), - }; + if (event == null) { + throw StateError('Event cannot be null when there is user response.'); + } + if (event is! SignInRespondToChallenge) { + throw StateError('Expected SignInRespondToChallenge event.'); + } - final challengeResponses = { - CognitoConstants.challengeParamMfasCanSetup: _enableMfaType == MfaType.totp - ? '["SOFTWARE_TOKEN_MFA"]' - : '["EMAIL_OTP"]', - }; - _challengeParameters = BuiltMap(challengeResponses); - await _processChallenge(); - return null; - } + if (_enableMfaType == null && _totpSetupResult == null) { + // User has just selected the MFA type + final selection = event.answer.toLowerCase(); + _enableMfaType = switch (selection) { + 'totp' => MfaType.totp, + 'email' => MfaType.email, + _ => throw const InvalidParameterException('Invalid MFA type selected'), + }; + + final challengeResponses = { + CognitoConstants.challengeParamMfasCanSetup: + _enableMfaType == MfaType.totp + ? '["SOFTWARE_TOKEN_MFA"]' + : '["EMAIL_OTP"]', + }; + _challengeParameters = BuiltMap(challengeResponses); + await _processChallenge(); + return null; + } - // totp mfa method was already selected - if (mfaTypesForSetup.length == 1 && mfaTypesForSetup.contains(MfaType.totp) && _totpSetupResult != null) { - createSoftwareTokenMfaRequest(event); - } + // totp mfa method was already selected + if (mfaTypesForSetup.length == 1 && + mfaTypesForSetup.contains(MfaType.totp) && + _totpSetupResult != null) { + createSoftwareTokenMfaRequest(event); + } - // User has provided the verification code - return _enableMfaType == MfaType.totp - ? createMfaSetupRequest(event) - : createEmailMfaSetupRequest(event); + // User has provided the verification code + return _enableMfaType == MfaType.totp + ? createMfaSetupRequest(event) + : createEmailMfaSetupRequest(event); } /// Completes set up of a TOTP MFA. @@ -1056,7 +1059,8 @@ final class SignInStateMachine if (_allowedMfaTypes case final allowedMfaTypes? when _challengeParameters .containsKey(CognitoConstants.challengeParamMfasCanSetup)) { - if (!allowedMfaTypes.contains(MfaType.totp) && !allowedMfaTypes.contains(MfaType.email)) { + if (!allowedMfaTypes.contains(MfaType.totp) && + !allowedMfaTypes.contains(MfaType.email)) { throw const InvalidUserPoolConfigurationException( 'Cannot enable SMS MFA and TOTP or EMAIL MFA is not allowed', recoverySuggestion: @@ -1064,7 +1068,10 @@ final class SignInStateMachine ); } final allowedMfaSetupTypes = [...?_allowedMfaTypes]..remove(MfaType.sms); - if (allowedMfaSetupTypes.length == 1 && allowedMfaSetupTypes.first == MfaType.totp && _totpSetupResult == null) _totpSetupResult = await associateSoftwareToken(accessToken: _session); + if (allowedMfaSetupTypes.length == 1 && + allowedMfaSetupTypes.first == MfaType.totp && + _totpSetupResult == null) + _totpSetupResult = await associateSoftwareToken(accessToken: _session); } // Query the state machine for a response given potential user input in From e7e08880d67aeb06455cdcb0f30a5bdb4f9e9ad9 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:57:44 -0700 Subject: [PATCH 114/159] chore: refactor setMfaSettings to make it easier to read with helper methods --- .../lib/src/sdk/sdk_bridge.dart | 104 +++++++++++------- 1 file changed, 65 insertions(+), 39 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index 8ea47761ed..d137d37225 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -804,55 +804,27 @@ extension MfaSettings on CognitoIdentityProviderClient { preferred: currentPreference, ) = await _getRawUserSettings(accessToken: accessToken); - final newPreferredMethods = [ - if (sms == MfaPreference.preferred) MfaType.sms, - if (totp == MfaPreference.preferred) MfaType.totp, - if (email == MfaPreference.preferred) MfaType.email, - ]; - - if (newPreferredMethods.length > 1) { - throw const InvalidParameterException( - 'Cannot assign multiple MFA methods as preferred', - ); - } - - var preferred = newPreferredMethods.isNotEmpty - ? newPreferredMethods.first - : currentPreference; - - final isCurrentPreferenceDisabled = switch (currentPreference) { - MfaType.sms => - sms == MfaPreference.disabled || sms == MfaPreference.notPreferred, - MfaType.totp => - totp == MfaPreference.disabled || totp == MfaPreference.notPreferred, - MfaType.email => - email == MfaPreference.disabled || email == MfaPreference.notPreferred, - _ => false, - }; - preferred = isCurrentPreferenceDisabled ? null : preferred; - - const enabledValues = [ - MfaPreference.enabled, - MfaPreference.notPreferred, - MfaPreference.preferred, - ]; + var preferred = + _getNewPreferredMethod(sms: sms, totp: totp, email: email) ?? + currentPreference; - bool isMfaEnabled(MfaType mfaType, MfaPreference? preference) { - if (preference == MfaPreference.disabled) return false; - return currentEnabled.contains(mfaType) || - enabledValues.contains(preference); + if (_isCurrentPreferenceDisabled(currentPreference, + sms: sms, totp: totp, email: email,)) { + preferred = null; } final smsMfaSettings = SmsMfaSettingsType( - enabled: isMfaEnabled(MfaType.sms, sms), + enabled: _isMfaEnabled(MfaType.sms, sms, currentEnabled), preferredMfa: preferred == MfaType.sms, ); + final softwareTokenSettings = SoftwareTokenMfaSettingsType( - enabled: isMfaEnabled(MfaType.totp, totp), + enabled: _isMfaEnabled(MfaType.totp, totp, currentEnabled), preferredMfa: preferred == MfaType.totp, ); + final emailMfaSettings = EmailMfaSettingsType( - enabled: isMfaEnabled(MfaType.email, email), + enabled: _isMfaEnabled(MfaType.email, email, currentEnabled), preferredMfa: preferred == MfaType.email, ); @@ -865,6 +837,60 @@ extension MfaSettings on CognitoIdentityProviderClient { ), ).result; } + + /// Making sure a maximum of one MFA method is set to preferred. + MfaType? _getNewPreferredMethod({ + MfaPreference? sms, + MfaPreference? totp, + MfaPreference? email, + }) { + final preferredMethods = [ + if (sms == MfaPreference.preferred) MfaType.sms, + if (totp == MfaPreference.preferred) MfaType.totp, + if (email == MfaPreference.preferred) MfaType.email, + ]; + + if (preferredMethods.length > 1) { + throw const InvalidParameterException( + 'Cannot assign multiple MFA methods as preferred', + ); + } + + return preferredMethods.isNotEmpty ? preferredMethods.first : null; + } + + /// Checks if the current preferred MFA method is being disabled or set to not preferred. + bool _isCurrentPreferenceDisabled( + MfaType? currentPreference, { + MfaPreference? sms, + MfaPreference? totp, + MfaPreference? email, + }) { + switch (currentPreference) { + case MfaType.sms: + return sms == MfaPreference.disabled || + sms == MfaPreference.notPreferred; + case MfaType.totp: + return totp == MfaPreference.disabled || + totp == MfaPreference.notPreferred; + case MfaType.email: + return email == MfaPreference.disabled || + email == MfaPreference.notPreferred; + default: + return false; + } + } + + /// Determines if an MFA type should be enabled based on preferences and current settings. + bool _isMfaEnabled( + MfaType mfaType, + MfaPreference? preference, + Set currentEnabled, + ) { + if (preference == MfaPreference.disabled) return false; + if (preference != null) return true; + return currentEnabled.contains(mfaType); + } } extension on String { From 4135f06efeeca7635285f2a9f0b46bc5bf433a40 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 14 Oct 2024 23:21:00 -0700 Subject: [PATCH 115/159] chore: refactor auth_bloc with helper function used in two switch statements --- .../lib/src/blocs/auth/auth_bloc.dart | 96 +++++++++---------- 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index d0cbff9fe8..6bf58c0493 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -234,9 +234,7 @@ class StateMachineBloc allowedMfaTypes: result.nextStep.allowedMfaTypes, ); case AuthSignInStep.continueSignInWithMfaSetupSelection: - yield ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: result.nextStep.allowedMfaTypes, - ); + await _handleMfaSetupSelection(result); case AuthSignInStep.continueSignInWithTotpSetup: assert( result.nextStep.totpSetupDetails != null, @@ -246,6 +244,8 @@ class StateMachineBloc result.nextStep.totpSetupDetails!, totpOptions, ); + case AuthSignInStep.continueSignInWithEmailMfaSetup: + yield UnauthenticatedState.continueSignInWithEmailMfaSetup; case AuthSignInStep.resetPassword: yield UnauthenticatedState.resetPassword; case AuthSignInStep.confirmSignUp: @@ -340,54 +340,7 @@ class StateMachineBloc ), ); case AuthSignInStep.continueSignInWithMfaSetupSelection: - final allowedMfaTypes = result.nextStep.allowedMfaTypes; - if (allowedMfaTypes != null) { - final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); - if (mfaTypesForSetup.length == 1) { - final mfaType = mfaTypesForSetup.first; - if (mfaType == MfaType.totp) { - assert( - result.nextStep.totpSetupDetails != null, - 'Sign In Result should have totpSetupDetails', - ); - _emit( - await ContinueSignInTotpSetup.setupURI( - result.nextStep.totpSetupDetails!, - totpOptions, - ), - ); - } else if (mfaType == MfaType.email) { - _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); - } else { - throw InvalidUserPoolConfigurationException( - 'Unsupported MFA type: ${mfaType.name}', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - } else { - _emit( - ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: result.nextStep.allowedMfaTypes, - ), - ); - } - } else { - throw const InvalidUserPoolConfigurationException( - 'Allowed MFA types are null', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - case AuthSignInStep.continueSignInWithTotpSetup: - assert( - result.nextStep.totpSetupDetails != null, - 'Sign In Result should have totpSetupDetails', - ); - _emit( - await ContinueSignInTotpSetup.setupURI( - result.nextStep.totpSetupDetails!, - totpOptions, - ), - ); + await _handleMfaSetupSelection(result); case AuthSignInStep.continueSignInWithEmailMfaSetup: _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); case AuthSignInStep.confirmSignInWithTotpMfaCode: @@ -590,6 +543,47 @@ class StateMachineBloc yield* const Stream.empty(); } + Future _handleMfaSetupSelection(SignInResult result) async { + final allowedMfaTypes = result.nextStep.allowedMfaTypes; + if (allowedMfaTypes != null) { + final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); + if (mfaTypesForSetup.length == 1) { + final mfaType = mfaTypesForSetup.first; + if (mfaType == MfaType.totp) { + assert( + result.nextStep.totpSetupDetails != null, + 'Sign In Result should have totpSetupDetails', + ); + _emit( + await ContinueSignInTotpSetup.setupURI( + result.nextStep.totpSetupDetails!, + totpOptions, + ), + ); + } else if (mfaType == MfaType.email) { + _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); + } else { + throw InvalidUserPoolConfigurationException( + 'Unsupported MFA type: ${mfaType.name}', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + } else { + _emit( + ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: result.nextStep.allowedMfaTypes, + ), + ); + } + } else { + _emit( + ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: result.nextStep.allowedMfaTypes, + ), + ); + } + } + @override Future close() async { await Future.wait([ From eb93be4403c2148d3605f7f376df3c57dd1cb8d3 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 14 Oct 2024 23:49:17 -0700 Subject: [PATCH 116/159] chore: refactor auth bloc helper method to remove nested if/else statements --- .../lib/src/blocs/auth/auth_bloc.dart | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 6bf58c0493..f53beb7acd 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -545,42 +545,48 @@ class StateMachineBloc Future _handleMfaSetupSelection(SignInResult result) async { final allowedMfaTypes = result.nextStep.allowedMfaTypes; - if (allowedMfaTypes != null) { - final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); - if (mfaTypesForSetup.length == 1) { - final mfaType = mfaTypesForSetup.first; - if (mfaType == MfaType.totp) { - assert( - result.nextStep.totpSetupDetails != null, - 'Sign In Result should have totpSetupDetails', - ); - _emit( - await ContinueSignInTotpSetup.setupURI( - result.nextStep.totpSetupDetails!, - totpOptions, - ), - ); - } else if (mfaType == MfaType.email) { - _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); - } else { - throw InvalidUserPoolConfigurationException( - 'Unsupported MFA type: ${mfaType.name}', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - } else { - _emit( - ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: result.nextStep.allowedMfaTypes, - ), - ); - } - } else { + + if (allowedMfaTypes == null) { + throw const InvalidUserPoolConfigurationException( + 'No MFA types are supported', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); + } + + final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); + + if (mfaTypesForSetup.length != 1) { _emit( ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: result.nextStep.allowedMfaTypes, + allowedMfaTypes: allowedMfaTypes, ), ); + return; + } + + final mfaType = mfaTypesForSetup.first; + + switch (mfaType) { + case MfaType.totp: + assert( + result.nextStep.totpSetupDetails != null, + 'Sign In Result should have totpSetupDetails', + ); + _emit( + await ContinueSignInTotpSetup.setupURI( + result.nextStep.totpSetupDetails!, + totpOptions, + ), + ); + + case MfaType.email: + _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); + + default: + throw InvalidUserPoolConfigurationException( + 'Unsupported MFA type: ${mfaType.name}', + recoverySuggestion: 'Check your user pool MFA configuration.', + ); } } From daacad78fc72cd5c9b38d1aaa4a77804c411499a Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 15 Oct 2024 00:22:36 -0700 Subject: [PATCH 117/159] chore: refactor sign in state machine and add in constants for email challenge --- .../lib/src/flows/constants.dart | 3 + .../state/machines/sign_in_state_machine.dart | 89 +++++++++++-------- 2 files changed, 53 insertions(+), 39 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart index 7a40ff446c..7f916b290b 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart @@ -11,6 +11,9 @@ abstract class CognitoConstants { /// The `USERNAME` parameter. static const challengeParamUsername = 'USERNAME'; + /// The 'EMAIL' parameter. + static const challengeParamEmail = 'EMAIL'; + /// The `SRP_A` parameter. static const challengeParamSrpA = 'SRP_A'; diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 725f66b9d1..a62e593d4d 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -330,8 +330,8 @@ final class SignInStateMachine createEmailMfaRequest(event), ChallengeNameType.selectMfaType when hasUserResponse => createSelectMfaRequest(event), - ChallengeNameType.mfaSetup => - handleMfaSetup(event: event, hasUserResponse: hasUserResponse), + ChallengeNameType.mfaSetup when hasUserResponse => + handleMfaSetup(event: event), ChallengeNameType.newPasswordRequired when hasUserResponse => createNewPasswordRequest(event), _ => null, @@ -655,7 +655,6 @@ final class SignInStateMachine @protected Future handleMfaSetup({ SignInEvent? event, - required bool hasUserResponse, }) async { final allowedMfaTypes = _allowedMfaTypes; // Exclude MfaType.sms from consideration @@ -667,38 +666,44 @@ final class SignInStateMachine ); } - if (mfaTypesForSetup.length == 1) { - final mfaType = mfaTypesForSetup.first; - if (mfaType == MfaType.totp) { - _enableMfaType = MfaType.totp; - _totpSetupResult ??= await associateSoftwareToken(); - if (hasUserResponse) { - return createMfaSetupRequest(event as SignInRespondToChallenge); - } else { - // Need to prompt user for the TOTP code - return null; - } - } else if (mfaType == MfaType.email) { - _enableMfaType = MfaType.email; - if (hasUserResponse) { - return createEmailMfaSetupRequest(event as SignInRespondToChallenge); - } else { - // Need to prompt user for the email verification code - return null; - } - } else { - throw InvalidUserPoolConfigurationException( - 'Unsupported MFA type: ${mfaType.name}', - recoverySuggestion: 'Check your user pool MFA configuration.', - ); - } - } else if (hasUserResponse) { - // Handle user's selection - return createMfaSetupRequest(event as SignInRespondToChallenge); - } else { - // Need to prompt user to select an MFA type + if (event == null) { + throw StateError('Event cannot be null when there is user response.'); + } + if (event is! SignInRespondToChallenge) { + throw StateError('Expected SignInRespondToChallenge event.'); + } + + if (_enableMfaType == null && _totpSetupResult == null) { + // User has just selected the MFA type + final selection = event.answer.toLowerCase(); + _enableMfaType = switch (selection) { + 'totp' => MfaType.totp, + 'email' => MfaType.email, + _ => throw const InvalidParameterException('Invalid MFA type selected'), + }; + + final challengeResponses = { + CognitoConstants.challengeParamMfasCanSetup: + _enableMfaType == MfaType.totp + ? '["SOFTWARE_TOKEN_MFA"]' + : '["EMAIL_OTP"]', + }; + _challengeParameters = BuiltMap(challengeResponses); + await _processChallenge(); return null; } + + // totp mfa method was already selected + if (mfaTypesForSetup.length == 1 && + mfaTypesForSetup.contains(MfaType.totp) && + _totpSetupResult != null) { + await createSoftwareTokenMfaRequest(event); + } + + // User has provided the verification code + return _enableMfaType == MfaType.totp + ? createMfaSetupRequest(event) + : createEmailMfaSetupRequest(event); } /// Completes set up of a TOTP MFA. @@ -732,10 +737,10 @@ final class SignInStateMachine _enableMfaType = MfaType.email; return RespondToAuthChallengeRequest.build((b) { b - ..challengeName = ChallengeNameType.emailOtp + ..challengeName = ChallengeNameType.mfaSetup ..challengeResponses.addAll({ CognitoConstants.challengeParamUsername: cognitoUsername, - CognitoConstants.challengeParamEmailMfaCode: event.answer, + CognitoConstants.challengeParamEmail: event.answer, }) ..clientId = _authOutputs.userPoolClientId ..clientMetadata.addAll(event.clientMetadata); @@ -1048,14 +1053,20 @@ final class SignInStateMachine if (_allowedMfaTypes case final allowedMfaTypes? when _challengeParameters .containsKey(CognitoConstants.challengeParamMfasCanSetup)) { - if (!allowedMfaTypes.contains(MfaType.totp)) { + if (!allowedMfaTypes.contains(MfaType.totp) && + allowedMfaTypes.contains(MfaType.email)) { throw const InvalidUserPoolConfigurationException( - 'Cannot enable SMS MFA and TOTP MFA is not allowed', + 'Cannot enable SMS MFA and TOTP or EMAIL MFA is not allowed', recoverySuggestion: - 'Contact an administrator to enable SMS MFA or allow TOTP MFA', + 'Contact an administrator to enable SMS MFA or allow TOTP or EMAIL MFA', ); } - _totpSetupResult ??= await associateSoftwareToken(); + final allowedMfaSetupTypes = [...?_allowedMfaTypes]..remove(MfaType.sms); + if (allowedMfaSetupTypes.length == 1 && + allowedMfaSetupTypes.first == MfaType.totp && + _totpSetupResult == null) { + _totpSetupResult = await associateSoftwareToken(accessToken: _session); + } } // Query the state machine for a response given potential user input in From a3c57e90b26e4d8ba041f516127a488d791736f3 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 15 Oct 2024 00:24:20 -0700 Subject: [PATCH 118/159] chore: fix missing ! --- .../lib/src/state/machines/sign_in_state_machine.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index a62e593d4d..2fdb6c66af 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -1054,7 +1054,7 @@ final class SignInStateMachine when _challengeParameters .containsKey(CognitoConstants.challengeParamMfasCanSetup)) { if (!allowedMfaTypes.contains(MfaType.totp) && - allowedMfaTypes.contains(MfaType.email)) { + !allowedMfaTypes.contains(MfaType.email)) { throw const InvalidUserPoolConfigurationException( 'Cannot enable SMS MFA and TOTP or EMAIL MFA is not allowed', recoverySuggestion: From 7129360f8eda5fddf007c9381aaa273927463eac Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 15 Oct 2024 00:47:31 -0700 Subject: [PATCH 119/159] chore: run dart format --- .../amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index d137d37225..a48c8d4a01 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -808,8 +808,12 @@ extension MfaSettings on CognitoIdentityProviderClient { _getNewPreferredMethod(sms: sms, totp: totp, email: email) ?? currentPreference; - if (_isCurrentPreferenceDisabled(currentPreference, - sms: sms, totp: totp, email: email,)) { + if (_isCurrentPreferenceDisabled( + currentPreference, + sms: sms, + totp: totp, + email: email, + )) { preferred = null; } From e984747130fa5c7c958ff2c800f666c637efe25b Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:15:32 -0700 Subject: [PATCH 120/159] chore: e2e test init commit --- .../mfa_email_optional_test.dart | 87 +++ .../mfa_email_required_test.dart | 83 +++ .../mfa_sms_email_optional_test.dart | 511 +++++++++++++++++ .../mfa_sms_email_required_test.dart | 516 ++++++++++++++++++ .../lib/src/environments.dart | 38 ++ 5 files changed, 1235 insertions(+) create mode 100644 packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart create mode 100644 packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart create mode 100644 packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart create mode 100644 packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart new file mode 100644 index 0000000000..d754842e4c --- /dev/null +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart @@ -0,0 +1,87 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:checks/checks.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; + +void main() { + testRunner.setupTests(); + + group('MFA (Email)', () { + testRunner.withEnvironment(mfaRequiredEmail, (env) { + asyncTest('can sign in with Email MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + + safePrint('USERNAME: $username'); + safePrint('ENV USERNAME: ${env.getDefaultAttributes(username)}'); + + final user = await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: true, + attributes: { + AuthUserAttributeKey.email: username, + }, + // enableMfa: true, + ); + + safePrint('USER: $user'); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is optional', + ).equals(AuthSignInStep.done); + + final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + + await plugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + Future signInWithEmail() async { + await signOutUser(assertComplete: true); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + final mfaSetupRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(mfaSetupRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + await signInWithEmail(); + await signInWithEmail(); + }); + }); + }); +} diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart new file mode 100644 index 0000000000..4a18ed0b98 --- /dev/null +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart @@ -0,0 +1,83 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:checks/checks.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; + +void main() { + testRunner.setupTests(); + + group('MFA (Email)', () { + testRunner.withEnvironment(mfaRequiredEmail, (env) { + asyncTest('can sign in with Email MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + + safePrint('USERNAME: $username'); + safePrint('ENV USERNAME: ${env.getDefaultAttributes(username)}'); + + final user = await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: true, + attributes: { + AuthUserAttributeKey.email: username, + }, + // enableMfa: true, + ); + + safePrint('USER: $user'); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.continueSignInWithMfaSetupSelection); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + Future signInWithEmail() async { + await signOutUser(assertComplete: true); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + final mfaSetupRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(mfaSetupRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + await signInWithEmail(); + await signInWithEmail(); + }); + }); + }); +} diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart new file mode 100644 index 0000000000..739f88bc2f --- /dev/null +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart @@ -0,0 +1,511 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:checks/checks.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; + +void main() { + testRunner.setupTests(); + + group('MFA (SMS + EMAIL)', () { + testRunner.withEnvironment(mfaOptionalEmailSms, (env) { + asyncTest('can set up EMAIL MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + + // Create user with no phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + autoFillAttributes: false, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + because: 'MFA is optional', + signInRes.nextStep.signInStep, + ).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()) + .equals(const UserMfaPreference()); + + final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + await plugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + Future signInWithEmail() async { + await signOutUser(assertComplete: true); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'Once Email MFA is preferred, it is performed ' + 'on every sign-in attempt.', + ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + await signInWithEmail(); + await signInWithEmail(); + + await check( + because: 'EMAIL can be disabled when optional', + cognitoPlugin.updateMfaPreference(email: MfaPreference.disabled), + ).completes(); + + check( + because: 'Disabling EMAIL should mark it as not preferred', + await cognitoPlugin.fetchMfaPreference(), + ).equals( + const UserMfaPreference(enabled: {}, preferred: null), + ); + }); + + asyncTest('can select Email MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + final phoneNumber = generatePhoneNumber(); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + + // Create a user with an unverified phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.phoneNumber: phoneNumber, + }, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is optional', + ).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()) + .equals(const UserMfaPreference()); + + final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + await plugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.enabled, + email: MfaPreference.enabled, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.continueSignInWithMfaSelection); + check(signInRes.nextStep.allowedMfaTypes) + .isNotNull() + .deepEquals({MfaType.sms, MfaType.email}); + + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'EMAIL', + ); + check(selectRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(selectRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + // Verify we can set EMAIL as preferred and forego selection. + + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.email, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify we can switch to SMS as preferred. + + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.sms, + ), + ); + + { + await signOutUser(assertComplete: true); + + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.sms) + ..has((d) => d.destination, 'destination') + .isNotNull() + .startsWith('+'); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify marking enabled does not change preference. + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.enabled, + email: MfaPreference.enabled, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'SMS should still be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.sms, + ), + ); + + // Verify we can mark neither as preferred + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.notPreferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'SMS should be marked not preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + // Verify that we can disable both + await check( + because: 'MFA can be disabled when optional', + cognitoPlugin.updateMfaPreference( + sms: MfaPreference.disabled, + email: MfaPreference.disabled, + ), + ).completes(); + + check( + because: 'Disabling MFA should mark it as not preferred', + await cognitoPlugin.fetchMfaPreference(), + ).equals( + const UserMfaPreference(enabled: {}, preferred: null), + ); + }); + + asyncTest('can select SMS MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + final phoneNumber = generatePhoneNumber(); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + + // Create a user with an unverified phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.phoneNumber: phoneNumber, + }, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is optional', + ).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()) + .equals(const UserMfaPreference()); + + final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + await plugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.enabled, + email: MfaPreference.enabled, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + await signOutUser(assertComplete: true); + + final resignInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(resignInRes.nextStep.signInStep) + .equals(AuthSignInStep.continueSignInWithMfaSelection); + check(resignInRes.nextStep.allowedMfaTypes) + .isNotNull() + .deepEquals({MfaType.sms, MfaType.email}); + + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'SMS', + ); + check(selectRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + check(selectRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.sms) + ..has((d) => d.destination, 'destination') + .isNotNull() + .startsWith('+'); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + // Verify we can set SMS as preferred and forego selection. + + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.sms, + ), + ); + + { + await signOutUser(assertComplete: true); + + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.sms) + ..has((d) => d.destination, 'destination') + .isNotNull() + .startsWith('+'); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify we can switch to EMAIL as preferred. + + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.email, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify marking enabled does not change preference. + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.enabled, + email: MfaPreference.enabled, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should still be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.email, + ), + ); + + // Verify we can mark neither as preferred + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.notPreferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should be marked not preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + // Verify that we can disable both + await check( + because: 'MFA can be disabled when optional', + cognitoPlugin.updateMfaPreference( + sms: MfaPreference.disabled, + email: MfaPreference.disabled, + ), + ).completes(); + + check( + because: 'Disabling MFA should mark it as not preferred', + await cognitoPlugin.fetchMfaPreference(), + ).equals( + const UserMfaPreference(enabled: {}, preferred: null), + ); + }); + }); + }); +} diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart new file mode 100644 index 0000000000..f9fa269307 --- /dev/null +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart @@ -0,0 +1,516 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:checks/checks.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; + +void main() { + testRunner.setupTests(); + + group('MFA (EMAIL + SMS)', () { + testRunner.withEnvironment(mfaRequiredEmailSms, (env) { + asyncTest('can set up EMAIL MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + + // Create a user with no phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + autoFillAttributes: false, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is required, and EMAIL is chosen when ' + 'no phone number is registered', + ).equals(AuthSignInStep.continueSignInWithMfaSetupSelection); + + final setupRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(setupRes.nextStep.signInStep).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + await signOutUser(assertComplete: true); + + final resignInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(resignInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(resignInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + }); + + asyncTest('can select EMAIL MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + final phoneNumber = generatePhoneNumber(); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + + // Create a user with an unverified phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.phoneNumber: phoneNumber, + }, + ); + + { + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is required so Cognito automatically enables SMS MFA', + ).equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'MFA is required so Cognito automatically enables SMS MFA', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms}, + preferred: MfaType.sms, + ), + ); + + final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + await plugin.updateMfaPreference( + email: MfaPreference.enabled, + ); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + ), + ); + + await signOutUser(assertComplete: true); + + { + final resignInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + resignInRes.nextStep.signInStep, + because: 'Both SMS + EMAIL are activated with no preference', + ).equals(AuthSignInStep.continueSignInWithMfaSelection); + check(resignInRes.nextStep.allowedMfaTypes) + .isNotNull() + .deepEquals({MfaType.sms, MfaType.email}); + + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'EMAIL', + ); + check(selectRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(selectRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + // Verify we can set EMAIL as preferred and forego selection. + + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.email, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'Preference is EMAIL MFA now', + ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify we can switch to SMS as preferred. + + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.sms, + ), + ); + + { + await signOutUser(assertComplete: true); + + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'Preference is SMS MFA now', + ).equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.sms) + ..has((d) => d.destination, 'destination') + .isNotNull() + .startsWith('+'); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify marking enabled does not change preference. + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.enabled, + email: MfaPreference.enabled, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'SMS should still be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.sms, + ), + ); + + // Verify we can mark neither as preferred + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.notPreferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'SMS should be marked not preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + // Verify that we can disable MFA + { + await check( + because: 'Interestingly, Cognito does not throw and allows ' + 'MFA to be disabled even when required.', + cognitoPlugin.updateMfaPreference( + sms: MfaPreference.disabled, + email: MfaPreference.disabled, + ), + ).completes(); + + check( + because: 'Disabling MFA should mark it as not preferred', + await cognitoPlugin.fetchMfaPreference(), + ).equals( + const UserMfaPreference( + enabled: {}, + preferred: null, + ), + ); + } + }); + + asyncTest('can select SMS MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + final phoneNumber = generatePhoneNumber(); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + + // Create a user with an unverified phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.phoneNumber: phoneNumber, + }, + ); + + { + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is required so Cognito automatically enables SMS MFA', + ).equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'MFA is required so Cognito automatically enables SMS MFA', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms}, + preferred: MfaType.sms, + ), + ); + + final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + await plugin.updateMfaPreference( + email: MfaPreference.enabled, + ); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + { + await signOutUser(assertComplete: true); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'Both SMS + EMAIL are activated', + ).equals(AuthSignInStep.continueSignInWithMfaSelection); + check(signInRes.nextStep.allowedMfaTypes) + .isNotNull() + .unorderedEquals([MfaType.sms, MfaType.email]); + + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'SMS', + ); + check(selectRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + check(selectRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.sms) + ..has((d) => d.destination, 'destination') + .isNotNull() + .startsWith('+'); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + // Verify we can set SMS as preferred and forego selection. + + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.sms, + ), + ); + + { + await signOutUser(assertComplete: true); + + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'Preference is SMS MFA now', + ).equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.sms) + ..has((d) => d.destination, 'destination') + .isNotNull() + .startsWith('+'); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify we can switch to EMAIL as preferred. + + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.email, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'Preference is EMAIL MFA now', + ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify marking enabled does not change preference. + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.enabled, + email: MfaPreference.enabled, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should still be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.email, + ), + ); + + // Verify we can mark neither as preferred + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.notPreferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should be marked not preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.sms, MfaType.email}, + preferred: null, + ), + ); + + // Verify that we can disable MFA + { + await check( + because: 'Interestingly, Cognito does not throw and allows ' + 'MFA to be disabled even when required.', + cognitoPlugin.updateMfaPreference( + sms: MfaPreference.disabled, + email: MfaPreference.disabled, + ), + ).completes(); + + check( + because: 'Disabling MFA should mark it as not preferred', + await cognitoPlugin.fetchMfaPreference(), + ).equals( + const UserMfaPreference( + enabled: {}, + preferred: null, + ), + ); + } + }); + }); + }); +} diff --git a/packages/test/amplify_auth_integration_test/lib/src/environments.dart b/packages/test/amplify_auth_integration_test/lib/src/environments.dart index f6b9ebee6f..d35c84f377 100644 --- a/packages/test/amplify_auth_integration_test/lib/src/environments.dart +++ b/packages/test/amplify_auth_integration_test/lib/src/environments.dart @@ -17,6 +17,12 @@ const List userPoolEnvironments = [ confirmationDeliveryMedium: DeliveryMedium.sms, resetPasswordDeliveryMedium: DeliveryMedium.sms, ), + EnvironmentInfo.withGen2Defaults( + name: 'email-sign-in', + loginMethod: LoginMethod.email, + confirmationDeliveryMedium: DeliveryMedium.email, + resetPasswordDeliveryMedium: DeliveryMedium.email, + ), ]; /// An environment with optional MFA via SMS only. @@ -55,6 +61,34 @@ const mfaRequiredSmsTotp = EnvironmentInfo.withGen1Defaults( mfaInfo: MfaInfo(smsEnabled: true, totpEnabled: true, required: true), ); +/// An environment with required MFA via Email only. +const mfaRequiredEmail = EnvironmentInfo.withGen2Defaults( + name: 'mfa-required-email', + mfaInfo: MfaInfo(emailEnabled: true, required: true), + loginMethod: LoginMethod.email, +); + +/// An environment with optional MFA via Email only. +const mfaOptionalEmail = EnvironmentInfo.withGen2Defaults( + name: 'mfa-optional-email', + mfaInfo: MfaInfo(emailEnabled: true, required: false), + loginMethod: LoginMethod.email, +); + +/// An environment with required MFA via Email & SMS. +const mfaRequiredEmailSms = EnvironmentInfo.withGen2Defaults( + name: 'mfa-required-email-sms', + mfaInfo: MfaInfo(emailEnabled: true, smsEnabled: true, required: true), + loginMethod: LoginMethod.email, +); + +/// An environment with optional MFA via Email & SMS. +const mfaOptionalEmailSms = EnvironmentInfo.withGen2Defaults( + name: 'mfa-optional-email-sms', + mfaInfo: MfaInfo(emailEnabled: true, smsEnabled: true, required: false), + loginMethod: LoginMethod.email, +); + /// Environments that support MFA const List mfaEnvironments = [ mfaOptionalSms, @@ -63,6 +97,10 @@ const List mfaEnvironments = [ mfaRequiredTotp, mfaOptionalSmsTotp, mfaRequiredSmsTotp, + mfaRequiredEmail, + mfaOptionalEmail, + mfaRequiredEmailSms, + mfaOptionalEmailSms, ]; /// Environments with a user pool and opt-in device tracking. From 58b64d4ede4a513ec38958beb3a1625df83619a3 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 17 Oct 2024 23:31:51 -0700 Subject: [PATCH 121/159] chore: add temporary backends for e2e testing --- .../auth/mfa-optional-email-sms/.gitignore | 5 ++++ .../amplify/auth/resource.ts | 18 +++++++++++++ .../mfa-optional-email-sms/amplify/backend.ts | 25 +++++++++++++++++++ .../amplify/package.json | 3 +++ .../amplify/tsconfig.json | 17 +++++++++++++ .../auth/mfa-optional-email-sms/package.json | 5 ++++ .../auth/mfa-optional-email/.gitignore | 5 ++++ .../amplify/auth/resource.ts | 17 +++++++++++++ .../mfa-optional-email/amplify/backend.ts | 25 +++++++++++++++++++ .../mfa-optional-email/amplify/package.json | 3 +++ .../mfa-optional-email/amplify/tsconfig.json | 17 +++++++++++++ .../auth/mfa-optional-email/package.json | 5 ++++ .../auth/mfa-required-email-sms/.gitignore | 5 ++++ .../amplify/auth/resource.ts | 17 +++++++++++++ .../mfa-required-email-sms/amplify/backend.ts | 25 +++++++++++++++++++ .../amplify/package.json | 3 +++ .../amplify/tsconfig.json | 17 +++++++++++++ .../auth/mfa-required-email-sms/package.json | 5 ++++ .../auth/mfa-required-email/.gitignore | 5 ++++ .../amplify/auth/resource.ts | 16 ++++++++++++ .../mfa-required-email/amplify/backend.ts | 25 +++++++++++++++++++ .../mfa-required-email/amplify/package.json | 3 +++ .../mfa-required-email/amplify/tsconfig.json | 17 +++++++++++++ .../auth/mfa-required-email/package.json | 5 ++++ infra-gen2/tool/deploy_gen2.dart | 20 +++++++++++++++ 25 files changed, 308 insertions(+) create mode 100644 infra-gen2/backends/auth/mfa-optional-email-sms/.gitignore create mode 100644 infra-gen2/backends/auth/mfa-optional-email-sms/amplify/auth/resource.ts create mode 100644 infra-gen2/backends/auth/mfa-optional-email-sms/amplify/backend.ts create mode 100644 infra-gen2/backends/auth/mfa-optional-email-sms/amplify/package.json create mode 100644 infra-gen2/backends/auth/mfa-optional-email-sms/amplify/tsconfig.json create mode 100644 infra-gen2/backends/auth/mfa-optional-email-sms/package.json create mode 100644 infra-gen2/backends/auth/mfa-optional-email/.gitignore create mode 100644 infra-gen2/backends/auth/mfa-optional-email/amplify/auth/resource.ts create mode 100644 infra-gen2/backends/auth/mfa-optional-email/amplify/backend.ts create mode 100644 infra-gen2/backends/auth/mfa-optional-email/amplify/package.json create mode 100644 infra-gen2/backends/auth/mfa-optional-email/amplify/tsconfig.json create mode 100644 infra-gen2/backends/auth/mfa-optional-email/package.json create mode 100644 infra-gen2/backends/auth/mfa-required-email-sms/.gitignore create mode 100644 infra-gen2/backends/auth/mfa-required-email-sms/amplify/auth/resource.ts create mode 100644 infra-gen2/backends/auth/mfa-required-email-sms/amplify/backend.ts create mode 100644 infra-gen2/backends/auth/mfa-required-email-sms/amplify/package.json create mode 100644 infra-gen2/backends/auth/mfa-required-email-sms/amplify/tsconfig.json create mode 100644 infra-gen2/backends/auth/mfa-required-email-sms/package.json create mode 100644 infra-gen2/backends/auth/mfa-required-email/.gitignore create mode 100644 infra-gen2/backends/auth/mfa-required-email/amplify/auth/resource.ts create mode 100644 infra-gen2/backends/auth/mfa-required-email/amplify/backend.ts create mode 100644 infra-gen2/backends/auth/mfa-required-email/amplify/package.json create mode 100644 infra-gen2/backends/auth/mfa-required-email/amplify/tsconfig.json create mode 100644 infra-gen2/backends/auth/mfa-required-email/package.json diff --git a/infra-gen2/backends/auth/mfa-optional-email-sms/.gitignore b/infra-gen2/backends/auth/mfa-optional-email-sms/.gitignore new file mode 100644 index 0000000000..03d4668c65 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-sms/.gitignore @@ -0,0 +1,5 @@ +# amplify +node_modules +.amplify +amplify_outputs* +amplifyconfiguration* diff --git a/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/auth/resource.ts b/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/auth/resource.ts new file mode 100644 index 0000000000..43ddc18eec --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/auth/resource.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineAuth } from "@aws-amplify/backend"; + +export const auth = defineAuth({ + name: "mfa-optional-email-sms", + loginWith: { + email: true, + }, + + // TODO(khatruong2009): Uncomment the following line when the feature is ready. + // multifactor: { + // mode: "OPTIONAL", + // email: true, + // sms: true, + // }, +}); diff --git a/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/backend.ts b/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/backend.ts new file mode 100644 index 0000000000..d6b854225f --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/backend.ts @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineBackend } from "@aws-amplify/backend"; +import { addAuthUserExtensions } from "infra-common"; +import { auth } from "./auth/resource"; + +const backend = defineBackend({ + auth, +}); + +const resources = backend.auth.resources; +const { userPool, cfnResources } = resources; +const { stack } = userPool; +const { cfnUserPool } = cfnResources; + +// Adds infra for creating/deleting users via App Sync and fetching confirmation +// and MFA codes from App Sync. +const customOutputs = addAuthUserExtensions({ + name: "mfa-optional-email-sms", + stack, + userPool, + cfnUserPool, +}); +backend.addOutput(customOutputs); diff --git a/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/package.json b/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/package.json new file mode 100644 index 0000000000..aead43de36 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/tsconfig.json b/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/tsconfig.json new file mode 100644 index 0000000000..4eb4ab26ca --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-sms/amplify/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "paths": { + "$amplify/*": [ + "../.amplify/generated/*" + ] + } + } +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-optional-email-sms/package.json b/infra-gen2/backends/auth/mfa-optional-email-sms/package.json new file mode 100644 index 0000000000..f8ffc5b939 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-sms/package.json @@ -0,0 +1,5 @@ +{ + "name": "mfa-optional-email-sms", + "version": "1.0.0", + "main": "index.js" +} diff --git a/infra-gen2/backends/auth/mfa-optional-email/.gitignore b/infra-gen2/backends/auth/mfa-optional-email/.gitignore new file mode 100644 index 0000000000..03d4668c65 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email/.gitignore @@ -0,0 +1,5 @@ +# amplify +node_modules +.amplify +amplify_outputs* +amplifyconfiguration* diff --git a/infra-gen2/backends/auth/mfa-optional-email/amplify/auth/resource.ts b/infra-gen2/backends/auth/mfa-optional-email/amplify/auth/resource.ts new file mode 100644 index 0000000000..1e33905c1d --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email/amplify/auth/resource.ts @@ -0,0 +1,17 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineAuth } from "@aws-amplify/backend"; + +export const auth = defineAuth({ + name: "mfa-optional-email", + loginWith: { + email: true, + }, + + // TODO(khatruong2009): Uncomment the following line when the feature is ready. + // multifactor: { + // mode: "OPTIONAL", + // email: true, + // }, +}); diff --git a/infra-gen2/backends/auth/mfa-optional-email/amplify/backend.ts b/infra-gen2/backends/auth/mfa-optional-email/amplify/backend.ts new file mode 100644 index 0000000000..ceb5e2a90a --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email/amplify/backend.ts @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineBackend } from "@aws-amplify/backend"; +import { addAuthUserExtensions } from "infra-common"; +import { auth } from "./auth/resource"; + +const backend = defineBackend({ + auth, +}); + +const resources = backend.auth.resources; +const { userPool, cfnResources } = resources; +const { stack } = userPool; +const { cfnUserPool } = cfnResources; + +// Adds infra for creating/deleting users via App Sync and fetching confirmation +// and MFA codes from App Sync. +const customOutputs = addAuthUserExtensions({ + name: "mfa-optional-email", + stack, + userPool, + cfnUserPool, +}); +backend.addOutput(customOutputs); diff --git a/infra-gen2/backends/auth/mfa-optional-email/amplify/package.json b/infra-gen2/backends/auth/mfa-optional-email/amplify/package.json new file mode 100644 index 0000000000..aead43de36 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email/amplify/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-optional-email/amplify/tsconfig.json b/infra-gen2/backends/auth/mfa-optional-email/amplify/tsconfig.json new file mode 100644 index 0000000000..4eb4ab26ca --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email/amplify/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "paths": { + "$amplify/*": [ + "../.amplify/generated/*" + ] + } + } +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-optional-email/package.json b/infra-gen2/backends/auth/mfa-optional-email/package.json new file mode 100644 index 0000000000..a716d71dd4 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email/package.json @@ -0,0 +1,5 @@ +{ + "name": "mfa-optional-email", + "version": "1.0.0", + "main": "index.js" +} diff --git a/infra-gen2/backends/auth/mfa-required-email-sms/.gitignore b/infra-gen2/backends/auth/mfa-required-email-sms/.gitignore new file mode 100644 index 0000000000..03d4668c65 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-sms/.gitignore @@ -0,0 +1,5 @@ +# amplify +node_modules +.amplify +amplify_outputs* +amplifyconfiguration* diff --git a/infra-gen2/backends/auth/mfa-required-email-sms/amplify/auth/resource.ts b/infra-gen2/backends/auth/mfa-required-email-sms/amplify/auth/resource.ts new file mode 100644 index 0000000000..e90924c42e --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-sms/amplify/auth/resource.ts @@ -0,0 +1,17 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineAuth } from "@aws-amplify/backend"; + +export const auth = defineAuth({ + name: "mfa-required-email-sms", + loginWith: { + email: true, + }, + // TODO(khatruong2009): Uncomment the following line when the feature is ready. + // multifactor: { + // mode: "REQUIRED", + // email: true, + // sms: true, + // }, +}); diff --git a/infra-gen2/backends/auth/mfa-required-email-sms/amplify/backend.ts b/infra-gen2/backends/auth/mfa-required-email-sms/amplify/backend.ts new file mode 100644 index 0000000000..397b7b4a6e --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-sms/amplify/backend.ts @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineBackend } from "@aws-amplify/backend"; +import { addAuthUserExtensions } from "infra-common"; +import { auth } from "./auth/resource"; + +const backend = defineBackend({ + auth, +}); + +const resources = backend.auth.resources; +const { userPool, cfnResources } = resources; +const { stack } = userPool; +const { cfnUserPool } = cfnResources; + +// Adds infra for creating/deleting users via App Sync and fetching confirmation +// and MFA codes from App Sync. +const customOutputs = addAuthUserExtensions({ + name: "mfa-required-email-sms", + stack, + userPool, + cfnUserPool, +}); +backend.addOutput(customOutputs); diff --git a/infra-gen2/backends/auth/mfa-required-email-sms/amplify/package.json b/infra-gen2/backends/auth/mfa-required-email-sms/amplify/package.json new file mode 100644 index 0000000000..aead43de36 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-sms/amplify/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-required-email-sms/amplify/tsconfig.json b/infra-gen2/backends/auth/mfa-required-email-sms/amplify/tsconfig.json new file mode 100644 index 0000000000..4eb4ab26ca --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-sms/amplify/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "paths": { + "$amplify/*": [ + "../.amplify/generated/*" + ] + } + } +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-required-email-sms/package.json b/infra-gen2/backends/auth/mfa-required-email-sms/package.json new file mode 100644 index 0000000000..b2e8c9c4c7 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-sms/package.json @@ -0,0 +1,5 @@ +{ + "name": "mfa-required-email-sms", + "version": "1.0.0", + "main": "index.js" +} diff --git a/infra-gen2/backends/auth/mfa-required-email/.gitignore b/infra-gen2/backends/auth/mfa-required-email/.gitignore new file mode 100644 index 0000000000..03d4668c65 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email/.gitignore @@ -0,0 +1,5 @@ +# amplify +node_modules +.amplify +amplify_outputs* +amplifyconfiguration* diff --git a/infra-gen2/backends/auth/mfa-required-email/amplify/auth/resource.ts b/infra-gen2/backends/auth/mfa-required-email/amplify/auth/resource.ts new file mode 100644 index 0000000000..ba859af386 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email/amplify/auth/resource.ts @@ -0,0 +1,16 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineAuth } from "@aws-amplify/backend"; + +export const auth = defineAuth({ + name: "mfa-required-email", + loginWith: { + email: true, + }, + // TODO(khatruong2009): Uncomment the following line when the feature is ready. + // multifactor: { + // mode: "REQUIRED", + // email: true, + // }, +}); diff --git a/infra-gen2/backends/auth/mfa-required-email/amplify/backend.ts b/infra-gen2/backends/auth/mfa-required-email/amplify/backend.ts new file mode 100644 index 0000000000..e9299cf711 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email/amplify/backend.ts @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineBackend } from "@aws-amplify/backend"; +import { addAuthUserExtensions } from "infra-common"; +import { auth } from "./auth/resource"; + +const backend = defineBackend({ + auth, +}); + +const resources = backend.auth.resources; +const { userPool, cfnResources } = resources; +const { stack } = userPool; +const { cfnUserPool } = cfnResources; + +// Adds infra for creating/deleting users via App Sync and fetching confirmation +// and MFA codes from App Sync. +const customOutputs = addAuthUserExtensions({ + name: "mfa-required-email", + stack, + userPool, + cfnUserPool, +}); +backend.addOutput(customOutputs); diff --git a/infra-gen2/backends/auth/mfa-required-email/amplify/package.json b/infra-gen2/backends/auth/mfa-required-email/amplify/package.json new file mode 100644 index 0000000000..aead43de36 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email/amplify/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-required-email/amplify/tsconfig.json b/infra-gen2/backends/auth/mfa-required-email/amplify/tsconfig.json new file mode 100644 index 0000000000..4eb4ab26ca --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email/amplify/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "paths": { + "$amplify/*": [ + "../.amplify/generated/*" + ] + } + } +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-required-email/package.json b/infra-gen2/backends/auth/mfa-required-email/package.json new file mode 100644 index 0000000000..3d30b5522b --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email/package.json @@ -0,0 +1,5 @@ +{ + "name": "mfa-required-email", + "version": "1.0.0", + "main": "index.js" +} diff --git a/infra-gen2/tool/deploy_gen2.dart b/infra-gen2/tool/deploy_gen2.dart index e5f8cf1a1e..42ab0bb25d 100644 --- a/infra-gen2/tool/deploy_gen2.dart +++ b/infra-gen2/tool/deploy_gen2.dart @@ -58,6 +58,26 @@ const List infraConfig = [ identifier: 'mfa-req-sms', pathToSource: 'infra-gen2/backends/auth/mfa-required-sms', ), + AmplifyBackend( + name: 'mfa-required-email', + identifier: 'mfa-req-email', + pathToSource: 'infra-gen2/backends/auth/mfa-required-email', + ), + AmplifyBackend( + name: 'mfa-required-email-sms', + identifier: 'mfa-req-ema-sms', + pathToSource: 'infra-gen2/backends/auth/mfa-required-email-sms', + ), + AmplifyBackend( + name: 'mfa-optional-email', + identifier: 'mfa-opt-email', + pathToSource: 'infra-gen2/backends/auth/mfa-optional-email', + ), + AmplifyBackend( + name: 'mfa-optional-email-sms', + identifier: 'mfa-opt-ema-sms', + pathToSource: 'infra-gen2/backends/auth/mfa-optional-email-sms', + ), ], ), AmplifyBackendGroup( From 3a997fe8d047f61b1b81e1800f2494c9098bd286 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:11:29 -0700 Subject: [PATCH 122/159] chore: fix auth_cognito tests to match expected behavior --- .../mfa_email_optional_test.dart | 14 +- .../mfa_email_required_test.dart | 8 +- .../mfa_sms_email_optional_test.dart | 106 ++++------- .../mfa_sms_email_required_test.dart | 174 ++++-------------- 4 files changed, 82 insertions(+), 220 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart index d754842e4c..2f6b2ffc7a 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart @@ -14,15 +14,11 @@ void main() { testRunner.setupTests(); group('MFA (Email)', () { - testRunner.withEnvironment(mfaRequiredEmail, (env) { + testRunner.withEnvironment(mfaOptionalEmail, (env) { asyncTest('can sign in with Email MFA', (_) async { final username = env.generateUsername(); final password = generatePassword(); - final otpResult = await getOtpCode( - env.getLoginAttribute(username), - ); - safePrint('USERNAME: $username'); safePrint('ENV USERNAME: ${env.getDefaultAttributes(username)}'); @@ -34,7 +30,6 @@ void main() { attributes: { AuthUserAttributeKey.email: username, }, - // enableMfa: true, ); safePrint('USER: $user'); @@ -49,7 +44,7 @@ void main() { ).equals(AuthSignInStep.done); final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); - + await plugin.updateMfaPreference( email: MfaPreference.preferred, ); @@ -63,6 +58,11 @@ void main() { Future signInWithEmail() async { await signOutUser(assertComplete: true); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + final signInRes = await Amplify.Auth.signIn( username: username, password: password, diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart index 4a18ed0b98..12dd54b362 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart @@ -33,7 +33,6 @@ void main() { attributes: { AuthUserAttributeKey.email: username, }, - // enableMfa: true, ); safePrint('USER: $user'); @@ -43,7 +42,7 @@ void main() { password: password, ); check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.continueSignInWithMfaSetupSelection); + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, @@ -59,6 +58,11 @@ void main() { Future signInWithEmail() async { await signOutUser(assertComplete: true); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + final signInRes = await Amplify.Auth.signIn( username: username, password: password, diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart index 739f88bc2f..5dd7465b66 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart @@ -19,10 +19,6 @@ void main() { final username = env.generateUsername(); final password = generatePassword(); - final otpResult = await getOtpCode( - env.getLoginAttribute(username), - ); - // Create user with no phone number. await adminCreateUser( username, @@ -57,6 +53,11 @@ void main() { Future signInWithEmail() async { await signOutUser(assertComplete: true); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + final signInRes = await Amplify.Auth.signIn( username: username, password: password, @@ -93,7 +94,7 @@ void main() { ); }); - asyncTest('can select Email MFA', (_) async { + asyncTest('can select EMAIL MFA', (_) async { final username = env.generateUsername(); final password = generatePassword(); final phoneNumber = generatePhoneNumber(); @@ -110,6 +111,7 @@ void main() { verifyAttributes: false, attributes: { AuthUserAttributeKey.phoneNumber: phoneNumber, + AuthUserAttributeKey.email: username, }, ); @@ -126,6 +128,7 @@ void main() { .equals(const UserMfaPreference()); final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + await plugin.updateMfaPreference( email: MfaPreference.preferred, ); @@ -139,12 +142,12 @@ void main() { await cognitoPlugin.updateMfaPreference( sms: MfaPreference.enabled, - email: MfaPreference.enabled, ); + check(await cognitoPlugin.fetchMfaPreference()).equals( const UserMfaPreference( enabled: {MfaType.sms, MfaType.email}, - preferred: null, + preferred: MfaType.email, ), ); @@ -156,17 +159,8 @@ void main() { password: password, ); check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.continueSignInWithMfaSelection); - check(signInRes.nextStep.allowedMfaTypes) - .isNotNull() - .deepEquals({MfaType.sms, MfaType.email}); - - final selectRes = await Amplify.Auth.confirmSignIn( - confirmationValue: 'EMAIL', - ); - check(selectRes.nextStep.signInStep) .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); - check(selectRes.nextStep.codeDeliveryDetails) + check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); @@ -180,7 +174,7 @@ void main() { check(await cognitoPlugin.fetchMfaPreference()).equals( const UserMfaPreference( enabled: {MfaType.sms, MfaType.email}, - preferred: null, + preferred: MfaType.email, ), ); @@ -213,8 +207,12 @@ void main() { .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); + final otpResult2 = await getOtpCode( + env.getLoginAttribute(username), + ); + final confirmRes = await Amplify.Auth.confirmSignIn( - confirmationValue: await otpResult.code, + confirmationValue: await otpResult2.code, ); check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); } @@ -269,20 +267,6 @@ void main() { ), ); - // Verify we can mark neither as preferred - await cognitoPlugin.updateMfaPreference( - sms: MfaPreference.notPreferred, - ); - check( - await cognitoPlugin.fetchMfaPreference(), - because: 'SMS should be marked not preferred', - ).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: null, - ), - ); - // Verify that we can disable both await check( because: 'MFA can be disabled when optional', @@ -305,10 +289,6 @@ void main() { final password = generatePassword(); final phoneNumber = generatePhoneNumber(); - final otpResult = await getOtpCode( - env.getLoginAttribute(username), - ); - // Create a user with an unverified phone number. await adminCreateUser( username, @@ -317,6 +297,7 @@ void main() { verifyAttributes: false, attributes: { AuthUserAttributeKey.phoneNumber: phoneNumber, + AuthUserAttributeKey.email: username, }, ); @@ -334,13 +315,14 @@ void main() { final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); await plugin.updateMfaPreference( - email: MfaPreference.preferred, + sms: MfaPreference.preferred, + email: MfaPreference.enabled, ); check(await cognitoPlugin.fetchMfaPreference()).equals( const UserMfaPreference( - enabled: {MfaType.email}, - preferred: MfaType.email, + enabled: {MfaType.email, MfaType.sms}, + preferred: MfaType.sms, ), ); @@ -351,7 +333,7 @@ void main() { check(await cognitoPlugin.fetchMfaPreference()).equals( const UserMfaPreference( enabled: {MfaType.sms, MfaType.email}, - preferred: null, + preferred: MfaType.sms, ), ); @@ -362,33 +344,25 @@ void main() { password: password, ); check(resignInRes.nextStep.signInStep) - .equals(AuthSignInStep.continueSignInWithMfaSelection); - check(resignInRes.nextStep.allowedMfaTypes) - .isNotNull() - .deepEquals({MfaType.sms, MfaType.email}); - - final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); - final selectRes = await Amplify.Auth.confirmSignIn( - confirmationValue: 'SMS', - ); - check(selectRes.nextStep.signInStep) .equals(AuthSignInStep.confirmSignInWithSmsMfaCode); - check(selectRes.nextStep.codeDeliveryDetails).isNotNull() + check(resignInRes.nextStep.codeDeliveryDetails).isNotNull() ..has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.sms) ..has((d) => d.destination, 'destination') .isNotNull() .startsWith('+'); + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await mfaCode.code, ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); check(await cognitoPlugin.fetchMfaPreference()).equals( const UserMfaPreference( enabled: {MfaType.sms, MfaType.email}, - preferred: null, + preferred: MfaType.sms, ), ); @@ -449,11 +423,17 @@ void main() { username: username, password: password, ); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + check(signInRes.nextStep.signInStep) .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); - check(signInRes.nextStep.codeDeliveryDetails).isNotNull() - .has((d) => d.deliveryMedium, 'deliveryMedium') - .equals(DeliveryMedium.email); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, @@ -476,20 +456,6 @@ void main() { ), ); - // Verify we can mark neither as preferred - await cognitoPlugin.updateMfaPreference( - email: MfaPreference.notPreferred, - ); - check( - await cognitoPlugin.fetchMfaPreference(), - because: 'EMAIL should be marked not preferred', - ).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: null, - ), - ); - // Verify that we can disable both await check( because: 'MFA can be disabled when optional', diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart index f9fa269307..4a94dd1cba 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart @@ -28,6 +28,9 @@ void main() { username, password, autoConfirm: true, + attributes: { + AuthUserAttributeKey.email: username, + }, autoFillAttributes: false, ); @@ -39,7 +42,7 @@ void main() { signInRes.nextStep.signInStep, because: 'MFA is required, and EMAIL is chosen when ' 'no phone number is registered', - ).equals(AuthSignInStep.continueSignInWithMfaSetupSelection); + ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); final setupRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, @@ -66,8 +69,12 @@ void main() { .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); + final otpResult2 = await getOtpCode( + env.getLoginAttribute(username), + ); + final confirmRes = await Amplify.Auth.confirmSignIn( - confirmationValue: await otpResult.code, + confirmationValue: await otpResult2.code, ); check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); }); @@ -77,11 +84,7 @@ void main() { final password = generatePassword(); final phoneNumber = generatePhoneNumber(); - final otpResult = await getOtpCode( - env.getLoginAttribute(username), - ); - - // Create a user with an unverified phone number. + // Verify we can set EMAIL as preferred and forego selection. await adminCreateUser( username, password, @@ -89,6 +92,7 @@ void main() { verifyAttributes: false, attributes: { AuthUserAttributeKey.phoneNumber: phoneNumber, + AuthUserAttributeKey.email: username, }, ); @@ -120,13 +124,17 @@ void main() { ); final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + + safePrint('${await plugin.fetchMfaPreference()}'); + await plugin.updateMfaPreference( - email: MfaPreference.enabled, + email: MfaPreference.preferred, ); check(await cognitoPlugin.fetchMfaPreference()).equals( const UserMfaPreference( enabled: {MfaType.sms, MfaType.email}, + preferred: MfaType.email, ), ); @@ -139,40 +147,23 @@ void main() { ); check( resignInRes.nextStep.signInStep, - because: 'Both SMS + EMAIL are activated with no preference', - ).equals(AuthSignInStep.continueSignInWithMfaSelection); - check(resignInRes.nextStep.allowedMfaTypes) - .isNotNull() - .deepEquals({MfaType.sms, MfaType.email}); - - final selectRes = await Amplify.Auth.confirmSignIn( - confirmationValue: 'EMAIL', - ); - check(selectRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); - check(selectRes.nextStep.codeDeliveryDetails) + because: 'Preference is EMAIL MFA now', + ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(resignInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, ); check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); } - check(await cognitoPlugin.fetchMfaPreference()).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: null, - ), - ); - - // Verify we can set EMAIL as preferred and forego selection. - - await cognitoPlugin.updateMfaPreference( - email: MfaPreference.preferred, - ); check(await cognitoPlugin.fetchMfaPreference()).equals( const UserMfaPreference( enabled: {MfaType.sms, MfaType.email}, @@ -180,28 +171,6 @@ void main() { ), ); - { - await signOutUser(assertComplete: true); - - final signInRes = await Amplify.Auth.signIn( - username: username, - password: password, - ); - check( - signInRes.nextStep.signInStep, - because: 'Preference is EMAIL MFA now', - ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); - check(signInRes.nextStep.codeDeliveryDetails) - .isNotNull() - .has((d) => d.deliveryMedium, 'deliveryMedium') - .equals(DeliveryMedium.email); - - final confirmRes = await Amplify.Auth.confirmSignIn( - confirmationValue: await otpResult.code, - ); - check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); - } - // Verify we can switch to SMS as preferred. await cognitoPlugin.updateMfaPreference( @@ -254,20 +223,6 @@ void main() { ), ); - // Verify we can mark neither as preferred - await cognitoPlugin.updateMfaPreference( - sms: MfaPreference.notPreferred, - ); - check( - await cognitoPlugin.fetchMfaPreference(), - because: 'SMS should be marked not preferred', - ).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: null, - ), - ); - // Verify that we can disable MFA { await check( @@ -296,10 +251,6 @@ void main() { final password = generatePassword(); final phoneNumber = generatePhoneNumber(); - final otpResult = await getOtpCode( - env.getLoginAttribute(username), - ); - // Create a user with an unverified phone number. await adminCreateUser( username, @@ -308,6 +259,7 @@ void main() { verifyAttributes: false, attributes: { AuthUserAttributeKey.phoneNumber: phoneNumber, + AuthUserAttributeKey.email: username, }, ); @@ -338,62 +290,11 @@ void main() { ), ); - final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); - await plugin.updateMfaPreference( - email: MfaPreference.enabled, - ); - - check(await cognitoPlugin.fetchMfaPreference()).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: null, - ), - ); - - { - await signOutUser(assertComplete: true); - final signInRes = await Amplify.Auth.signIn( - username: username, - password: password, - ); - check( - signInRes.nextStep.signInStep, - because: 'Both SMS + EMAIL are activated', - ).equals(AuthSignInStep.continueSignInWithMfaSelection); - check(signInRes.nextStep.allowedMfaTypes) - .isNotNull() - .unorderedEquals([MfaType.sms, MfaType.email]); - - final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); - final selectRes = await Amplify.Auth.confirmSignIn( - confirmationValue: 'SMS', - ); - check(selectRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithSmsMfaCode); - check(selectRes.nextStep.codeDeliveryDetails).isNotNull() - ..has((d) => d.deliveryMedium, 'deliveryMedium') - .equals(DeliveryMedium.sms) - ..has((d) => d.destination, 'destination') - .isNotNull() - .startsWith('+'); - - final confirmRes = await Amplify.Auth.confirmSignIn( - confirmationValue: await mfaCode.code, - ); - check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); - } - - check(await cognitoPlugin.fetchMfaPreference()).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: null, - ), - ); - // Verify we can set SMS as preferred and forego selection. await cognitoPlugin.updateMfaPreference( sms: MfaPreference.preferred, + email: MfaPreference.enabled, ); check(await cognitoPlugin.fetchMfaPreference()).equals( const UserMfaPreference( @@ -450,9 +351,14 @@ void main() { signInRes.nextStep.signInStep, because: 'Preference is EMAIL MFA now', ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); - check(signInRes.nextStep.codeDeliveryDetails).isNotNull() - .has((d) => d.deliveryMedium, 'deliveryMedium') - .equals(DeliveryMedium.email); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, @@ -475,20 +381,6 @@ void main() { ), ); - // Verify we can mark neither as preferred - await cognitoPlugin.updateMfaPreference( - email: MfaPreference.notPreferred, - ); - check( - await cognitoPlugin.fetchMfaPreference(), - because: 'EMAIL should be marked not preferred', - ).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: null, - ), - ); - // Verify that we can disable MFA { await check( From 769bada8b45d8cdca3a28d46a39d7886c1ff841b Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Sat, 19 Oct 2024 12:13:01 -0700 Subject: [PATCH 123/159] chore: add authenticator test for sign in with email mfa --- .../sign_in_mfa_email_test.dart | 114 ++++++++++++++++++ .../lib/amplify_auth_integration_test.dart | 1 + .../lib/src/email_utils.dart | 13 ++ 3 files changed, 128 insertions(+) create mode 100644 packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart create mode 100644 packages/test/amplify_auth_integration_test/lib/src/email_utils.dart diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart new file mode 100644 index 0000000000..1e513dbc37 --- /dev/null +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart @@ -0,0 +1,114 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_authenticator_test/amplify_authenticator_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; +import 'utils/test_utils.dart'; + +void main() { + testRunner.setupTests(); + + group('sign-in-email-mfa', () { + testRunner.withEnvironment(mfaRequiredEmail, (env) { + // Scenario: Sign in using a totp code + testWidgets('Setup & Sign in with EMAIL MFA', (tester) async { + final username = env.generateUsername(); + final password = generatePassword(); + + await adminCreateUser( + username, + password, + autoConfirm: true, + attributes: { + AuthUserAttributeKey.email: username, + }, + autoFillAttributes: false, + ); + + await loadAuthenticator(tester: tester); + + expect( + tester.bloc.stream, + emitsInOrder([ + UnauthenticatedState.signIn, + UnauthenticatedState.confirmSignInWithEmailMfaCode, + isA(), + UnauthenticatedState.signIn, + UnauthenticatedState.confirmSignInWithEmailMfaCode, + isA(), + emitsDone, + ]), + ); + + final signInPage = SignInPage(tester: tester); + final confirmSignInPage = ConfirmSignInPage(tester: tester); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the totp setup page + await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + // And I type a valid EMAIL OTP code + await confirmSignInPage.enterVerificationCode(await otpResult.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + /// Sign out and login again with EMAIL OTP code + /// validates [AuthenticatorStep.confirmSignInWithEmailMfaCode] + + // When I sign out using Auth.signOut() + await Amplify.Auth.signOut(); + await tester.pumpAndSettle(); + + // Then I see the sign in page + signInPage.expectUsername(label: 'Email'); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the EMAIL OTP code page + await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + + final otpResult2 = await getOtpCode( + env.getLoginAttribute(username), + ); + + // When I type a valid EMAIL OTP code + await confirmSignInPage.enterVerificationCode(await otpResult2.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + await tester.bloc.close(); + }); + }); + }); +} diff --git a/packages/test/amplify_auth_integration_test/lib/amplify_auth_integration_test.dart b/packages/test/amplify_auth_integration_test/lib/amplify_auth_integration_test.dart index 0e94ac7fd3..2e3d46e086 100644 --- a/packages/test/amplify_auth_integration_test/lib/amplify_auth_integration_test.dart +++ b/packages/test/amplify_auth_integration_test/lib/amplify_auth_integration_test.dart @@ -6,6 +6,7 @@ library amplify_auth_integration_test; export 'src/async_test.dart'; +export 'src/email_utils.dart'; export 'src/environments.dart'; export 'src/test_auth_plugin.dart'; export 'src/test_runner.dart'; diff --git a/packages/test/amplify_auth_integration_test/lib/src/email_utils.dart b/packages/test/amplify_auth_integration_test/lib/src/email_utils.dart new file mode 100644 index 0000000000..20c726351f --- /dev/null +++ b/packages/test/amplify_auth_integration_test/lib/src/email_utils.dart @@ -0,0 +1,13 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Sets up EMAIL MFA for the current user. +Future setUpEmailMfa() async { + final user = await Amplify.Auth.getCurrentUser(); + final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + await plugin.updateMfaPreference(email: MfaPreference.preferred); +} From 47d510f449ff4a6ee55c99dd6411b263e7640350 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Sat, 19 Oct 2024 12:56:04 -0700 Subject: [PATCH 124/159] chore: add and update utilities for integ tests --- .../lib/src/pages/confirm_sign_in_page.dart | 41 +++++++++++++++++++ .../lib/src/email_utils.dart | 1 - 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart index 84c8f8cbfb..8ccfa07ad9 100644 --- a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart +++ b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart @@ -25,8 +25,12 @@ class ConfirmSignInPage extends AuthenticatorPage { Finder get confirmSignInButton => find.byKey(keyConfirmSignInButton); Finder get confirmSignInMfaSelectionButton => find.byKey(keyConfirmSignInMfaSelectionButton); + Finder get confirmSignInMfaSetupSelectionButton => + find.byKey(keyConfirmSignInMfaSetupSelectionButton); Finder get selectMfaRadio => find.byKey(keyMfaMethodRadioConfirmSignInFormField); + Finder get selectMfaSetupRadio => + find.byKey(keyMfaSetupMethodRadioConfirmSignInFormField); Finder get backToSignIn => find.byKey(keyBackToSignInButton); /// Then I see "Confirm Sign In - New Password" @@ -59,6 +63,28 @@ class ConfirmSignInPage extends AuthenticatorPage { ); } + /// Then I see "Select an MFA Method to set up" + Future expectContinueSignInWithMfaSetupSelectionIsPresent() async { + final currentScreen = tester.widget( + find.byType(AuthenticatorScreen), + ); + expect( + currentScreen.step, + equals(AuthenticatorStep.continueSignInWithMfaSetupSelection), + ); + } + + /// Then I see "Enter your one-time passcode for Email" + Future expectConfirmSignInWithEmailMfaCodeIsPresent() async { + final currentScreen = tester.widget( + find.byType(AuthenticatorScreen), + ); + expect( + currentScreen.step, + equals(AuthenticatorStep.confirmSignInWithEmailMfaCode), + ); + } + /// Then I see "Setup an Authentication App" Future expectSignInTotpSetupIsPresent() async { final currentScreen = tester.widget( @@ -132,6 +158,21 @@ class ConfirmSignInPage extends AuthenticatorPage { await tester.pumpAndSettle(); } + // When I select a MFA setup method + Future selectMfaSetupMethod({ + required MfaType mfaMethod, + }) async { + expect(selectMfaSetupRadio, findsOneWidget); + + final mfaMethodWidget = find.descendant( + of: selectMfaSetupRadio, + matching: find.textContaining('(${mfaMethod.name.toUpperCase()})'), + ); + + await tester.tap(mfaMethodWidget); + await tester.pumpAndSettle(); + } + /// When I click the "Confirm Sign In" button Future submitConfirmSignInMfaSelection() async { await tester.ensureVisible(confirmSignInMfaSelectionButton); diff --git a/packages/test/amplify_auth_integration_test/lib/src/email_utils.dart b/packages/test/amplify_auth_integration_test/lib/src/email_utils.dart index 20c726351f..ffb0534cd0 100644 --- a/packages/test/amplify_auth_integration_test/lib/src/email_utils.dart +++ b/packages/test/amplify_auth_integration_test/lib/src/email_utils.dart @@ -7,7 +7,6 @@ import 'package:flutter_test/flutter_test.dart'; /// Sets up EMAIL MFA for the current user. Future setUpEmailMfa() async { - final user = await Amplify.Auth.getCurrentUser(); final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); await plugin.updateMfaPreference(email: MfaPreference.preferred); } From 06e20197eda8e45a356385e9e25502d3124acccf Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Sun, 20 Oct 2024 19:05:08 -0700 Subject: [PATCH 125/159] chore: add authenticator email sms test --- .../sign_in_mfa_sms_email_test.dart | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart new file mode 100644 index 0000000000..b3fc1ef8d9 --- /dev/null +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart @@ -0,0 +1,230 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_authenticator_test/amplify_authenticator_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; +import 'utils/test_utils.dart'; + +void main() { + testRunner.setupTests(); + + group('sign-in-sms-totp-mfa', () { + testRunner.withEnvironment(mfaRequiredEmailSms, (env) { + // Scenario: Sign in using a totp code when both SMS and EMAIL are enabled + // Note: When email and sms are both enabled, + // one of them must be selected as preferred. + // This is different from other mfa methods and + // is expected behavior from cognito + testWidgets('can select EMAIL MFA', (tester) async { + final username = env.generateUsername(); + final password = generatePassword(); + final phoneNumber = generateUSPhoneNumber(); + + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.phoneNumber: phoneNumber.toE164(), + AuthUserAttributeKey.email: username, + }, + ); + + await loadAuthenticator(tester: tester); + + expect( + tester.bloc.stream, + emitsInOrder([ + UnauthenticatedState.signIn, + UnauthenticatedState.confirmSignInMfa, + isA(), + UnauthenticatedState.signIn, + // isA(), + UnauthenticatedState.confirmSignInWithEmailMfaCode, + isA(), + emitsDone, + ]), + ); + + final signInPage = SignInPage(tester: tester); + final confirmSignInPage = ConfirmSignInPage(tester: tester); + + final smsResult = + await getOtpCode(UserAttribute.phone(phoneNumber.toE164())); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the confirm sms mfa page + await confirmSignInPage.expectConfirmSignInMFAIsPresent(); + + // When I type a valid confirmation code + await confirmSignInPage.enterVerificationCode(await smsResult.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + // When I enable EMAIL for MFA instead of the default set up by cognito (SMS) + // await setUpTotp(); + await setUpEmailMfa(); + + // And I sign out using Auth.signOut() + await Amplify.Auth.signOut(); + await tester.pumpAndSettle(); + + // Then I see the sign in page + signInPage.expectEmail(); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the EMAIL MFA code page + await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + + final code_2 = await getOtpCode(env.getLoginAttribute(username)); + + // When I type a valid EMAIL MFA code + await confirmSignInPage.enterVerificationCode(await code_2.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + await tester.bloc.close(); + }); + + // Scenario: Sign in using a SMS code when both SMS and TOTP are enabled + testWidgets('can select SMS MFA', (tester) async { + final username = env.generateUsername(); + final password = generatePassword(); + final phoneNumber = generateUSPhoneNumber(); + + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.phoneNumber: phoneNumber.toE164(), + AuthUserAttributeKey.email: username, + }, + ); + + await loadAuthenticator(tester: tester); + + expect( + tester.bloc.stream, + emitsInOrder([ + UnauthenticatedState.signIn, + UnauthenticatedState.confirmSignInMfa, + isA(), + UnauthenticatedState.signIn, + // isA(), + UnauthenticatedState.confirmSignInMfa, + isA(), + emitsDone, + ]), + ); + + final signInPage = SignInPage(tester: tester); + final confirmSignInPage = ConfirmSignInPage(tester: tester); + + final smsResult_1 = + await getOtpCode(UserAttribute.phone(phoneNumber.toE164())); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the confirm sms mfa page + await confirmSignInPage.expectConfirmSignInMFAIsPresent(); + + // When I type a valid confirmation code + await confirmSignInPage.enterVerificationCode(await smsResult_1.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + // When I enable EMAIL for MFA instead of the default set up by cognito (SMS) + await setUpEmailMfa(); + + final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + await plugin.updateMfaPreference(sms: MfaPreference.preferred); + + // And I sign out using Auth.signOut() + await Amplify.Auth.signOut(); + await tester.pumpAndSettle(); + + // Then I see the sign in page + signInPage.expectEmail(); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the MFA selection page + // await confirmSignInPage.expectConfirmSignInMfaSelectionIsPresent(); + + final smsResult_2 = + await getOtpCode(UserAttribute.phone(phoneNumber.toE164())); + + // When I select "SMS" + // await confirmSignInPage.selectMfaMethod(mfaMethod: MfaType.sms); + + // And I click the "Confirm" button + // await confirmSignInPage.submitConfirmSignInMfaSelection(); + + // Then I will be redirected to the confirm sms mfa page + await confirmSignInPage.expectConfirmSignInMFAIsPresent(); + + // When I type a valid confirmation code + await confirmSignInPage.enterVerificationCode(await smsResult_2.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + await tester.bloc.close(); + }); + }); + }); +} From 0467ababa60de112a817680e9480033dc4c8a196 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Sun, 20 Oct 2024 19:37:15 -0700 Subject: [PATCH 126/159] chore: add backend for email and totp mfa --- .../auth/mfa-optional-email-totp/.gitignore | 5 ++++ .../amplify/auth/resource.ts | 18 +++++++++++++ .../amplify/backend.ts | 25 +++++++++++++++++++ .../amplify/package.json | 3 +++ .../amplify/tsconfig.json | 17 +++++++++++++ .../auth/mfa-optional-email-totp/package.json | 5 ++++ .../auth/mfa-required-email-totp/.gitignore | 5 ++++ .../amplify/auth/resource.ts | 17 +++++++++++++ .../amplify/backend.ts | 25 +++++++++++++++++++ .../amplify/package.json | 3 +++ .../amplify/tsconfig.json | 17 +++++++++++++ .../auth/mfa-required-email-totp/package.json | 5 ++++ 12 files changed, 145 insertions(+) create mode 100644 infra-gen2/backends/auth/mfa-optional-email-totp/.gitignore create mode 100644 infra-gen2/backends/auth/mfa-optional-email-totp/amplify/auth/resource.ts create mode 100644 infra-gen2/backends/auth/mfa-optional-email-totp/amplify/backend.ts create mode 100644 infra-gen2/backends/auth/mfa-optional-email-totp/amplify/package.json create mode 100644 infra-gen2/backends/auth/mfa-optional-email-totp/amplify/tsconfig.json create mode 100644 infra-gen2/backends/auth/mfa-optional-email-totp/package.json create mode 100644 infra-gen2/backends/auth/mfa-required-email-totp/.gitignore create mode 100644 infra-gen2/backends/auth/mfa-required-email-totp/amplify/auth/resource.ts create mode 100644 infra-gen2/backends/auth/mfa-required-email-totp/amplify/backend.ts create mode 100644 infra-gen2/backends/auth/mfa-required-email-totp/amplify/package.json create mode 100644 infra-gen2/backends/auth/mfa-required-email-totp/amplify/tsconfig.json create mode 100644 infra-gen2/backends/auth/mfa-required-email-totp/package.json diff --git a/infra-gen2/backends/auth/mfa-optional-email-totp/.gitignore b/infra-gen2/backends/auth/mfa-optional-email-totp/.gitignore new file mode 100644 index 0000000000..03d4668c65 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-totp/.gitignore @@ -0,0 +1,5 @@ +# amplify +node_modules +.amplify +amplify_outputs* +amplifyconfiguration* diff --git a/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/auth/resource.ts b/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/auth/resource.ts new file mode 100644 index 0000000000..ae1765e5d0 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/auth/resource.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineAuth } from "@aws-amplify/backend"; + +export const auth = defineAuth({ + name: "mfa-optional-email-totp", + loginWith: { + email: true, + }, + + // TODO(khatruong2009): Uncomment the following line when the feature is ready. + // multifactor: { + // mode: "OPTIONAL", + // email: true, + // totp: true, + // }, +}); diff --git a/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/backend.ts b/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/backend.ts new file mode 100644 index 0000000000..a3f1f19985 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/backend.ts @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineBackend } from "@aws-amplify/backend"; +import { addAuthUserExtensions } from "infra-common"; +import { auth } from "./auth/resource"; + +const backend = defineBackend({ + auth, +}); + +const resources = backend.auth.resources; +const { userPool, cfnResources } = resources; +const { stack } = userPool; +const { cfnUserPool } = cfnResources; + +// Adds infra for creating/deleting users via App Sync and fetching confirmation +// and MFA codes from App Sync. +const customOutputs = addAuthUserExtensions({ + name: "mfa-optional-email-totp", + stack, + userPool, + cfnUserPool, +}); +backend.addOutput(customOutputs); diff --git a/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/package.json b/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/package.json new file mode 100644 index 0000000000..aead43de36 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/tsconfig.json b/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/tsconfig.json new file mode 100644 index 0000000000..4eb4ab26ca --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-totp/amplify/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "paths": { + "$amplify/*": [ + "../.amplify/generated/*" + ] + } + } +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-optional-email-totp/package.json b/infra-gen2/backends/auth/mfa-optional-email-totp/package.json new file mode 100644 index 0000000000..20be47dae0 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-optional-email-totp/package.json @@ -0,0 +1,5 @@ +{ + "name": "mfa-optional-email-totp", + "version": "1.0.0", + "main": "index.js" +} diff --git a/infra-gen2/backends/auth/mfa-required-email-totp/.gitignore b/infra-gen2/backends/auth/mfa-required-email-totp/.gitignore new file mode 100644 index 0000000000..03d4668c65 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-totp/.gitignore @@ -0,0 +1,5 @@ +# amplify +node_modules +.amplify +amplify_outputs* +amplifyconfiguration* diff --git a/infra-gen2/backends/auth/mfa-required-email-totp/amplify/auth/resource.ts b/infra-gen2/backends/auth/mfa-required-email-totp/amplify/auth/resource.ts new file mode 100644 index 0000000000..bf09fd7dc7 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-totp/amplify/auth/resource.ts @@ -0,0 +1,17 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineAuth } from "@aws-amplify/backend"; + +export const auth = defineAuth({ + name: "mfa-required-email-totp", + loginWith: { + email: true, + }, + // TODO(khatruong2009): Uncomment the following line when the feature is ready. + // multifactor: { + // mode: "REQUIRED", + // email: true, + // totp: true, + // }, +}); diff --git a/infra-gen2/backends/auth/mfa-required-email-totp/amplify/backend.ts b/infra-gen2/backends/auth/mfa-required-email-totp/amplify/backend.ts new file mode 100644 index 0000000000..c9e3bd79c1 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-totp/amplify/backend.ts @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineBackend } from "@aws-amplify/backend"; +import { addAuthUserExtensions } from "infra-common"; +import { auth } from "./auth/resource"; + +const backend = defineBackend({ + auth, +}); + +const resources = backend.auth.resources; +const { userPool, cfnResources } = resources; +const { stack } = userPool; +const { cfnUserPool } = cfnResources; + +// Adds infra for creating/deleting users via App Sync and fetching confirmation +// and MFA codes from App Sync. +const customOutputs = addAuthUserExtensions({ + name: "mfa-required-email-totp", + stack, + userPool, + cfnUserPool, +}); +backend.addOutput(customOutputs); diff --git a/infra-gen2/backends/auth/mfa-required-email-totp/amplify/package.json b/infra-gen2/backends/auth/mfa-required-email-totp/amplify/package.json new file mode 100644 index 0000000000..aead43de36 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-totp/amplify/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-required-email-totp/amplify/tsconfig.json b/infra-gen2/backends/auth/mfa-required-email-totp/amplify/tsconfig.json new file mode 100644 index 0000000000..4eb4ab26ca --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-totp/amplify/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "paths": { + "$amplify/*": [ + "../.amplify/generated/*" + ] + } + } +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/mfa-required-email-totp/package.json b/infra-gen2/backends/auth/mfa-required-email-totp/package.json new file mode 100644 index 0000000000..1ebbbbb859 --- /dev/null +++ b/infra-gen2/backends/auth/mfa-required-email-totp/package.json @@ -0,0 +1,5 @@ +{ + "name": "mfa-required-email-totp", + "version": "1.0.0", + "main": "index.js" +} From d4dfeea8bee3ff0d0d8c120e71af3866a1bf1eb2 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Sun, 20 Oct 2024 19:39:06 -0700 Subject: [PATCH 127/159] chore: add backend to the deploy gen 2 script --- infra-gen2/tool/deploy_gen2.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/infra-gen2/tool/deploy_gen2.dart b/infra-gen2/tool/deploy_gen2.dart index 42ab0bb25d..b6f2ce715c 100644 --- a/infra-gen2/tool/deploy_gen2.dart +++ b/infra-gen2/tool/deploy_gen2.dart @@ -78,6 +78,16 @@ const List infraConfig = [ identifier: 'mfa-opt-ema-sms', pathToSource: 'infra-gen2/backends/auth/mfa-optional-email-sms', ), + AmplifyBackend( + name: 'mfa-required-email-totp', + identifier: 'mfa-req-ema-tot', + pathToSource: 'infra-gen2/backends/auth/mfa-required-email-totp', + ), + AmplifyBackend( + name: 'mfa-optional-email-totp', + identifier: 'mfa-opt-ema-tot', + pathToSource: 'infra-gen2/backends/auth/mfa-optional-email-totp', + ), ], ), AmplifyBackendGroup( From 53ef164471248df173a97792545584da5fe49b3b Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:55:14 -0700 Subject: [PATCH 128/159] chore: add mfa-totp optional and required environments to script --- .../lib/src/environments.dart | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/test/amplify_auth_integration_test/lib/src/environments.dart b/packages/test/amplify_auth_integration_test/lib/src/environments.dart index d35c84f377..08fd99ea8e 100644 --- a/packages/test/amplify_auth_integration_test/lib/src/environments.dart +++ b/packages/test/amplify_auth_integration_test/lib/src/environments.dart @@ -89,6 +89,20 @@ const mfaOptionalEmailSms = EnvironmentInfo.withGen2Defaults( loginMethod: LoginMethod.email, ); +/// An environment with required MFA via Email & TOTP. +const mfaRequiredEmailTotp = EnvironmentInfo.withGen2Defaults( + name: 'mfa-required-email-totp', + mfaInfo: MfaInfo(emailEnabled: true, totpEnabled: true, required: true), + loginMethod: LoginMethod.email, +); + +/// An environment with optional MFA via Email & TOTP. +const mfaOptionalEmailTotp = EnvironmentInfo.withGen2Defaults( + name: 'mfa-optional-email-totp', + mfaInfo: MfaInfo(emailEnabled: true, totpEnabled: true, required: false), + loginMethod: LoginMethod.email, +); + /// Environments that support MFA const List mfaEnvironments = [ mfaOptionalSms, @@ -101,6 +115,8 @@ const List mfaEnvironments = [ mfaOptionalEmail, mfaRequiredEmailSms, mfaOptionalEmailSms, + mfaRequiredEmailTotp, + mfaOptionalEmailTotp, ]; /// Environments with a user pool and opt-in device tracking. From 46e30ee0b51b5c8ed1e13de163f6c5e16bbbf6fe Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:55:30 -0700 Subject: [PATCH 129/159] chore: add expect email method for authenticator page tests --- .../lib/src/pages/authenticator_page.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/authenticator/amplify_authenticator_test/lib/src/pages/authenticator_page.dart b/packages/authenticator/amplify_authenticator_test/lib/src/pages/authenticator_page.dart index 4b4da3226b..78eb6148c6 100644 --- a/packages/authenticator/amplify_authenticator_test/lib/src/pages/authenticator_page.dart +++ b/packages/authenticator/amplify_authenticator_test/lib/src/pages/authenticator_page.dart @@ -42,6 +42,21 @@ abstract class AuthenticatorPage { expect(usernameFieldHint, isPresent ? findsOneWidget : findsNothing); } + /// Then I see "Email" as an input field + void expectEmail({ + String label = 'Email', + bool isPresent = true, + }) { + // email field is present + expect(usernameField, findsOneWidget); + // login type is "email" + final usernameFieldHint = find.descendant( + of: usernameField, + matching: find.text(label), + ); + expect(usernameFieldHint, isPresent ? findsOneWidget : findsNothing); + } + /// Expects the current step to be [step]. void expectStep(AuthenticatorStep step) { final currentScreen = tester.widget( From 104c248c2263f857f7c393274c6605333cff9ea9 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:59:54 -0700 Subject: [PATCH 130/159] chore: dart format --- .../integration_test/sign_in_mfa_sms_email_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart index b3fc1ef8d9..40b1db4d31 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart @@ -17,9 +17,9 @@ void main() { group('sign-in-sms-totp-mfa', () { testRunner.withEnvironment(mfaRequiredEmailSms, (env) { // Scenario: Sign in using a totp code when both SMS and EMAIL are enabled - // Note: When email and sms are both enabled, - // one of them must be selected as preferred. - // This is different from other mfa methods and + // Note: When email and sms are both enabled, + // one of them must be selected as preferred. + // This is different from other mfa methods and // is expected behavior from cognito testWidgets('can select EMAIL MFA', (tester) async { final username = env.generateUsername(); From 2c6ca44b6647f34cde9329dca1f048ade73508fd Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 03:11:56 -0700 Subject: [PATCH 131/159] chore: add email-totp optional test to auth cognito package --- .../mfa_email_totp_optional_test.dart | 488 ++++++++++++++++++ 1 file changed, 488 insertions(+) create mode 100644 packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart new file mode 100644 index 0000000000..799eab659c --- /dev/null +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart @@ -0,0 +1,488 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:checks/checks.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; + +void main() { + testRunner.setupTests(); + + group('MFA (EMAIL + TOTP)', () { + testRunner.withEnvironment(mfaOptionalEmailTotp, (env) { + asyncTest('can set up TOTP MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + // Create user with no phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + autoFillAttributes: false, + attributes: { + AuthUserAttributeKey.email: username, + }, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + because: 'MFA is optional', + signInRes.nextStep.signInStep, + ).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()) + .equals(const UserMfaPreference()); + + await setUpTotp(); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.totp}, + preferred: MfaType.totp, + ), + ); + + Future signInWithTotp() async { + await signOutUser(assertComplete: true); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'Once TOTP MFA is preferred, it is performed ' + 'on every sign-in attempt.', + ).equals(AuthSignInStep.confirmSignInWithTotpMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.totp) + ..has((d) => d.destination, 'destination') + .equals(friendlyDeviceName); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await generateTotpCode(), + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + await signInWithTotp(); + await signInWithTotp(); + + await check( + because: 'TOTP can be disabled when optional', + cognitoPlugin.updateMfaPreference(totp: MfaPreference.disabled), + ).completes(); + + check( + because: 'Disabling TOTP should mark it as not preferred', + await cognitoPlugin.fetchMfaPreference(), + ).equals( + const UserMfaPreference(enabled: {}, preferred: null), + ); + }); + + asyncTest('can select TOTP MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + // Create a user with an unverified phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.email: username, + }, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is optional', + ).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()) + .equals(const UserMfaPreference()); + + await setUpTotp(); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.totp}, + preferred: MfaType.totp, + ), + ); + + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.enabled, + totp: MfaPreference.enabled, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.continueSignInWithMfaSelection); + check(signInRes.nextStep.allowedMfaTypes) + .isNotNull() + .deepEquals({MfaType.email, MfaType.totp}); + + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'TOTP', + ); + check(selectRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithTotpMfaCode); + check(selectRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.totp) + ..has((d) => d.destination, 'destination') + .equals(friendlyDeviceName); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await generateTotpCode(), + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + // Verify we can set TOTP as preferred and forego selection. + + await cognitoPlugin.updateMfaPreference( + totp: MfaPreference.preferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'TOTP should be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: MfaType.totp, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithTotpMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.totp) + ..has((d) => d.destination, 'destination') + .equals(friendlyDeviceName); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await generateTotpCode(), + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify we can switch to EMAIL as preferred. + + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: MfaType.email, + ), + ); + + { + await signOutUser(assertComplete: true); + + final otpRes = await getOtpCode(env.getLoginAttribute(username)); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpRes.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify marking enabled does not change preference. + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.enabled, + totp: MfaPreference.enabled, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should still be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: MfaType.email, + ), + ); + + // Verify we can mark neither as preferred + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.notPreferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should be marked not preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + // Verify that we can disable both + await check( + because: 'MFA can be disabled when optional', + cognitoPlugin.updateMfaPreference( + email: MfaPreference.disabled, + totp: MfaPreference.disabled, + ), + ).completes(); + + check( + because: 'Disabling MFA should mark it as not preferred', + await cognitoPlugin.fetchMfaPreference(), + ).equals( + const UserMfaPreference(enabled: {}, preferred: null), + ); + }); + + asyncTest('can select EMAIL MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + // Create a user with an unverified phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.email: username, + }, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is optional', + ).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()) + .equals(const UserMfaPreference()); + + await setUpTotp(); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.totp}, + preferred: MfaType.totp, + ), + ); + + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.enabled, + totp: MfaPreference.enabled, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + await signOutUser(assertComplete: true); + + final resignInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(resignInRes.nextStep.signInStep) + .equals(AuthSignInStep.continueSignInWithMfaSelection); + check(resignInRes.nextStep.allowedMfaTypes) + .isNotNull() + .deepEquals({MfaType.email, MfaType.totp}); + + final otpResult = await getOtpCode(UserAttribute.email(username)); + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'EMAIL', + ); + check(selectRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(selectRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + // Verify we can set EMAIL as preferred and forego selection. + + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: MfaType.email, + ), + ); + + { + await signOutUser(assertComplete: true); + + final otpResult = await getOtpCode(UserAttribute.email(username)); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify we can switch to TOTP as preferred. + + await cognitoPlugin.updateMfaPreference( + totp: MfaPreference.preferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'TOTP should be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: MfaType.totp, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(signInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithTotpMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.totp) + ..has((d) => d.destination, 'destination') + .equals(friendlyDeviceName); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await generateTotpCode(), + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify marking enabled does not change preference. + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.enabled, + totp: MfaPreference.enabled, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'TOTP should still be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: MfaType.totp, + ), + ); + + // Verify we can mark neither as preferred + await cognitoPlugin.updateMfaPreference( + totp: MfaPreference.notPreferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'TOTP should be marked not preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + // Verify that we can disable both + await check( + because: 'MFA can be disabled when optional', + cognitoPlugin.updateMfaPreference( + email: MfaPreference.disabled, + totp: MfaPreference.disabled, + ), + ).completes(); + + check( + because: 'Disabling MFA should mark it as not preferred', + await cognitoPlugin.fetchMfaPreference(), + ).equals( + const UserMfaPreference(enabled: {}, preferred: null), + ); + }); + }); + }); +} From b41ae4921c068050a58fd443f312ed162f50ae21 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 03:12:30 -0700 Subject: [PATCH 132/159] chore: add confirm sign in page utility to tap email mfa option --- .../lib/src/pages/confirm_sign_in_page.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart index 8ccfa07ad9..3167221ac8 100644 --- a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart +++ b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart @@ -149,9 +149,15 @@ class ConfirmSignInPage extends AuthenticatorPage { }) async { expect(selectMfaRadio, findsOneWidget); + // if mfaMethod is email, don't make it uppercase except for the first letter + // if mfa method is totp, make it all uppercase final mfaMethodWidget = find.descendant( of: selectMfaRadio, - matching: find.textContaining('(${mfaMethod.name.toUpperCase()})'), + matching: find.textContaining( + mfaMethod == MfaType.email + ? 'Email' + : '(${mfaMethod.name.toUpperCase()})', + ), ); await tester.tap(mfaMethodWidget); From c7d574daed047c87c0b08e18d849fd83223cd8f6 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 03:12:41 -0700 Subject: [PATCH 133/159] chore: add authenticator test for email otp --- .../sign_in_mfa_email_totp_test.dart | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_totp_test.dart diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_totp_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_totp_test.dart new file mode 100644 index 0000000000..fdb17d628c --- /dev/null +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_totp_test.dart @@ -0,0 +1,223 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_authenticator_test/amplify_authenticator_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; +import 'utils/test_utils.dart'; + +void main() { + testRunner.setupTests(); + + group('sign-in-email-totp-mfa', () { + testRunner.withEnvironment(mfaRequiredEmailTotp, (env) { + // Scenario: Sign in using a totp code when both EMAIL and TOTP are enabled + testWidgets('can select TOTP MFA', (tester) async { + final username = env.generateUsername(); + final password = generatePassword(); + + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.email: username, + }, + ); + + await loadAuthenticator(tester: tester); + + expect( + tester.bloc.stream, + emitsInOrder([ + UnauthenticatedState.signIn, + UnauthenticatedState.confirmSignInWithEmailMfaCode, + isA(), + UnauthenticatedState.signIn, + isA(), + UnauthenticatedState.confirmSignInWithTotpMfaCode, + isA(), + emitsDone, + ]), + ); + + final signInPage = SignInPage(tester: tester); + final confirmSignInPage = ConfirmSignInPage(tester: tester); + + final otpResult = await getOtpCode(UserAttribute.email(username)); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the confirm email mfa page + await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + + // When I type a valid confirmation code + await confirmSignInPage.enterVerificationCode(await otpResult.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + // When I enable TOTP for MFA instead of the default set up by cognito (EMAIL) + await setUpTotp(); + + // And I sign out using Auth.signOut() + await Amplify.Auth.signOut(); + await tester.pumpAndSettle(); + + // Then I see the sign in page + signInPage.expectEmail(); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the MFA selection page + await confirmSignInPage.expectConfirmSignInMfaSelectionIsPresent(); + + // When I select "TOTP" + await confirmSignInPage.selectMfaMethod(mfaMethod: MfaType.totp); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignInMfaSelection(); + + // Then I will be redirected to the TOTP MFA code page + await confirmSignInPage.expectConfirmSignInWithTotpMfaCodeIsPresent(); + + final code_2 = await generateTotpCode(); + + // When I type a valid TOTP code + await confirmSignInPage.enterVerificationCode(code_2); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + await tester.bloc.close(); + }); + + // Scenario: Sign in using a EMAIL code when both EMAIL and TOTP are enabled + testWidgets('can select EMAIL MFA', (tester) async { + final username = env.generateUsername(); + final password = generatePassword(); + + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.email: username, + }, + ); + + await loadAuthenticator(tester: tester); + + expect( + tester.bloc.stream, + emitsInOrder([ + UnauthenticatedState.signIn, + UnauthenticatedState.confirmSignInWithEmailMfaCode, + isA(), + UnauthenticatedState.signIn, + isA(), + UnauthenticatedState.confirmSignInWithEmailMfaCode, + isA(), + emitsDone, + ]), + ); + + final signInPage = SignInPage(tester: tester); + final confirmSignInPage = ConfirmSignInPage(tester: tester); + + final otpResult = await getOtpCode(UserAttribute.email(username)); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the confirm email mfa page + await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + + // When I type a valid confirmation code + await confirmSignInPage.enterVerificationCode(await otpResult.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + // When I enable TOTP for MFA instead of the default set up by cognito (EMAIL) + await setUpTotp(); + + // And I sign out using Auth.signOut() + await Amplify.Auth.signOut(); + await tester.pumpAndSettle(); + + // Then I see the sign in page + signInPage.expectEmail(); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the MFA selection page + await confirmSignInPage.expectConfirmSignInMfaSelectionIsPresent(); + + final otpResult2 = await getOtpCode(UserAttribute.email(username)); + + // When I select "EMAIL" + await confirmSignInPage.selectMfaMethod(mfaMethod: MfaType.email); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignInMfaSelection(); + + // Then I will be redirected to the confirm EMAIL mfa page + await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + + // When I type a valid confirmation code + await confirmSignInPage.enterVerificationCode(await otpResult2.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + await tester.bloc.close(); + }); + }); + }); +} From d3173eb93ddfd2bc47c7af0c6279415bd7703178 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 13:56:41 -0700 Subject: [PATCH 134/159] chore: add email-totp required tests --- .../mfa_email_totp_required_test.dart | 288 ++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart new file mode 100644 index 0000000000..6cfbf60cc8 --- /dev/null +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart @@ -0,0 +1,288 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:checks/checks.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; + +void main() { + testRunner.setupTests(); + + group('MFA (EMAIL + TOTP)', () { + testRunner.withEnvironment(mfaRequiredEmailTotp, (env) { + asyncTest('can set up EMAIL MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + // Create a user with no phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + autoFillAttributes: false, + verifyAttributes: false, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: + 'When an email is registered and the userpool has email MFA enabled, Cognito will automatically enable email MFA as the preferred MFA method.', + ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + + final otpResult = await getOtpCode(UserAttribute.email(username)); + final setupRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(setupRes.nextStep.signInStep).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + await signOutUser(assertComplete: true); + + final resignInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(resignInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(resignInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final otpResult2 = await getOtpCode(UserAttribute.email(username)); + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult2.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + }); + + asyncTest('can select TOTP MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + // Create a user with an unverified phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + attributes: { + AuthUserAttributeKey.email: username, + }, + ); + + { + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: + 'MFA is required so Cognito automatically enables EMAIL MFA', + ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + + final otpResult = await getOtpCode(UserAttribute.email(username)); + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + check( + await cognitoPlugin.fetchMfaPreference(), + because: + 'MFA is required so Cognito automatically enables EMAIL MFA, this is expected behavior', + ).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + await setUpTotp(); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + await signOutUser(assertComplete: true); + + { + final resignInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + resignInRes.nextStep.signInStep, + because: 'Both EMAIL + TOTP are activated with no preference', + ).equals(AuthSignInStep.continueSignInWithMfaSelection); + check(resignInRes.nextStep.allowedMfaTypes) + .isNotNull() + .deepEquals({MfaType.email, MfaType.totp}); + + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'TOTP', + ); + check(selectRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithTotpMfaCode); + check(selectRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.totp) + ..has((d) => d.destination, 'destination') + .equals(friendlyDeviceName); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await generateTotpCode(), + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + // Verify we can set TOTP as preferred and forego selection. + + await cognitoPlugin.updateMfaPreference( + totp: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: MfaType.totp, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'Preference is TOTP MFA now', + ).equals(AuthSignInStep.confirmSignInWithTotpMfaCode); + check(signInRes.nextStep.codeDeliveryDetails).isNotNull() + ..has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.totp) + ..has((d) => d.destination, 'destination') + .equals(friendlyDeviceName); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await generateTotpCode(), + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify we can switch to EMAIL as preferred. + + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.preferred, + ); + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: MfaType.email, + ), + ); + + { + await signOutUser(assertComplete: true); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'Preference is EMAIL MFA now', + ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final otpResult = await getOtpCode(UserAttribute.email(username)); + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + // Verify marking enabled does not change preference. + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.enabled, + totp: MfaPreference.enabled, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should still be marked preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: MfaType.email, + ), + ); + + // Verify we can mark neither as preferred + await cognitoPlugin.updateMfaPreference( + email: MfaPreference.notPreferred, + ); + check( + await cognitoPlugin.fetchMfaPreference(), + because: 'EMAIL should be marked not preferred', + ).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + // Verify that we can disable MFA + { + await check( + because: 'Interestingly, Cognito does not throw and allows ' + 'MFA to be disabled even when required.', + cognitoPlugin.updateMfaPreference( + email: MfaPreference.disabled, + totp: MfaPreference.disabled, + ), + ).completes(); + + check( + because: 'Disabling MFA should mark it as not preferred', + await cognitoPlugin.fetchMfaPreference(), + ).equals( + const UserMfaPreference( + enabled: {}, + preferred: null, + ), + ); + } + }); + }); + }); +} From a94edd657c3b11507c66bb6f61037cfe4278357a Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:55:41 -0700 Subject: [PATCH 135/159] chore: add setup selection step to form field state --- .../amplify_authenticator/lib/src/widgets/form_field.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index a9824be8c5..cc538d7dc8 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -240,7 +240,8 @@ abstract class AuthenticatorFormFieldState< state.confirmTotp(); case AuthenticatorStep.continueSignInWithEmailMfaSetup: state.continueEmailMfaSetup(); - // TODO(khatruong2009): add case for AuthenticatorStep.continueSignInWithMfaSetupSelection + case AuthenticatorStep.continueSignInWithMfaSetupSelection: + state.continueSignInWithMfaSetupSelection(); case AuthenticatorStep.resetPassword: state.resetPassword(); case AuthenticatorStep.confirmResetPassword: From d85e665ccc70fa8b02fe7da0acebae240fd836fd Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:56:27 -0700 Subject: [PATCH 136/159] chore: add authenticator tests for mfa setup selection --- .../sign_in_mfa_username_login_test.dart | 245 ++++++++++++++++++ .../lib/amplify_authenticator_test.dart | 1 + .../lib/src/pages/email_mfa_setup_page.dart | 44 ++++ .../lib/src/environments.dart | 8 + 4 files changed, 298 insertions(+) create mode 100644 packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart create mode 100644 packages/authenticator/amplify_authenticator_test/lib/src/pages/email_mfa_setup_page.dart diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart new file mode 100644 index 0000000000..e581e3e3f9 --- /dev/null +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart @@ -0,0 +1,245 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_authenticator_test/amplify_authenticator_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; +import 'utils/test_utils.dart'; + +void main() { + testRunner.setupTests(); + + group('sign-in-email-totp-mfa', () { + testRunner.withEnvironment(mfaRequiredUsernameLogin, (env) { + // Scenario: Select EMAIL MFA to set up from the setup selection page + testWidgets('can select EMAIL MFA to set up', (tester) async { + final username = env.generateUsername(); + final password = generatePassword(); + final email = generateEmail(); + + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + autoFillAttributes: false, + ); + + await loadAuthenticator(tester: tester); + + expect( + tester.bloc.stream, + emitsInOrder([ + UnauthenticatedState.signIn, + isA(), + UnauthenticatedState.continueSignInWithEmailMfaSetup, + UnauthenticatedState.confirmSignInWithEmailMfaCode, + isA(), + UnauthenticatedState.signIn, + isA(), + UnauthenticatedState.confirmSignInWithTotpMfaCode, + isA(), + emitsDone, + ]), + ); + + final signInPage = SignInPage(tester: tester); + final confirmSignInPage = ConfirmSignInPage(tester: tester); + final emailMfaSetupPage = EmailMfaSetupPage(tester: tester); + + final otpResult = await getOtpCode(UserAttribute.email(email)); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the confirm email mfa page + await confirmSignInPage + .expectContinueSignInWithMfaSetupSelectionIsPresent(); + + // When I select "EMAIL" + await confirmSignInPage.selectMfaSetupMethod(mfaMethod: MfaType.email); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignInMfaSetupSelection(); + + // Then I will be redirected to the EMAIL mfa setup page + await emailMfaSetupPage.expectEmailMfaSetupIsPresent(); + + // When I type a valid email + await emailMfaSetupPage.enterEmail(email); + + // And I click the "Confirm" button + await emailMfaSetupPage.submitEmail(); + + // When I type a valid confirmation code + await confirmSignInPage.enterVerificationCode(await otpResult.code); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + // When I enable TOTP for MFA instead of the default set up by cognito (EMAIL) + await setUpTotp(); + + // And I sign out using Auth.signOut() + await Amplify.Auth.signOut(); + await tester.pumpAndSettle(); + + // Then I see the sign in page + signInPage.expectUsername(); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the MFA selection page + await confirmSignInPage.expectConfirmSignInMfaSelectionIsPresent(); + + // When I select "TOTP" + await confirmSignInPage.selectMfaMethod(mfaMethod: MfaType.totp); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignInMfaSelection(); + + // Then I will be redirected to the TOTP MFA code page + await confirmSignInPage.expectConfirmSignInWithTotpMfaCodeIsPresent(); + + final code_2 = await generateTotpCode(); + + // When I type a valid TOTP code + await confirmSignInPage.enterVerificationCode(code_2); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + await tester.bloc.close(); + }); + + // Scenario: Sign in using a EMAIL code when both EMAIL and TOTP are enabled + testWidgets('can select TOTP MFA to set up', (tester) async { + final username = env.generateUsername(); + final password = generatePassword(); + late String sharedSecret; + + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + autoFillAttributes: false, + ); + + await loadAuthenticator(tester: tester); + + tester.bloc.stream.listen((event) { + if (event is ContinueSignInTotpSetup) { + sharedSecret = event.totpSetupDetails.sharedSecret; + } + }); + + expect( + tester.bloc.stream, + emitsInOrder([ + UnauthenticatedState.signIn, + isA(), + isA(), + isA(), + UnauthenticatedState.signIn, + UnauthenticatedState.confirmSignInWithTotpMfaCode, + // UnauthenticatedState.confirmSignInWithEmailMfaCode, + isA(), + emitsDone, + ]), + ); + + final signInPage = SignInPage(tester: tester); + final confirmSignInPage = ConfirmSignInPage(tester: tester); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the confirm email mfa page + await confirmSignInPage + .expectContinueSignInWithMfaSetupSelectionIsPresent(); + + // When I select "TOTP" + await confirmSignInPage.selectMfaSetupMethod(mfaMethod: MfaType.totp); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignInMfaSetupSelection(); + + // Then I will be redirected to the TOTP mfa setup page + await confirmSignInPage.expectSignInTotpSetupIsPresent(); + + final totpCode = await generateTotpCode(sharedSecret); + + // And I type a valid TOTP code + await confirmSignInPage.enterVerificationCode(totpCode); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + // And I sign out using Auth.signOut() + await Amplify.Auth.signOut(); + await tester.pumpAndSettle(); + + // Then I see the sign in page + signInPage.expectUsername(); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the TOTP MFA code page + await confirmSignInPage.expectConfirmSignInWithTotpMfaCodeIsPresent(); + + final code_2 = await generateTotpCode(sharedSecret); + + // When I type a valid TOTP code + await confirmSignInPage.enterVerificationCode(code_2); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see the authenticated app + await signInPage.expectAuthenticated(); + + await tester.bloc.close(); + }); + }); + }); +} diff --git a/packages/authenticator/amplify_authenticator_test/lib/amplify_authenticator_test.dart b/packages/authenticator/amplify_authenticator_test/lib/amplify_authenticator_test.dart index d247d71507..49b9300e16 100644 --- a/packages/authenticator/amplify_authenticator_test/lib/amplify_authenticator_test.dart +++ b/packages/authenticator/amplify_authenticator_test/lib/amplify_authenticator_test.dart @@ -18,6 +18,7 @@ export 'src/pages/authenticator_page.dart'; export 'src/pages/confirm_sign_in_page.dart'; export 'src/pages/confirm_sign_up_page.dart'; export 'src/pages/confirm_verify_user_page.dart'; +export 'src/pages/email_mfa_setup_page.dart'; export 'src/pages/forgot_password_page.dart'; export 'src/pages/sign_in_page.dart'; export 'src/pages/sign_up_page.dart'; diff --git a/packages/authenticator/amplify_authenticator_test/lib/src/pages/email_mfa_setup_page.dart b/packages/authenticator/amplify_authenticator_test/lib/src/pages/email_mfa_setup_page.dart new file mode 100644 index 0000000000..c2d67b8d8b --- /dev/null +++ b/packages/authenticator/amplify_authenticator_test/lib/src/pages/email_mfa_setup_page.dart @@ -0,0 +1,44 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_authenticator/amplify_authenticator.dart'; +// ignore: implementation_imports +import 'package:amplify_authenticator/src/keys.dart'; +// ignore: implementation_imports +import 'package:amplify_authenticator/src/screens/authenticator_screen.dart'; +import 'package:amplify_authenticator_test/src/pages/authenticator_page.dart'; +import 'package:flutter_test/flutter_test.dart'; + +class EmailMfaSetupPage extends AuthenticatorPage { + EmailMfaSetupPage({required super.tester}); + + @override + Finder get usernameField => throw UnimplementedError(); + + Finder get emailField => find.byKey(keyEmailSetupFormField); + Finder get continueSignIn => + find.byKey(keyConfirmSignInWithEmailMfaSetupButton); + + /// When I type my email + Future enterEmail(String email) async { + await tester.ensureVisible(emailField); + await tester.enterText(emailField, email); + await tester.pumpAndSettle(); + } + + /// Then I see "Add Email for Two-Factor Authentication" + Future expectEmailMfaSetupIsPresent() async { + final currentScreen = tester.widget( + find.byType(AuthenticatorScreen), + ); + expect(currentScreen.step, + equals(AuthenticatorStep.continueSignInWithEmailMfaSetup),); + } + + /// When I enter an email + Future submitEmail() async { + await tester.ensureVisible(continueSignIn); + await tester.tap(continueSignIn); + await tester.pumpAndSettle(); + } +} diff --git a/packages/test/amplify_auth_integration_test/lib/src/environments.dart b/packages/test/amplify_auth_integration_test/lib/src/environments.dart index 08fd99ea8e..8eab2d4814 100644 --- a/packages/test/amplify_auth_integration_test/lib/src/environments.dart +++ b/packages/test/amplify_auth_integration_test/lib/src/environments.dart @@ -103,6 +103,13 @@ const mfaOptionalEmailTotp = EnvironmentInfo.withGen2Defaults( loginMethod: LoginMethod.email, ); +/// An environment with required MFA and username login. +const mfaRequiredUsernameLogin = EnvironmentInfo.withGen2Defaults( + name: 'username-login-mfa', + mfaInfo: MfaInfo(smsEnabled: true, totpEnabled: true, emailEnabled: true, required: true), + loginMethod: LoginMethod.username, +); + /// Environments that support MFA const List mfaEnvironments = [ mfaOptionalSms, @@ -117,6 +124,7 @@ const List mfaEnvironments = [ mfaOptionalEmailSms, mfaRequiredEmailTotp, mfaOptionalEmailTotp, + mfaRequiredUsernameLogin, ]; /// Environments with a user pool and opt-in device tracking. From 453a175c3aa6ece7f2eb60a7fb1ee59135a4ade7 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:57:36 -0700 Subject: [PATCH 137/159] chore: add new backend for username only login --- .../auth/username-login-mfa/.gitignore | 5 ++ .../amplify/auth/resource.ts | 19 +++++ .../username-login-mfa/amplify/backend.ts | 40 +++++++++++ .../username-login-mfa/amplify/package.json | 3 + .../username-login-mfa/amplify/tsconfig.json | 17 +++++ .../auth/username-login-mfa/package.json | 5 ++ infra-gen2/package-lock.json | 71 +++++++++---------- infra-gen2/tool/deploy_gen2.dart | 5 ++ 8 files changed, 126 insertions(+), 39 deletions(-) create mode 100644 infra-gen2/backends/auth/username-login-mfa/.gitignore create mode 100644 infra-gen2/backends/auth/username-login-mfa/amplify/auth/resource.ts create mode 100644 infra-gen2/backends/auth/username-login-mfa/amplify/backend.ts create mode 100644 infra-gen2/backends/auth/username-login-mfa/amplify/package.json create mode 100644 infra-gen2/backends/auth/username-login-mfa/amplify/tsconfig.json create mode 100644 infra-gen2/backends/auth/username-login-mfa/package.json diff --git a/infra-gen2/backends/auth/username-login-mfa/.gitignore b/infra-gen2/backends/auth/username-login-mfa/.gitignore new file mode 100644 index 0000000000..03d4668c65 --- /dev/null +++ b/infra-gen2/backends/auth/username-login-mfa/.gitignore @@ -0,0 +1,5 @@ +# amplify +node_modules +.amplify +amplify_outputs* +amplifyconfiguration* diff --git a/infra-gen2/backends/auth/username-login-mfa/amplify/auth/resource.ts b/infra-gen2/backends/auth/username-login-mfa/amplify/auth/resource.ts new file mode 100644 index 0000000000..ebd216d43a --- /dev/null +++ b/infra-gen2/backends/auth/username-login-mfa/amplify/auth/resource.ts @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineAuth } from "@aws-amplify/backend"; + +export const auth = defineAuth({ + name: "mfa-required-email", + loginWith: { + phone: true, + }, + // TODO(khatruong2009): Uncomment the following line when the feature is ready. + // multifactor: { + // mode: "REQUIRED", + // email: true, + // sms: true, + // totp: true, + // }, + accountRecovery: "PHONE_WITHOUT_MFA_AND_EMAIL", +}); diff --git a/infra-gen2/backends/auth/username-login-mfa/amplify/backend.ts b/infra-gen2/backends/auth/username-login-mfa/amplify/backend.ts new file mode 100644 index 0000000000..ce86475882 --- /dev/null +++ b/infra-gen2/backends/auth/username-login-mfa/amplify/backend.ts @@ -0,0 +1,40 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineBackend } from "@aws-amplify/backend"; +import { addAuthUserExtensions } from "infra-common"; +import { auth } from "./auth/resource"; + +const backend = defineBackend({ + auth, +}); + +const resources = backend.auth.resources; +const { userPool, cfnResources } = resources; +const { stack } = userPool; +const { cfnUserPool } = cfnResources; + +// Adds infra for creating/deleting users via App Sync and fetching confirmation +// and MFA codes from App Sync. +const customOutputs = addAuthUserExtensions({ + name: "username-login-mfa", + stack, + userPool, + cfnUserPool, +}); +backend.addOutput(customOutputs); + +cfnUserPool.schema = undefined; +cfnUserPool.usernameAttributes = []; +cfnUserPool.emailConfiguration = { + emailSendingAccount: "DEVELOPER", + from: "ktruon@amazon.com", + sourceArn: `arn:aws:ses:${stack.region}:${stack.account}:identity/ktruon@amazon.com`, +}; +cfnUserPool.adminCreateUserConfig = { + allowAdminCreateUserOnly: true, +}; +cfnUserPool.autoVerifiedAttributes = []; +cfnUserPool.userAttributeUpdateSettings = { + attributesRequireVerificationBeforeUpdate: [], +}; diff --git a/infra-gen2/backends/auth/username-login-mfa/amplify/package.json b/infra-gen2/backends/auth/username-login-mfa/amplify/package.json new file mode 100644 index 0000000000..aead43de36 --- /dev/null +++ b/infra-gen2/backends/auth/username-login-mfa/amplify/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/username-login-mfa/amplify/tsconfig.json b/infra-gen2/backends/auth/username-login-mfa/amplify/tsconfig.json new file mode 100644 index 0000000000..4eb4ab26ca --- /dev/null +++ b/infra-gen2/backends/auth/username-login-mfa/amplify/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "paths": { + "$amplify/*": [ + "../.amplify/generated/*" + ] + } + } +} \ No newline at end of file diff --git a/infra-gen2/backends/auth/username-login-mfa/package.json b/infra-gen2/backends/auth/username-login-mfa/package.json new file mode 100644 index 0000000000..e604512607 --- /dev/null +++ b/infra-gen2/backends/auth/username-login-mfa/package.json @@ -0,0 +1,5 @@ +{ + "name": "username-login-mfa", + "version": "1.0.0", + "main": "index.js" +} diff --git a/infra-gen2/package-lock.json b/infra-gen2/package-lock.json index 806c800dd6..f56c0348d5 100644 --- a/infra-gen2/package-lock.json +++ b/infra-gen2/package-lock.json @@ -45,9 +45,15 @@ "backends/auth/email-sign-in": { "version": "1.0.0" }, + "backends/auth/mfa-optional-email": { + "version": "1.0.0" + }, "backends/auth/mfa-optional-sms": { "version": "1.0.0" }, + "backends/auth/mfa-required-email": { + "version": "1.0.0" + }, "backends/auth/mfa-required-sms": { "version": "1.0.0" }, @@ -4338,35 +4344,11 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.624.0", - "@aws-sdk/client-sts": "3.624.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-sdk-ec2": "3.622.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@aws-sdk/util-endpoints": "3.637.0", "@smithy/protocol-http": "^4.1.0", "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.1.2", - "tslib": "^2.6.2", - "uuid": "^9.0.1" + "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" @@ -4378,14 +4360,6 @@ "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/types": "^3.3.0", @@ -4498,8 +4472,6 @@ "license": "Apache-2.0", "dependencies": { "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { @@ -10505,6 +10477,20 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/middleware-user-agent/node_modules/@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/region-config-resolver": { "version": "3.614.0", "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", @@ -10555,10 +10541,9 @@ } }, "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/util-endpoints": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", - "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", - "license": "Apache-2.0", + "version": "3.637.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.637.0.tgz", + "integrity": "sha512-pAqOKUHeVWHEXXDIp/qoMk/6jyxIb6GGjnK1/f8dKHtKIEs4tKsnnL563gceEvdad53OPXIt86uoevCcCzmBnw==", "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/types": "^3.3.0", @@ -20121,10 +20106,18 @@ "node": ">= 8" } }, + "node_modules/mfa-optional-email": { + "resolved": "backends/auth/mfa-optional-email", + "link": true + }, "node_modules/mfa-optional-sms": { "resolved": "backends/auth/mfa-optional-sms", "link": true }, + "node_modules/mfa-required-email": { + "resolved": "backends/auth/mfa-required-email", + "link": true + }, "node_modules/mfa-required-sms": { "resolved": "backends/auth/mfa-required-sms", "link": true diff --git a/infra-gen2/tool/deploy_gen2.dart b/infra-gen2/tool/deploy_gen2.dart index b6f2ce715c..b83efb7c60 100644 --- a/infra-gen2/tool/deploy_gen2.dart +++ b/infra-gen2/tool/deploy_gen2.dart @@ -88,6 +88,11 @@ const List infraConfig = [ identifier: 'mfa-opt-ema-tot', pathToSource: 'infra-gen2/backends/auth/mfa-optional-email-totp', ), + AmplifyBackend( + name: 'username-login-mfa', + identifier: 'user-login-mfa', + pathToSource: 'infra-gen2/backends/auth/username-login-mfa', + ), ], ), AmplifyBackendGroup( From d196c8f5b35047d079af8739e612679278a04853 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:58:04 -0700 Subject: [PATCH 138/159] chore: use provided cognitoPlugin utility --- .../integration_test/mfa_email_optional_test.dart | 5 +---- .../integration_test/mfa_sms_email_optional_test.dart | 11 +++-------- .../integration_test/mfa_sms_email_required_test.dart | 7 ++----- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart index 2f6b2ffc7a..a59a121320 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart @@ -1,7 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; import 'package:amplify_integration_test/amplify_integration_test.dart'; @@ -43,9 +42,7 @@ void main() { because: 'MFA is optional', ).equals(AuthSignInStep.done); - final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); - - await plugin.updateMfaPreference( + await cognitoPlugin.updateMfaPreference( email: MfaPreference.preferred, ); diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart index 5dd7465b66..26b23ae056 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart @@ -1,7 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; import 'package:amplify_integration_test/amplify_integration_test.dart'; @@ -39,8 +38,7 @@ void main() { check(await cognitoPlugin.fetchMfaPreference()) .equals(const UserMfaPreference()); - final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); - await plugin.updateMfaPreference( + await cognitoPlugin.updateMfaPreference( email: MfaPreference.preferred, ); @@ -127,9 +125,7 @@ void main() { check(await cognitoPlugin.fetchMfaPreference()) .equals(const UserMfaPreference()); - final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); - - await plugin.updateMfaPreference( + await cognitoPlugin.updateMfaPreference( email: MfaPreference.preferred, ); @@ -313,8 +309,7 @@ void main() { check(await cognitoPlugin.fetchMfaPreference()) .equals(const UserMfaPreference()); - final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); - await plugin.updateMfaPreference( + await cognitoPlugin.updateMfaPreference( sms: MfaPreference.preferred, email: MfaPreference.enabled, ); diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart index 4a94dd1cba..9c03bef97c 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart @@ -1,7 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; import 'package:amplify_integration_test/amplify_integration_test.dart'; @@ -123,11 +122,9 @@ void main() { ), ); - final plugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + safePrint('${await cognitoPlugin.fetchMfaPreference()}'); - safePrint('${await plugin.fetchMfaPreference()}'); - - await plugin.updateMfaPreference( + await cognitoPlugin.updateMfaPreference( email: MfaPreference.preferred, ); From 0bd084248125470acae0fff4958f978916dcc259 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:58:26 -0700 Subject: [PATCH 139/159] chore: add find email mfa radio select widget --- .../lib/src/pages/confirm_sign_in_page.dart | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart index 3167221ac8..90004e529f 100644 --- a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart +++ b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart @@ -172,7 +172,11 @@ class ConfirmSignInPage extends AuthenticatorPage { final mfaMethodWidget = find.descendant( of: selectMfaSetupRadio, - matching: find.textContaining('(${mfaMethod.name.toUpperCase()})'), + matching: find.textContaining( + mfaMethod == MfaType.email + ? 'Email' + : '(${mfaMethod.name.toUpperCase()})', + ), ); await tester.tap(mfaMethodWidget); @@ -186,6 +190,13 @@ class ConfirmSignInPage extends AuthenticatorPage { await tester.pumpAndSettle(); } + /// When I click the continue sign in with MFA setup selection button + Future submitConfirmSignInMfaSetupSelection() async { + await tester.ensureVisible(confirmSignInMfaSetupSelectionButton); + await tester.tap(confirmSignInMfaSetupSelectionButton); + await tester.pumpAndSettle(); + } + /// When I navigate to the "Sign In" step. Future navigateToSignIn() async { await tester.tap(backToSignIn); From 14bb1ebbc2f374f49a536f784fd9e190fdab916f Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:30:32 -0700 Subject: [PATCH 140/159] chore: add test for mfa setup selection screen in amplify auth cognito --- .../mfa_username_login_required_test.dart | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart new file mode 100644 index 0000000000..caef8fd9a9 --- /dev/null +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart @@ -0,0 +1,261 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; +import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart'; +import 'package:amplify_flutter/amplify_flutter.dart'; +import 'package:amplify_integration_test/amplify_integration_test.dart'; +import 'package:checks/checks.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_runner.dart'; + +void main() { + testRunner.setupTests(); + + group('MFA (EMAIL + TOTP + SMS)', () { + testRunner.withEnvironment(mfaRequiredUsernameLogin, (env) { + asyncTest('can set up EMAIL MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + final email = generateEmail(); + + final otpResult = await getOtpCode(UserAttribute.email(email)); + + // Create a user with no phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + autoFillAttributes: false, + verifyAttributes: false, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + + check( + signInRes.nextStep.signInStep, + because: + 'When an email is registered and the userpool has email MFA enabled, Cognito will automatically enable email MFA as the preferred MFA method.', + ).equals(AuthSignInStep.continueSignInWithMfaSetupSelection); + + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'EMAIL', + ); + + final setupRes = await Amplify.Auth.confirmSignIn( + confirmationValue: email, + ); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + await signOutUser(assertComplete: true); + + final resignInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check(resignInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(resignInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + final otpResult2 = await getOtpCode(UserAttribute.email(email)); + final confirmRes2 = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult2.code, + ); + check(confirmRes2.nextStep.signInStep).equals(AuthSignInStep.done); + }); + + asyncTest('can setup TOTP MFA', (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + + // Create a user with an unverified phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + autoFillAttributes: false, + ); + + { + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is required so users select a method to setup', + ).equals(AuthSignInStep.continueSignInWithMfaSetupSelection); + + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'TOTP', + ); + + final sharedSecret = + selectRes.nextStep.totpSetupDetails!.sharedSecret; + final setupRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await generateTotpCode(sharedSecret), + options: const ConfirmSignInOptions( + pluginOptions: CognitoConfirmSignInPluginOptions( + friendlyDeviceName: friendlyDeviceName, + ), + ), + ); + + check(setupRes.nextStep.signInStep).equals(AuthSignInStep.done); + } + + check( + await cognitoPlugin.fetchMfaPreference(), + because: + 'MFA is required so Cognito automatically enables EMAIL MFA, this is expected behavior', + ).equals( + const UserMfaPreference( + enabled: {MfaType.totp}, + preferred: MfaType.totp, + ), + ); + + await signOutUser(assertComplete: true); + }); + + asyncTest( + 'Can set up EMAIL and TOTP MFA and then choose a preferred method', + (_) async { + final username = env.generateUsername(); + final password = generatePassword(); + final email = generateEmail(); + + final otpResult = await getOtpCode(UserAttribute.email(email)); + + // Create a user with no phone number. + await adminCreateUser( + username, + password, + autoConfirm: true, + autoFillAttributes: false, + verifyAttributes: false, + ); + + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + + check( + signInRes.nextStep.signInStep, + because: + 'When both EMAIL and TOTP are enabled but email attribute isnt verified, choose an mfa method to set up.', + ).equals(AuthSignInStep.continueSignInWithMfaSetupSelection); + + final selectRes = await Amplify.Auth.confirmSignIn( + confirmationValue: 'EMAIL', + ); + + final setupRes = await Amplify.Auth.confirmSignIn( + confirmationValue: email, + ); + + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult.code, + ); + + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email}, + preferred: MfaType.email, + ), + ); + + await signOutUser(assertComplete: true); + + final resignInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + + final otpResult2 = await getOtpCode(UserAttribute.email(email)); + + check(resignInRes.nextStep.signInStep) + .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + check(resignInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); + + safePrint('RESIGN IN RES: $resignInRes'); + + final confirmRes2 = await Amplify.Auth.confirmSignIn( + confirmationValue: await otpResult2.code, + ); + check(confirmRes2.nextStep.signInStep).equals(AuthSignInStep.done); + + await setUpTotp(); + + check(await cognitoPlugin.fetchMfaPreference()).equals( + const UserMfaPreference( + enabled: {MfaType.email, MfaType.totp}, + preferred: null, + ), + ); + + // await cognitoPlugin.updateMfaPreference( + // totp: MfaPreference.preferred, + // ); + + // check(setupRes.nextStep.signInStep).equals(AuthSignInStep.done); + + // sign out and sign back in and confirm TOTP + await signOutUser(assertComplete: true); + + final resignInRes2 = await Amplify.Auth.signIn( + username: username, + password: password, + ); + + safePrint('RESIGN IN RES 2: $resignInRes2'); + + check(resignInRes2.nextStep.signInStep) + .equals(AuthSignInStep.continueSignInWithMfaSelection); + + // select totp as the preferred method + final selectRes2 = await Amplify.Auth.confirmSignIn( + confirmationValue: 'TOTP', + ); + + safePrint('SELECT RES 2: $selectRes2'); + + // final sharedSecret = + // selectRes2.nextStep.totpSetupDetails!.sharedSecret; + + final confirmRes3 = await Amplify.Auth.confirmSignIn( + confirmationValue: await generateTotpCode(), + ); + + check(confirmRes3.nextStep.signInStep).equals(AuthSignInStep.done); + }, + ); + }); + }); +} From 63077c82cb916dd0ec24daa2f85ba1bd1639b562 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:35:30 -0700 Subject: [PATCH 141/159] chore: dart format and remove unused variables --- .../integration_test/mfa_email_totp_optional_test.dart | 7 ++++--- .../mfa_username_login_required_test.dart | 8 ++++---- .../lib/src/pages/email_mfa_setup_page.dart | 6 ++++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart index 799eab659c..7b4165f88f 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart @@ -392,9 +392,10 @@ void main() { ); check(signInRes.nextStep.signInStep) .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); - check(signInRes.nextStep.codeDeliveryDetails).isNotNull() - .has((d) => d.deliveryMedium, 'deliveryMedium') - .equals(DeliveryMedium.email); + check(signInRes.nextStep.codeDeliveryDetails) + .isNotNull() + .has((d) => d.deliveryMedium, 'deliveryMedium') + .equals(DeliveryMedium.email); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart index caef8fd9a9..e0229c3793 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart @@ -42,11 +42,11 @@ void main() { 'When an email is registered and the userpool has email MFA enabled, Cognito will automatically enable email MFA as the preferred MFA method.', ).equals(AuthSignInStep.continueSignInWithMfaSetupSelection); - final selectRes = await Amplify.Auth.confirmSignIn( + await Amplify.Auth.confirmSignIn( confirmationValue: 'EMAIL', ); - final setupRes = await Amplify.Auth.confirmSignIn( + await Amplify.Auth.confirmSignIn( confirmationValue: email, ); @@ -167,11 +167,11 @@ void main() { 'When both EMAIL and TOTP are enabled but email attribute isnt verified, choose an mfa method to set up.', ).equals(AuthSignInStep.continueSignInWithMfaSetupSelection); - final selectRes = await Amplify.Auth.confirmSignIn( + await Amplify.Auth.confirmSignIn( confirmationValue: 'EMAIL', ); - final setupRes = await Amplify.Auth.confirmSignIn( + await Amplify.Auth.confirmSignIn( confirmationValue: email, ); diff --git a/packages/authenticator/amplify_authenticator_test/lib/src/pages/email_mfa_setup_page.dart b/packages/authenticator/amplify_authenticator_test/lib/src/pages/email_mfa_setup_page.dart index c2d67b8d8b..546049a4b6 100644 --- a/packages/authenticator/amplify_authenticator_test/lib/src/pages/email_mfa_setup_page.dart +++ b/packages/authenticator/amplify_authenticator_test/lib/src/pages/email_mfa_setup_page.dart @@ -31,8 +31,10 @@ class EmailMfaSetupPage extends AuthenticatorPage { final currentScreen = tester.widget( find.byType(AuthenticatorScreen), ); - expect(currentScreen.step, - equals(AuthenticatorStep.continueSignInWithEmailMfaSetup),); + expect( + currentScreen.step, + equals(AuthenticatorStep.continueSignInWithEmailMfaSetup), + ); } /// When I enter an email From 3a8a1f1aec608f39de0a5ecccf3b0416ff1f8ca5 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:41:57 -0700 Subject: [PATCH 142/159] chore: remove commented code and print statements --- .../integration_test/mfa_email_optional_test.dart | 5 ----- .../integration_test/mfa_email_required_test.dart | 7 +------ .../mfa_sms_email_required_test.dart | 2 -- .../mfa_username_login_required_test.dart | 15 --------------- .../integration_test/sign_in_mfa_email_test.dart | 3 --- .../sign_in_mfa_sms_email_test.dart | 12 ------------ .../sign_in_mfa_username_login_test.dart | 1 - 7 files changed, 1 insertion(+), 44 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart index a59a121320..6a330db3c3 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart @@ -18,9 +18,6 @@ void main() { final username = env.generateUsername(); final password = generatePassword(); - safePrint('USERNAME: $username'); - safePrint('ENV USERNAME: ${env.getDefaultAttributes(username)}'); - final user = await adminCreateUser( username, password, @@ -31,8 +28,6 @@ void main() { }, ); - safePrint('USER: $user'); - final signInRes = await Amplify.Auth.signIn( username: username, password: password, diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart index 12dd54b362..f0aed4cd87 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart @@ -22,10 +22,7 @@ void main() { env.getLoginAttribute(username), ); - safePrint('USERNAME: $username'); - safePrint('ENV USERNAME: ${env.getDefaultAttributes(username)}'); - - final user = await adminCreateUser( + await adminCreateUser( username, password, autoConfirm: true, @@ -35,8 +32,6 @@ void main() { }, ); - safePrint('USER: $user'); - final signInRes = await Amplify.Auth.signIn( username: username, password: password, diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart index 9c03bef97c..074aa720d3 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart @@ -122,8 +122,6 @@ void main() { ), ); - safePrint('${await cognitoPlugin.fetchMfaPreference()}'); - await cognitoPlugin.updateMfaPreference( email: MfaPreference.preferred, ); diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart index e0229c3793..0f0c1b3540 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart @@ -204,8 +204,6 @@ void main() { .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); - safePrint('RESIGN IN RES: $resignInRes'); - final confirmRes2 = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult2.code, ); @@ -220,12 +218,6 @@ void main() { ), ); - // await cognitoPlugin.updateMfaPreference( - // totp: MfaPreference.preferred, - // ); - - // check(setupRes.nextStep.signInStep).equals(AuthSignInStep.done); - // sign out and sign back in and confirm TOTP await signOutUser(assertComplete: true); @@ -234,8 +226,6 @@ void main() { password: password, ); - safePrint('RESIGN IN RES 2: $resignInRes2'); - check(resignInRes2.nextStep.signInStep) .equals(AuthSignInStep.continueSignInWithMfaSelection); @@ -244,11 +234,6 @@ void main() { confirmationValue: 'TOTP', ); - safePrint('SELECT RES 2: $selectRes2'); - - // final sharedSecret = - // selectRes2.nextStep.totpSetupDetails!.sharedSecret; - final confirmRes3 = await Amplify.Auth.confirmSignIn( confirmationValue: await generateTotpCode(), ); diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart index 1e513dbc37..e7b80792f4 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart @@ -72,9 +72,6 @@ void main() { // Then I see the authenticated app await signInPage.expectAuthenticated(); - /// Sign out and login again with EMAIL OTP code - /// validates [AuthenticatorStep.confirmSignInWithEmailMfaCode] - // When I sign out using Auth.signOut() await Amplify.Auth.signOut(); await tester.pumpAndSettle(); diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart index 40b1db4d31..bc3f25d934 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart @@ -46,7 +46,6 @@ void main() { UnauthenticatedState.confirmSignInMfa, isA(), UnauthenticatedState.signIn, - // isA(), UnauthenticatedState.confirmSignInWithEmailMfaCode, isA(), emitsDone, @@ -81,7 +80,6 @@ void main() { await signInPage.expectAuthenticated(); // When I enable EMAIL for MFA instead of the default set up by cognito (SMS) - // await setUpTotp(); await setUpEmailMfa(); // And I sign out using Auth.signOut() @@ -143,7 +141,6 @@ void main() { UnauthenticatedState.confirmSignInMfa, isA(), UnauthenticatedState.signIn, - // isA(), UnauthenticatedState.confirmSignInMfa, isA(), emitsDone, @@ -199,18 +196,9 @@ void main() { // And I click the "Sign in" button await signInPage.submitSignIn(); - // Then I will be redirected to the MFA selection page - // await confirmSignInPage.expectConfirmSignInMfaSelectionIsPresent(); - final smsResult_2 = await getOtpCode(UserAttribute.phone(phoneNumber.toE164())); - // When I select "SMS" - // await confirmSignInPage.selectMfaMethod(mfaMethod: MfaType.sms); - - // And I click the "Confirm" button - // await confirmSignInPage.submitConfirmSignInMfaSelection(); - // Then I will be redirected to the confirm sms mfa page await confirmSignInPage.expectConfirmSignInMFAIsPresent(); diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart index e581e3e3f9..ad33d06a51 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart @@ -166,7 +166,6 @@ void main() { isA(), UnauthenticatedState.signIn, UnauthenticatedState.confirmSignInWithTotpMfaCode, - // UnauthenticatedState.confirmSignInWithEmailMfaCode, isA(), emitsDone, ]), From d5ec3c3f47d43539fd91cd5a71fa5da150254f93 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:00:57 -0700 Subject: [PATCH 143/159] chore: remove unnecessary variable assignments --- .../example/integration_test/mfa_email_optional_test.dart | 2 +- .../integration_test/mfa_username_login_required_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart index 6a330db3c3..9762aa9d58 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart @@ -18,7 +18,7 @@ void main() { final username = env.generateUsername(); final password = generatePassword(); - final user = await adminCreateUser( + await adminCreateUser( username, password, autoConfirm: true, diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart index 0f0c1b3540..d11b8363ea 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart @@ -230,7 +230,7 @@ void main() { .equals(AuthSignInStep.continueSignInWithMfaSelection); // select totp as the preferred method - final selectRes2 = await Amplify.Auth.confirmSignIn( + await Amplify.Auth.confirmSignIn( confirmationValue: 'TOTP', ); From e355d02e5955179dd0d0ba0edef5328e575a9549 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:01:26 -0700 Subject: [PATCH 144/159] chore: add invalid mfa code tests to authenticator --- .../sign_in_mfa_email_test.dart | 59 +++++++++- .../sign_in_mfa_username_login_test.dart | 103 ++++++++++-------- .../lib/src/pages/confirm_sign_in_page.dart | 6 + 3 files changed, 122 insertions(+), 46 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart index e7b80792f4..5b865ac793 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart @@ -15,8 +15,8 @@ void main() { group('sign-in-email-mfa', () { testRunner.withEnvironment(mfaRequiredEmail, (env) { - // Scenario: Sign in using a totp code - testWidgets('Setup & Sign in with EMAIL MFA', (tester) async { + // Scenario: Sign in using a valid email MFA code + testWidgets('Sign in with valid EMAIL MFA code', (tester) async { final username = env.generateUsername(); final password = generatePassword(); @@ -57,7 +57,7 @@ void main() { // And I click the "Sign in" button await signInPage.submitSignIn(); - // Then I will be redirected to the totp setup page + // Then I will be redirected to the email MFA code page await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); final otpResult = await getOtpCode( @@ -106,6 +106,59 @@ void main() { await tester.bloc.close(); }); + + // Scenario: Sign in using an invalid email MFA code + testWidgets('Sign in with invalid EMAIL MFA code', (tester) async { + final username = env.generateUsername(); + final password = generatePassword(); + + await adminCreateUser( + username, + password, + autoConfirm: true, + attributes: { + AuthUserAttributeKey.email: username, + }, + autoFillAttributes: false, + ); + + await loadAuthenticator(tester: tester); + + expect( + tester.bloc.stream, + emitsInOrder([ + UnauthenticatedState.signIn, + UnauthenticatedState.confirmSignInWithEmailMfaCode, + emitsDone, + ]), + ); + + final signInPage = SignInPage(tester: tester); + final confirmSignInPage = ConfirmSignInPage(tester: tester); + + // When I type my "username" + await signInPage.enterUsername(username); + + // And I type my password + await signInPage.enterPassword(password); + + // And I click the "Sign in" button + await signInPage.submitSignIn(); + + // Then I will be redirected to the EMAIL OTP code page + await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + + // And I type an invalid confirmation code + await confirmSignInPage.enterVerificationCode('123456'); + + // And I click the "Confirm" button + await confirmSignInPage.submitConfirmSignIn(); + + // Then I see "The code entered is not correct." + confirmSignInPage.expectInvalidVerificationCode(); + + await tester.bloc.close(); + }); }); }); } diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart index ad33d06a51..8d8c8dca06 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart @@ -39,10 +39,6 @@ void main() { UnauthenticatedState.continueSignInWithEmailMfaSetup, UnauthenticatedState.confirmSignInWithEmailMfaCode, isA(), - UnauthenticatedState.signIn, - isA(), - UnauthenticatedState.confirmSignInWithTotpMfaCode, - isA(), emitsDone, ]), ); @@ -62,7 +58,7 @@ void main() { // And I click the "Sign in" button await signInPage.submitSignIn(); - // Then I will be redirected to the confirm email mfa page + // Then I will be redirected to the MFA setup selection page await confirmSignInPage .expectContinueSignInWithMfaSetupSelectionIsPresent(); @@ -72,7 +68,7 @@ void main() { // And I click the "Confirm" button await confirmSignInPage.submitConfirmSignInMfaSetupSelection(); - // Then I will be redirected to the EMAIL mfa setup page + // Then I will be redirected to the EMAIL MFA setup page await emailMfaSetupPage.expectEmailMfaSetupIsPresent(); // When I type a valid email @@ -90,15 +86,44 @@ void main() { // Then I see the authenticated app await signInPage.expectAuthenticated(); - // When I enable TOTP for MFA instead of the default set up by cognito (EMAIL) - await setUpTotp(); + await tester.bloc.close(); + }); - // And I sign out using Auth.signOut() - await Amplify.Auth.signOut(); - await tester.pumpAndSettle(); + // Scenario: Select TOTP MFA to set up from the setup selection page + testWidgets('can select TOTP MFA to set up', (tester) async { + final username = env.generateUsername(); + final password = generatePassword(); + late String sharedSecret; + + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: false, + autoFillAttributes: false, + ); + + await loadAuthenticator(tester: tester); + + tester.bloc.stream.listen((event) { + if (event is ContinueSignInTotpSetup) { + sharedSecret = event.totpSetupDetails.sharedSecret; + } + }); + + expect( + tester.bloc.stream, + emitsInOrder([ + UnauthenticatedState.signIn, + isA(), + isA(), + isA(), + emitsDone, + ]), + ); - // Then I see the sign in page - signInPage.expectUsername(); + final signInPage = SignInPage(tester: tester); + final confirmSignInPage = ConfirmSignInPage(tester: tester); // When I type my "username" await signInPage.enterUsername(username); @@ -109,22 +134,23 @@ void main() { // And I click the "Sign in" button await signInPage.submitSignIn(); - // Then I will be redirected to the MFA selection page - await confirmSignInPage.expectConfirmSignInMfaSelectionIsPresent(); + // Then I will be redirected to the MFA setup selection page + await confirmSignInPage + .expectContinueSignInWithMfaSetupSelectionIsPresent(); // When I select "TOTP" - await confirmSignInPage.selectMfaMethod(mfaMethod: MfaType.totp); + await confirmSignInPage.selectMfaSetupMethod(mfaMethod: MfaType.totp); // And I click the "Confirm" button - await confirmSignInPage.submitConfirmSignInMfaSelection(); + await confirmSignInPage.submitConfirmSignInMfaSetupSelection(); - // Then I will be redirected to the TOTP MFA code page - await confirmSignInPage.expectConfirmSignInWithTotpMfaCodeIsPresent(); + // Then I will be redirected to the TOTP MFA setup page + await confirmSignInPage.expectSignInTotpSetupIsPresent(); - final code_2 = await generateTotpCode(); + final totpCode = await generateTotpCode(sharedSecret); // When I type a valid TOTP code - await confirmSignInPage.enterVerificationCode(code_2); + await confirmSignInPage.enterVerificationCode(totpCode); // And I click the "Confirm" button await confirmSignInPage.submitConfirmSignIn(); @@ -135,8 +161,8 @@ void main() { await tester.bloc.close(); }); - // Scenario: Sign in using a EMAIL code when both EMAIL and TOTP are enabled - testWidgets('can select TOTP MFA to set up', (tester) async { + // Scenario: Sign in using an invalid TOTP code + testWidgets('sign in with invalid TOTP code', (tester) async { final username = env.generateUsername(); final password = generatePassword(); late String sharedSecret; @@ -166,7 +192,6 @@ void main() { isA(), UnauthenticatedState.signIn, UnauthenticatedState.confirmSignInWithTotpMfaCode, - isA(), emitsDone, ]), ); @@ -183,7 +208,7 @@ void main() { // And I click the "Sign in" button await signInPage.submitSignIn(); - // Then I will be redirected to the confirm email mfa page + // Then I will be redirected to the MFA setup selection page await confirmSignInPage .expectContinueSignInWithMfaSetupSelectionIsPresent(); @@ -193,12 +218,12 @@ void main() { // And I click the "Confirm" button await confirmSignInPage.submitConfirmSignInMfaSetupSelection(); - // Then I will be redirected to the TOTP mfa setup page + // Then I will be redirected to the TOTP MFA setup page await confirmSignInPage.expectSignInTotpSetupIsPresent(); final totpCode = await generateTotpCode(sharedSecret); - // And I type a valid TOTP code + // When I type a valid TOTP code await confirmSignInPage.enterVerificationCode(totpCode); // And I click the "Confirm" button @@ -207,35 +232,27 @@ void main() { // Then I see the authenticated app await signInPage.expectAuthenticated(); - // And I sign out using Auth.signOut() + // Sign out to test invalid TOTP code during sign-in await Amplify.Auth.signOut(); await tester.pumpAndSettle(); - // Then I see the sign in page - signInPage.expectUsername(); - - // When I type my "username" + // When I attempt to sign in again await signInPage.enterUsername(username); - - // And I type my password await signInPage.enterPassword(password); - - // And I click the "Sign in" button await signInPage.submitSignIn(); // Then I will be redirected to the TOTP MFA code page - await confirmSignInPage.expectConfirmSignInWithTotpMfaCodeIsPresent(); + await confirmSignInPage + .expectConfirmSignInWithTotpMfaCodeIsPresent(); - final code_2 = await generateTotpCode(sharedSecret); - - // When I type a valid TOTP code - await confirmSignInPage.enterVerificationCode(code_2); + // When I type an invalid TOTP code + await confirmSignInPage.enterVerificationCode('000000'); // And I click the "Confirm" button await confirmSignInPage.submitConfirmSignIn(); - // Then I see the authenticated app - await signInPage.expectAuthenticated(); + // Then I see "Invalid code" error message + confirmSignInPage.expectInvalidVerificationCode(); await tester.bloc.close(); }); diff --git a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart index 90004e529f..833713a476 100644 --- a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart +++ b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart @@ -112,6 +112,12 @@ class ConfirmSignInPage extends AuthenticatorPage { expect(newPasswordField, findsOneWidget); } + /// Then I see "Invalid verification code" + @override + void expectInvalidVerificationCode() { + expectError('Invalid code'); + } + /// When I enter a verification code Future enterVerificationCode(String code) async { await tester.ensureVisible(verificationField); From 1d030463bf30889fd1b082272ebf413c7b334959 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:11:19 -0700 Subject: [PATCH 145/159] chore: dart format --- .../integration_test/sign_in_mfa_username_login_test.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart index 8d8c8dca06..032f700ed4 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart @@ -242,8 +242,7 @@ void main() { await signInPage.submitSignIn(); // Then I will be redirected to the TOTP MFA code page - await confirmSignInPage - .expectConfirmSignInWithTotpMfaCodeIsPresent(); + await confirmSignInPage.expectConfirmSignInWithTotpMfaCodeIsPresent(); // When I type an invalid TOTP code await confirmSignInPage.enterVerificationCode('000000'); From 944fc4be4844dc386969c6f2a09d243ced8c6e81 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 22 Oct 2024 22:16:12 -0700 Subject: [PATCH 146/159] chore: remove username login sms user pool from sms tests because it uses username to login and not phone number --- .../amplify_auth_integration_test/lib/src/environments.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/test/amplify_auth_integration_test/lib/src/environments.dart b/packages/test/amplify_auth_integration_test/lib/src/environments.dart index 8eab2d4814..1b2ab30f67 100644 --- a/packages/test/amplify_auth_integration_test/lib/src/environments.dart +++ b/packages/test/amplify_auth_integration_test/lib/src/environments.dart @@ -106,7 +106,7 @@ const mfaOptionalEmailTotp = EnvironmentInfo.withGen2Defaults( /// An environment with required MFA and username login. const mfaRequiredUsernameLogin = EnvironmentInfo.withGen2Defaults( name: 'username-login-mfa', - mfaInfo: MfaInfo(smsEnabled: true, totpEnabled: true, emailEnabled: true, required: true), + mfaInfo: MfaInfo(totpEnabled: true, emailEnabled: true, required: true), loginMethod: LoginMethod.username, ); From ddb8ab7464b34bdc7237d77ccdfa624d2dd351b0 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:12:56 -0700 Subject: [PATCH 147/159] chore: add tests to main_test file and make some backend changes --- .../username-login-mfa/amplify/auth/resource.ts | 2 +- .../example/integration_test/main_test.dart | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/infra-gen2/backends/auth/username-login-mfa/amplify/auth/resource.ts b/infra-gen2/backends/auth/username-login-mfa/amplify/auth/resource.ts index ebd216d43a..94d78b3d4b 100644 --- a/infra-gen2/backends/auth/username-login-mfa/amplify/auth/resource.ts +++ b/infra-gen2/backends/auth/username-login-mfa/amplify/auth/resource.ts @@ -4,7 +4,7 @@ import { defineAuth } from "@aws-amplify/backend"; export const auth = defineAuth({ - name: "mfa-required-email", + name: "mfa-username-login", loginWith: { phone: true, }, diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart index 192d73db19..e8d5fab4bd 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart @@ -15,11 +15,19 @@ import 'fetch_auth_session_test.dart' as fetch_auth_session_tests; import 'get_current_user_test.dart' as get_current_user_tests; import 'hosted_ui_webview_test.dart' as hosted_ui_webview_tests; import 'hub_events_test.dart' as hub_events_tests; +import 'mfa_email_optional_test.dart' as mfa_email_optional_tests; +import 'mfa_email_required_test.dart' as mfa_email_required_tests; +import 'mfa_email_totp_optional_test.dart' as mfa_email_totp_optional_tests; +import 'mfa_email_totp_required_test.dart' as mfa_email_totp_required_tests; +import 'mfa_sms_email_optional_test.dart' as mfa_sms_email_optional_tests; +import 'mfa_sms_email_required_test.dart' as mfa_sms_email_required_tests; import 'mfa_sms_test.dart' as mfa_sms_tests; import 'mfa_sms_totp_optional_test.dart' as mfa_sms_totp_optional_tests; import 'mfa_sms_totp_required_test.dart' as mfa_sms_totp_required_tests; import 'mfa_totp_optional_test.dart' as mfa_totp_optional_tests; import 'mfa_totp_required_test.dart' as mfa_totp_required_tests; +import 'mfa_username_login_required_test.dart' + as mfa_username_login_required_tests; import 'native_auth_bridge_test.dart' as native_auth_bridge_tests; import 'reset_password_test.dart' as reset_password_tests; import 'security_test.dart' as security_tests; @@ -47,6 +55,13 @@ void main() async { get_current_user_tests.main(); hosted_ui_webview_tests.main(); hub_events_tests.main(); + mfa_email_optional_tests.main(); + mfa_email_required_tests.main(); + mfa_sms_email_optional_tests.main(); + mfa_sms_email_required_tests.main(); + mfa_email_totp_optional_tests.main(); + mfa_email_totp_required_tests.main(); + mfa_username_login_required_tests.main(); mfa_sms_tests.main(); mfa_sms_totp_optional_tests.main(); mfa_sms_totp_required_tests.main(); From c418a33aba695210617283a9afe101055ac527c2 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:35:05 -0700 Subject: [PATCH 148/159] chore: add authenticator tests to main_test file and move getOtpCode up on some tests to get code faster --- .../example/integration_test/main_test.dart | 8 ++++++++ .../integration_test/sign_in_mfa_email_test.dart | 15 ++++++++------- .../sign_in_mfa_sms_email_test.dart | 10 +++++----- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/main_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/main_test.dart index fa1cbc1f8a..e27167580e 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/main_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/main_test.dart @@ -13,9 +13,13 @@ import 'http_test.dart' as http_tests; import 'reset_password_test.dart' as reset_password_tests; import 'sign_in_force_new_password_test.dart' as sign_in_force_new_password_tests; +import 'sign_in_mfa_email_test.dart' as sign_in_mfa_email_tests; +import 'sign_in_mfa_email_totp_test.dart' as sign_in_mfa_email_totp_tests; +import 'sign_in_mfa_sms_email_test.dart' as sign_in_mfa_sms_email_tests; import 'sign_in_mfa_sms_test.dart' as sign_in_mfa_sms_tests; import 'sign_in_mfa_sms_totp_test.dart' as sign_in_mfa_sms_totp_tests; import 'sign_in_mfa_totp_test.dart' as sign_in_mfa_totp_tests; +import 'sign_in_mfa_username_login_test.dart' as sign_in_mfa_username_login_tests; import 'sign_in_with_email_test.dart' as sign_in_with_email_tests; import 'sign_in_with_phone_test.dart' as sign_in_with_phone_tests; import 'sign_in_with_username_test.dart' as sign_in_with_username_tests; @@ -45,6 +49,10 @@ void main() { sign_in_with_email_tests.main(); sign_in_with_phone_tests.main(); sign_in_with_username_tests.main(); + sign_in_mfa_email_tests.main(); + sign_in_mfa_email_totp_tests.main(); + sign_in_mfa_sms_email_tests.main(); + sign_in_mfa_username_login_tests.main(); sign_out_tests.main(); sign_up_with_email_tests.main(); sign_up_with_email_with_lambda_trigger_tests.main(); diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart index 5b865ac793..3618170b5f 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart @@ -48,6 +48,10 @@ void main() { final signInPage = SignInPage(tester: tester); final confirmSignInPage = ConfirmSignInPage(tester: tester); + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + // When I type my "username" await signInPage.enterUsername(username); @@ -60,9 +64,6 @@ void main() { // Then I will be redirected to the email MFA code page await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); - final otpResult = await getOtpCode( - env.getLoginAttribute(username), - ); // And I type a valid EMAIL OTP code await confirmSignInPage.enterVerificationCode(await otpResult.code); @@ -76,6 +77,10 @@ void main() { await Amplify.Auth.signOut(); await tester.pumpAndSettle(); + final otpResult2 = await getOtpCode( + env.getLoginAttribute(username), + ); + // Then I see the sign in page signInPage.expectUsername(label: 'Email'); @@ -91,10 +96,6 @@ void main() { // Then I will be redirected to the EMAIL OTP code page await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); - final otpResult2 = await getOtpCode( - env.getLoginAttribute(username), - ); - // When I type a valid EMAIL OTP code await confirmSignInPage.enterVerificationCode(await otpResult2.code); diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart index bc3f25d934..d425e94eb2 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart @@ -86,6 +86,8 @@ void main() { await Amplify.Auth.signOut(); await tester.pumpAndSettle(); + final code_2 = await getOtpCode(env.getLoginAttribute(username)); + // Then I see the sign in page signInPage.expectEmail(); @@ -101,8 +103,6 @@ void main() { // Then I will be redirected to the EMAIL MFA code page await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); - final code_2 = await getOtpCode(env.getLoginAttribute(username)); - // When I type a valid EMAIL MFA code await confirmSignInPage.enterVerificationCode(await code_2.code); @@ -184,6 +184,9 @@ void main() { await Amplify.Auth.signOut(); await tester.pumpAndSettle(); + final smsResult_2 = + await getOtpCode(UserAttribute.phone(phoneNumber.toE164())); + // Then I see the sign in page signInPage.expectEmail(); @@ -196,9 +199,6 @@ void main() { // And I click the "Sign in" button await signInPage.submitSignIn(); - final smsResult_2 = - await getOtpCode(UserAttribute.phone(phoneNumber.toE164())); - // Then I will be redirected to the confirm sms mfa page await confirmSignInPage.expectConfirmSignInMFAIsPresent(); From 54155cff3cadf08040e68dccbf7dcdea98e764d7 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:36:55 -0700 Subject: [PATCH 149/159] chore: move new mfa tests to be closer to the old ones --- .../example/integration_test/main_test.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart index e8d5fab4bd..fca141ea35 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart @@ -55,18 +55,18 @@ void main() async { get_current_user_tests.main(); hosted_ui_webview_tests.main(); hub_events_tests.main(); - mfa_email_optional_tests.main(); - mfa_email_required_tests.main(); - mfa_sms_email_optional_tests.main(); - mfa_sms_email_required_tests.main(); - mfa_email_totp_optional_tests.main(); - mfa_email_totp_required_tests.main(); mfa_username_login_required_tests.main(); mfa_sms_tests.main(); mfa_sms_totp_optional_tests.main(); mfa_sms_totp_required_tests.main(); mfa_totp_optional_tests.main(); mfa_totp_required_tests.main(); + mfa_email_optional_tests.main(); + mfa_email_required_tests.main(); + mfa_sms_email_optional_tests.main(); + mfa_sms_email_required_tests.main(); + mfa_email_totp_optional_tests.main(); + mfa_email_totp_required_tests.main(); native_auth_bridge_tests.main(); reset_password_tests.main(); security_tests.main(); From ce4bd2f755b703180b7c5e3b595771f67200eb8a Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:41:34 -0700 Subject: [PATCH 150/159] chore: dart format --- .../example/integration_test/main_test.dart | 3 ++- .../amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/main_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/main_test.dart index e27167580e..2fd7c73508 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/main_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/main_test.dart @@ -19,7 +19,8 @@ import 'sign_in_mfa_sms_email_test.dart' as sign_in_mfa_sms_email_tests; import 'sign_in_mfa_sms_test.dart' as sign_in_mfa_sms_tests; import 'sign_in_mfa_sms_totp_test.dart' as sign_in_mfa_sms_totp_tests; import 'sign_in_mfa_totp_test.dart' as sign_in_mfa_totp_tests; -import 'sign_in_mfa_username_login_test.dart' as sign_in_mfa_username_login_tests; +import 'sign_in_mfa_username_login_test.dart' + as sign_in_mfa_username_login_tests; import 'sign_in_with_email_test.dart' as sign_in_with_email_tests; import 'sign_in_with_phone_test.dart' as sign_in_with_phone_tests; import 'sign_in_with_username_test.dart' as sign_in_with_username_tests; diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 353db05de4..d6b2a435c5 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -543,7 +543,8 @@ class StateMachineBloc yield* const Stream.empty(); } - Future _handleMfaSetupSelection(SignInResult result) async { + Future _handleMfaSetupSelection( + SignInResult result) async { final allowedMfaTypes = result.nextStep.allowedMfaTypes; if (allowedMfaTypes == null) { @@ -556,7 +557,8 @@ class StateMachineBloc final mfaTypesForSetup = allowedMfaTypes.toSet()..remove(MfaType.sms); if (mfaTypesForSetup.length != 1) { - return ContinueSignInWithMfaSetupSelection(allowedMfaTypes: allowedMfaTypes); + return ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: allowedMfaTypes); } final mfaType = mfaTypesForSetup.first; From 645a9717c06059c003de2eed68aabbfd0a49aa5e Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 23 Oct 2024 20:47:18 -0700 Subject: [PATCH 151/159] chore: move mfa tests to the top so that they run first (testing) --- .../example/integration_test/main_test.dart | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart index fca141ea35..4c2bcec0ba 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart @@ -44,17 +44,6 @@ void main() async { group('amplify_auth_cognito', () { asf_tests.main(); - confirm_sign_in_tests.main(); - confirm_sign_up_tests.main(); - custom_auth_tests.main(); - custom_authorizer_tests.main(); - delete_user_tests.main(); - device_tracking_tests.main(); - federated_sign_in_tests.main(); - fetch_auth_session_tests.main(); - get_current_user_tests.main(); - hosted_ui_webview_tests.main(); - hub_events_tests.main(); mfa_username_login_required_tests.main(); mfa_sms_tests.main(); mfa_sms_totp_optional_tests.main(); @@ -67,6 +56,17 @@ void main() async { mfa_sms_email_required_tests.main(); mfa_email_totp_optional_tests.main(); mfa_email_totp_required_tests.main(); + confirm_sign_in_tests.main(); + confirm_sign_up_tests.main(); + custom_auth_tests.main(); + custom_authorizer_tests.main(); + delete_user_tests.main(); + device_tracking_tests.main(); + federated_sign_in_tests.main(); + fetch_auth_session_tests.main(); + get_current_user_tests.main(); + hosted_ui_webview_tests.main(); + hub_events_tests.main(); native_auth_bridge_tests.main(); reset_password_tests.main(); security_tests.main(); From 1d50b5845161e4a8f9aa5c67e9daebff20e92dad Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 23 Oct 2024 22:28:50 -0700 Subject: [PATCH 152/159] chore: comment out non mfa tests to see if they pass chore: formatting --- .../example/integration_test/main_test.dart | 60 +++++++------------ 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart index 4c2bcec0ba..00a44eaf1d 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart @@ -4,17 +4,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'asf_test.dart' as asf_tests; -import 'confirm_sign_in_test.dart' as confirm_sign_in_tests; -import 'confirm_sign_up_test.dart' as confirm_sign_up_tests; -import 'custom_auth_test.dart' as custom_auth_tests; -import 'custom_authorizer_test.dart' as custom_authorizer_tests; -import 'delete_user_test.dart' as delete_user_tests; -import 'device_tracking_test.dart' as device_tracking_tests; -import 'federated_sign_in_test.dart' as federated_sign_in_tests; -import 'fetch_auth_session_test.dart' as fetch_auth_session_tests; -import 'get_current_user_test.dart' as get_current_user_tests; -import 'hosted_ui_webview_test.dart' as hosted_ui_webview_tests; -import 'hub_events_test.dart' as hub_events_tests; import 'mfa_email_optional_test.dart' as mfa_email_optional_tests; import 'mfa_email_required_test.dart' as mfa_email_required_tests; import 'mfa_email_totp_optional_test.dart' as mfa_email_totp_optional_tests; @@ -28,16 +17,7 @@ import 'mfa_totp_optional_test.dart' as mfa_totp_optional_tests; import 'mfa_totp_required_test.dart' as mfa_totp_required_tests; import 'mfa_username_login_required_test.dart' as mfa_username_login_required_tests; -import 'native_auth_bridge_test.dart' as native_auth_bridge_tests; -import 'reset_password_test.dart' as reset_password_tests; -import 'security_test.dart' as security_tests; -import 'sign_in_test.dart' as sign_in_tests; -import 'sign_out_test.dart' as sign_out_tests; -import 'sign_up_test.dart' as sign_up_tests; import 'test_runner.dart'; -import 'update_password_test.dart' as update_password_tests; -import 'user_attributes_test.dart' as user_attributes_tests; -import 'version_upgrade_test.dart' as version_upgrade_tests; void main() async { testRunner.setupTests(); @@ -56,25 +36,25 @@ void main() async { mfa_sms_email_required_tests.main(); mfa_email_totp_optional_tests.main(); mfa_email_totp_required_tests.main(); - confirm_sign_in_tests.main(); - confirm_sign_up_tests.main(); - custom_auth_tests.main(); - custom_authorizer_tests.main(); - delete_user_tests.main(); - device_tracking_tests.main(); - federated_sign_in_tests.main(); - fetch_auth_session_tests.main(); - get_current_user_tests.main(); - hosted_ui_webview_tests.main(); - hub_events_tests.main(); - native_auth_bridge_tests.main(); - reset_password_tests.main(); - security_tests.main(); - sign_in_tests.main(); - sign_out_tests.main(); - sign_up_tests.main(); - update_password_tests.main(); - user_attributes_tests.main(); - version_upgrade_tests.main(); + // confirm_sign_in_tests.main(); + // confirm_sign_up_tests.main(); + // custom_auth_tests.main(); + // custom_authorizer_tests.main(); + // delete_user_tests.main(); + // device_tracking_tests.main(); + // federated_sign_in_tests.main(); + // fetch_auth_session_tests.main(); + // get_current_user_tests.main(); + // hosted_ui_webview_tests.main(); + // hub_events_tests.main(); + // native_auth_bridge_tests.main(); + // reset_password_tests.main(); + // security_tests.main(); + // sign_in_tests.main(); + // sign_out_tests.main(); + // sign_up_tests.main(); + // update_password_tests.main(); + // user_attributes_tests.main(); + // version_upgrade_tests.main(); }); } From 0672db3dd8a992752c3bed598d06f0153f8f6b68 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:59:33 -0700 Subject: [PATCH 153/159] Revert "chore: comment out non mfa tests to see if they pass" This reverts commit 1d50b5845161e4a8f9aa5c67e9daebff20e92dad. --- .../example/integration_test/main_test.dart | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart index 00a44eaf1d..4c2bcec0ba 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/main_test.dart @@ -4,6 +4,17 @@ import 'package:flutter_test/flutter_test.dart'; import 'asf_test.dart' as asf_tests; +import 'confirm_sign_in_test.dart' as confirm_sign_in_tests; +import 'confirm_sign_up_test.dart' as confirm_sign_up_tests; +import 'custom_auth_test.dart' as custom_auth_tests; +import 'custom_authorizer_test.dart' as custom_authorizer_tests; +import 'delete_user_test.dart' as delete_user_tests; +import 'device_tracking_test.dart' as device_tracking_tests; +import 'federated_sign_in_test.dart' as federated_sign_in_tests; +import 'fetch_auth_session_test.dart' as fetch_auth_session_tests; +import 'get_current_user_test.dart' as get_current_user_tests; +import 'hosted_ui_webview_test.dart' as hosted_ui_webview_tests; +import 'hub_events_test.dart' as hub_events_tests; import 'mfa_email_optional_test.dart' as mfa_email_optional_tests; import 'mfa_email_required_test.dart' as mfa_email_required_tests; import 'mfa_email_totp_optional_test.dart' as mfa_email_totp_optional_tests; @@ -17,7 +28,16 @@ import 'mfa_totp_optional_test.dart' as mfa_totp_optional_tests; import 'mfa_totp_required_test.dart' as mfa_totp_required_tests; import 'mfa_username_login_required_test.dart' as mfa_username_login_required_tests; +import 'native_auth_bridge_test.dart' as native_auth_bridge_tests; +import 'reset_password_test.dart' as reset_password_tests; +import 'security_test.dart' as security_tests; +import 'sign_in_test.dart' as sign_in_tests; +import 'sign_out_test.dart' as sign_out_tests; +import 'sign_up_test.dart' as sign_up_tests; import 'test_runner.dart'; +import 'update_password_test.dart' as update_password_tests; +import 'user_attributes_test.dart' as user_attributes_tests; +import 'version_upgrade_test.dart' as version_upgrade_tests; void main() async { testRunner.setupTests(); @@ -36,25 +56,25 @@ void main() async { mfa_sms_email_required_tests.main(); mfa_email_totp_optional_tests.main(); mfa_email_totp_required_tests.main(); - // confirm_sign_in_tests.main(); - // confirm_sign_up_tests.main(); - // custom_auth_tests.main(); - // custom_authorizer_tests.main(); - // delete_user_tests.main(); - // device_tracking_tests.main(); - // federated_sign_in_tests.main(); - // fetch_auth_session_tests.main(); - // get_current_user_tests.main(); - // hosted_ui_webview_tests.main(); - // hub_events_tests.main(); - // native_auth_bridge_tests.main(); - // reset_password_tests.main(); - // security_tests.main(); - // sign_in_tests.main(); - // sign_out_tests.main(); - // sign_up_tests.main(); - // update_password_tests.main(); - // user_attributes_tests.main(); - // version_upgrade_tests.main(); + confirm_sign_in_tests.main(); + confirm_sign_up_tests.main(); + custom_auth_tests.main(); + custom_authorizer_tests.main(); + delete_user_tests.main(); + device_tracking_tests.main(); + federated_sign_in_tests.main(); + fetch_auth_session_tests.main(); + get_current_user_tests.main(); + hosted_ui_webview_tests.main(); + hub_events_tests.main(); + native_auth_bridge_tests.main(); + reset_password_tests.main(); + security_tests.main(); + sign_in_tests.main(); + sign_out_tests.main(); + sign_up_tests.main(); + update_password_tests.main(); + user_attributes_tests.main(); + version_upgrade_tests.main(); }); } From c4bfbba8b750372e95899c7ad9a888af8600c226 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 24 Oct 2024 00:41:50 -0700 Subject: [PATCH 154/159] chore: trim down on overlapping tests and moved getOtpCode earlier in files --- .../mfa_email_totp_optional_test.dart | 3 +- .../mfa_email_totp_required_test.dart | 12 +- .../mfa_sms_email_optional_test.dart | 50 +------ .../mfa_sms_email_required_test.dart | 133 ++++++------------ .../mfa_username_login_required_test.dart | 7 +- 5 files changed, 62 insertions(+), 143 deletions(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart index 7b4165f88f..97f46ff4b8 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart @@ -337,6 +337,8 @@ void main() { await signOutUser(assertComplete: true); + final otpResult = await getOtpCode(UserAttribute.email(username)); + final resignInRes = await Amplify.Auth.signIn( username: username, password: password, @@ -347,7 +349,6 @@ void main() { .isNotNull() .deepEquals({MfaType.email, MfaType.totp}); - final otpResult = await getOtpCode(UserAttribute.email(username)); final selectRes = await Amplify.Auth.confirmSignIn( confirmationValue: 'EMAIL', ); diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart index 6cfbf60cc8..514cc9c53e 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart @@ -18,6 +18,8 @@ void main() { final username = env.generateUsername(); final password = generatePassword(); + final otpResult = await getOtpCode(UserAttribute.email(username)); + // Create a user with no phone number. await adminCreateUser( username, @@ -37,7 +39,6 @@ void main() { 'When an email is registered and the userpool has email MFA enabled, Cognito will automatically enable email MFA as the preferred MFA method.', ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); - final otpResult = await getOtpCode(UserAttribute.email(username)); final setupRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, ); @@ -52,6 +53,8 @@ void main() { await signOutUser(assertComplete: true); + final otpResult2 = await getOtpCode(UserAttribute.email(username)); + final resignInRes = await Amplify.Auth.signIn( username: username, password: password, @@ -63,7 +66,6 @@ void main() { .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); - final otpResult2 = await getOtpCode(UserAttribute.email(username)); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult2.code, ); @@ -74,6 +76,8 @@ void main() { final username = env.generateUsername(); final password = generatePassword(); + final otpResult = await getOtpCode(UserAttribute.email(username)); + // Create a user with an unverified phone number. await adminCreateUser( username, @@ -96,7 +100,6 @@ void main() { 'MFA is required so Cognito automatically enables EMAIL MFA', ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); - final otpResult = await getOtpCode(UserAttribute.email(username)); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, ); @@ -212,6 +215,8 @@ void main() { { await signOutUser(assertComplete: true); + final otpResult = await getOtpCode(UserAttribute.email(username)); + final signInRes = await Amplify.Auth.signIn( username: username, password: password, @@ -225,7 +230,6 @@ void main() { .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); - final otpResult = await getOtpCode(UserAttribute.email(username)); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, ); diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart index 26b23ae056..ec45284a6a 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart @@ -174,45 +174,6 @@ void main() { ), ); - // Verify we can set EMAIL as preferred and forego selection. - - await cognitoPlugin.updateMfaPreference( - email: MfaPreference.preferred, - ); - check( - await cognitoPlugin.fetchMfaPreference(), - because: 'EMAIL should be marked preferred', - ).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: MfaType.email, - ), - ); - - { - await signOutUser(assertComplete: true); - - final signInRes = await Amplify.Auth.signIn( - username: username, - password: password, - ); - check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); - check(signInRes.nextStep.codeDeliveryDetails) - .isNotNull() - .has((d) => d.deliveryMedium, 'deliveryMedium') - .equals(DeliveryMedium.email); - - final otpResult2 = await getOtpCode( - env.getLoginAttribute(username), - ); - - final confirmRes = await Amplify.Auth.confirmSignIn( - confirmationValue: await otpResult2.code, - ); - check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); - } - // Verify we can switch to SMS as preferred. await cognitoPlugin.updateMfaPreference( @@ -334,6 +295,8 @@ void main() { await signOutUser(assertComplete: true); + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + final resignInRes = await Amplify.Auth.signIn( username: username, password: password, @@ -347,7 +310,6 @@ void main() { .isNotNull() .startsWith('+'); - final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await mfaCode.code, ); @@ -414,15 +376,15 @@ void main() { { await signOutUser(assertComplete: true); + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + final signInRes = await Amplify.Auth.signIn( username: username, password: password, ); - final otpResult = await getOtpCode( - env.getLoginAttribute(username), - ); - check(signInRes.nextStep.signInStep) .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); check(signInRes.nextStep.codeDeliveryDetails) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart index 074aa720d3..0aa4871021 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart @@ -57,6 +57,12 @@ void main() { await signOutUser(assertComplete: true); + // Verify we can sign in with EMAIL MFA as the preferred method and forego selection. + + final otpResult2 = await getOtpCode( + env.getLoginAttribute(username), + ); + final resignInRes = await Amplify.Auth.signIn( username: username, password: password, @@ -68,10 +74,6 @@ void main() { .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); - final otpResult2 = await getOtpCode( - env.getLoginAttribute(username), - ); - final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult2.code, ); @@ -83,6 +85,8 @@ void main() { final password = generatePassword(); final phoneNumber = generatePhoneNumber(); + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + // Verify we can set EMAIL as preferred and forego selection. await adminCreateUser( username, @@ -95,22 +99,19 @@ void main() { }, ); - { - final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); - final signInRes = await Amplify.Auth.signIn( - username: username, - password: password, - ); - check( - signInRes.nextStep.signInStep, - because: 'MFA is required so Cognito automatically enables SMS MFA', - ).equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is required so Cognito automatically enables SMS MFA', + ).equals(AuthSignInStep.confirmSignInWithSmsMfaCode); - final confirmRes = await Amplify.Auth.confirmSignIn( - confirmationValue: await mfaCode.code, - ); - check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); - } + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); check( await cognitoPlugin.fetchMfaPreference(), @@ -136,6 +137,9 @@ void main() { await signOutUser(assertComplete: true); { + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); final resignInRes = await Amplify.Auth.signIn( username: username, password: password, @@ -149,10 +153,6 @@ void main() { .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); - final otpResult = await getOtpCode( - env.getLoginAttribute(username), - ); - final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, ); @@ -166,43 +166,6 @@ void main() { ), ); - // Verify we can switch to SMS as preferred. - - await cognitoPlugin.updateMfaPreference( - sms: MfaPreference.preferred, - ); - check(await cognitoPlugin.fetchMfaPreference()).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: MfaType.sms, - ), - ); - - { - await signOutUser(assertComplete: true); - - final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); - final signInRes = await Amplify.Auth.signIn( - username: username, - password: password, - ); - check( - signInRes.nextStep.signInStep, - because: 'Preference is SMS MFA now', - ).equals(AuthSignInStep.confirmSignInWithSmsMfaCode); - check(signInRes.nextStep.codeDeliveryDetails).isNotNull() - ..has((d) => d.deliveryMedium, 'deliveryMedium') - .equals(DeliveryMedium.sms) - ..has((d) => d.destination, 'destination') - .isNotNull() - .startsWith('+'); - - final confirmRes = await Amplify.Auth.confirmSignIn( - confirmationValue: await mfaCode.code, - ); - check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); - } - // Verify marking enabled does not change preference. await cognitoPlugin.updateMfaPreference( sms: MfaPreference.enabled, @@ -214,7 +177,7 @@ void main() { ).equals( const UserMfaPreference( enabled: {MfaType.sms, MfaType.email}, - preferred: MfaType.sms, + preferred: MfaType.email, ), ); @@ -246,6 +209,8 @@ void main() { final password = generatePassword(); final phoneNumber = generatePhoneNumber(); + final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); + // Create a user with an unverified phone number. await adminCreateUser( username, @@ -258,22 +223,19 @@ void main() { }, ); - { - final mfaCode = await getOtpCode(UserAttribute.phone(phoneNumber)); - final signInRes = await Amplify.Auth.signIn( - username: username, - password: password, - ); - check( - signInRes.nextStep.signInStep, - because: 'MFA is required so Cognito automatically enables SMS MFA', - ).equals(AuthSignInStep.confirmSignInWithSmsMfaCode); + final signInRes = await Amplify.Auth.signIn( + username: username, + password: password, + ); + check( + signInRes.nextStep.signInStep, + because: 'MFA is required so Cognito automatically enables SMS MFA', + ).equals(AuthSignInStep.confirmSignInWithSmsMfaCode); - final confirmRes = await Amplify.Auth.confirmSignIn( - confirmationValue: await mfaCode.code, - ); - check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); - } + final confirmRes = await Amplify.Auth.confirmSignIn( + confirmationValue: await mfaCode.code, + ); + check(confirmRes.nextStep.signInStep).equals(AuthSignInStep.done); check( await cognitoPlugin.fetchMfaPreference(), @@ -287,17 +249,6 @@ void main() { // Verify we can set SMS as preferred and forego selection. - await cognitoPlugin.updateMfaPreference( - sms: MfaPreference.preferred, - email: MfaPreference.enabled, - ); - check(await cognitoPlugin.fetchMfaPreference()).equals( - const UserMfaPreference( - enabled: {MfaType.sms, MfaType.email}, - preferred: MfaType.sms, - ), - ); - { await signOutUser(assertComplete: true); @@ -338,6 +289,10 @@ void main() { { await signOutUser(assertComplete: true); + final otpResult = await getOtpCode( + env.getLoginAttribute(username), + ); + final signInRes = await Amplify.Auth.signIn( username: username, password: password, @@ -351,10 +306,6 @@ void main() { .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); - final otpResult = await getOtpCode( - env.getLoginAttribute(username), - ); - final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, ); diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart index d11b8363ea..7ad5291dd3 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart @@ -65,6 +65,8 @@ void main() { await signOutUser(assertComplete: true); + final otpResult2 = await getOtpCode(UserAttribute.email(email)); + final resignInRes = await Amplify.Auth.signIn( username: username, password: password, @@ -76,7 +78,6 @@ void main() { .has((d) => d.deliveryMedium, 'deliveryMedium') .equals(DeliveryMedium.email); - final otpResult2 = await getOtpCode(UserAttribute.email(email)); final confirmRes2 = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult2.code, ); @@ -190,13 +191,13 @@ void main() { await signOutUser(assertComplete: true); + final otpResult2 = await getOtpCode(UserAttribute.email(email)); + final resignInRes = await Amplify.Auth.signIn( username: username, password: password, ); - final otpResult2 = await getOtpCode(UserAttribute.email(email)); - check(resignInRes.nextStep.signInStep) .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); check(resignInRes.nextStep.codeDeliveryDetails) From b5f6dcbe7b72f503678871141636b3ae6d15a1dd Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 24 Oct 2024 00:56:28 -0700 Subject: [PATCH 155/159] chore: dart format --- .../integration_test/mfa_username_login_required_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart index 7ad5291dd3..edbb8ce43f 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart @@ -192,7 +192,7 @@ void main() { await signOutUser(assertComplete: true); final otpResult2 = await getOtpCode(UserAttribute.email(email)); - + final resignInRes = await Amplify.Auth.signIn( username: username, password: password, From c9a64246e93fdcc3e3ed3dd949e2d05623947ba8 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:01:50 -0700 Subject: [PATCH 156/159] chore: dart format --- .../amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart | 4 ++-- .../amplify_authenticator/lib/src/widgets/form.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index d6b2a435c5..4b07f8fd51 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -544,7 +544,7 @@ class StateMachineBloc } Future _handleMfaSetupSelection( - SignInResult result) async { + SignInResult result,) async { final allowedMfaTypes = result.nextStep.allowedMfaTypes; if (allowedMfaTypes == null) { @@ -558,7 +558,7 @@ class StateMachineBloc if (mfaTypesForSetup.length != 1) { return ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: allowedMfaTypes); + allowedMfaTypes: allowedMfaTypes,); } final mfaType = mfaTypesForSetup.first; diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart index b8a7bd15b1..abad5f4369 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form.dart @@ -679,7 +679,7 @@ class ContinueSignInWithEmailMfaSetupForm extends AuthenticatorForm { super.key, }) : super._( fields: [ - EmailSetupFormField.email(), + const EmailSetupFormField.email(), ], actions: const [ ContinueSignInWithEmailMfaSetupButton(), From a19b523ab7695d8395769456474dd3bc97348289 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:03:11 -0700 Subject: [PATCH 157/159] chore: dart format --- .../amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 4b07f8fd51..446182fc3f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -544,7 +544,8 @@ class StateMachineBloc } Future _handleMfaSetupSelection( - SignInResult result,) async { + SignInResult result, + ) async { final allowedMfaTypes = result.nextStep.allowedMfaTypes; if (allowedMfaTypes == null) { @@ -558,7 +559,8 @@ class StateMachineBloc if (mfaTypesForSetup.length != 1) { return ContinueSignInWithMfaSetupSelection( - allowedMfaTypes: allowedMfaTypes,); + allowedMfaTypes: allowedMfaTypes, + ); } final mfaType = mfaTypesForSetup.first; From e63b865c22d8063342676fe2db38ad4be0a166e5 Mon Sep 17 00:00:00 2001 From: Tyler-Larkin Date: Thu, 24 Oct 2024 15:41:18 -0700 Subject: [PATCH 158/159] Feat(authenticator) email otp tests goldens (#5603) * chore(authenticator): Added Emil MFA to Mock Authenticator * chore(authenticator): Updated goldens images. * chore(authenticator): Added missing const --- ...MaterialTheme_darkMode_desktopGeometry.png | Bin 0 -> 34005 bytes ...tMaterialTheme_darkMode_mobileGeometry.png | Bin 0 -> 58071 bytes ...aterialTheme_lightMode_desktopGeometry.png | Bin 0 -> 34003 bytes ...MaterialTheme_lightMode_mobileGeometry.png | Bin 0 -> 57639 bytes ...MaterialTheme_darkMode_desktopGeometry.png | Bin 0 -> 32618 bytes ...tMaterialTheme_darkMode_mobileGeometry.png | Bin 0 -> 55060 bytes ...aterialTheme_lightMode_desktopGeometry.png | Bin 0 -> 32600 bytes ...MaterialTheme_lightMode_mobileGeometry.png | Bin 0 -> 54658 bytes ...MaterialTheme_darkMode_desktopGeometry.png | Bin 44198 -> 45703 bytes ...tMaterialTheme_darkMode_mobileGeometry.png | Bin 85053 -> 89299 bytes ...aterialTheme_lightMode_desktopGeometry.png | Bin 44155 -> 45625 bytes ...MaterialTheme_lightMode_mobileGeometry.png | Bin 84738 -> 88938 bytes ...MaterialTheme_darkMode_desktopGeometry.png | Bin 0 -> 45076 bytes ...tMaterialTheme_darkMode_mobileGeometry.png | Bin 0 -> 83913 bytes ...aterialTheme_lightMode_desktopGeometry.png | Bin 0 -> 44850 bytes ...MaterialTheme_lightMode_mobileGeometry.png | Bin 0 -> 83630 bytes .../lib/src/mock_authenticator_app.dart | 11 +++++++++++ 17 files changed, 11 insertions(+) create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_desktopGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_mobileGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_desktopGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_mobileGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_darkMode_desktopGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_darkMode_mobileGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_lightMode_desktopGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_lightMode_mobileGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_darkMode_desktopGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_darkMode_mobileGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_lightMode_desktopGeometry.png create mode 100644 packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_lightMode_mobileGeometry.png diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_desktopGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..a6420c3365c52b8b30b920b4d9b1146e9b04dcfc GIT binary patch literal 34005 zcmeIbd010PyDu8ssoRO}c4}qPHj2umARx20tr!(hPzD*IA|PXgFbE-pt)I|}f(9Wn zMnyp8$$&9HP?RZiye)yAO9}Hj;=cL@A8j2upj=uIPzfG z&wrO;H`hh|yZrOjr7o5x3JC3zL@ntBunJ2C1h!;pVX!5C0UY;|V}&ij0~l-x9xTBF z2rn?EWrcF94x^D*b+Pda?fB_m+;AaDVO|G3yp&bQt5%#U( zRF+NiU|{p0iq{LLee2crvMtCKq1J1`w`L6%Jt5mxS$RBJkD@oOEd12om6l|NwME(! zRZPR5pD%M<1{2^qymyZ)D|?}c1Vglk=iEJe8)l}NX{zM8g~HAqprvo@Ul!b`Ah{cT zQONQ^w^2e*hfj~C+vK+Q+5QlfWw$>OG--u(!KQ3awJo&MMces!ytHaPrLLDn&b1G< z{$*i2=eBp@{;CcJ<*30to7}7QEnd0B`POpTa@&eesxb8@r%3o*+nnds)uz=L(KN>x z)VxF%_N-nw=VhmC)6L29L^IYY9dKB;taeSl^M23IQE$Awz3KNly>jd2I0aBs0~y)B z0Xp03dRkc@t2;H^MnQ#IuY|ETYGUU+vZ51p(A+7029(e&xw&!S$!M)UerVhMyO+Sj{|po|M*lEer_(BpRo!Sln)B$ z_bd0At_L+Pt=#?Z8oRP=z*v{T`tr{2&&sqJ=6it(F!jC5c7Rif^ZEP>pd_CGl9UIP zz`ckcm(>0Li@NV4(1v?HRZ?=^1b*o1dhCQE>s3l8D|}zQiS9F9NNux^2ltsSWUtvQ zL(lXCOMUi$UxSoe#2I*(U=?A_eRnsjs7Nc69qGA!L@{v2(359jF#m#*^N#WY+}G69 zMBrsoNvJ3YtPkwQR>y_R_GfI7HPLMNV`f8-Y`86lp@ZyiFHTQMjSRPqGo9-S4dz!- zHTY)5FF&2~dVxBLzc*X^mw(E_fJ$B#EJ)zlp9^)J$|X6W$gzp;a!+j`*`nCMNL|6z zaP;0q&t%3M3Fj+cSm0P5I8TUYuzU*B^NYxNJzPj9VH(Qn3+l7!Pm)b*d#>$Pi6_68 z9E(LA!`4wMrae8*zCZ!aU|}zSTqd>E(iRsdMi-dCgM(>2`7!0gmp%s?3jP=jG|Vq3 zYqqJ*$<5toikWd9@ma58a^p^e*0`y|uc0z7-8o|TeX_16-6>A-(6tX&;z=)GYD`r7 zgJ%-3s|n#5sLu9wNDVb7X5ZXetvwOS{P3aV9m9d_On;CVqtSs4%NIoyt2t1sOUk_ znsU<8fW{H~zLl?2I$W~F@4hQ4h+jR*K9h22U%yBRY0N9RTo*V-h-+P?==&hMKKp!r z#~I>5Q#IW9K(D-3>QZFtR)4P-!>R7(+V(sLD=T7$qT-CWFSO9r;`-FKVkFgMddjxj zQ;s!KmJFzwB^O5y<|FWRafdY&%%(2kuhLp8TV#@P;xDSdJ)E1HJD)GCYiyH=UP6tg z(0~zpsgU=jh&ln zY9v`?pWi>&-e%p(K*_{csKV&E=m_yUZQe0O?B3<8)}6$^B#{Q=aWc0!W7(^htv>np zUC^^Bc&vC$%+ z>m5A@vQtr~@V&D9o;I*#Yqeh==<%btbUI+~KcWqu-=BCU!^ALVUbHjW6ca+1a>*pg zLwI3fp_t``r1gn<``oo8Z1xGctu$5nRD%+>_oEjIg`+V_zlp;y ze_BhH#`TmlGcZ}Dr3Vo@p8PatY-~3tV07 zQ%3tJp(7(BpDMFZ(hJ~p=?O39rWJae!!MEe;#TG%ry8H z9Ublax+$AH$aOM$e|atMyuCd^U7MEu|&+yJQs=7Zc?! z)t4{SaJgJC_Q7v;8yG2d%!2exXDv@4_T(7}lUuLKaiFN8(gevl#N?go3d2FI$2J(j zp`k~wS4`6Q(PngXRM$TtfIO^bP(A3`sF+dQVee$Rnvc7*T~QGrngqDzeM@n#r#WF` zoaxgxOx)qIzapfMiakHq{s(0JhlU=TH@H@#-v+2%rN~)DZL>luHgcv58*ep%%st=y zO)r{9$em?>a76m#y^r_9rn17z#hZPms;)JN@1KPp_Zuo~={Vo@9Ku5Ti9| z>gVStZk9*v?l;rdQp*Us!eViYf2*hqF@_^5`T~0HNxEKD9T>h1Z_31B4ndWS@8eAO zQn(W4b1(!yAxr1W=byTR$}P*K^d8T-so|!Zn;W)-j;j~H*4elr<3U?ZBF4wFQBa0*^G z=bfHUuSp~zBMo^Gk~F1R@^bX(c%@cIZ?|V!`Y*dqz!5dLX;JyGN2*6#tA6XCy>o`f zkF8cxYL3=qHE=dtT>{UU$(rIlr<{J88g-nl6YC8FxqIx0dtR z815Gf6{{^PZnn0zhRr^VDQB8t+*8LZo8tXv&z0@)n4jNCEUw0lTKlIjpE2Hn2xRt! zx`v)m5^>fg753@Y{SVHyL3_PDtOZuIrheQ+A%v7{QY|0M{se2o4hfnLV8}m zC$Ky%^i5dPO-bW_x9$NdR# zhKb}%1uHy1;;JxyprxGAQWYk&*`FBLDbKi|NPWrZ_)FnlBRADA1D>qoekx=;)mFdH zw@oRyV}fyQEUrd*DTZ$&EpHlR}Z? zsET-W7XsgupvL=3@jEa94Zx&-8dw;fS893MI_jQc}mHmW1t2^1LLPplE-L z0IEFGg^6c{R6#%>&Sa$V>d_mAzm#vp!|S3q&=RaolN(fU8VwoOeKT-h#PFu&RLl<1 z{7lBxH+eVL7LvK6`4Z_+w5mHRzwMKLv8Fu|6D*tJnY+)7bpr@#;diDuLug+(PrHR{ zYGatB!^uGYC#CsRBEW??SoWyXc7c9mB{0J;D=R&T(wU}~WL?|b^MQ5Ns77o5`KEdD z%a`qTmz-HV@5?JL7TT5bJZD;-BNA*t9RXIvE!nlfX+ZRsn`KW|T1V zrKE$avHT~yUoXVELGiD5{|0fqwUQ&Gi>)n=x?97>$h?fv$%_^i7An%7%yd_ZB!g1^ zp6dkcV%F2APq%n$(mhmr3TA}hiJw&LN8(Lnv;Cy;a~5$*$;N`$y4e|9CR5*z zd8IPNhT(I`IgmbB^%xcF`;y>I@9u0g#zt%W_@UnaPz5ciA{I=&cfP9D)aPRg9>C0c zd3ojDj)9bWrW;3uBN!Q`J`4-!uhYC%FV_$u`_^FIUc=DFemU(m+=eGg=RLjr{92#J zgtA?Y5PPU5h7juS*WX5Ps|h+&Bz;2)lilW_C$hFO?ev|mRR=Rq<4xup>s)Gzg;aE; z4ob&W21(und7LHuMfK!YERBLEW1P?m5al z)Nu-rkKulzX}8AINA5*TQaJJ=egB~k;vOZrkSKQ^2!r~*CuSU62!t5!UVf$BTbgbj z77`i3>CCC&wl;u(fIq!D^*WQXA_`UU;v~w8e-w+w<`mxAnm2lmP|@tvka0Rc^V2~& zQCZm~j#OD0I)|awNWI_mtr|r=plOpM9`c+IdpKIA>H`F*N!q+|tE;3ym)^YE0#{-? zR=Ib4eB4lQQy4gVIR=VlVpKzJY%m}Db|&3Oud*+|N$d5%Gpox(2&Cyg9uX4>B0Zf* z!o)TzZMG%ZSWUs?+mRY!pCBlFkKMMiQ}_Wfk0=Q2tEi|*6OJ>FQTsyrG##6Hd0B$_ z83{d>zZKXzhjliCXIPY9{-)hpp+xp{459c6qd#Q^M&^#~H-rwl_XqnWNs;2AF;xP8=_{vylI;wDs%!We& zPd4p*;@)o$4bj}H{*Kk0W=jLkqg#8F9z8u4!;O+|IEin`Fr~EVzisn8!>C=hyu5jT zzQ&}|TKk<5Va+s`xazjV!7ZL&&G+nC`?Ux{)gx2(#>yyf@4VZwYb$kJFP_FIxJGz& zyR{4s=H_JNN$2}wsi~^Y@>_#}>5*8;ZiH)Om`t|>0IRF-{`v)h-xY6E)^-<98GA|l zeR(ZB?CTx1z?O*yIAWE8N*aSN?;d;EZv|F~-Xuo{`Z;~kaJVlhK&2&?*96$5q@RhUgTIUix)Ds!!9#)jic$`sRU%zhqp=)<)^6$i3 z7D!DZ851rQ=b>HwPkw7YeE=#%;WnaNO$CCD@(eiCVZAE*6>auEmaozZxISf9RLy6B z&<3~xUujce0z6bc!?$wFz|M5To90xV&4HgzkJD>6xY~k?L*UP(&4zcivk&4(wYM9# z>?hDplbTsy=Lg?V+at~9OX?^}xPBkhJw{UfJ@lQ$93z z^$prE;=Z_Ft@`jjMA?^BiXq98Bq!fwiGXY_;-GP>HvIPL45Q<1;#{XwX!W7?&<(Ek zF76##yc_*`8%$?EXf=Qs5(s%2ZFE84sEY#kqVTc4?@)}|Q}(=K?+W^hU~jabBi~+&GF!%yaP9y?mHRYC^%UM$ zg6#1~wf3_$t^h8$nQqKagNFex!wDJv`aaA+@CNWam@m=97OHk#^mCs@Ut=wZHV0jrhe?0Ut$3&7!LMtHMZq!7~6Ku5zx|zWz zva595lQZ%m|AdFw6#`JfaZb$B{0*(|x4QNY8b^o+2|nlglH4!@) z1)<6bOq{iolN0^$=)JV5!31cLfWt5Wkl_^YF@8>c_O4-B6<=A#0aArx1_Eie4>1XB z1_TU4jbso!`(!l^mwFqExlDB|0ZE!iezs(#9x0wo&jxY zQ3oag7c*LB#4-;4YH!tIjhgj>*h3IY@?N>cozBZGv^fk29;E|cqTJ2olrV)Yp+wGF zp38OD3fa5PZHKO%H7o5Bv#uA* z=t~A}13yqt?0fvvYO9lA02MtU6iBM}#5ybsXnA~)JYC_0ZnHFSf4gksC%|NlRgC&~ z2lHG2ahEm)*be=ff#UQujT%8bQID_oV=u9pg?kKk(pEsurdy>X6 zs^POwS+js7g^PN_tXVA9r{3N)jlWh>Ct6YMMdct!fe^of>HJw}86aMPDs4qU;ZkL< zY;LGOo*rK;2>={KV9U9Nfp5nYtO0l&7gkhOGXH@1cNm+vNPm7avj;HBoNy}Zz0C1d z*7#dLRDOpy0ewN;1$i3p6d86p+nPwd=<4F)vTB2pgK>yZ(}4Gcp?ZF8a`?7;t&FZ#geQ`a5r46d5 zNf#|`-E4uuhah~sZ2aR`HHQsRqod3lb<(jHK^ikvD5c6nqR)j@9az`)v@MYa0L<{n z-yFmHO(+r3arB0eF87$;5Q!fY*8t829DvUO02JNql`}BnQykgDD7kJ1F_UFG?r9Qe zxpw*D!Q#kdH|xU{`h0-rASh3J>D7ien3w2cX2zgrBn4!ih&zP`0!iCoEO=lpA7lVl z2uTDUd(ET^lH0E@HAn2hLe=Q&gR8ot~D47PCQ?1&l*Hold21^CW)sVq2&L zUoEN{X$BLUQ&d#6MGm1YC|>rj9`9szWnqi(17HOnQ3Pa4MS94wW5+;bR8%uF!or64 zOH&Sc*;H`CBqkH@HiB_``TCv#7#J`(!cPN)$z-Y7V&>!qQGNZG`PE^ZB9toork{NV zdoX{!GP|$s(mt?0kVF9@x~1RR#C7d^_KT-acd9B$-vAsp?cz8sxF217(1eM^VDVQa z>6OKWUn>q{o#s3S8XrO=fo>?jw^GT;-rl~)NCZUVbxY4gO*&ZnV5Xx1nn!O1p&FQ$ z2`j-Hd@oP*7Es1IR|j`OU-enm*JC)+m|51q$3ST?)$aLSB!Tf-{-_hAttTQb{h4v& z>m49I&A+;!hVqV;v%K>MlRYz%0JH~>tXEtQaQWB82CtnMm4akdzMQS{!S0=ShfSqOo{W4Fvp8b z7qm;KQjLde%DhcTS6B=`V}sxrY6I-)-W5@xQthM-vu`6Pz&>-B5LObHNj%0*xRnEc zodC~?l(zFTwm=^r*}3Qqhx8TwUY?uj@{4D21l0oeyi9>A=rml&k8HZVkZh0g7mk%P zxI~6j7a+LCU?!5#!+!;maqlEuD1pQeLPhpSENL-22NSH#`VVQ$c?#xN&`s@K&*t{6 z<*W~1pk&xk2*Xr9}| zX0Q^a^~y#X{h{5abi!+YsHl&O9> zHQZB(?g}RKl`&i;?vu0x-LT2iE^)Z<`06rd2C->vLI&f}KHDU*k>dSrsl`e-8xTj| z0gbAYnA#@tulG3al?C!Q(+S>sxX5n|L-F%s_soNCXkf}Uh0{s(7;N=z{q7siGc2KQ zx2Hfl`7z!%DZ>=QRgJfdu%}nEUuU8}-9ffS$(Ex5(O09+Tj7x5@v*3(a>gj<XrZx@{Kl9n0s>Exflvt>$+Pd$>J3Z21gpvWopR?Ru}hPDo1^ z2x6*cSU!+l?R51S_pRwpG8}oli_=D4SpI^>6;Ys2yJj>A$xg%0unc_eJE#NpIPp|g z$XKST*dcss=pjxzN(MNsCUev|@_iP0BAe(j($2J(OWvtffOtAw{2t2vFkLygw`RZ{ z-mqXgrMZ;`9?TGcCN(dv1}RZ6Y_5Yd2PpI*e_+t zE!;4A6M{=m$8eIRrM#9fG)hI>Q`bEqGoy#3DfaB~Gb3O{ECZ%TT)Eb&8vpqMq^hO>m9}j$f#B8FYa3F?LFDm zj{`~2dGAtDnb^bWDzUnz>w4a2tU_-B)pX_>{;FKMp)skh;uJn;{F9!&^IRLCH3qjy zSwmTTX5NK-rN9sNIziH>UapSGl^m5+qH_QOP`Dijc$24#T7=pr#OCH^-?EQ;97`@8 z<=2RcdV?9rt?D+iN(PGRHZnSjrdQJG^I{<$o}gykjEcmd;}j=IzSV>Jv72F{K2Pep zo`@SpcEK$JA~jyLVzE=ffn<2!>tIHcS{k0;7k;&~AUSMC>`8bn%1-r70(^&hHD;RL z?q!Q^Yo)fxt7qR@c&vnkaBuJeWp*TCCdSyG0kRtjE+KP&99vdWP@u7V^}164SE<|> zl0}!E)|x}S4&vieQbryT?62l)R?>kV7LpR;PvZ+n+|N@(A9Yu&T)z%RZ|h>403YU{ zrlETvQO9VsceM%&JC6SY|GcV7WAkRYY>mf@l)OPX zuT11B$;Qc-8Om>h8Nl#s>_OOD(#~Y^q#`xX`$v7Qe!F-uyS1dU%ztfK~A-LI}Ll$f(?+8M9U?tSi;S^*_0JX+F9yU+mS97!=K zZfV&jS23R+Xw&tL{gRuT3sKddaMLm|Ka9h0w|7lxP?0;~pJORAP!mUu`Cv687)GG{hKYyRWPF#fJJx1gngWfc{4EdZA7ZD@vh zDnR5@qm=LzJ)b0a_hpH)?cPl~lZgadB$5a>9Qn)bQx=*4Vtx+#^V8J>QMW|2fBhuL z!iZG5FAYV<7K%q+;5?|>f`o(`87Ye&)@hi-BQY)15H(mC8PXiw)tYj~VYS?Amc z1k?l$yb(|CM4k!`4vsD`Kcwjdq&>o)!tng~?6{cK)G*k!@x;}46BfG>Gkrc(coWKB z8XRXF@F)K2rvZc^|J^UA)1Ha6kzkKV&`8%lhKVRB&V*Y6@sHgU~lOZxbK8 zb#dzw;82%!n`xOy#dJu}%F2$v4j#>bJGy<|j=&qsredO*Y&54Ywvfc#?gPzG!XC?( z5vd*Hgra{Mw>8!C%iG(-4jmI4%b~e|J=$--Ku=h*3oGUNbuoU)%4SqsezlxEHQcul zV!Ze$H``qdf(-<|pZaDpv{Jk9`+5Y`M8({cb;o}b-2a3@Cv=}UihoaEK1AqKgK zERUnDUyH%4XAY$3`+4J^yERy;8Vh>S^wY6hG$(s{{F|05unB<6;MI?!tY}G^a-Qi{ z4TlGvg-$u{G`nPToNL{URDHj)YagFkPiV>fnjeWEE$v_xRlJ)6n$%3PcOit<-=`VS zO?A=S7AySJIA!jN`#X?4*rO_I!9UOTILdnIl>p`o%uIN$gr07!hM4T^GC~No_e9<( z>zmXE9EQflmwT02p(g=%q*zZ4riY2gTPw3{a}=z07mS=u1V$c2?}f=`*l<>bU(faJ zpK{D_?|Yq7Q&aQh9aWSQ@xUv!u+r}_GoSfYZCzZ%;2<0k&o|v7 z>26KYQx`-!z!%=pa_w%~f>sv%%AXY~cZUk3K-YBwzW(bB;LS>TxX8W^^5^-r=nuyAMsP$Rwmce9RhW{gH1(P6L2s?n#dqZj&Hh_wM?n5ZrRwnz< zl4huDn_WeOgGGzHSmB#2!15%?hXbzYb9`gZpO5%PvT}5E1S}68uBX>A+)F;ap;!LI zWVUg6@*%HJze=QIBSh|3Rag8m1v8Bc7nE&XT+#uMQv(1A6*-;EVOSTvf}4|PCnLh- z%XP1PesWJ$?jOCO?*KMjgaE#^NIn>hz;pT{eL^_Fi~Km4NG2?H1ircZ-T?j ze>{Y8O->K#GCUUJ`vCCag9B|=*B%QqRpmRN*?j}{^o>_Yoq>|-`pgu-n*dbb&Ncn^ zVfj9Fby|&NjPUfBzQaf)cotpA`HYNsmxElKI|Q?UUIOB(n8qQ7jo@bgB=Gw}8wP>H z$Z#z8bnm~f-;{wFORoXDZs+a|i)X|f-@ST(BjZk$Tekx4RM%Jd#c=9#-6xQ90r?>} z@*In(S0I{fBtUwM0Bai}ear9m81)m*7^Ac&YHGyeKM6!4Sl2=%xX`Y zZq+ptF6=yjIXG@Mx)AI%>2wWDW)$OE^UFKKedWkfw}}0a2%K|eU)TJ0w=A66p?mr3 zzrYqF?P>AMI4h^>nF&}CX`|jnl6N8mN_r{%ThtphEgRyL69(Lv5)A-5+VVXGRl59i z4d+*%ckxKR-TRe|Ls}?;I7y=+@XgY>qKwc6s-)B>F)=XM01p|8FBb-}U#>dUC`VnwqLhz-BpV7<%*787094=g`W@J1rP zY8T>Dp_AyP4^s;jk1-}lXYVTE#(whZsqi~j1}#a!-tQt+5Ci~NT~j1NCzRcL$fvXF z%LK2IvlB51w&v_XteR4N0N+-{{d_OX=S(!J)LpB3XmWFgB52{#@xYY_z!_{m&q~sC z(x0bPRs9a0dAo|BbTlLEi(K~cdIu_IMi~!ROP?bFFJfA!ubN?NZDavQ9Jf0s0fb*6r}0%n zzA*wHcj1EiVMEYJ?cK};HH6ik@@z?U)45*zq@a>N*X^F8{rq_Bmi4=-%WHxzd9*x! z7+PQ5b^tdiNr1?1C3Jh~0)h#jD$Ok_qK~4gT;GL4GWg-ucP(=mo}bE7w*l@3k{Ao+ zfHM$A6!nIN;;+tbapKBW3tYbHF=byKU(sAYJ@55qV<_GGVFmdI$SN%!{|ybwe?JrXzvhXa z+`Y13a~-;0`Zy&{uR=Z4n^QoDw6JYi=;EO9UgJWi3eAv1Q5W9!ipzC}r2)xPvR7x) z=B->Y!uM6P%^QW#UZ5RIxtUK6 zj!4?7sHz)sH3KvJuy^`%v5sH;z_UTf6gfC<0$x5}JLE@j@nkqz$L~tGXv}`>H{y#t zEMZJ|`NM*u0A^_yRc%u z4;h)_Se~=hm~OG?iMOA2T=Yu?*EVl%4Xn*j^I)XMos})$d$~2WvN6M0Ir)~zP!D`| zR~ee7OSf$oOqAU|zn-8*5##l4N(BGO6^mt;47&%>s|O{XefSDLqfN%p?~rQOWG&)o zo&C+~lZCcLw9iKsH-nF8-Jmd-swOqrJh=IN9OSl3-Y$BX{CmH|M5y_!?=9&%2)hRN zDJ~5-p){F(r2*7|Ib2?tV6YZiMB}~2sL)HLZm=D#fTU!Y|62a}-HJ`wwj!{PKW0j$Ho_t&c z6P6b%>DaP$W%s4((V6#nzIWFpHd*hc4~#JnEjJV9u|dt5fdg!wsBT+8CI8j zzcR3GeI-|hQEA#L;<%B=CgORn%~415c~Q4!tndI{?o~_I|Gj!{%0X+iuDL}3E&P*x zixQPmuwmS2tMLyJ1zxr}ygLmUbQO#MBp0335oPQLr1Cm?4_ARo(M5Lo#k}{{>e#7dazHKJ=y!K__hd7_6ZnDJW1`m1 zo(-q*^WSdLgq@Eo(Qo4Ehz6?*+eGwP=j-g<+l2L9>n>*EGO;JVIg&&aNWreXoo6~j z;?;Dqq$IoRm(OmAo7W(~&kE<_)1Wrmo*j2zRVY5%RP^kbi6YAAkS&{-0=CWRw>VYf zh|xIFaF6;%wKH?XvUR_`n)_8v9L)bTY@Q(?@J(OqJBxd&Eh^znFZZ>{bFff%QG*uW z722ca1{Lb=!Ud8w{vOt+_e#HzOJ~rut5e8mF4&RMJ={h1E)8@A02B}J=uj^jxOnpN zM8oa)v^DCRsZi7$mHmD0%d#2g=PnI)Qcw(d)6hAThQ92x6i1u3m+#-)y8ly_PtHA6 zgPrA`tzI`|q;n{M@0x?gx-Q@LjJE0jzYAc}r`75dK+Ih2vPU*$qtx!H|E}ZrNzy;bllboqSqHN#G3SIH^Ps0(T!@|j?GGmX;H#SVgn?C?zqp}0y(9|M1!>SFd=W#0_;7K`Q1PN6mK@2(<@`^w$8hC!t(7*k1bBm)bx@B7rmmd@9GPW0{p(Zj7_lYyZ zrnaP;Q@YN9x-h#JlXjXtY4&5#tR898Maj}$Iu&9|-83!$|CWKBc-rzn`*u;GrJGKN;e z0J=_uIDWkRip38ADdo95iXqM(i^MVYwwZrv1@H-cb8pHYIeGrm?>9gfhfHm=Ezbxt zq<59wl7sU`lC=5Zz9C&6@%$6sE#}9-IWGMkN*02OVGsP zLLXY>CXQt8CH?RjchTo_ba!BzOZf@;POrAtF07aSgw8@c+jT1(j&9K?XzC3s2XSUW zONQ>Q;u={*#*LYxsu^zV`?#6hMI?0p{Q}Jjle@Po${Sx8$j&V;9_(9b^WSk47&mN| z^Iw|y_+NwS|BG@)wK_vAa%gzaI6=ill7(T`?9W&th`jQLD8Z1&_ zGr)=&+}8bD6;XZOq;*4;{+Z+5S+>O|93jR5W~aCL{RXH2%lgcURY5%cCXhoLHB$*l z?EbB;VZPi}qAiW*U{SC@9 z)j^}ZIhV(pczp09B@-L>d{qi?8&HGon2HkV>>=^&T3l#B6^)lQgytu8@XtK z-_8GB4F;jOTAl5NbID4fGaC$rH>H!cZk6ssubsHFby^Nz4C5rtq2;49F%fx8yYq)= z23D_({4SDcVdiEgyXak7p{7CTXum3SoY{~Q0*{=Zk&r)6{z9vsUx>>zkc*^9l=~qJ zed-=Ya39`ej>Ks7tmhanpOZ=Qdhg!#FuW$PEn|PyoMb;QB?}%pK{jnYqY?ykrXeOK z$2z-pwBzT%_Gx+jnRK&&J6NNTp`>48(g+9LEV!NK$nFDdDuZQsjaZy>b}ub@)GvKw z{QPAts;mX<{`OIzS@kGA@OPOT=wK3QmX$7#fT2%vz7v@!JU)<^AVdcF6g6Z`>IQ+)=*`uyu`jbB>P?0 z)7ptkTv&jDyaf*g`;0rkcT?GTN%f~HM|YW+RldHTIsffx5Wj0zan+1-bdjz}&-xy9 zq&X_SO4dos^=0eWJ72dpdO4bAz!7_faK5N_i`F&_JlJU9;yWJVmmfH|QuG`IG~_Rx zYqxSL3p55n5`E3XyLY(=yrzNl54wpg$FZbj53rgGVPc^HXIBid?6|kjR`d4)Xr|^z z$lYO-<-)g(4U^zMJRE80C5$!%mff$SH>lEiQdkU9!MIM%Z6?<;ThjFO@=3!FKr_{s z`6<#EkMi|q#QRJRVC_`Xi_$T?DqB=zE~i_)xLW*GEi$QRU5~o4Z#j-jC#E9=@ian+ zxtXFux0YHuWmG=73o_|Z7x0TT>ZNUdU|Gb{;LOP!MRp@Io(xaOxyR_B&V@kfa;s!L z&u}d=w>?cNl`1xeBH5z@@Fp|l;XTT%V0xvN(IL>N&j!QG3Gk*jk_=W!ByEdd;CnDX z?y>rYQi{am?eog5J=+<^SO4A%fNSY`XejtvXM;o%a8*;+Kijo8Jed(UbUTru8OMxjilfacXXKk`ea2}xpfx)Juu2D8Yzv><*_*ld$= zS-5}%q+(Eq3Q@2yy9g2K(tEiCjq900OSy-L`*3i7zNxu1g^NVru@NV+hSh}A^Z zNSk%sN6vR>Cbl|pb9wyMXUEqjz!l785XlPAD?}vGAyg9nUQ79&`Wwu8UDb4v~hWSANxSXOJ7Fy>~;KA_Pk-TF)k!LL_j?wP8hgf=}Ldb zI*!1fD>f(o@l-?EILL|1git|k-eQCeOZwO&h@%tv(&PRVp{HR#2H7(E6Uu`(zTpi1 z5rM$lN-%lY7GJF~Za4bqVP*zsZsq!7mqNb_z=D#x!V}o4geKd10~4)HX0xyT<)+pS z+%upXfbEI1c6D8#cc29xxjAze&L27rKuOu9qrv{<{xWEdKyQ+)u=3`#z?S!?TLc|$ zAe~$-cTk0v!NG9R&DZ9fcdC5xC6DD-*`+?tvKwqhM(*OthCcURAHAJhl)*e8sz#u) z{8Be~F)Q*ej{(xcfA7zGnu_H&yduRE)#rdu5++LN4%zDJV>xeKW0@uy4V)e0cR8 zP{B?e=f#| z_%Xz*QP#Si8-xf!3zA2mN-lT0y7fnRiTZ`3=B}&~+0?cKv|tytwf>kHL7N`}e%2}e zcu#41>Q_VV1x9Pia)XmpwvYSRt8?3cM_K2HiM@Atz&Ol(s?Bf`&^TDE3t!$NNV+i& z1S3NlVy@+>jC1#wk9LF!$L-6+(Z<<*-pYz>8ZMlBdo`3_R4NmI7xEM{szwZfIl7fJ z%7eHmScK8P{YnWZ+)y+y8dx7-fAzlXSYU%GbC883f(-3};qhK^t)(Nta^g;AF#~c2 zE!}N49W_26&-{36U>~X`m2J9e5He1Y6y;P4;+(C&v~4r=Mge>~c2*RsWoUxtG3a4A z><1vVuKBRPSfTe3@cx5p9I`HAQc629Fb$;GpJ;x_Q$^nP(zkn$`K!s z=R>RvQH*wt7xXU@V!9wB09~P66RLulqtB1kqqGjywzZo|cXs~Jt272y`>FW6~&z@U%ss<{KH$?R12nbgN@Qwae51=ro( z2fe5l8_uL26z}3euA|N44A_n}p2N<$K-1r+jY{f9XB*tpL$QC?bb3h#V4vW1|L)}7 zg3gK&xAHv*fy#0r|6d1(&v%%DZ#G}pYW6tpLSLESoDX(nzGVNl?~xdYe?VOI)Ayu_ zhDC5NiRkbGgB!sR!-yc1(KuKElxT~_3s+(76-V6^x}TOSnEvV17mq{k*KZR&sf0L zM>4O2#7#u);)Pql4?Cci7LNZOS;zmw!FSY&b9*-d7mNgv)7kT2i_gAIYre;7=N6nG zh}F~|WmOba0J8bX3$O>k){dKh0|>yAfZ0w6LR{MfXeh8>>L?(ZkDSwVetE$C_T(ZN zow9e4Yd&}W{2^;g%ix6?7wj38ed@RxaY|`zID@r9*{Iq*kz#bm3w4!b<+=U^2lw&AhxoaIhGI zryN)u&c{Rf*D?SkPBwG%F3kiSyq;fuJBVS2r_7<}I`_T9yx{x}oAM`nKq$Qz1oaL( z0T+?6a;^8L*B5%eH+cAagN2>h#{jjGy3bZEr>Ld~Br~3zYwuvXH@7z>8=ze6e0rXO zdl1|@^3?W1<=mARZ~;pJo@TBkMRym_?%@wL`+>pO9|DIt_;c+Uw5e@vHm-IV6@Dz> z;x`#XKW`{mvq&)8y;!+6PnR0*+T2XD>7JK&QwV9%%XX}}nb0+`i;uJap|thpv47d+ zS$*rwOycS@X~CVr>F$o)pveMQlw5Flrn|x~gTafCn{Y=b^duDw>5L(PHr*kFMriOm z4BCI-dZkD9?2drgFxI0lDP;s4wuOC@r(5M15*cVSZM66meXw7jR#p`b{l4Q{bf-N; z1i{#CWd&$tCz)f0G+o%p3d7HLKti%`MD19%W1#^3S@DmTOYZpRdt8tHa0L2%;rQ{N zuW|k7`#5i|h+3=x{{H;W7r*XUwgcQ+JeIlu@9A9;^?f#$CJLH}C5c*6JxC6g^aA|v zEq*uxO~t~oq!&wi0SUsAUM%Sa5Q8PC1`=;efD^Wa%$Hy@bH*Y#R0jFw>`19!b?~=77S4(pBKP*>Eva~n@|7TkAvtKXZm2Zx2Sjavh Nj$8d%^v9)}{}<896$bzS literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_mobileGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..a846131d904f786a8850da90c677fe0e1aa6d5a2 GIT binary patch literal 58071 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 VeT46kjJOrHCmgMw{(Rxue*@92j&uM3 literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_desktopGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..26e399a43358d50f7d84cffa1636383787a73573 GIT binary patch literal 34003 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 MoBUSr>y1DD2MkMH-v9sr literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_mobileGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..1f1bee56e3957167de2ef567d24bf11d23309892 GIT binary patch literal 57639 zcmeFZ2U}BH7d48Ai-4 z5a}hf&_nLZ``+*Vi2J>H9v%YOduQ*p*P3(8F~;0cFSJ#tZZO@TprD{qQ+=*SL2)UO zg5vt0YgfR3jGky*1ivnL>#01YsOV=|1%F)feyV104ZK3Gz5YN!agRdn`4fYHtPQL~ zz~5sS^bY%_@(Bo%81lIfjc~MPyM(NTvJqGiW41_2OC+)q>cWZ#^tP2&Zy`Q@$}$}!RuCJ{yFu3 z-%> z$#CxZ|M%`*YI2#VSlz-lSF!1&@TVm5=xn8Zrhux_(%oj=#NYeRM%N7dA3R7Auy#v> zga#iDFMBNLM!k^2z_f9Wnavb0*Uf zmv*oVN;2L{n(t6&5s2cI$H0M$Rh0cJ!Ej}s*$x?;^+Dz zC_l1!9_)PdcNC}Ga3Xh{?Q^y_{nk>#k?r&Ne<&#ES!Kg|7XxL_&I0RCyEC}TZu}X5 zU%X1w>5RZ^@|)#N)LMw>^T-p+D=K`Xa@fH=ksU-C$;QPaOub z$By@w?dlZ^1_xhoQQp|~cLcZcKN0>fEpXhYhzNc$mtxd2aQXoh&2``xczvg(Rr}8y zipqbV)Bb+TEa~=Z-h)?0W_s@Hk%fUlG7EL&`S~gS&C#*jOvBe024Q{za1lUw;EPn8Gm)Su~wiiTw*ch)xEPn!iJ0=!doO}h(ox|yOW2J zx!ya68a00+xnx5Ae8|#XCN3}betKp-KvZWGeZ9{cad)D^a^#27T%)T-5_cTaxchI< zIZ5}~(H1z$YbsU5R(Y&ccLa9+EibRu7b5{PtykvJ$sXRpp>2>?MZ^E)Rf*3kHTe3D zKNy=d0&3(J`wfVp@Gq+Ws~#${rv)j%DV1ul*K z^(|}PqhFs)P(01pigMHHV!d#6e(Tnj8w^24Pp+GUoJ`lcnANRZD=b;zM($^_{=@^os5F z=xOBq*7o@zlQp{F1jlBHr#3{E^ruggxipLnVHQe+wQ)n$&RZiBshmY4C5A3WE>pX9 zAbJ(|;CsQC^MX|xR5ys=H!gI|3Jr3`w<1qoP3f^JgqT2CW%84Xv=s((1jRC=>G{5; z@f+z)J+iZ_$KV9%MV03gXrKob|)t&NLSuWww}os|nrd7whQ7$6g={%?56Z_&#*u2itR z9Xm=>Wc)Th$FnIGwnx&Sr+2pJs^p9}r0K#Arc@;2@5=gbjz*^l_@4dr%$5q=eQV-_ zKeO6ScQ7dQVN40!QIZGSa;YW$T=qP&Wx11D@;W{9b|t6o z?F%2TbUuLFq^JvB?U2aSIz8Ob+776L%oWl@%o<%~J&&NC%1TPBWyjVoe?IG0wZ81F zaTzfpo*qcDwkRnn@u|#Ousz?JZaC~LRm$VorCZjcjRBMh-5!6?HHp}!a zByg|EH){$Xa++YCBJFM8mmzEZEP_gW(*ZY4#m0lMVL98=F)TC0RuU(2{enWCRC$gl z*RD^_+L^ySJFfLwy`e!oyR(y!8bU%AYGy9%B5b*Jw&a-3#_t*O8qdOTHX(bPe-T&* z2kbDZaf(4%ssV+n_tSC<==(BUdVdWSq9vTipM#N(B?R;=35o^%yn94xCY{j5khg_LNqXdP)eMaksvBO{f%H(ORo-rz!lmWLuev|fIc3wzUbIW!?gxil` zo<*z{s4qp)Sx+^(6fudrEFjJ$V3^_}goFRoc)20vrpKpiHwD-V!}l0IA2f%x2h~Dr z^Lpw&p)C*o{7YX2XC>|pOn97eW!dA ziY~g|4Z+l}?seU%4eX(>k9V0Uga!Gm-w$r`QHbfdk%vb^p$;1ul+ODIY7u#KA*hRwXn7L{7>m9X+_3m@y6O>CXy{Gs_->r}N z&W2?rP<(55O3!JP$(NsBgGF6Z;TB(=tTiWQL$~7KlyndCx8SI+rG}*^oL~P8c*cGr zU&-LdHa8@6)35o;0rQs#0y8f^zj`BO0~@JzDlZM3=9aDn`I~5ZQrAWX6n)qI?GRI= zMaJ&6PGe?WNj!%uwHI`%YN!H!!OZJ@&VF7OcN)@kr(*nb@a5&whH0r)Swz_RVp>4V z5HrA4goEaG!xA&Q`XtrF8Za1!FjK9(Id&YPfCj{OgMnG(f+okY`gzE)Cf*Ok^>JM5 zL`8yp5|8rxpmBQ{;(pJ-4T0m9D>s=|4t{GSQnM=L`>|RXHOFuIf?!pjprg4p)0hX+ zncgCkA-45DX0%%huSX-puupNs!m?t4&w?mUSEPYObBZ1TNE%J1v9JGaikmU zu@wqUgPCa02@~7Oq(T;dbi_nQM-P9l!k3WGH5)g}D*cqeG(HiPROR5))IRUw`1^Og zLD3V-ghbV*!$4th6`k?y{v?Y(CG4q!hK=fr;;$!P)DN&G);JUR4NHwo!F(D&rd+-g z%F^VYRDPyGH;V8V21DN@`5s?ekxej5({2hPlp0rET98@-VWmtn+{+CGWu=Zh*~ga^ z3TCeFrt~O8EzTWmVamKxy4U+!k=S!f>1=H(_MLcsLs6y%F51-T^*)F`RK{Bt1c_suM{+=RueW{4MnG&R8dsxQ$LPw0%A)%Q0pdSbquMh12l<*=YW9()cqk zJ-ad_IKFGA)0-}7Ojp*D->yQ|1z%F$yMbjZ%) zO{%+MgJlYSThk?-eHlSx==O1U6Sx^+Er94R8@QIwB<@c8kL2j~++&XG0jk7KDkR%2 zbb$MrN$x(5a#=Xbc!a)B)1kLvy}2W1vHnRHk~T z5Fx_}Ae?`>|GpMX=G=ZxR%!cWA&Z9J2cFGg*n$jSmyXi6f8yHOBLd{|2Gc@PTBN~! zvWJ;9lCg@|@$*2mcV-7~ugC#B#rgMa0H+u;)n}v%;_> z&21CjIx3T7fMIr*y7IuG*3ZHzWkQZTvaET_jNrptbADweLpC&WIh<;=WW2hFC8I8; z17nb{(h|^yqP&kD>18+hMR}KcgIb3UTG6oK*UT2Y;kgNNL2%fdZIEZ3W0#F#iABdI z$MAWov_5x=kf9lv!roJ@enfzThI?TOmUPAOx+pjK5nB||?Q21Ee}P7dk;%@2I%!lt z`a?sBsKbEc>aLw9^{#bT0dgE>R;GF1lc6X4l!Jp~A4CApS;HF4W~nZ$sXE+V-^1gE zrI*w`#vRomJr)M`yFo=Y_NJ8>%5qE+_^62TTI?-ImdMne73gJ}ICbuwJRGYGdq%F& zQmvQU6BLKvh0kRupaFt?ZgPFGJ6&HbiE}I}iKoWp5MH>$BJZb(j|;ZO-(+@^ruTo{ z`&l=I-^k0<6@vx%^vk^hwe0C-ksuEHXW<_|YBq(QrpB|$mdc|@Y|EZ56L3+a$n6pL zrQUSkodu<|@OsNY=$T1e@W6@I=RJmg^NbXed(bdCK|KRL{lZa@j`q>BiVJ7br&KIo z^td$m%pE0qb~rC(_7yr%%9jn6n-Y$22?BC*78vOC?PdIL5VV-~&Vz%XHMN(>*=%%a zvCcE+s(Knfj3b;Qr{S!yHcCIuGhfZ(-p{@|^HdCW3U<5PhTk{+kA4C4p2N_H= z*A_9g4?y*eJ|_NVtWae8*JqJ5PU{DdLKHjr<4JqO4E%oD-GxEqv?+0p>DKbzkLbvf zKYPNwp(p!Iew!K8XMrzJ#5&Br?7BrjgG}o|X=+IQq+T2htaldqAcN4WW~Z}cbnyt( zI{f@*^YhCVZjXNp05ClI`_;3B5G#|Nf9M1)p8G$*uYq!4dhawxY9J4J(pth!AF9*G z`BRow?J9~6_ z0y0)+B-3S4z4xSX}A=Ct|nNf5XU5J6NaAz$+g0%mS!h#QC&YWq(e%uv1( z5|+x4a4N0Jo7)R~*!ltl0bkd-CwA(nyJa3hK0Y;JCUpkxDA}1!%92FknLQu3^)U8tJE^HE~xHfEw=m$4XaJiE2|P4t~gd=PEOETi3x;UHh*t( zcbd9^^Y)*+KqL^d0(Yu2Q<`@H!&8ynT&!HXR^{gm7FM0ad4n20p5;|glFRwKW9Q-G zDo`qQ90wtm`$RU&K!vq7hAaZr*+Mn3GmiP>58`@;oNx3ic6@Ar3b;E6gBEDNai=)W zRU$LUZ~bd(pLv6(t8BKmR*r-cyUx+i$^;PXoQV+x&#l(6f%Oe{Wsel)E zcy#m*C7X^P+JC1@t-HXz)R&Prz!S3cC@MeLTx1|aL?0Qx3>zdUo;T=NsU()R7)(|6VHY7P@hl>moXNuG+N&c){!{b-e!P9(7t=KG zS;jI?CDu#&C^7%bmwPD!`bK4GaD(?j1gg`ioe}E3EOF8PT&^m9^TOCvD9Qk2>_I?E z8iNfC!6YJ&j9_N{hk8h=KM8~kAy;q``?#jK(p^2f_BOn}j(kCzJ5_XwPngM}Wbl#e zu~9#ZbPZ&Lo@xa%XGg1cxWxiDt?KrW$mfKa*ufn4vSs~8%XHk^4=NX4nbo?6zXG_p z)TrW{Z`t_TF)i24+`V}ocJt_ERJjg(HbXizqC16eefKW~wM5QR^X7Po3RC#5U61M3 zVY?^$%DVL4O@G2oYHA~Vj=M9qRJ=-P`W%8DP&5rf+6kn(fTa_$iEov+u+~fmcZ5@| zM89Z!`Hq4pR@@7%BfGz+O%kSZdjW3^GpTt_wJzz=h&{ATkS{DvDRU(3rZ}6-h1f>= zt00+|*DXEoTX%k?GdYeY{(ktDfN*F(}tDi=eHv{wGwO{>Y{SPDt7P*qSP>b;%M?dJ7GxbiI4GuUDXc;(TC%oN5ob zk|8_GeA+sHH0)Nt4#s2@&`0fzN`ZTS#%N+viy>ta5pa?7JQ|a=xBwN7>tTyNGXKFn z=c1?82tax|tuEjRHcl@7=d!5rE}ym2bi^#)?N7+jwrdRhN1APyLa_h>5?Ei# zL0UnOCmi$SnpvF?LZWC-4qR}XSWrRG3q{M@4p}PQU>N`5PH#3HA*&SqHHS|5FdFW!udR^**(@=TiYWTtg z+lI%Q2E?p(JQAnik^VTygnV(WlH>cqF9BL*4x_i-Pz?CK{j>(;Yo@JE+F>xUK68KQ zOO2R?_9tZC#GLG}K?3P*$Q9`wbB#1%QS5Wh7Yj$Hc$D~>JnquURa>;V)uYc6T4teQ zTNm5^O#-Mjfm;-R(U)a!@gXkGjvRVHz+#%cN373RODa{V-(otB_h+VCnT;zl^>$#c zgUUPPsHZ%nb5Lw+YYXx}k}bqbBGOae2!B+4H-{XrMd*--RTD%(9rlBvBN{=SvI(T@ z+t6TU9esJ2_w6;r`O zLqi!NBLPlZE4TAzPUJy8229mmp4%3JG@T@&9IMa{q|N#i!Y)B{$6z-+F$k$)Tz>+= zG{wy;Wu;`7jaQhvd|tT*_!sWDSpOxT#W77%JA+qgt-t+U*HC;y)0TzIOn#eP=9iR*DuiV^c+%rvsZeU$ZMr#4h#x@q}Jk=6D zulWMO_>N?E@sw)2SlKMxYf%d$TZjL0Px6!s1a8mwhoh~;Q=HuF!y!fcKfLt=*ZJP- zJO488WUy-vBaXq&L+rM{*UxAxYv?uAI1$u?ajah#GNv4L9E^d?WpPd^z;?-=neqR4 z0sKP?BGdb)<8f#A)ox41Ib;?EEvVJw_>O;2MnLSNb{EiwA_~6S7o=kRv13*{CBk=!1unJqaB+HlnVNTl{w2f zbI=JOz07Rgsf@P4e1A4w{8;n?S3gCFQ0 zJy^Hi8$p>)6Vn0N{vjGUa*bd{6|Rc5dQ7#tVa-5tAFZK5#GG8=?wKAh7pd6PEmPK7 z1hm_}Z(qwyUADs6p9g7>tJG}C?empl1+s$xmc~qQOxtrjc%X&<=@$k=phM9&zr~$L z036u zo&`<#&iKGTpql5>;+Q4$DzYjPy3z)ux^7+bv_OSnDdjeQ zVM1~i{#!Fq;(L-W&?2afM>%n$)qxrbw(3C3L8INKnmRn_7nv=a`9VftBbXzUsrsz{ znX|*3Upy5QOt~o677Nyrnq1b@M<7GB6BdEKM|i}42r85xmDg;Ks~1}`+FsRc;Fqn# zb{xC3UOXZ#)vSLWbu(!SG0j55%@EU-edVe<-|%s1^gf##=h-DtvWyhuhkrHM8a&`` zMPTPmJl;X>t#4r?{A0@iwmCcA4ID#Fm2>JikXEgbS9Sii7t!XbWAZBDvPS{E5x?>Re+({eL2&UnmzAeeyA1SU~!V9dH6CD3B_UGI}-LLOzdorPS- zr8{|crA-8s&&PPNzqw7T_J(F^vmz~8$&~l`y36SSGya`kcMq(J@{d0GE2I?mU&<^fDg7%AWJkl_EQFMo0e4Qaz(b)A<6o1 z;w$PVW-W6=#?~-H%<1O32te8Yv=xxSO;?4QtWo#nu^wK7(|=|V&Y9m zer}|x#f@4}LS#vK{@DHuw6_Dtsa)Z+CJbTM1Sn=KI*OZ~C@^?8QMrAcd~fParmvtf zkHdE=ZsdG`3%1_L1S%_29T#*%1b(GM(j6=23W8h{ns}m-$f-73qjo3m^kqwrA7T+= zUJnu9s0S-E0sQg3IEAn7coExcaHqUGh}QeXBVR5Vx^u!KKqB+S1w z_;fYAblv?kn;io}7i97PPuaLWK{_}R_i;D9`d8#s_&!z9NZDcX(9Nla8{Jp=5#FDs zqu;xAyi4}Z6k*HrhGtFm5^Hmo1+JDks#WLXDFu{ah{ z^#|x!a(QjA)bWVlvNU<#Z!bzZ9*`x>b>XjlvbSsbd3k?%mA{pV7s~4Z-GmjD}p>pZZ;7nW-`)4+4#Js}!=cT5P zw{Xvg=b+8GFXe;wi&J4H6?l56L%=H*YZ=tITG>Q-{GKnM!RCqC%w$sos6$pk$zsrC z;3R*Xe|ov#{6?W_I0cs6-)fv{Kv04$_2oD;^bV(x`6D1)1i@S!==hCH04*^x z178aCJ>U0dQ5H?y@C$y&Ekj0}^<9l~#g~*qM4P|T<{q&<2j6!|?%NMyvTF2)e`c8^ z2gRKS2P+}jF*2&Cjk699Gyl!$&Yo$`)puQAIAR#YRoLh=#t4>ABEv1cUiLd0JqN@j zJUUxpFs;k&V-(jXpV^*8(VRz^LguIm>@QUm*N+Drv1z_nOJ6^E5<$=}w|aeE=~|+m zA_(K+4o|tG4t56)4Lz87-R{bfRwi`R{MnTfkDYH!a;_h=b7az27XDHHeRnJEpWKI;k}=x`5w2))h-UFU$9%wD;9!3 zfRIqRw9I)YeEttZXaubrpStg_(Cd5( z9u?Des!Yqw?55@8i(K({oklu^B3N_(@@2V0XV((!@j8E}^VUvRc^&UZlTWIDvFSch z$hf^@ohSq`1B!Wv9X5|V0zd>x-kNwq;ktFuW@g`0dup3cl|g#eY=tk%BPzV9<1ux(smkL+7InaLgO`2eO` z(xZYM>b&!&t_-m#66)#&>j&hS*1Pp(AotL>1-XS#nA{r6WfFIEGJ zDA-*k{nbL~I|j~bIePJfOinJk)+^*1~^_8?Y!7lln7$4I!&I0kl2 z_FKx1mALR|<;rOR1}ES#`V+UWb6NtsY)++b8MxE72ie|RGp2OEa_2zZX-BW$enK@` z?t};k#EO-S{M10b0gkH#At3EWKrZht8auy#`wMD$?6pYcf9?2ix6XInQs>nGeTLQm zeUL=|gvco|R{@uKVX`k%lFB9O$T|3g^eC^bWedxA(1D+H_2)-$G`;1tG{br8o)it2 z0g{;0QBL&?5ScyR7+iv4|LN*|D2Z4Z+~K-SOpROn6_^>adw;Ueyv}iaW-6$*UEl(1$X#-9(m7fYG)ExABe*f&clX~(YW~#dQ7CS_TWNk0;U}a-UR3VTG(RQS- zbL?=)=%0?gO$5aoFww~|J-W-OOT!|!a@ZvJcIns919DOD29UIpuIAfgXKyq)8fgKq z+Ls|Vl03lUG}093Je^;%y2qoPlaHyl6ux{jS*o|c`*JsmW+i4w1&E@zoN{a}{HVh~^%Yab3`n~PF5XNOJHrOXHIxw2fVM^U)zOd4NAPbw1gXBxelL(Z1^GN*y{pr@|duDcj`R6^;k zp9aYU`;qBf?vVYcd2e7qn;&4~_59P5Hn83BuVylkrMPu+dy z9bs6cY#Z)E$lC(Q_XnlVC-)*Cnf0zlpi;Ucmh+Qy1C&r2JmjF6c?A>A0H&_T%dPI1 z0_#y-hWAWBkr;C^DhsMzb5lP55~a`0T$dtb+FiNHm-KXIez`qm?)9xx>s^Z~n+S-0 zp^iRIIS$D$h6KJVR+$Z%Rdc{W=8nEpzXrH05euOvyLEbOOQ2}~H`I3&IF6oxQH94; z9R%%H-`}3llu~BIR41?hTj~7fsRLO-@0_X@n1-Hq!a z*;+~BE=KKj9*ScO*Ph>Je0DPi&n6S1>T)x>&YUonKR|^c3k8OA*ZFvPRTsNcy{DEu zq{Qr|M}bQ-Dsw6>Q3Q`F5-^5?wf%Mt*vY1Aj#b(ZSfst0LS|eK;jydo!n^o0G=dSv z9(ocb(=skHjsm8j)!b_XC*?*3rLQoI?+d!#(yCNsHQq$~kJxLH{e%fNpYjRJl8$Q( zBR0fLslY@xY%DT76s(G9MdKMjT^M`I$MXTdBhFSM?V;1;0WfDE*O<4j(vpV-oN0=6 zsq3Udz{)MSi<;|H(^%z-kBx)h*R8d!OwO@#H;Acu?2W~4<~mkTmI8Usy9@=*l;S#I z?YK*|Cizb`UlLc0C&%jctARBaVuKyxRoleR@<4rDdMJC??kDv7mAQkBArOpiVg!tX zy7Iz^1uaiF)Dke_J^B~UCFa-<^;3q<9rs$9zbN; zW9Xe|QzWAHcgx$xmyI+ZeO~2IGZZiu$r`&$XBYA$_|IpD9zWCcvRBk-v;AD$HwuDpMuR%(ijSly{h=A#lGUg{&Mlf%FH4%w1* zLiNv_vP_lp*tddL7{IdDK8nW%T13UikE3&$Ci(%_SMa=k-3Hm@tL0Bib~hxPQiD=r z36|k9IM^1{i0iS!#vP8@b|nE?guUvF;nL;HB|R?LH!+|D&jS_OyeBDF`%IH~h5ALU z*;s8rmrcUyPB>YFuNfHy;91PKX~z}Cedu@3w*%a&Cc--QycOj!|1RiY%WjhG_Iyxd zKy20((IQT#`EU4{Xs*r+Nq?c0J7z9&QL8xvThuE|@~XZsFjv>xl5JV@iMn~FZvZsp zGp=ZHst)X*k#!$DAqcp4>u7+5r8P@@WOKC!Obvq=3D_11y0%~9JXBb) z>T~q7*vWR!((oKc=E;!C&2^pc+kl(7)B$hh)>kbRw(zf6Ed(-Y)#@ru$8W;hALg~_ zBmdG*COboZ;DllWsIF_fo$Fy3FUi&do!r@)S(7x$CMNAZ$wywjjw2U*(zLU&Yr?nk zZ)%rJH2a9VS|k19PN+BV2bK%A=!7z*_0+>TYY@eCQ;8w(Z+Q~~vYT0r)9S%ZEV-5?uwl1Ia?3y3 z4H0gTP~aeh<1Y7tcAdX89gT1$BU={V(JMfabULl{pEZh{u&VM|CTCD4k)Y&h-&pyP zRlo-6B8(D@F1VM;R`SKmT(t+BN(T28vcFl|QYPK)Ei(=+m^oJI^k78R3@C1Tpq^jY z=qYdgev0dK1{Ij6)jd2g*gJ!>+3||_`Awyst&pJxHeEZ!L5W}jR&aOV-~aAI-zKmr z%MXk&=&BR_b$ZxM{4I@PNy=8;&7fLAtXdpcZvHV0B~KTlt5P#$Sg6O`N57YGJ=r4X z_Oygtpg~2%G1ESbCnW+L{#3r1@Q*9-R69@A)dD-0gVU8hVA%o#MGb(xO>dUG2Jji} z%h>B|&eZA?n8qgNA9xB2&elV7GisgPf<#V~(w!yu@7sE= z{ELMTJN7g%5!@`*A_8NRcS8A(sFr3eHH=6F_q5DQO`cZzYJ>tL9SFv)u0i!AK> z%;u2javHx`iv3bCzr?UbrtWWWtIYuOMnyGU&-!VBqRE>3Va}WZxW6zjk<&)}n=nvr zG#c;xWj|RnM8yQ{jl}MO~vLMm4f{`~3O8AOmv(Ox^UyV`V>m1V~U% z+9}f)2IwY$HAUQhBRGOcwrv|a8yGf^Lkx>w-UkSPbe@U@yo?N3s;Os{&k;+#5=1X( zEw0RsSpHVXHX@eax-QG9N)L;9vR+aoHy4fcACRmCp?UL|=%2O;657ZCzwBsL=vAPx z>L2edHYbtkve26rG=8;Q>&FE?#mjHZAx5{d^!+Bq?U*clO1ljglQT;_Kr^=mS=R z8dY6z+1Aote++klps}2lw59(wW2!1U0sxuRr&?v!wTk*n1B+IDD2i7zNE*OhoNN zon+#j=C%~DFqqUNb@IA~{qKZ~Sx z86H(DggU6LO~`I}1_9D_V|Cc+Xs})jE=o3KS`XyH?EyE?8)KJpUQ+ZoBVEb%_TI_f z!21kohdSVubXg^opZq3zmg*rgRu4n#bFj4`i#LEf+UoKy!wcX}2j=kd;$mLQMlU6d zpX)?cpm!~87l3vbTPqq zb=36Y$$_L?;YbT|({4 z9=&a!-92?fElZiZcefP`Y8qp&)jh)PgAGXdJr38xj5?>2oQ z@Er_)&|N~v77iROyd_~a{WK6voS?ViM-X)Mu7-bkXo1Plx57<8Z^aNMV@pQvU=Q`b zT)%N+SOur}B5qn-OHm^@j6{4(X_48tWF(l_m8)gY=5Qm36)ybHtokTyxCitD0m>s) zkvUP!=BPQM_AUtqYKIIF?}%46j}JSk0GsB1T-ztblBRh_4G6~LAD_I}S}!3x0p2{h zh$qbfJszZyRMNO#v!$S>#EWbBQZ_d?Bp-v+E1^}cbF`ta1%A5TAD;i4pipHX{0Jnr z#LXWxMl5Z+tN*Ps zGGQ?niWu}+9YBHeu0K0;0&bl`?JU=(_9%f(4ANDaO||_B&6vO@Z0v=HOm=FLDrg@d z`$Q^K*geDA!6$+@T1MC8@ zI#^r`M{^?RPV37QpWwlL0-voSb!~5ABu&Z-ChGm!fr%fp9&o-1?K*K!5il0&L0?j5 zX_7n*n?Jj(a2j6=2pq?=$U@n6#_Khnv780!De4IO-hDMqAkqE<^ZXOn&>q zM$eIj@R-p&^FtMhsK4{xs&RB>H~SjB?#nO~2s5d8OS}>=rbBK~+=~$&tMz7pryjK! zlq9wuJGUC+J0zQ0Dx8vv_@4!lEPnIU0AHEo@u3EiZ4@=VV<>3aFzK_L^Rpae@#z}3 zytTkaF@r>fyRuffI!BtT!-WJj*Bml9s6U~p+1C6S2`ZiSo>gn-nP6LFj+!Z;6CfrC zp?mfmVkbDU8RLeLU<4g$p}xzppf=)heC z_pvp@)aY+KYKhN*YvdWT5nLb83G&f=5kQUjU4LaYZBx^o1!2hxCM2eYq6}Cu{@WV?&6fHKx%p&iMPDJSBwJF)3TD-+ zF5k@T&hpZ5c|yi%Dv@0-jOM}?2k7FQhrj#A2dP+(`uTUUPhc#AxT;>E57u2hX+l(Q zse_>wd`*h5c|R^7HaX<{vY=VzixF-e!_AD^8JRlZ9myT1u4M-9iHCNJ z)hEVHJw=cgyUUzA)DZ~#aygs!2Z2eE7k6KCH_KfPK4J_5NH%o0O~ve-s0Z3WreT*J zgQT&)b3{`M9k3F2ere^x@zp1YARbD>(!!IV%6ON&fi@IlXg?>PRCu@;tmglC0Z!+X zNTlfs6dHMaGb2<|;rs~ac9;eXcUny1<8@l*{#EH_N9&Fh^Eunz%=_bXM|M2S~HT1yZS%q*8*U)s#-o#Pg#?n-=_FPHWiycK%b zSD%VX0|esNu+S6do=$c{n6tQ=-gHfcOJI5!K0_76E8yoSv92TL16xTmp_v~ztRtwI zzOkCuxx7SOV9S=gpu+{8Z(vKZrwF41j=>QJ?e$-u9-OQX-Ukh8PjwWI^Q#?tDgdhi zeAV_6~B zkkql(T07OPo`}{{-HSRp{(X$g0vgnaRcm7|;lt-J0dNM8Jhzq)oISaH# zn-zM2&Rb&39s{{OEe#CC@va>RrF_7o-TnD~9&r7a0b4j4BYiXuGner_Nseb#tN<;6 z%Z%O+m*Vo#Ir zdMaoT-T!k(XO=ms$oODGM*uydbIPUg7_?2_a~pG+7z6~8t-Qi%k16QkEVs7#i$acR zMhmo)|8}3bagpNARcaQG^yk%6uKbqO$>fj03wr<4B?|7=&xC>=G_Vo;8S{Ed{}YGVL!G3Jt-6xA3)7Kxr4K)v!m=QTo{l~`z=EL^bHEg zXcP=l_x*Z$x@n5kYb0K!${5XQCnr zD8|6W+a3`2pQncW#i*n}@%^3a*C{c(h1XmevCje8?IrU}o2WRn2Y82<>rBe#xQw=bpfO$QPoKgW&kP#>^ z_4l~@48A%YU?D}9q4}nr~ z^}k)Nf4q4PiR3C`*bl3kMb z?_aQndrR>QEGrD`5tkIy`WxL_!NV6g-~H#|I*Hf*^B5gfj{nTKdr|kuOXhzc{%;We zubm0^5*B;X(4dQSy%{_(hGOuGSOuQ?@w1OzuNT@P+2Uyw&i>&J5fM>WSLfjP2GZAb zErdCe{Qx-$nXp`M&V0-obdv6X!|5pS$-0de>#}(7>kgHhB7!y} z&0=Jg^(h`A%rgB1znTtEFLg02(hzBH%xKSZSV*@SNsTj8X^mzfG3xUJ$#pc<#&&8(N9_Yd65OA zH`o>ze3kugtxO5af?x;4RKs%X>4T)M>Y+I(t6P5#PsWfjVVtOiTEHVWNr1AJ%TP*(m}g7N0g_t zMN)zdy3o~tKS!ab9I_eL4_6UprY&44AK->2>#?LbCW8^+Pt| z0Y>`1-t(Ud!8DcyrxKUgLylf)L*~CJ?Q|98c1AF}zE~tkV!d2u4+|R_q^RXyl2(S0 z!LJchyxEpanXc8Ijox5N?pmF$t;5k@BU$t|@ph0ZkNF=ats#L^o&dOtxn&(V*l(QT zmq(RRL_gR89uDjxog8R62Sdcd&Xzsb7#&i}s3x6z8diQ#CRPm8cN!+J zVO?O*IeR#2NBL|%QA2<=JlO_(jm<*7nrBA=w6wMr081D8vWt=w0LzQK{^cf3@Si2> zJT$5N(s|hT`q9n_v-{F0s+s6#c!kU59jtDKBZ#nJT2Y5r2v$M-yZUBtsjo-&+sXza zEMtFG%w<~a0PBGFswJH6NA*c!9+rSw7nF*eWBiYNR;;SFZalEOK}m_*entbUJr6aH zV?7PC@Y!J(xcO-uKf*)a_h_oo0lk=JMZ28s?H59-e3s`jArv@3+HOxEhl~oG6~MAo zDYw-di4v&+Vh9j=&Rp*Oz32V~_qpdh?+-p|)>?DTIp&;We8y*tIaYyv z5APu}t@}Chmr5Ex9i(b+`z<9;XwLsl0sX@8dBzC~g(@w&I+mCW7kSTaY=<)2!#iW6 zKusmAqNS%0wX$9>)ZaC(@o86b)6c=46*Rusm)i7`lW+D9EkP!gkBduNn7$h@Gxj5} zE4qeH+4dn*Kr)$FZc+iM#n*Qb(8;*Q(GbSQ^7_P)B$rRt{wyg+ z?Z(JRT}6_zN6U|v!`ea}1l*Gvb!Oyc8I(MY%D1;SWwCS_l*e*7E~ap1Q|oZ3yoXh9 z7Q+NVLp&SE4{%+b%h?h}ao!ytaC6V_EW`&Yt@xX77T`c$4O;n@Wfr3mj3a1xkc;P8!-90jx zWTb{qjk@bFGLSLTQP`DYxAId)H2a$t6fS{VTQBdEKZlP6^4gwIp5E{CN+bD zi&&$4ASH)wp@M9rC3$(qEH1%$s2Dr!Y(xQ36|E9Ip#sMQ;Q`>lS-3lrS_A3R8AeZL zDj&*%f;&zF`N}PR^8(-mUo`OUEZi&5-+)dj*2@wwD%Oj;f8k`61tMC}-9npY)0XU? zQt^9=XHTLdv*aAxUmiG8;61AcO_b9}xk)afxsJ~!NX2t^gA!l1PFqYOYpQ{i26`rD z@U6QiW>+t+gjC(_RI^%^d1+Rod~FDw+JsepPn^jvpjR6*G4m!HAmTk|EbK3teVbt4(Q-JX!J zWuUhDOB6=l4aaSMY{4d;g>}xCq*p-F2n$)HPrGEVlf`J#k89BD7FK>8Cid7(-tn+S zy7*L<4|5wmDrI41=)oS!{mF)G*vG7P52UWyv@S2z`i;iW*$OIe06yV+db2l z%a@=@zXgp}6G3B$q_z!g*W8;1Mkd}`XfUKY|Rnh9W$X-zb`r!30?*R@sTQF;B>^*17+ z+ z?-GZ1HfwI*J~|G2qrBOEvH~GIO!aK#3g7ENm}vAwMs6PAZC7U!ML0EAoN_`2qiTEl zR80bwV^7Jstmc`@o5+#nByz3k+i=`|P7QAV$xVU;4wz!uttEe`U+oUr>j~ZfLv1oE zo)*zmQ@S9~RZ+dCqt~BYL!8x)k5(cD$c3%-z_Gm91l`Ch!Rw3A?#bCQ&@A6#)}OQF zJe|qdZDaJIx(GG#j`jH^d0`hkn&xK?`&Y!&uuS*1s|H|GT_x=*j=K%x?v-xqIV!L{ zPnk;j%H7Ve*OUG<*jW^;mFIZoeURiMjU`wrKXV$#lbsK;uIxJ+nGy|4+o%$ z(H04|dR>rVy8cTvq4PE$t9BgcwfFJ>Y%|TQ!?gxuP(@wPQOu6(scDtCRBAq!$?WXx zD#_tZSy}v%}i*n;?8z`O)<_n#!~9&z%5}YYwOK z@L>TBzUn1O z$;w}ATsTb;NF8|Dnq`2ZSR->S`PW8O+}atUl!$DP>eU=mDNEB03oxBzn*akz%f`xR zzq|xX4^-P{!UV!q5ZeAzQ&Wd=&8sVypWrJW2HLugH#pFohpzDl(y=-+F-ZkBrN7ob zfBt+=JEYh4!x=qQMy2_KPd*jp!(z_?2!zdA`;U~imG@>Qsa~zI=FnQJEH&v#hvA6f zQcPOkgh!c|dcnx9TW8$1vPbJ?dZD*#&+7bnSogf6G5@IPn!h(FjRgzlcnN5&QqJN= zh3j7;mUwU)W*SG|s%`dUUiEcJqXzW8Rk%!hGyeGI8`Ck6Fvak~mu_|f#CKwwhSVQ> z@(I%6C2*lU|I|;q$Vq_-Po#Am-w$b^Y}}E=3qfmhTmaT301(`Px8$rGXhYWyeZK+y zvB%<$g-chXXU4r|7g0D8Z150vwz*{;vbk2lyBvYG6Lwz{NB!Y#1&%mj1E4W`GGr2% znj2TDn-*}g?&A$!vk-)AT8dYtY}h4q1=qZe;q5>W$eBhm;Pp2-Rg{luY`pUlAvva{ zcOnSH-w?1Lo;X}HL6?vb&Vob~7Sz`a6utYnru61bqQ^$UX39IMh=RKvUmqbi2sk8d)g zUma6BbIo^=AHs|fJXioe8hV?R=e=D21s(&mp5!>v6LZhK+O4xUO9gRE$ORe4y+(KQ zXj#Lzt|?YoVmZSDp01JuQb0n84p=;r8Ujkvdz;^HR;aBkC+o=csBSrbG_~x!E1q*4 zFzN9i$olo^RiIXol$FcX(LfMss?2%Eyf~VOpLv5T(&dE+*w_l9$pY^b$k0*L#4@wmj=#lR-lqvH|_^Dg?EiuLV4MZvvN_xdJCPheTxJ zA(8j}nFxtu6SHT(Si7B=kPQrWkRu#0J@u+C#0cPq6j<;llWtAW$heVS6r4;8;rue42x7> zugwps#_tVqdM_Z!Fh@yHzp;C-+9~1e&8eLFFbj&a69*BySTq`bb%xnh$-d$sg}ebIJ0-dg;0xRu_O%&w)xyIS40RSp60K39U3zjfS}7e1@RYzs9Qo)X76*iv!A%H%1&cXB>bNY$@& z%}>Gz2rGTUyTr?Haa6Xtb!X7rvu#bH)nhjIAR$10iWrU(r|qtf1)IMnG&l{M3kxHu zsH_1E7kLR3a3}?f^Fzy@$pWS75sT?YmoHt4I%FGS@IwK>&~MxCfn(JCez-eNBu#bP zxd0u?@EAhZg)+xf9d+Sj-ZSm1?FZgds0K#jInS(CHeK`0Rw{)|Kta~k5Wo{mHQ9NU z)W)5XyFl9%bRSj%a3jWxWtuZ?mgJzDtp(R;^Iq6|Sr&1I9Q0^E`_V{nF32Qs=^C~2 zBv#nlM=umO{}pXB12@Vhliz z9T=APLR#FtZl$#*rQ)3{Pr6DOb$?T#F~P@-XfZ;Msw**I40y1Pyg z)t=E)Roi&CpRqicp^r8=O^XZFq&06ZxA|Lz47{G+b8q@|@b1#;a@zI{Rz*!Yk~*>Q zz~DpBFlWMjG}e#2sYgnZfrnYNopHvgGw)oh0S7`<5H0*ksrm(4JTmK66AP5F`#G7Y zdP_(}l;jTjRm4U*8FYPSZ2sKNMp30z&8}@Z-zF2owsXcajEapbK;hjFEr*f?KD51A zN;3*ZC;KKxXlAJX2QU$n!IhFJT|alPpvH=`&#%dyd-8?D`(|`mu~Vwt9s}p?qPqNx z_>&qF6GL&F%{vJZL}M6=gt=R=N#Q}uH7Rlf8q~yX-vZ7;)%NLtk9#TznG1SWMQD>k zu;*0}A+8Ur=AjOEo&31iLX{q9N+u4PjsQg0SH^MrgUQO8pj+a07(_uk%`J}OpD#6i zIR;x(Af!!jI00Bhr;EdX#!6>h`4N*TE9x(l4IIp(Za)Xp4{gD|ykM)xOmh1B%Gx{X zrh9I$92?2Gm*OdLzZ^0;Ix=miPm1eCg9CcN^%{Dj)fJnm>S@!=SXt5-IX*oxh1O;+ zkD&FLYJ{KLfz=!b;#?Y29=kWB&}M6@hq3itOy&i0WbwE>%EwR7efWq>r)7cn{$gVz zG&hK#^?!f_dO`PX`!O<6!zN^Y+G~wVRBPssySO<1B=6mHOE+QQ6_wWIM)Mkm0Y0#T zILk9Fc=ne&$h$g7-wF{g)QFO8Eq^Zy1Xze(2eo)0< zslG)ZsiCD3>9IUq4i$mU8WTs)@->3qZYezu}}S~WY{ z^A-o-)GE2n_2-N;z=~XqR8+$WXy0U(2U%F&YOg%3C014bu>KzPC)zc?IS|k9LToX~ zMQ(r86p0l%y+#SxNYW;hAHO8Qf0s~p@bT?zwU`GP#&+*FB1)T-^%ENe_D638C>oVa z>lIarkVe)1Cl_Ej60?x0iuAy9^dN_X0O2L3C8qEUa@3+@VtPWIvM`Tsw6gZt2QaJ) zTwJmqlUNlI7l=4SEum9}JCo1rxHJ=32(QsKcYLXVhl8cLIT91bskZT8l1}I@5wD(T z4Qy~5yK2$k#`W5^<~(Dp1YX4@;&6n~TB5M|uut03R7c%Kc_r>vPK&^+LeDStT}U|) zcMA~&imVA3iJ4XPg7_oZVG9g>zcJx&fDK1<$-U8C8BRRB7^A zTD5I9C{u*`>gDWAj2qort;bEptFqqy1~NpyvGePrc6Zz+Yivobp6Ip4fS&`{g-TCE zktNbY1<|2k-W24J=WOoU{gT2nPf};LWf>%Ihni{wSnZf6WK)eVylb%7NUc_x#bfK| zhii@ciuW;Qa5a9}WfBY6@;#y(sd7xh8th$P-Nc52qpmgT-Y*LcWYGL2aKC%EZpEHf zk(hn^IM6So;!aO`vr#2LFCrzmD=7kN8CH;P0$8_mQN_F41u)82v+n2q&C3e-4p%|= z0_a!43bFTDPDL&EzP(7E`euuN^nw}U%8qawtLxl#`BQO;tXZN6lw_txo7gp<(lMW! z-xv?|qcdkqPjxBvqy+(Vda%g5RiP!sJxHkf2x7T~I#VSAsBRuK_^gEMepj)oeb@XK zxB&qGm`>mnuB*~IgK2T!vLc47ttWCinl2AX;MnVvlatNy&r8xOqgwo^Z;i5T*j?$8 z-yA4K8Ma+zwtn;HU3DY5dH&|PoN(uE67B7}Z_^#dLVtxLuC6Tl@)m|&xRkC=4q<%D zu^@9O^{TGaYUJsHo#EwTR6J9iZESh?@Zpt+j}%Q-Yv1@EY|kUECpJXzE6V%-J@9Kb zFUAobEM21EgHx~YrFjrrW_J5kfL$&h(~%fb$N9j4=UigJY+71ZooW&EklaSD7#Ea2 z;zL6+%mYWB>aiS_8Pd&`sBl0`k%YcTFrMW(hwLgYpzeiMctS|?*+)~AHODuad<<7* zB6Us4>s8?ry561S4R*25e9pwo5gD{`)q1%r(7XG$2MWm5LyG&@-k}dA4$rjyQb&TP7J-rLPOldIA?GXG@()$_Po2wIjs5Dwjmav@V8uq9J+zpKm>^-VDlSCim4)MmMSu@p?(1_499=fS9O zS#DQ+_VIbnIM8CLO1)LFm~1w-%DaEub&UjRnb^h&H|uKX+<2o8jo?|}G<41X@of3g zF)9B~lc41&EIj1urZ5zUQ2zd%))C5NwT&-@3of<}ea}g<^`7mEGmvS`^x6HAp!U{i z;wdH0+r@oihI}>j)5`-Ujet@*LhnP-W`>PESHILcpn}Mf^G3d?(bX1)1?ag0-dJMt zT-a^krr=N&*4g-~0$}VBc#J!5k4a z#dHQR;+W9*>~81=mFO?NyQ8t!o^m(Tasarb)59Qh0`iKwm>VF(0Q>d+4c1d;hbT~M z2|V^clksQ1L>#MH$q9|%s2FJTpRms`2Sj4dR-6*?gueRj{UU<2En2M_Locr53=2mw z(HkS4efo!`(Yh807oIm^w8We(6EoI%EsXUhH?jmCsF){|r@G|?;M?pl*zIutrF0$X zw$?#K;ecQ7n|8V@R?v$6HY1`67{t_1J{$U$MpA{x3#oRlPlSq>?9E{IgaAwpO%si? z37{8kbku~M1nX*V7eA-`qdmoLs(sSH97NX=AxZ6LcjNi?Rtw=tT%XnXvIJ#}14cY3lO1Am%d9_M&zDmBzE!Z9^2ycHQ5|%3G1v0{t zo9Hu^Q-GbjXa+a25a85UeHOP3VmlQ#DO<~I^8yMk+&BFuq=bXdu>{0H=XXA{*!~>G zCa~1{wmW1hh%|84$ShFr#*G^do@5QjAP~t@695?Lmb@oP4e+Rf>>@sopwQ~b^3B_d zWVd<{o4O8}qm9IG4n3q<;H7HU&wMMNR9Q5`Yy@(1|I{0>Oc4t1O`tGv;!tp;EATg} zE9J9^1%%E;8_zcL)&N-APzA_&6>`iC)H0j^?ti@IdgjKw%IwTANH*r4wf%*Ptl@*( z*7-OW6{H&aE)QSoQ{S$HVk%xXkdsu8+kV(ih4<@YN| zHf(GU$gy`Uz8oc1ObLxeETsV)@0+`ol4AGk-K4K3I_aB(-OdJ%0z-@@Wx*rW;$8gM;^8MMG0yl3~l6tLj_6h8{t7 zzJ5*LCR-o3hC*bey|2$D^cRcL4CmMXxFB6n(&`f0KqkB)X(I5+PVJ$QKU0qB?J zA5&cou4RR7n^O14nmZphhzDk8hXJo-y0I_dHfp&}hXlv9;47VnnidCjo&d+ZJk&j- zFPG9ut%*U0UOuLZ_kncGr%g;$ik>oB3qyeZyO@v=k6Lb3pLg`U4dx$;vr2p^Ow0B8 zOo#QqU^lLR!>Y%TzD(sGk@u)PrU|9ZZl0X$J*GK8-UN#+e=9OK@T%vo4d+P9RL2Jgn#Im ztH$hV^VitybHz72M2vd^Ua)U_uvB0uf1T`49(C@22O=rK6wp+qkNh1>m|(}g?Ip9S z`Ii87z&^vUour#@Iu!`kd>}B9&1?li1_sS6$7}HJ0FoBL6VLxvF*K;C;2qkTF^<_$ zscv50;#XOC{S&QqKy&}dX0wx(IX~p?o&LZIgILWD%K~!W!)%A!&?LMO3375%e|8;F zTtB_N>7J}y)Zmmm$yg!QNON;@x1+Zgg;Z(s%EBRYN&KKDn8~ss6mA?1+g_T|)>OWV zxAbfiK(@8yeT#;~%dhPGtJ}CVR z(CWv7IR(?}ML|k~{L=$Hy!feZWF-O$litr!mc6Irs0}m|2#7lY0N4Pw9Hi+56s|V8 zn}n{9ZDh&^dZqSB#~ons-KsFH%D2PD50v=VfI!)Z1UVeUB4nLcegg6`O4fJ0VXhw? z>egUDo*OUH$*nvh4-ynT}J(#{+nd>n)L?A6?8tzA`PeI3Y&?PyBSj2|3iRm(O4Z_`uX~ae^<%BkNkgn zQGnpj4*KxCF7V&E ziFiXO+W|=obG-jnO$C6hW&)rP^2u6)9b=m6a^SQk>fRDi2$%G(0fN%E zDYeXq(!pm7!go7nfGLpzw(TSr7nHKGC?C)-u@*Bf4&^{TNA&+sVDPXl4tTC`S-Yu? z6uo%z?)uKCTfMI9BpyPa>%QCTODTU9g4lkCZFQS86#NdfwFNo!aoabEwOY`GRN612 zXGyJR4Ph`CHxEx*1r$%;tO*km3EMD;8;9bVy}y3gW4DhAT1+d*pjW+4d+$W?MBHK7 zTUdgmi{EYB2JZU~n4Nlpg6~*`jmHvy=Hx=;|dVxywTyF_0m>M|?Dx7h*=H)nT9&Mv!(-L%4b;Z2!45XJ}IO{}Jfr2kHV$muL*E94wL zCaV@&E&b3IsWP=JDk_qlX{!aoSgzMEnzi-oNSpqvdY`5HDG>nFPSfIfKYvvX)p-XV-QK;D^(WGXI4RMp0dlSanXMd*QYKH3f&o2 zDVEv(PJ1=iN$q=UvK+vW@OxqjoZkXK@Y-XCN-~Tq+Q4Vo@)xOX>*I2V4@=mb*^Vm7 zlkg8AHP5y~`6X5BrQ!cJ(VO#7L+0!ucW*c7)rdot>e`!5Iiz4 zHa4F2O;D#}2JS$?NsvilGFfvNtoZUj#M_$>CnA9UrFw%`UK)1WbWn2BWF zE}&aeRl}H?w9d#`I4*b@z(oGF&oT6x@Lg5u*6%x`z3Y_+-&}L;p zhMq}Y&w}Xh%;WOuS{~jpVUVLI;ct@-av@1u&#M|^E2J@!!hyeDG;Q}yP#TQFP5_KH z-PgRnCFoK{7(V#BAJ3nj6xWMBWV_>;+OP2?!X)q;NQCin5zl=V0!1>#VBRL3-Or6J}WYpS^Qlph{j!vVQRG-Ob9@3x-4Yip#(^b^;tW ze$`Rh-f-wH5bE4E6(M+@mKXl(6MLF!o-*u-q3Zwaz4IW4)Mz=NFGmHuv7(`25(W^8 zgc=j%3C7;PVC2_|T}FwoRXnUOo{kq(C|8SzvhcY1_%ej_fubuDTFCoHHJ%W<=5x{C zs>Se5Dy|YtI@$xekK4F)XrdrN-DZ6a;-x`3xBClb$ZG2zA^lv%s%}@HGA-BFCIcDC zUrEf|slle`E!8s+j$0t^$eAvnU|Jk1c6CU-tUKms1q*aiv zXB@OwXW!GU+e`&1jb4_+QvbFC*t>i{sM=#~^|DT+Trg=x_eaiZr>l}&Vx)k0=ves0 z?I0%cjd63|Kr~3G5&%g>_E?#=oqMUhnFc>LK{&g566Sxy@YUIWRQuN-Z^CLO=~76d zFvJO|crH%{(sAq}5@v#m@+@gLJ1knH-pss7)fd_52{d*`l6DBjY6%23h^c;d#3!U228Is1@H+5-2mn<*68r7@qz>MnmqgJ(dMRVo+9*to_1pWF(Zg84LK1 z)BaOkP;yNj1M)SXluE=zfd{vwWu|yKWXbX732N)+lOa9sDr*okd0r<&>q1Ib;F64) zH5au86Q&mmvPfa0%!F7sML{kuh$S8cQBIfPnhe{(^Lra5JzfhyaKQKM88;uuMG{Xe zO(1Iwf`>Ik|5*(6Ec750UD%ZSI8m)^|z$XxbK-U0H z-=6FLw2Dx8{To$Xw*i?4c0loSaShbn)_KAC(*b2os*|9g(&zlTZw>wbZK@c%y{ z+=VDl*Eh+|jH#Zede*k*;9{n_>tjiaCb6qAkp7J8h)M7Kd?0IU`2si*Xi@f%k?%Cv z0HJs-gOtvJhOuh{<+}BAgHF*DB4(#HUgZKDhl@nO-9v!b{2(<6`I{ zxJc*^PBZtEtzM20IQURS^8i}rK@>P-t4$ED%6Eh}4xl_yb8Rmr&_(+F0fF4aDw2u#Rr?13j>a?{J{O&bM-e+bBG%g7hRsLoZvYrmPE*Z ztusZg(T!BH6&8VqD68+J0^wH@4tXju5 zE$ozMtC~hQcMfwf>L<9}ZS2RTAguze18YQ~g(z_Q0)?{}+lEAQ86CI-?lZnQ>mfz?P=Jh& z+ww1`RX^bT<1YDXQ9W<_et!&4fh{W^jRGFqM*+9*e(IF(B1a?f?%4!?GxIob-w99= zFXl%AMnqrpsv?+EyuUwa()K*GXamHFh_aJ@?-jL|*S|2!wr^E_l*i zsIo@n0e9m6%0(e!Q*dJ{hkcu8-o^3;BC-b z^Pi5l{(Il=w^DHY+~Dn%V8}fnkd_6rE9qFvh>Pyv9R`N(ov?!Qpt9aI$C5dua|w73 zaVN2X_mo_a*W}JDpWS@2{XZj!?4-&^Q}jf*E!~J!plecGVpZq&b{GC`qHLKxd5EU~ z^ziP7ld<`6?c7!3s2|n_Jm>P_jI-309XjXK`(W)i;y{64ziIs7IBX*U8TSe0X->9& z%%f0FJNCh4Z*5_g-rweVBngbq=>u35q1}<2|C0;Q#EK6edl(`GINw)s!QmE@fx8v8 zR?*;<*Y_hq(!vHcuBJoVt^^OJ>%hxGh2g*T9XmNPFpqS_AmQ`()b&t0FWba|ZS#<9 z{XPPS;oYgB*$#z_*x1`gGKT#@@;=);3tlO!69k*9SML>ns{qp44_dnKKp$+{t22-d zCrv>@{l!`&`e)|aXKDTlwkQ_Mx*sH}F7`s~Z|-|@x6A*d=u=Cndt~XmCN5p=?r&{P zwRk|NyC@NT=Op*M)b+n~p06g7CJOJ5-!IM~i~RL9%iCc^FS#qLD@22krbC`}XR2gb zk5Y>)mL?SS|MjxaZ-!GzU4&}tiSq@YPhfj?2VX@J4sV*@ zw92?~(!9Q8+$nwOZ~t62?+x&Bz90UXIk|o-aaga?vQ6D%H?5EtZ2f|sDol`u zgwj&C?tw`{+v*D&_V3WzZ0K@-&yseOoSuV@;3mDfyd;!&(aR zg;NQ6gW%eAc18)gm7jy742<+7cyhRYD7|9~VbUxO9qf)T^{qf+drw{VwmztPTnure z%(#7jIQ|hpP0!=!e{9cacNZ2a-c1}n_$}Dp-Ob!l5#mCGhN91>$r;hNgyH55Y8vQK2sL=aD8DWz<00HDgy#?DhlE2E#|d_R|)q0k>G0J$`3PdYoIgO zep*TJ&^KPifPusTi6m}qMP#m3_N{_T$GPZ(jEa0T`YgfzgUAg-!K;q=x20ueV36Qy z{{>@OS)58e{%6b4bQc#BSd} zwr9hoHJ*_VaaGY}j+{8(OQ56ifil@~f3Pjxs6ks#!7(8ot3nU*d|65w{^6D8iv}HR z&y?GCUY;qd0z%zaW-P%gGnz@g%68`5xlVmy{*xugqHT6tv=VIW4J=H#Rm)wTe0f`L z-ux6~v^J>BU|KZ{%i@)&GdViiSX52ciNHWzk@`?-UMMU4SEMk#k*Od1;-4OC$`4)K= z%t!wVUn!Y*nK0J3fvRBVDersT(NirrI8Q~oM;tt4mp*FIj52X`JEF0&S$__5M*a4^ zqI2oeliU>0@aSb~SVF}Yjo)s-t%UTe^;he#=sAt5uTg$AZJ?sV7vA%KmX;0n}y#5{W>cc zik+bt*^K?9MI5fR2}&j^!E-=ir7A1-S8Elmm{SuQhNrMztMdT3Q7$IHUg6=l_oiMwoG zQ{z-zufRF=XS1zMRAl{NXL+Lu_VbwF)Sl{WXP~FBklCJH(3kl`;vy%F`uI=Cs3E5A zq=vO~c*+Z2IybfH%pO)1j-H<0U`WYm6IP~14NQjajqJOQ{ovlSTuL$$JYRIXS-R+E zkN&fxRZc?@LfX5AY;5Cs26o%+8<+MEbsCl#?@Ub$UHz-DQ+Sv9IbfA^;1tCyEMVnv zO?}ne7|OeIwA@}7r{!`#@(;E*)$h;pWGgNA`koTXJ97z(uPN*HJ;dg7Jp;pRkFA}} zGZ&W8sJ}X}8NM|VV}NkiA2$!Y?aa-K*eSSu<3`x(V#=xE(;oKL*X-pn8r;4JjyFpd zca2vid(3SzjKjigRu_jscOTb4lS}Z2&HBJakqIU zN95d9)9!VMuxPJ&ttn&T>DU8ir;(njGBQsFhd%lY}m^4&R-1#!E+jn$tl&>$!F2eLyEAL+l>og^sM%p3pU5kng z&lqUIH`r-xrZMu#A6G&r63EDl!mYuieYRhEa8>b|dn>P-R=Z)co2zFB{2v8!^X~12 zzEyQ~-?OP;K) zRKai}Ht{Ml)w&gS!=oDX^ok4ZzXsaYi8AN%tCwlCF|dlKkeYdq6&2W2>cezR?q?=b zC9WynFpM|x7*C^~V4Hh%K~E@0w%&f7;rfKx*Cy4{Czl|3_ek=&bHzCtg=1&tcY3hx zsv1`=E!}mf>FJ4?GqgD^+7pcZN(sV_@g+pFHoL#nx;Qi96tv@(PO7h41}UyIX~+iL zO4wK=NPoSSUHtBhX7}ZLl+^k+9bm~(u(rW!>5`+Vuu0H_lIp86*bv=qS0Ex`IZaVx zWkciPtHREj$L*OU7;(+9v%TzY_T=ccM?ss$16^+_CA9)UE{_zs;PSdhikD;L!F>Ho&r6 z#)|`O0=T0=p$|cPlfN$5d9r9+(+f^98#uzitI9`}&2RZgknAa!9uV5%?Mv7;b7kaEa7 zH~I(#=*U=D%E3aR;F;H=axV*Mq4Pf)c4@nFmz=jfn`Wv_L&;MJOg4wBfBQ}bzC#CB z4UU7fnj;rJ?(!Iw8BcD%F?+IApkwDcy&Ou(u=f4SDrmYX_R*X#7~oVoD^xl!G-M22 z`#FDSeSqur_8K9}iD^ux8K-I!uE-`QGgi zRu3n3YID9VVI4o*5y#pz-usb zYK!grBWP&_fu&_#75)d?>4&#-2Q!?OCJlyMm=e^%OIt!iQtp*O`tJDS^S%H-Zjksy zqQ|vZaXCSxNU+;;=Fk`x*-`GV!d+r8_3|mZR}pJ>e3nF~^_AKJ9-JL)V7K`uaIS6n zJ!)24*ViE+07tX!`!i{sIU(X05g^*R+7~3r*1$`C@2#JhYF9kHFVR)%p)}qw4!*$4 zMgN$ar7z`L3G7P3BO*IUGwJ<$NcaHxuoIPpx#-b5i=ud^xtfxbBl5%f+9lnWg9Cp=2^J9hoW zg8!OSN4B0W)9UI-vsj{|o>-|g+)XK!9+6S`S$;QbTSl&!IULhzW^833TD>(4iD2m2GFiKxLZ zaW7t>6av+{6oyM!LSnnB&O7z{*|gvOyM{iW!*uQc{&l>z?V3AE!Eq{8(PfdiL1M47 zo5*WeBJH*)21>F$TV?#Sq3}&VF0nN|T6;@dy)ZKw4tQm1QKQdCx+;W~DEUk{q8^phj`?T+QBhG(r(zUJlPccIa z)70MPGl{8LqfFF9zkI0_CWCnTsd!_ZgL8R;)M)PykT2R3mGAg4 zrkaefygR<0XDyXI09KTB$eTWOxn!@()_e$=_kWTMM_jdAtgFy-qWgC0olfKh$g3XZ$%LJ!uJ!on^G`ew za7~$g>OH>sMXob1EC4pXzF==T)TnbW<_Q4FQPrB84WA6mGxrRN=xhJ4#y~YVyQ3eI z{ApD+Ph+itiI2j`NL`LTB+hwHu%g2CYvxjeQ(r`^H3H<_$E%tUMv*lP^lPr?0-+IgM~0#vlkTy$MLI9FFvL>ds^`a z1_nOF%`1IS+gqF9!+!rU-!lZcoQ~wT>1#Q*A>!UUaEy;l4l`Z$VFCt#2YLcrMcr;E z-WKP!f&d;VW@o2$j)-)v?wR|ghLFPE>$!G25Sd&$Zj(zj1a>|T-l#@eS*8yl2RzpS zz!uVMrl><8tpe52`dJSh})3y01f%KO-e$wo7M+$tt>eaS0km+b%!mJJHQgxUoL za?!T1T`-cR7IyG;w%tgbl&q5Pe4uyc%0L=daLNPZf*+AFFv)!}HW7z~Gp zZsK_}jj39M#Lh$_oSa$J_RJn+!97*MkOHm@b*aE2_Yp^#R`}>!HUcO;Cab;lx z{aZtqH#TaZcWQ&5kScwpG>}35?mJ{=UOahHnerUFJZ^AOX=lhW zx*V^La<#M)VSDC7CpNoZ5wGO2MMzC{xV*Xpz`xZk%Y~(L2Kb+$5Y*IUEf;}}HL|bfq1i+tJt+B3 z(Vhll!B;`SS63K?EY`5AeE;Jk)45c?$en<9un|A@Lt&Aa{m^@fw8(T?Zte6{JU=q` z!HsqV(xSN&5v>vGahfNd6&4wmZA>DNj%w=cY+h$&WMtx1Yi(CGi!Fb{=#`ZxBXw1^ zKA(!sF~tiXNEHA($$AVv=T|N~*XTwPg8VM~8jtu~6NNWx8f@3M@dakH8{?d00bMoD zzeT^s7Al?rZED5OpOnFTxJD>qyIyEmmZ{`QydmZ9S_ZjElyJ-81?E1saijs3$#V|D z6(ok>I$3-a@(CcvJudeOpb35n0GD2t{_}=`p+zcijRB3MdrA6IEIs8Q;6rSHOD_tb z(38oi6Q&rc=+%wKKCe0oZ?JQj8S@o z)NBIqVB`UFU>9+eb_yFuga7W=nUZ)xvgScfY7+IT6KL|FwNJ;W6~xZ6sZ66_6MzMJ zr6ojGiilfG`{x01@K2tCcv?2~>Q~TRE${#xtUvI8*JuB!Mjh~zZsygml@P~vE$6Ig zQ0L#5@|;Mf!0-HUSyLG}JL;c7f1k&n)zp-!ZrLgXUx4!E0dfM$SYU|j$5xg^u~4?j}g;v*H`Lskdu$uqW>g^JZWfiNq-qHu_+IZc!f zCj31&IC3kxQ7>`$SWe*HSAIFPZFLX0_}o<1!3v|y2&u9j-+#kUH8CTD&n$eg;UabN z5}0m4^gcGRF%U2d-)Z>T!}w6PejQL`sb;C2+tupl0nq^6;Jb#^k6DQx1pS8Cx2IEG zuPCiLoq($Wmz5>^P*3m2o+?Sx2?oM;B(3K~$v%2;`=7Vpyy|lc7cdcg0jvUxJBh=6 z0IOrgJ(Xoze3h2KL7eC7WtPmrjjxWl_|JdU-U_C8RthcP+vGI@zXbkXO2Cn2dv_bG zo%@MS*gx(r4L`rZLr=ox@!Y+~UQuRm4!@ro?qziy@yK8UAv`*NLb z;mdo-rNpAi8G!u^R4d5LfCK2*v}IR_fXf=O% z2L@^t(lOffT?(uHIH|}@=*5|`S7R2>V1-T+uqm|#6go2Gx3c7H@HKT%b> zCB!WjE`J4Z#|QsRzEdCYqd4F@&fBi9QsMWEJwGkrKlQw6b%|m(TH6LX=pK0{sOBu7?KPtEy3YAWw^i`e*?8z zRA=GNpFpQH9NF9qlnpRX06RE5_7p)WB4I)3_gatfyOr2}))LbwA)&M!`>kfTY_dVl z&v@k4THg4mr4e5+6Az%d_2O8Y5}^nP{&X4y4q$g5`z#nA2M$(2VZ+6ibUtky$vWQ* zEBeRg?=POnj_f&r;>9L(j+OgsTy#{vT%s-V2xqhb?utoh_&+y+Y$8-P0<4^pX z-Wd5iPv-fpf0G{nEqeIhNB=9P{{xo9rC#5CY}Y4h>&q`__!F0$?QA!f?FT%s2ll!A zhwa@G;G_G0RNB_7r^}Sx_i-~Qc{yicbK+HmU&3IWUX_hy^~lJGWBiCi{D2pTM=?JkYKS#?{RY)O(-Sd>wH$GgAO+#zM~`E0)X5@c zpc#0~TDRNzm7DTSTqtw(4%3ZIYi2k|v1F?+e+r(3c0WJ^wXjW;_$>p28}(S$hGjwr z(7B@Lo^&L4kJdSxwNh^y9dlh;`sS{LIbMhn7GL zuHLaaYD|vM-k!paW!La>c>~`!XdxhAXns9NhNDxD*Iv^IxSa;_X7*|LCiqrA7Fw!CJq&Qk|pIh?OHt`Lat>EmO#rVOF3Ju8F zg#$i}JA+$G*O!Q{{q!a1v|$@a*axcX%sGQ_7iN%PsYva z_pyCV0tUZnWq*p@V$}Y@PQeAETHl`KoRQlT^&wp|v9 g|ni!Tp*8LV{g;Dph;|( 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 literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_darkMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_darkMode_desktopGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..046d31c7c316d4f88030114783c7c9bf3cbcd3ea GIT binary patch literal 32618 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 T^FNhu<04Nw{#f$Eh2Q=MJ57gu literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_darkMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_darkMode_mobileGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..565ef428351e4813b8ed02f2b25407b4bc6fd02d GIT binary patch literal 55060 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 z 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

@ElnDzgVFr0*oP#xBPZ#fIt2Py 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 D@DOJI literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_lightMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_lightMode_desktopGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..9b30f02df280449928c17d6b9e05d59e4ac2cfdc GIT binary patch literal 32600 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 literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_lightMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithEmailMfaSetupStep_defaultMaterialTheme_lightMode_mobileGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..c9fed4c0109ea41488d656ea6ec4d35ba27dc4a4 GIT binary patch literal 54658 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�ba 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 literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSelectionStep_defaultMaterialTheme_darkMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSelectionStep_defaultMaterialTheme_darkMode_desktopGeometry.png index 53c27c7301fe3bde87903cca1c680397c8256ff6..8a75ce5fa1526d1584cdf9809b234d9748536f44 100644 GIT binary patch literal 45703 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%0D+qqY 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 O?%>fM^8az}>c0USTtV{y diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSelectionStep_defaultMaterialTheme_darkMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSelectionStep_defaultMaterialTheme_darkMode_mobileGeometry.png index 21795345c9ca6419e531192c6a93be2b75fca29b..dd709da29a5e5b033f30d4c03187aee4c62f8df0 100644 GIT binary patch delta 25067 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 delta 21974 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 H_sRbQ8Jh=} diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSelectionStep_defaultMaterialTheme_lightMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSelectionStep_defaultMaterialTheme_lightMode_desktopGeometry.png index 17569d4a1182b23426a9964dce1380869d998cd6..6e1e3bda1d3585af6ee1c1782185f98f1e0b7fe7 100644 GIT binary patch literal 45625 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 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSelectionStep_defaultMaterialTheme_lightMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSelectionStep_defaultMaterialTheme_lightMode_mobileGeometry.png index 1a8803016a92406def092a8129550301c04eeba0..26145cb92cf787bc3b427cfb4f5761dc2f2866fc 100644 GIT binary patch delta 24867 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 RCHS1R)wxpz-(UFWzX8uLk9`0D delta 21793 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 O-_bG9F8TA}i~kQ)ABMvK diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_darkMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_darkMode_desktopGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..c7f2fbe43ba330652afc0c6e6f33560cdda6f1e6 GIT binary patch literal 45076 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 AJOBUy literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_darkMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_darkMode_mobileGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..a25542f90fb18686e6f01a8c74aeede94181a8df GIT binary patch literal 83913 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 literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_lightMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_lightMode_desktopGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..07ff1fc98cddf0cb460e5b9d981fbcc8f25b1091 GIT binary patch literal 44850 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

N`I&P^WX=#McS&j>T4~>X4rWq-iV!i}G=c(+!BO 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 Lcg5dc{>T3U^;>pJ literal 0 HcmV?d00001 diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_lightMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_continueSignInWithMfaSetupSelectionStep_defaultMaterialTheme_lightMode_mobileGeometry.png new file mode 100644 index 0000000000000000000000000000000000000000..5f27b9f6a50f92284d2348395deb892052bfc762 GIT binary patch literal 83630 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 { allowedMfaTypes: { MfaType.totp, MfaType.sms, + MfaType.email, }, ), ); @@ -87,6 +88,16 @@ class _MockAuthenticatorAppState extends State { ), ), ); + case AuthenticatorStep.continueSignInWithMfaSetupSelection: + baseBloc.setState( + const ContinueSignInWithMfaSetupSelection( + allowedMfaTypes: { + MfaType.sms, + MfaType.totp, + MfaType.email, + }, + ), + ); default: baseBloc.add(const AuthLoad()); break; From 6cd3a623795aa587699a0a4e49285c3e288792f8 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 24 Oct 2024 18:15:09 -0700 Subject: [PATCH 159/159] chore: API Name Change Amendment (#5602) --- packages/amplify_core/doc/lib/auth.dart | 2 +- .../auth/sign_in/auth_next_sign_in_step.g.dart | 2 +- .../src/types/auth/sign_in/auth_sign_in_step.dart | 2 +- .../integration_test/mfa_email_optional_test.dart | 2 +- .../integration_test/mfa_email_required_test.dart | 4 ++-- .../mfa_email_totp_optional_test.dart | 6 +++--- .../mfa_email_totp_required_test.dart | 8 ++++---- .../mfa_sms_email_optional_test.dart | 6 +++--- .../mfa_sms_email_required_test.dart | 8 ++++---- .../mfa_username_login_required_test.dart | 4 ++-- .../lib/src/flows/constants.dart | 2 +- .../lib/src/sdk/sdk_bridge.dart | 3 +-- .../src/state/machines/sign_in_state_machine.dart | 10 +++++----- .../integration_test/sign_in_mfa_email_test.dart | 12 ++++++------ .../sign_in_mfa_email_totp_test.dart | 12 ++++++------ .../sign_in_mfa_sms_email_test.dart | 4 ++-- .../sign_in_mfa_username_login_test.dart | 2 +- .../lib/amplify_authenticator.dart | 2 +- .../lib/src/blocs/auth/auth_bloc.dart | 8 ++++---- .../lib/src/enums/authenticator_step.dart | 2 +- .../lib/src/l10n/generated/title_localizations.dart | 2 +- .../src/l10n/generated/title_localizations_en.dart | 2 +- .../lib/src/l10n/title_resolver.dart | 8 ++++---- .../lib/src/screens/authenticator_screen.dart | 8 ++++---- .../lib/src/state/auth_state.dart | 4 ++-- .../lib/src/state/inherited_forms.dart | 12 ++++++------ .../lib/src/widgets/form_field.dart | 2 +- ...faultMaterialTheme_darkMode_desktopGeometry.png} | Bin ...efaultMaterialTheme_darkMode_mobileGeometry.png} | Bin ...aultMaterialTheme_lightMode_desktopGeometry.png} | Bin ...faultMaterialTheme_lightMode_mobileGeometry.png} | Bin .../lib/src/pages/confirm_sign_in_page.dart | 4 ++-- 32 files changed, 71 insertions(+), 72 deletions(-) rename packages/authenticator/amplify_authenticator/test/ui/goldens/{theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_desktopGeometry.png => theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_darkMode_desktopGeometry.png} (100%) rename packages/authenticator/amplify_authenticator/test/ui/goldens/{theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_mobileGeometry.png => theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_darkMode_mobileGeometry.png} (100%) rename packages/authenticator/amplify_authenticator/test/ui/goldens/{theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_desktopGeometry.png => theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_lightMode_desktopGeometry.png} (100%) rename packages/authenticator/amplify_authenticator/test/ui/goldens/{theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_mobileGeometry.png => theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_lightMode_mobileGeometry.png} (100%) diff --git a/packages/amplify_core/doc/lib/auth.dart b/packages/amplify_core/doc/lib/auth.dart index 79cc4e0858..d4f33ab4c7 100644 --- a/packages/amplify_core/doc/lib/auth.dart +++ b/packages/amplify_core/doc/lib/auth.dart @@ -146,7 +146,7 @@ Future _handleSignInResult(SignInResult result) async { _handleCodeDelivery(codeDeliveryDetails); // #enddocregion handle-confirm-signin-sms // #docregion handle-confirm-signin-email - case AuthSignInStep.confirmSignInWithEmailMfaCode: + case AuthSignInStep.confirmSignInWithOtpCode: final codeDeliveryDetails = result.nextStep.codeDeliveryDetails!; _handleCodeDelivery(codeDeliveryDetails); // #enddocregion handle-confirm-signin-email diff --git a/packages/amplify_core/lib/src/types/auth/sign_in/auth_next_sign_in_step.g.dart b/packages/amplify_core/lib/src/types/auth/sign_in/auth_next_sign_in_step.g.dart index addf8e6b35..6d480f1414 100644 --- a/packages/amplify_core/lib/src/types/auth/sign_in/auth_next_sign_in_step.g.dart +++ b/packages/amplify_core/lib/src/types/auth/sign_in/auth_next_sign_in_step.g.dart @@ -82,7 +82,7 @@ const _$AuthSignInStepEnumMap = { 'continueSignInWithEmailMfaSetup', AuthSignInStep.confirmSignInWithSmsMfaCode: 'confirmSignInWithSmsMfaCode', AuthSignInStep.confirmSignInWithTotpMfaCode: 'confirmSignInWithTotpMfaCode', - AuthSignInStep.confirmSignInWithEmailMfaCode: 'confirmSignInWithEmailMfaCode', + AuthSignInStep.confirmSignInWithOtpCode: 'confirmSignInWithOtpCode', AuthSignInStep.confirmSignInWithNewPassword: 'confirmSignInWithNewPassword', AuthSignInStep.confirmSignInWithCustomChallenge: 'confirmSignInWithCustomChallenge', diff --git a/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart b/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart index eef001a650..e63cb3a58f 100644 --- a/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart +++ b/packages/amplify_core/lib/src/types/auth/sign_in/auth_sign_in_step.dart @@ -29,7 +29,7 @@ enum AuthSignInStep { confirmSignInWithTotpMfaCode, /// The sign-in is not complete and must be confirmed with an email code. - confirmSignInWithEmailMfaCode, + confirmSignInWithOtpCode, /// The sign-in is not complete and must be confirmed with the user's new /// password. diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart index 9762aa9d58..0fed40593b 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_optional_test.dart @@ -60,7 +60,7 @@ void main() { password: password, ); check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart index f0aed4cd87..5cd4809ad6 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_required_test.dart @@ -37,7 +37,7 @@ void main() { password: password, ); check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, @@ -63,7 +63,7 @@ void main() { password: password, ); check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart index 97f46ff4b8..16a9987e1c 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_optional_test.dart @@ -230,7 +230,7 @@ void main() { password: password, ); check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') @@ -353,7 +353,7 @@ void main() { confirmationValue: 'EMAIL', ); check(selectRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(selectRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') @@ -392,7 +392,7 @@ void main() { password: password, ); check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart index 514cc9c53e..b7f49da0e6 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_email_totp_required_test.dart @@ -37,7 +37,7 @@ void main() { signInRes.nextStep.signInStep, because: 'When an email is registered and the userpool has email MFA enabled, Cognito will automatically enable email MFA as the preferred MFA method.', - ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + ).equals(AuthSignInStep.confirmSignInWithOtpCode); final setupRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, @@ -60,7 +60,7 @@ void main() { password: password, ); check(resignInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(resignInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') @@ -98,7 +98,7 @@ void main() { signInRes.nextStep.signInStep, because: 'MFA is required so Cognito automatically enables EMAIL MFA', - ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + ).equals(AuthSignInStep.confirmSignInWithOtpCode); final confirmRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, @@ -224,7 +224,7 @@ void main() { check( signInRes.nextStep.signInStep, because: 'Preference is EMAIL MFA now', - ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + ).equals(AuthSignInStep.confirmSignInWithOtpCode); check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart index ec45284a6a..4be77b4f06 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_optional_test.dart @@ -64,7 +64,7 @@ void main() { signInRes.nextStep.signInStep, because: 'Once Email MFA is preferred, it is performed ' 'on every sign-in attempt.', - ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + ).equals(AuthSignInStep.confirmSignInWithOtpCode); check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') @@ -155,7 +155,7 @@ void main() { password: password, ); check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') @@ -386,7 +386,7 @@ void main() { ); check(signInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart index 0aa4871021..6a3da16919 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_sms_email_required_test.dart @@ -41,7 +41,7 @@ void main() { signInRes.nextStep.signInStep, because: 'MFA is required, and EMAIL is chosen when ' 'no phone number is registered', - ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + ).equals(AuthSignInStep.confirmSignInWithOtpCode); final setupRes = await Amplify.Auth.confirmSignIn( confirmationValue: await otpResult.code, @@ -68,7 +68,7 @@ void main() { password: password, ); check(resignInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(resignInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') @@ -147,7 +147,7 @@ void main() { check( resignInRes.nextStep.signInStep, because: 'Preference is EMAIL MFA now', - ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + ).equals(AuthSignInStep.confirmSignInWithOtpCode); check(resignInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') @@ -300,7 +300,7 @@ void main() { check( signInRes.nextStep.signInStep, because: 'Preference is EMAIL MFA now', - ).equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + ).equals(AuthSignInStep.confirmSignInWithOtpCode); check(signInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') diff --git a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart index edbb8ce43f..9903ed6e2d 100644 --- a/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart +++ b/packages/auth/amplify_auth_cognito/example/integration_test/mfa_username_login_required_test.dart @@ -72,7 +72,7 @@ void main() { password: password, ); check(resignInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(resignInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') @@ -199,7 +199,7 @@ void main() { ); check(resignInRes.nextStep.signInStep) - .equals(AuthSignInStep.confirmSignInWithEmailMfaCode); + .equals(AuthSignInStep.confirmSignInWithOtpCode); check(resignInRes.nextStep.codeDeliveryDetails) .isNotNull() .has((d) => d.deliveryMedium, 'deliveryMedium') diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart index 361ac6ccb8..174bf2c9bf 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/flows/constants.dart @@ -61,7 +61,7 @@ abstract class CognitoConstants { static const challengeParamSmsMfaCode = 'SMS_MFA_CODE'; /// The `EMAIL_OTP_CODE` parameter. - static const challengeParamEmailMfaCode = 'EMAIL_OTP_CODE'; + static const challengeParamEmailOtpCode = 'EMAIL_OTP_CODE'; /// The `SOFTWARE_TOKEN_MFA_CODE` parameter. static const challengeParamSoftwareTokenMfaCode = 'SOFTWARE_TOKEN_MFA_CODE'; diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart index a48c8d4a01..9b4de91f08 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/sdk/sdk_bridge.dart @@ -32,8 +32,7 @@ extension ChallengeNameTypeBridge on ChallengeNameType { AuthSignInStep.continueSignInWithMfaSetupSelection, ChallengeNameType.softwareTokenMfa => AuthSignInStep.confirmSignInWithTotpMfaCode, - ChallengeNameType.emailOtp => - AuthSignInStep.confirmSignInWithEmailMfaCode, + ChallengeNameType.emailOtp => AuthSignInStep.confirmSignInWithOtpCode, ChallengeNameType.adminNoSrpAuth || ChallengeNameType.passwordVerifier || ChallengeNameType.devicePasswordVerifier || diff --git a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart index 2fdb6c66af..61a725e683 100644 --- a/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart +++ b/packages/auth/amplify_auth_cognito_dart/lib/src/state/machines/sign_in_state_machine.dart @@ -327,7 +327,7 @@ final class SignInStateMachine ChallengeNameType.softwareTokenMfa when hasUserResponse => createSoftwareTokenMfaRequest(event), ChallengeNameType.emailOtp when hasUserResponse => - createEmailMfaRequest(event), + createEmailOtpRequest(event), ChallengeNameType.selectMfaType when hasUserResponse => createSelectMfaRequest(event), ChallengeNameType.mfaSetup when hasUserResponse => @@ -454,7 +454,7 @@ final class SignInStateMachine /// Creates the response object for an Email MFA challenge. @protected - Future createEmailMfaRequest( + Future createEmailOtpRequest( SignInRespondToChallenge event, ) async { _enableMfaType = MfaType.email; @@ -464,7 +464,7 @@ final class SignInStateMachine ..challengeName = _challengeName ..challengeResponses.addAll({ CognitoConstants.challengeParamUsername: cognitoUsername, - CognitoConstants.challengeParamEmailMfaCode: event.answer, + CognitoConstants.challengeParamEmailOtpCode: event.answer, }) ..clientMetadata.addAll(event.clientMetadata); }); @@ -702,13 +702,13 @@ final class SignInStateMachine // User has provided the verification code return _enableMfaType == MfaType.totp - ? createMfaSetupRequest(event) + ? createTotpMfaSetupRequest(event) : createEmailMfaSetupRequest(event); } /// Completes set up of a TOTP MFA. @protected - Future createMfaSetupRequest( + Future createTotpMfaSetupRequest( SignInRespondToChallenge event, ) async { await verifySoftwareToken( diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart index 3618170b5f..f7c6986312 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_test.dart @@ -36,10 +36,10 @@ void main() { tester.bloc.stream, emitsInOrder([ UnauthenticatedState.signIn, - UnauthenticatedState.confirmSignInWithEmailMfaCode, + UnauthenticatedState.confirmSignInWithOtpCode, isA(), UnauthenticatedState.signIn, - UnauthenticatedState.confirmSignInWithEmailMfaCode, + UnauthenticatedState.confirmSignInWithOtpCode, isA(), emitsDone, ]), @@ -62,7 +62,7 @@ void main() { await signInPage.submitSignIn(); // Then I will be redirected to the email MFA code page - await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + await confirmSignInPage.expectConfirmSignInWithOtpCodeIsPresent(); // And I type a valid EMAIL OTP code await confirmSignInPage.enterVerificationCode(await otpResult.code); @@ -94,7 +94,7 @@ void main() { await signInPage.submitSignIn(); // Then I will be redirected to the EMAIL OTP code page - await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + await confirmSignInPage.expectConfirmSignInWithOtpCodeIsPresent(); // When I type a valid EMAIL OTP code await confirmSignInPage.enterVerificationCode(await otpResult2.code); @@ -129,7 +129,7 @@ void main() { tester.bloc.stream, emitsInOrder([ UnauthenticatedState.signIn, - UnauthenticatedState.confirmSignInWithEmailMfaCode, + UnauthenticatedState.confirmSignInWithOtpCode, emitsDone, ]), ); @@ -147,7 +147,7 @@ void main() { await signInPage.submitSignIn(); // Then I will be redirected to the EMAIL OTP code page - await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + await confirmSignInPage.expectConfirmSignInWithOtpCodeIsPresent(); // And I type an invalid confirmation code await confirmSignInPage.enterVerificationCode('123456'); diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_totp_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_totp_test.dart index fdb17d628c..fcee99259c 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_totp_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_email_totp_test.dart @@ -36,7 +36,7 @@ void main() { tester.bloc.stream, emitsInOrder([ UnauthenticatedState.signIn, - UnauthenticatedState.confirmSignInWithEmailMfaCode, + UnauthenticatedState.confirmSignInWithOtpCode, isA(), UnauthenticatedState.signIn, isA(), @@ -61,7 +61,7 @@ void main() { await signInPage.submitSignIn(); // Then I will be redirected to the confirm email mfa page - await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + await confirmSignInPage.expectConfirmSignInWithOtpCodeIsPresent(); // When I type a valid confirmation code await confirmSignInPage.enterVerificationCode(await otpResult.code); @@ -138,11 +138,11 @@ void main() { tester.bloc.stream, emitsInOrder([ UnauthenticatedState.signIn, - UnauthenticatedState.confirmSignInWithEmailMfaCode, + UnauthenticatedState.confirmSignInWithOtpCode, isA(), UnauthenticatedState.signIn, isA(), - UnauthenticatedState.confirmSignInWithEmailMfaCode, + UnauthenticatedState.confirmSignInWithOtpCode, isA(), emitsDone, ]), @@ -163,7 +163,7 @@ void main() { await signInPage.submitSignIn(); // Then I will be redirected to the confirm email mfa page - await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + await confirmSignInPage.expectConfirmSignInWithOtpCodeIsPresent(); // When I type a valid confirmation code await confirmSignInPage.enterVerificationCode(await otpResult.code); @@ -205,7 +205,7 @@ void main() { await confirmSignInPage.submitConfirmSignInMfaSelection(); // Then I will be redirected to the confirm EMAIL mfa page - await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + await confirmSignInPage.expectConfirmSignInWithOtpCodeIsPresent(); // When I type a valid confirmation code await confirmSignInPage.enterVerificationCode(await otpResult2.code); diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart index d425e94eb2..c01460f6d5 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_sms_email_test.dart @@ -46,7 +46,7 @@ void main() { UnauthenticatedState.confirmSignInMfa, isA(), UnauthenticatedState.signIn, - UnauthenticatedState.confirmSignInWithEmailMfaCode, + UnauthenticatedState.confirmSignInWithOtpCode, isA(), emitsDone, ]), @@ -101,7 +101,7 @@ void main() { await signInPage.submitSignIn(); // Then I will be redirected to the EMAIL MFA code page - await confirmSignInPage.expectConfirmSignInWithEmailMfaCodeIsPresent(); + await confirmSignInPage.expectConfirmSignInWithOtpCodeIsPresent(); // When I type a valid EMAIL MFA code await confirmSignInPage.enterVerificationCode(await code_2.code); diff --git a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart index 032f700ed4..823fa1ee51 100644 --- a/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart +++ b/packages/authenticator/amplify_authenticator/example/integration_test/sign_in_mfa_username_login_test.dart @@ -37,7 +37,7 @@ void main() { UnauthenticatedState.signIn, isA(), UnauthenticatedState.continueSignInWithEmailMfaSetup, - UnauthenticatedState.confirmSignInWithEmailMfaCode, + UnauthenticatedState.confirmSignInWithOtpCode, isA(), emitsDone, ]), diff --git a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart index 55abb9c220..81d94d88a8 100644 --- a/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart +++ b/packages/authenticator/amplify_authenticator/lib/amplify_authenticator.dart @@ -719,7 +719,7 @@ class _AuthenticatorState extends State { continueSignInWithEmailMfaSetupForm: ContinueSignInWithEmailMfaSetupForm(), confirmSignInWithTotpMfaCodeForm: ConfirmSignInMFAForm(), - confirmSignInWithEmailMfaCodeForm: ConfirmSignInMFAForm(), + confirmSignInWithOtpCodeForm: ConfirmSignInMFAForm(), verifyUserForm: VerifyUserForm(), confirmVerifyUserForm: ConfirmVerifyUserForm(), child: widget.child, diff --git a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart index 446182fc3f..00c6eb222d 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/blocs/auth/auth_bloc.dart @@ -227,8 +227,8 @@ class StateMachineBloc yield UnauthenticatedState.confirmSignInNewPassword; case AuthSignInStep.confirmSignInWithTotpMfaCode: yield UnauthenticatedState.confirmSignInWithTotpMfaCode; - case AuthSignInStep.confirmSignInWithEmailMfaCode: - yield UnauthenticatedState.confirmSignInWithEmailMfaCode; + case AuthSignInStep.confirmSignInWithOtpCode: + yield UnauthenticatedState.confirmSignInWithOtpCode; case AuthSignInStep.continueSignInWithMfaSelection: yield ContinueSignInWithMfaSelection( allowedMfaTypes: result.nextStep.allowedMfaTypes, @@ -345,9 +345,9 @@ class StateMachineBloc _emit(UnauthenticatedState.continueSignInWithEmailMfaSetup); case AuthSignInStep.confirmSignInWithTotpMfaCode: _emit(UnauthenticatedState.confirmSignInWithTotpMfaCode); - case AuthSignInStep.confirmSignInWithEmailMfaCode: + case AuthSignInStep.confirmSignInWithOtpCode: _notifyCodeSent(result.nextStep.codeDeliveryDetails?.destination); - _emit(UnauthenticatedState.confirmSignInWithEmailMfaCode); + _emit(UnauthenticatedState.confirmSignInWithOtpCode); case AuthSignInStep.resetPassword: _emit(UnauthenticatedState.confirmResetPassword); case AuthSignInStep.confirmSignUp: diff --git a/packages/authenticator/amplify_authenticator/lib/src/enums/authenticator_step.dart b/packages/authenticator/amplify_authenticator/lib/src/enums/authenticator_step.dart index 5ef325081a..8fcc406563 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/enums/authenticator_step.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/enums/authenticator_step.dart @@ -82,7 +82,7 @@ enum AuthenticatorStep { confirmSignInWithTotpMfaCode, /// The sign-in is not complete and must be confirmed with an email code. - confirmSignInWithEmailMfaCode, + confirmSignInWithOtpCode, /// The user is on the Reset Password step. resetPassword, diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart index 852f8e4d7b..abe2edf4ce 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations.dart @@ -145,7 +145,7 @@ abstract class AuthenticatorTitleLocalizations { /// /// In en, this message translates to: /// **'Enter your one-time passcode'** - String get confirmSignInWithEmailMfaCode; + String get confirmSignInWithOtpCode; /// Title of the Continue Sign In with Email MFA Setup step and form /// diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart index 692f579fa5..938f974e9f 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/generated/title_localizations_en.dart @@ -31,7 +31,7 @@ class AuthenticatorTitleLocalizationsEn String get confirmSignInWithTotpMfaCode => 'Enter your one-time passcode'; @override - String get confirmSignInWithEmailMfaCode => 'Enter your one-time passcode'; + String get confirmSignInWithOtpCode => 'Enter your one-time passcode'; @override String get continueSignInWithEmailMfaSetup => diff --git a/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart b/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart index e5c1b19480..318753c227 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/l10n/title_resolver.dart @@ -50,9 +50,9 @@ class TitleResolver extends Resolver { } /// The title for the confirm sign in (email MFA code) Widget. - String confirmSignInWithEmailMfaCode(BuildContext context) { + String confirmSignInWithOtpCode(BuildContext context) { return AuthenticatorLocalizations.titlesOf(context) - .confirmSignInWithEmailMfaCode; + .confirmSignInWithOtpCode; } /// The title for the continue sign in (email MFA setup) Widget. @@ -99,8 +99,8 @@ class TitleResolver extends Resolver { return continueSignInWithTotpSetup(context); case AuthenticatorStep.confirmSignInWithTotpMfaCode: return confirmSignInWithTotpMfaCode(context); - case AuthenticatorStep.confirmSignInWithEmailMfaCode: - return confirmSignInWithEmailMfaCode(context); + case AuthenticatorStep.confirmSignInWithOtpCode: + return confirmSignInWithOtpCode(context); case AuthenticatorStep.continueSignInWithEmailMfaSetup: return continueSignInWithEmailMfaSetup(context); case AuthenticatorStep.continueSignInWithMfaSetupSelection: diff --git a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart index e405a6a812..2524d2cb35 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/screens/authenticator_screen.dart @@ -40,8 +40,8 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { const AuthenticatorScreen.confirmSignInWithTotpMfaCode({Key? key}) : this(key: key, step: AuthenticatorStep.confirmSignInWithTotpMfaCode); - const AuthenticatorScreen.confirmSignInWithEmailMfaCode({Key? key}) - : this(key: key, step: AuthenticatorStep.confirmSignInWithEmailMfaCode); + const AuthenticatorScreen.confirmSignInWithOtpCode({Key? key}) + : this(key: key, step: AuthenticatorStep.confirmSignInWithOtpCode); const AuthenticatorScreen.continueSignInWithEmailMfaSetup({Key? key}) : this(key: key, step: AuthenticatorStep.continueSignInWithEmailMfaSetup); @@ -103,7 +103,7 @@ class AuthenticatorScreen extends StatelessAuthenticatorComponent { case AuthenticatorStep.confirmResetPassword: case AuthenticatorStep.verifyUser: case AuthenticatorStep.confirmVerifyUser: - case AuthenticatorStep.confirmSignInWithEmailMfaCode: + case AuthenticatorStep.confirmSignInWithOtpCode: case AuthenticatorStep.continueSignInWithEmailMfaSetup: case AuthenticatorStep.continueSignInWithMfaSetupSelection: child = _FormWrapperView(step: step); @@ -314,7 +314,7 @@ extension on AuthenticatorStep { case AuthenticatorStep.verifyUser: case AuthenticatorStep.confirmVerifyUser: case AuthenticatorStep.loading: - case AuthenticatorStep.confirmSignInWithEmailMfaCode: + case AuthenticatorStep.confirmSignInWithOtpCode: case AuthenticatorStep.continueSignInWithEmailMfaSetup: case AuthenticatorStep.continueSignInWithMfaSetupSelection: throw StateError('Invalid step: $this'); diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/auth_state.dart b/packages/authenticator/amplify_authenticator/lib/src/state/auth_state.dart index 834afbe683..ed4d213700 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/auth_state.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/auth_state.dart @@ -49,8 +49,8 @@ class UnauthenticatedState extends AuthState static const continueSignInWithEmailMfaSetup = UnauthenticatedState( step: AuthenticatorStep.continueSignInWithEmailMfaSetup, ); - static const confirmSignInWithEmailMfaCode = UnauthenticatedState( - step: AuthenticatorStep.confirmSignInWithEmailMfaCode, + static const confirmSignInWithOtpCode = UnauthenticatedState( + step: AuthenticatorStep.confirmSignInWithOtpCode, ); static const resetPassword = UnauthenticatedState(step: AuthenticatorStep.resetPassword); diff --git a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart index 2b75184038..12717df25b 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/state/inherited_forms.dart @@ -20,7 +20,7 @@ class InheritedForms extends InheritedWidget { required this.continueSignInWithTotpSetupForm, required this.continueSignInWithEmailMfaSetupForm, required this.confirmSignInWithTotpMfaCodeForm, - required this.confirmSignInWithEmailMfaCodeForm, + required this.confirmSignInWithOtpCodeForm, required this.verifyUserForm, required this.confirmVerifyUserForm, required super.child, @@ -38,7 +38,7 @@ class InheritedForms extends InheritedWidget { final ContinueSignInWithTotpSetupForm continueSignInWithTotpSetupForm; final ContinueSignInWithEmailMfaSetupForm continueSignInWithEmailMfaSetupForm; final ConfirmSignInMFAForm confirmSignInWithTotpMfaCodeForm; - final ConfirmSignInMFAForm confirmSignInWithEmailMfaCodeForm; + final ConfirmSignInMFAForm confirmSignInWithOtpCodeForm; final ResetPasswordForm resetPasswordForm; final ConfirmResetPasswordForm confirmResetPasswordForm; final VerifyUserForm verifyUserForm; @@ -70,8 +70,8 @@ class InheritedForms extends InheritedWidget { return confirmSignInWithTotpMfaCodeForm; case AuthenticatorStep.continueSignInWithEmailMfaSetup: return continueSignInWithEmailMfaSetupForm; - case AuthenticatorStep.confirmSignInWithEmailMfaCode: - return confirmSignInWithEmailMfaCodeForm; + case AuthenticatorStep.confirmSignInWithOtpCode: + return confirmSignInWithOtpCodeForm; case AuthenticatorStep.resetPassword: return resetPasswordForm; case AuthenticatorStep.confirmResetPassword: @@ -118,8 +118,8 @@ class InheritedForms extends InheritedWidget { continueSignInWithTotpSetupForm || oldWidget.confirmSignInWithTotpMfaCodeForm != confirmSignInWithTotpMfaCodeForm || - oldWidget.confirmSignInWithEmailMfaCodeForm != - confirmSignInWithEmailMfaCodeForm || + oldWidget.confirmSignInWithOtpCodeForm != + confirmSignInWithOtpCodeForm || oldWidget.continueSignInWithEmailMfaSetupForm != continueSignInWithEmailMfaSetupForm || oldWidget.continueSignInWithMfaSetupSelectionForm != diff --git a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart index cc538d7dc8..83f862044e 100644 --- a/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart +++ b/packages/authenticator/amplify_authenticator/lib/src/widgets/form_field.dart @@ -231,7 +231,7 @@ abstract class AuthenticatorFormFieldState< state.confirmSignInCustomAuth(); case AuthenticatorStep.confirmSignInMfa: state.confirmSignInMFA(); - case AuthenticatorStep.confirmSignInWithEmailMfaCode: + case AuthenticatorStep.confirmSignInWithOtpCode: state.confirmEmailMfa(); case AuthenticatorStep.confirmSignInNewPassword: state.confirmSignInNewPassword(); diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_darkMode_desktopGeometry.png similarity index 100% rename from packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_desktopGeometry.png rename to packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_darkMode_desktopGeometry.png diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_darkMode_mobileGeometry.png similarity index 100% rename from packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_darkMode_mobileGeometry.png rename to packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_darkMode_mobileGeometry.png diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_desktopGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_lightMode_desktopGeometry.png similarity index 100% rename from packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_desktopGeometry.png rename to packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_lightMode_desktopGeometry.png diff --git a/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_mobileGeometry.png b/packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_lightMode_mobileGeometry.png similarity index 100% rename from packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithEmailMfaCodeStep_defaultMaterialTheme_lightMode_mobileGeometry.png rename to packages/authenticator/amplify_authenticator/test/ui/goldens/theme_emailConfig_confirmSignInWithOtpCodeStep_defaultMaterialTheme_lightMode_mobileGeometry.png diff --git a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart index 833713a476..5d2d352509 100644 --- a/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart +++ b/packages/authenticator/amplify_authenticator_test/lib/src/pages/confirm_sign_in_page.dart @@ -75,13 +75,13 @@ class ConfirmSignInPage extends AuthenticatorPage { } /// Then I see "Enter your one-time passcode for Email" - Future expectConfirmSignInWithEmailMfaCodeIsPresent() async { + Future expectConfirmSignInWithOtpCodeIsPresent() async { final currentScreen = tester.widget( find.byType(AuthenticatorScreen), ); expect( currentScreen.step, - equals(AuthenticatorStep.confirmSignInWithEmailMfaCode), + equals(AuthenticatorStep.confirmSignInWithOtpCode), ); }