diff --git a/src/firebase.android.ts b/src/firebase.android.ts index cc352ba0..d91f0e1f 100755 --- a/src/firebase.android.ts +++ b/src/firebase.android.ts @@ -1405,12 +1405,33 @@ firebase._alreadyLinkedToAuthProvider = (user, providerId) => { firebase.reauthenticate = arg => { return new Promise((resolve, reject) => { try { + // need these to support using phone auth more than once + firebase.resolve = resolve; + firebase.reject = reject; + const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (user === null) { reject("no current user"); return; } + const onCompleteListener = new gmsTasks.OnCompleteListener({ + onComplete: task => { + if (task.isSuccessful()) { + const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); + const loginResult = toLoginResult(user); + + firebase.notifyAuthStateListeners({ + loggedIn: true, + user: loginResult + }); + resolve(loginResult); + } else { + reject((task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException())); + } + } + }); + firebase.moveLoginOptionsToObjects(arg); let authCredential = null; @@ -1421,6 +1442,61 @@ firebase.reauthenticate = arg => { } authCredential = com.google.firebase.auth.EmailAuthProvider.getCredential(arg.passwordOptions.email, arg.passwordOptions.password); + } else if (arg.type === firebase.LoginType.PHONE) { + if (!arg.phoneOptions || !arg.phoneOptions.phoneNumber) { + reject("Auth type PHONE requires a 'phoneOptions.phoneNumber' argument"); + return; + } + + const OnVerificationStateChangedCallbacks = com.google.firebase.auth.PhoneAuthProvider.OnVerificationStateChangedCallbacks.extend({ + onVerificationCompleted: phoneAuthCredential => { + firebase._verifyPhoneNumberInProgress = false; + user.reauthenticate(phoneAuthCredential).addOnCompleteListener(onCompleteListener); + }, + onVerificationFailed: firebaseException => { + firebase._verifyPhoneNumberInProgress = false; + const errorMessage = firebaseException.getMessage(); + if (errorMessage.includes("INVALID_APP_CREDENTIAL")) { + if (firebase.reject) { + firebase.reject("Please upload the SHA1 fingerprint of your debug and release keystores to the Firebase console, see https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/master/docs/AUTHENTICATION.md#phone-verification"); + } + } else { + if (firebase.reject) { + firebase.reject(errorMessage); + } + } + }, + onCodeSent: (verificationId, forceResendingToken) => { + // If the device has a SIM card auto-verification may occur in the background (eventually calling onVerificationCompleted) + // .. so the prompt would be redundant, but it's recommended by Google not to wait to long before showing the prompt + setTimeout(() => { + if (firebase._verifyPhoneNumberInProgress) { + firebase._verifyPhoneNumberInProgress = false; + firebase.requestPhoneAuthVerificationCode(userResponse => { + if (userResponse === undefined && firebase.reject) { + firebase.reject("Prompt was canceled"); + return; + } + authCredential = com.google.firebase.auth.PhoneAuthProvider.getCredential(verificationId, userResponse); + + user.reauthenticate(authCredential).addOnCompleteListener(onCompleteListener); + }, arg.phoneOptions.verificationPrompt); + } + }, 3000); + } + }); + + firebase._verifyPhoneNumberInProgress = true; + + let timeout = arg.phoneOptions.android ? arg.phoneOptions.android.timeout : 60; + com.google.firebase.auth.PhoneAuthProvider.getInstance().verifyPhoneNumber( + arg.phoneOptions.phoneNumber, + timeout, // timeout (in seconds, because of the next argument) + java.util.concurrent.TimeUnit.SECONDS, + Application.android.foregroundActivity, + new OnVerificationStateChangedCallbacks()); + + return; } else if (arg.type === firebase.LoginType.GOOGLE) { if (!firebase._googleSignInIdToken) { reject("Not currently logged in with Google"); @@ -1437,26 +1513,10 @@ firebase.reauthenticate = arg => { } if (authCredential === null) { - reject("arg.type should be one of LoginType.PASSWORD | LoginType.GOOGLE | LoginType.FACEBOOK"); + reject("arg.type should be one of LoginType.PASSWORD | LoginType.PHONE | LoginType.GOOGLE | LoginType.FACEBOOK"); return; } - const onCompleteListener = new gmsTasks.OnCompleteListener({ - onComplete: task => { - if (task.isSuccessful()) { - const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); - const loginResult = toLoginResult(user); - - firebase.notifyAuthStateListeners({ - loggedIn: true, - user: loginResult - }); - resolve(loginResult); - } else { - reject((task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException())); - } - } - }); user.reauthenticate(authCredential).addOnCompleteListener(onCompleteListener); } catch (ex) { diff --git a/src/firebase.ios.ts b/src/firebase.ios.ts index a5dac1a3..5a8b7329 100755 --- a/src/firebase.ios.ts +++ b/src/firebase.ios.ts @@ -1229,6 +1229,20 @@ firebase.reauthenticate = arg => { firebase.moveLoginOptionsToObjects(arg); + const onCompletion = (authResult: FIRAuthDataResult, error: NSError) => { + if (error) { + reject(error.localizedDescription); + + } else { + firebase.notifyAuthStateListeners({ + loggedIn: true, + user: toLoginResult(authResult.user) + }); + + resolve(toLoginResult(authResult && authResult.user, authResult && authResult.additionalUserInfo)); + } + }; + let authCredential = null; if (arg.type === firebase.LoginType.PASSWORD) { if (!arg.passwordOptions || !arg.passwordOptions.email || !arg.passwordOptions.password) { @@ -1237,6 +1251,31 @@ firebase.reauthenticate = arg => { } authCredential = FIREmailAuthProvider.credentialWithEmailPassword(arg.passwordOptions.email, arg.passwordOptions.password); + } else if (arg.type === firebase.LoginType.PHONE) { + // https://firebase.google.com/docs/auth/ios/phone-auth + if (!arg.phoneOptions || !arg.phoneOptions.phoneNumber) { + reject("Auth type PHONE requires a 'phoneOptions.phoneNumber' argument"); + return; + } + + FIRPhoneAuthProvider.provider().verifyPhoneNumberUIDelegateCompletion(arg.phoneOptions.phoneNumber, null, (verificationID: string, error: NSError) => { + if (error) { + reject(error.localizedDescription); + return; + } + + firebase.requestPhoneAuthVerificationCode(userResponse => { + if (userResponse === undefined) { + reject("Prompt was canceled"); + return; + } + const fIRAuthCredential = FIRPhoneAuthProvider.provider().credentialWithVerificationIDVerificationCode(verificationID, userResponse); + + user.reauthenticateWithCredentialCompletion(fIRAuthCredential, onCompletion); + }, arg.phoneOptions.verificationPrompt); + }); + + return; } else if (arg.type === firebase.LoginType.GOOGLE) { if (!firebase._gIDAuthentication) { reject("Not currently logged in with Google"); @@ -1253,23 +1292,10 @@ firebase.reauthenticate = arg => { } if (authCredential === null) { - reject("arg.type should be one of LoginType.PASSWORD | LoginType.GOOGLE | LoginType.FACEBOOK"); + reject("arg.type should be one of LoginType.PASSWORD | LoginType.PHONE | LoginType.GOOGLE | LoginType.FACEBOOK"); return; } - const onCompletion = (authResult: FIRAuthDataResult, error: NSError) => { - if (error) { - reject(error.localizedDescription); - - } else { - firebase.notifyAuthStateListeners({ - loggedIn: true, - user: toLoginResult(authResult.user) - }); - - resolve(toLoginResult(authResult && authResult.user, authResult && authResult.additionalUserInfo)); - } - }; user.reauthenticateWithCredentialCompletion(authCredential, onCompletion); } catch (ex) {