Skip to content

Commit accf260

Browse files
committed
fix(auth, android): catch native error in signWithEmailLink
the firebase-android-sdk throws an unhandled error if the link is mal-formed (e.g., missing apiKey param) which bubbled up to javascript inappropriately making it very hard to handle now we catch all exceptions and handle correctly with a Promise reject, and we probe the same with an e2e test
1 parent 443da15 commit accf260

File tree

2 files changed

+65
-15
lines changed

2 files changed

+65
-15
lines changed

packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -459,18 +459,23 @@ private void signInWithEmailLink(
459459
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
460460
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
461461

462-
firebaseAuth
463-
.signInWithEmailLink(email, emailLink)
464-
.addOnSuccessListener(
465-
authResult -> {
466-
Log.d(TAG, "signInWithEmailLink:onComplete:success");
467-
promiseWithAuthResult(authResult, promise);
468-
})
469-
.addOnFailureListener(
470-
exception -> {
471-
Log.e(TAG, "signInWithEmailLink:onComplete:failure", exception);
472-
promiseRejectAuthException(promise, exception);
473-
});
462+
try {
463+
firebaseAuth
464+
.signInWithEmailLink(email, emailLink)
465+
.addOnSuccessListener(
466+
authResult -> {
467+
Log.d(TAG, "signInWithEmailLink:onComplete:success");
468+
promiseWithAuthResult(authResult, promise);
469+
})
470+
.addOnFailureListener(
471+
exception -> {
472+
Log.e(TAG, "signInWithEmailLink:onComplete:failure", exception);
473+
promiseRejectAuthException(promise, exception);
474+
});
475+
} catch (Exception exception) {
476+
Log.e(TAG, "signInWithEmailLink:onComplete:totalfailure", exception);
477+
promiseRejectAuthException(promise, exception);
478+
}
474479
}
475480

476481
@ReactMethod

packages/auth/e2e/emailLink.e2e.js

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ describe('auth() -> emailLink Provider', function () {
5555
await sendSignInLinkToEmail(auth, email, actionCodeSettings);
5656
const oobInfo = await getLastOob(email);
5757
oobInfo.oobLink.should.containEql(encodeURIComponent(continueUrl));
58+
console.error('the oobLink was: ' + oobInfo.oobLink);
5859
const signInResponse = await signInUser(oobInfo.oobLink);
5960
signInResponse.should.containEql(continueUrl);
6061
signInResponse.should.containEql(oobInfo.oobCode);
@@ -96,9 +97,53 @@ describe('auth() -> emailLink Provider', function () {
9697
});
9798
});
9899

99-
// FOR MANUAL TESTING ONLY
100-
xdescribe('signInWithEmailLink', function () {
101-
it('should signIn', async function () {
100+
describe('signInWithEmailLink', function () {
101+
it.only('sign in via email does not crash with missing apiKey', async function () {
102+
const { getAuth, sendSignInLinkToEmail, signInWithEmailLink } = authModular;
103+
104+
const auth = getAuth();
105+
const random = Utils.randString(12, '#aa');
106+
const email = `${random}@${random}.com`;
107+
const continueUrl = `http://${Platform.android ? '10.0.2.2' : '127.0.0.1'}:8081/authLinkFoo?bar=${random}`;
108+
const actionCodeSettings = {
109+
url: continueUrl,
110+
handleCodeInApp: true,
111+
iOS: {
112+
bundleId: 'com.testing',
113+
},
114+
android: {
115+
packageName: 'com.testing',
116+
installApp: true,
117+
minimumVersion: '12',
118+
},
119+
};
120+
await sendSignInLinkToEmail(auth, email, actionCodeSettings);
121+
const oobInfo = await getLastOob(email);
122+
oobInfo.oobLink.should.containEql(encodeURIComponent(continueUrl));
123+
124+
// Specifically remove the apiKey param. Android requires it and needs
125+
// specific error handling or it crashes, See #8360
126+
let linkNoApiKey = oobInfo.oobLink.replace('&apiKey=fake-api-key', '');
127+
try {
128+
const signInResponse = await signInWithEmailLink(auth, email, linkNoApiKey);
129+
if (Platform.OS === 'android') {
130+
throw new Error('Should have rejected on Android');
131+
} else {
132+
signInResponse.user.email.should.equal(email);
133+
auth.currentUser.email.should.equal(email);
134+
}
135+
} catch (e) {
136+
if (Platform.OS === 'android') {
137+
e.message.should.containEql('Given link is not a valid email link');
138+
} else {
139+
// all non-android platforms should have been fine without apiKey
140+
throw e;
141+
}
142+
}
143+
});
144+
145+
// FOR MANUAL TESTING ONLY
146+
xit('should signIn', async function () {
102147
const auth = getAuth();
103148
const email = 'MANUAL TEST EMAIL HERE';
104149
const emailLink = 'MANUAL TEST CODE HERE';

0 commit comments

Comments
 (0)