Skip to content
This repository has been archived by the owner on Apr 10, 2024. It is now read-only.

Commit

Permalink
implement password too long check
Browse files Browse the repository at this point in the history
  • Loading branch information
Mateusz Wijas committed Oct 30, 2018
1 parent 7727f5c commit 27b27ad
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 9 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
5 changes: 4 additions & 1 deletion example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class App extends React.Component {
<ReactPasswordStrength
ref={ref => this.ReactPasswordStrength = ref}
minLength={6}
maxLength={10}
tooLongWord="woah there"
inputProps={inputProps}
changeCallback={this.changeCallback}
/>
Expand All @@ -40,7 +42,8 @@ class App extends React.Component {

<ReactPasswordStrength
minLength={6}
inputProps={inputProps}
maxLength={10}
inputProps={{ ...inputProps, id: "inputPassword2" }}
defaultValue="defaultValue"
/>
</div>
Expand Down
23 changes: 15 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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,
Expand All @@ -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: [],
}
Expand Down Expand Up @@ -64,21 +68,21 @@ 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;
let result = null;

// 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,
}, () => {
Expand All @@ -93,10 +97,12 @@ export default class ReactPasswordStrength extends Component {
const {
className,
inputProps,
maxLength,
minLength,
namespaceClassName,
scoreWords,
style,
tooLongWord,
tooShortWord,
} = this.props;

Expand All @@ -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');
Expand All @@ -126,6 +132,7 @@ export default class ReactPasswordStrength extends Component {
<div className={wrapperClasses.join(' ')} style={style}>
<input
type="password"
maxLength={maxLength}
{...inputProps}
className={inputClasses.join(' ')}
onChange={this.handleChange}
Expand Down
14 changes: 14 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,20 @@ describe('ReactPasswordStrength Events', () => {
expect(result.state.isValid).toBe(false);
})

it('invalidates too long passwords', () => {
const result = renderIntoDocument(<PassStrength maxLength={9} />);
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(<PassStrength minScore={2} userInputs={[knownKeyword]} />);
Expand Down

0 comments on commit 27b27ad

Please sign in to comment.