check-password-strength
Advanced tools
Comparing version 1.0.15 to 2.0.0
135
index.js
@@ -1,83 +0,76 @@ | ||
module.exports = (password) => { | ||
if (!password) { | ||
throw new Error("Password is empty."); | ||
defaultOptions = [ | ||
{ | ||
id: 0, | ||
value: "Too weak", | ||
minDiversity: 0, | ||
minLength: 0 | ||
}, | ||
{ | ||
id: 1, | ||
value: "Weak", | ||
minDiversity: 2, | ||
minLength: 6 | ||
}, | ||
{ | ||
id: 2, | ||
value: "Medium", | ||
minDiversity: 4, | ||
minLength: 8 | ||
}, | ||
{ | ||
id: 3, | ||
value: "Strong", | ||
minDiversity: 4, | ||
minLength: 10 | ||
} | ||
] | ||
const lowerCaseRegex = "(?=.*[a-z])"; | ||
const upperCaseRegex = "(?=.*[A-Z])"; | ||
const symbolsRegex = "(?=.*[!@#$%^&*])"; | ||
const numericRegex = "(?=.*[0-9])"; | ||
let strength = { | ||
id: null, | ||
value: null, | ||
length: null, | ||
contains: [], | ||
}; | ||
passwordStrength = (password, options = defaultOptions, allowedSymbols="!@#$%^&*") => { | ||
// Default | ||
let passwordContains = []; | ||
let passwordCopy = password || '' | ||
if (new RegExp(`^${lowerCaseRegex}`).test(password)) { | ||
passwordContains = [ | ||
...passwordContains, | ||
{ | ||
message: "lowercase", | ||
}, | ||
]; | ||
} | ||
options[0].minDiversity = 0, | ||
options[0].minLength = 0 | ||
if (new RegExp(`^${upperCaseRegex}`).test(password)) { | ||
passwordContains = [ | ||
...passwordContains, | ||
{ | ||
message: "uppercase", | ||
}, | ||
]; | ||
} | ||
const rules = [ | ||
{ | ||
regex: "[a-z]", | ||
message: 'lowercase' | ||
}, | ||
{ | ||
regex: '[A-Z]', | ||
message: 'uppercase' | ||
}, | ||
{ | ||
regex: '[0-9]', | ||
message: 'number' | ||
}, | ||
] | ||
if (new RegExp(`^${symbolsRegex}`).test(password)) { | ||
passwordContains = [ | ||
...passwordContains, | ||
{ | ||
message: "symbol", | ||
}, | ||
]; | ||
if (allowedSymbols) { | ||
rules.push({ | ||
regex: `[${allowedSymbols}]`, | ||
message: 'symbol' | ||
}) | ||
} | ||
if (new RegExp(`^${numericRegex}`).test(password)) { | ||
passwordContains = [ | ||
...passwordContains, | ||
{ | ||
message: "number", | ||
}, | ||
]; | ||
} | ||
let strength = {} | ||
const strongRegex = new RegExp( | ||
`^${lowerCaseRegex}${upperCaseRegex}${numericRegex}${symbolsRegex}(?=.{8,})` | ||
); | ||
const mediumRegex = new RegExp( | ||
`^((${lowerCaseRegex}${upperCaseRegex})|(${lowerCaseRegex}${numericRegex})|(${upperCaseRegex}${numericRegex})|(${upperCaseRegex}${symbolsRegex})|(${lowerCaseRegex}${symbolsRegex})|(${numericRegex}${symbolsRegex}))(?=.{6,})` | ||
); | ||
strength.contains = rules | ||
.filter(rule => new RegExp(`${rule.regex}`).test(passwordCopy)) | ||
.map(rule => rule.message) | ||
if (strongRegex.test(password)) { | ||
strength = { | ||
id: 2, | ||
value: "Strong", | ||
}; | ||
} else if (mediumRegex.test(password)) { | ||
strength = { | ||
id: 1, | ||
value: "Medium", | ||
}; | ||
} else { | ||
strength = { | ||
id: 0, | ||
value: "Weak", | ||
}; | ||
} | ||
strength.length = password.length; | ||
strength.contains = passwordContains; | ||
strength.length = passwordCopy.length; | ||
let fulfilledOptions = options | ||
.filter(option => strength.contains.length >= option.minDiversity) | ||
.filter(option => strength.length >= option.minLength) | ||
.sort((o1, o2) => o2.id - o1.id) | ||
.map(option => ({id: option.id, value: option.value})) | ||
Object.assign(strength, fulfilledOptions[0]) | ||
return strength; | ||
}; | ||
module.exports = { passwordStrength, defaultOptions } |
@@ -1,11 +0,21 @@ | ||
const app = require("./index"); | ||
const {passwordStrength: app, defaultOptions} = require("./index"); | ||
it("Should return strength id 2 if password is strong", () => { | ||
expect(app("Asdf12343!").id).toBe(2); | ||
it("Should not modify the password parameter", () => { | ||
let pwd = "Hello!" | ||
app(pwd) | ||
expect(pwd).toBe("Hello!") | ||
}) | ||
it("Should return strength id 3 if password is Strong", () => { | ||
expect(app("A@2asdF2020!!*!").id).toBe(3); | ||
}); | ||
it("Should return strength id 1 if password is medium", () => { | ||
expect(app("Asdfasdf2020").id).toBe(1); | ||
it("Should return strength id 2 if password is Medium", () => { | ||
expect(app("Asd1234!").id).toBe(2); | ||
}); | ||
it("Should return strength id 1 if password is Weak", () => { | ||
expect(app("asdf1234").id).toBe(1); | ||
}); | ||
it("Should return strength id 1 if password has two combination of symbol + lowercase", () => { | ||
@@ -27,25 +37,29 @@ expect(app("asdf!@#$").id).toBe(1); | ||
it("Should return strength value 'Strong' if password is strong", () => { | ||
expect(app("Asdf12343!").value).toBe("Strong"); | ||
it("Should return strength value 'Strong' if password is Medium", () => { | ||
expect(app("A@2asdF2020!!*").value).toBe("Strong"); | ||
}); | ||
it("Should return strength value 'Medium' if password is medium", () => { | ||
expect(app("Asdf1234").value).toBe("Medium"); | ||
it("Should return strength value 'Medium' if password is Medium", () => { | ||
expect(app("Asd1234!").value).toBe("Medium"); | ||
}); | ||
it("Should return strength value 'Weak' if password is Weak", () => { | ||
expect(app("Asdf1234").value).toBe("Weak"); | ||
}); | ||
// pass combination | ||
it("Should return strength value 'Medium' if password has two combination of symbol + lowercase", () => { | ||
expect(app("asdf!@#$").value).toBe("Medium"); | ||
it("Should return strength value 'Weak' if password has two combination of symbol + lowercase", () => { | ||
expect(app("asdf!@#$").value).toBe("Weak"); | ||
}); | ||
it("Should return strength value 'Medium' if password has two combination of symbol + uppercase", () => { | ||
expect(app("ASDF!@#$").value).toBe("Medium"); | ||
it("Should return strength value 'Weak' if password has two combination of symbol + uppercase", () => { | ||
expect(app("ASDF!@#$").value).toBe("Weak"); | ||
}); | ||
it("Should return strength value 'Medium' if password has two combination of symbol + numeric", () => { | ||
expect(app("1234!@#$").value).toBe("Medium"); | ||
it("Should return strength value 'Weak' if password has two combination of symbol + numeric", () => { | ||
expect(app("1234!@#$").value).toBe("Weak"); | ||
}); | ||
it("Should return strength value 'Weak' if password is weak", () => { | ||
expect(app("a").value).toBe("Weak"); | ||
it("Should return strength value 'Too weak' if password is weak", () => { | ||
expect(app("a").value).toBe("Too weak"); | ||
}); | ||
@@ -73,4 +87,4 @@ | ||
const contains = app("lower").contains; | ||
const contain = contains.find((x) => x.message === "lowercase"); | ||
const condition = contain.message === "lowercase"; | ||
const contain = contains.find((x) => x === "lowercase"); | ||
const condition = contain === "lowercase"; | ||
expect(condition).toEqual(true); | ||
@@ -81,4 +95,4 @@ }); | ||
const contains = app("Uppercase").contains; | ||
const contain = contains.find((x) => x.message === "uppercase"); | ||
const condition = contain.message === "uppercase"; | ||
const contain = contains.find((x) => x === "uppercase"); | ||
const condition = contain === "uppercase"; | ||
expect(condition).toEqual(true); | ||
@@ -89,4 +103,4 @@ }); | ||
const contains = app("!test").contains; | ||
const contain = contains.find((x) => x.message === "symbol"); | ||
const condition = contain.message === "symbol"; | ||
const contain = contains.find((x) => x === "symbol"); | ||
const condition = contain === "symbol"; | ||
expect(condition).toEqual(true); | ||
@@ -97,4 +111,4 @@ }); | ||
const contains = app("1234").contains; | ||
const contain = contains.find((x) => x.message === "number"); | ||
const condition = contain.message === "number"; | ||
const contain = contains.find((x) => x === "number"); | ||
const condition = contain === "number"; | ||
expect(condition).toEqual(true); | ||
@@ -105,6 +119,6 @@ }); | ||
expect(app("asdfASDF!@#$1234").contains).toStrictEqual([ | ||
{ message: "lowercase" }, | ||
{ message: "uppercase" }, | ||
{ message: "symbol" }, | ||
{ message: "number" }, | ||
"lowercase", | ||
"uppercase", | ||
"number", | ||
"symbol", | ||
]); | ||
@@ -115,4 +129,4 @@ }); | ||
expect(app("asdfASDF").contains).toStrictEqual([ | ||
{ message: "lowercase" }, | ||
{ message: "uppercase" }, | ||
"lowercase", | ||
"uppercase", | ||
]); | ||
@@ -134,5 +148,109 @@ }); | ||
// exception | ||
it("Should throw an exception if password parameter is empty", () => { | ||
expect(() => app(null)).toThrow("Password is empty."); | ||
it("Should return an empty password result if password parameter is null", () => { | ||
expect(app(null).id).toBe(0); | ||
expect(app(null).length).toBe(0); | ||
expect(app(null).contains).toStrictEqual([]); | ||
}); | ||
overridenOptions = [ | ||
{ | ||
id: 0, | ||
value: "Too weak", | ||
minDiversity: 0, | ||
minLength: 0 | ||
}, | ||
{ | ||
id: 1, | ||
value: "Weak", | ||
minDiversity: 2, | ||
minLength: 6 | ||
}, | ||
{ | ||
id: 2, | ||
value: "Medium", | ||
minDiversity: 3, | ||
minLength: 8 | ||
}, | ||
{ | ||
id: 3, | ||
value: "Strong", | ||
minDiversity: 4, | ||
minLength: 10 | ||
} | ||
] | ||
it("[overridden options] Should return strength id 0 if password is weak", () => { | ||
expect(app("aB1$", overridenOptions).id).toBe(0); | ||
expect(app("aB1$", overridenOptions).value).toBe("Too weak"); | ||
}); | ||
it("[overridden options] Should return strength id 1 if password is Weak", () => { | ||
expect(app("abcde123456", overridenOptions).id).toBe(1); | ||
expect(app("abcde123456", overridenOptions).value).toBe("Weak"); | ||
}); | ||
it("[overridden options] Should return strength id 2 if password is Medium", () => { | ||
expect(app("abcde123456$", overridenOptions).id).toBe(2); | ||
expect(app("abcde123456$", overridenOptions).value).toBe("Medium"); | ||
}); | ||
it("[overridden options] Should return strength id 3 if password is Strong", () => { | ||
expect(app("abcde123456$B", overridenOptions).id).toBe(3); | ||
expect(app("abcde123456$B", overridenOptions).value).toBe("Strong"); | ||
}); | ||
it("[overridden options] Should return true if request for contains is an array", () => { | ||
const arrayData = Array.isArray(app("a", overridenOptions).contains); | ||
expect(arrayData).toEqual(true); | ||
}); | ||
it("[overridden options] Should return contains of 'lowercase' if the password has lowercase", () => { | ||
const contains = app("lower", overridenOptions).contains; | ||
const contain = contains.find((x) => x === "lowercase"); | ||
const condition = contain === "lowercase"; | ||
expect(condition).toEqual(true); | ||
}); | ||
it("[overridden options] Should return contains of 'uppercase' if the password has uppercase", () => { | ||
const contains = app("Uppercase", overridenOptions).contains; | ||
const contain = contains.find((x) => x === "uppercase"); | ||
const condition = contain === "uppercase"; | ||
expect(condition).toEqual(true); | ||
}); | ||
it("[overridden options] Should return contains of 'symbol' if the password has symbol", () => { | ||
const contains = app("!test", overridenOptions).contains; | ||
const contain = contains.find((x) => x === "symbol"); | ||
const condition = contain === "symbol"; | ||
expect(condition).toEqual(true); | ||
}); | ||
it("[overridden options] Should return contains of 'number' if the password has number", () => { | ||
const contains = app("1234", overridenOptions).contains; | ||
const contain = contains.find((x) => x === "number"); | ||
const condition = contain === "number"; | ||
expect(condition).toEqual(true); | ||
}); | ||
it("[overridden options] Should return the same object with the default option", () => { | ||
expect(app("abcd@")).toStrictEqual(app('abdc@', defaultOptions)) | ||
expect(app("abcd@E")).toStrictEqual(app('abdc@E', defaultOptions)) | ||
expect(app("abcd@3")).toStrictEqual(app('abdc@3', defaultOptions)) | ||
expect(app(null)).toStrictEqual(app(null, defaultOptions)) | ||
}); | ||
it("[overridden allowedSymbols] Should not contains symbols if the password does not have one", () => { | ||
const contains = app("abcd@", undefined, '$').contains; | ||
expect(contains).toEqual(expect.arrayContaining(['lowercase'])); | ||
expect(contains).toEqual(expect.not.arrayContaining(['uppercase'])); | ||
expect(contains).toEqual(expect.not.arrayContaining(['number'])); | ||
expect(contains).toEqual(expect.not.arrayContaining(['symbol'])); | ||
}); | ||
it("[overridden allowedSymbols] Should contains symbols if the password have one", () => { | ||
const contains = app("abcd@Ê", undefined, 'Ê').contains; | ||
expect(contains).toEqual(expect.arrayContaining(['lowercase'])); | ||
expect(contains).toEqual(expect.not.arrayContaining(['uppercase'])); | ||
expect(contains).toEqual(expect.not.arrayContaining(['number'])); | ||
expect(contains).toEqual(expect.arrayContaining(['symbol'])); | ||
}); |
{ | ||
"name": "check-password-strength", | ||
"version": "1.0.15", | ||
"version": "2.0.0", | ||
"description": "A NPM Password strength checker based from Javascript RegExp. Check passphrase if it's \"Weak\", \"Medium\" or \"Strong\"", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
115
README.md
@@ -7,4 +7,6 @@ | ||
[![Build Status](https://travis-ci.org/deanilvincent/check-password-strength.svg?branch=master)](https://travis-ci.org/deanilvincent/check-password-strength) | ||
[![npm](https://img.shields.io/npm/dm/check-password-strength.svg)]() | ||
[![npm](https://img.shields.io/npm/dm/check-password-strength.svg)](https://img.shields.io/npm/dm/check-password-strength.svg) | ||
[![Downloads](https://img.shields.io/npm/dt/check-password-strength.svg)](https://img.shields.io/npm/dt/check-password-strength.svg) | ||
[DEMO here](https://check-password-strength.netlify.app/) | ||
@@ -16,2 +18,20 @@ | ||
## Migration from 1.x.x to 2.0.O | ||
``` | ||
// 1.x.x | ||
const whateEverYourFunctionNameWasBefore = require("./index"); | ||
// 'contains' attribute of the response object format was | ||
response.contains = [{'message': 'lowercase'}, ...] | ||
``` | ||
``` | ||
// 2.0.0 | ||
const { passwordStrength : whateEverYourFunctionNameWasBefore } = require("./index"); | ||
// 'contains' attribute of the response object format is now | ||
response.contains = ['lowercase', ...] | ||
``` | ||
## Setup & Basic Usage | ||
@@ -22,5 +42,8 @@ ``` | ||
console.log(passwordStrength('asdfasdf').value) | ||
// Weak (It will return weak if the value doesn't match the RegEx conditions) | ||
// Too weak (It will return Too weak if the value doesn't match the RegEx conditions) | ||
console.log(passwordStrength('Asdfasdf2020').value) | ||
console.log(passwordStrength('asdf1234').value) | ||
// Weak | ||
console.log(passwordStrength('Asd1234!').value) | ||
// Medium | ||
@@ -34,10 +57,17 @@ | ||
### Object | ||
### Object Result | ||
| Property| Desc. | | ||
| -- | -- | | ||
| id | **0** = Weak, **1** = Medium & **2** = Strong | | ||
| value | Weak, Medium & Strong | | ||
| id | **0** = Too weak, **1** = Weak & **2** = Medium, **3** = Strong | | ||
| value | Too weak, Weak, Medium & Strong | | ||
| contains | lowercase, uppercase, symbol and/or number | | ||
| length | length of the password | | ||
### Password Length Default Options | ||
| Name | Mininum Diversity | Mininum Length | | ||
| -- | -- | -- | | ||
| Too weak | 0 | 0 | | ||
| Weak | 2 | 6 | | ||
| Medium | 4 | 8 | | ||
| Strong | 4 | 10 | | ||
@@ -50,3 +80,3 @@ ``` | ||
"value": "Strong", | ||
"contains": [{'message': 'lowercase'},{'message': 'uppercase'},{'message': 'symbol'},{'message': 'number'}], | ||
"contains": ['lowercase', 'uppercase', 'symbol', 'number'], | ||
"length": 15 | ||
@@ -56,9 +86,63 @@ } | ||
### Default Options | ||
the default options can be required: | ||
``` | ||
const { defaultOptions } = require("./index"); | ||
``` | ||
default options: | ||
``` | ||
[ | ||
{ | ||
id: 0, | ||
value: "Too weak", | ||
minDiversity: 0, | ||
minLength: 0 | ||
}, | ||
{ | ||
id: 1, | ||
value: "Weak", | ||
minDiversity: 2, | ||
minLength: 6 | ||
}, | ||
{ | ||
id: 2, | ||
value: "Medium", | ||
minDiversity: 4, | ||
minLength: 8 | ||
}, | ||
{ | ||
id: 3, | ||
value: "Strong", | ||
minDiversity: 4, | ||
minLength: 10 | ||
} | ||
] | ||
``` | ||
To override the default options, simply pass your custom array as the second argument: | ||
- id: correspond to the return id attribute. | ||
- value: correspond to the return value attribute. | ||
- minDiversity: between 0 and 4, correspond to the minimum of different criterias ('lowercase', 'uppercase', 'symbol', 'number') that should be met to pass the password strength | ||
- minLength: minimum length of the password that should be met to pass the password strength | ||
The minDiversity and minLength parameters of the first element cannot be overriden (set to 0 at the beginning of the method). Therefore, the first element should always correspond to a "too weak" option. | ||
``` | ||
passwordStrength('myPassword', yourCustomOptions) | ||
``` | ||
### RegEx | ||
**Strong Password RegEx used:** | ||
**Strong** | ||
`^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{10,})` | ||
**Medium Password RegEx used:** | ||
`^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})` | ||
**Medium Password RegEx used:** | ||
**Weak Password RegEx used:** | ||
@@ -71,7 +155,8 @@ `^((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[!@#\$%\^&\*])|((?=.*[a-z])(?=.*[!@#\$%\^&\*])|((?=.*[0-9])(?=.*[!@#\$%\^&\*]))(?=.{6,})"` | ||
| (?=.*[a-z]) | The string must contain at least 1 lowercase alphabetical character | | ||
|(?=.*[A-Z]) | The string must contain at least 1 uppercase alphabetical character | ||
|(?=.*[0-9]) | The string must contain at least 1 numeric character | ||
|(?=._[!@#\$%\^&_]) | The string must contain at least one special character, but we are escaping reserved RegEx characters to avoid conflict | ||
| (?=.{8,}) | The string must be eight characters or longer for strong strength | ||
| (?=.{6,}) | Mininum of 6 characters for medium strength | ||
|(?=.*[A-Z]) | The string must contain at least 1 uppercase alphabetical character | | ||
|(?=.*[0-9]) | The string must contain at least 1 numeric character | | ||
|(?=._[!@#\$%\^&_]) | The string must contain at least one special character, but we are escaping reserved RegEx characters to avoid conflict | | ||
| (?=.{10,}) | The string must be eight characters or longer for Strong strength | | ||
| (?=.{8,}) | The string must be eight characters or longer for Medium strength | | ||
| (?=.{6,}) | Mininum of 6 characters for Weak strength | | ||
@@ -98,3 +183,5 @@ ## Other resources | ||
*** | ||
Kudos to [@Ennoriel](https://github.com/Ennoriel) and his efforts for making v2.0.0 possible! | ||
### License | ||
This project is licensed under the MIT License - see the [LICENSE.md](https://github.com/deanilvincent/check-password-strength/blob/master/LICENSE.md/) file for details. |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
18756
269
180
1