@react-native-firebase/app-check 18.3.2 → 18.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 CHANGED
@@ -3,6 +3,12 @@
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
+ ## [18.4.0](https://github.com/invertase/react-native-firebase/compare/v18.3.2...v18.4.0) (2023-09-11)
7
+
8
+ ### Features
9
+
10
+ - **app-check, android:** Implement app check token change listener ([#7309](https://github.com/invertase/react-native-firebase/issues/7309)) ([adebe40](https://github.com/invertase/react-native-firebase/commit/adebe40883adc539bf84134d407be677084a5b47))
11
+
6
12
  ## [18.3.2](https://github.com/invertase/react-native-firebase/compare/v18.3.1...v18.3.2) (2023-09-02)
7
13
 
8
14
  **Note:** Version bump only for package @react-native-firebase/app-check
@@ -28,11 +28,19 @@ import io.invertase.firebase.common.ReactNativeFirebaseJSON;
28
28
  import io.invertase.firebase.common.ReactNativeFirebaseMeta;
29
29
  import io.invertase.firebase.common.ReactNativeFirebaseModule;
30
30
  import io.invertase.firebase.common.ReactNativeFirebasePreferences;
31
+ import io.invertase.firebase.common.ReactNativeFirebaseEvent;
32
+ import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter;
33
+ import java.util.HashMap;
34
+ import java.util.Iterator;
35
+ import java.util.Map;
31
36
 
32
37
  public class ReactNativeFirebaseAppCheckModule extends ReactNativeFirebaseModule {
33
38
  private static final String TAG = "AppCheck";
34
39
  private static final String LOGTAG = "RNFBAppCheck";
35
40
  private static final String KEY_APPCHECK_TOKEN_REFRESH_ENABLED = "app_check_token_auto_refresh";
41
+
42
+ private static HashMap<String, FirebaseAppCheck.AppCheckListener> mAppCheckListeners = new HashMap<>();
43
+
36
44
  ReactNativeFirebaseAppCheckProviderFactory providerFactory =
37
45
  new ReactNativeFirebaseAppCheckProviderFactory();
38
46
 
@@ -90,6 +98,24 @@ public class ReactNativeFirebaseAppCheckModule extends ReactNativeFirebaseModule
90
98
  firebaseAppCheck.setTokenAutoRefreshEnabled(isAppCheckTokenRefreshEnabled());
91
99
  }
92
100
 
101
+ @Override
102
+ public void onCatalystInstanceDestroy() {
103
+ super.onCatalystInstanceDestroy();
104
+ Log.d(TAG, "instance-destroyed");
105
+
106
+ Iterator appCheckListenerIterator = mAppCheckListeners.entrySet().iterator();
107
+
108
+ while (appCheckListenerIterator.hasNext()) {
109
+ Map.Entry pair = (Map.Entry) appCheckListenerIterator.next();
110
+ String appName = (String) pair.getKey();
111
+ FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
112
+ FirebaseAppCheck firebaseAppCheck = FirebaseAppCheck.getInstance(firebaseApp);
113
+ FirebaseAppCheck.AppCheckListener mAppCheckListener = (FirebaseAppCheck.AppCheckListener) pair.getValue();
114
+ firebaseAppCheck.removeAppCheckListener(mAppCheckListener);
115
+ appCheckListenerIterator.remove();
116
+ }
117
+ }
118
+
93
119
  @ReactMethod
94
120
  public void configureProvider(
95
121
  String appName, String providerName, String debugToken, Promise promise) {
@@ -177,4 +203,45 @@ public class ReactNativeFirebaseAppCheckModule extends ReactNativeFirebaseModule
177
203
  }
178
204
  });
179
205
  }
206
+
207
+ /** Add a new token change listener - if one doesn't exist already */
208
+ @ReactMethod
209
+ public void addAppCheckListener(final String appName) {
210
+ Log.d(TAG, "addAppCheckListener " + appName);
211
+
212
+ FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
213
+ FirebaseAppCheck firebaseAppCheck = FirebaseAppCheck.getInstance(firebaseApp);
214
+
215
+ if (mAppCheckListeners.get(appName) == null) {
216
+ FirebaseAppCheck.AppCheckListener newAppCheckListener = appCheckToken -> {
217
+ WritableMap eventBody = Arguments.createMap();
218
+ eventBody.putString("appName", appName); // for js side distribution
219
+ eventBody.putString("token", appCheckToken.getToken());
220
+ eventBody.putDouble("expireTimeMillis", appCheckToken.getExpireTimeMillis());
221
+
222
+ ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();
223
+ ReactNativeFirebaseEvent event = new ReactNativeFirebaseEvent("appCheck_token_changed", eventBody, appName);
224
+ emitter.sendEvent(event);
225
+ };
226
+
227
+ firebaseAppCheck.addAppCheckListener(newAppCheckListener);
228
+ mAppCheckListeners.put(appName, newAppCheckListener);
229
+ }
230
+ }
231
+
232
+ /** Removes the current token change listener */
233
+ @ReactMethod
234
+ public void removeAppCheckListener(String appName) {
235
+ Log.d(TAG, "removeAppCheckListener " + appName);
236
+
237
+ FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
238
+ FirebaseAppCheck firebaseAppCheck = FirebaseAppCheck.getInstance(firebaseApp);
239
+
240
+ FirebaseAppCheck.AppCheckListener mAppCheckListener = mAppCheckListeners.get(appName);
241
+
242
+ if (mAppCheckListener != null) {
243
+ firebaseAppCheck.removeAppCheckListener(mAppCheckListener);
244
+ mAppCheckListeners.remove(appName);
245
+ }
246
+ }
180
247
  }
package/lib/index.d.ts CHANGED
@@ -88,6 +88,18 @@ export namespace FirebaseAppCheckTypes {
88
88
  isTokenAutoRefreshEnabled?: boolean;
89
89
  }
90
90
 
91
+ export type NextFn<T> = (value: T) => void;
92
+ export type ErrorFn = (error: Error) => void;
93
+ export type CompleteFn = () => void;
94
+
95
+ export interface Observer<T> {
96
+ next: NextFn<T>;
97
+ error: ErrorFn;
98
+ complete: CompleteFn;
99
+ }
100
+
101
+ export type PartialObserver<T> = Partial<Observer<T>>;
102
+
91
103
  export interface ReactNativeFirebaseAppCheckProviderOptions {
92
104
  /**
93
105
  * debug token to use, if any. Defaults to undefined, pre-configure tokens in firebase web console if needed
@@ -165,6 +177,10 @@ export namespace FirebaseAppCheckTypes {
165
177
  */
166
178
  readonly expireTimeMillis: number;
167
179
  }
180
+ /**
181
+ * The result return from `onTokenChanged`
182
+ */
183
+ export type AppCheckListenerResult = AppCheckToken & { readonly appName: string };
168
184
 
169
185
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
170
186
  export interface Statics {
@@ -258,12 +274,9 @@ export namespace FirebaseAppCheckTypes {
258
274
  *
259
275
  * @returns A function that unsubscribes this listener.
260
276
  */
261
- // TODO there is a great deal of Observer / PartialObserver typing to carry-in
262
- // onTokenChanged(observer: PartialObserver<AppCheckTokenResult>): () => void;
277
+ onTokenChanged(observer: PartialObserver<AppCheckListenerResult>): () => void;
263
278
 
264
279
  /**
265
- * TODO implement token listener for android.
266
- *
267
280
  * Registers a listener to changes in the token state. There can be more
268
281
  * than one listener registered at the same time for one or more
269
282
  * App Check instances. The listeners call back on the UI thread whenever
@@ -272,13 +285,19 @@ export namespace FirebaseAppCheckTypes {
272
285
  * Token listeners do not exist in the native SDK for iOS, no token change events will be emitted on that platform.
273
286
  * This is not yet implemented on Android, no token change events will be emitted until implemented.
274
287
  *
288
+ * NOTE: Although an `onError` callback can be provided, it will
289
+ * never be called, Android sdk code doesn't provide handling for onError function
290
+ *
291
+ * NOTE: Although an `onCompletion` callback can be provided, it will
292
+ * never be called because the token stream is never-ending.
293
+ *
275
294
  * @returns A function that unsubscribes this listener.
276
295
  */
277
- // onTokenChanged(
278
- // onNext: (tokenResult: AppCheckTokenResult) => void,
279
- // onError?: (error: Error) => void,
280
- // onCompletion?: () => void,
281
- // ): () => void;
296
+ onTokenChanged(
297
+ onNext: (tokenResult: AppCheckListenerResult) => void,
298
+ onError?: (error: Error) => void,
299
+ onCompletion?: () => void,
300
+ ): () => void;
282
301
  }
283
302
  }
284
303
 
package/lib/index.js CHANGED
@@ -40,6 +40,16 @@ const namespace = 'appCheck';
40
40
  const nativeModuleName = 'RNFBAppCheckModule';
41
41
 
42
42
  class FirebaseAppCheckModule extends FirebaseModule {
43
+ constructor(...args) {
44
+ super(...args);
45
+
46
+ this.emitter.addListener(this.eventNameForApp('appCheck_token_changed'), event => {
47
+ this.emitter.emit(this.eventNameForApp('onAppCheckTokenChanged'), event);
48
+ });
49
+
50
+ this._listenerCount = 0;
51
+ }
52
+
43
53
  getIsTokenRefreshEnabledDefault() {
44
54
  // no default to start
45
55
  isTokenAutoRefreshEnabled = undefined;
@@ -131,13 +141,40 @@ class FirebaseAppCheckModule extends FirebaseModule {
131
141
  }
132
142
  }
133
143
 
134
- onTokenChanged() {
144
+ _parseListener(listenerOrObserver) {
145
+ return typeof listenerOrObserver === 'object'
146
+ ? listenerOrObserver.next.bind(listenerOrObserver)
147
+ : listenerOrObserver;
148
+ }
149
+
150
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
151
+ onTokenChanged(onNextOrObserver, onError, onCompletion) {
135
152
  // iOS does not provide any native listening feature
136
153
  if (isIOS) {
154
+ // eslint-disable-next-line no-console
155
+ console.warn('onTokenChanged is not implemented on IOS, only for Android');
137
156
  return () => {};
138
157
  }
139
- // TODO unimplemented on Android
140
- return () => {};
158
+ const nextFn = this._parseListener(onNextOrObserver);
159
+ // let errorFn = function () { };
160
+ // if (onNextOrObserver.error != null) {
161
+ // errorFn = onNextOrObserver.error.bind(onNextOrObserver);
162
+ // }
163
+ // else if (onError) {
164
+ // errorFn = onError;
165
+ // }
166
+ const subscription = this.emitter.addListener(
167
+ this.eventNameForApp('onAppCheckTokenChanged'),
168
+ nextFn,
169
+ );
170
+ if (this._listenerCount === 0) this.native.addAppCheckListener();
171
+
172
+ this._listenerCount++;
173
+ return () => {
174
+ subscription.remove();
175
+ this._listenerCount--;
176
+ if (this._listenerCount === 0) this.native.removeAppCheckListener();
177
+ };
141
178
  }
142
179
  }
143
180
 
@@ -151,7 +188,7 @@ export default createModuleNamespace({
151
188
  version,
152
189
  namespace,
153
190
  nativeModuleName,
154
- nativeEvents: false, // TODO implement ['appcheck-token-changed'],
191
+ nativeEvents: ['appCheck_token_changed'],
155
192
  hasMultiAppSupport: true,
156
193
  hasCustomUrlOrRegionSupport: false,
157
194
  ModuleClass: FirebaseAppCheckModule,
package/lib/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- module.exports = '18.3.2';
2
+ module.exports = '18.4.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-firebase/app-check",
3
- "version": "18.3.2",
3
+ "version": "18.4.0",
4
4
  "author": "Invertase <oss@invertase.io> (http://invertase.io)",
5
5
  "description": "React Native Firebase - App Check",
6
6
  "main": "lib/index.js",
@@ -23,10 +23,10 @@
23
23
  "appCheck"
24
24
  ],
25
25
  "peerDependencies": {
26
- "@react-native-firebase/app": "18.3.2"
26
+ "@react-native-firebase/app": "18.4.0"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"
30
30
  },
31
- "gitHead": "f323891622441c9d59a25ef37b19534db512b372"
31
+ "gitHead": "5f6460a87970d8b6013530de980bc760ddc70f90"
32
32
  }