Skip to content

Commit

Permalink
fix(auth, android): fixing an issue that could cause `getEnrolledFact…
Browse files Browse the repository at this point in the history
…ors` to return an empty list if signing out in the same app session (#12488)

* fix(auth): fixing an issue that could cause getEnrolledFactors to return an empty list if signing out in the same app session

* format

* fix tests
  • Loading branch information
Lyokone committed Mar 15, 2024
1 parent 3a88eea commit 04280a3
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 0 deletions.
Expand Up @@ -4,6 +4,7 @@

package io.flutter.plugins.firebase.auth;

import static io.flutter.plugins.firebase.auth.FlutterFirebaseMultiFactor.multiFactorUserMap;
import static io.flutter.plugins.firebase.core.FlutterFirebasePluginRegistry.registerPlugin;

import android.app.Activity;
Expand All @@ -17,6 +18,7 @@
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.MultiFactor;
import com.google.firebase.auth.MultiFactorInfo;
import com.google.firebase.auth.MultiFactorSession;
import com.google.firebase.auth.OAuthProvider;
Expand Down Expand Up @@ -441,6 +443,13 @@ public void signOut(
@NonNull GeneratedAndroidFirebaseAuth.Result<Void> result) {
try {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
if (firebaseAuth.getCurrentUser() != null) {
final Map<String, MultiFactor> appMultiFactorUser =
multiFactorUserMap.get(app.getAppName());
if (appMultiFactorUser != null) {
appMultiFactorUser.remove(firebaseAuth.getCurrentUser().getUid());
}
}
firebaseAuth.signOut();
result.success(null);
} catch (Exception e) {
Expand Down
Expand Up @@ -170,6 +170,123 @@ void main() {
skip: kIsWeb || defaultTargetPlatform != TargetPlatform.android,
);

test(
'should enroll and unenroll factor with signing out in the middle',
() async {
String email = generateRandomEmail();

String testPhoneNumber = '+441444555626';
User? user;
UserCredential userCredential;

userCredential =
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email,
password: testPassword,
);
user = userCredential.user;

await user!.sendEmailVerification();
final oobCode = (await emulatorOutOfBandCode(
email,
EmulatorOobCodeType.verifyEmail,
))!;

await emulatorVerifyEmail(
oobCode.oobCode!,
);

await FirebaseAuth.instance.signOut();

await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: testPassword,
);

final multiFactor = user.multiFactor;
final session = await multiFactor.getSession();

Future<String> getCredential() async {
Completer completer = Completer<String>();

unawaited(
FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: testPhoneNumber,
multiFactorSession: session,
verificationCompleted: (PhoneAuthCredential credential) {
if (!completer.isCompleted) {
return completer.completeError(
Exception(
'verificationCompleted should not have been called',
),
);
}
},
verificationFailed: (FirebaseException e) {
if (!completer.isCompleted) {
return completer.completeError(
Exception(
'verificationFailed should not have been called',
),
);
}
},
codeSent: (String verificationId, int? resetToken) {
completer.complete(verificationId);
},
codeAutoRetrievalTimeout: (String foo) {
if (!completer.isCompleted) {
return completer.completeError(
Exception(
'codeAutoRetrievalTimeout should not have been called',
),
);
}
},
),
);

return completer.future as FutureOr<String>;
}

final verificationId = await getCredential();

final smsCode = await emulatorPhoneVerificationCode(
testPhoneNumber,
);

final credential = PhoneAuthProvider.credential(
verificationId: verificationId,
smsCode: smsCode!,
);

expect(credential, isA<PhoneAuthCredential>());

await user.multiFactor.enroll(
PhoneMultiFactorGenerator.getAssertion(
credential,
),
displayName: 'My phone number',
);

final enrolledFactors = await multiFactor.getEnrolledFactors();

// Assertions
expect(enrolledFactors.length, 1);
expect(enrolledFactors.first.displayName, 'My phone number');

await user.multiFactor.unenroll(
multiFactorInfo: enrolledFactors.first,
);

final enrolledFactorsAfter = await multiFactor.getEnrolledFactors();

// Assertions
expect(enrolledFactorsAfter.length, 0);
},
skip: kIsWeb || defaultTargetPlatform != TargetPlatform.android,
);

test(
'should enroll and throw if trying to unenroll an unknown factor',
() async {
Expand Down

0 comments on commit 04280a3

Please sign in to comment.