diff --git a/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuth.java b/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuth.java index 0863b6e0..d5c26cf6 100644 --- a/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuth.java +++ b/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuth.java @@ -23,6 +23,7 @@ import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.ActionCodeResult; import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException; @@ -552,6 +553,43 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { }); } + /** + * @param code + * @param promise + */ + @ReactMethod + public void checkActionCode(String code, final Promise promise) { + Log.d(TAG, "checkActionCode"); + mAuth.checkActionCode(code).addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "checkActionCode:onComplete:success"); + ActionCodeResult result = task.getResult(); + WritableMap writableMap = Arguments.createMap(); + WritableMap dataMap = Arguments.createMap(); + + dataMap.putString("email", result.getData(ActionCodeResult.EMAIL)); + dataMap.putString("fromEmail", result.getData(ActionCodeResult.FROM_EMAIL)); + + writableMap.putMap("data", dataMap); + + // TODO figure out if these are required - web sdk only returns the 'email' and nothing else + // writableMap.putString("error", result.getData(ActionCodeResult.ERROR)); + // writableMap.putString("verifyEmail", result.getData(ActionCodeResult.VERIFY_EMAIL)); + // writableMap.putString("recoverEmail", result.getData(ActionCodeResult.RECOVER_EMAIL)); + // writableMap.putString("passwordReset", result.getData(ActionCodeResult.PASSWORD_RESET)); + + promise.resolve(writableMap); + } else { + Exception exception = task.getException(); + Log.e(TAG, "checkActionCode:onComplete:failure", exception); + promiseRejectAuthException(promise, exception); + } + } + }); + } + /** * link * diff --git a/index.d.ts b/index.d.ts index 2f84ab45..2041bafe 100644 --- a/index.d.ts +++ b/index.d.ts @@ -7,10 +7,15 @@ declare module "react-native-firebase" { export default class FireBase { constructor(config?: RNFirebase.configurationOptions) + log: any + analytics(): RNFirebase.Analytics; + auth(): RNFirebase.auth.Auth; + on(type: string, handler: (msg: any) => void): any; + /** mimics firebase Web SDK */ database: { (): RNFirebase.database.Database @@ -18,10 +23,12 @@ declare module "react-native-firebase" { TIMESTAMP: number } } + /**RNFirebase mimics the Web Firebase SDK Storage, * whilst providing some iOS and Android specific functionality. */ storage(): RNFirebase.storage.Storage; + /** * Firebase Cloud Messaging (FCM) allows you to send push messages at no cost to both Android & iOS platforms. * Assuming the installation instructions have been followed, FCM is ready to go. @@ -29,6 +36,7 @@ declare module "react-native-firebase" { * the following methods within react-native-firebase have been created to handle FCM in the React Native environment. */ messaging(): RNFirebase.messaging.Messaging; + /** * RNFirebase provides crash reporting for your app out of the box. * Please note crashes do not appear in real-time on the console, @@ -37,9 +45,12 @@ declare module "react-native-firebase" { * such as a pre-caught exception this is possible by using the report method. */ crash(): RNFirebase.crash.Crash; + apps: Array; googleApiAvailability: RNFirebase.GoogleApiAvailabilityType; + static initializeApp(options?: any | RNFirebase.configurationOptions, name?: string): FireBase; + [key: string]: any; } @@ -56,10 +67,10 @@ declare module "react-native-firebase" { }; /** - * pass custom options by passing an object with configuration options. - * The configuration object will be generated first by the native configuration object, if set and then will be overridden if passed in JS. - * That is, all of the following key/value pairs are optional if the native configuration is set. - */ + * pass custom options by passing an object with configuration options. + * The configuration object will be generated first by the native configuration object, if set and then will be overridden if passed in JS. + * That is, all of the following key/value pairs are optional if the native configuration is set. + */ interface configurationOptions { /** * default false @@ -74,7 +85,7 @@ declare module "react-native-firebase" { */ persistence?: boolean; /** - * Default from app [NSBundle mainBundle] The bundle ID for the app to be bundled with + * Default from app [NSBundle mainBundle] The bundle ID for the app to be bundled with */ bundleID?: string; /** @@ -103,7 +114,7 @@ declare module "react-native-firebase" { */ androidClientID?: string; /** - * default "" + * default "" * The Project number from the Google Developer's console used to configure Google Cloud Messaging */ GCMSenderID?: string; @@ -127,12 +138,10 @@ declare module "react-native-firebase" { namespace storage { interface StorageTask extends Promise { - on( - event: TaskEvent, - nextOrObserver: (snapshot: any) => any, - error: (error: RnError) => any, - complete: (complete: any) => any - ): any + on(event: TaskEvent, + nextOrObserver: (snapshot: any) => any, + error: (error: RnError) => any, + complete: (complete: any) => any): any /** * is not currently supported by react-native-firebase */ @@ -183,17 +192,13 @@ declare module "react-native-firebase" { name: string; parent: storage.Reference | null; put(data: any | Uint8Array | ArrayBuffer, - metadata?: storage.UploadMetadata): - storage.UploadTask; - putString( - data: string, format?: storage.StringFormat, - metadata?: storage.UploadMetadata): - storage.UploadTask; + metadata?: storage.UploadMetadata): storage.UploadTask; + putString(data: string, format?: storage.StringFormat, + metadata?: storage.UploadMetadata): storage.UploadTask; root: storage.Reference; storage: storage.Storage; toString(): string; - updateMetadata(metadata: storage.SettableMetadata): - Promise; + updateMetadata(metadata: storage.SettableMetadata): Promise; } interface UploadMetadata extends storage.SettableMetadata { md5Hash?: string | null; @@ -219,13 +224,12 @@ declare module "react-native-firebase" { cancel(): boolean; catch(onRejected: (a: RnError) => any): Promise; on(event: storage.TaskEvent, nextOrObserver?: null | Object, - error?: ((a: RnError) => any) | null, complete?: (() => any) | null): Function; + error?: ((a: RnError) => any) | null, complete?: (() => any) | null): Function; pause(): boolean; resume(): boolean; snapshot: storage.UploadTaskSnapshot; - then( - onFulfilled?: ((a: storage.UploadTaskSnapshot) => any) | null, - onRejected?: ((a: RnError) => any) | null): Promise; + then(onFulfilled?: ((a: storage.UploadTaskSnapshot) => any) | null, + onRejected?: ((a: RnError) => any) | null): Promise; } interface UploadTaskSnapshot { @@ -310,18 +314,15 @@ declare module "react-native-firebase" { limitToFirst(limit: number): database.Query; limitToLast(limit: number): database.Query; off(eventType?: string, - callback?: (a: database.DataSnapshot, b?: string | null) => any, - context?: Object | null): any; + callback?: (a: database.DataSnapshot, b?: string | null) => any, + context?: Object | null): any; on(eventType: string, - callback: (a: database.DataSnapshot | null, b?: string) => any, - cancelCallbackOrContext?: Object | null, context?: Object | null): - (a: database.DataSnapshot | null, b?: string) => any; - once( - eventType: string, - successCallback?: - (a: database.DataSnapshot, b?: string) => any, - failureCallbackOrContext?: Object | null, - context?: Object | null): Promise; + callback: (a: database.DataSnapshot | null, b?: string) => any, + cancelCallbackOrContext?: Object | null, context?: Object | null): (a: database.DataSnapshot | null, b?: string) => any; + once(eventType: string, + successCallback?: (a: database.DataSnapshot, b?: string) => any, + failureCallbackOrContext?: Object | null, + context?: Object | null): Promise; orderByChild(path: string): database.Query; orderByKey(): database.Query; orderByPriority(): database.Query; @@ -356,18 +357,14 @@ declare module "react-native-firebase" { remove(onComplete?: (a: RnError | null) => any): Promise; root: database.Reference; set(value: any, onComplete?: (a: RnError | null) => any): Promise; - setPriority( - priority: string | number | null, - onComplete: (a: RnError | null) => any): Promise; - setWithPriority( - newVal: any, newPriority: string | number | null, - onComplete?: (a: RnError | null) => any): Promise; - transaction( - transactionUpdate: (a: any) => any, - onComplete?: - (a: RnError | null, b: boolean, - c: database.DataSnapshot | null) => any, - applyLocally?: boolean): Promise; + setPriority(priority: string | number | null, + onComplete: (a: RnError | null) => any): Promise; + setWithPriority(newVal: any, newPriority: string | number | null, + onComplete?: (a: RnError | null) => any): Promise; + transaction(transactionUpdate: (a: any) => any, + onComplete?: (a: RnError | null, b: boolean, + c: database.DataSnapshot | null) => any, + applyLocally?: boolean): Promise; update(values: Object, onComplete?: (a: RnError | null) => any): Promise; } } @@ -491,6 +488,17 @@ declare module "react-native-firebase" { token: string, secret: string } + + + interface ActionCodeInfo { + email: string, + error: string, + fromEmail: string, + verifyEmail: string, + recoverEmail: string, + passwordReset: string + } + namespace auth { interface Auth { @@ -507,9 +515,8 @@ declare module "react-native-firebase" { * This method returns a unsubscribe function to stop listening to events. * Always ensure you unsubscribe from the listener when no longer needed to prevent updates to components no longer in use. */ - onAuthStateChanged( - nextOrObserver: Object, error?: (a: RnError) => any, - completed?: () => any): () => any; + onAuthStateChanged(nextOrObserver: Object, error?: (a: RnError) => any, + completed?: () => any): () => any; /** * We can create a user by calling the createUserWithEmailAndPassword() function. * The method accepts two parameters, an email and a password. @@ -547,13 +554,17 @@ declare module "react-native-firebase" { /** * Completes the password reset process, given a confirmation code and new password. */ - confirmPasswordReset(code: string, newPassword: string): Promise + confirmPasswordReset(code: string, newPassword: string): Promise /** * Applies a verification code sent to the user by email or other out-of-band mechanism. */ - applyActionCode(code: string): Promise + applyActionCode(code: string): Promise + /** + * Checks a verification code sent to the user by email or other out-of-band mechanism. + */ + checkActionCode(code: string): Promise /** * Completes the password reset process, * given a confirmation code and new password. diff --git a/ios/RNFirebase/auth/RNFirebaseAuth.m b/ios/RNFirebase/auth/RNFirebaseAuth.m index eb4de425..457f163c 100644 --- a/ios/RNFirebase/auth/RNFirebaseAuth.m +++ b/ios/RNFirebase/auth/RNFirebaseAuth.m @@ -350,7 +350,7 @@ RCT_EXPORT_METHOD(confirmPasswordReset:(NSString *)code newPassword:(NSString *) * @return */ RCT_EXPORT_METHOD(applyActionCode:(NSString *)code resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) { - [[FIRAuth auth] applyActionCode:code completion:^(NSError *_Nullable error) { + [[FIRAuth auth] applyActionCode:code completion:^(NSError *_Nullable error) { if (error) { [self promiseRejectAuthException:reject error:error]; } else { @@ -359,6 +359,38 @@ RCT_EXPORT_METHOD(applyActionCode:(NSString *)code resolver:(RCTPromiseResolveBl }]; } +/** + * checkActionCode + * + * @param NSString code + * @param RCTPromiseResolveBlock resolve + * @param RCTPromiseRejectBlock reject + * @return + */ +RCT_EXPORT_METHOD(checkActionCode:(NSString *) code resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) { + [[FIRAuth auth] checkActionCode:code completion:^(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error){ + if (error) { + [self promiseRejectAuthException:reject error:error]; + } else { + NSDictionary * result = @{ + @"data": @{ + @"email": [info dataForKey:FIRActionCodeEmailKey], + @"fromEmail": [info dataForKey:FIRActionCodeFromEmailKey], + } + }; + + // TODO action code operation codes? + /* + FIRActionCodeOperationUnknown = 0, + FIRActionCodeOperationPasswordReset = 1, + FIRActionCodeOperationVerifyEmail = 2 + */ + + resolve(result); + } + }]; +} + /** sendPasswordResetEmail diff --git a/lib/modules/auth/index.js b/lib/modules/auth/index.js index 31c4d5a7..73f37c4f 100644 --- a/lib/modules/auth/index.js +++ b/lib/modules/auth/index.js @@ -172,14 +172,20 @@ export default class Auth extends Base { * @param code * @return {Promise.} */ - applyActionCode(code: string): Promise { + applyActionCode(code: string): Promise { return FirebaseAuth.applyActionCode(code); } - - // TODO: https://firebase.google.com/docs/reference/js/firebase.auth.Auth#applyActionCode - // TODO: applyActionCode - // TODO: checkActionCode + /** + * Checks a verification code sent to the user by email or other out-of-band mechanism. + * + * @link https://firebase.google.com/docs/reference/js/firebase.auth.Auth#checkActionCode + * @param code + * @return {Promise.|Promise} + */ + checkActionCode(code: string): Promise { + return FirebaseAuth.checkActionCode(code); + } /** * Get the currently signed in user