diff options
author | Christopher Speller <crspeller@gmail.com> | 2016-03-30 14:33:32 -0400 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2016-03-30 14:33:32 -0400 |
commit | 74d2c5b6ceb507e11032c79252f1778e7512d612 (patch) | |
tree | e2addd98f0a14cdf54fce337bfc9d732de6f0f04 /webapp/components/user_settings | |
parent | 6cad40ecf41740ae57a14df12dc363adafb49d18 (diff) | |
parent | f9a3a4b3949dddecae413b97904c895b2cd887bf (diff) | |
download | chat-74d2c5b6ceb507e11032c79252f1778e7512d612.tar.gz chat-74d2c5b6ceb507e11032c79252f1778e7512d612.tar.bz2 chat-74d2c5b6ceb507e11032c79252f1778e7512d612.zip |
Merge pull request #2518 from mattermost/plt-2187
PLT-2187 Add MFA functionality
Diffstat (limited to 'webapp/components/user_settings')
-rw-r--r-- | webapp/components/user_settings/user_settings_security.jsx | 223 |
1 files changed, 219 insertions, 4 deletions
diff --git a/webapp/components/user_settings/user_settings_security.jsx b/webapp/components/user_settings/user_settings_security.jsx index f24beb6b3..e4044e6d0 100644 --- a/webapp/components/user_settings/user_settings_security.jsx +++ b/webapp/components/user_settings/user_settings_security.jsx @@ -47,12 +47,16 @@ class SecurityTab extends React.Component { super(props); this.submitPassword = this.submitPassword.bind(this); + this.activateMfa = this.activateMfa.bind(this); + this.deactivateMfa = this.deactivateMfa.bind(this); this.updateCurrentPassword = this.updateCurrentPassword.bind(this); this.updateNewPassword = this.updateNewPassword.bind(this); this.updateConfirmPassword = this.updateConfirmPassword.bind(this); + this.updateMfaToken = this.updateMfaToken.bind(this); this.getDefaultState = this.getDefaultState.bind(this); this.createPasswordSection = this.createPasswordSection.bind(this); this.createSignInSection = this.createSignInSection.bind(this); + this.showQrCode = this.showQrCode.bind(this); this.state = this.getDefaultState(); } @@ -61,7 +65,9 @@ class SecurityTab extends React.Component { currentPassword: '', newPassword: '', confirmPassword: '', - authService: this.props.user.auth_service + authService: this.props.user.auth_service, + mfaShowQr: false, + mfaToken: '' }; } submitPassword(e) { @@ -112,6 +118,51 @@ class SecurityTab extends React.Component { } ); } + activateMfa() { + const data = {}; + data.activate = true; + data.token = this.state.mfaToken; + + Client.updateMfa(data, + () => { + this.props.updateSection(''); + AsyncClient.getMe(); + this.setState(this.getDefaultState()); + }, + (err) => { + const state = this.getDefaultState(); + if (err.message) { + state.serverError = err.message; + } else { + state.serverError = err; + } + state.mfaError = ''; + this.setState(state); + } + ); + } + deactivateMfa() { + const data = {}; + data.activate = false; + + Client.updateMfa(data, + () => { + this.props.updateSection(''); + AsyncClient.getMe(); + this.setState(this.getDefaultState()); + }, + (err) => { + const state = this.getDefaultState(); + if (err.message) { + state.serverError = err.message; + } else { + state.serverError = err; + } + state.mfaError = ''; + this.setState(state); + } + ); + } updateCurrentPassword(e) { this.setState({currentPassword: e.target.value}); } @@ -121,6 +172,163 @@ class SecurityTab extends React.Component { updateConfirmPassword(e) { this.setState({confirmPassword: e.target.value}); } + updateMfaToken(e) { + this.setState({mfaToken: e.target.value}); + } + showQrCode(e) { + e.preventDefault(); + this.setState({mfaShowQr: true}); + } + createMfaSection() { + let updateSectionStatus; + let submit; + + if (this.props.activeSection === 'mfa') { + let content; + let extraInfo; + if (this.props.user.mfa_active) { + content = ( + <div key='mfaQrCode'> + <a + className='btn btn-primary' + href='#' + onClick={this.deactivateMfa} + > + <FormattedMessage + id='user.settings.mfa.remove' + defaultMessage='Remove MFA from your account' + /> + </a> + <br/> + </div> + ); + + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.mfa.removeHelp' + defaultMessage='Removing multi-factor authentication will make your account more vulnerable to attacks.' + /> + </span> + ); + } else if (this.state.mfaShowQr) { + content = ( + <div key='mfaButton'> + <label className='col-sm-5 control-label'> + <FormattedMessage + id='user.settings.mfa.qrCode' + defaultMessage='QR Code' + /> + </label> + <div className='col-sm-7'> + <img + className='qr-code-img' + src={'/api/v1/users/generate_mfa_qr?time=' + this.props.user.update_at} + /> + </div> + <br/> + <label className='col-sm-5 control-label'> + <FormattedMessage + id='user.settings.mfa.enterToken' + defaultMessage='Token' + /> + </label> + <div className='col-sm-7'> + <input + className='form-control' + type='text' + onChange={this.updateMfaToken} + value={this.state.mfaToken} + /> + </div> + </div> + ); + + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.mfa.addHelp' + defaultMessage='Please scan the QR code with the Google Authenticator app on your smartphone and fill in the token with one provided by the app.' + /> + </span> + ); + + submit = this.activateMfa; + } else { + content = ( + <div key='mfaQrCode'> + <a + className='btn btn-primary' + href='#' + onClick={this.showQrCode} + > + <FormattedMessage + id='user.settings.mfa.add' + defaultMessage='Add MFA to your account' + /> + </a> + <br/> + </div> + ); + + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.mfa.addHelp' + defaultMessage='To add multi-factor authentication to your account you must have a smartphone with Google Authenticator installed.' + /> + </span> + ); + } + + const inputs = []; + inputs.push( + <div + key='mfaSetting' + className='form-group' + > + {content} + </div> + ); + + updateSectionStatus = function resetSection(e) { + this.props.updateSection(''); + this.setState({mfaToken: '', mfaShowQr: false, mfaError: null}); + e.preventDefault(); + }.bind(this); + + return ( + <SettingItemMax + title={Utils.localizeMessage('user.settings.mfa.title', 'Multi-factor Authentication')} + inputs={inputs} + extraInfo={extraInfo} + submit={submit} + server_error={this.state.serverError} + client_error={this.state.mfaError} + updateSection={updateSectionStatus} + /> + ); + } + + let describe; + if (this.props.user.mfa_active) { + describe = Utils.localizeMessage('user.settings.security.active', 'Active'); + } else { + describe = Utils.localizeMessage('user.settings.security.inactive', 'Inactive'); + } + + updateSectionStatus = function updateSection() { + this.props.updateSection('mfa'); + }.bind(this); + + return ( + <SettingItemMin + title={Utils.localizeMessage('user.settings.mfa.title', 'Multi-factor Authentication')} + describe={describe} + updateSection={updateSectionStatus} + /> + ); + } createPasswordSection() { let updateSectionStatus; @@ -316,7 +524,6 @@ class SecurityTab extends React.Component { const user = this.props.user; if (this.props.activeSection === 'signin') { - const inputs = []; const teamName = TeamStore.getCurrent().name; let emailOption; @@ -398,6 +605,7 @@ class SecurityTab extends React.Component { ); } + const inputs = []; inputs.push( <div key='userSignInOption'> {emailOption} @@ -463,17 +671,22 @@ class SecurityTab extends React.Component { } render() { const passwordSection = this.createPasswordSection(); - let signInSection; let numMethods = 0; numMethods = global.window.mm_config.EnableSignUpWithGitLab === 'true' ? numMethods + 1 : numMethods; numMethods = global.window.mm_config.EnableSignUpWithGoogle === 'true' ? numMethods + 1 : numMethods; numMethods = global.window.mm_config.EnableLdap === 'true' ? numMethods + 1 : numMethods; - if (global.window.mm_config.EnableSignUpWithEmail && numMethods > 0) { + let signInSection; + if (global.window.mm_config.EnableSignUpWithEmail === 'true' && numMethods > 0) { signInSection = this.createSignInSection(); } + let mfaSection; + if (global.window.mm_config.EnableMultifactorAuthentication === 'true' && global.window.mm_license.IsLicensed === 'true') { + mfaSection = this.createMfaSection(); + } + return ( <div> <div className='modal-header'> @@ -512,6 +725,8 @@ class SecurityTab extends React.Component { <div className='divider-dark first'/> {passwordSection} <div className='divider-light'/> + {mfaSection} + <div className='divider-light'/> {signInSection} <div className='divider-dark'/> <br></br> |