Add MFA functionality
Этот коммит содержится в:
@@ -84,6 +84,7 @@ class ServiceSettings extends React.Component {
|
||||
config.ServiceSettings.EnableDeveloper = ReactDOM.findDOMNode(this.refs.EnableDeveloper).checked;
|
||||
config.ServiceSettings.EnableSecurityFixAlert = ReactDOM.findDOMNode(this.refs.EnableSecurityFixAlert).checked;
|
||||
config.ServiceSettings.EnableInsecureOutgoingConnections = ReactDOM.findDOMNode(this.refs.EnableInsecureOutgoingConnections).checked;
|
||||
config.ServiceSettings.EnableMultifactorAuthentication = ReactDOM.findDOMNode(this.refs.EnableMultifactorAuthentication).checked;
|
||||
config.ServiceSettings.EnableCommands = ReactDOM.findDOMNode(this.refs.EnableCommands).checked;
|
||||
config.ServiceSettings.EnableOnlyAdminIntegrations = ReactDOM.findDOMNode(this.refs.EnableOnlyAdminIntegrations).checked;
|
||||
|
||||
@@ -173,6 +174,58 @@ class ServiceSettings extends React.Component {
|
||||
saveClass = 'btn btn-primary';
|
||||
}
|
||||
|
||||
let mfaSetting;
|
||||
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') {
|
||||
mfaSetting = (
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableMultifactorAuthentication'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='admin.service.mfaTitle'
|
||||
defaultMessage='Enable Multi-factor Authentication:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='EnableMultifactorAuthentication'
|
||||
value='true'
|
||||
ref='EnableMultifactorAuthentication'
|
||||
defaultChecked={this.props.config.ServiceSettings.EnableMultifactorAuthentication}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='admin.service.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='EnableMultifactorAuthentication'
|
||||
value='false'
|
||||
defaultChecked={!this.props.config.ServiceSettings.EnableMultifactorAuthentication}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='admin.service.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.mfaDesc'
|
||||
defaultMessage='When true, users will be given the option to add multi-factor authentication to their account. They will need a smartphone and an authenticator app such as Google Authenticator.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
|
||||
@@ -773,6 +826,8 @@ class ServiceSettings extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{mfaSetting}
|
||||
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
|
||||
@@ -2,69 +2,40 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import * as Client from 'utils/client.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import {browserHistory} from 'react-router';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
|
||||
|
||||
var holders = defineMessages({
|
||||
badTeam: {
|
||||
id: 'login_email.badTeam',
|
||||
defaultMessage: 'Bad team name'
|
||||
},
|
||||
emailReq: {
|
||||
id: 'login_email.emailReq',
|
||||
defaultMessage: 'An email is required'
|
||||
},
|
||||
pwdReq: {
|
||||
id: 'login_email.pwdReq',
|
||||
defaultMessage: 'A password is required'
|
||||
},
|
||||
email: {
|
||||
id: 'login_email.email',
|
||||
defaultMessage: 'Email'
|
||||
},
|
||||
pwd: {
|
||||
id: 'login_email.pwd',
|
||||
defaultMessage: 'Password'
|
||||
}
|
||||
});
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class LoginEmail extends React.Component {
|
||||
export default class LoginEmail extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
|
||||
this.state = {
|
||||
serverError: ''
|
||||
serverError: props.serverError
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({serverError: nextProps.serverError});
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const {formatMessage} = this.props.intl;
|
||||
var state = {};
|
||||
|
||||
const name = this.props.teamName;
|
||||
if (!name) {
|
||||
state.serverError = formatMessage(holders.badTeam);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const email = this.refs.email.value.trim();
|
||||
if (!email) {
|
||||
state.serverError = formatMessage(holders.emailReq);
|
||||
state.serverError = Utils.localizeMessage('login_email.emailReq', 'An email is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const password = this.refs.password.value.trim();
|
||||
if (!password) {
|
||||
state.serverError = formatMessage(holders.pwdReq);
|
||||
state.serverError = Utils.localizeMessage('login_email.pwdReq', 'A password is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -72,21 +43,7 @@ class LoginEmail extends React.Component {
|
||||
state.serverError = '';
|
||||
this.setState(state);
|
||||
|
||||
Client.loginByEmail(name, email, password,
|
||||
() => {
|
||||
UserStore.setLastEmail(email);
|
||||
browserHistory.push('/' + name + '/channels/town-square');
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
browserHistory.push('/verify_email?teamname=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(email));
|
||||
return;
|
||||
}
|
||||
state.serverError = err.message;
|
||||
this.valid = false;
|
||||
this.setState(state);
|
||||
}
|
||||
);
|
||||
this.props.submit(Constants.EMAIL_SERVICE, email, password);
|
||||
}
|
||||
render() {
|
||||
let serverError;
|
||||
@@ -110,7 +67,6 @@ class LoginEmail extends React.Component {
|
||||
priorEmail = decodeURIComponent(emailParam);
|
||||
}
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
@@ -125,7 +81,7 @@ class LoginEmail extends React.Component {
|
||||
name='email'
|
||||
defaultValue={priorEmail}
|
||||
ref='email'
|
||||
placeholder={formatMessage(holders.email)}
|
||||
placeholder={Utils.localizeMessage('login_email.email', 'Email')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -136,7 +92,7 @@ class LoginEmail extends React.Component {
|
||||
className='form-control'
|
||||
name='password'
|
||||
ref='password'
|
||||
placeholder={formatMessage(holders.pwd)}
|
||||
placeholder={Utils.localizeMessage('login_email.pwd', 'Password')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -160,8 +116,6 @@ LoginEmail.defaultProps = {
|
||||
};
|
||||
|
||||
LoginEmail.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
teamName: React.PropTypes.string.isRequired
|
||||
submit: React.PropTypes.func.isRequired,
|
||||
serverError: React.PropTypes.string
|
||||
};
|
||||
|
||||
export default injectIntl(LoginEmail);
|
||||
@@ -2,68 +2,39 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import * as Client from 'utils/client.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
const holders = defineMessages({
|
||||
badTeam: {
|
||||
id: 'login_ldap.badTeam',
|
||||
defaultMessage: 'Bad team name'
|
||||
},
|
||||
idReq: {
|
||||
id: 'login_ldap.idlReq',
|
||||
defaultMessage: 'An LDAP ID is required'
|
||||
},
|
||||
pwdReq: {
|
||||
id: 'login_ldap.pwdReq',
|
||||
defaultMessage: 'An LDAP password is required'
|
||||
},
|
||||
username: {
|
||||
id: 'login_ldap.username',
|
||||
defaultMessage: 'LDAP Username'
|
||||
},
|
||||
pwd: {
|
||||
id: 'login_ldap.pwd',
|
||||
defaultMessage: 'LDAP Password'
|
||||
}
|
||||
});
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class LoginLdap extends React.Component {
|
||||
export default class LoginLdap extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
|
||||
this.state = {
|
||||
serverError: ''
|
||||
serverError: props.serverError
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({serverError: nextProps.serverError});
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const {formatMessage} = this.props.intl;
|
||||
var state = {};
|
||||
|
||||
const teamName = this.props.teamName;
|
||||
if (!teamName) {
|
||||
state.serverError = formatMessage(holders.badTeam);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
const state = {};
|
||||
|
||||
const id = this.refs.id.value.trim();
|
||||
if (!id) {
|
||||
state.serverError = formatMessage(holders.idReq);
|
||||
state.serverError = Utils.localizeMessage('login_ldap.idlReq', 'An LDAP ID is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const password = this.refs.password.value.trim();
|
||||
if (!password) {
|
||||
state.serverError = formatMessage(holders.pwdReq);
|
||||
state.serverError = Utils.localizeMessage('login_ldap.pwdReq', 'An LDAP password is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -71,20 +42,7 @@ class LoginLdap extends React.Component {
|
||||
state.serverError = '';
|
||||
this.setState(state);
|
||||
|
||||
Client.loginByLdap(teamName, id, password,
|
||||
() => {
|
||||
const redirect = Utils.getUrlParameter('redirect');
|
||||
if (redirect) {
|
||||
browserHistory.push(decodeURIComponent(redirect));
|
||||
} else {
|
||||
browserHistory.push('/' + teamName + '/channels/town-square');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
state.serverError = err.message;
|
||||
this.setState(state);
|
||||
}
|
||||
);
|
||||
this.props.submit(Constants.LDAP_SERVICE, id, password);
|
||||
}
|
||||
render() {
|
||||
let serverError;
|
||||
@@ -93,7 +51,7 @@ class LoginLdap extends React.Component {
|
||||
serverError = <label className='control-label'>{this.state.serverError}</label>;
|
||||
errorClass = ' has-error';
|
||||
}
|
||||
const {formatMessage} = this.props.intl;
|
||||
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
@@ -105,7 +63,7 @@ class LoginLdap extends React.Component {
|
||||
autoFocus={true}
|
||||
className='form-control'
|
||||
ref='id'
|
||||
placeholder={formatMessage(holders.username)}
|
||||
placeholder={Utils.localizeMessage('login_ldap.username', 'LDAP Username')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -114,7 +72,7 @@ class LoginLdap extends React.Component {
|
||||
type='password'
|
||||
className='form-control'
|
||||
ref='password'
|
||||
placeholder={formatMessage(holders.pwd)}
|
||||
placeholder={Utils.localizeMessage('login_ldap.pwd', 'LDAP Password')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -138,8 +96,6 @@ LoginLdap.defaultProps = {
|
||||
};
|
||||
|
||||
LoginLdap.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
teamName: React.PropTypes.string.isRequired
|
||||
serverError: React.PropTypes.string,
|
||||
submit: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(LoginLdap);
|
||||
92
webapp/components/login/components/login_mfa.jsx
Обычный файл
92
webapp/components/login/components/login_mfa.jsx
Обычный файл
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default class LoginMfa extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
|
||||
this.state = {
|
||||
serverError: ''
|
||||
};
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const state = {};
|
||||
|
||||
const token = this.refs.token.value.trim();
|
||||
if (!token) {
|
||||
state.serverError = Utils.localizeMessage('login_mfa.tokenReq', 'Please enter an MFA token');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.serverError = '';
|
||||
this.setState(state);
|
||||
|
||||
this.props.submit(this.props.method, this.props.loginId, this.props.password, token);
|
||||
}
|
||||
render() {
|
||||
let serverError;
|
||||
let errorClass = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <label className='control-label'>{this.state.serverError}</label>;
|
||||
errorClass = ' has-error';
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='login_mfa.enterToken'
|
||||
defaultMessage="To complete the sign in process, please enter a token from your smartphone's authenticator"
|
||||
/>
|
||||
</p>
|
||||
<div className={'form-group' + errorClass}>
|
||||
{serverError}
|
||||
</div>
|
||||
<div className={'form-group' + errorClass}>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
name='token'
|
||||
ref='token'
|
||||
placeholder={Utils.localizeMessage('login_mfa.token', 'MFA Token')}
|
||||
spellCheck='false'
|
||||
autoComplete='off'
|
||||
autoFocus={true}
|
||||
/>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='login_mfa.submit'
|
||||
defaultMessage='Submit'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
LoginMfa.defaultProps = {
|
||||
};
|
||||
|
||||
LoginMfa.propTypes = {
|
||||
method: React.PropTypes.string.isRequired,
|
||||
loginId: React.PropTypes.string.isRequired,
|
||||
password: React.PropTypes.string.isRequired,
|
||||
submit: React.PropTypes.func.isRequired
|
||||
};
|
||||
@@ -2,42 +2,10 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import * as Client from 'utils/client.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
var holders = defineMessages({
|
||||
badTeam: {
|
||||
id: 'login_username.badTeam',
|
||||
defaultMessage: 'Bad team name'
|
||||
},
|
||||
usernameReq: {
|
||||
id: 'login_username.usernameReq',
|
||||
defaultMessage: 'A username is required'
|
||||
},
|
||||
pwdReq: {
|
||||
id: 'login_username.pwdReq',
|
||||
defaultMessage: 'A password is required'
|
||||
},
|
||||
verifyEmailError: {
|
||||
id: 'login_username.verifyEmailError',
|
||||
defaultMessage: 'Please verify your email address. Check your inbox for an email.'
|
||||
},
|
||||
userNotFoundError: {
|
||||
id: 'login_username.userNotFoundError',
|
||||
defaultMessage: "We couldn't find an existing account matching your username for this team."
|
||||
},
|
||||
username: {
|
||||
id: 'login_username.username',
|
||||
defaultMessage: 'Username'
|
||||
},
|
||||
pwd: {
|
||||
id: 'login_username.pwd',
|
||||
defaultMessage: 'Password'
|
||||
}
|
||||
});
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
@@ -48,31 +16,26 @@ export default class LoginUsername extends React.Component {
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
|
||||
this.state = {
|
||||
serverError: ''
|
||||
serverError: props.serverError
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({serverError: nextProps.serverError});
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const {formatMessage} = this.props.intl;
|
||||
var state = {};
|
||||
|
||||
const name = this.props.teamName;
|
||||
if (!name) {
|
||||
state.serverError = formatMessage(holders.badTeam);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
const state = {};
|
||||
|
||||
const username = this.refs.username.value.trim();
|
||||
if (!username) {
|
||||
state.serverError = formatMessage(holders.usernameReq);
|
||||
state.serverError = Utils.localizeMessage('login_username.usernameReq', 'A username is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const password = this.refs.password.value.trim();
|
||||
if (!password) {
|
||||
state.serverError = formatMessage(holders.pwdReq);
|
||||
state.serverError = Utils.localizeMessage('login_username.pwdReq', 'A password is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -80,30 +43,7 @@ export default class LoginUsername extends React.Component {
|
||||
state.serverError = '';
|
||||
this.setState(state);
|
||||
|
||||
Client.loginByUsername(name, username, password,
|
||||
() => {
|
||||
UserStore.setLastUsername(username);
|
||||
|
||||
const redirect = Utils.getUrlParameter('redirect');
|
||||
if (redirect) {
|
||||
browserHistory.push(decodeURIComponent(redirect));
|
||||
} else {
|
||||
browserHistory.push('/' + name + '/channels/town-square');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
state.serverError = formatMessage(holders.verifyEmailError);
|
||||
} else if (err.id === 'store.sql_user.get_by_username.app_error') {
|
||||
state.serverError = formatMessage(holders.userNotFoundError);
|
||||
} else {
|
||||
state.serverError = err.message;
|
||||
}
|
||||
|
||||
this.valid = false;
|
||||
this.setState(state);
|
||||
}
|
||||
);
|
||||
this.props.submit(Constants.USERNAME_SERVICE, username, password);
|
||||
}
|
||||
render() {
|
||||
let serverError;
|
||||
@@ -127,7 +67,6 @@ export default class LoginUsername extends React.Component {
|
||||
priorUsername = decodeURIComponent(emailParam);
|
||||
}
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
@@ -142,7 +81,7 @@ export default class LoginUsername extends React.Component {
|
||||
name='username'
|
||||
defaultValue={priorUsername}
|
||||
ref='username'
|
||||
placeholder={formatMessage(holders.username)}
|
||||
placeholder={Utils.localizeMessage('login_username.username', 'Username')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -153,7 +92,7 @@ export default class LoginUsername extends React.Component {
|
||||
className='form-control'
|
||||
name='password'
|
||||
ref='password'
|
||||
placeholder={formatMessage(holders.pwd)}
|
||||
placeholder={Utils.localizeMessage('login_username.pwd', 'Password')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -177,8 +116,6 @@ LoginUsername.defaultProps = {
|
||||
};
|
||||
|
||||
LoginUsername.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
teamName: React.PropTypes.string.isRequired
|
||||
serverError: React.PropTypes.string,
|
||||
submit: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(LoginUsername);
|
||||
@@ -1,14 +1,17 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import LoginEmail from './login_email.jsx';
|
||||
import LoginUsername from './login_username.jsx';
|
||||
import LoginLdap from './login_ldap.jsx';
|
||||
import LoginEmail from './components/login_email.jsx';
|
||||
import LoginUsername from './components/login_username.jsx';
|
||||
import LoginLdap from './components/login_ldap.jsx';
|
||||
import LoginMfa from './components/login_mfa.jsx';
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import * as Client from 'utils/client.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
import * as Client from 'utils/client.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {browserHistory, Link} from 'react-router';
|
||||
@@ -21,6 +24,8 @@ export default class Login extends React.Component {
|
||||
|
||||
this.getStateFromStores = this.getStateFromStores.bind(this);
|
||||
this.onTeamChange = this.onTeamChange.bind(this);
|
||||
this.preSubmit = this.preSubmit.bind(this);
|
||||
this.submit = this.submit.bind(this);
|
||||
|
||||
this.state = this.getStateFromStores();
|
||||
}
|
||||
@@ -46,54 +51,89 @@ export default class Login extends React.Component {
|
||||
onTeamChange() {
|
||||
this.setState(this.getStateFromStores());
|
||||
}
|
||||
render() {
|
||||
const currentTeam = this.state.currentTeam;
|
||||
if (currentTeam == null || !this.state.doneCheckLogin) {
|
||||
return <div/>;
|
||||
preSubmit(method, loginId, password) {
|
||||
if (global.window.mm_config.EnableMultifactorAuthentication !== 'true') {
|
||||
this.submit(method, loginId, password, '');
|
||||
return;
|
||||
}
|
||||
|
||||
const teamDisplayName = currentTeam.display_name;
|
||||
const teamName = currentTeam.name;
|
||||
const ldapEnabled = global.window.mm_config.EnableLdap === 'true';
|
||||
const usernameSigninEnabled = global.window.mm_config.EnableSignInWithUsername === 'true';
|
||||
Client.checkMfa(method, this.state.currentTeam.name, loginId,
|
||||
(data) => {
|
||||
if (data.mfa_required === 'true') {
|
||||
this.setState({showMfa: true, method, loginId, password});
|
||||
} else {
|
||||
this.submit(method, loginId, password, '');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (method === Constants.EMAIL_SERVICE) {
|
||||
this.setState({serverEmailError: err.message});
|
||||
} else if (method === Constants.USERNAME_SERVICE) {
|
||||
this.setState({serverUsernameError: err.message});
|
||||
} else if (method === Constants.LDAP_SERVICE) {
|
||||
this.setState({serverLdapError: err.message});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
submit(method, loginId, password, token) {
|
||||
this.setState({showMfa: false, serverEmailError: null, serverUsernameError: null, serverLdapError: null});
|
||||
|
||||
let loginMessage = [];
|
||||
if (global.window.mm_config.EnableSignUpWithGitLab === 'true') {
|
||||
loginMessage.push(
|
||||
<a
|
||||
className='btn btn-custom-login gitlab'
|
||||
key='gitlab'
|
||||
href={'/api/v1/oauth/gitlab/login?team=' + encodeURIComponent(teamName)}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.gitlab'
|
||||
defaultMessage='with GitLab'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
const team = this.state.currentTeam.name;
|
||||
|
||||
if (method === Constants.EMAIL_SERVICE) {
|
||||
Client.loginByEmail(team, loginId, password, token,
|
||||
() => {
|
||||
UserStore.setLastEmail(loginId);
|
||||
browserHistory.push('/' + team + '/channels/town-square');
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
browserHistory.push('/verify_email?teamname=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(loginId));
|
||||
return;
|
||||
}
|
||||
this.setState({serverEmailError: err.message});
|
||||
}
|
||||
);
|
||||
} else if (method === Constants.USERNAME_SERVICE) {
|
||||
Client.loginByUsername(team, loginId, password, token,
|
||||
() => {
|
||||
UserStore.setLastUsername(loginId);
|
||||
|
||||
const redirect = Utils.getUrlParameter('redirect');
|
||||
if (redirect) {
|
||||
browserHistory.push(decodeURIComponent(redirect));
|
||||
} else {
|
||||
browserHistory.push('/' + team + '/channels/town-square');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
this.setState({serverUsernameError: Utils.localizeMessage('login_username.verifyEmailError', 'Please verify your email address. Check your inbox for an email.')});
|
||||
} else if (err.id === 'store.sql_user.get_by_username.app_error') {
|
||||
this.setState({serverUsernameError: Utils.localizeMessage('login_username.userNotFoundError', 'We couldn\'t find an existing account matching your username for this team.')});
|
||||
} else {
|
||||
this.setState({serverUsernameError: err.message});
|
||||
}
|
||||
}
|
||||
);
|
||||
} else if (method === Constants.LDAP_SERVICE) {
|
||||
Client.loginByLdap(team, loginId, password, token,
|
||||
() => {
|
||||
const redirect = Utils.getUrlParameter('redirect');
|
||||
if (redirect) {
|
||||
browserHistory.push(decodeURIComponent(redirect));
|
||||
} else {
|
||||
browserHistory.push('/' + team + '/channels/town-square');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
this.setState({serverLdapError: err.message});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (global.window.mm_config.EnableSignUpWithGoogle === 'true') {
|
||||
loginMessage.push(
|
||||
<a
|
||||
className='btn btn-custom-login google'
|
||||
key='google'
|
||||
href={'/api/v1/oauth/google/login?team=' + encodeURIComponent(teamName)}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.google'
|
||||
defaultMessage='with Google Apps'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
createLoginOptions(currentTeam) {
|
||||
const extraParam = Utils.getUrlParameter('extra');
|
||||
let extraBox = '';
|
||||
if (extraParam) {
|
||||
@@ -130,44 +170,126 @@ export default class Login extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
let emailSignup;
|
||||
if (global.window.mm_config.EnableSignInWithEmail === 'true') {
|
||||
emailSignup = (
|
||||
const teamName = currentTeam.name;
|
||||
const ldapEnabled = global.window.mm_config.EnableLdap === 'true';
|
||||
const gitlabSigninEnabled = global.window.mm_config.EnableSignUpWithGitLab === 'true';
|
||||
const googleSigninEnabled = global.window.mm_config.EnableSignUpWithGoogle === 'true';
|
||||
const usernameSigninEnabled = global.window.mm_config.EnableSignInWithUsername === 'true';
|
||||
const emailSigninEnabled = global.window.mm_config.EnableSignInWithEmail === 'true';
|
||||
|
||||
const oauthLogins = [];
|
||||
if (gitlabSigninEnabled) {
|
||||
oauthLogins.push(
|
||||
<Link
|
||||
className='btn btn-custom-login gitlab'
|
||||
key='gitlab'
|
||||
to={'/api/v1/oauth/gitlab/login?team=' + encodeURIComponent(teamName)}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.gitlab'
|
||||
defaultMessage='with GitLab'
|
||||
/>
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
if (googleSigninEnabled) {
|
||||
oauthLogins.push(
|
||||
<Link
|
||||
className='btn btn-custom-login google'
|
||||
key='google'
|
||||
to={'/api/v1/oauth/google/login?team=' + encodeURIComponent(teamName)}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.google'
|
||||
defaultMessage='with Google Apps'
|
||||
/>
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
let emailLogin;
|
||||
if (emailSigninEnabled) {
|
||||
emailLogin = (
|
||||
<LoginEmail
|
||||
teamName={teamName}
|
||||
serverError={this.state.serverEmailError}
|
||||
submit={this.preSubmit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (loginMessage.length > 0 && emailSignup) {
|
||||
loginMessage = (
|
||||
<div>
|
||||
{loginMessage}
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
/>
|
||||
if (oauthLogins.length > 0) {
|
||||
emailLogin = (
|
||||
<div>
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
/>
|
||||
</div>
|
||||
{emailLogin}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let forgotPassword;
|
||||
if (emailSignup) {
|
||||
forgotPassword = (
|
||||
<div className='form-group'>
|
||||
<Link to={'/' + teamName + '/reset_password'}>
|
||||
<FormattedMessage
|
||||
id='login.forgot'
|
||||
defaultMessage='I forgot my password'
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
let usernameLogin;
|
||||
if (usernameSigninEnabled) {
|
||||
usernameLogin = (
|
||||
<LoginUsername
|
||||
teamName={teamName}
|
||||
serverError={this.state.serverUsernameError}
|
||||
submit={this.preSubmit}
|
||||
/>
|
||||
);
|
||||
|
||||
if (emailSigninEnabled || oauthLogins.length > 0) {
|
||||
usernameLogin = (
|
||||
<div>
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
/>
|
||||
</div>
|
||||
{usernameLogin}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let userSignUp = null;
|
||||
let ldapLogin;
|
||||
if (ldapEnabled) {
|
||||
ldapLogin = (
|
||||
<LoginLdap
|
||||
teamName={teamName}
|
||||
serverError={this.state.serverLdapError}
|
||||
submit={this.preSubmit}
|
||||
/>
|
||||
);
|
||||
|
||||
if (emailSigninEnabled || usernameSigninEnabled || oauthLogins.length > 0) {
|
||||
ldapLogin = (
|
||||
<div>
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
/>
|
||||
</div>
|
||||
{ldapLogin}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let userSignUp;
|
||||
if (currentTeam.allow_open_invite) {
|
||||
userSignUp = (
|
||||
<div>
|
||||
@@ -190,7 +312,21 @@ export default class Login extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let teamSignUp = null;
|
||||
let forgotPassword;
|
||||
if (usernameSigninEnabled || emailSigninEnabled) {
|
||||
forgotPassword = (
|
||||
<div className='form-group'>
|
||||
<Link to={'/' + teamName + '/reset_password'}>
|
||||
<FormattedMessage
|
||||
id='login.forgot'
|
||||
defaultMessage='I forgot my password'
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let teamSignUp;
|
||||
if (global.window.mm_config.EnableTeamCreation === 'true' && !Utils.isMobileApp()) {
|
||||
teamSignUp = (
|
||||
<div className='margin--extra'>
|
||||
@@ -207,54 +343,37 @@ export default class Login extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let ldapLogin = null;
|
||||
if (global.window.mm_config.EnableLdap === 'true') {
|
||||
ldapLogin = (
|
||||
<LoginLdap
|
||||
teamName={teamName}
|
||||
return (
|
||||
<div>
|
||||
{extraBox}
|
||||
{oauthLogins}
|
||||
{emailLogin}
|
||||
{usernameLogin}
|
||||
{ldapLogin}
|
||||
{userSignUp}
|
||||
{forgotPassword}
|
||||
{teamSignUp}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
const currentTeam = this.state.currentTeam;
|
||||
if (currentTeam == null || !this.state.doneCheckLogin) {
|
||||
return <div/>;
|
||||
}
|
||||
|
||||
let content;
|
||||
if (this.state.showMfa) {
|
||||
content = (
|
||||
<LoginMfa
|
||||
method={this.state.method}
|
||||
loginId={this.state.loginId}
|
||||
password={this.state.password}
|
||||
submit={this.submit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (ldapEnabled && (loginMessage.length > 0 || emailSignup || usernameSigninEnabled)) {
|
||||
ldapLogin = (
|
||||
<div>
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
/>
|
||||
</div>
|
||||
<LoginLdap
|
||||
teamName={teamName}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let usernameLogin = null;
|
||||
if (global.window.mm_config.EnableSignInWithUsername === 'true') {
|
||||
usernameLogin = (
|
||||
<LoginUsername
|
||||
teamName={teamName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (usernameSigninEnabled && (loginMessage.length > 0 || emailSignup || ldapEnabled)) {
|
||||
usernameLogin = (
|
||||
<div>
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
/>
|
||||
</div>
|
||||
<LoginUsername
|
||||
teamName={teamName}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
content = this.createLoginOptions(currentTeam);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -275,7 +394,7 @@ export default class Login extends React.Component {
|
||||
defaultMessage='Sign in to:'
|
||||
/>
|
||||
</h5>
|
||||
<h2 className='signup-team__name'>{teamDisplayName}</h2>
|
||||
<h2 className='signup-team__name'>{currentTeam.display_name}</h2>
|
||||
<h2 className='signup-team__subdomain'>
|
||||
<FormattedMessage
|
||||
id='login.on'
|
||||
@@ -285,14 +404,7 @@ export default class Login extends React.Component {
|
||||
}}
|
||||
/>
|
||||
</h2>
|
||||
{extraBox}
|
||||
{loginMessage}
|
||||
{emailSignup}
|
||||
{usernameLogin}
|
||||
{ldapLogin}
|
||||
{userSignUp}
|
||||
{forgotPassword}
|
||||
{teamSignUp}
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2,7 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import LoadingScreen from 'components/loading_screen.jsx';
|
||||
import LoginLdap from 'components/login_ldap.jsx';
|
||||
import LoginLdap from 'components/login/components/login_ldap.jsx';
|
||||
|
||||
import BrowserStore from 'stores/browser_store.jsx';
|
||||
import UserStore from 'stores/user_store.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>
|
||||
|
||||
Ссылка в новой задаче
Block a user