@carecard/validate 3.23.0 → 3.24.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/index.d.ts CHANGED
@@ -6,9 +6,16 @@
6
6
  export type ValidatePropertiesInput = Record<string, unknown> | null | undefined;
7
7
  export type ValidatePropertiesResult = Record<string, unknown>;
8
8
  export type BoolValidator = (input: unknown) => boolean;
9
- export type FailureMessageValidator = (input: unknown) => string | null;
10
9
  export type InStringArrayValidator = (stringArray: readonly string[], input: unknown) => boolean;
11
10
 
11
+ export type PasswordValidationFailureReason =
12
+ 'invalid_type' | 'invalid_unicode' | 'too_short' | 'too_long' | 'blocked';
13
+ export type PasswordValidationResult =
14
+ { isValid: true; value: string } | { isValid: false; reason: PasswordValidationFailureReason };
15
+
16
+ /** Validates and NFC-normalizes a new password using the CareCard password policy. */
17
+ export function validatePassword(input: unknown): PasswordValidationResult;
18
+
12
19
  /**
13
20
  * Utility function to validate multiple properties of an object at once.
14
21
  */
@@ -145,24 +152,12 @@ export const isSafeSearchString: BoolValidator;
145
152
  export const isEmailString: BoolValidator;
146
153
  /** Checks if the string is a valid JWT format. */
147
154
  export const isJwtString: BoolValidator;
148
- /** Checks if the string is a valid strong password. */
149
- export const isPasswordString: BoolValidator;
150
- /** Checks if the string is a valid simple password. */
151
- export const isSimplePasswordString: BoolValidator;
152
- /** Returns a failure message if the password is not strong enough. */
153
- export const isPasswordStringFailureMessage: FailureMessageValidator;
154
- /** Returns a failure message if the password is not valid as a simple password. */
155
- export const isSimplePasswordStringFailureMessage: FailureMessageValidator;
156
155
  /** Checks if the string is a valid username. */
157
156
  export const isUsernameString: BoolValidator;
158
157
  /** Checks if the string is a valid phone number. */
159
158
  export const isPhoneNumber: BoolValidator;
160
159
  /** Checks if the string is URL-safe. */
161
160
  export const isUrlSafeString: BoolValidator;
162
- /** Checks if the string length is between 6 and 24 characters. */
163
- export const isString6To24CharacterLong: BoolValidator;
164
- /** Checks if the string length is between 6 and 16 characters. */
165
- export const isString6To16CharacterLong: BoolValidator;
166
161
  /** Checks if the string is a valid Canadian province abbreviation (ON, QC). */
167
162
  export const isProvinceString: BoolValidator;
168
163
  /** Checks if the value is a boolean. */
@@ -211,15 +206,9 @@ export const validate: {
211
206
  isSafeSearchString: typeof isSafeSearchString;
212
207
  isEmailString: typeof isEmailString;
213
208
  isJwtString: typeof isJwtString;
214
- isPasswordString: typeof isPasswordString;
215
- isSimplePasswordString: typeof isSimplePasswordString;
216
- isPasswordStringFailureMessage: typeof isPasswordStringFailureMessage;
217
- isSimplePasswordStringFailureMessage: typeof isSimplePasswordStringFailureMessage;
218
209
  isUsernameString: typeof isUsernameString;
219
210
  isPhoneNumber: typeof isPhoneNumber;
220
211
  isUrlSafeString: typeof isUrlSafeString;
221
- isString6To24CharacterLong: typeof isString6To24CharacterLong;
222
- isString6To16CharacterLong: typeof isString6To16CharacterLong;
223
212
  isProvinceString: typeof isProvinceString;
224
213
  isBoolValue: typeof isBoolValue;
225
214
  isPostalCodeString: typeof isPostalCodeString;
package/index.js CHANGED
@@ -1,13 +1,15 @@
1
1
  const validate = require('./lib/validate');
2
+ const { validatePassword, ...legacyValidate } = validate;
2
3
  const validateProperties = require('./lib/validateProperties');
3
4
  const validateWhitelistProperties = require('./lib/validateWhitelistProperties');
4
5
  const validateNewUserRoleRequest = require('./lib/validateNewUserRoleRequest');
5
6
 
6
7
  module.exports = {
7
- validate,
8
+ validate: legacyValidate,
9
+ validatePassword,
8
10
  validateProperties,
9
11
  validateWhitelistProperties,
10
12
  ...validateNewUserRoleRequest,
11
- ...validate,
13
+ ...legacyValidate,
12
14
  ...validateProperties,
13
15
  };
package/lib/validate.js CHANGED
@@ -100,36 +100,25 @@ const isJwtString = jwt => {
100
100
  return jwtRegex.test(jwt);
101
101
  };
102
102
 
103
- const isPasswordString = password => {
104
- if (typeof password !== 'string' || password.length === 0 || password.length > 128) {
105
- return false;
103
+ const validatePassword = password => {
104
+ if (typeof password !== 'string') {
105
+ return { isValid: false, reason: 'invalid_type' };
106
106
  }
107
- const regExPassword = /^(?=.*[a-zA-Z0-9])(?=.*[!@#$%^&*_-])[a-zA-Z0-9!@#$%^&*_-]{6,32}$/;
108
- return regExPassword.test(String(password));
109
- };
110
-
111
- const isSimplePasswordString = password => {
112
- if (typeof password !== 'string' || password.length === 0 || password.length > 128) {
113
- return false;
107
+ if (!password.isWellFormed()) {
108
+ return { isValid: false, reason: 'invalid_unicode' };
114
109
  }
115
- const regExPassword = /^[a-zA-Z0-9!@#$%^&*_-]{6,32}$/;
116
- return regExPassword.test(String(password));
117
- };
118
-
119
- const isPasswordStringFailureMessage = password => {
120
- if (!isPasswordString(password)) {
121
- return 'Total 6 to 32 characters, numbers and one of !@#$%^&*_-';
122
- } else {
123
- return null;
110
+ const normalizedPassword = password.normalize('NFC');
111
+ const passwordLength = [...normalizedPassword].length;
112
+ if (passwordLength < MINIMUM_PASSWORD_LENGTH) {
113
+ return { isValid: false, reason: 'too_short' };
124
114
  }
125
- };
126
-
127
- const isSimplePasswordStringFailureMessage = password => {
128
- if (!isSimplePasswordString(password)) {
129
- return 'Total 6 to 32 characters, numbers or !@#$%^&*_-';
130
- } else {
131
- return null;
115
+ if (passwordLength > MAXIMUM_PASSWORD_LENGTH) {
116
+ return { isValid: false, reason: 'too_long' };
117
+ }
118
+ if (commonPasswords.has(normalizedPassword)) {
119
+ return { isValid: false, reason: 'blocked' };
132
120
  }
121
+ return { isValid: true, value: normalizedPassword };
133
122
  };
134
123
 
135
124
  const isUsernameString = str => {
@@ -159,20 +148,6 @@ const isUrlSafeString = inputString => {
159
148
  return urlSafeRegex.test(inputString);
160
149
  };
161
150
 
162
- const isString6To24CharacterLong = password => {
163
- if (typeof password !== 'string' || password.length === 0) {
164
- return false;
165
- }
166
- return 6 <= password.length && password.length <= 24;
167
- };
168
-
169
- const isString6To16CharacterLong = password => {
170
- if (typeof password !== 'string' || password.length === 0) {
171
- return false;
172
- }
173
- return 6 <= password.length && password.length <= 16;
174
- };
175
-
176
151
  const isProvinceString = inputString => {
177
152
  const provinces = ['on', 'qc'];
178
153
 
@@ -356,15 +331,10 @@ module.exports = {
356
331
  isSafeSearchString,
357
332
  isEmailString,
358
333
  isJwtString,
359
- isPasswordString,
360
- isSimplePasswordString,
361
- isPasswordStringFailureMessage,
362
- isSimplePasswordStringFailureMessage,
334
+ validatePassword,
363
335
  isUsernameString,
364
336
  isPhoneNumber,
365
337
  isUrlSafeString,
366
- isString6To24CharacterLong,
367
- isString6To16CharacterLong,
368
338
  isProvinceString,
369
339
  isBoolValue,
370
340
  isPostalCodeString,
@@ -381,3 +351,7 @@ module.exports = {
381
351
  isValidUrl,
382
352
  isValidArrayOfStrings,
383
353
  };
354
+ const commonPasswords = new Set(require('../data/commonPasswords.json'));
355
+
356
+ const MINIMUM_PASSWORD_LENGTH = 15;
357
+ const MAXIMUM_PASSWORD_LENGTH = 128;
@@ -5,9 +5,7 @@ const {
5
5
  isUrlSafeString,
6
6
  isValidUuidString,
7
7
  isCcIdString,
8
- isSimplePasswordString,
9
- isPasswordString,
10
- isString6To16CharacterLong,
8
+ validatePassword,
11
9
  isNameString,
12
10
  isSafeSearchString,
13
11
  isCharactersString,
@@ -110,14 +108,11 @@ function validateProperties(obj = {}) {
110
108
  case 'password':
111
109
  case 'new_password':
112
110
  case 'newPassword':
113
- if (isString6To16CharacterLong(value) && isSimplePasswordString(value)) {
114
- returnObj[key] = value;
115
- }
116
- break;
117
- case 'strong_password':
118
- case 'strongPassword':
119
- if (isString6To16CharacterLong(value) && isPasswordString(value)) {
120
- returnObj[key] = value;
111
+ {
112
+ const passwordResult = validatePassword(value);
113
+ if (passwordResult.isValid) {
114
+ returnObj[key] = passwordResult.value;
115
+ }
121
116
  }
122
117
  break;
123
118
  case 'email':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carecard/validate",
3
- "version": "3.23.0",
3
+ "version": "3.24.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/CareCard-ca/pkg-validate.git"
@@ -8,6 +8,9 @@
8
8
  "description": "Validate data",
9
9
  "main": "index.js",
10
10
  "types": "index.d.ts",
11
+ "engines": {
12
+ "node": ">=24.20.0 <25"
13
+ },
11
14
  "scripts": {
12
15
  "test": "node scripts/runPackageTask.mjs test",
13
16
  "test:order": "node --test scripts/testOrder/randomizeTestOrder.test.mjs scripts/testParallel/runIndexedMochaTests.test.mjs scripts/packageTaskRunner.test.mjs scripts/canonicalTestCommand.test.mjs",
@@ -44,7 +47,7 @@
44
47
  "typescript": "6.0.3"
45
48
  },
46
49
  "dependencies": {
47
- "@carecard/common-util": "3.23.0"
50
+ "@carecard/common-util": "3.24.0"
48
51
  },
49
52
  "nyc": {
50
53
  "all": true,