summaryrefslogtreecommitdiff
path: root/ui/app/components/password_field.js
blob: 8397967f48c3068aacab4a4250a00ec67f61dd7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//
// A validating password field, with a label and error messages.
//

import React from 'react'
import { FormGroup, ControlLabel, FormControl, HelpBlock} from 'react-bootstrap'
import Validate from 'lib/validate'

export default class PasswordField extends React.Component {

  static get defaultProps() {return{
    id: null,                // required. controlId of the element
    label: "Password",
    onChange: null,          // callback passed current password
    validationMode: "crack", // one of 'none', 'match', 'crack'
    matchText: null,         // used if validationMode == 'match'
  }}

  constructor(props) {
    super(props)
    this.state = {
      password: null,       // password value
      passwordState: null,  // password validation state
      passwordError: false, // password help message
    }
    this.keypress = this.keypress.bind(this)
  }

  componentDidMount() {
    if (this.props.validationMode == 'crack') {
      Validate.loadPasswdLib()
    }
  }

  render() {
    let passwordHelp = null

    if (this.state.passwordError) {
      passwordHelp = <HelpBlock>{this.state.passwordError}</HelpBlock>
    }

    return (
      <FormGroup controlId={this.props.id} validationState={this.state.passwordState}>
        <ControlLabel>{this.props.label}</ControlLabel>
        <FormControl
          type="password"
          ref="password"
          value={this.state.password || ""}
          onChange={this.keypress} />
        {this.state.passwordState == 'success' ? null : <FormControl.Feedback/>}
        {passwordHelp}
      </FormGroup>
     )
  }

  keypress(e) {
    let password = e.target.value
    if (this.props.onChange) {
      this.props.onChange(password)
    }
    this.setState({password: password})
    if (this.props.validationMode == 'crack') {
      if (password.length > 0) {
        this.validateCrack(password)
      } else {
        this.setState({
          passwordState: null,
          passwordError: null
        })
      }
    } else if (this.props.validationMode == 'match') {
      this.validateMatch(password)
    }
  }

  validateCrack(password) {
    let state = null
    let message = null
    let result = Validate.passwordStrength(password)
    if (result) {
      message = "Time to crack: " + result.crack_times_display.offline_slow_hashing_1e4_per_second
      if (result.score == 0) {
        state = 'error'
      } else if (result.score == 1 || result.score == 2) {
        state = 'warning'
      } else {
        state = 'success'
      }
    }
    this.setState({
      passwordState: state,
      passwordError: message
    })
  }

  validateMatch(password) {
    if (this.props.matchText) {
      if (password != this.props.matchText) {
        this.setState({
          passwordState: 'error',
          passwordError: "Does not match"
        })
      } else {
        this.setState({
          passwordState: 'success',
          passwordError: null
        })
      }
    }
  }

}