Skip to content

Commit 530dd79

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 14eef92 commit 530dd79

File tree

2 files changed

+66
-15
lines changed

2 files changed

+66
-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: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,55 @@ describe('auth() -> emailLink Provider', function () {
9696
});
9797
});
9898

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

0 commit comments

Comments
 (0)