diff --git a/README.md b/README.md
index b72b6b5..1b22781 100644
--- a/README.md
+++ b/README.md
@@ -56,6 +56,11 @@ Using in a __Universal JS App__ (server-side rendering):
- Minimum password length acceptable for password to be considered valid
+#### maxLength (Default: 1000)
+
+- Maximum password length acceptable for password to be considered valid
+- Used to prevent DDOS attacks with exceptionally long passwords meant to overload servers with work.
+
#### minScore (Default: 2)
- Minimum score acceptable for password to be considered valid
@@ -70,6 +75,10 @@ Using in a __Universal JS App__ (server-side rendering):
- A string to describe when password is too short (based on minLength prop).
+#### tooLongWord (Default: 'too long')
+
+- A string to describe when password is too long (based on maxLength prop).
+
#### changeCallback
- Callback after input has changed (and score was recomputed)
diff --git a/example/index.html b/example/index.html
new file mode 100644
index 0000000..136e531
--- /dev/null
+++ b/example/index.html
@@ -0,0 +1,53 @@
+
+
+
+
+ React Password Strength Example
+
+
+
+
+
+
+
+
+
diff --git a/example/index.js b/example/index.js
new file mode 100644
index 0000000..3a48e8b
--- /dev/null
+++ b/example/index.js
@@ -0,0 +1,54 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import ReactPasswordStrength from "../dist/index";
+
+class App extends React.Component {
+ state = {
+ passLength: 0,
+ }
+
+ changeCallback = state =>
+ this.setState({ passLength: state.password.length })
+
+ clear = () => this.ReactPasswordStrength.clear()
+
+ render() {
+ const inputProps = {
+ placeholder: "Try a password...",
+ id: "inputPassword",
+ autoFocus: true,
+ className: 'another-input-prop-class-name',
+ };
+
+ return (
+
+
React Password Strength Tool
+
Powered by zxcvbn
+
+
this.ReactPasswordStrength = ref}
+ minLength={6}
+ maxLength={10}
+ tooLongWord="woah there"
+ inputProps={inputProps}
+ changeCallback={this.changeCallback}
+ />
+
+
+ Clear
+
+
+ Password Input with Default Value for password
+
+
+
+ );
+ }
+}
+
+ReactDOM.render( , document.getElementById("example"));
diff --git a/src/index.js b/src/index.js
index 7140d4b..a528774 100644
--- a/src/index.js
+++ b/src/index.js
@@ -5,6 +5,7 @@ import zxcvbn from 'zxcvbn';
import PropTypes from 'prop-types';
const isTooShort = (password, minLength) => password.length < minLength;
+const isTooLong = (password, maxLength) => password.length > maxLength;
export default class ReactPasswordStrength extends Component {
static propTypes = {
@@ -13,6 +14,7 @@ export default class ReactPasswordStrength extends Component {
defaultValue: PropTypes.string,
inputProps: PropTypes.object,
minLength: PropTypes.number,
+ maxLength: PropTypes.number,
minScore: PropTypes.number,
namespaceClassName: PropTypes.string,
scoreWords: PropTypes.array,
@@ -25,10 +27,12 @@ export default class ReactPasswordStrength extends Component {
changeCallback: null,
className: '',
defaultValue: '',
+ maxLength: 1000,
minLength: 5,
minScore: 2,
namespaceClassName: 'ReactPasswordStrength',
scoreWords: ['weak', 'weak', 'okay', 'good', 'strong'],
+ tooLongWord: 'too long',
tooShortWord: 'too short',
userInputs: [],
}
@@ -64,7 +68,7 @@ export default class ReactPasswordStrength extends Component {
}
handleChange = () => {
- const { changeCallback, minScore, userInputs, minLength } = this.props;
+ const { changeCallback, minScore, userInputs, minLength, maxLength } = this.props;
const password = this.reactPasswordStrengthInput.value;
let score = 0;
@@ -72,13 +76,13 @@ export default class ReactPasswordStrength extends Component {
// always sets a zero score when min length requirement is not met
// avoids unnecessary zxcvbn computations (CPU intensive)
- if (isTooShort(password, minLength) === false) {
+ if (isTooShort(password, minLength) === false && isTooLong(password, maxLength) === false) {
result = zxcvbn(password, userInputs);
score = result.score;
}
this.setState({
- isValid: score >= minScore,
+ isValid: score >= minScore && !isTooLong(password, maxLength),
password,
score,
}, () => {
@@ -93,10 +97,12 @@ export default class ReactPasswordStrength extends Component {
const {
className,
inputProps,
+ maxLength,
minLength,
namespaceClassName,
scoreWords,
style,
+ tooLongWord,
tooShortWord,
} = this.props;
@@ -106,11 +112,11 @@ export default class ReactPasswordStrength extends Component {
className ? className : '',
password.length > 0 ? `is-strength-${score}` : '',
];
- const strengthDesc = (
- isTooShort(password, minLength)
- ? tooShortWord
- : scoreWords[score]
- );
+
+ let strengthDesc = scoreWords[score];
+
+ if (isTooShort(password, minLength)) strengthDesc = tooShortWord;
+ if (isTooLong(password, maxLength)) strengthDesc = tooLongWord;
if (isValid === true) {
inputClasses.push('is-password-valid');
diff --git a/test/index.js b/test/index.js
index 6aa360f..c3e7228 100644
--- a/test/index.js
+++ b/test/index.js
@@ -143,6 +143,20 @@ describe('ReactPasswordStrength Events', () => {
expect(result.state.isValid).toBe(false);
})
+ it('invalidates too long passwords', () => {
+ const result = renderIntoDocument( );
+ let input = findRenderedDOMComponentWithClass(result, 'ReactPasswordStrength-input');
+
+ // this normally passes but must fail because it exceeds the max length
+ input.value = '4mf2df32df52df3';
+
+ Simulate.change(input);
+
+ expect(result.state.password).toBe('4mf2df32df52df3');
+ expect(result.state.score).toBe(0);
+ expect(result.state.isValid).toBe(false);
+ })
+
it('adds strings in userInputs to zxcvbn dictionary', () => {
const knownKeyword = 'longwordthatiscommon';
const result = renderIntoDocument( );