@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.
- package/CHANGELOG.md +27 -0
- package/RNFBAuth.podspec +8 -2
- package/android/build.gradle +5 -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 +68 -102
- package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthCacheRegistry.kt +77 -0
- package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthListenerRegistry.kt +76 -0
- package/android/src/test/java/io/invertase/firebase/auth/RNFBAuthCacheRegistryTest.java +184 -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/index.js +1 -2
- package/dist/module/index.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/types/internal.d.ts +2 -3
- package/dist/typescript/lib/types/internal.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 +84 -0
- package/ios/RNFBAuth/RNFBAuthCacheRegistryStorage.swift +53 -0
- package/ios/RNFBAuth/RNFBAuthErrorCodeMapper.swift +333 -0
- package/ios/RNFBAuth/RNFBAuthHelper.m +147 -262
- package/ios/RNFBAuth/RNFBAuthListenerRegistry.h +39 -0
- package/ios/RNFBAuth/RNFBAuthListenerRegistry.m +83 -0
- package/ios/RNFBAuth/RNFBAuthListenerRegistryStorage.swift +76 -0
- package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.h +40 -0
- package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.m +49 -0
- package/ios/RNFBAuth.xcodeproj/project.pbxproj +22 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthCacheRegistryStorageTests.swift +72 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthCacheRegistryTests.m +131 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthErrorCodeMapperTests.swift +250 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthListenerRegistryStorageTests.swift +122 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthListenerRegistryTests.m +152 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthNullSentinelDecodeTests.m +78 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/project.pbxproj +311 -0
- package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBAuthUnitTests.xcscheme +69 -0
- package/lib/ActionCodeURL.ts +1 -2
- package/lib/index.ts +1 -1
- package/lib/types/internal.ts +2 -2
- package/lib/version.ts +1 -1
- package/package.json +5 -4
- package/plugin/build/index.js +4 -0
- package/plugin/build/ios/index.d.ts +2 -1
- package/plugin/build/ios/index.js +3 -1
- package/plugin/build/ios/openUrlFix.js +12 -0
- package/plugin/build/ios/sceneDelegate.d.ts +34 -0
- package/plugin/build/ios/sceneDelegate.js +127 -0
- package/plugin/build/ios/sceneLifecycle.d.ts +32 -0
- package/plugin/build/ios/sceneLifecycle.js +115 -0
- package/plugin/src/index.ts +9 -1
- package/plugin/src/ios/index.ts +2 -1
- package/plugin/src/ios/openUrlFix.ts +15 -0
- package/plugin/src/ios/sceneDelegate.ts +159 -0
- package/plugin/src/ios/sceneLifecycle.ts +134 -0
- package/plugin/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,33 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [27.0.0](https://github.com/invertase/react-native-firebase/compare/v26.4.0...v27.0.0) (2026-10-19)
|
|
7
|
+
|
|
8
|
+
### ⚠ BREAKING CHANGES
|
|
9
|
+
|
|
10
|
+
- **app, sdk:** bump Firebase Android 35, Apple 13, and JS 13
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- **app, sdk:** bump Firebase Android 35, Apple 13, and JS 13 ([0ca03d1](https://github.com/invertase/react-native-firebase/commit/0ca03d11b0c271fb37cfbee8a0c3074a21969f0b))
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
- **app,database:** resolve platform native module when bundlers apply package exports ([959d91f](https://github.com/invertase/react-native-firebase/commit/959d91fc79d7155d1d9a08e1f836789e6e6d6156))
|
|
19
|
+
- **auth, analytics, remote-config:** unwrap iOS null sentinels on Object args ([53fdb6a](https://github.com/invertase/react-native-firebase/commit/53fdb6a1c273d4125cff69e33b2d0af6bfd7d6dc))
|
|
20
|
+
- **auth, android:** accept null keys in auth cache registry get/take ([211c6cf](https://github.com/invertase/react-native-firebase/commit/211c6cff37c004c06134242cf84e670afd52eff5))
|
|
21
|
+
- **auth:** apply the reCAPTCHA openURL fix on the UIScene life cycle ([327fbe3](https://github.com/invertase/react-native-firebase/commit/327fbe319ba238c4f50aadc85ed687225b0804c8))
|
|
22
|
+
- **auth:** remove sensitive authentication logs ([57c5d1c](https://github.com/invertase/react-native-firebase/commit/57c5d1c993e8497148cd40a706fb40ebe01426ef))
|
|
23
|
+
|
|
24
|
+
## [26.4.0](https://github.com/invertase/react-native-firebase/compare/v26.3.3...v26.4.0) (2026-09-05)
|
|
25
|
+
|
|
26
|
+
### Bug Fixes
|
|
27
|
+
|
|
28
|
+
- **auth, ios:** look up customAuthDomains with JS app name ([9873f61](https://github.com/invertase/react-native-firebase/commit/9873f618a972c3324ec05b9e30f5aaefa7ab163b))
|
|
29
|
+
- **auth:** [LOW] handle malformed action links ([0961ccc](https://github.com/invertase/react-native-firebase/commit/0961ccc1108195c40fbb00ba38280f70f1419fbe))
|
|
30
|
+
- **auth:** use RNFBHandleMap for auth state and id-token listeners ([a708e84](https://github.com/invertase/react-native-firebase/commit/a708e847119995b8cfbde07f11ea84d48aede29b))
|
|
31
|
+
- **auth:** use RNFBHandleMap for credential and MFA caches ([bd891f5](https://github.com/invertase/react-native-firebase/commit/bd891f5f8955c8c08d9d9447f2442beda91c9174))
|
|
32
|
+
|
|
6
33
|
## [26.3.3](https://github.com/invertase/react-native-firebase/compare/v26.3.2...v26.3.3) (2026-09-01)
|
|
7
34
|
|
|
8
35
|
### Bug Fixes
|
package/RNFBAuth.podspec
CHANGED
|
@@ -28,14 +28,20 @@ Pod::Spec.new do |s|
|
|
|
28
28
|
s.ios.deployment_target = firebase_ios_target
|
|
29
29
|
s.macos.deployment_target = firebase_macos_target
|
|
30
30
|
s.tvos.deployment_target = firebase_tvos_target
|
|
31
|
-
s.
|
|
31
|
+
s.swift_version = '5.10'
|
|
32
|
+
s.source_files = 'ios/**/*.{h,m,mm,cpp,swift}'
|
|
32
33
|
s.private_header_files = [
|
|
33
34
|
'ios/RNFBAuth/RNFBAuthModule.h',
|
|
35
|
+
'ios/RNFBAuth/RNFBAuthNullSentinelDecoder.h',
|
|
34
36
|
'ios/generated/**/*.h',
|
|
35
37
|
]
|
|
36
|
-
|
|
38
|
+
# CocoaPods FileList uses FNM_PATHNAME: `ios/*UnitTests/**` does not match nested
|
|
39
|
+
# paths like `ios/RNFBAuthUnitTests/HostStubs/**` (those would compile into the pod).
|
|
40
|
+
s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*', 'ios/*UnitTests/**/*'
|
|
37
41
|
|
|
42
|
+
# DEFINES_MODULE is required for the generated RNFBAuth-Swift.h interface.
|
|
38
43
|
s.pod_target_xcconfig = {
|
|
44
|
+
"DEFINES_MODULE" => "YES",
|
|
39
45
|
"HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ios/generated/RNFBAuthTurboModules\" \"$(PODS_TARGET_SRCROOT)/ios/generated\"",
|
|
40
46
|
"CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" => "YES",
|
|
41
47
|
}
|
package/android/build.gradle
CHANGED
|
@@ -13,6 +13,7 @@ buildscript {
|
|
|
13
13
|
|
|
14
14
|
dependencies {
|
|
15
15
|
classpath("com.android.tools.build:gradle:8.4.0")
|
|
16
|
+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.findProperty('kotlinVersion') ?: '2.4.0'}")
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
}
|
|
@@ -21,6 +22,8 @@ plugins {
|
|
|
21
22
|
id "io.invertase.gradle.build" version "1.5"
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
apply plugin: "org.jetbrains.kotlin.android"
|
|
26
|
+
|
|
24
27
|
def appProject
|
|
25
28
|
if (findProject(':@react-native-firebase_app')) {
|
|
26
29
|
appProject = project(':@react-native-firebase_app')
|
|
@@ -91,6 +94,8 @@ dependencies {
|
|
|
91
94
|
api appProject
|
|
92
95
|
implementation platform("com.google.firebase:firebase-bom:${ReactNative.ext.getVersion("firebase", "bom")}")
|
|
93
96
|
implementation "com.google.firebase:firebase-auth"
|
|
97
|
+
|
|
98
|
+
testImplementation "junit:junit:4.13.2"
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
ReactNative.shared.applyPackageVersion()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package io.invertase.firebase.auth;
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this library except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Detach surface stored in {@link RNFBAuthListenerRegistry}. Invoked after {@code get}/{@code
|
|
22
|
+
* take}/{@code takeAll}, never under the HandleMap lock.
|
|
23
|
+
*/
|
|
24
|
+
interface AuthListenerHandle {
|
|
25
|
+
void remove();
|
|
26
|
+
}
|
|
@@ -84,7 +84,6 @@ import java.text.SimpleDateFormat;
|
|
|
84
84
|
import java.util.ArrayList;
|
|
85
85
|
import java.util.Date;
|
|
86
86
|
import java.util.HashMap;
|
|
87
|
-
import java.util.Iterator;
|
|
88
87
|
import java.util.List;
|
|
89
88
|
import java.util.Locale;
|
|
90
89
|
import java.util.Map;
|
|
@@ -104,21 +103,23 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
104
103
|
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
|
105
104
|
|
|
106
105
|
private static final String TAG = "Auth";
|
|
107
|
-
private static
|
|
108
|
-
private static
|
|
106
|
+
private static final RNFBAuthListenerRegistry authStateListeners = new RNFBAuthListenerRegistry();
|
|
107
|
+
private static final RNFBAuthListenerRegistry idTokenListeners = new RNFBAuthListenerRegistry();
|
|
109
108
|
private static HashMap<String, String> emulatorConfigs = new HashMap<>();
|
|
110
109
|
private String mVerificationId;
|
|
111
110
|
private String mLastPhoneNumber;
|
|
112
111
|
private PhoneAuthProvider.ForceResendingToken mForceResendingToken;
|
|
113
112
|
private PhoneAuthCredential mCredential;
|
|
114
113
|
|
|
115
|
-
private final
|
|
116
|
-
|
|
117
|
-
private final
|
|
114
|
+
private final RNFBAuthCacheRegistry<MultiFactorResolver> mCachedResolvers =
|
|
115
|
+
new RNFBAuthCacheRegistry<>();
|
|
116
|
+
private final RNFBAuthCacheRegistry<MultiFactorSession> mMultiFactorSessions =
|
|
117
|
+
new RNFBAuthCacheRegistry<>();
|
|
118
|
+
private final RNFBAuthCacheRegistry<TotpSecret> mTotpSecrets = new RNFBAuthCacheRegistry<>();
|
|
118
119
|
|
|
119
120
|
// storage for anonymous phone auth credentials, used for linkWithCredentials
|
|
120
121
|
// https://github.com/invertase/react-native-firebase/issues/4911
|
|
121
|
-
private
|
|
122
|
+
private final RNFBAuthCacheRegistry<AuthCredential> credentials = new RNFBAuthCacheRegistry<>();
|
|
122
123
|
|
|
123
124
|
private final TaskExecutorService executorService;
|
|
124
125
|
|
|
@@ -142,34 +143,13 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
142
143
|
super.invalidate();
|
|
143
144
|
Log.d(TAG, "instance-destroyed");
|
|
144
145
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
while (authListenerIterator.hasNext()) {
|
|
148
|
-
Map.Entry pair = (Map.Entry) authListenerIterator.next();
|
|
149
|
-
String appName = (String) pair.getKey();
|
|
150
|
-
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
|
151
|
-
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
|
152
|
-
FirebaseAuth.AuthStateListener mAuthListener =
|
|
153
|
-
(FirebaseAuth.AuthStateListener) pair.getValue();
|
|
154
|
-
firebaseAuth.removeAuthStateListener(mAuthListener);
|
|
155
|
-
authListenerIterator.remove();
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
Iterator idTokenListenerIterator = mIdTokenListeners.entrySet().iterator();
|
|
159
|
-
|
|
160
|
-
while (idTokenListenerIterator.hasNext()) {
|
|
161
|
-
Map.Entry pair = (Map.Entry) idTokenListenerIterator.next();
|
|
162
|
-
String appName = (String) pair.getKey();
|
|
163
|
-
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
|
164
|
-
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
|
165
|
-
FirebaseAuth.IdTokenListener mAuthListener = (FirebaseAuth.IdTokenListener) pair.getValue();
|
|
166
|
-
firebaseAuth.removeIdTokenListener(mAuthListener);
|
|
167
|
-
idTokenListenerIterator.remove();
|
|
168
|
-
}
|
|
146
|
+
authStateListeners.takeAllAndRemove();
|
|
147
|
+
idTokenListeners.takeAllAndRemove();
|
|
169
148
|
|
|
170
149
|
mCachedResolvers.clear();
|
|
171
150
|
mMultiFactorSessions.clear();
|
|
172
151
|
mTotpSecrets.clear();
|
|
152
|
+
// credentials intentionally not cleared (prior HashMap behavior)
|
|
173
153
|
}
|
|
174
154
|
|
|
175
155
|
@Override
|
|
@@ -199,46 +179,37 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
199
179
|
|
|
200
180
|
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
|
201
181
|
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
firebaseAuth1 -> {
|
|
206
|
-
FirebaseUser user = firebaseAuth1.getCurrentUser();
|
|
207
|
-
WritableMap eventBody = Arguments.createMap();
|
|
208
|
-
ReactNativeFirebaseEventEmitter emitter =
|
|
209
|
-
ReactNativeFirebaseEventEmitter.getSharedInstance();
|
|
210
|
-
if (user != null) {
|
|
211
|
-
eventBody.putString("appName", appName); // for js side distribution
|
|
212
|
-
eventBody.putMap("user", firebaseUserToMap(user));
|
|
213
|
-
} else {
|
|
214
|
-
eventBody.putString("appName", appName); // for js side distribution
|
|
215
|
-
}
|
|
216
|
-
Log.d(TAG, "addAuthStateListener:eventBody " + eventBody.toString());
|
|
182
|
+
if (authStateListeners.get(appName) != null) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
217
185
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
186
|
+
FirebaseAuth.AuthStateListener newAuthListener =
|
|
187
|
+
firebaseAuth1 -> {
|
|
188
|
+
FirebaseUser user = firebaseAuth1.getCurrentUser();
|
|
189
|
+
WritableMap eventBody = Arguments.createMap();
|
|
190
|
+
ReactNativeFirebaseEventEmitter emitter =
|
|
191
|
+
ReactNativeFirebaseEventEmitter.getSharedInstance();
|
|
192
|
+
if (user != null) {
|
|
193
|
+
eventBody.putString("appName", appName); // for js side distribution
|
|
194
|
+
eventBody.putMap("user", firebaseUserToMap(user));
|
|
195
|
+
} else {
|
|
196
|
+
eventBody.putString("appName", appName); // for js side distribution
|
|
197
|
+
}
|
|
198
|
+
ReactNativeFirebaseEvent event =
|
|
199
|
+
new ReactNativeFirebaseEvent("auth_state_changed", eventBody, appName);
|
|
200
|
+
emitter.sendEvent(event);
|
|
201
|
+
};
|
|
222
202
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
203
|
+
firebaseAuth.addAuthStateListener(newAuthListener);
|
|
204
|
+
authStateListeners.putOrDiscard(
|
|
205
|
+
appName, () -> firebaseAuth.removeAuthStateListener(newAuthListener));
|
|
226
206
|
}
|
|
227
207
|
|
|
228
208
|
/** Removes the current auth state listener */
|
|
229
209
|
@Override
|
|
230
210
|
public void removeAuthStateListener(String appName) {
|
|
231
211
|
Log.d(TAG, "removeAuthStateListener");
|
|
232
|
-
|
|
233
|
-
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
|
234
|
-
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
|
235
|
-
|
|
236
|
-
FirebaseAuth.AuthStateListener mAuthListener = mAuthListeners.get(appName);
|
|
237
|
-
|
|
238
|
-
if (mAuthListener != null) {
|
|
239
|
-
firebaseAuth.removeAuthStateListener(mAuthListener);
|
|
240
|
-
mAuthListeners.remove(appName);
|
|
241
|
-
}
|
|
212
|
+
authStateListeners.takeAndRemove(appName);
|
|
242
213
|
}
|
|
243
214
|
|
|
244
215
|
/** Add a new id token listener - if one doesn't exist already */
|
|
@@ -249,46 +220,40 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
249
220
|
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
|
250
221
|
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
|
251
222
|
|
|
252
|
-
if (
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
FirebaseUser user = firebaseAuth1.getCurrentUser();
|
|
256
|
-
ReactNativeFirebaseEventEmitter emitter =
|
|
257
|
-
ReactNativeFirebaseEventEmitter.getSharedInstance();
|
|
258
|
-
WritableMap eventBody = Arguments.createMap();
|
|
259
|
-
if (user != null) {
|
|
260
|
-
eventBody.putBoolean("authenticated", true);
|
|
261
|
-
eventBody.putString("appName", appName);
|
|
262
|
-
eventBody.putMap("user", firebaseUserToMap(user));
|
|
263
|
-
} else {
|
|
264
|
-
eventBody.putString("appName", appName);
|
|
265
|
-
eventBody.putBoolean("authenticated", false);
|
|
266
|
-
}
|
|
223
|
+
if (idTokenListeners.get(appName) != null) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
267
226
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
227
|
+
FirebaseAuth.IdTokenListener newIdTokenListener =
|
|
228
|
+
firebaseAuth1 -> {
|
|
229
|
+
FirebaseUser user = firebaseAuth1.getCurrentUser();
|
|
230
|
+
ReactNativeFirebaseEventEmitter emitter =
|
|
231
|
+
ReactNativeFirebaseEventEmitter.getSharedInstance();
|
|
232
|
+
WritableMap eventBody = Arguments.createMap();
|
|
233
|
+
if (user != null) {
|
|
234
|
+
eventBody.putBoolean("authenticated", true);
|
|
235
|
+
eventBody.putString("appName", appName);
|
|
236
|
+
eventBody.putMap("user", firebaseUserToMap(user));
|
|
237
|
+
} else {
|
|
238
|
+
eventBody.putString("appName", appName);
|
|
239
|
+
eventBody.putBoolean("authenticated", false);
|
|
240
|
+
}
|
|
272
241
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
242
|
+
ReactNativeFirebaseEvent event =
|
|
243
|
+
new ReactNativeFirebaseEvent("auth_id_token_changed", eventBody, appName);
|
|
244
|
+
emitter.sendEvent(event);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
firebaseAuth.addIdTokenListener(newIdTokenListener);
|
|
248
|
+
idTokenListeners.putOrDiscard(
|
|
249
|
+
appName, () -> firebaseAuth.removeIdTokenListener(newIdTokenListener));
|
|
276
250
|
}
|
|
277
251
|
|
|
278
252
|
/** Removes the current id token listener */
|
|
279
253
|
@Override
|
|
280
254
|
public void removeIdTokenListener(String appName) {
|
|
281
255
|
Log.d(TAG, "removeIdTokenListener");
|
|
282
|
-
|
|
283
|
-
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
|
284
|
-
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
|
285
|
-
|
|
286
|
-
FirebaseAuth.IdTokenListener mIdTokenListener = mIdTokenListeners.get(appName);
|
|
287
|
-
|
|
288
|
-
if (mIdTokenListener != null) {
|
|
289
|
-
firebaseAuth.removeIdTokenListener(mIdTokenListener);
|
|
290
|
-
mIdTokenListeners.remove(appName);
|
|
291
|
-
}
|
|
256
|
+
idTokenListeners.takeAndRemove(appName);
|
|
292
257
|
}
|
|
293
258
|
|
|
294
259
|
/**
|
|
@@ -1152,7 +1117,7 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
1152
1117
|
|
|
1153
1118
|
final MultiFactorSession session = task.getResult();
|
|
1154
1119
|
final String sessionId = Integer.toString(session.hashCode());
|
|
1155
|
-
mMultiFactorSessions.
|
|
1120
|
+
mMultiFactorSessions.putReplacing(sessionId, session);
|
|
1156
1121
|
|
|
1157
1122
|
promise.resolve(sessionId);
|
|
1158
1123
|
});
|
|
@@ -1493,7 +1458,7 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
1493
1458
|
if (task.isSuccessful()) {
|
|
1494
1459
|
TotpSecret totpSecret = task.getResult();
|
|
1495
1460
|
String totpSecretKey = totpSecret.getSharedSecretKey();
|
|
1496
|
-
mTotpSecrets.
|
|
1461
|
+
mTotpSecrets.putReplacing(totpSecretKey, totpSecret);
|
|
1497
1462
|
WritableMap result = Arguments.createMap();
|
|
1498
1463
|
result.putString("secretKey", totpSecretKey);
|
|
1499
1464
|
promise.resolve(result);
|
|
@@ -1551,7 +1516,7 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
1551
1516
|
final String requestKey,
|
|
1552
1517
|
final double timeout,
|
|
1553
1518
|
final boolean forceResend) {
|
|
1554
|
-
Log.d(TAG, "verifyPhoneNumber
|
|
1519
|
+
Log.d(TAG, "verifyPhoneNumber");
|
|
1555
1520
|
|
|
1556
1521
|
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
|
1557
1522
|
final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
|
@@ -2061,8 +2026,9 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
2061
2026
|
if (provider.startsWith("oidc.")) {
|
|
2062
2027
|
return OAuthProvider.newCredentialBuilder(provider).setIdToken(authToken).build();
|
|
2063
2028
|
}
|
|
2064
|
-
|
|
2065
|
-
|
|
2029
|
+
AuthCredential cachedCredential = credentials.get(authToken);
|
|
2030
|
+
if (cachedCredential != null) {
|
|
2031
|
+
return cachedCredential;
|
|
2066
2032
|
}
|
|
2067
2033
|
|
|
2068
2034
|
switch (provider) {
|
|
@@ -2463,7 +2429,7 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
2463
2429
|
authCredentialsMap.putString("secret", null);
|
|
2464
2430
|
|
|
2465
2431
|
// Temporarily store the non-serializable credential for later
|
|
2466
|
-
credentials.
|
|
2432
|
+
credentials.putReplacing(authHashCode, authCredential);
|
|
2467
2433
|
|
|
2468
2434
|
WritableMap userInfoMap = Arguments.createMap();
|
|
2469
2435
|
userInfoMap.putString("code", error.getString("code"));
|
|
@@ -2565,7 +2531,7 @@ public class NativeRNFBTurboAuth extends NativeRNFBTurboAuthSpec {
|
|
|
2565
2531
|
code = "MULTI_FACTOR_AUTH_REQUIRED";
|
|
2566
2532
|
final MultiFactorResolver resolver = multiFactorException.getResolver();
|
|
2567
2533
|
final String sessionId = Integer.toString(resolver.getSession().hashCode());
|
|
2568
|
-
mCachedResolvers.
|
|
2534
|
+
mCachedResolvers.putReplacing(sessionId, resolver);
|
|
2569
2535
|
// Passing around a resolver ReadableMap leads to issues when trying to send the data back by
|
|
2570
2536
|
// calling Promise#reject. Building the map just before sending solves that issue.
|
|
2571
2537
|
error.putString("sessionId", sessionId);
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
package io.invertase.firebase.auth
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this library except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import io.invertase.firebase.common.RNFBHandleCollisionException
|
|
21
|
+
import io.invertase.firebase.common.RNFBHandleMap
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Credential / MFA cache map (data only — no SDK cancel). Unique [put]; callers that previously
|
|
25
|
+
* HashMap-upserted use [putReplacing] (atomic last wins). Peek with [get]; remove with [take];
|
|
26
|
+
* invalidate with [clear].
|
|
27
|
+
*
|
|
28
|
+
* Collision vs prior HashMap.put upsert: unique [put] throws; replace at call sites is
|
|
29
|
+
* [putReplacing] (last wins). [putOrDiscard] keeps the first mapping.
|
|
30
|
+
*/
|
|
31
|
+
internal class RNFBAuthCacheRegistry<V> {
|
|
32
|
+
private val map = RNFBHandleMap<String, V>()
|
|
33
|
+
|
|
34
|
+
@Throws(RNFBHandleCollisionException::class)
|
|
35
|
+
fun put(
|
|
36
|
+
key: String,
|
|
37
|
+
value: V,
|
|
38
|
+
) {
|
|
39
|
+
map.put(key, value)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Unique put. On collision, leave the existing mapping and discard the incoming value (data
|
|
44
|
+
* only).
|
|
45
|
+
*
|
|
46
|
+
* @return true if stored
|
|
47
|
+
*/
|
|
48
|
+
fun putOrDiscard(
|
|
49
|
+
key: String,
|
|
50
|
+
value: V,
|
|
51
|
+
): Boolean = map.putIfAbsent(key, value)
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Atomic replace (last wins). Preserves prior HashMap `put` upsert. Taken value discarded.
|
|
55
|
+
*/
|
|
56
|
+
fun putReplacing(
|
|
57
|
+
key: String,
|
|
58
|
+
value: V,
|
|
59
|
+
) {
|
|
60
|
+
map.putReplacing(key, value)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Peek. Nullable [key] matches prior Java `HashMap.get(null)` → null (no NPE). Java callers such
|
|
65
|
+
* as `promiseRejectAuthException` may pass a null sessionId when the error map has none.
|
|
66
|
+
*/
|
|
67
|
+
fun get(key: String?): V? = if (key == null) null else map.get(key)
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Remove. Nullable [key] matches prior Java `HashMap.remove(null)` → null (no NPE).
|
|
71
|
+
*/
|
|
72
|
+
fun take(key: String?): V? = if (key == null) null else map.take(key)
|
|
73
|
+
|
|
74
|
+
fun clear() {
|
|
75
|
+
map.takeAll()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
package io.invertase.firebase.auth
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this library except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import io.invertase.firebase.common.RNFBHandleCollisionException
|
|
21
|
+
import io.invertase.firebase.common.RNFBHandleMap
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Auth-state / id-token listener map. Unique [put] / [putOrDiscard]; callers [take] or
|
|
25
|
+
* [takeAllAndRemove] then `remove()` outside the HandleMap lock. Skip-if-registered is
|
|
26
|
+
* `get(appName) != null`.
|
|
27
|
+
*
|
|
28
|
+
* Null-key note: [get]/[take]/[takeAndRemove] keep non-null [String] keys. Call sites always
|
|
29
|
+
* pass TurboModule `appName` (never null). Unlike [RNFBAuthCacheRegistry], no Java path passes a
|
|
30
|
+
* null lookup key.
|
|
31
|
+
*/
|
|
32
|
+
internal class RNFBAuthListenerRegistry {
|
|
33
|
+
private val map = RNFBHandleMap<String, AuthListenerHandle?>()
|
|
34
|
+
|
|
35
|
+
@Throws(RNFBHandleCollisionException::class)
|
|
36
|
+
fun put(
|
|
37
|
+
appName: String,
|
|
38
|
+
handle: AuthListenerHandle?,
|
|
39
|
+
) {
|
|
40
|
+
map.put(appName, handle)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Unique put. On collision, `remove()` the incoming handle and leave the existing mapping.
|
|
45
|
+
*
|
|
46
|
+
* @return true if stored
|
|
47
|
+
*/
|
|
48
|
+
fun putOrDiscard(
|
|
49
|
+
appName: String,
|
|
50
|
+
handle: AuthListenerHandle?,
|
|
51
|
+
): Boolean {
|
|
52
|
+
try {
|
|
53
|
+
map.put(appName, handle)
|
|
54
|
+
return true
|
|
55
|
+
} catch (_: RNFBHandleCollisionException) {
|
|
56
|
+
handle?.remove()
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fun get(appName: String): AuthListenerHandle? = map.get(appName)
|
|
62
|
+
|
|
63
|
+
fun take(appName: String): AuthListenerHandle? = map.take(appName)
|
|
64
|
+
|
|
65
|
+
fun takeAndRemove(appName: String) {
|
|
66
|
+
val handle = map.take(appName)
|
|
67
|
+
handle?.remove()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fun takeAllAndRemove() {
|
|
71
|
+
val remaining = map.takeAll()
|
|
72
|
+
for (handle in remaining) {
|
|
73
|
+
handle?.remove()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|