Skip to content

Commit

Permalink
fix(auth): Cancel sign in
Browse files Browse the repository at this point in the history
Properly enqueues sign-in calls and cancels previous attempts when
  • Loading branch information
Dillon Nys committed Apr 11, 2023
1 parent e6c3674 commit 5a4e792
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 133 deletions.
176 changes: 78 additions & 98 deletions packages/auth/amplify_auth_cognito_dart/lib/src/auth_plugin_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -552,59 +552,49 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface
String? password,
SignInOptions? options,
}) async {
bool isSignedIn;
try {
isSignedIn = (await fetchAuthSession()).isSignedIn;
} on Exception {
isSignedIn = false;
}
if (isSignedIn) {
throw const InvalidStateException(
'A user is already signed in.',
recoverySuggestion:
'Sign out the current user by calling `Amplify.Auth.signOut` and try the sign in again.',
);
}

final pluginOptions = reifyPluginOptions(
pluginOptions: options?.pluginOptions,
defaultPluginOptions: const CognitoSignInPluginOptions(),
);

// Create a new state machine for every call since it caches values
// internally on each run.
final stream = _stateMachine.create(SignInStateMachine.type).stream;
await _stateMachine
.accept(
SignInEvent.initiate(
authFlowType: pluginOptions.authFlowType,
parameters: SignInParameters(
(p) => p
..username = username
..password = password,
),
clientMetadata: pluginOptions.clientMetadata,
// Cancel the current sign in, if any.
await _stateMachine.acceptAndComplete<SignInNotStarted>(
const SignInEvent.cancelled(),
);
try {
final result = await _stateMachine.acceptAndComplete<SignInState>(
SignInEvent.initiate(
authFlowType: pluginOptions.authFlowType,
parameters: SignInParameters(
(p) => p
..username = username
..password = password,
),
)
.accepted;
clientMetadata: pluginOptions.clientMetadata,
),
);

await for (final state in stream) {
switch (state.type) {
switch (result.type) {
case SignInStateType.notStarted:
case SignInStateType.initiating:
case SignInStateType.failure:
// This should never happen.
throw const UnknownException('Sign in could not be completed');
case SignInStateType.cancelling:
continue;
throw const UserCancelledException(
'The user canceled the sign-in flow',
);
case SignInStateType.challenge:
state as SignInChallenge;
result as SignInChallenge;
return CognitoSignInResult(
isSignedIn: false,
nextStep: AuthNextSignInStep(
signInStep: state.challengeName.signInStep,
signInStep: result.challengeName.signInStep,
codeDeliveryDetails: _getChallengeDeliveryDetails(
state.challengeParameters,
result.challengeParameters,
),
additionalInfo: state.challengeParameters,
missingAttributes: state.requiredAttributes,
additionalInfo: result.challengeParameters,
missingAttributes: result.requiredAttributes,
),
);
case SignInStateType.success:
Expand All @@ -614,28 +604,22 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface
signInStep: AuthSignInStep.done,
),
);
case SignInStateType.failure:
final exception = (state as SignInFailure).exception;
if (exception is PasswordResetRequiredException) {
return const CognitoSignInResult(
isSignedIn: false,
nextStep: AuthNextSignInStep(
signInStep: AuthSignInStep.resetPassword,
),
);
} else if (exception is UserNotConfirmedException) {
return const CognitoSignInResult(
isSignedIn: false,
nextStep: AuthNextSignInStep(
signInStep: AuthSignInStep.confirmSignUp,
),
);
}
throw exception;
}
} on PasswordResetRequiredException {
return const CognitoSignInResult(
isSignedIn: false,
nextStep: AuthNextSignInStep(
signInStep: AuthSignInStep.resetPassword,
),
);
} on UserNotConfirmedException {
return const CognitoSignInResult(
isSignedIn: false,
nextStep: AuthNextSignInStep(
signInStep: AuthSignInStep.confirmSignUp,
),
);
}

throw const UserCancelledException('The user cancelled the sign-in flow');
}

@override
Expand All @@ -647,50 +631,46 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface
pluginOptions: options?.pluginOptions,
defaultPluginOptions: const CognitoConfirmSignInPluginOptions(),
);
await _stateMachine
.accept(
SignInEvent.respondToChallenge(
answer: confirmationValue,
clientMetadata: pluginOptions.clientMetadata,
userAttributes: pluginOptions.userAttributes,
),
)
.accepted;

final stream = _stateMachine.expect(SignInStateMachine.type).stream;
await for (final state in stream) {
switch (state.type) {
case SignInStateType.notStarted:
case SignInStateType.initiating:
case SignInStateType.cancelling:
continue;
case SignInStateType.challenge:
state as SignInChallenge;
return CognitoSignInResult(
isSignedIn: false,
nextStep: AuthNextSignInStep(
signInStep: state.challengeName.signInStep,
codeDeliveryDetails: _getChallengeDeliveryDetails(
state.challengeParameters,
),
additionalInfo: state.challengeParameters,
missingAttributes: state.requiredAttributes,
),
);
case SignInStateType.success:
return const CognitoSignInResult(
isSignedIn: true,
nextStep: AuthNextSignInStep(
signInStep: AuthSignInStep.done,
final result = await _stateMachine.acceptAndComplete<SignInState>(
SignInEvent.respondToChallenge(
answer: confirmationValue,
clientMetadata: pluginOptions.clientMetadata,
userAttributes: pluginOptions.userAttributes,
),
);

switch (result.type) {
case SignInStateType.notStarted:
case SignInStateType.initiating:
case SignInStateType.failure:
// This should never happen.
throw const UnknownException('Sign in could not be completed');
case SignInStateType.cancelling:
throw const UserCancelledException(
'The user canceled the sign-in flow',
);
case SignInStateType.challenge:
result as SignInChallenge;
return CognitoSignInResult(
isSignedIn: false,
nextStep: AuthNextSignInStep(
signInStep: result.challengeName.signInStep,
codeDeliveryDetails: _getChallengeDeliveryDetails(
result.challengeParameters,
),
);
case SignInStateType.failure:
throw (state as SignInFailure).exception;
}
additionalInfo: result.challengeParameters,
missingAttributes: result.requiredAttributes,
),
);
case SignInStateType.success:
return const CognitoSignInResult(
isSignedIn: true,
nextStep: AuthNextSignInStep(
signInStep: AuthSignInStep.done,
),
);
}

// This should never happen.
throw const UnknownException('Sign in could not be completed');
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,6 @@ class SignInInitiate extends SignInEvent {

@override
PreconditionException? checkPrecondition(SignInState currentState) {
if (currentState.type != SignInStateType.notStarted) {
return const AuthPreconditionException(
'Auth flow has already been initiated',
);
}
return null;
}
}
Expand Down

0 comments on commit 5a4e792

Please sign in to comment.