// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import SettingItemMin from '../setting_item_min.jsx'; import SettingItemMax from '../setting_item_max.jsx'; import AccessHistoryModal from '../access_history_modal.jsx'; import ActivityLogModal from '../activity_log_modal.jsx'; import ToggleModalButton from '../toggle_modal_button.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; import {generateMfaSecret} from 'actions/user_actions.jsx'; import Client from 'client/web_client.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; import $ from 'jquery'; import React from 'react'; import {FormattedMessage, FormattedHTMLMessage, FormattedTime, FormattedDate} from 'react-intl'; import {Link} from 'react-router/es6'; import icon50 from 'images/icon50x50.png'; export default class SecurityTab extends React.Component { constructor(props) { 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.createOAuthAppsSection = this.createOAuthAppsSection.bind(this); this.showQrCode = this.showQrCode.bind(this); this.deauthorizeApp = this.deauthorizeApp.bind(this); this.state = this.getDefaultState(); } getDefaultState() { return { currentPassword: '', newPassword: '', confirmPassword: '', passwordError: '', serverError: '', authService: this.props.user.auth_service, mfaShowQr: false, mfaToken: '' }; } componentDidMount() { if (global.mm_config.EnableOAuthServiceProvider === 'true') { Client.getAuthorizedApps( (authorizedApps) => { this.setState({authorizedApps, serverError: null}); //eslint-disable-line react/no-did-mount-set-state }, (err) => { this.setState({serverError: err.message}); //eslint-disable-line react/no-did-mount-set-state }); } } submitPassword(e) { e.preventDefault(); var user = this.props.user; var currentPassword = this.state.currentPassword; var newPassword = this.state.newPassword; var confirmPassword = this.state.confirmPassword; if (currentPassword === '') { this.setState({passwordError: Utils.localizeMessage('user.settings.security.currentPasswordError', 'Please enter your current password.'), serverError: ''}); return; } const passwordErr = Utils.isValidPassword(newPassword); if (passwordErr !== '') { this.setState({ passwordError: passwordErr, serverError: '' }); return; } if (newPassword !== confirmPassword) { var defaultState = Object.assign(this.getDefaultState(), {passwordError: Utils.localizeMessage('user.settings.security.passwordMatchError', 'The new passwords you entered do not match.'), serverError: ''}); this.setState(defaultState); return; } Client.updatePassword( user.id, currentPassword, newPassword, () => { this.props.updateSection(''); AsyncClient.getMe(); this.setState(this.getDefaultState()); }, (err) => { var state = this.getDefaultState(); if (err.message) { state.serverError = err.message; } else { state.serverError = err; } state.passwordError = ''; this.setState(state); } ); } activateMfa() { Client.updateMfa( this.state.mfaToken, true, () => { 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() { Client.updateMfa( '', false, () => { 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}); } updateNewPassword(e) { this.setState({newPassword: e.target.value}); } updateConfirmPassword(e) { this.setState({confirmPassword: e.target.value}); } updateMfaToken(e) { this.setState({mfaToken: e.target.value}); } showQrCode(e) { e.preventDefault(); generateMfaSecret( (data) => this.setState({mfaShowQr: true, secret: data.secret, qrCode: data.qr_code}), (err) => this.setState({serverError: err.message}) ); } deauthorizeApp(e) { e.preventDefault(); const appId = e.currentTarget.getAttribute('data-app'); Client.deauthorizeOAuthApp( appId, () => { const authorizedApps = this.state.authorizedApps.filter((app) => { return app.id !== appId; }); this.setState({authorizedApps, serverError: null}); }, (err) => { this.setState({serverError: err.message}); }); } createMfaSection() { let updateSectionStatus; let submit; if (this.props.activeSection === 'mfa') { let content; let extraInfo; if (this.props.user.mfa_active) { content = (

); extraInfo = ( ); } else if (this.state.mfaShowQr) { content = (
{this.state.secret}

); extraInfo = ( ); submit = this.activateMfa; } else { content = (

); extraInfo = ( ); } const inputs = []; inputs.push(
{content}
); updateSectionStatus = function resetSection(e) { this.props.updateSection(''); this.setState({mfaToken: '', mfaShowQr: false, mfaError: null, serverError: null}); e.preventDefault(); }.bind(this); return ( ); } 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 ( ); } createPasswordSection() { let updateSectionStatus; if (this.props.activeSection === 'password') { const inputs = []; let submit; if (this.props.user.auth_service === '') { submit = this.submitPassword; inputs.push(
); inputs.push(
); inputs.push(
); } else if (this.props.user.auth_service === Constants.GITLAB_SERVICE) { inputs.push(
); } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) { inputs.push(
); } else if (this.props.user.auth_service === Constants.SAML_SERVICE) { inputs.push(
); } updateSectionStatus = function resetSection(e) { this.props.updateSection(''); this.setState({currentPassword: '', newPassword: '', confirmPassword: '', serverError: null, passwordError: null}); e.preventDefault(); $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update'); }.bind(this); return ( } inputs={inputs} submit={submit} server_error={this.state.serverError} client_error={this.state.passwordError} updateSection={updateSectionStatus} /> ); } let describe; if (this.props.user.auth_service === '') { const d = new Date(this.props.user.last_password_update); const hours12 = !PreferenceStore.getBool(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, Constants.Preferences.USE_MILITARY_TIME, false); describe = ( ), time: ( ) }} /> ); } else if (this.props.user.auth_service === Constants.GITLAB_SERVICE) { describe = ( ); } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) { describe = ( ); } else if (this.props.user.auth_service === Constants.SAML_SERVICE) { describe = ( ); } updateSectionStatus = function updateSection() { this.props.updateSection('password'); }.bind(this); return ( } describe={describe} updateSection={updateSectionStatus} /> ); } createSignInSection() { let updateSectionStatus; const user = this.props.user; if (this.props.activeSection === 'signin') { let emailOption; let gitlabOption; let googleOption; let office365Option; let ldapOption; let samlOption; if (user.auth_service === '') { if (global.window.mm_config.EnableSignUpWithGitLab === 'true') { gitlabOption = (

); } if (global.window.mm_config.EnableSignUpWithGoogle === 'true') { googleOption = (

); } if (global.window.mm_config.EnableSignUpWithOffice365 === 'true') { office365Option = (

); } if (global.window.mm_config.EnableLdap === 'true') { ldapOption = (

); } if (global.window.mm_config.EnableSaml === 'true') { samlOption = (

); } } else if (global.window.mm_config.EnableSignUpWithEmail === 'true') { let link; if (user.auth_service === Constants.LDAP_SERVICE) { link = '/claim/ldap_to_email?email=' + encodeURIComponent(user.email); } else { link = '/claim/oauth_to_email?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service; } emailOption = (

); } const inputs = []; inputs.push(
{emailOption} {gitlabOption} {googleOption} {office365Option} {ldapOption} {samlOption}
); updateSectionStatus = function updateSection(e) { this.props.updateSection(''); this.setState({serverError: null}); e.preventDefault(); }.bind(this); const extraInfo = ( ); return ( ); } updateSectionStatus = function updateSection() { this.props.updateSection('signin'); }.bind(this); let describe = ( ); if (this.props.user.auth_service === Constants.GITLAB_SERVICE) { describe = ( ); } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) { describe = ( ); } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) { describe = ( ); } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) { describe = ( ); } else if (this.props.user.auth_service === Constants.SAML_SERVICE) { describe = ( ); } return ( ); } createOAuthAppsSection() { let updateSectionStatus; if (this.props.activeSection === 'apps') { let apps; if (this.state.authorizedApps && this.state.authorizedApps.length > 0) { apps = this.state.authorizedApps.map((app) => { const homepage = ( {app.homepage} ); return (
{app.name} {' -'} {homepage}
{app.description}
{app.name}

); }); } else { apps = (
); } const inputs = []; let wrapperClass; let helpText; if (Array.isArray(apps)) { wrapperClass = 'authorized-apps__wrapper'; helpText = (
); } inputs.push(
{apps}
); updateSectionStatus = function updateSection(e) { this.props.updateSection(''); this.setState({serverError: null}); e.preventDefault(); }.bind(this); const title = (
{helpText}
); return ( ); } updateSectionStatus = function updateSection() { this.props.updateSection('apps'); }.bind(this); return ( } updateSection={updateSectionStatus} /> ); } render() { const user = this.props.user; const config = window.mm_config; const passwordSection = this.createPasswordSection(); let numMethods = 0; numMethods = config.EnableSignUpWithGitLab === 'true' ? numMethods + 1 : numMethods; numMethods = config.EnableSignUpWithGoogle === 'true' ? numMethods + 1 : numMethods; numMethods = config.EnableLdap === 'true' ? numMethods + 1 : numMethods; numMethods = config.EnableSaml === 'true' ? numMethods + 1 : numMethods; // If there are other sign-in methods and either email is enabled or the user's account is email, then allow switching let signInSection; if ((config.EnableSignUpWithEmail === 'true' || user.auth_service === '') && numMethods > 0) { signInSection = this.createSignInSection(); } let mfaSection; if (config.EnableMultifactorAuthentication === 'true' && global.window.mm_license.IsLicensed === 'true' && (user.auth_service === '' || user.auth_service === Constants.LDAP_SERVICE)) { mfaSection = this.createMfaSection(); } let oauthSection; if (config.EnableOAuthServiceProvider === 'true') { oauthSection = this.createOAuthAppsSection(); } return (

{passwordSection}
{mfaSection}
{oauthSection}
{signInSection}

); } } SecurityTab.defaultProps = { user: {}, activeSection: '' }; SecurityTab.propTypes = { user: React.PropTypes.object, activeSection: React.PropTypes.string, updateSection: React.PropTypes.func, updateTab: React.PropTypes.func, closeModal: React.PropTypes.func.isRequired, collapseModal: React.PropTypes.func.isRequired, setEnforceFocus: React.PropTypes.func.isRequired };