Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V3 - allow all symbols by default, set the default min length to 12 instead of 10, fix license filename (fix #78) #81

Merged
merged 8 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
116 changes: 38 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# Overview

A simple way to check that password strength of a certain passphrase. A password strength checker based from [Javascript RegEx](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions).
A simple way to check that password strength of a certain passphrase. The library is fully typed.

[![Build status](https://dev.azure.com/dv-github-repos/check-password-strength/_apis/build/status/check-password-strength-CI)](https://dev.azure.com/dv-github-repos/check-password-strength/_build/latest?definitionId=12)

Expand All @@ -20,13 +20,14 @@ A simple way to check that password strength of a certain passphrase. A password
### Install via Browser Script Tag using [UNPKG](https://unpkg.com/)

```html
<script src="https://unpkg.com/check-password-strength/dist/umd.js"></script>
<script src="https://unpkg.com/check-password-strength/dist/umd.cjs"></script>
<script type="text/javascript">
const passwordStrength = checkPasswordStrength.passwordStrength('pwd123').value; // 'Weak'
</script>
```

## Setup & Basic Usage

```javascript
const { passwordStrength } = require('check-password-strength')
// OR
Expand All @@ -45,46 +46,27 @@ console.log(passwordStrength('A@2asdF2020!!*').value)
// Strong
```

## Additional Info
## API

### Object Result
| Property | Desc. |
| -------- | --------------------------------------------------------------- |
| 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 |
### arguments

### Password Length Default Options
| Name | Mininum Diversity | Mininum Length |
| -------- | ----------------- | -------------- |
| Too weak | 0 | 0 |
| Weak | 2 | 6 |
| Medium | 4 | 8 |
| Strong | 4 | 10 |
The `passwordStrength` takes 3 arguments:

```javascript
console.log(passwordStrength('@Sdfasd2020!@#$'))
// output
{
"id": 1,
"value": "Strong",
"contains": ['lowercase', 'uppercase', 'symbol', 'number'],
"length": 15
}
```
- `password` (string): the user password
- `options` (array — optional): an option to override the default complexity required to match your password policy. See below.
- `restrictSymbolsTo` (string — optional):
- By default, the `passwordStrength` function checks against all characters except for the 26 Latin lowercase letters, 26 uppercase letters, and 10 digits. This includes OWASP-recommended characters, accented letters, other alphabets, and emojis.
- If you wish to apply restrictions, you can provide a custom string. This string should consist of unescaped symbol characters, which will be utilized internally in a RegExp expression in the following format: `[${escapeStringRegexp(restrictSymbolsTo)}]`.
- Additionally, you can import and use the owaspSymbols to limit the symbols to those recommended by OWASP.

### Default Options

The default symbols are based from **Password Special Characters [OWASP](https://owasp.org/www-community/password-special-characters)** list (except for the space)
```
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
```
Thanks for [jlherren](https://github.com/jlherren) & [Ennoriel](https://github.com/Ennoriel) for this suggestion! 👨🏻‍💻👨🏻‍💻
**Password Default Options**

The default options can be required:

```javascript
const { defaultOptions } = require("./index");
// OR
import { defaultOptions } from 'check-password-strength'
```

default options:
Expand All @@ -100,19 +82,19 @@ default options:
id: 1,
value: "Weak",
minDiversity: 2,
minLength: 6
minLength: 8
},
{
id: 2,
value: "Medium",
minDiversity: 4,
minLength: 8
minLength: 10
},
{
id: 3,
value: "Strong",
minDiversity: 4,
minLength: 10
minLength: 12
}
]
```
Expand All @@ -124,57 +106,35 @@ To override the default options, simply pass your custom array as the second arg
- 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.
**You can use an array containing fewer or more than four items to define the levels of trust.** However, the first element must have both the minDiversity and minLength parameters set to 0. This means that the first element should always represent a "too weak" option.

```javascript
passwordStrength('myPassword', yourCustomOptions)
```
### RegEx
**Strong**
```
^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*"'()+,-./:;<=>?[\]^_`{|}~])(?=.{10,})
```

**Medium Password RegEx used:**
```
^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*"'()+,-./:;<=>?[\]^_`{|}~])(?=.{8,})
```

| RegEx | Desc. |
| ----------------------------------------- | ------------------------------------------------------------------- |
| ^ | The password string will start this way |
| (?=.*[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 |
| (?=.{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 |

## TypeScript type declarations &#9745;
Available starting version `v2.0.3` and above. (Thanks to [@Mesoptier!](https://github.com/Mesoptier))

## Other resources

##### For .NET Project
If you're working with .net core project, I've created a simple nuget package with same RegEx strings to validate a password strength.
### Result

You can easily install via Nuget Package Manager or .NET CLI ([Check.Password.Strength](https://github.com/deanilvincent/Check.Password.Strength)). This package uses Regular Expression `new Regex()` derives from `System.Text.RegularExpressions`. You can use this especially if you want to validate the passcode strength on backend services or web apis of your project.
The result is an object containing the following values (unless you override the `options`):

##### Other NPM RegEx validator
I also made another NPM package ([hey-regex](https://www.npmjs.com/package/hey-regex)) that checks common inputs like numbers (whole number and decimal), alpha numeric, email and url. This package only returns `true` or `false` based from the selected function (with RegEx `.test()` inside).
| Property | Desc. |
| -------- | --------------------------------------------------------------- |
| id | **0** = Too weak, **1** = Weak & **2** = Medium, **3** = Strong |
| value | Too weak, Weak, Medium & Strong |
| contains | lowercase, uppercase, number and / or symbol |
| length | length of the password |

Reference [blog](https://www.thepolyglotdeveloper.com/2015/05/use-regex-to-test-password-strength-in-javascript/).
If you want to translate the value (Too weak → Trop faible), you can translate it based on the return value, or override the `defaultOptions` option, which will be passed back as the function's return value.

### Contribute
## Contribute

Feel free to clone or fork this project: `https://github.com/deanilvincent/check-password-strength.git`

Contributions & pull requests are welcome!

I'll be glad if you give this project a ★ on [Github](https://github.com/deanilvincent/check-password-strength) :)

## changelog

- v3: allow all symbols by default (any character except the 26 latin lowercase, uppercase letters and 10 digits) & set the default min length to 12 instead of 10
- v2: allow configuration through `options` object
- v1: first version

***
Kudos to [@Ennoriel](https://github.com/Ennoriel) and his efforts for making v2.x.x 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.

Kudos to [@Ennoriel](https://github.com/Ennoriel) and his efforts for making v2 and v3 possible!
4 changes: 3 additions & 1 deletion dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export type Options<V> = [FirstOption<V>, ...Option<V>[]];

export const defaultOptions: Options<string>;

export const owaspSymbols: string;

export type DiversityType = "lowercase" | "uppercase" | "symbol" | "number";

export interface Result<V> {
Expand All @@ -26,5 +28,5 @@ export interface Result<V> {
export function passwordStrength<V = string>(
password: string,
options?: Options<V>,
allowedSymbols?: string,
restrictSymbolsTo?: string | undefined,
): Result<V>;
90 changes: 56 additions & 34 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,100 @@
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

Check warning

Code scanning / Jshint (reported by Codacy)

'exports' is not defined. Warning

'exports' is not defined.

function escapeStringRegexp(string) {
if (typeof string !== 'string') {
throw new TypeError('Expected a string');
}

// Escape characters with special meaning either inside or outside character sets.
// Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
return string
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
.replace(/-/g, '\\x2d');
}

const defaultOptions = [
{
id: 0,
value: "Too weak",
minDiversity: 0,
minLength: 0
minLength: 0,
},
{
id: 1,
value: "Weak",
minDiversity: 2,
minLength: 6
minLength: 8,
},
{
id: 2,
value: "Medium",
minDiversity: 4,
minLength: 8
minLength: 10,
},
{
id: 3,
value: "Strong",
minDiversity: 4,
minLength: 10
}
]
minLength: 12,
},
];

const passwordStrength = (password, options = defaultOptions, allowedSymbols = "!\"#\$%&'\(\)\*\+,-\./:;<=>\?@\[\\\\\\]\^_`\{|\}~") => {
const owaspSymbols = "!\"#$%&'()*+,-./\\:;<=>?@[]^_`{|}~";

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

let passwordCopy = password || ''
const passwordStrength = (

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
password,
options = defaultOptions,
restrictSymbolsTo
) => {
options[0].minDiversity = 0;
options[0].minLength = 0;

options[0].minDiversity = 0,
options[0].minLength = 0
// prevent [a-z] to match null and compute length
const _password = password ?? "";

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

Check warning

Code scanning / Jshint (reported by Codacy)

Requires each line to end in a semicolon Warning

Missing semicolon.

const rules = [
{
key: "lowercase",
regex: "[a-z]",
message: 'lowercase'
},
{
regex: '[A-Z]',
message: 'uppercase'
key: "uppercase",
regex: "[A-Z]",
},
{
regex: '[0-9]',
message: 'number'
key: "number",
regex: "[0-9]",
},
]

if (allowedSymbols) {
rules.push({
regex: `[${allowedSymbols}]`,
message: 'symbol'
})
}
{
key: "symbol",
regex: restrictSymbolsTo ? `[${escapeStringRegexp(restrictSymbolsTo)}]` : "[^a-zA-Z0-9]",
},
];

let strength = {}
let strength = {};

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

strength.contains = rules
.filter(rule => new RegExp(`${rule.regex}`).test(passwordCopy))
.map(rule => rule.message)
.filter((rule) => new RegExp(`${rule.regex}`).test(_password))
.map((rule) => rule.key);

strength.length = passwordCopy.length;
strength.length = _password.length;

let fulfilledOptions = options
.filter(option => strength.contains.length >= option.minDiversity)
.filter(option => strength.length >= option.minLength)
.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 }))
.map((option) => ({ id: option.id, value: option.value }));

Object.assign(strength, fulfilledOptions[0])
Object.assign(strength, fulfilledOptions[0]);

return strength;
};

module.exports = { passwordStrength, defaultOptions }
module.exports.passwordStrength = passwordStrength
module.exports.defaultOptions = defaultOptions
var index = { passwordStrength, defaultOptions, owaspSymbols };

Check notice

Code scanning / Jshint (reported by Codacy)

Prohibits the use of __iterator__ property due to compatibility issues Note

'object short notation' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

exports.default = index;

Check warning

Code scanning / Jshint (reported by Codacy)

'exports' is not defined. Warning

'exports' is not defined.
exports.defaultOptions = defaultOptions;

Check warning

Code scanning / Jshint (reported by Codacy)

'exports' is not defined. Warning

'exports' is not defined.
exports.owaspSymbols = owaspSymbols;

Check warning

Code scanning / Jshint (reported by Codacy)

'exports' is not defined. Warning

'exports' is not defined.
exports.passwordStrength = passwordStrength;

Check warning

Code scanning / Jshint (reported by Codacy)

'exports' is not defined. Warning

'exports' is not defined.
Loading
Loading