From 82a97ef97e1e0efbbca3916544939306963624cb Mon Sep 17 00:00:00 2001 From: Jean Regisser Date: Wed, 23 Oct 2019 13:42:23 +0200 Subject: [PATCH] [Wallet] Fix firebase initialization error on iOS after reinstalling the app (#1423) --- packages/mobile/ios/celo/AppDelegate.m | 31 ++++++++++++++++++++++++ packages/mobile/src/firebase/firebase.ts | 4 +++ 2 files changed, 35 insertions(+) diff --git a/packages/mobile/ios/celo/AppDelegate.m b/packages/mobile/ios/celo/AppDelegate.m index d1c06486b66..df4b9b8b29d 100644 --- a/packages/mobile/ios/celo/AppDelegate.m +++ b/packages/mobile/ios/celo/AppDelegate.m @@ -23,10 +23,18 @@ #import "RNFirebaseNotifications.h" #import "RNFirebaseMessaging.h" +// Use same key as react-native-secure-key-store +// so we don't reset already working installs +static NSString * const kHasRunBeforeKey = @"RnSksIsAppInstalled"; + @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Reset keychain on first run to clear existing Firebase credentials + // Note: react-native-secure-key-store also does that but is run too late + // and hence can't clear Firebase credentials + [self resetKeychainIfNecessary]; [FIRApp configure]; [RNFirebaseNotifications configure]; RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; @@ -68,4 +76,27 @@ - (void)application:(UIApplication *)application didRegisterUserNotificationSett [[RNFirebaseMessaging instance] didRegisterUserNotificationSettings:notificationSettings]; } +// Reset keychain on first app run, this is so we don't run with leftover items +// after reinstalling the app +- (void)resetKeychainIfNecessary +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if ([defaults boolForKey:kHasRunBeforeKey]) { + return; + } + + NSArray *secItemClasses = @[(__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrGeneric, + (__bridge id)kSecAttrAccount, + (__bridge id)kSecClassKey, + (__bridge id)kSecAttrService]; + for (id secItemClass in secItemClasses) { + NSDictionary *spec = @{(__bridge id)kSecClass:secItemClass}; + SecItemDelete((__bridge CFDictionaryRef)spec); + } + + [defaults setBool:YES forKey:kHasRunBeforeKey]; + [defaults synchronize]; +} + @end diff --git a/packages/mobile/src/firebase/firebase.ts b/packages/mobile/src/firebase/firebase.ts index d3ebb607986..64f966b36de 100644 --- a/packages/mobile/src/firebase/firebase.ts +++ b/packages/mobile/src/firebase/firebase.ts @@ -21,6 +21,10 @@ export const initializeAuth = async (app: Firebase, address: string) => { await userRef.child(user.user.uid).transaction((userData) => { if (userData == null) { return { address } + } else if (userData.address !== undefined && userData.address !== address) { + // This shouldn't happen! If this is thrown it means the firebase user is reused + // with different addresses (which we don't want) or the db was incorrectly changed remotely! + throw new Error("User address in the db doesn't match persisted address") } }) Logger.info(TAG, 'Firebase Auth initialized successfully')