@react-native-firebase/auth 26.4.0 → 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 (47) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/RNFBAuth.podspec +8 -2
  3. package/android/build.gradle +3 -0
  4. package/android/src/main/java/io/invertase/firebase/auth/NativeRNFBTurboAuth.java +1 -3
  5. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthCacheRegistry.kt +77 -0
  6. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthListenerRegistry.kt +76 -0
  7. package/android/src/test/java/io/invertase/firebase/auth/RNFBAuthCacheRegistryTest.java +12 -0
  8. package/dist/module/index.js +1 -2
  9. package/dist/module/index.js.map +1 -1
  10. package/dist/module/version.js +1 -1
  11. package/dist/typescript/lib/types/internal.d.ts +2 -3
  12. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  13. package/dist/typescript/lib/version.d.ts +1 -1
  14. package/ios/RNFBAuth/RNFBAuthCacheRegistry.m +27 -8
  15. package/ios/RNFBAuth/RNFBAuthCacheRegistryStorage.swift +53 -0
  16. package/ios/RNFBAuth/RNFBAuthErrorCodeMapper.swift +333 -0
  17. package/ios/RNFBAuth/RNFBAuthHelper.m +24 -154
  18. package/ios/RNFBAuth/RNFBAuthListenerRegistry.m +26 -26
  19. package/ios/RNFBAuth/RNFBAuthListenerRegistryStorage.swift +76 -0
  20. package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.h +40 -0
  21. package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.m +49 -0
  22. package/ios/RNFBAuth.xcodeproj/project.pbxproj +22 -0
  23. package/ios/RNFBAuthUnitTests/RNFBAuthCacheRegistryStorageTests.swift +72 -0
  24. package/ios/RNFBAuthUnitTests/RNFBAuthErrorCodeMapperTests.swift +250 -0
  25. package/ios/RNFBAuthUnitTests/RNFBAuthListenerRegistryStorageTests.swift +122 -0
  26. package/ios/RNFBAuthUnitTests/RNFBAuthNullSentinelDecodeTests.m +78 -0
  27. package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/project.pbxproj +50 -0
  28. package/lib/index.ts +1 -1
  29. package/lib/types/internal.ts +2 -2
  30. package/lib/version.ts +1 -1
  31. package/package.json +4 -4
  32. package/plugin/build/index.js +4 -0
  33. package/plugin/build/ios/index.d.ts +2 -1
  34. package/plugin/build/ios/index.js +3 -1
  35. package/plugin/build/ios/openUrlFix.js +12 -0
  36. package/plugin/build/ios/sceneDelegate.d.ts +34 -0
  37. package/plugin/build/ios/sceneDelegate.js +127 -0
  38. package/plugin/build/ios/sceneLifecycle.d.ts +32 -0
  39. package/plugin/build/ios/sceneLifecycle.js +115 -0
  40. package/plugin/src/index.ts +9 -1
  41. package/plugin/src/ios/index.ts +2 -1
  42. package/plugin/src/ios/openUrlFix.ts +15 -0
  43. package/plugin/src/ios/sceneDelegate.ts +159 -0
  44. package/plugin/src/ios/sceneLifecycle.ts +134 -0
  45. package/plugin/tsconfig.tsbuildinfo +1 -1
  46. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthCacheRegistry.java +0 -66
  47. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthListenerRegistry.java +0 -76
@@ -39,6 +39,17 @@
39
39
  #import "RNFBAuthCacheRegistry.h"
40
40
  #import "RNFBAuthHelper.h"
41
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
42
53
 
43
54
  @interface RNFBAuthListenerRemover : NSObject
44
55
  @property(nonatomic, copy, nullable) void (^onRemove)(void);
@@ -88,68 +99,6 @@ static NSString *const AUTH_STATE_CHANGED_EVENT = @"auth_state_changed";
88
99
  static NSString *const AUTH_ID_TOKEN_CHANGED_EVENT = @"auth_id_token_changed";
89
100
  static NSString *const PHONE_AUTH_STATE_CHANGED_EVENT = @"phone_auth_state_changed";
90
101
 
91
- static NSString *const AuthErrorCode_toJSErrorCode[] = {
92
- [FIRAuthErrorCodeInvalidCustomToken] = @"invalid-custom-token",
93
- [FIRAuthErrorCodeCustomTokenMismatch] = @"custom-token-mismatch",
94
- [FIRAuthErrorCodeInvalidCredential] = @"invalid-credential",
95
- [FIRAuthErrorCodeUserDisabled] = @"user-disabled",
96
- [FIRAuthErrorCodeOperationNotAllowed] = @"operation-not-allowed",
97
- [FIRAuthErrorCodeEmailAlreadyInUse] = @"email-already-in-use",
98
- [FIRAuthErrorCodeInvalidEmail] = @"invalid-email",
99
- [FIRAuthErrorCodeWrongPassword] = @"wrong-password",
100
- [FIRAuthErrorCodeTooManyRequests] = @"too-many-requests",
101
- [FIRAuthErrorCodeUserNotFound] = @"user-not-found",
102
- [FIRAuthErrorCodeAccountExistsWithDifferentCredential] =
103
- @"account-exists-with-different-credential",
104
- [FIRAuthErrorCodeRequiresRecentLogin] = @"requires-recent-login",
105
- [FIRAuthErrorCodeProviderAlreadyLinked] = @"provider-already-linked",
106
- [FIRAuthErrorCodeNoSuchProvider] = @"no-such-provider",
107
- [FIRAuthErrorCodeInvalidUserToken] = @"invalid-user-token",
108
- [FIRAuthErrorCodeNetworkError] = @"network-request-failed",
109
- [FIRAuthErrorCodeUserTokenExpired] = @"user-token-expired",
110
- [FIRAuthErrorCodeInvalidAPIKey] = @"invalid-api-key",
111
- [FIRAuthErrorCodeUserMismatch] = @"user-mismatch",
112
- [FIRAuthErrorCodeCredentialAlreadyInUse] = @"credential-already-in-use",
113
- [FIRAuthErrorCodeWeakPassword] = @"weak-password",
114
- [FIRAuthErrorCodeAppNotAuthorized] = @"app-not-authorized",
115
- [FIRAuthErrorCodeExpiredActionCode] = @"expired-action-code",
116
- [FIRAuthErrorCodeInvalidActionCode] = @"invalid-action-code",
117
- [FIRAuthErrorCodeInvalidMessagePayload] = @"invalid-message-payload",
118
- [FIRAuthErrorCodeInvalidSender] = @"invalid-sender",
119
- [FIRAuthErrorCodeInvalidRecipientEmail] = @"invalid-recipient-email",
120
- [FIRAuthErrorCodeMissingEmail] = @"invalid-email",
121
- [FIRAuthErrorCodeMissingIosBundleID] = @"missing-ios-bundle-id",
122
- [FIRAuthErrorCodeMissingAndroidPackageName] = @"missing-android-pkg-name",
123
- [FIRAuthErrorCodeUnauthorizedDomain] = @"unauthorized-domain",
124
- [FIRAuthErrorCodeInvalidContinueURI] = @"invalid-continue-uri",
125
- [FIRAuthErrorCodeMissingContinueURI] = @"missing-continue-uri",
126
- [FIRAuthErrorCodeMissingPhoneNumber] = @"missing-phone-number",
127
- [FIRAuthErrorCodeInvalidPhoneNumber] = @"invalid-phone-number",
128
- [FIRAuthErrorCodeMissingVerificationCode] = @"missing-verification-code",
129
- [FIRAuthErrorCodeInvalidVerificationCode] = @"invalid-verification-code",
130
- [FIRAuthErrorCodeMissingVerificationID] = @"missing-verification-id",
131
- [FIRAuthErrorCodeInvalidVerificationID] = @"invalid-verification-id",
132
- [FIRAuthErrorCodeMissingAppCredential] = @"missing-app-credential",
133
- [FIRAuthErrorCodeInvalidAppCredential] = @"invalid-app-credential",
134
- [FIRAuthErrorCodeSessionExpired] = @"code-expired",
135
- [FIRAuthErrorCodeQuotaExceeded] = @"quota-exceeded",
136
- [FIRAuthErrorCodeMissingAppToken] = @"missing-apns-token",
137
- [FIRAuthErrorCodeNotificationNotForwarded] = @"notification-not-forwarded",
138
- [FIRAuthErrorCodeAppNotVerified] = @"app-not-verified",
139
- [FIRAuthErrorCodeCaptchaCheckFailed] = @"captcha-check-failed",
140
- [FIRAuthErrorCodeWebContextAlreadyPresented] = @"cancelled-popup-request",
141
- [FIRAuthErrorCodeWebContextCancelled] = @"popup-closed-by-user",
142
- [FIRAuthErrorCodeAppVerificationUserInteractionFailure] =
143
- @"app-verification-user-interaction-failure",
144
- [FIRAuthErrorCodeInvalidClientID] = @"invalid-oauth-client-id",
145
- [FIRAuthErrorCodeWebNetworkRequestFailed] = @"network-request-failed",
146
- [FIRAuthErrorCodeWebInternalError] = @"internal-error",
147
- [FIRAuthErrorCodeNullUser] = @"null-user",
148
- [FIRAuthErrorCodeKeychainError] = @"keychain-error",
149
- [FIRAuthErrorCodeInternalError] = @"internal-error",
150
- [FIRAuthErrorCodeMalformedJWT] = @"malformed-jwt",
151
- [FIRAuthErrorCodeSecondFactorRequired] = @"multi-factor-auth-required"};
152
-
153
102
  static __strong RNFBAuthListenerRegistry *authStateHandlers;
154
103
  static __strong RNFBAuthListenerRegistry *idTokenHandlers;
155
104
  static __strong NSMutableDictionary *emulatorConfigs;
@@ -652,15 +601,18 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
652
601
 
653
602
  if (user) {
654
603
  FIRUserProfileChangeRequest *changeRequest = [user profileChangeRequest];
655
- 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];
656
607
 
657
- for (NSString *key in allKeys) {
608
+ for (NSString *key in props) {
658
609
  @try {
610
+ id value = decodedProps[key];
659
611
  if ([key isEqualToString:keyPhotoUrl]) {
660
- NSURL *url = [NSURL URLWithString:[props valueForKey:key]];
661
- [changeRequest setValue:url forKey:key];
612
+ [changeRequest setValue:[RNFBAuthNullSentinelDecoder photoURLFromDecodedValue:value]
613
+ forKey:key];
662
614
  } else {
663
- [changeRequest setValue:props[key] forKey:key];
615
+ [changeRequest setValue:value forKey:key];
664
616
  }
665
617
  } @catch (NSException *exception) {
666
618
  DLog(@"Exception occurred while configuring: %@", exception);
@@ -1100,8 +1052,7 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
1100
1052
  if (error) {
1101
1053
  [self promiseRejectAuthException:reject error:error];
1102
1054
  } else {
1103
- DLog(@"verificationID: %@", verificationID)
1104
- resolve(verificationID);
1055
+ resolve(verificationID);
1105
1056
  }
1106
1057
  }];
1107
1058
  }
@@ -1115,8 +1066,6 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
1115
1066
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
1116
1067
 
1117
1068
  DLog(@"verifyPhoneNumberForMultifactor using app: %@", firebaseApp.name);
1118
- DLog(@"verifyPhoneNumberForMultifactor phoneNumber: %@", phoneNumber);
1119
- DLog(@"verifyPhoneNumberForMultifactor sessionKey: %@", sessionKey);
1120
1069
  FIRMultiFactorSession *session = [cachedSessions get:sessionKey];
1121
1070
  if (session == nil) {
1122
1071
  [RNFBSharedUtils rejectPromiseWithUserInfo:reject
@@ -1155,8 +1104,6 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
1155
1104
  [[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firebaseApp]]
1156
1105
  credentialWithVerificationID:verificationId
1157
1106
  verificationCode:verificationCode];
1158
- DLog(@"credential: %@", credential);
1159
-
1160
1107
  FIRMultiFactorAssertion *assertion =
1161
1108
  [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
1162
1109
 
@@ -1214,8 +1161,6 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
1214
1161
  DLog(@"using instance resolve generateTotpSecret: %@", firebaseApp.name);
1215
1162
 
1216
1163
  FIRMultiFactorSession *session = [cachedSessions get:sessionKey];
1217
- DLog(@"using sessionKey: %@", sessionKey);
1218
- DLog(@"using session: %@", session);
1219
1164
  [FIRTOTPMultiFactorGenerator
1220
1165
  generateSecretWithMultiFactorSession:session
1221
1166
  completion:^(FIRTOTPSecret *_Nullable totpSecret,
@@ -1225,9 +1170,7 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
1225
1170
  }
1226
1171
  else {
1227
1172
  NSString *secretKey = totpSecret.sharedSecretKey;
1228
- DLog(@"secretKey generated: %@", secretKey);
1229
1173
  [cachedTotpSecrets putReplacing:secretKey value:totpSecret];
1230
- DLog(@"cachedSecret: %@", [cachedTotpSecrets get:secretKey]);
1231
1174
  resolve(@{
1232
1175
  @"secretKey" : secretKey,
1233
1176
  });
@@ -1243,14 +1186,12 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
1243
1186
  FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
1244
1187
 
1245
1188
  DLog(@"generateQrCodeUrl using instance resolve generateQrCodeUrl: %@", firebaseApp.name);
1246
- DLog(@"generateQrCodeUrl using secretKey: %@", secretKey);
1247
1189
  FIRTOTPSecret *totpSecret = [cachedTotpSecrets get:secretKey];
1248
1190
  if (!totpSecret) {
1249
1191
  RNFBAuthThrowSyncErrorWithCode(@"invalid-multi-factor-secret",
1250
1192
  @"can't find secret for provided key");
1251
1193
  }
1252
1194
  NSString *url = [totpSecret generateQRCodeURLWithAccountName:account issuer:issuer];
1253
- DLog(@"generateQrCodeUrl got QR Code URL %@", url);
1254
1195
  return url;
1255
1196
  }
1256
1197
 
@@ -1259,9 +1200,7 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
1259
1200
  qrCodeUri:(NSString *)qrCodeUri {
1260
1201
  [self initializeSharedStateOnce];
1261
1202
 
1262
- DLog(@"generateQrCodeUrl using secretKey: %@", secretKey);
1263
1203
  FIRTOTPSecret *totpSecret = [cachedTotpSecrets get:secretKey];
1264
- DLog(@"openInOtpApp using qrCodeUri: %@", qrCodeUri);
1265
1204
  [totpSecret openInOTPAppWithQRCodeURL:qrCodeUri];
1266
1205
  }
1267
1206
 
@@ -1348,8 +1287,6 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
1348
1287
  DLog(@"using instance finalizeTotpEnrollment: %@", firebaseApp.name);
1349
1288
 
1350
1289
  FIRTOTPSecret *cachedTotpSecret = [cachedTotpSecrets get:totpSecret];
1351
- DLog(@"using totpSecretKey: %@", totpSecret);
1352
- DLog(@"using cachedSecret: %@", cachedTotpSecret);
1353
1290
  FIRTOTPMultiFactorAssertion *assertion =
1354
1291
  [FIRTOTPMultiFactorGenerator assertionForEnrollmentWithSecret:cachedTotpSecret
1355
1292
  oneTimePassword:verificationCode];
@@ -1910,82 +1847,15 @@ static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
1910
1847
 
1911
1848
  + (NSDictionary *)getJSError:(NSError *)error {
1912
1849
  [self initializeSharedStateOnce];
1913
- NSString *code = AuthErrorCode_toJSErrorCode[error.code];
1850
+ NSString *code = [RNFBAuthErrorCodeMapper jsErrorCodeForAuthErrorCode:error.code];
1914
1851
  NSString *message = [error localizedDescription];
1915
1852
  NSString *nativeErrorMessage = [error localizedDescription];
1916
1853
 
1917
1854
  if (code == nil) code = @"unknown";
1918
1855
 
1919
- // TODO(Salakar): replace these with a AuthErrorCode_toJSErrorMessage map (like codes now does)
1920
- switch (error.code) {
1921
- case FIRAuthErrorCodeInvalidCustomToken:
1922
- message = @"The custom token format is incorrect. Please check the documentation.";
1923
- break;
1924
- case FIRAuthErrorCodeCustomTokenMismatch:
1925
- message = @"The custom token corresponds to a different audience.";
1926
- break;
1927
- case FIRAuthErrorCodeInvalidCredential:
1928
- message = @"The supplied auth credential is malformed or has expired.";
1929
- break;
1930
- case FIRAuthErrorCodeInvalidEmail:
1931
- message = @"The email address is badly formatted.";
1932
- break;
1933
- case FIRAuthErrorCodeWrongPassword:
1934
- message = @"The password is invalid or the user does not have a password.";
1935
- break;
1936
- case FIRAuthErrorCodeUserMismatch:
1937
- message = @"The supplied credentials do not correspond to the previously signed in user.";
1938
- break;
1939
- case FIRAuthErrorCodeRequiresRecentLogin:
1940
- message = @"This operation is sensitive and requires recent authentication. Log in again "
1941
- @"before retrying this request.";
1942
- break;
1943
- case FIRAuthErrorCodeSecondFactorRequired:
1944
- message = @"Please complete a second factor challenge to finish signing into this account.";
1945
- break;
1946
- case FIRAuthErrorCodeAccountExistsWithDifferentCredential:
1947
- message = @"An account already exists with the same email address but different sign-in "
1948
- @"credentials. Sign in using a provider associated with this email address.";
1949
- break;
1950
- case FIRAuthErrorCodeEmailAlreadyInUse:
1951
- message = @"The email address is already in use by another account.";
1952
- break;
1953
- case FIRAuthErrorCodeCredentialAlreadyInUse:
1954
- message = @"This credential is already associated with a different user account.";
1955
- break;
1956
- case FIRAuthErrorCodeUserDisabled:
1957
- message = @"The user account has been disabled by an administrator.";
1958
- break;
1959
- case FIRAuthErrorCodeUserTokenExpired:
1960
- message = @"The user's credential is no longer valid. The user must sign in again.";
1961
- break;
1962
- case FIRAuthErrorCodeUserNotFound:
1963
- message = @"There is no user record corresponding to this identifier. The user may have been "
1964
- @"deleted.";
1965
- break;
1966
- case FIRAuthErrorCodeInvalidUserToken:
1967
- message = @"The user's credential is no longer valid. The user must sign in again.";
1968
- break;
1969
- case FIRAuthErrorCodeWeakPassword:
1970
- message = @"The given password is invalid.";
1971
- break;
1972
- case FIRAuthErrorCodeOperationNotAllowed:
1973
- message = @"This operation is not allowed. You must enable this service in the console.";
1974
- break;
1975
- case FIRAuthErrorCodeNetworkError:
1976
- message = @"A network error has occurred, please try again.";
1977
- break;
1978
- case FIRAuthErrorCodeInternalError:
1979
- message = @"An internal error has occurred, please try again.";
1980
- break;
1981
- case FIRAuthErrorCodeInvalidPhoneNumber:
1982
- message = @"The format of the phone number provided is incorrect. "
1983
- @"Please enter the phone number in a format that can be parsed into E.164 format. "
1984
- @"E.164 phone numbers are written in the format [+][country code][subscriber "
1985
- @"number including area code].";
1986
- break;
1987
- default:
1988
- break;
1856
+ NSString *overrideMessage = [RNFBAuthErrorCodeMapper jsErrorMessageForAuthErrorCode:error.code];
1857
+ if (overrideMessage != nil) {
1858
+ message = overrideMessage;
1989
1859
  }
1990
1860
 
1991
1861
  NSDictionary *authCredentialDict = nil;
@@ -23,12 +23,18 @@
23
23
  #import "RNFBApp/RNFBHandleMap.h"
24
24
  #endif
25
25
 
26
- @protocol RNFBAuthRemovable <NSObject>
27
- - (void)remove;
28
- @end
26
+ #if __has_include(<RNFBAuth/RNFBAuth-Swift.h>)
27
+ #import <RNFBAuth/RNFBAuth-Swift.h>
28
+ #elif __has_include("RNFBAuth-Swift.h")
29
+ #import "RNFBAuth-Swift.h"
30
+ #elif __has_include("RNFBHandleMapStorage-Swift.inc")
31
+ #import "RNFBHandleMapStorage-Swift.inc"
32
+ #else
33
+ #error "RNFBAuthListenerRegistryStorage Swift interface not found"
34
+ #endif
29
35
 
30
36
  @interface RNFBAuthListenerRegistry ()
31
- @property(nonatomic, strong) RNFBHandleMap *map;
37
+ @property(nonatomic, strong) RNFBAuthListenerRegistryStorage *storage;
32
38
  @end
33
39
 
34
40
  @implementation RNFBAuthListenerRegistry
@@ -36,48 +42,42 @@
36
42
  - (instancetype)init {
37
43
  self = [super init];
38
44
  if (self) {
39
- _map = [[RNFBHandleMap alloc] init];
45
+ _storage = [[RNFBAuthListenerRegistryStorage alloc] init];
40
46
  }
41
47
  return self;
42
48
  }
43
49
 
44
- - (void)rnfb_removeHandle:(id)handle {
45
- if (handle && [handle respondsToSelector:@selector(remove)]) {
46
- [(id<RNFBAuthRemovable>)handle remove];
47
- }
48
- }
49
-
50
50
  - (BOOL)put:(id)key value:(id)value error:(NSError **)error {
51
- return [self.map put:key value:value error:error];
51
+ if (![self.storage putIfAbsent:key value:value]) {
52
+ if (error != nil) {
53
+ NSString *message = [NSString stringWithFormat:@"Handle id already registered: %@", key];
54
+ *error = [NSError errorWithDomain:RNFBHandleMapErrorDomain
55
+ code:RNFBHandleMapErrorCollision
56
+ userInfo:@{NSLocalizedDescriptionKey : message}];
57
+ }
58
+ return NO;
59
+ }
60
+ return YES;
52
61
  }
53
62
 
54
63
  - (BOOL)putOrDiscard:(id)key value:(id)value {
55
- NSError *error = nil;
56
- if ([self.map put:key value:value error:&error]) {
57
- return YES;
58
- }
59
- [self rnfb_removeHandle:value];
60
- return NO;
64
+ return [self.storage putOrDiscard:key value:value];
61
65
  }
62
66
 
63
67
  - (id)get:(id)key {
64
- return [self.map get:key];
68
+ return [self.storage get:key];
65
69
  }
66
70
 
67
71
  - (id)take:(id)key {
68
- return [self.map take:key];
72
+ return [self.storage take:key];
69
73
  }
70
74
 
71
75
  - (void)takeAndRemove:(id)key {
72
- id handle = [self.map take:key];
73
- [self rnfb_removeHandle:handle];
76
+ [self.storage takeAndRemove:key];
74
77
  }
75
78
 
76
79
  - (void)removeAll {
77
- NSArray *handlers = [self.map takeAll];
78
- for (id handler in handlers) {
79
- [self rnfb_removeHandle:handler];
80
- }
80
+ [self.storage removeAll];
81
81
  }
82
82
 
83
83
  @end
@@ -0,0 +1,76 @@
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
+ import Foundation
18
+
19
+ #if canImport(RNFBApp)
20
+ import RNFBApp
21
+ #endif
22
+
23
+ /// Auth-state / id-token listener map storage. Composes `RNFBHandleMapStorage`.
24
+ /// `putOrDiscard` is first-wins and calls `remove` on the incoming value on collision.
25
+ /// Unique `put` collision errors stay on the ObjC façade.
26
+ @objc(RNFBAuthListenerRegistryStorage)
27
+ public final class RNFBAuthListenerRegistryStorage: NSObject {
28
+ private static let removeSelector = Selector(("remove"))
29
+
30
+ private let storage = RNFBHandleMapStorage()
31
+
32
+ private func removeHandle(_ handle: AnyObject?) {
33
+ guard let handle = handle, handle.responds(to: Self.removeSelector) else {
34
+ return
35
+ }
36
+ _ = handle.perform(Self.removeSelector)
37
+ }
38
+
39
+ /// First-wins store without discarding the incoming value. Used by façade `put`.
40
+ @objc(putIfAbsent:value:)
41
+ public func putIfAbsent(_ key: AnyObject, value: AnyObject) -> Bool {
42
+ storage.putIfAbsent(key, value: value)
43
+ }
44
+
45
+ /// Unique put. On collision, `remove`s the incoming value and leaves the existing mapping.
46
+ @objc(putOrDiscard:value:)
47
+ public func putOrDiscard(_ key: AnyObject, value: AnyObject) -> Bool {
48
+ if storage.putIfAbsent(key, value: value) {
49
+ return true
50
+ }
51
+ removeHandle(value)
52
+ return false
53
+ }
54
+
55
+ @objc(get:)
56
+ public func get(_ key: AnyObject) -> AnyObject? {
57
+ storage.get(key)
58
+ }
59
+
60
+ @objc(take:)
61
+ public func take(_ key: AnyObject) -> AnyObject? {
62
+ storage.take(key)
63
+ }
64
+
65
+ @objc(takeAndRemove:)
66
+ public func takeAndRemove(_ key: AnyObject) {
67
+ removeHandle(storage.take(key))
68
+ }
69
+
70
+ @objc
71
+ public func removeAll() {
72
+ for handle in storage.takeAll() {
73
+ removeHandle(handle)
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,40 @@
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
+ /**
21
+ * Decodes New Architecture null sentinels for updateProfile. Foundation only so unit tests can
22
+ * compile it without the Firebase SDK.
23
+ */
24
+ @interface RNFBAuthNullSentinelDecoder : NSObject
25
+
26
+ /**
27
+ * Decode sentinels and turn NSNull into nil before profileChangeRequest writes.
28
+ * FIRUserProfileChangeRequest clears a field when the property is set to nil (not the same as
29
+ * leaving it unassigned). NSDictionary cannot store nil, so cleared keys are omitted and
30
+ * subscript returns nil, the same value updateProfile reads.
31
+ * displayName/photoURL null arrive as { __rnfbNull: true } and/or NSNull after decode.
32
+ */
33
+ + (NSDictionary *)decodedProfileProps:(NSDictionary *)props;
34
+
35
+ /**
36
+ * photoURL clear arm: omitted/nil decoded value must become nil (not @""), not URLWithString:.
37
+ */
38
+ + (NSURL *)photoURLFromDecodedValue:(id)value;
39
+
40
+ @end
@@ -0,0 +1,49 @@
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 "RNFBAuthNullSentinelDecoder.h"
19
+
20
+ #if __has_include(<RNFBApp/RNFBApp-Swift.h>)
21
+ #import <RNFBApp/RNFBApp-Swift.h>
22
+ #elif __has_include("RNFBApp-Swift.h")
23
+ #import "RNFBApp-Swift.h"
24
+ #elif __has_include("RNFBHandleMapStorage-Swift.inc")
25
+ #import "RNFBHandleMapStorage-Swift.inc"
26
+ #else
27
+ #error "RNFBApp Swift interface not found"
28
+ #endif
29
+
30
+ @implementation RNFBAuthNullSentinelDecoder
31
+
32
+ + (NSDictionary *)decodedProfileProps:(NSDictionary *)props {
33
+ NSDictionary *decoded = [RNFBNullSentinelDecoder decodeNullSentinels:props];
34
+ NSMutableDictionary *normalized = [NSMutableDictionary dictionaryWithCapacity:decoded.count];
35
+ for (NSString *key in decoded) {
36
+ id value = decoded[key];
37
+ if (value == [NSNull null]) {
38
+ continue;
39
+ }
40
+ normalized[key] = value;
41
+ }
42
+ return normalized;
43
+ }
44
+
45
+ + (NSURL *)photoURLFromDecodedValue:(id)value {
46
+ return value == nil ? nil : [NSURL URLWithString:value];
47
+ }
48
+
49
+ @end
@@ -8,6 +8,10 @@
8
8
 
9
9
  /* Begin PBXBuildFile section */
10
10
  2744B98621F45429004F8E3F /* RNFBAuthModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAuthModule.mm */; };
11
+ RNFBAUTH0000000000000001 /* RNFBAuthCacheRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = RNFBAUTH0000000000000002 /* RNFBAuthCacheRegistry.m */; };
12
+ RNFBAUTH0000000000000003 /* RNFBAuthCacheRegistryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBAUTH0000000000000004 /* RNFBAuthCacheRegistryStorage.swift */; };
13
+ RNFBAUTH0000000000000008 /* RNFBAuthListenerRegistryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBAUTH0000000000000009 /* RNFBAuthListenerRegistryStorage.swift */; };
14
+ RNFBAUTH000000000000000A /* RNFBAuthErrorCodeMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBAUTH000000000000000B /* RNFBAuthErrorCodeMapper.swift */; };
11
15
  /* End PBXBuildFile section */
12
16
 
13
17
  /* Begin PBXCopyFilesBuildPhase section */
@@ -26,6 +30,11 @@
26
30
  2744B98221F45429004F8E3F /* libRNFBAuth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBAuth.a; sourceTree = BUILT_PRODUCTS_DIR; };
27
31
  2744B98421F45429004F8E3F /* RNFBAuthModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAuthModule.h; path = RNFBAuth/RNFBAuthModule.h; sourceTree = SOURCE_ROOT; };
28
32
  2744B98521F45429004F8E3F /* RNFBAuthModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = RNFBAuthModule.mm; path = RNFBAuth/RNFBAuthModule.mm; sourceTree = SOURCE_ROOT; };
33
+ RNFBAUTH0000000000000005 /* RNFBAuthCacheRegistry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAuthCacheRegistry.h; path = RNFBAuth/RNFBAuthCacheRegistry.h; sourceTree = SOURCE_ROOT; };
34
+ RNFBAUTH0000000000000002 /* RNFBAuthCacheRegistry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAuthCacheRegistry.m; path = RNFBAuth/RNFBAuthCacheRegistry.m; sourceTree = SOURCE_ROOT; };
35
+ RNFBAUTH0000000000000004 /* RNFBAuthCacheRegistryStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAuthCacheRegistryStorage.swift; path = RNFBAuth/RNFBAuthCacheRegistryStorage.swift; sourceTree = SOURCE_ROOT; };
36
+ RNFBAUTH0000000000000009 /* RNFBAuthListenerRegistryStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAuthListenerRegistryStorage.swift; path = RNFBAuth/RNFBAuthListenerRegistryStorage.swift; sourceTree = SOURCE_ROOT; };
37
+ RNFBAUTH000000000000000B /* RNFBAuthErrorCodeMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAuthErrorCodeMapper.swift; path = RNFBAuth/RNFBAuthErrorCodeMapper.swift; sourceTree = SOURCE_ROOT; };
29
38
  /* End PBXFileReference section */
30
39
 
31
40
  /* Begin PBXFrameworksBuildPhase section */
@@ -52,6 +61,11 @@
52
61
  children = (
53
62
  2744B9A121F48736004F8E3F /* converters */,
54
63
  2744B98C21F45C64004F8E3F /* common */,
64
+ RNFBAUTH0000000000000005 /* RNFBAuthCacheRegistry.h */,
65
+ RNFBAUTH0000000000000002 /* RNFBAuthCacheRegistry.m */,
66
+ RNFBAUTH0000000000000004 /* RNFBAuthCacheRegistryStorage.swift */,
67
+ RNFBAUTH0000000000000009 /* RNFBAuthListenerRegistryStorage.swift */,
68
+ RNFBAUTH000000000000000B /* RNFBAuthErrorCodeMapper.swift */,
55
69
  2744B98421F45429004F8E3F /* RNFBAuthModule.h */,
56
70
  2744B98521F45429004F8E3F /* RNFBAuthModule.mm */,
57
71
  );
@@ -124,6 +138,10 @@
124
138
  isa = PBXSourcesBuildPhase;
125
139
  buildActionMask = 2147483647;
126
140
  files = (
141
+ RNFBAUTH0000000000000003 /* RNFBAuthCacheRegistryStorage.swift in Sources */,
142
+ RNFBAUTH0000000000000001 /* RNFBAuthCacheRegistry.m in Sources */,
143
+ RNFBAUTH0000000000000008 /* RNFBAuthListenerRegistryStorage.swift in Sources */,
144
+ RNFBAUTH000000000000000A /* RNFBAuthErrorCodeMapper.swift in Sources */,
127
145
  2744B98621F45429004F8E3F /* RNFBAuthModule.mm in Sources */,
128
146
  );
129
147
  runOnlyForDeploymentPostprocessing = 0;
@@ -150,6 +168,7 @@
150
168
  CODE_SIGN_STYLE = Automatic;
151
169
  COPY_PHASE_STRIP = NO;
152
170
  DEBUG_INFORMATION_FORMAT = dwarf;
171
+ DEFINES_MODULE = YES;
153
172
  GCC_C_LANGUAGE_STANDARD = gnu11;
154
173
  GCC_DYNAMIC_NO_PIC = NO;
155
174
  GCC_OPTIMIZATION_LEVEL = 0;
@@ -166,6 +185,7 @@
166
185
  PRODUCT_NAME = "$(TARGET_NAME)";
167
186
  SDKROOT = iphoneos;
168
187
  SKIP_INSTALL = YES;
188
+ SWIFT_VERSION = 5.10;
169
189
  TARGETED_DEVICE_FAMILY = "1,2";
170
190
  };
171
191
  name = Debug;
@@ -189,6 +209,7 @@
189
209
  CODE_SIGN_STYLE = Automatic;
190
210
  COPY_PHASE_STRIP = NO;
191
211
  DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
212
+ DEFINES_MODULE = YES;
192
213
  ENABLE_NS_ASSERTIONS = NO;
193
214
  GCC_C_LANGUAGE_STANDARD = gnu11;
194
215
  GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -200,6 +221,7 @@
200
221
  PRODUCT_NAME = "$(TARGET_NAME)";
201
222
  SDKROOT = iphoneos;
202
223
  SKIP_INSTALL = YES;
224
+ SWIFT_VERSION = 5.10;
203
225
  TARGETED_DEVICE_FAMILY = "1,2";
204
226
  VALIDATE_PRODUCT = YES;
205
227
  };