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.js b/example/index.js index fc1ce9c..3a48e8b 100644 --- a/example/index.js +++ b/example/index.js @@ -28,6 +28,8 @@ class App extends React.Component { this.ReactPasswordStrength = ref} minLength={6} + maxLength={10} + tooLongWord="woah there" inputProps={inputProps} changeCallback={this.changeCallback} /> @@ -40,7 +42,8 @@ class App extends React.Component { 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();