@react-native-firebase/auth 26.3.3 → 27.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/RNFBAuth.podspec +8 -2
  3. package/android/build.gradle +5 -0
  4. package/android/src/main/java/io/invertase/firebase/auth/AuthListenerHandle.java +26 -0
  5. package/android/src/main/java/io/invertase/firebase/auth/NativeRNFBTurboAuth.java +68 -102
  6. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthCacheRegistry.kt +77 -0
  7. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthListenerRegistry.kt +76 -0
  8. package/android/src/test/java/io/invertase/firebase/auth/RNFBAuthCacheRegistryTest.java +184 -0
  9. package/android/src/test/java/io/invertase/firebase/auth/RNFBAuthListenerRegistryTest.java +171 -0
  10. package/dist/module/ActionCodeURL.js +1 -1
  11. package/dist/module/ActionCodeURL.js.map +1 -1
  12. package/dist/module/index.js +1 -2
  13. package/dist/module/index.js.map +1 -1
  14. package/dist/module/version.js +1 -1
  15. package/dist/typescript/lib/ActionCodeURL.d.ts.map +1 -1
  16. package/dist/typescript/lib/types/internal.d.ts +2 -3
  17. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  18. package/dist/typescript/lib/version.d.ts +1 -1
  19. package/ios/RNFBAuth/RNFBAuthCacheRegistry.h +41 -0
  20. package/ios/RNFBAuth/RNFBAuthCacheRegistry.m +84 -0
  21. package/ios/RNFBAuth/RNFBAuthCacheRegistryStorage.swift +53 -0
  22. package/ios/RNFBAuth/RNFBAuthErrorCodeMapper.swift +333 -0
  23. package/ios/RNFBAuth/RNFBAuthHelper.m +147 -262
  24. package/ios/RNFBAuth/RNFBAuthListenerRegistry.h +39 -0
  25. package/ios/RNFBAuth/RNFBAuthListenerRegistry.m +83 -0
  26. package/ios/RNFBAuth/RNFBAuthListenerRegistryStorage.swift +76 -0
  27. package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.h +40 -0
  28. package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.m +49 -0
  29. package/ios/RNFBAuth.xcodeproj/project.pbxproj +22 -0
  30. package/ios/RNFBAuthUnitTests/RNFBAuthCacheRegistryStorageTests.swift +72 -0
  31. package/ios/RNFBAuthUnitTests/RNFBAuthCacheRegistryTests.m +131 -0
  32. package/ios/RNFBAuthUnitTests/RNFBAuthErrorCodeMapperTests.swift +250 -0
  33. package/ios/RNFBAuthUnitTests/RNFBAuthListenerRegistryStorageTests.swift +122 -0
  34. package/ios/RNFBAuthUnitTests/RNFBAuthListenerRegistryTests.m +152 -0
  35. package/ios/RNFBAuthUnitTests/RNFBAuthNullSentinelDecodeTests.m +78 -0
  36. package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/project.pbxproj +311 -0
  37. package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBAuthUnitTests.xcscheme +69 -0
  38. package/lib/ActionCodeURL.ts +1 -2
  39. package/lib/index.ts +1 -1
  40. package/lib/types/internal.ts +2 -2
  41. package/lib/version.ts +1 -1
  42. package/package.json +5 -4
  43. package/plugin/build/index.js +4 -0
  44. package/plugin/build/ios/index.d.ts +2 -1
  45. package/plugin/build/ios/index.js +3 -1
  46. package/plugin/build/ios/openUrlFix.js +12 -0
  47. package/plugin/build/ios/sceneDelegate.d.ts +34 -0
  48. package/plugin/build/ios/sceneDelegate.js +127 -0
  49. package/plugin/build/ios/sceneLifecycle.d.ts +32 -0
  50. package/plugin/build/ios/sceneLifecycle.js +115 -0
  51. package/plugin/src/index.ts +9 -1
  52. package/plugin/src/ios/index.ts +2 -1
  53. package/plugin/src/ios/openUrlFix.ts +15 -0
  54. package/plugin/src/ios/sceneDelegate.ts +159 -0
  55. package/plugin/src/ios/sceneLifecycle.ts +134 -0
  56. package/plugin/tsconfig.tsbuildinfo +1 -1
@@ -36,7 +36,35 @@
36
36
  #import "RNFBApp/RCTConvert+FIRApp.h"
37
37
  #import "RNFBApp/RNFBAppModule.h"
38
38
  #import "RNFBApp/RNFBSharedUtils.h"
39
+ #import "RNFBAuthCacheRegistry.h"
39
40
  #import "RNFBAuthHelper.h"
41
+ #import "RNFBAuthListenerRegistry.h"
42
+ #import "RNFBAuthNullSentinelDecoder.h"
43
+
44
+ #if __has_include(<RNFBAuth/RNFBAuth-Swift.h>)
45
+ #import <RNFBAuth/RNFBAuth-Swift.h>
46
+ #elif __has_include("RNFBAuth-Swift.h")
47
+ #import "RNFBAuth-Swift.h"
48
+ #elif __has_include("RNFBHandleMapStorage-Swift.inc")
49
+ #import "RNFBHandleMapStorage-Swift.inc"
50
+ #else
51
+ #error "RNFBAuthErrorCodeMapper Swift interface not found"
52
+ #endif
53
+
54
+ @interface RNFBAuthListenerRemover : NSObject
55
+ @property(nonatomic, copy, nullable) void (^onRemove)(void);
56
+ - (void)remove;
57
+ @end
58
+
59
+ @implementation RNFBAuthListenerRemover
60
+ - (void)remove {
61
+ if (self.onRemove != nil) {
62
+ void (^block)(void) = self.onRemove;
63
+ self.onRemove = nil;
64
+ block();
65
+ }
66
+ }
67
+ @end
40
68
 
41
69
  static void RNFBAuthThrowSyncErrorWithCode(NSString *code, NSString *message) {
42
70
  @throw [NSException exceptionWithName:code
@@ -71,77 +99,15 @@ static NSString *const AUTH_STATE_CHANGED_EVENT = @"auth_state_changed";
71
99
  static NSString *const AUTH_ID_TOKEN_CHANGED_EVENT = @"auth_id_token_changed";
72
100
  static NSString *const PHONE_AUTH_STATE_CHANGED_EVENT = @"phone_auth_state_changed";
73
101
 
74
- static NSString *const AuthErrorCode_toJSErrorCode[] = {
75
- [FIRAuthErrorCodeInvalidCustomToken] = @"invalid-custom-token",
76
- [FIRAuthErrorCodeCustomTokenMismatch] = @"custom-token-mismatch",
77
- [FIRAuthErrorCodeInvalidCredential] = @"invalid-credential",
78
- [FIRAuthErrorCodeUserDisabled] = @"user-disabled",
79
- [FIRAuthErrorCodeOperationNotAllowed] = @"operation-not-allowed",
80
- [FIRAuthErrorCodeEmailAlreadyInUse] = @"email-already-in-use",
81
- [FIRAuthErrorCodeInvalidEmail] = @"invalid-email",
82
- [FIRAuthErrorCodeWrongPassword] = @"wrong-password",
83
- [FIRAuthErrorCodeTooManyRequests] = @"too-many-requests",
84
- [FIRAuthErrorCodeUserNotFound] = @"user-not-found",
85
- [FIRAuthErrorCodeAccountExistsWithDifferentCredential] =
86
- @"account-exists-with-different-credential",
87
- [FIRAuthErrorCodeRequiresRecentLogin] = @"requires-recent-login",
88
- [FIRAuthErrorCodeProviderAlreadyLinked] = @"provider-already-linked",
89
- [FIRAuthErrorCodeNoSuchProvider] = @"no-such-provider",
90
- [FIRAuthErrorCodeInvalidUserToken] = @"invalid-user-token",
91
- [FIRAuthErrorCodeNetworkError] = @"network-request-failed",
92
- [FIRAuthErrorCodeUserTokenExpired] = @"user-token-expired",
93
- [FIRAuthErrorCodeInvalidAPIKey] = @"invalid-api-key",
94
- [FIRAuthErrorCodeUserMismatch] = @"user-mismatch",
95
- [FIRAuthErrorCodeCredentialAlreadyInUse] = @"credential-already-in-use",
96
- [FIRAuthErrorCodeWeakPassword] = @"weak-password",
97
- [FIRAuthErrorCodeAppNotAuthorized] = @"app-not-authorized",
98
- [FIRAuthErrorCodeExpiredActionCode] = @"expired-action-code",
99
- [FIRAuthErrorCodeInvalidActionCode] = @"invalid-action-code",
100
- [FIRAuthErrorCodeInvalidMessagePayload] = @"invalid-message-payload",
101
- [FIRAuthErrorCodeInvalidSender] = @"invalid-sender",
102
- [FIRAuthErrorCodeInvalidRecipientEmail] = @"invalid-recipient-email",
103
- [FIRAuthErrorCodeMissingEmail] = @"invalid-email",
104
- [FIRAuthErrorCodeMissingIosBundleID] = @"missing-ios-bundle-id",
105
- [FIRAuthErrorCodeMissingAndroidPackageName] = @"missing-android-pkg-name",
106
- [FIRAuthErrorCodeUnauthorizedDomain] = @"unauthorized-domain",
107
- [FIRAuthErrorCodeInvalidContinueURI] = @"invalid-continue-uri",
108
- [FIRAuthErrorCodeMissingContinueURI] = @"missing-continue-uri",
109
- [FIRAuthErrorCodeMissingPhoneNumber] = @"missing-phone-number",
110
- [FIRAuthErrorCodeInvalidPhoneNumber] = @"invalid-phone-number",
111
- [FIRAuthErrorCodeMissingVerificationCode] = @"missing-verification-code",
112
- [FIRAuthErrorCodeInvalidVerificationCode] = @"invalid-verification-code",
113
- [FIRAuthErrorCodeMissingVerificationID] = @"missing-verification-id",
114
- [FIRAuthErrorCodeInvalidVerificationID] = @"invalid-verification-id",
115
- [FIRAuthErrorCodeMissingAppCredential] = @"missing-app-credential",
116
- [FIRAuthErrorCodeInvalidAppCredential] = @"invalid-app-credential",
117
- [FIRAuthErrorCodeSessionExpired] = @"code-expired",
118
- [FIRAuthErrorCodeQuotaExceeded] = @"quota-exceeded",
119
- [FIRAuthErrorCodeMissingAppToken] = @"missing-apns-token",
120
- [FIRAuthErrorCodeNotificationNotForwarded] = @"notification-not-forwarded",
121
- [FIRAuthErrorCodeAppNotVerified] = @"app-not-verified",
122
- [FIRAuthErrorCodeCaptchaCheckFailed] = @"captcha-check-failed",
123
- [FIRAuthErrorCodeWebContextAlreadyPresented] = @"cancelled-popup-request",
124
- [FIRAuthErrorCodeWebContextCancelled] = @"popup-closed-by-user",
125
- [FIRAuthErrorCodeAppVerificationUserInteractionFailure] =
126
- @"app-verification-user-interaction-failure",
127
- [FIRAuthErrorCodeInvalidClientID] = @"invalid-oauth-client-id",
128
- [FIRAuthErrorCodeWebNetworkRequestFailed] = @"network-request-failed",
129
- [FIRAuthErrorCodeWebInternalError] = @"internal-error",
130
- [FIRAuthErrorCodeNullUser] = @"null-user",
131
- [FIRAuthErrorCodeKeychainError] = @"keychain-error",
132
- [FIRAuthErrorCodeInternalError] = @"internal-error",
133
- [FIRAuthErrorCodeMalformedJWT] = @"malformed-jwt",
134
- [FIRAuthErrorCodeSecondFactorRequired] = @"multi-factor-auth-required"};
135
-
136
- static __strong NSMutableDictionary *authStateHandlers;
137
- static __strong NSMutableDictionary *idTokenHandlers;
102
+ static __strong RNFBAuthListenerRegistry *authStateHandlers;
103
+ static __strong RNFBAuthListenerRegistry *idTokenHandlers;
138
104
  static __strong NSMutableDictionary *emulatorConfigs;
139
105
  // Used for caching credentials between method calls.
140
- static __strong NSMutableDictionary<NSString *, FIRAuthCredential *> *credentials;
106
+ static __strong RNFBAuthCacheRegistry *credentials;
141
107
  #if TARGET_OS_IOS
142
- static __strong NSMutableDictionary<NSString *, FIRMultiFactorResolver *> *cachedResolver;
143
- static __strong NSMutableDictionary<NSString *, FIRMultiFactorSession *> *cachedSessions;
144
- static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecrets;
108
+ static __strong RNFBAuthCacheRegistry *cachedResolver;
109
+ static __strong RNFBAuthCacheRegistry *cachedSessions;
110
+ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
145
111
  #endif
146
112
 
147
113
  @interface RNFBAuthHelper ()
@@ -200,14 +166,14 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
200
166
  + (void)initializeSharedStateOnce {
201
167
  static dispatch_once_t onceToken;
202
168
  dispatch_once(&onceToken, ^{
203
- authStateHandlers = [[NSMutableDictionary alloc] init];
204
- idTokenHandlers = [[NSMutableDictionary alloc] init];
169
+ authStateHandlers = [[RNFBAuthListenerRegistry alloc] init];
170
+ idTokenHandlers = [[RNFBAuthListenerRegistry alloc] init];
205
171
  emulatorConfigs = [[NSMutableDictionary alloc] init];
206
- credentials = [[NSMutableDictionary alloc] init];
172
+ credentials = [[RNFBAuthCacheRegistry alloc] init];
207
173
  #if TARGET_OS_IOS
208
- cachedResolver = [[NSMutableDictionary alloc] init];
209
- cachedSessions = [[NSMutableDictionary alloc] init];
210
- cachedTotpSecrets = [[NSMutableDictionary alloc] init];
174
+ cachedResolver = [[RNFBAuthCacheRegistry alloc] init];
175
+ cachedSessions = [[RNFBAuthCacheRegistry alloc] init];
176
+ cachedTotpSecrets = [[RNFBAuthCacheRegistry alloc] init];
211
177
  #endif
212
178
  });
213
179
  }
@@ -215,26 +181,14 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
215
181
  + (void)invalidate {
216
182
  [self initializeSharedStateOnce];
217
183
 
218
- for (NSString *key in authStateHandlers) {
219
- FIRApp *firebaseApp = [RCTConvert firAppFromString:key];
220
-
221
- [[FIRAuth authWithApp:firebaseApp]
222
- removeAuthStateDidChangeListener:[authStateHandlers valueForKey:key]];
223
- }
224
- [authStateHandlers removeAllObjects];
225
-
226
- for (NSString *key in idTokenHandlers) {
227
- FIRApp *firebaseApp = [RCTConvert firAppFromString:key];
228
- [[FIRAuth authWithApp:firebaseApp]
229
- removeIDTokenDidChangeListener:[idTokenHandlers valueForKey:key]];
230
- }
231
- [idTokenHandlers removeAllObjects];
184
+ [authStateHandlers removeAll];
185
+ [idTokenHandlers removeAll];
232
186
 
233
- [credentials removeAllObjects];
187
+ [credentials clear];
234
188
  #if TARGET_OS_IOS
235
- [cachedResolver removeAllObjects];
236
- [cachedSessions removeAllObjects];
237
- [cachedTotpSecrets removeAllObjects];
189
+ [cachedResolver clear];
190
+ [cachedSessions clear];
191
+ [cachedTotpSecrets clear];
238
192
  #endif
239
193
  }
240
194
 
@@ -245,68 +199,75 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
245
199
  [self initializeSharedStateOnce];
246
200
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
247
201
 
248
- if (![authStateHandlers valueForKey:firebaseApp.name]) {
249
- FIRAuthStateDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firebaseApp]
250
- addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
251
- if (user != nil) {
252
- [RNFBSharedUtils sendJSEventForApp:firebaseApp
253
- name:AUTH_STATE_CHANGED_EVENT
254
- body:@{keyUser : [self firebaseUserToDict:user]}];
255
- } else {
256
- [RNFBSharedUtils sendJSEventForApp:firebaseApp name:AUTH_STATE_CHANGED_EVENT body:@{}];
257
- }
258
- }];
259
- authStateHandlers[firebaseApp.name] = newListenerHandle;
202
+ if ([authStateHandlers get:firebaseApp.name] != nil) {
203
+ return;
260
204
  }
205
+
206
+ FIRAuth *auth = [FIRAuth authWithApp:firebaseApp];
207
+ FIRAuthStateDidChangeListenerHandle newListenerHandle = [auth
208
+ addAuthStateDidChangeListener:^(FIRAuth *_Nonnull authInstance, FIRUser *_Nullable user) {
209
+ if (user != nil) {
210
+ [RNFBSharedUtils sendJSEventForApp:firebaseApp
211
+ name:AUTH_STATE_CHANGED_EVENT
212
+ body:@{keyUser : [self firebaseUserToDict:user]}];
213
+ } else {
214
+ [RNFBSharedUtils sendJSEventForApp:firebaseApp name:AUTH_STATE_CHANGED_EVENT body:@{}];
215
+ }
216
+ }];
217
+
218
+ RNFBAuthListenerRemover *remover = [[RNFBAuthListenerRemover alloc] init];
219
+ remover.onRemove = ^{
220
+ [auth removeAuthStateDidChangeListener:newListenerHandle];
221
+ };
222
+ [authStateHandlers putOrDiscard:firebaseApp.name value:remover];
261
223
  }
262
224
 
263
225
  + (void)removeAuthStateListener:(NSString *)appName {
264
226
  [self initializeSharedStateOnce];
265
227
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
266
-
267
- if ([authStateHandlers valueForKey:firebaseApp.name]) {
268
- [[FIRAuth authWithApp:firebaseApp]
269
- removeAuthStateDidChangeListener:[authStateHandlers valueForKey:firebaseApp.name]];
270
- [authStateHandlers removeObjectForKey:firebaseApp.name];
271
- }
228
+ [authStateHandlers takeAndRemove:firebaseApp.name];
272
229
  }
273
230
 
274
231
  + (void)addIdTokenListener:(NSString *)appName {
275
232
  [self initializeSharedStateOnce];
276
233
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
277
234
 
278
- if (![idTokenHandlers valueForKey:firebaseApp.name]) {
279
- FIRIDTokenDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firebaseApp]
280
- addIDTokenDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
281
- if (user != nil) {
282
- [RNFBSharedUtils sendJSEventForApp:firebaseApp
283
- name:AUTH_ID_TOKEN_CHANGED_EVENT
284
- body:@{keyUser : [self firebaseUserToDict:user]}];
285
- } else {
286
- [RNFBSharedUtils sendJSEventForApp:firebaseApp
287
- name:AUTH_ID_TOKEN_CHANGED_EVENT
288
- body:@{}];
289
- }
290
- }];
291
- idTokenHandlers[firebaseApp.name] = newListenerHandle;
235
+ if ([idTokenHandlers get:firebaseApp.name] != nil) {
236
+ return;
292
237
  }
238
+
239
+ FIRAuth *auth = [FIRAuth authWithApp:firebaseApp];
240
+ FIRIDTokenDidChangeListenerHandle newListenerHandle =
241
+ [auth addIDTokenDidChangeListener:^(FIRAuth *_Nonnull authInstance, FIRUser *_Nullable user) {
242
+ if (user != nil) {
243
+ [RNFBSharedUtils sendJSEventForApp:firebaseApp
244
+ name:AUTH_ID_TOKEN_CHANGED_EVENT
245
+ body:@{keyUser : [self firebaseUserToDict:user]}];
246
+ } else {
247
+ [RNFBSharedUtils sendJSEventForApp:firebaseApp name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{}];
248
+ }
249
+ }];
250
+
251
+ RNFBAuthListenerRemover *remover = [[RNFBAuthListenerRemover alloc] init];
252
+ remover.onRemove = ^{
253
+ [auth removeIDTokenDidChangeListener:newListenerHandle];
254
+ };
255
+ [idTokenHandlers putOrDiscard:firebaseApp.name value:remover];
293
256
  }
294
257
 
295
258
  + (void)removeIdTokenListener:(NSString *)appName {
296
259
  [self initializeSharedStateOnce];
297
260
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
298
-
299
- if ([idTokenHandlers valueForKey:firebaseApp.name]) {
300
- [[FIRAuth authWithApp:firebaseApp]
301
- removeIDTokenDidChangeListener:[idTokenHandlers valueForKey:firebaseApp.name]];
302
- [idTokenHandlers removeObjectForKey:firebaseApp.name];
303
- }
261
+ [idTokenHandlers takeAndRemove:firebaseApp.name];
304
262
  }
305
263
 
306
264
  + (void)configureAuthDomain:(NSString *)appName {
307
265
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
308
266
 
309
- NSString *authDomain = [RNFBAppModule getCustomDomain:firebaseApp.name];
267
+ // customAuthDomains is keyed by the JS app name ([DEFAULT]); FIRApp.name for the default app
268
+ // is __FIRAPP_DEFAULT. Look up with the existing JS-name converter (no parallel key helper).
269
+ NSString *authDomain =
270
+ [RNFBAppModule getCustomDomain:[RNFBSharedUtils getAppJavaScriptName:firebaseApp.name]];
310
271
  DLog(@"RNFBAuth app: %@ customAuthDomain: %@", firebaseApp.name, authDomain);
311
272
  if (authDomain != nil) {
312
273
  [FIRAuth authWithApp:firebaseApp].customAuthDomain = authDomain;
@@ -640,15 +601,18 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
640
601
 
641
602
  if (user) {
642
603
  FIRUserProfileChangeRequest *changeRequest = [user profileChangeRequest];
643
- NSMutableArray *allKeys = [[props allKeys] mutableCopy];
604
+ // The decoder omits NSNull keys (subscript → nil). Iterate the original props keys so a
605
+ // cleared displayName/photoURL still reaches setValue:forKey: with nil.
606
+ NSDictionary *decodedProps = [RNFBAuthNullSentinelDecoder decodedProfileProps:props];
644
607
 
645
- for (NSString *key in allKeys) {
608
+ for (NSString *key in props) {
646
609
  @try {
610
+ id value = decodedProps[key];
647
611
  if ([key isEqualToString:keyPhotoUrl]) {
648
- NSURL *url = [NSURL URLWithString:[props valueForKey:key]];
649
- [changeRequest setValue:url forKey:key];
612
+ [changeRequest setValue:[RNFBAuthNullSentinelDecoder photoURLFromDecodedValue:value]
613
+ forKey:key];
650
614
  } else {
651
- [changeRequest setValue:props[key] forKey:key];
615
+ [changeRequest setValue:value forKey:key];
652
616
  }
653
617
  } @catch (NSException *exception) {
654
618
  DLog(@"Exception occurred while configuring: %@", exception);
@@ -1054,7 +1018,8 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1054
1018
  [self initializeSharedStateOnce];
1055
1019
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
1056
1020
 
1057
- if ([cachedResolver valueForKey:sessionKey] == nil) {
1021
+ FIRMultiFactorResolver *resolver = [cachedResolver get:sessionKey];
1022
+ if (resolver == nil) {
1058
1023
  [RNFBSharedUtils
1059
1024
  rejectPromiseWithUserInfo:reject
1060
1025
  userInfo:(NSMutableDictionary *)@{
@@ -1063,10 +1028,10 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1063
1028
  }];
1064
1029
  return;
1065
1030
  }
1066
- FIRMultiFactorSession *session = cachedResolver[sessionKey].session;
1031
+ FIRMultiFactorSession *session = resolver.session;
1067
1032
  NSPredicate *findByUid = [NSPredicate predicateWithFormat:@"UID == %@", hintUid];
1068
1033
  FIRMultiFactorInfo *_Nullable hint =
1069
- [[cachedResolver[sessionKey].hints filteredArrayUsingPredicate:findByUid] firstObject];
1034
+ [[resolver.hints filteredArrayUsingPredicate:findByUid] firstObject];
1070
1035
  if (hint == nil) {
1071
1036
  [RNFBSharedUtils rejectPromiseWithUserInfo:reject
1072
1037
  userInfo:(NSMutableDictionary *)@{
@@ -1087,8 +1052,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1087
1052
  if (error) {
1088
1053
  [self promiseRejectAuthException:reject error:error];
1089
1054
  } else {
1090
- DLog(@"verificationID: %@", verificationID)
1091
- resolve(verificationID);
1055
+ resolve(verificationID);
1092
1056
  }
1093
1057
  }];
1094
1058
  }
@@ -1102,9 +1066,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1102
1066
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
1103
1067
 
1104
1068
  DLog(@"verifyPhoneNumberForMultifactor using app: %@", firebaseApp.name);
1105
- DLog(@"verifyPhoneNumberForMultifactor phoneNumber: %@", phoneNumber);
1106
- DLog(@"verifyPhoneNumberForMultifactor sessionKey: %@", sessionKey);
1107
- FIRMultiFactorSession *session = cachedSessions[sessionKey];
1069
+ FIRMultiFactorSession *session = [cachedSessions get:sessionKey];
1108
1070
  if (session == nil) {
1109
1071
  [RNFBSharedUtils rejectPromiseWithUserInfo:reject
1110
1072
  userInfo:(NSMutableDictionary *)@{
@@ -1142,23 +1104,22 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1142
1104
  [[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firebaseApp]]
1143
1105
  credentialWithVerificationID:verificationId
1144
1106
  verificationCode:verificationCode];
1145
- DLog(@"credential: %@", credential);
1146
-
1147
1107
  FIRMultiFactorAssertion *assertion =
1148
1108
  [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
1149
1109
 
1150
- [cachedResolver[session] resolveSignInWithAssertion:assertion
1151
- completion:^(FIRAuthDataResult *_Nullable authResult,
1152
- NSError *_Nullable error) {
1153
- DLog(@"authError: %@", error) if (error) {
1154
- [self promiseRejectAuthException:reject error:error];
1155
- }
1156
- else {
1157
- [self promiseWithAuthResult:resolve
1158
- rejecter:reject
1159
- authResult:authResult];
1160
- }
1161
- }];
1110
+ FIRMultiFactorResolver *signInResolver = [cachedResolver get:session];
1111
+ [signInResolver resolveSignInWithAssertion:assertion
1112
+ completion:^(FIRAuthDataResult *_Nullable authResult,
1113
+ NSError *_Nullable error) {
1114
+ DLog(@"authError: %@", error) if (error) {
1115
+ [self promiseRejectAuthException:reject error:error];
1116
+ }
1117
+ else {
1118
+ [self promiseWithAuthResult:resolve
1119
+ rejecter:reject
1120
+ authResult:authResult];
1121
+ }
1122
+ }];
1162
1123
  }
1163
1124
 
1164
1125
  + (void)resolveTotpSignIn:(NSString *)appName
@@ -1175,19 +1136,19 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1175
1136
  FIRMultiFactorAssertion *assertion =
1176
1137
  [FIRTOTPMultiFactorGenerator assertionForSignInWithEnrollmentID:uid
1177
1138
  oneTimePassword:oneTimePassword];
1178
- [cachedResolver[sessionKey] resolveSignInWithAssertion:assertion
1179
- completion:^(FIRAuthDataResult *_Nullable authResult,
1180
- NSError *_Nullable error) {
1181
- DLog(@"authError: %@", error) if (error) {
1182
- [self promiseRejectAuthException:reject
1183
- error:error];
1184
- }
1185
- else {
1186
- [self promiseWithAuthResult:resolve
1187
- rejecter:reject
1188
- authResult:authResult];
1189
- }
1190
- }];
1139
+ FIRMultiFactorResolver *totpSignInResolver = [cachedResolver get:sessionKey];
1140
+ [totpSignInResolver resolveSignInWithAssertion:assertion
1141
+ completion:^(FIRAuthDataResult *_Nullable authResult,
1142
+ NSError *_Nullable error) {
1143
+ DLog(@"authError: %@", error) if (error) {
1144
+ [self promiseRejectAuthException:reject error:error];
1145
+ }
1146
+ else {
1147
+ [self promiseWithAuthResult:resolve
1148
+ rejecter:reject
1149
+ authResult:authResult];
1150
+ }
1151
+ }];
1191
1152
  }
1192
1153
 
1193
1154
  + (void)generateTotpSecret:(NSString *)appName
@@ -1199,9 +1160,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1199
1160
 
1200
1161
  DLog(@"using instance resolve generateTotpSecret: %@", firebaseApp.name);
1201
1162
 
1202
- FIRMultiFactorSession *session = cachedSessions[sessionKey];
1203
- DLog(@"using sessionKey: %@", sessionKey);
1204
- DLog(@"using session: %@", session);
1163
+ FIRMultiFactorSession *session = [cachedSessions get:sessionKey];
1205
1164
  [FIRTOTPMultiFactorGenerator
1206
1165
  generateSecretWithMultiFactorSession:session
1207
1166
  completion:^(FIRTOTPSecret *_Nullable totpSecret,
@@ -1211,9 +1170,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1211
1170
  }
1212
1171
  else {
1213
1172
  NSString *secretKey = totpSecret.sharedSecretKey;
1214
- DLog(@"secretKey generated: %@", secretKey);
1215
- cachedTotpSecrets[secretKey] = totpSecret;
1216
- DLog(@"cachedSecret: %@", cachedTotpSecrets[secretKey]);
1173
+ [cachedTotpSecrets putReplacing:secretKey value:totpSecret];
1217
1174
  resolve(@{
1218
1175
  @"secretKey" : secretKey,
1219
1176
  });
@@ -1229,14 +1186,12 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1229
1186
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
1230
1187
 
1231
1188
  DLog(@"generateQrCodeUrl using instance resolve generateQrCodeUrl: %@", firebaseApp.name);
1232
- DLog(@"generateQrCodeUrl using secretKey: %@", secretKey);
1233
- FIRTOTPSecret *totpSecret = cachedTotpSecrets[secretKey];
1189
+ FIRTOTPSecret *totpSecret = [cachedTotpSecrets get:secretKey];
1234
1190
  if (!totpSecret) {
1235
1191
  RNFBAuthThrowSyncErrorWithCode(@"invalid-multi-factor-secret",
1236
1192
  @"can't find secret for provided key");
1237
1193
  }
1238
1194
  NSString *url = [totpSecret generateQRCodeURLWithAccountName:account issuer:issuer];
1239
- DLog(@"generateQrCodeUrl got QR Code URL %@", url);
1240
1195
  return url;
1241
1196
  }
1242
1197
 
@@ -1245,9 +1200,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1245
1200
  qrCodeUri:(NSString *)qrCodeUri {
1246
1201
  [self initializeSharedStateOnce];
1247
1202
 
1248
- DLog(@"generateQrCodeUrl using secretKey: %@", secretKey);
1249
- FIRTOTPSecret *totpSecret = cachedTotpSecrets[secretKey];
1250
- DLog(@"openInOtpApp using qrCodeUri: %@", qrCodeUri);
1203
+ FIRTOTPSecret *totpSecret = [cachedTotpSecrets get:secretKey];
1251
1204
  [totpSecret openInOTPAppWithQRCodeURL:qrCodeUri];
1252
1205
  }
1253
1206
 
@@ -1266,7 +1219,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1266
1219
  }
1267
1220
 
1268
1221
  NSString *sessionId = [NSString stringWithFormat:@"%@", @([session hash])];
1269
- cachedSessions[sessionId] = session;
1222
+ [cachedSessions putReplacing:sessionId value:session];
1270
1223
  resolve(sessionId);
1271
1224
  }];
1272
1225
  }
@@ -1333,9 +1286,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1333
1286
 
1334
1287
  DLog(@"using instance finalizeTotpEnrollment: %@", firebaseApp.name);
1335
1288
 
1336
- FIRTOTPSecret *cachedTotpSecret = cachedTotpSecrets[totpSecret];
1337
- DLog(@"using totpSecretKey: %@", totpSecret);
1338
- DLog(@"using cachedSecret: %@", cachedTotpSecret);
1289
+ FIRTOTPSecret *cachedTotpSecret = [cachedTotpSecrets get:totpSecret];
1339
1290
  FIRTOTPMultiFactorAssertion *assertion =
1340
1291
  [FIRTOTPMultiFactorGenerator assertionForEnrollmentWithSecret:cachedTotpSecret
1341
1292
  oneTimePassword:verificationCode];
@@ -1789,8 +1740,9 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1789
1740
  FIRAuthCredential *credential;
1790
1741
 
1791
1742
  // First check if we cached an authToken
1792
- if (credentials[authToken] != nil && ![credentials[authToken] isEqual:[NSNull null]]) {
1793
- credential = credentials[authToken];
1743
+ FIRAuthCredential *cachedCredential = [credentials get:authToken];
1744
+ if (cachedCredential != nil) {
1745
+ credential = cachedCredential;
1794
1746
  } else if ([provider compare:@"twitter.com" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
1795
1747
  credential = [FIRTwitterAuthProvider credentialWithToken:authToken secret:authTokenSecret];
1796
1748
  } else if ([provider compare:@"facebook.com" options:NSCaseInsensitiveSearch] == NSOrderedSame &&
@@ -1895,82 +1847,15 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1895
1847
 
1896
1848
  + (NSDictionary *)getJSError:(NSError *)error {
1897
1849
  [self initializeSharedStateOnce];
1898
- NSString *code = AuthErrorCode_toJSErrorCode[error.code];
1850
+ NSString *code = [RNFBAuthErrorCodeMapper jsErrorCodeForAuthErrorCode:error.code];
1899
1851
  NSString *message = [error localizedDescription];
1900
1852
  NSString *nativeErrorMessage = [error localizedDescription];
1901
1853
 
1902
1854
  if (code == nil) code = @"unknown";
1903
1855
 
1904
- // TODO(Salakar): replace these with a AuthErrorCode_toJSErrorMessage map (like codes now does)
1905
- switch (error.code) {
1906
- case FIRAuthErrorCodeInvalidCustomToken:
1907
- message = @"The custom token format is incorrect. Please check the documentation.";
1908
- break;
1909
- case FIRAuthErrorCodeCustomTokenMismatch:
1910
- message = @"The custom token corresponds to a different audience.";
1911
- break;
1912
- case FIRAuthErrorCodeInvalidCredential:
1913
- message = @"The supplied auth credential is malformed or has expired.";
1914
- break;
1915
- case FIRAuthErrorCodeInvalidEmail:
1916
- message = @"The email address is badly formatted.";
1917
- break;
1918
- case FIRAuthErrorCodeWrongPassword:
1919
- message = @"The password is invalid or the user does not have a password.";
1920
- break;
1921
- case FIRAuthErrorCodeUserMismatch:
1922
- message = @"The supplied credentials do not correspond to the previously signed in user.";
1923
- break;
1924
- case FIRAuthErrorCodeRequiresRecentLogin:
1925
- message = @"This operation is sensitive and requires recent authentication. Log in again "
1926
- @"before retrying this request.";
1927
- break;
1928
- case FIRAuthErrorCodeSecondFactorRequired:
1929
- message = @"Please complete a second factor challenge to finish signing into this account.";
1930
- break;
1931
- case FIRAuthErrorCodeAccountExistsWithDifferentCredential:
1932
- message = @"An account already exists with the same email address but different sign-in "
1933
- @"credentials. Sign in using a provider associated with this email address.";
1934
- break;
1935
- case FIRAuthErrorCodeEmailAlreadyInUse:
1936
- message = @"The email address is already in use by another account.";
1937
- break;
1938
- case FIRAuthErrorCodeCredentialAlreadyInUse:
1939
- message = @"This credential is already associated with a different user account.";
1940
- break;
1941
- case FIRAuthErrorCodeUserDisabled:
1942
- message = @"The user account has been disabled by an administrator.";
1943
- break;
1944
- case FIRAuthErrorCodeUserTokenExpired:
1945
- message = @"The user's credential is no longer valid. The user must sign in again.";
1946
- break;
1947
- case FIRAuthErrorCodeUserNotFound:
1948
- message = @"There is no user record corresponding to this identifier. The user may have been "
1949
- @"deleted.";
1950
- break;
1951
- case FIRAuthErrorCodeInvalidUserToken:
1952
- message = @"The user's credential is no longer valid. The user must sign in again.";
1953
- break;
1954
- case FIRAuthErrorCodeWeakPassword:
1955
- message = @"The given password is invalid.";
1956
- break;
1957
- case FIRAuthErrorCodeOperationNotAllowed:
1958
- message = @"This operation is not allowed. You must enable this service in the console.";
1959
- break;
1960
- case FIRAuthErrorCodeNetworkError:
1961
- message = @"A network error has occurred, please try again.";
1962
- break;
1963
- case FIRAuthErrorCodeInternalError:
1964
- message = @"An internal error has occurred, please try again.";
1965
- break;
1966
- case FIRAuthErrorCodeInvalidPhoneNumber:
1967
- message = @"The format of the phone number provided is incorrect. "
1968
- @"Please enter the phone number in a format that can be parsed into E.164 format. "
1969
- @"E.164 phone numbers are written in the format [+][country code][subscriber "
1970
- @"number including area code].";
1971
- break;
1972
- default:
1973
- break;
1856
+ NSString *overrideMessage = [RNFBAuthErrorCodeMapper jsErrorMessageForAuthErrorCode:error.code];
1857
+ if (overrideMessage != nil) {
1858
+ message = overrideMessage;
1974
1859
  }
1975
1860
 
1976
1861
  NSDictionary *authCredentialDict = nil;
@@ -1986,7 +1871,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
1986
1871
  resolverDict = [self multiFactorResolverToDict:resolver];
1987
1872
 
1988
1873
  NSString *sessionKey = [NSString stringWithFormat:@"%@", @([resolver.session hash])];
1989
- cachedResolver[sessionKey] = resolver;
1874
+ [cachedResolver putReplacing:sessionKey value:resolver];
1990
1875
  }
1991
1876
  #endif
1992
1877
 
@@ -2175,7 +2060,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
2175
2060
  NSString *authCredentialHash = [NSString stringWithFormat:@"%@", @([authCredential hash])];
2176
2061
 
2177
2062
  // Temporarily store the non-serializable credential for later
2178
- credentials[authCredentialHash] = authCredential;
2063
+ [credentials putReplacing:authCredentialHash value:authCredential];
2179
2064
 
2180
2065
  return @{
2181
2066
  keyProviderId : authCredential.provider,
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <Foundation/Foundation.h>
19
+
20
+ NS_ASSUME_NONNULL_BEGIN
21
+
22
+ /**
23
+ * Auth-state / id-token listener map. Unique `put` / `putOrDiscard`; callers `take` or `removeAll`
24
+ * then `remove` outside the HandleMap lock. Skip-if-registered is `get != nil`. Stored values are
25
+ * expected to respond to `remove`.
26
+ */
27
+ @interface RNFBAuthListenerRegistry : NSObject
28
+
29
+ - (BOOL)put:(id)key value:(id)value error:(NSError *_Nullable *_Nullable)error;
30
+ /// Unique put. On collision, `remove`s the incoming value and leaves the existing mapping.
31
+ - (BOOL)putOrDiscard:(id)key value:(id)value;
32
+ - (nullable id)get:(id)key;
33
+ - (nullable id)take:(id)key;
34
+ - (void)takeAndRemove:(id)key;
35
+ - (void)removeAll;
36
+
37
+ @end
38
+
39
+ NS_ASSUME_NONNULL_END