@react-native-firebase/auth 26.3.3 → 26.4.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.
- package/CHANGELOG.md +9 -0
- package/RNFBAuth.podspec +1 -1
- package/android/build.gradle +2 -0
- package/android/src/main/java/io/invertase/firebase/auth/AuthListenerHandle.java +26 -0
- package/android/src/main/java/io/invertase/firebase/auth/NativeRNFBTurboAuth.java +69 -101
- package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthCacheRegistry.java +66 -0
- package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthListenerRegistry.java +76 -0
- package/android/src/test/java/io/invertase/firebase/auth/RNFBAuthCacheRegistryTest.java +172 -0
- package/android/src/test/java/io/invertase/firebase/auth/RNFBAuthListenerRegistryTest.java +171 -0
- package/dist/module/ActionCodeURL.js +1 -1
- package/dist/module/ActionCodeURL.js.map +1 -1
- package/dist/module/version.js +1 -1
- package/dist/typescript/lib/ActionCodeURL.d.ts.map +1 -1
- package/dist/typescript/lib/version.d.ts +1 -1
- package/ios/RNFBAuth/RNFBAuthCacheRegistry.h +41 -0
- package/ios/RNFBAuth/RNFBAuthCacheRegistry.m +65 -0
- package/ios/RNFBAuth/RNFBAuthHelper.m +124 -109
- package/ios/RNFBAuth/RNFBAuthListenerRegistry.h +39 -0
- package/ios/RNFBAuth/RNFBAuthListenerRegistry.m +83 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthCacheRegistryTests.m +131 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthListenerRegistryTests.m +152 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/project.pbxproj +261 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBAuthUnitTests.xcscheme +69 -0
- package/lib/ActionCodeURL.ts +1 -2
- package/lib/version.ts +1 -1
- package/package.json +5 -4
|
@@ -36,7 +36,24 @@
|
|
|
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
|
+
|
|
43
|
+
@interface RNFBAuthListenerRemover : NSObject
|
|
44
|
+
@property(nonatomic, copy, nullable) void (^onRemove)(void);
|
|
45
|
+
- (void)remove;
|
|
46
|
+
@end
|
|
47
|
+
|
|
48
|
+
@implementation RNFBAuthListenerRemover
|
|
49
|
+
- (void)remove {
|
|
50
|
+
if (self.onRemove != nil) {
|
|
51
|
+
void (^block)(void) = self.onRemove;
|
|
52
|
+
self.onRemove = nil;
|
|
53
|
+
block();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
@end
|
|
40
57
|
|
|
41
58
|
static void RNFBAuthThrowSyncErrorWithCode(NSString *code, NSString *message) {
|
|
42
59
|
@throw [NSException exceptionWithName:code
|
|
@@ -133,15 +150,15 @@ static NSString *const AuthErrorCode_toJSErrorCode[] = {
|
|
|
133
150
|
[FIRAuthErrorCodeMalformedJWT] = @"malformed-jwt",
|
|
134
151
|
[FIRAuthErrorCodeSecondFactorRequired] = @"multi-factor-auth-required"};
|
|
135
152
|
|
|
136
|
-
static __strong
|
|
137
|
-
static __strong
|
|
153
|
+
static __strong RNFBAuthListenerRegistry *authStateHandlers;
|
|
154
|
+
static __strong RNFBAuthListenerRegistry *idTokenHandlers;
|
|
138
155
|
static __strong NSMutableDictionary *emulatorConfigs;
|
|
139
156
|
// Used for caching credentials between method calls.
|
|
140
|
-
static __strong
|
|
157
|
+
static __strong RNFBAuthCacheRegistry *credentials;
|
|
141
158
|
#if TARGET_OS_IOS
|
|
142
|
-
static __strong
|
|
143
|
-
static __strong
|
|
144
|
-
static __strong
|
|
159
|
+
static __strong RNFBAuthCacheRegistry *cachedResolver;
|
|
160
|
+
static __strong RNFBAuthCacheRegistry *cachedSessions;
|
|
161
|
+
static __strong RNFBAuthCacheRegistry *cachedTotpSecrets;
|
|
145
162
|
#endif
|
|
146
163
|
|
|
147
164
|
@interface RNFBAuthHelper ()
|
|
@@ -200,14 +217,14 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
200
217
|
+ (void)initializeSharedStateOnce {
|
|
201
218
|
static dispatch_once_t onceToken;
|
|
202
219
|
dispatch_once(&onceToken, ^{
|
|
203
|
-
authStateHandlers = [[
|
|
204
|
-
idTokenHandlers = [[
|
|
220
|
+
authStateHandlers = [[RNFBAuthListenerRegistry alloc] init];
|
|
221
|
+
idTokenHandlers = [[RNFBAuthListenerRegistry alloc] init];
|
|
205
222
|
emulatorConfigs = [[NSMutableDictionary alloc] init];
|
|
206
|
-
credentials = [[
|
|
223
|
+
credentials = [[RNFBAuthCacheRegistry alloc] init];
|
|
207
224
|
#if TARGET_OS_IOS
|
|
208
|
-
cachedResolver = [[
|
|
209
|
-
cachedSessions = [[
|
|
210
|
-
cachedTotpSecrets = [[
|
|
225
|
+
cachedResolver = [[RNFBAuthCacheRegistry alloc] init];
|
|
226
|
+
cachedSessions = [[RNFBAuthCacheRegistry alloc] init];
|
|
227
|
+
cachedTotpSecrets = [[RNFBAuthCacheRegistry alloc] init];
|
|
211
228
|
#endif
|
|
212
229
|
});
|
|
213
230
|
}
|
|
@@ -215,26 +232,14 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
215
232
|
+ (void)invalidate {
|
|
216
233
|
[self initializeSharedStateOnce];
|
|
217
234
|
|
|
218
|
-
|
|
219
|
-
|
|
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];
|
|
235
|
+
[authStateHandlers removeAll];
|
|
236
|
+
[idTokenHandlers removeAll];
|
|
232
237
|
|
|
233
|
-
[credentials
|
|
238
|
+
[credentials clear];
|
|
234
239
|
#if TARGET_OS_IOS
|
|
235
|
-
[cachedResolver
|
|
236
|
-
[cachedSessions
|
|
237
|
-
[cachedTotpSecrets
|
|
240
|
+
[cachedResolver clear];
|
|
241
|
+
[cachedSessions clear];
|
|
242
|
+
[cachedTotpSecrets clear];
|
|
238
243
|
#endif
|
|
239
244
|
}
|
|
240
245
|
|
|
@@ -245,68 +250,75 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
245
250
|
[self initializeSharedStateOnce];
|
|
246
251
|
FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
|
|
247
252
|
|
|
248
|
-
if (
|
|
249
|
-
|
|
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;
|
|
253
|
+
if ([authStateHandlers get:firebaseApp.name] != nil) {
|
|
254
|
+
return;
|
|
260
255
|
}
|
|
256
|
+
|
|
257
|
+
FIRAuth *auth = [FIRAuth authWithApp:firebaseApp];
|
|
258
|
+
FIRAuthStateDidChangeListenerHandle newListenerHandle = [auth
|
|
259
|
+
addAuthStateDidChangeListener:^(FIRAuth *_Nonnull authInstance, FIRUser *_Nullable user) {
|
|
260
|
+
if (user != nil) {
|
|
261
|
+
[RNFBSharedUtils sendJSEventForApp:firebaseApp
|
|
262
|
+
name:AUTH_STATE_CHANGED_EVENT
|
|
263
|
+
body:@{keyUser : [self firebaseUserToDict:user]}];
|
|
264
|
+
} else {
|
|
265
|
+
[RNFBSharedUtils sendJSEventForApp:firebaseApp name:AUTH_STATE_CHANGED_EVENT body:@{}];
|
|
266
|
+
}
|
|
267
|
+
}];
|
|
268
|
+
|
|
269
|
+
RNFBAuthListenerRemover *remover = [[RNFBAuthListenerRemover alloc] init];
|
|
270
|
+
remover.onRemove = ^{
|
|
271
|
+
[auth removeAuthStateDidChangeListener:newListenerHandle];
|
|
272
|
+
};
|
|
273
|
+
[authStateHandlers putOrDiscard:firebaseApp.name value:remover];
|
|
261
274
|
}
|
|
262
275
|
|
|
263
276
|
+ (void)removeAuthStateListener:(NSString *)appName {
|
|
264
277
|
[self initializeSharedStateOnce];
|
|
265
278
|
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
|
-
}
|
|
279
|
+
[authStateHandlers takeAndRemove:firebaseApp.name];
|
|
272
280
|
}
|
|
273
281
|
|
|
274
282
|
+ (void)addIdTokenListener:(NSString *)appName {
|
|
275
283
|
[self initializeSharedStateOnce];
|
|
276
284
|
FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
|
|
277
285
|
|
|
278
|
-
if (
|
|
279
|
-
|
|
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;
|
|
286
|
+
if ([idTokenHandlers get:firebaseApp.name] != nil) {
|
|
287
|
+
return;
|
|
292
288
|
}
|
|
289
|
+
|
|
290
|
+
FIRAuth *auth = [FIRAuth authWithApp:firebaseApp];
|
|
291
|
+
FIRIDTokenDidChangeListenerHandle newListenerHandle =
|
|
292
|
+
[auth addIDTokenDidChangeListener:^(FIRAuth *_Nonnull authInstance, FIRUser *_Nullable user) {
|
|
293
|
+
if (user != nil) {
|
|
294
|
+
[RNFBSharedUtils sendJSEventForApp:firebaseApp
|
|
295
|
+
name:AUTH_ID_TOKEN_CHANGED_EVENT
|
|
296
|
+
body:@{keyUser : [self firebaseUserToDict:user]}];
|
|
297
|
+
} else {
|
|
298
|
+
[RNFBSharedUtils sendJSEventForApp:firebaseApp name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{}];
|
|
299
|
+
}
|
|
300
|
+
}];
|
|
301
|
+
|
|
302
|
+
RNFBAuthListenerRemover *remover = [[RNFBAuthListenerRemover alloc] init];
|
|
303
|
+
remover.onRemove = ^{
|
|
304
|
+
[auth removeIDTokenDidChangeListener:newListenerHandle];
|
|
305
|
+
};
|
|
306
|
+
[idTokenHandlers putOrDiscard:firebaseApp.name value:remover];
|
|
293
307
|
}
|
|
294
308
|
|
|
295
309
|
+ (void)removeIdTokenListener:(NSString *)appName {
|
|
296
310
|
[self initializeSharedStateOnce];
|
|
297
311
|
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
|
-
}
|
|
312
|
+
[idTokenHandlers takeAndRemove:firebaseApp.name];
|
|
304
313
|
}
|
|
305
314
|
|
|
306
315
|
+ (void)configureAuthDomain:(NSString *)appName {
|
|
307
316
|
FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
|
|
308
317
|
|
|
309
|
-
|
|
318
|
+
// customAuthDomains is keyed by the JS app name ([DEFAULT]); FIRApp.name for the default app
|
|
319
|
+
// is __FIRAPP_DEFAULT. Look up with the existing JS-name converter (no parallel key helper).
|
|
320
|
+
NSString *authDomain =
|
|
321
|
+
[RNFBAppModule getCustomDomain:[RNFBSharedUtils getAppJavaScriptName:firebaseApp.name]];
|
|
310
322
|
DLog(@"RNFBAuth app: %@ customAuthDomain: %@", firebaseApp.name, authDomain);
|
|
311
323
|
if (authDomain != nil) {
|
|
312
324
|
[FIRAuth authWithApp:firebaseApp].customAuthDomain = authDomain;
|
|
@@ -1054,7 +1066,8 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1054
1066
|
[self initializeSharedStateOnce];
|
|
1055
1067
|
FIRApp *firebaseApp = [RCTConvert firAppFromString:appName];
|
|
1056
1068
|
|
|
1057
|
-
|
|
1069
|
+
FIRMultiFactorResolver *resolver = [cachedResolver get:sessionKey];
|
|
1070
|
+
if (resolver == nil) {
|
|
1058
1071
|
[RNFBSharedUtils
|
|
1059
1072
|
rejectPromiseWithUserInfo:reject
|
|
1060
1073
|
userInfo:(NSMutableDictionary *)@{
|
|
@@ -1063,10 +1076,10 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1063
1076
|
}];
|
|
1064
1077
|
return;
|
|
1065
1078
|
}
|
|
1066
|
-
FIRMultiFactorSession *session =
|
|
1079
|
+
FIRMultiFactorSession *session = resolver.session;
|
|
1067
1080
|
NSPredicate *findByUid = [NSPredicate predicateWithFormat:@"UID == %@", hintUid];
|
|
1068
1081
|
FIRMultiFactorInfo *_Nullable hint =
|
|
1069
|
-
[[
|
|
1082
|
+
[[resolver.hints filteredArrayUsingPredicate:findByUid] firstObject];
|
|
1070
1083
|
if (hint == nil) {
|
|
1071
1084
|
[RNFBSharedUtils rejectPromiseWithUserInfo:reject
|
|
1072
1085
|
userInfo:(NSMutableDictionary *)@{
|
|
@@ -1104,7 +1117,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1104
1117
|
DLog(@"verifyPhoneNumberForMultifactor using app: %@", firebaseApp.name);
|
|
1105
1118
|
DLog(@"verifyPhoneNumberForMultifactor phoneNumber: %@", phoneNumber);
|
|
1106
1119
|
DLog(@"verifyPhoneNumberForMultifactor sessionKey: %@", sessionKey);
|
|
1107
|
-
FIRMultiFactorSession *session = cachedSessions
|
|
1120
|
+
FIRMultiFactorSession *session = [cachedSessions get:sessionKey];
|
|
1108
1121
|
if (session == nil) {
|
|
1109
1122
|
[RNFBSharedUtils rejectPromiseWithUserInfo:reject
|
|
1110
1123
|
userInfo:(NSMutableDictionary *)@{
|
|
@@ -1147,18 +1160,19 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1147
1160
|
FIRMultiFactorAssertion *assertion =
|
|
1148
1161
|
[FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
|
|
1149
1162
|
|
|
1150
|
-
[cachedResolver
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1163
|
+
FIRMultiFactorResolver *signInResolver = [cachedResolver get:session];
|
|
1164
|
+
[signInResolver resolveSignInWithAssertion:assertion
|
|
1165
|
+
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
1166
|
+
NSError *_Nullable error) {
|
|
1167
|
+
DLog(@"authError: %@", error) if (error) {
|
|
1168
|
+
[self promiseRejectAuthException:reject error:error];
|
|
1169
|
+
}
|
|
1170
|
+
else {
|
|
1171
|
+
[self promiseWithAuthResult:resolve
|
|
1172
|
+
rejecter:reject
|
|
1173
|
+
authResult:authResult];
|
|
1174
|
+
}
|
|
1175
|
+
}];
|
|
1162
1176
|
}
|
|
1163
1177
|
|
|
1164
1178
|
+ (void)resolveTotpSignIn:(NSString *)appName
|
|
@@ -1175,19 +1189,19 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1175
1189
|
FIRMultiFactorAssertion *assertion =
|
|
1176
1190
|
[FIRTOTPMultiFactorGenerator assertionForSignInWithEnrollmentID:uid
|
|
1177
1191
|
oneTimePassword:oneTimePassword];
|
|
1178
|
-
[cachedResolver
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1192
|
+
FIRMultiFactorResolver *totpSignInResolver = [cachedResolver get:sessionKey];
|
|
1193
|
+
[totpSignInResolver resolveSignInWithAssertion:assertion
|
|
1194
|
+
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
1195
|
+
NSError *_Nullable error) {
|
|
1196
|
+
DLog(@"authError: %@", error) if (error) {
|
|
1197
|
+
[self promiseRejectAuthException:reject error:error];
|
|
1198
|
+
}
|
|
1199
|
+
else {
|
|
1200
|
+
[self promiseWithAuthResult:resolve
|
|
1201
|
+
rejecter:reject
|
|
1202
|
+
authResult:authResult];
|
|
1203
|
+
}
|
|
1204
|
+
}];
|
|
1191
1205
|
}
|
|
1192
1206
|
|
|
1193
1207
|
+ (void)generateTotpSecret:(NSString *)appName
|
|
@@ -1199,7 +1213,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1199
1213
|
|
|
1200
1214
|
DLog(@"using instance resolve generateTotpSecret: %@", firebaseApp.name);
|
|
1201
1215
|
|
|
1202
|
-
FIRMultiFactorSession *session = cachedSessions
|
|
1216
|
+
FIRMultiFactorSession *session = [cachedSessions get:sessionKey];
|
|
1203
1217
|
DLog(@"using sessionKey: %@", sessionKey);
|
|
1204
1218
|
DLog(@"using session: %@", session);
|
|
1205
1219
|
[FIRTOTPMultiFactorGenerator
|
|
@@ -1212,8 +1226,8 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1212
1226
|
else {
|
|
1213
1227
|
NSString *secretKey = totpSecret.sharedSecretKey;
|
|
1214
1228
|
DLog(@"secretKey generated: %@", secretKey);
|
|
1215
|
-
cachedTotpSecrets
|
|
1216
|
-
DLog(@"cachedSecret: %@", cachedTotpSecrets
|
|
1229
|
+
[cachedTotpSecrets putReplacing:secretKey value:totpSecret];
|
|
1230
|
+
DLog(@"cachedSecret: %@", [cachedTotpSecrets get:secretKey]);
|
|
1217
1231
|
resolve(@{
|
|
1218
1232
|
@"secretKey" : secretKey,
|
|
1219
1233
|
});
|
|
@@ -1230,7 +1244,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1230
1244
|
|
|
1231
1245
|
DLog(@"generateQrCodeUrl using instance resolve generateQrCodeUrl: %@", firebaseApp.name);
|
|
1232
1246
|
DLog(@"generateQrCodeUrl using secretKey: %@", secretKey);
|
|
1233
|
-
FIRTOTPSecret *totpSecret = cachedTotpSecrets
|
|
1247
|
+
FIRTOTPSecret *totpSecret = [cachedTotpSecrets get:secretKey];
|
|
1234
1248
|
if (!totpSecret) {
|
|
1235
1249
|
RNFBAuthThrowSyncErrorWithCode(@"invalid-multi-factor-secret",
|
|
1236
1250
|
@"can't find secret for provided key");
|
|
@@ -1246,7 +1260,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1246
1260
|
[self initializeSharedStateOnce];
|
|
1247
1261
|
|
|
1248
1262
|
DLog(@"generateQrCodeUrl using secretKey: %@", secretKey);
|
|
1249
|
-
FIRTOTPSecret *totpSecret = cachedTotpSecrets
|
|
1263
|
+
FIRTOTPSecret *totpSecret = [cachedTotpSecrets get:secretKey];
|
|
1250
1264
|
DLog(@"openInOtpApp using qrCodeUri: %@", qrCodeUri);
|
|
1251
1265
|
[totpSecret openInOTPAppWithQRCodeURL:qrCodeUri];
|
|
1252
1266
|
}
|
|
@@ -1266,7 +1280,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1266
1280
|
}
|
|
1267
1281
|
|
|
1268
1282
|
NSString *sessionId = [NSString stringWithFormat:@"%@", @([session hash])];
|
|
1269
|
-
cachedSessions
|
|
1283
|
+
[cachedSessions putReplacing:sessionId value:session];
|
|
1270
1284
|
resolve(sessionId);
|
|
1271
1285
|
}];
|
|
1272
1286
|
}
|
|
@@ -1333,7 +1347,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1333
1347
|
|
|
1334
1348
|
DLog(@"using instance finalizeTotpEnrollment: %@", firebaseApp.name);
|
|
1335
1349
|
|
|
1336
|
-
FIRTOTPSecret *cachedTotpSecret = cachedTotpSecrets
|
|
1350
|
+
FIRTOTPSecret *cachedTotpSecret = [cachedTotpSecrets get:totpSecret];
|
|
1337
1351
|
DLog(@"using totpSecretKey: %@", totpSecret);
|
|
1338
1352
|
DLog(@"using cachedSecret: %@", cachedTotpSecret);
|
|
1339
1353
|
FIRTOTPMultiFactorAssertion *assertion =
|
|
@@ -1789,8 +1803,9 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1789
1803
|
FIRAuthCredential *credential;
|
|
1790
1804
|
|
|
1791
1805
|
// First check if we cached an authToken
|
|
1792
|
-
|
|
1793
|
-
|
|
1806
|
+
FIRAuthCredential *cachedCredential = [credentials get:authToken];
|
|
1807
|
+
if (cachedCredential != nil) {
|
|
1808
|
+
credential = cachedCredential;
|
|
1794
1809
|
} else if ([provider compare:@"twitter.com" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
|
1795
1810
|
credential = [FIRTwitterAuthProvider credentialWithToken:authToken secret:authTokenSecret];
|
|
1796
1811
|
} else if ([provider compare:@"facebook.com" options:NSCaseInsensitiveSearch] == NSOrderedSame &&
|
|
@@ -1986,7 +2001,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
1986
2001
|
resolverDict = [self multiFactorResolverToDict:resolver];
|
|
1987
2002
|
|
|
1988
2003
|
NSString *sessionKey = [NSString stringWithFormat:@"%@", @([resolver.session hash])];
|
|
1989
|
-
cachedResolver
|
|
2004
|
+
[cachedResolver putReplacing:sessionKey value:resolver];
|
|
1990
2005
|
}
|
|
1991
2006
|
#endif
|
|
1992
2007
|
|
|
@@ -2175,7 +2190,7 @@ static __strong NSMutableDictionary<NSString *, FIRTOTPSecret *> *cachedTotpSecr
|
|
|
2175
2190
|
NSString *authCredentialHash = [NSString stringWithFormat:@"%@", @([authCredential hash])];
|
|
2176
2191
|
|
|
2177
2192
|
// Temporarily store the non-serializable credential for later
|
|
2178
|
-
credentials
|
|
2193
|
+
[credentials putReplacing:authCredentialHash value:authCredential];
|
|
2179
2194
|
|
|
2180
2195
|
return @{
|
|
2181
2196
|
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
|
|
@@ -0,0 +1,83 @@
|
|
|
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 "RNFBAuthListenerRegistry.h"
|
|
19
|
+
|
|
20
|
+
#if __has_include("RNFBHandleMap.h")
|
|
21
|
+
#import "RNFBHandleMap.h"
|
|
22
|
+
#else
|
|
23
|
+
#import "RNFBApp/RNFBHandleMap.h"
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
@protocol RNFBAuthRemovable <NSObject>
|
|
27
|
+
- (void)remove;
|
|
28
|
+
@end
|
|
29
|
+
|
|
30
|
+
@interface RNFBAuthListenerRegistry ()
|
|
31
|
+
@property(nonatomic, strong) RNFBHandleMap *map;
|
|
32
|
+
@end
|
|
33
|
+
|
|
34
|
+
@implementation RNFBAuthListenerRegistry
|
|
35
|
+
|
|
36
|
+
- (instancetype)init {
|
|
37
|
+
self = [super init];
|
|
38
|
+
if (self) {
|
|
39
|
+
_map = [[RNFBHandleMap alloc] init];
|
|
40
|
+
}
|
|
41
|
+
return self;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
- (void)rnfb_removeHandle:(id)handle {
|
|
45
|
+
if (handle && [handle respondsToSelector:@selector(remove)]) {
|
|
46
|
+
[(id<RNFBAuthRemovable>)handle remove];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
- (BOOL)put:(id)key value:(id)value error:(NSError **)error {
|
|
51
|
+
return [self.map put:key value:value error:error];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
- (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;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
- (id)get:(id)key {
|
|
64
|
+
return [self.map get:key];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
- (id)take:(id)key {
|
|
68
|
+
return [self.map take:key];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
- (void)takeAndRemove:(id)key {
|
|
72
|
+
id handle = [self.map take:key];
|
|
73
|
+
[self rnfb_removeHandle:handle];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
- (void)removeAll {
|
|
77
|
+
NSArray *handlers = [self.map takeAll];
|
|
78
|
+
for (id handler in handlers) {
|
|
79
|
+
[self rnfb_removeHandle:handler];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@end
|
|
@@ -0,0 +1,131 @@
|
|
|
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 <XCTest/XCTest.h>
|
|
19
|
+
|
|
20
|
+
#import "RNFBAuthCacheRegistry.h"
|
|
21
|
+
#import "RNFBHandleMap.h"
|
|
22
|
+
|
|
23
|
+
@interface RNFBAuthCacheRegistryTests : XCTestCase
|
|
24
|
+
@property(nonatomic, strong) RNFBAuthCacheRegistry *registry;
|
|
25
|
+
@end
|
|
26
|
+
|
|
27
|
+
@implementation RNFBAuthCacheRegistryTests
|
|
28
|
+
|
|
29
|
+
- (void)setUp {
|
|
30
|
+
[super setUp];
|
|
31
|
+
self.registry = [[RNFBAuthCacheRegistry alloc] init];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
- (void)testPutGetTake_happyPath {
|
|
35
|
+
NSError *error = nil;
|
|
36
|
+
XCTAssertTrue([self.registry put:@"k1" value:@"payload" error:&error]);
|
|
37
|
+
XCTAssertNil(error);
|
|
38
|
+
XCTAssertEqualObjects(@"payload", [self.registry get:@"k1"]);
|
|
39
|
+
XCTAssertEqualObjects(@"payload", [self.registry take:@"k1"]);
|
|
40
|
+
XCTAssertNil([self.registry get:@"k1"]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
- (void)testPut_occupiedId_returnsCollision {
|
|
44
|
+
XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
|
|
45
|
+
|
|
46
|
+
NSError *error = nil;
|
|
47
|
+
XCTAssertFalse([self.registry put:@"k1" value:@"second" error:&error]);
|
|
48
|
+
XCTAssertNotNil(error);
|
|
49
|
+
XCTAssertEqualObjects(error.domain, RNFBHandleMapErrorDomain);
|
|
50
|
+
XCTAssertEqual(error.code, RNFBHandleMapErrorCollision);
|
|
51
|
+
XCTAssertEqualObjects(@"first", [self.registry get:@"k1"]);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
- (void)testPut_occupiedId_nilErrorOut_returnsNo {
|
|
55
|
+
XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
|
|
56
|
+
XCTAssertFalse([self.registry put:@"k1" value:@"second" error:nil]);
|
|
57
|
+
XCTAssertEqualObjects(@"first", [self.registry get:@"k1"]);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
- (void)testGet_whenFree_isNil {
|
|
61
|
+
XCTAssertNil([self.registry get:@"missing"]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
- (void)testTake_whenFree_isNil {
|
|
65
|
+
XCTAssertNil([self.registry take:@"missing"]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
- (void)testPutOrDiscard_storesWhenFree {
|
|
69
|
+
XCTAssertTrue([self.registry putOrDiscard:@"k1" value:@"payload"]);
|
|
70
|
+
XCTAssertEqualObjects(@"payload", [self.registry get:@"k1"]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
- (void)testPutOrDiscard_collision_keepsExisting {
|
|
74
|
+
XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
|
|
75
|
+
XCTAssertFalse([self.registry putOrDiscard:@"k1" value:@"second"]);
|
|
76
|
+
XCTAssertEqualObjects(@"first", [self.registry get:@"k1"]);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
- (void)testPutReplacing_whenFree_stores {
|
|
80
|
+
XCTAssertTrue([self.registry putReplacing:@"k1" value:@"payload"]);
|
|
81
|
+
XCTAssertEqualObjects(@"payload", [self.registry get:@"k1"]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
- (void)testPutReplacing_whenOccupied_replacesLastWins {
|
|
85
|
+
XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
|
|
86
|
+
XCTAssertTrue([self.registry putReplacing:@"k1" value:@"second"]);
|
|
87
|
+
XCTAssertEqualObjects(@"second", [self.registry get:@"k1"]);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
- (void)testPutReplacing_sameIdFromTwoThreads_lastWins {
|
|
91
|
+
XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
|
|
92
|
+
|
|
93
|
+
dispatch_group_t group = dispatch_group_create();
|
|
94
|
+
dispatch_group_enter(group);
|
|
95
|
+
dispatch_group_enter(group);
|
|
96
|
+
|
|
97
|
+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
|
|
98
|
+
[self.registry putReplacing:@"k1" value:@"second"];
|
|
99
|
+
dispatch_group_leave(group);
|
|
100
|
+
});
|
|
101
|
+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
|
|
102
|
+
[self.registry putReplacing:@"k1" value:@"third"];
|
|
103
|
+
dispatch_group_leave(group);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
|
|
107
|
+
id stored = [self.registry get:@"k1"];
|
|
108
|
+
XCTAssertTrue([stored isEqual:@"second"] || [stored isEqual:@"third"]);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
- (void)testPut_afterTake_allowsReuse {
|
|
112
|
+
XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
|
|
113
|
+
XCTAssertEqualObjects(@"first", [self.registry take:@"k1"]);
|
|
114
|
+
XCTAssertTrue([self.registry put:@"k1" value:@"second" error:nil]);
|
|
115
|
+
XCTAssertEqualObjects(@"second", [self.registry get:@"k1"]);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
- (void)testClear_removesAll {
|
|
119
|
+
XCTAssertTrue([self.registry put:@"a" value:@"1" error:nil]);
|
|
120
|
+
XCTAssertTrue([self.registry put:@"b" value:@"2" error:nil]);
|
|
121
|
+
[self.registry clear];
|
|
122
|
+
XCTAssertNil([self.registry get:@"a"]);
|
|
123
|
+
XCTAssertNil([self.registry get:@"b"]);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
- (void)testClear_empty_isNoOp {
|
|
127
|
+
[self.registry clear];
|
|
128
|
+
XCTAssertNil([self.registry get:@"k1"]);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@end
|