react-password-strength
Advanced tools
+13
-9
@@ -13,3 +13,6 @@ // Karma configuration | ||
| basePath: '', | ||
| files: ['test/*.js'], | ||
| files: [ | ||
| 'node_modules/es6-shim/es6-shim.js', | ||
| 'test/*.js', | ||
| ], | ||
| exclude: [], | ||
@@ -25,17 +28,18 @@ | ||
| webpack: { | ||
| entry: './src/index.js', | ||
| module: { | ||
| loaders: [ | ||
| rules: [ | ||
| { | ||
| test: /\.js$/, | ||
| include: [/src/, /test/], | ||
| loader: 'babel', | ||
| loader: 'babel-loader', | ||
| query: { | ||
| presets: ['es2015', 'react'] | ||
| } | ||
| presets: ['react', 'es2015', 'stage-2'], | ||
| }, | ||
| }, { | ||
| test: /\.css$/, | ||
| loader: "style-loader!css-loader" | ||
| } | ||
| ] | ||
| } | ||
| use: ["style-loader", "css-loader"], | ||
| }, | ||
| ], | ||
| }, | ||
| }, | ||
@@ -42,0 +46,0 @@ webpackMiddleware: { |
+21
-16
| { | ||
| "name": "react-password-strength", | ||
| "version": "2.2.0", | ||
| "version": "2.3.0", | ||
| "engines": { | ||
| "node": "6.11.1" | ||
| }, | ||
| "description": "A password strength indicator field for use in React projects", | ||
| "main": "dist/index.js", | ||
| "scripts": { | ||
| "build-watch": "./node_modules/.bin/webpack --config=webpack.build.config.js --watch", | ||
| "build-module": "./node_modules/.bin/webpack --config=webpack.build.config.js", | ||
| "build-prod": "npm run build-module -p & npm run build-universal-module -p", | ||
| "build-universal-module": "./node_modules/.bin/webpack --config=webpack.universal.config.js", | ||
| "build-watch": "./node_modules/.bin/webpack --config=webpack.build.config.js --watch", | ||
| "example-build": "./node_modules/.bin/webpack --config=webpack.config.js", | ||
| "example-publish": "git subtree push --prefix example origin gh-pages", | ||
| "example": "./node_modules/.bin/webpack-dev-server --content-base example/", | ||
| "prepublish": "npm run build-module -p & npm run build-universal-module -p", | ||
| "start": "npm run example & npm run build-watch", | ||
@@ -35,24 +38,26 @@ "test": "./node_modules/karma/bin/karma start" | ||
| "babel-preset-react": "^6.11.1", | ||
| "babel-preset-stage-2": "^6.24.1", | ||
| "css-loader": "^0.23.1", | ||
| "extract-text-webpack-plugin": "^1.0.1", | ||
| "jasmine": "^2.5.2", | ||
| "karma": "^1.3.0", | ||
| "es6-shim": "^0.35.3", | ||
| "extract-text-webpack-plugin": "^3.0.2", | ||
| "jasmine": "^2.8.0", | ||
| "karma": "^1.7.1", | ||
| "karma-jasmine": "^1.1.0", | ||
| "karma-phantomjs-launcher": "^1.0.2", | ||
| "karma-spec-reporter": "0.0.26", | ||
| "karma-webpack": "^1.8.0", | ||
| "react": "^15.5.0", | ||
| "react-addons-test-utils": "^15.4.1", | ||
| "react-dom": "^15.5.0", | ||
| "karma-phantomjs-launcher": "^1.0.4", | ||
| "karma-spec-reporter": "0.0.31", | ||
| "karma-webpack": "^2.0.6", | ||
| "react": "^16.1.1", | ||
| "react-dom": "^16.1.1", | ||
| "style-loader": "^0.13.1", | ||
| "webpack": "^1.13.1", | ||
| "webpack-dev-server": "^1.14.1" | ||
| "webpack": "^3.8.1", | ||
| "webpack-dev-server": "^2.9.4" | ||
| }, | ||
| "peerDependencies": { | ||
| "react-dom": "^15.5.0" | ||
| "react": "^16.0.0", | ||
| "react-dom": "^16.0.0" | ||
| }, | ||
| "dependencies": { | ||
| "prop-types": "^15.5.10", | ||
| "prop-types": "^15.6.0", | ||
| "zxcvbn": "^4.3.0" | ||
| } | ||
| } |
+4
-0
@@ -89,2 +89,6 @@ # React Password Strength  | ||
| #### defaultValue | ||
| - A default value to set for the password field. If a non-empty string is provided the `changeCallback` will be called in `componentDidMount`. | ||
| #### userInputs | ||
@@ -91,0 +95,0 @@ |
+60
-60
@@ -1,17 +0,49 @@ | ||
| import React from 'react'; | ||
| import './style.css'; | ||
| import React, { Component } from 'react'; | ||
| import zxcvbn from 'zxcvbn'; | ||
| import PropTypes from 'prop-types'; | ||
| export default class ReactPasswordStrength extends React.Component { | ||
| constructor() { | ||
| super(); | ||
| const isTooShort = (password, minLength) => password.length < minLength; | ||
| this.state = { | ||
| score: 0, | ||
| isValid: false, | ||
| password: '', | ||
| }; | ||
| export default class ReactPasswordStrength extends Component { | ||
| static propTypes = { | ||
| changeCallback: PropTypes.func, | ||
| className: PropTypes.string, | ||
| defaultValue: PropTypes.string, | ||
| inputProps: PropTypes.object, | ||
| minLength: PropTypes.number, | ||
| minScore: PropTypes.number, | ||
| scoreWords: PropTypes.array, | ||
| style: PropTypes.object, | ||
| tooShortWord: PropTypes.string, | ||
| userInputs: PropTypes.array, | ||
| } | ||
| clear() { | ||
| static defaultProps = { | ||
| changeCallback: null, | ||
| className: '', | ||
| defaultValue: '', | ||
| minLength: 5, | ||
| minScore: 2, | ||
| scoreWords: ['weak', 'weak', 'okay', 'good', 'strong'], | ||
| tooShortWord: 'too short', | ||
| userInputs: [], | ||
| } | ||
| state = { | ||
| score: 0, | ||
| isValid: false, | ||
| password: '', | ||
| } | ||
| componentDidMount() { | ||
| const { defaultValue } = this.props; | ||
| if (defaultValue.length > 0) { | ||
| this.setState({ password: defaultValue }, this.handleChange); | ||
| } | ||
| } | ||
| clear = () => { | ||
| const { changeCallback } = this.props; | ||
@@ -24,3 +56,3 @@ | ||
| }, () => { | ||
| this.refs['ReactPasswordStrength-input'].value = ''; | ||
| this.reactPasswordStrengthInput.value = ''; | ||
@@ -33,10 +65,6 @@ if (changeCallback !== null) { | ||
| isTooShort(password) { | ||
| return password.length < this.props.minLength; | ||
| } | ||
| handleChange = () => { | ||
| const { changeCallback, minScore, userInputs, minLength } = this.props; | ||
| const password = this.reactPasswordStrengthInput.value; | ||
| handleChange(e) { | ||
| const { changeCallback, minScore, userInputs } = this.props; | ||
| const password = this.refs['ReactPasswordStrength-input'].value; | ||
| let score = 0; | ||
@@ -46,4 +74,4 @@ let result = null; | ||
| // always sets a zero score when min length requirement is not met | ||
| // which avoids unnecessary zxcvbn computations (they require quite lots of CPU) | ||
| if (!this.isTooShort(password)) { | ||
| // avoids unnecessary zxcvbn computations (CPU intensive) | ||
| if (isTooShort(password, minLength) === false) { | ||
| result = zxcvbn(password, userInputs); | ||
@@ -57,3 +85,3 @@ score = result.score; | ||
| score, | ||
| }, function() { | ||
| }, () => { | ||
| if (changeCallback !== null) { | ||
@@ -66,6 +94,3 @@ changeCallback(this.state, result); | ||
| render() { | ||
| require('./style.css'); | ||
| const { score, password, isValid } = this.state; | ||
| const { | ||
@@ -76,13 +101,18 @@ scoreWords, | ||
| style, | ||
| tooShortWord | ||
| tooShortWord, | ||
| minLength, | ||
| } = this.props; | ||
| const inputClasses = [ 'ReactPasswordStrength-input' ]; | ||
| const wrapperClasses = [ | ||
| 'ReactPasswordStrength', | ||
| className ? className : '', | ||
| password.length > 0 ? `is-strength-${score}` : '' | ||
| password.length > 0 ? `is-strength-${score}` : '', | ||
| ]; | ||
| const strengthDesc = ( | ||
| isTooShort(password, minLength) | ||
| ? tooShortWord | ||
| : scoreWords[score] | ||
| ); | ||
| const inputClasses = [ 'ReactPasswordStrength-input' ]; | ||
| if (isValid === true) { | ||
@@ -98,10 +128,2 @@ inputClasses.push('is-password-valid'); | ||
| let strengthDesc; | ||
| if (this.isTooShort(password)) { | ||
| strengthDesc = tooShortWord; | ||
| } else { | ||
| strengthDesc = scoreWords[score]; | ||
| } | ||
| return ( | ||
@@ -113,4 +135,4 @@ <div className={wrapperClasses.join(' ')} style={style}> | ||
| className={inputClasses.join(' ')} | ||
| onChange={this.handleChange.bind(this)} | ||
| ref="ReactPasswordStrength-input" | ||
| onChange={this.handleChange} | ||
| ref={ref => this.reactPasswordStrengthInput = ref} | ||
| value={password} | ||
@@ -125,23 +147,1 @@ /> | ||
| } | ||
| ReactPasswordStrength.propTypes = { | ||
| changeCallback: PropTypes.func, | ||
| className: PropTypes.string, | ||
| inputProps: PropTypes.object, | ||
| minLength: PropTypes.number, | ||
| minScore: PropTypes.number, | ||
| scoreWords: PropTypes.array, | ||
| tooShortWord: PropTypes.string, | ||
| style: PropTypes.object, | ||
| userInputs: PropTypes.array, | ||
| }; | ||
| ReactPasswordStrength.defaultProps = { | ||
| changeCallback: null, | ||
| className: '', | ||
| minLength: 5, | ||
| minScore: 2, | ||
| scoreWords: ['weak', 'weak', 'okay', 'good', 'strong'], | ||
| tooShortWord: 'too short', | ||
| userInputs: [], | ||
| }; |
+19
-23
| import React from 'react'; | ||
| import { | ||
| createRenderer, | ||
| findRenderedDOMComponentWithClass, | ||
| findRenderedDOMComponentWithTag, | ||
| renderIntoDocument, | ||
@@ -12,14 +12,11 @@ Simulate, | ||
| describe('ReactPasswordStrength', () => { | ||
| const renderer = createRenderer(); | ||
| it('is rendered', () => { | ||
| renderer.render(<PassStrength />); | ||
| const result = renderer.getRenderOutput(); | ||
| const { children } = result.props; | ||
| const render = renderIntoDocument(<PassStrength />); | ||
| const result = findRenderedDOMComponentWithClass(render, 'ReactPasswordStrength'); | ||
| const strengthBar = findRenderedDOMComponentWithClass(render, 'ReactPasswordStrength-strength-bar'); | ||
| const description = findRenderedDOMComponentWithClass(render, 'ReactPasswordStrength-strength-desc'); | ||
| expect(result.type).toBe('div'); | ||
| expect(children[0].type).toBe('input'); | ||
| expect(children[1].props.className).toBe('ReactPasswordStrength-strength-bar'); | ||
| expect(children[2].props.className).toBe('ReactPasswordStrength-strength-desc'); | ||
| expect(result).toBeDefined(); | ||
| expect(strengthBar.className).toBe('ReactPasswordStrength-strength-bar'); | ||
| expect(description.className).toBe('ReactPasswordStrength-strength-desc'); | ||
| }); | ||
@@ -33,23 +30,22 @@ | ||
| renderer.render(<PassStrength inputProps={inputProps} />); | ||
| const result = renderer.getRenderOutput(); | ||
| const { children } = result.props; | ||
| const render = renderIntoDocument(<PassStrength inputProps={inputProps} />); | ||
| const input = findRenderedDOMComponentWithTag(render, 'input'); | ||
| expect(children[0].props.className).toBe('ReactPasswordStrength-input test'); | ||
| expect(children[0].props.value).not.toBe('value-test'); | ||
| expect(input.className).toBe('ReactPasswordStrength-input test'); | ||
| expect(input.value).not.toBe('value-test'); | ||
| }); | ||
| it('accepts className prop', () => { | ||
| renderer.render(<PassStrength className="testClassName" />); | ||
| const result = renderer.getRenderOutput(); | ||
| const render = renderIntoDocument(<PassStrength className="testClassName" />); | ||
| const result = findRenderedDOMComponentWithClass(render, 'ReactPasswordStrength'); | ||
| expect(result.props.className).toContain("testClassName"); | ||
| expect(result.props.className).toContain("ReactPasswordStrength"); | ||
| expect(result.className).toContain("testClassName"); | ||
| expect(result.className).toContain("ReactPasswordStrength"); | ||
| }); | ||
| it('accepts style prop', () => { | ||
| renderer.render(<PassStrength style={{ margin: "10px" }} />); | ||
| const result = renderer.getRenderOutput(); | ||
| const render = renderIntoDocument(<PassStrength style={{ margin: "10px" }} />); | ||
| const result = findRenderedDOMComponentWithClass(render, 'ReactPasswordStrength'); | ||
| expect(result.props.style.margin).toBe("10px"); | ||
| expect(result.style.margin).toBe("10px"); | ||
| }); | ||
@@ -56,0 +52,0 @@ }); |
+13
-10
@@ -7,22 +7,25 @@ module.exports = { | ||
| libraryTarget: 'umd', | ||
| library: 'ReactPasswordStrength' | ||
| library: 'ReactPasswordStrength', | ||
| }, | ||
| module: { | ||
| loaders: [ | ||
| rules: [ | ||
| { | ||
| test: /\.js$/, | ||
| loader: 'babel-loader', | ||
| include: /src/, | ||
| loader: 'babel', | ||
| query: { | ||
| presets: ['es2015', 'react'] | ||
| } | ||
| presets: ['react', 'es2015', 'stage-2'], | ||
| }, | ||
| }, { | ||
| test: /\.css$/, | ||
| loader: 'style-loader!css-loader', | ||
| } | ||
| ] | ||
| use: [ 'style-loader', 'css-loader' ], | ||
| }, | ||
| ], | ||
| }, | ||
| externals: { | ||
| 'react': 'react' | ||
| } | ||
| } | ||
| }, | ||
| resolve: { | ||
| extensions: ['.js'], | ||
| }, | ||
| }; |
@@ -5,17 +5,17 @@ module.exports = { | ||
| filename: 'bundle.js', | ||
| path: __dirname + '/example' | ||
| path: __dirname + '/example', | ||
| }, | ||
| module: { | ||
| loaders: [{ | ||
| rules: [{ | ||
| test: /\.js$/, | ||
| include: [/example/, /dist/], | ||
| loader: 'babel', | ||
| loader: 'babel-loader', | ||
| include: /example/, | ||
| query: { | ||
| presets: ['es2015', 'react'] | ||
| } | ||
| }] | ||
| presets: ['react', 'es2015', 'stage-2'], | ||
| }, | ||
| }], | ||
| }, | ||
| resolve: { | ||
| extensions: ['', '.js'] | ||
| } | ||
| extensions: ['.js'], | ||
| }, | ||
| } |
@@ -9,18 +9,21 @@ var ExtractTextPlugin = require('extract-text-webpack-plugin'); | ||
| libraryTarget: 'umd', | ||
| library: 'ReactPasswordStrength' | ||
| library: 'ReactPasswordStrength', | ||
| }, | ||
| module: { | ||
| loaders: [ | ||
| rules: [ | ||
| { | ||
| test: /\.js$/, | ||
| include: /src/, | ||
| loader: 'babel', | ||
| loader: 'babel-loader', | ||
| query: { | ||
| presets: ['es2015', 'react'] | ||
| } | ||
| presets: ['react', 'es2015', 'stage-2'], | ||
| }, | ||
| }, { | ||
| test: /\.css$/, | ||
| loader: ExtractTextPlugin.extract('style-loader', 'css-loader'), | ||
| } | ||
| ] | ||
| use: ExtractTextPlugin.extract({ | ||
| fallback: "style-loader", | ||
| use: "css-loader", | ||
| }), | ||
| }, | ||
| ], | ||
| }, | ||
@@ -31,4 +34,4 @@ plugins: [ | ||
| externals: { | ||
| 'react': 'react' | ||
| } | ||
| } | ||
| 'react': 'react', | ||
| }, | ||
| }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
3427472
0.12%35039
0.79%113
3.67%4
33.33%19
5.56%208
20.23%+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated