@umituz/react-native-firebase 2.4.40 → 2.4.41

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-firebase",
3
- "version": "2.4.40",
3
+ "version": "2.4.41",
4
4
  "description": "Unified Firebase package for React Native apps - Auth and Firestore services using Firebase JS SDK (no native modules).",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -4,8 +4,6 @@
4
4
  */
5
5
 
6
6
  import { deleteUser, type User } from "firebase/auth";
7
-
8
- declare const __DEV__: boolean;
9
7
  import { getFirebaseAuth } from "../../../auth/infrastructure/config/FirebaseAuthClient";
10
8
  import { markUserDeleted } from "../../../auth/infrastructure/services/user-document.service";
11
9
  import {
@@ -28,15 +26,7 @@ let deletionInProgress = false;
28
26
  export async function deleteCurrentUser(
29
27
  options: AccountDeletionOptions = { autoReauthenticate: true }
30
28
  ): Promise<AccountDeletionResult> {
31
- if (typeof __DEV__ !== "undefined" && __DEV__) {
32
- console.log("[deleteCurrentUser] Called with options:", options);
33
- }
34
-
35
- // FIX: Check if deletion already in progress
36
29
  if (deletionInProgress) {
37
- if (typeof __DEV__ !== "undefined" && __DEV__) {
38
- console.log("[deleteCurrentUser] Deletion already in progress");
39
- }
40
30
  return {
41
31
  success: false,
42
32
  error: { code: "auth/operation-in-progress", message: "Account deletion already in progress" },
@@ -51,9 +41,6 @@ export async function deleteCurrentUser(
51
41
  const user = auth?.currentUser;
52
42
 
53
43
  if (!auth || !user) {
54
- if (typeof __DEV__ !== "undefined" && __DEV__) {
55
- console.log("[deleteCurrentUser] Auth not ready");
56
- }
57
44
  return {
58
45
  success: false,
59
46
  error: { code: "auth/not-ready", message: "Auth not ready" },
@@ -61,13 +48,9 @@ export async function deleteCurrentUser(
61
48
  };
62
49
  }
63
50
 
64
- // FIX: Capture user ID early to detect if user changes during operation
65
51
  const originalUserId = user.uid;
66
52
 
67
53
  if (user.isAnonymous) {
68
- if (typeof __DEV__ !== "undefined" && __DEV__) {
69
- console.log("[deleteCurrentUser] Cannot delete anonymous user");
70
- }
71
54
  return {
72
55
  success: false,
73
56
  error: { code: "auth/anonymous", message: "Cannot delete anonymous" },
@@ -76,37 +59,17 @@ export async function deleteCurrentUser(
76
59
  }
77
60
 
78
61
  const provider = getUserAuthProvider(user);
79
- if (typeof __DEV__ !== "undefined" && __DEV__) {
80
- console.log("[deleteCurrentUser] User provider:", provider);
81
- }
82
62
 
83
63
  if (provider === "password" && options.autoReauthenticate && options.onPasswordRequired) {
84
- if (typeof __DEV__ !== "undefined" && __DEV__) {
85
- console.log("[deleteCurrentUser] Password provider, calling attemptReauth");
86
- }
87
64
  const reauth = await attemptReauth(user, options, originalUserId);
88
- if (typeof __DEV__ !== "undefined" && __DEV__) {
89
- console.log("[deleteCurrentUser] attemptReauth result:", reauth);
90
- }
91
65
  if (reauth) {
92
- if (typeof __DEV__ !== "undefined" && __DEV__) {
93
- console.log("[deleteCurrentUser] Reauth returned result, returning:", reauth);
94
- }
95
66
  return reauth;
96
67
  }
97
- if (typeof __DEV__ !== "undefined" && __DEV__) {
98
- console.log("[deleteCurrentUser] Reauth returned null, continuing to deleteUser");
99
- }
100
68
  }
101
69
 
102
70
  try {
103
- // Verify user hasn't changed before deletion
104
71
  const validation = validateUserUnchanged(auth, originalUserId);
105
72
  if (!('valid' in validation)) {
106
- // User changed - validation is a FailureResult
107
- if (typeof __DEV__ !== "undefined" && __DEV__) {
108
- console.log("[deleteCurrentUser] User changed during operation");
109
- }
110
73
  return {
111
74
  success: false,
112
75
  error: validation.error,
@@ -114,23 +77,10 @@ export async function deleteCurrentUser(
114
77
  };
115
78
  }
116
79
 
117
- if (typeof __DEV__ !== "undefined" && __DEV__) {
118
- console.log("[deleteCurrentUser] Marking user as deleted in Firestore");
119
- }
120
80
  await markUserDeleted(user.uid);
121
-
122
- if (typeof __DEV__ !== "undefined" && __DEV__) {
123
- console.log("[deleteCurrentUser] Calling deleteUser");
124
- }
125
81
  await deleteUser(user);
126
- if (typeof __DEV__ !== "undefined" && __DEV__) {
127
- console.log("[deleteCurrentUser] deleteUser successful");
128
- }
129
82
  return successResult();
130
83
  } catch (error: unknown) {
131
- if (typeof __DEV__ !== "undefined" && __DEV__) {
132
- console.error("[deleteCurrentUser] deleteUser failed:", error);
133
- }
134
84
  const errorInfo = toErrorInfo(error, 'auth/failed');
135
85
  const code = errorInfo.code;
136
86
  const message = errorInfo.message;
@@ -150,25 +100,15 @@ export async function deleteCurrentUser(
150
100
  };
151
101
  }
152
102
  } finally {
153
- // FIX: Always release lock when done
154
103
  deletionInProgress = false;
155
104
  }
156
105
  }
157
106
 
158
107
  async function attemptReauth(user: User, options: AccountDeletionOptions, originalUserId?: string): Promise<AccountDeletionResult | null> {
159
- if (typeof __DEV__ !== "undefined" && __DEV__) {
160
- console.log("[attemptReauth] Called");
161
- }
162
-
163
- // Verify user hasn't changed if originalUserId provided
164
108
  if (originalUserId) {
165
- const auth = getFirebaseAuth();
166
- const validation = validateUserUnchanged(auth, originalUserId);
109
+ const authInstance = getFirebaseAuth();
110
+ const validation = validateUserUnchanged(authInstance, originalUserId);
167
111
  if (!('valid' in validation)) {
168
- // User changed - validation is a FailureResult
169
- if (typeof __DEV__ !== "undefined" && __DEV__) {
170
- console.log("[attemptReauth] User changed during reauthentication");
171
- }
172
112
  return {
173
113
  success: false,
174
114
  error: validation.error,
@@ -178,21 +118,12 @@ async function attemptReauth(user: User, options: AccountDeletionOptions, origin
178
118
  }
179
119
 
180
120
  const provider = getUserAuthProvider(user);
181
- if (typeof __DEV__ !== "undefined" && __DEV__) {
182
- console.log("[attemptReauth] Provider:", provider);
183
- }
184
121
 
185
122
  let res: { success: boolean; error?: { code?: string; message?: string } };
186
123
 
187
124
  if (provider === "apple.com") {
188
- if (typeof __DEV__ !== "undefined" && __DEV__) {
189
- console.log("[attemptReauth] Apple provider");
190
- }
191
125
  res = await reauthenticateWithApple(user);
192
126
  } else if (provider === "google.com") {
193
- if (typeof __DEV__ !== "undefined" && __DEV__) {
194
- console.log("[attemptReauth] Google provider");
195
- }
196
127
  let googleToken = options.googleIdToken;
197
128
  if (!googleToken && options.onGoogleReauthRequired) {
198
129
  const token = await options.onGoogleReauthRequired();
@@ -214,93 +145,50 @@ async function attemptReauth(user: User, options: AccountDeletionOptions, origin
214
145
  }
215
146
  res = await reauthenticateWithGoogle(user, googleToken);
216
147
  } else if (provider === "password") {
217
- if (typeof __DEV__ !== "undefined" && __DEV__) {
218
- console.log("[attemptReauth] Password provider, calling onPasswordRequired...");
219
- }
220
148
  let password = options.password;
221
149
  if (!password && options.onPasswordRequired) {
222
- if (typeof __DEV__ !== "undefined" && __DEV__) {
223
- console.log("[attemptReauth] Calling onPasswordRequired callback");
224
- }
225
150
  const pwd = await options.onPasswordRequired();
226
- if (typeof __DEV__ !== "undefined" && __DEV__) {
227
- console.log("[attemptReauth] onPasswordRequired returned:", pwd ? "password received" : "null/cancelled");
228
- }
229
151
  if (!pwd) {
230
- if (typeof __DEV__ !== "undefined" && __DEV__) {
231
- console.log("[attemptReauth] Password was null/cancelled, returning error");
232
- }
233
152
  return {
234
153
  success: false,
235
154
  error: { code: "auth/password-reauth-cancelled", message: "Password reauth cancelled" },
236
155
  requiresReauth: true
237
156
  };
238
157
  }
239
- if (typeof __DEV__ !== "undefined" && __DEV__) {
240
- console.log("[attemptReauth] Password received, setting password variable");
241
- }
242
158
  password = pwd;
243
159
  }
244
160
  if (!password) {
245
- if (typeof __DEV__ !== "undefined" && __DEV__) {
246
- console.log("[attemptReauth] No password available after callback, returning error");
247
- }
248
161
  return {
249
162
  success: false,
250
163
  error: { code: "auth/password-reauth", message: "Password required" },
251
164
  requiresReauth: true
252
165
  };
253
166
  }
254
- if (typeof __DEV__ !== "undefined" && __DEV__) {
255
- console.log("[attemptReauth] Calling reauthenticateWithPassword");
256
- }
257
167
  res = await reauthenticateWithPassword(user, password);
258
- if (typeof __DEV__ !== "undefined" && __DEV__) {
259
- console.log("[attemptReauth] reauthenticateWithPassword result:", res);
260
- }
261
168
  } else {
262
169
  return null;
263
170
  }
264
171
 
265
172
  if (res.success) {
266
- if (typeof __DEV__ !== "undefined" && __DEV__) {
267
- console.log("[attemptReauth] Reauthentication successful, calling deleteUser");
268
- }
269
173
  try {
270
- const auth = getFirebaseAuth();
271
- const currentUser = auth?.currentUser || user;
174
+ const postReauthAuth = getFirebaseAuth();
175
+ const currentUser = postReauthAuth?.currentUser || user;
272
176
 
273
- // Final verification before deletion
274
177
  if (originalUserId) {
275
- const auth = getFirebaseAuth();
276
- const validation = validateUserUnchanged(auth, originalUserId);
277
- if (!('valid' in validation)) {
278
- // User changed - validation is a FailureResult
279
- if (typeof __DEV__ !== "undefined" && __DEV__) {
280
- console.log("[attemptReauth] User changed after reauthentication");
281
- }
178
+ const validationCheck = validateUserUnchanged(postReauthAuth, originalUserId);
179
+ if (!('valid' in validationCheck)) {
282
180
  return {
283
181
  success: false,
284
- error: validation.error,
182
+ error: validationCheck.error,
285
183
  requiresReauth: false
286
184
  };
287
185
  }
288
186
  }
289
187
 
290
- if (typeof __DEV__ !== "undefined" && __DEV__) {
291
- console.log("[attemptReauth] Marking user as deleted in Firestore");
292
- }
293
188
  await markUserDeleted(currentUser.uid);
294
-
295
189
  await deleteUser(currentUser);
296
- if (typeof __DEV__ !== "undefined" && __DEV__) {
297
- console.log("[attemptReauth] deleteUser successful after reauth");
298
- }
299
190
  return successResult();
300
191
  } catch (err: unknown) {
301
- if (typeof __DEV__ !== "undefined" && __DEV__) {
302
- console.error("[attemptReauth] deleteUser failed after reauth:", err);
303
- }
304
192
  const errorInfo = toErrorInfo(err, 'auth/failed');
305
193
  return {
306
194
  success: false,
@@ -310,9 +198,6 @@ async function attemptReauth(user: User, options: AccountDeletionOptions, origin
310
198
  }
311
199
  }
312
200
 
313
- if (typeof __DEV__ !== "undefined" && __DEV__) {
314
- console.log("[attemptReauth] Reauthentication failed, returning error");
315
- }
316
201
  return {
317
202
  success: false,
318
203
  error: {
@@ -58,24 +58,30 @@ export abstract class BaseRepository implements IPathResolver {
58
58
  return db;
59
59
  }
60
60
 
61
+ private validateSegment(value: string, fieldName: string): void {
62
+ if (!value || value.trim() === '') {
63
+ throw new Error(`${fieldName} must be a non-empty string`);
64
+ }
65
+ if (value.includes('/')) {
66
+ throw new Error(`${fieldName} must not contain '/' characters`);
67
+ }
68
+ if (value === '.' || value === '..') {
69
+ throw new Error(`${fieldName} must not be '.' or '..'`);
70
+ }
71
+ }
72
+
61
73
  getUserCollection(userId: string): CollectionReference<DocumentData> | null {
62
74
  const db = this.getDb();
63
75
  if (!db) return null;
64
- if (!userId || userId.trim() === '') {
65
- throw new Error('userId must be a non-empty string');
66
- }
76
+ this.validateSegment(userId, 'userId');
67
77
  return collection(db, 'users', userId, this.collectionName);
68
78
  }
69
79
 
70
80
  getDocRef(userId: string, documentId: string): DocumentReference<DocumentData> | null {
71
81
  const db = this.getDb();
72
82
  if (!db) return null;
73
- if (!userId || userId.trim() === '') {
74
- throw new Error('userId must be a non-empty string');
75
- }
76
- if (!documentId || documentId.trim() === '') {
77
- throw new Error('documentId must be a non-empty string');
78
- }
83
+ this.validateSegment(userId, 'userId');
84
+ this.validateSegment(documentId, 'documentId');
79
85
  return doc(db, 'users', userId, this.collectionName, documentId);
80
86
  }
81
87
 
@@ -3,11 +3,15 @@
3
3
  * Centralized ID generation utilities for unique identifiers
4
4
  */
5
5
 
6
+ import * as Crypto from "expo-crypto";
7
+
6
8
  /**
7
- * Generate a unique ID using timestamp and random string
9
+ * Generate a unique ID using timestamp and cryptographically secure random string
8
10
  * Format: timestamp-randomstring
9
11
  * @returns Unique identifier string
10
12
  */
11
13
  export function generateUniqueId(): string {
12
- return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
14
+ const randomBytes = Crypto.getRandomBytes(8);
15
+ const hex = Array.from(randomBytes).map(b => b.toString(16).padStart(2, "0")).join("");
16
+ return `${Date.now()}-${hex}`;
13
17
  }