Skip to content

Commit 04280a3

Browse files
authored
fix(auth, android): fixing an issue that could cause getEnrolledFactors 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
1 parent 3a88eea commit 04280a3

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed

packages/firebase_auth/firebase_auth/android/src/main/java/io/flutter/plugins/firebase/auth/FlutterFirebaseAuthPlugin.java

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package io.flutter.plugins.firebase.auth;
66

7+
import static io.flutter.plugins.firebase.auth.FlutterFirebaseMultiFactor.multiFactorUserMap;
78
import static io.flutter.plugins.firebase.core.FlutterFirebasePluginRegistry.registerPlugin;
89

910
import android.app.Activity;
@@ -17,6 +18,7 @@
1718
import com.google.firebase.auth.AuthResult;
1819
import com.google.firebase.auth.FirebaseAuth;
1920
import com.google.firebase.auth.FirebaseUser;
21+
import com.google.firebase.auth.MultiFactor;
2022
import com.google.firebase.auth.MultiFactorInfo;
2123
import com.google.firebase.auth.MultiFactorSession;
2224
import com.google.firebase.auth.OAuthProvider;
@@ -441,6 +443,13 @@ public void signOut(
441443
@NonNull GeneratedAndroidFirebaseAuth.Result<Void> result) {
442444
try {
443445
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
446+
if (firebaseAuth.getCurrentUser() != null) {
447+
final Map<String, MultiFactor> appMultiFactorUser =
448+
multiFactorUserMap.get(app.getAppName());
449+
if (appMultiFactorUser != null) {
450+
appMultiFactorUser.remove(firebaseAuth.getCurrentUser().getUid());
451+
}
452+
}
444453
firebaseAuth.signOut();
445454
result.success(null);
446455
} catch (Exception e) {

tests/integration_test/firebase_auth/firebase_auth_multi_factor_e2e_test.dart

+117
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,123 @@ void main() {
170170
skip: kIsWeb || defaultTargetPlatform != TargetPlatform.android,
171171
);
172172

173+
test(
174+
'should enroll and unenroll factor with signing out in the middle',
175+
() async {
176+
String email = generateRandomEmail();
177+
178+
String testPhoneNumber = '+441444555626';
179+
User? user;
180+
UserCredential userCredential;
181+
182+
userCredential =
183+
await FirebaseAuth.instance.createUserWithEmailAndPassword(
184+
email: email,
185+
password: testPassword,
186+
);
187+
user = userCredential.user;
188+
189+
await user!.sendEmailVerification();
190+
final oobCode = (await emulatorOutOfBandCode(
191+
email,
192+
EmulatorOobCodeType.verifyEmail,
193+
))!;
194+
195+
await emulatorVerifyEmail(
196+
oobCode.oobCode!,
197+
);
198+
199+
await FirebaseAuth.instance.signOut();
200+
201+
await FirebaseAuth.instance.signInWithEmailAndPassword(
202+
email: email,
203+
password: testPassword,
204+
);
205+
206+
final multiFactor = user.multiFactor;
207+
final session = await multiFactor.getSession();
208+
209+
Future<String> getCredential() async {
210+
Completer completer = Completer<String>();
211+
212+
unawaited(
213+
FirebaseAuth.instance.verifyPhoneNumber(
214+
phoneNumber: testPhoneNumber,
215+
multiFactorSession: session,
216+
verificationCompleted: (PhoneAuthCredential credential) {
217+
if (!completer.isCompleted) {
218+
return completer.completeError(
219+
Exception(
220+
'verificationCompleted should not have been called',
221+
),
222+
);
223+
}
224+
},
225+
verificationFailed: (FirebaseException e) {
226+
if (!completer.isCompleted) {
227+
return completer.completeError(
228+
Exception(
229+
'verificationFailed should not have been called',
230+
),
231+
);
232+
}
233+
},
234+
codeSent: (String verificationId, int? resetToken) {
235+
completer.complete(verificationId);
236+
},
237+
codeAutoRetrievalTimeout: (String foo) {
238+
if (!completer.isCompleted) {
239+
return completer.completeError(
240+
Exception(
241+
'codeAutoRetrievalTimeout should not have been called',
242+
),
243+
);
244+
}
245+
},
246+
),
247+
);
248+
249+
return completer.future as FutureOr<String>;
250+
}
251+
252+
final verificationId = await getCredential();
253+
254+
final smsCode = await emulatorPhoneVerificationCode(
255+
testPhoneNumber,
256+
);
257+
258+
final credential = PhoneAuthProvider.credential(
259+
verificationId: verificationId,
260+
smsCode: smsCode!,
261+
);
262+
263+
expect(credential, isA<PhoneAuthCredential>());
264+
265+
await user.multiFactor.enroll(
266+
PhoneMultiFactorGenerator.getAssertion(
267+
credential,
268+
),
269+
displayName: 'My phone number',
270+
);
271+
272+
final enrolledFactors = await multiFactor.getEnrolledFactors();
273+
274+
// Assertions
275+
expect(enrolledFactors.length, 1);
276+
expect(enrolledFactors.first.displayName, 'My phone number');
277+
278+
await user.multiFactor.unenroll(
279+
multiFactorInfo: enrolledFactors.first,
280+
);
281+
282+
final enrolledFactorsAfter = await multiFactor.getEnrolledFactors();
283+
284+
// Assertions
285+
expect(enrolledFactorsAfter.length, 0);
286+
},
287+
skip: kIsWeb || defaultTargetPlatform != TargetPlatform.android,
288+
);
289+
173290
test(
174291
'should enroll and throw if trying to unenroll an unknown factor',
175292
() async {

0 commit comments

Comments
 (0)