@react-native-firebase/auth 21.12.3 → 21.13.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
+ ## [21.13.0](https://github.com/invertase/react-native-firebase/compare/v21.12.3...v21.13.0) (2025-03-31)
7
+
8
+ ### Features
9
+
10
+ - **auth:** validatePassword method implementation ([#8400](https://github.com/invertase/react-native-firebase/issues/8400)) ([1ec33f5](https://github.com/invertase/react-native-firebase/commit/1ec33f5020664fe32aa8132a170a83ec865aa95d))
11
+
6
12
  ## [21.12.3](https://github.com/invertase/react-native-firebase/compare/v21.12.2...v21.12.3) (2025-03-26)
7
13
 
8
14
  **Note:** Version bump only for package @react-native-firebase/auth
@@ -690,10 +690,85 @@ export function getAdditionalUserInfo(
690
690
  export function getCustomAuthDomain(auth: Auth): Promise<string>;
691
691
 
692
692
  /**
693
- * Various Providers.
693
+ * Validates the password against the password policy configured for the project or tenant.
694
+ *
695
+ * @remarks
696
+ * If no tenant ID is set on the `Auth` instance, then this method will use the password
697
+ * policy configured for the project. Otherwise, this method will use the policy configured
698
+ * for the tenant. If a password policy has not been configured, then the default policy
699
+ * configured for all projects will be used.
700
+ *
701
+ * If an auth flow fails because a submitted password does not meet the password policy
702
+ * requirements and this method has previously been called, then this method will use the
703
+ * most recent policy available when called again.
704
+ *
705
+ * When using this method, ensure you have the Identity Toolkit enabled on the
706
+ * Google Cloud Platform with the API Key for your application permitted to use it.
707
+ *
708
+ * @example
709
+ * ``` js
710
+ * import { getAuth, validatePassword } from "firebase/auth";
711
+ *
712
+ * const status = await validatePassword(getAuth(), passwordFromUser);
713
+ * if (!status.isValid) {
714
+ * // Password could not be validated. Use the status to show what
715
+ * // requirements are met and which are missing.
694
716
  *
717
+ * // If a criterion is undefined, it is not required by policy. If the
718
+ * // criterion is defined but false, it is required but not fulfilled by
719
+ * // the given password. For example:
720
+ * const needsLowerCase = status.containsLowercaseLetter !== true;
721
+ * }
722
+ * ```
695
723
  *
724
+ * @param auth The {@link Auth} instance.
725
+ * @param password The password to validate.
726
+ *
727
+ * @public
696
728
  */
729
+ export function validatePassword(auth: Auth, password: string): Promise<PasswordValidationStatus>;
730
+
731
+ /**
732
+ * A structure indicating which password policy requirements were met or violated and what the
733
+ * requirements are.
734
+ *
735
+ * @public
736
+ */
737
+ export interface PasswordValidationStatus {
738
+ /**
739
+ * Whether the password meets all requirements.
740
+ */
741
+ readonly isValid: boolean;
742
+ /**
743
+ * Whether the password meets the minimum password length, or undefined if not required.
744
+ */
745
+ readonly meetsMinPasswordLength?: boolean;
746
+ /**
747
+ * Whether the password meets the maximum password length, or undefined if not required.
748
+ */
749
+ readonly meetsMaxPasswordLength?: boolean;
750
+ /**
751
+ * Whether the password contains a lowercase letter, or undefined if not required.
752
+ */
753
+ readonly containsLowercaseLetter?: boolean;
754
+ /**
755
+ * Whether the password contains an uppercase letter, or undefined if not required.
756
+ */
757
+ readonly containsUppercaseLetter?: boolean;
758
+ /**
759
+ * Whether the password contains a numeric character, or undefined if not required.
760
+ */
761
+ readonly containsNumericCharacter?: boolean;
762
+ /**
763
+ * Whether the password contains a non-alphanumeric character, or undefined if not required.
764
+ */
765
+ readonly containsNonAlphanumericCharacter?: boolean;
766
+ /**
767
+ * The policy used to validate the password.
768
+ */
769
+ readonly passwordPolicy: PasswordPolicy;
770
+ }
771
+
697
772
  export {
698
773
  AppleAuthProvider,
699
774
  EmailAuthProvider,
@@ -16,6 +16,8 @@
16
16
  */
17
17
 
18
18
  import { getApp } from '@react-native-firebase/app';
19
+ import { fetchPasswordPolicy } from '../password-policy/passwordPolicyApi';
20
+ import { PasswordPolicyImpl } from '../password-policy/PasswordPolicyImpl';
19
21
  import FacebookAuthProvider from '../providers/FacebookAuthProvider';
20
22
  export { FacebookAuthProvider };
21
23
 
@@ -353,17 +355,6 @@ export function useDeviceLanguage(auth) {
353
355
  throw new Error('useDeviceLanguage is unsupported by the native Firebase SDKs');
354
356
  }
355
357
 
356
- /**
357
- * Validates the password against the password policy configured for the project or tenant.
358
- *
359
- * @param auth - The Auth instance.
360
- * @param password - The password to validate.
361
- *
362
- */
363
- export function validatePassword(auth, password) {
364
- throw new Error('validatePassword is only supported on Web');
365
- } //TO DO: ADD support.
366
-
367
358
  /**
368
359
  * Sets the current language to the default device/browser preference.
369
360
  * @param {Auth} auth - The Auth instance.
@@ -614,3 +605,23 @@ export function getAdditionalUserInfo(userCredential) {
614
605
  export function getCustomAuthDomain(auth) {
615
606
  return auth.getCustomAuthDomain();
616
607
  }
608
+
609
+ /**
610
+ * Returns a password validation status
611
+ * @param {Auth} auth - The Auth instance.
612
+ * @param {string} password - The password to validate.
613
+ * @returns {Promise<PasswordValidationStatus>}
614
+ */
615
+ export async function validatePassword(auth, password) {
616
+ if (password === null || password === undefined) {
617
+ throw new Error(
618
+ "firebase.auth().validatePassword(*) expected 'password' to be a non-null or a defined value.",
619
+ );
620
+ }
621
+ let passwordPolicy = await fetchPasswordPolicy(auth);
622
+
623
+ const passwordPolicyImpl = await new PasswordPolicyImpl(passwordPolicy);
624
+ let status = passwordPolicyImpl.validatePassword(password);
625
+
626
+ return status;
627
+ }
@@ -0,0 +1,132 @@
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
+ // Minimum min password length enforced by the backend, even if no minimum length is set.
19
+ const MINIMUM_MIN_PASSWORD_LENGTH = 6;
20
+
21
+ /**
22
+ * Stores password policy requirements and provides password validation against the policy.
23
+ *
24
+ * @internal
25
+ */
26
+ export class PasswordPolicyImpl {
27
+ constructor(response) {
28
+ // Only include custom strength options defined in the response.
29
+ const responseOptions = response.customStrengthOptions;
30
+ this.customStrengthOptions = {};
31
+ this.customStrengthOptions.minPasswordLength =
32
+ responseOptions.minPasswordLength ?? MINIMUM_MIN_PASSWORD_LENGTH;
33
+ if (responseOptions.maxPasswordLength) {
34
+ this.customStrengthOptions.maxPasswordLength = responseOptions.maxPasswordLength;
35
+ }
36
+ if (responseOptions.containsLowercaseCharacter !== undefined) {
37
+ this.customStrengthOptions.containsLowercaseLetter =
38
+ responseOptions.containsLowercaseCharacter;
39
+ }
40
+ if (responseOptions.containsUppercaseCharacter !== undefined) {
41
+ this.customStrengthOptions.containsUppercaseLetter =
42
+ responseOptions.containsUppercaseCharacter;
43
+ }
44
+ if (responseOptions.containsNumericCharacter !== undefined) {
45
+ this.customStrengthOptions.containsNumericCharacter =
46
+ responseOptions.containsNumericCharacter;
47
+ }
48
+ if (responseOptions.containsNonAlphanumericCharacter !== undefined) {
49
+ this.customStrengthOptions.containsNonAlphanumericCharacter =
50
+ responseOptions.containsNonAlphanumericCharacter;
51
+ }
52
+
53
+ this.enforcementState =
54
+ response.enforcementState === 'ENFORCEMENT_STATE_UNSPECIFIED'
55
+ ? 'OFF'
56
+ : response.enforcementState;
57
+
58
+ // Use an empty string if no non-alphanumeric characters are specified in the response.
59
+ this.allowedNonAlphanumericCharacters =
60
+ response.allowedNonAlphanumericCharacters?.join('') ?? '';
61
+
62
+ this.forceUpgradeOnSignin = response.forceUpgradeOnSignin ?? false;
63
+ this.schemaVersion = response.schemaVersion;
64
+ }
65
+
66
+ validatePassword(password) {
67
+ const status = {
68
+ isValid: true,
69
+ passwordPolicy: this,
70
+ };
71
+
72
+ this.validatePasswordLengthOptions(password, status);
73
+ this.validatePasswordCharacterOptions(password, status);
74
+
75
+ status.isValid &&= status.meetsMinPasswordLength ?? true;
76
+ status.isValid &&= status.meetsMaxPasswordLength ?? true;
77
+ status.isValid &&= status.containsLowercaseLetter ?? true;
78
+ status.isValid &&= status.containsUppercaseLetter ?? true;
79
+ status.isValid &&= status.containsNumericCharacter ?? true;
80
+ status.isValid &&= status.containsNonAlphanumericCharacter ?? true;
81
+
82
+ return status;
83
+ }
84
+
85
+ validatePasswordLengthOptions(password, status) {
86
+ const minPasswordLength = this.customStrengthOptions.minPasswordLength;
87
+ const maxPasswordLength = this.customStrengthOptions.maxPasswordLength;
88
+ if (minPasswordLength) {
89
+ status.meetsMinPasswordLength = password.length >= minPasswordLength;
90
+ }
91
+ if (maxPasswordLength) {
92
+ status.meetsMaxPasswordLength = password.length <= maxPasswordLength;
93
+ }
94
+ }
95
+
96
+ validatePasswordCharacterOptions(password, status) {
97
+ this.updatePasswordCharacterOptionsStatuses(status, false, false, false, false);
98
+
99
+ for (let i = 0; i < password.length; i++) {
100
+ const passwordChar = password.charAt(i);
101
+ this.updatePasswordCharacterOptionsStatuses(
102
+ status,
103
+ passwordChar >= 'a' && passwordChar <= 'z',
104
+ passwordChar >= 'A' && passwordChar <= 'Z',
105
+ passwordChar >= '0' && passwordChar <= '9',
106
+ this.allowedNonAlphanumericCharacters.includes(passwordChar),
107
+ );
108
+ }
109
+ }
110
+
111
+ updatePasswordCharacterOptionsStatuses(
112
+ status,
113
+ containsLowercaseCharacter,
114
+ containsUppercaseCharacter,
115
+ containsNumericCharacter,
116
+ containsNonAlphanumericCharacter,
117
+ ) {
118
+ if (this.customStrengthOptions.containsLowercaseLetter) {
119
+ status.containsLowercaseLetter ||= containsLowercaseCharacter;
120
+ }
121
+ if (this.customStrengthOptions.containsUppercaseLetter) {
122
+ status.containsUppercaseLetter ||= containsUppercaseCharacter;
123
+ }
124
+ if (this.customStrengthOptions.containsNumericCharacter) {
125
+ status.containsNumericCharacter ||= containsNumericCharacter;
126
+ }
127
+ if (this.customStrengthOptions.containsNonAlphanumericCharacter) {
128
+ status.containsNonAlphanumericCharacter ||= containsNonAlphanumericCharacter;
129
+ }
130
+ }
131
+ }
132
+ export default PasswordPolicyImpl;
@@ -0,0 +1,55 @@
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
+ /**
19
+ * Performs an API request to Firebase Console to get password policy json.
20
+ *
21
+ * @param {Object} auth - The authentication instance
22
+ * @returns {Promise<Response>} A promise that resolves to the API response.
23
+ * @throws {Error} Throws an error if the request fails or encounters an issue.
24
+ */
25
+ export async function fetchPasswordPolicy(auth) {
26
+ let schemaVersion = 1;
27
+
28
+ try {
29
+ // Identity toolkit API endpoint for password policy. Ensure this is enabled on Google cloud.
30
+ const baseURL = 'https://identitytoolkit.googleapis.com/v2/passwordPolicy?key=';
31
+ const apiKey = auth.app.options.apiKey;
32
+
33
+ const response = await fetch(`${baseURL}${apiKey}`);
34
+ if (!response.ok) {
35
+ const errorDetails = await response.text();
36
+ throw new Error(
37
+ `firebase.auth().validatePassword(*) failed to fetch password policy from Firebase Console: ${response.statusText}. Details: ${errorDetails}`,
38
+ );
39
+ }
40
+ const passwordPolicy = await response.json();
41
+
42
+ if (passwordPolicy.schemaVersion !== schemaVersion) {
43
+ throw new Error(
44
+ `Password policy schema version mismatch. Expected: ${schemaVersion}, received: ${passwordPolicy.schemaVersion}`,
45
+ );
46
+ }
47
+ return passwordPolicy;
48
+ } catch (error) {
49
+ throw new Error(
50
+ `firebase.auth().validatePassword(*) Failed to fetch password policy: ${error.message}`,
51
+ );
52
+ }
53
+ }
54
+
55
+ module.exports = { fetchPasswordPolicy };
package/lib/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- module.exports = '21.12.3';
2
+ module.exports = '21.13.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-firebase/auth",
3
- "version": "21.12.3",
3
+ "version": "21.13.0",
4
4
  "author": "Invertase <oss@invertase.io> (http://invertase.io)",
5
5
  "description": "React Native Firebase - The authentication module provides an easy-to-use API to integrate an authentication workflow into new and existing applications. React Native Firebase provides access to all Firebase authentication methods and identity providers.",
6
6
  "main": "lib/index.js",
@@ -27,7 +27,7 @@
27
27
  "plist": "^3.1.0"
28
28
  },
29
29
  "peerDependencies": {
30
- "@react-native-firebase/app": "21.12.3",
30
+ "@react-native-firebase/app": "21.13.0",
31
31
  "expo": ">=47.0.0"
32
32
  },
33
33
  "devDependencies": {
@@ -42,5 +42,5 @@
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "gitHead": "ea8aeec70b59b191d42bc753d1353c6f705b3e4b"
45
+ "gitHead": "d4d02d15431a0be091a7417833e0180479f5e788"
46
46
  }