@quatrain/auth-firebase 1.2.5 → 1.2.7

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.
@@ -74,4 +74,11 @@ export declare class FirebaseAuthAdapter extends AbstractAuthAdapter {
74
74
  * @returns The generated token payload.
75
75
  */
76
76
  refreshToken(refreshToken: string): Promise<any>;
77
+ /**
78
+ * Initiates password recovery/reset process for a user.
79
+ *
80
+ * @param email - The user email.
81
+ * @param redirectTo - Optional redirect destination.
82
+ */
83
+ recoverPassword(email: string, redirectTo?: string): Promise<any>;
77
84
  }
@@ -130,6 +130,7 @@ class FirebaseAuthAdapter extends auth_1.AbstractAuthAdapter {
130
130
  */
131
131
  update(user, updatable) {
132
132
  return __awaiter(this, void 0, void 0, function* () {
133
+ var _a;
133
134
  auth_1.Auth.log('auth data to update', JSON.stringify(updatable));
134
135
  try {
135
136
  if (Object.keys(updatable).length > 0) {
@@ -137,7 +138,13 @@ class FirebaseAuthAdapter extends auth_1.AbstractAuthAdapter {
137
138
  yield (0, auth_2.getAuth)().updateUser(user.uid, updatable);
138
139
  }
139
140
  }
140
- catch (e) { }
141
+ catch (e) {
142
+ auth_1.Auth.error(e);
143
+ if (e.code === 'auth/weak-password' || ((_a = e.message) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes('password'))) {
144
+ throw new auth_1.AuthenticationError(auth_1.Auth.ERROR_WEAK_PASSWORD);
145
+ }
146
+ throw new auth_1.AuthenticationError(e.message);
147
+ }
141
148
  });
142
149
  }
143
150
  /**
@@ -191,5 +198,42 @@ class FirebaseAuthAdapter extends auth_1.AbstractAuthAdapter {
191
198
  return data;
192
199
  });
193
200
  }
201
+ /**
202
+ * Initiates password recovery/reset process for a user.
203
+ *
204
+ * @param email - The user email.
205
+ * @param redirectTo - Optional redirect destination.
206
+ */
207
+ recoverPassword(email, redirectTo) {
208
+ return __awaiter(this, void 0, void 0, function* () {
209
+ var _a;
210
+ if (!this._params.config || !this._params.config.apiKey) {
211
+ auth_1.Auth.warn(`Can't recover password, no API key provided in Firebase config`);
212
+ throw new Error('Firebase Auth API key is not configured');
213
+ }
214
+ const body = {
215
+ requestType: 'PASSWORD_RESET',
216
+ email,
217
+ };
218
+ if (redirectTo) {
219
+ body.actionCodeSettings = {
220
+ url: redirectTo,
221
+ handleCodeInApp: true,
222
+ };
223
+ }
224
+ const response = yield nativeFetch.fetch(`https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key=${this._params.config.apiKey}`, {
225
+ method: 'POST',
226
+ body: JSON.stringify(body),
227
+ headers: { 'Content-Type': 'application/json' },
228
+ });
229
+ if (!response.ok) {
230
+ const errorData = yield response.json().catch(() => ({}));
231
+ const message = ((_a = errorData.error) === null || _a === void 0 ? void 0 : _a.message) || response.statusText;
232
+ throw new Error(message);
233
+ }
234
+ const data = yield response.json();
235
+ return data;
236
+ });
237
+ }
194
238
  }
195
239
  exports.FirebaseAuthAdapter = FirebaseAuthAdapter;
@@ -199,13 +199,19 @@ describe('FirebaseAuthAdapter', () => {
199
199
  yield adapter.update(mockUser, {});
200
200
  expect(mockAuth.updateUser).not.toHaveBeenCalled();
201
201
  }));
202
- it('should silently handle errors during update', () => __awaiter(void 0, void 0, void 0, function* () {
202
+ it('should throw AuthenticationError on update error', () => __awaiter(void 0, void 0, void 0, function* () {
203
203
  const updatable = { displayName: 'New Name' };
204
204
  mockAuth.updateUser.mockRejectedValue(new Error('Update failed'));
205
- // Should not throw
206
- yield expect(adapter.update(mockUser, updatable)).resolves.toBeUndefined();
205
+ yield expect(adapter.update(mockUser, updatable)).rejects.toThrow(auth_1.AuthenticationError);
207
206
  expect(mockAuth.updateUser).toHaveBeenCalledWith('user-123', updatable);
208
207
  }));
208
+ it('should throw Auth.ERROR_WEAK_PASSWORD on weak password error', () => __awaiter(void 0, void 0, void 0, function* () {
209
+ const updatable = { password: '123' };
210
+ const weakError = new Error('Password should be stronger');
211
+ weakError.code = 'auth/weak-password';
212
+ mockAuth.updateUser.mockRejectedValue(weakError);
213
+ yield expect(adapter.update(mockUser, updatable)).rejects.toThrow('weak_password');
214
+ }));
209
215
  });
210
216
  describe('delete()', () => {
211
217
  const mockUser = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quatrain/auth-firebase",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "license": "AGPL-3.0-only",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,13 +19,13 @@
19
19
  },
20
20
  "author": "Quatrain Développement SAS <developers@quatrain.com>",
21
21
  "peerDependencies": {
22
- "@quatrain/core": "^1.2.14"
22
+ "@quatrain/core": "^1.2.16"
23
23
  },
24
24
  "dependencies": {
25
- "@quatrain/api": "^1.1.5",
26
- "@quatrain/auth": "^1.2.3",
27
- "@quatrain/backend": "^1.2.11",
28
- "@quatrain/core": "^1.2.14",
25
+ "@quatrain/api": "^1.1.6",
26
+ "@quatrain/auth": "^1.2.5",
27
+ "@quatrain/backend": "^1.2.14",
28
+ "@quatrain/core": "^1.2.16",
29
29
  "firebase-admin": "^13.0.1",
30
30
  "node-fetch-native": "^1.6.4"
31
31
  },
@@ -204,18 +204,29 @@ describe('FirebaseAuthAdapter', () => {
204
204
  expect(mockAuth.updateUser).not.toHaveBeenCalled()
205
205
  })
206
206
 
207
- it('should silently handle errors during update', async () => {
207
+ it('should throw AuthenticationError on update error', async () => {
208
208
  const updatable = { displayName: 'New Name' }
209
209
 
210
210
  mockAuth.updateUser.mockRejectedValue(new Error('Update failed'))
211
211
 
212
- // Should not throw
213
212
  await expect(
214
213
  adapter.update(mockUser, updatable)
215
- ).resolves.toBeUndefined()
214
+ ).rejects.toThrow(AuthenticationError)
216
215
 
217
216
  expect(mockAuth.updateUser).toHaveBeenCalledWith('user-123', updatable)
218
217
  })
218
+
219
+ it('should throw Auth.ERROR_WEAK_PASSWORD on weak password error', async () => {
220
+ const updatable = { password: '123' }
221
+ const weakError = new Error('Password should be stronger')
222
+ ;(weakError as any).code = 'auth/weak-password'
223
+
224
+ mockAuth.updateUser.mockRejectedValue(weakError)
225
+
226
+ await expect(
227
+ adapter.update(mockUser, updatable)
228
+ ).rejects.toThrow('weak_password')
229
+ })
219
230
  })
220
231
 
221
232
  describe('delete()', () => {
@@ -105,7 +105,13 @@ export class FirebaseAuthAdapter extends AbstractAuthAdapter {
105
105
  Auth.log(`Updating ${updatable.displayName} Auth record`)
106
106
  await getAuth().updateUser(user.uid, updatable)
107
107
  }
108
- } catch (e) {}
108
+ } catch (e: any) {
109
+ Auth.error(e)
110
+ if (e.code === 'auth/weak-password' || e.message?.toLowerCase().includes('password')) {
111
+ throw new AuthenticationError(Auth.ERROR_WEAK_PASSWORD)
112
+ }
113
+ throw new AuthenticationError((e as Error).message)
114
+ }
109
115
  }
110
116
 
111
117
  /**
@@ -159,4 +165,47 @@ export class FirebaseAuthAdapter extends AbstractAuthAdapter {
159
165
 
160
166
  return data
161
167
  }
168
+
169
+ /**
170
+ * Initiates password recovery/reset process for a user.
171
+ *
172
+ * @param email - The user email.
173
+ * @param redirectTo - Optional redirect destination.
174
+ */
175
+ async recoverPassword(email: string, redirectTo?: string): Promise<any> {
176
+ if (!this._params.config || !this._params.config.apiKey) {
177
+ Auth.warn(`Can't recover password, no API key provided in Firebase config`)
178
+ throw new Error('Firebase Auth API key is not configured')
179
+ }
180
+
181
+ const body: any = {
182
+ requestType: 'PASSWORD_RESET',
183
+ email,
184
+ }
185
+
186
+ if (redirectTo) {
187
+ body.actionCodeSettings = {
188
+ url: redirectTo,
189
+ handleCodeInApp: true,
190
+ }
191
+ }
192
+
193
+ const response = await nativeFetch.fetch(
194
+ `https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key=${this._params.config.apiKey}`,
195
+ {
196
+ method: 'POST',
197
+ body: JSON.stringify(body),
198
+ headers: { 'Content-Type': 'application/json' },
199
+ }
200
+ )
201
+
202
+ if (!response.ok) {
203
+ const errorData = await response.json().catch(() => ({}))
204
+ const message = errorData.error?.message || response.statusText
205
+ throw new Error(message)
206
+ }
207
+
208
+ const data = await response.json()
209
+ return data
210
+ }
162
211
  }