diff --git a/NOTICE.txt b/NOTICE.txt index 364f96611f04..e7931290dc3f 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -56,7 +56,8 @@ The most popular front-end framework for developing responsive, mobile first pro The MIT License (MIT) -Copyright (c) 2011-2018 Twitter, Inc. +Copyright (c) 2011-2019 Twitter, Inc. +Copyright (c) 2011-2019 The Bootstrap Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -855,12 +856,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ## katex -This product contains 'katex' by Khan Academy. +This product contains 'katex' by GitHub user "KaTeX". Fast math typesetting for the web. * HOMEPAGE: - * https://github.com/Khan/KaTeX#readme + * https://katex.org/ * LICENSE: MIT @@ -1509,6 +1510,29 @@ SOFTWARE. --- +## popmotion + +This product contains 'popmotion' by Matt Perry. + +A functional, reactive motion library. + +* HOMEPAGE: + * https://popmotion.io/ + +* LICENSE: MIT + +The MIT License (MIT) + +Copyright © 2019 Framer BV + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- + ## prop-types This product contains 'prop-types' by Facebook. @@ -1970,6 +1994,50 @@ SOFTWARE. --- +## react-transition-group + +This product contains 'react-transition-group' by React Community. + +A react component toolset for managing animations + +* HOMEPAGE: + * https://github.com/reactjs/react-transition-group#readme + +* LICENSE: BSD-3-Clause + +BSD 3-Clause License + +Copyright (c) 2018, React Community +Forked from React (https://github.com/facebook/react) Copyright 2013-present, Facebook, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--- + ## rebound This product contains 'rebound' by Facebook. @@ -2358,64 +2426,3 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---- - -## popmotion - -The MIT License (MIT) - -Copyright (c) 2018 Inventing With Monster Ltd - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ---- - -## react-transition-group - -BSD 3-Clause License - -Copyright (c) 2018, React Community -Forked from React (https://github.com/facebook/react) Copyright 2013-present, Facebook, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/actions/emoji_actions.jsx b/actions/emoji_actions.jsx index 7ec846bdda3d..6ef9158324a0 100644 --- a/actions/emoji_actions.jsx +++ b/actions/emoji_actions.jsx @@ -65,9 +65,7 @@ export function addRecentEmoji(alias) { } else if (emoji.name) { name = emoji.name; } else { - // Use the alias the user input or the first alias - // This puts the user chosen alias in recent emojis - name = emoji.aliases.find((aliasOption) => alias === aliasOption) || emoji.aliases[0]; + name = emoji.aliases[0]; } const index = recentEmojis.indexOf(name); diff --git a/actions/views/mfa.js b/actions/views/mfa.js index 8ea3d19dfdec..8fc709161ad1 100644 --- a/actions/views/mfa.js +++ b/actions/views/mfa.js @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import * as UserActions from 'mattermost-redux/actions/users'; -import {getConfig} from 'mattermost-redux/selectors/entities/general'; import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; export function activateMfa(code) { @@ -29,14 +28,3 @@ export function generateMfaSecret() { }; } -export function checkMfa(loginId) { - return (dispatch, getState) => { - const config = getConfig(getState()); - - if (config.EnableMultifactorAuthentication !== 'true') { - return Promise.resolve({data: false}); - } - - return dispatch(UserActions.checkMfa(loginId)); - }; -} diff --git a/actions/views/mfa.test.js b/actions/views/mfa.test.js index 3b444eb0ed2f..350723e76df3 100644 --- a/actions/views/mfa.test.js +++ b/actions/views/mfa.test.js @@ -7,7 +7,6 @@ import * as UserActions from 'mattermost-redux/actions/users'; import { activateMfa, - checkMfa, deactivateMfa, generateMfaSecret, } from 'actions/views/mfa'; @@ -71,24 +70,4 @@ describe('actions/views/mfa', () => { expect(UserActions.generateMfaSecret).toHaveBeenCalledWith(currentUserId); }); }); - - describe('checkMfa', () => { - it('should skip actually checking for MFA if MFA is disabled', async () => { - const store = configureStore({ - entities: { - general: { - config: { - EnableMultifactorAuthentication: 'false', - }, - }, - }, - }); - - const loginId = 'user'; - const result = await store.dispatch(checkMfa(loginId)); - - expect(result).toEqual({data: false}); - expect(UserActions.checkMfa).not.toHaveBeenCalled(); - }); - }); }); diff --git a/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.jsx.snap b/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.jsx.snap index 792147f4bad4..5ff32e44775a 100644 --- a/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.jsx.snap +++ b/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.jsx.snap @@ -5,8 +5,12 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou className="wrapper--fixed" >

+

+

+

+ -

+

+ )} /> @@ -76,7 +74,6 @@ export default class ClaimController extends React.PureComponent { )} @@ -88,7 +85,6 @@ export default class ClaimController extends React.PureComponent { email={email} siteName={this.props.siteName} ldapLoginFieldName={this.props.ldapLoginFieldName} - checkMfa={this.props.actions.checkMfa} /> )} /> diff --git a/components/claim/components/email_to_ldap.jsx b/components/claim/components/email_to_ldap.jsx index bcf63bf2a740..d0db39f1ccb7 100644 --- a/components/claim/components/email_to_ldap.jsx +++ b/components/claim/components/email_to_ldap.jsx @@ -15,7 +15,6 @@ export default class EmailToLDAP extends React.Component { email: PropTypes.string, siteName: PropTypes.string, ldapLoginFieldName: PropTypes.string, - checkMfa: PropTypes.func.isRequired, }; constructor(props) { @@ -69,21 +68,7 @@ export default class EmailToLDAP extends React.Component { state.ldapPassword = ldapPassword; this.setState(state); - this.props.checkMfa(this.props.email).then((result) => { - if (result.error) { - this.setState({ - error: result.error.message, - }); - return; - } - - const requiresMfa = result.data; - if (requiresMfa) { - this.setState({showMfa: true}); - } else { - this.submit(this.props.email, password, '', ldapId, ldapPassword); - } - }); + this.submit(this.props.email, password, '', ldapId, ldapPassword); } submit(loginId, password, token, ldapId, ldapPassword) { @@ -99,20 +84,24 @@ export default class EmailToLDAP extends React.Component { } }, (err) => { - switch (err.id) { - case 'ent.ldap.do_login.user_not_registered.app_error': - case 'ent.ldap.do_login.user_filtered.app_error': - case 'ent.ldap.do_login.matched_to_many_users.app_error': - this.setState({ldapError: err.message, showMfa: false}); - break; - case 'ent.ldap.do_login.invalid_password.app_error': - this.setState({ldapPasswordError: err.message, showMfa: false}); - break; - case 'api.user.check_user_password.invalid.app_error': - this.setState({passwordError: err.message, showMfa: false}); - break; - default: - this.setState({serverError: err.message, showMfa: false}); + if (!this.state.showMfa && err.server_error_id === 'mfa.validate_token.authenticate.app_error') { + this.setState({showMfa: true}); + } else { + switch (err.id) { + case 'ent.ldap.do_login.user_not_registered.app_error': + case 'ent.ldap.do_login.user_filtered.app_error': + case 'ent.ldap.do_login.matched_to_many_users.app_error': + this.setState({ldapError: err.message, showMfa: false}); + break; + case 'ent.ldap.do_login.invalid_password.app_error': + this.setState({ldapPasswordError: err.message, showMfa: false}); + break; + case 'api.user.check_user_password.invalid.app_error': + this.setState({passwordError: err.message, showMfa: false}); + break; + default: + this.setState({serverError: err.message, showMfa: false}); + } } } ); diff --git a/components/claim/components/email_to_oauth.jsx b/components/claim/components/email_to_oauth.jsx index af841775936e..f817c134a601 100644 --- a/components/claim/components/email_to_oauth.jsx +++ b/components/claim/components/email_to_oauth.jsx @@ -17,7 +17,6 @@ export default class EmailToOAuth extends React.PureComponent { newType: PropTypes.string, email: PropTypes.string, siteName: PropTypes.string, - checkMfa: PropTypes.func.isRequired, }; constructor(props) { @@ -45,21 +44,7 @@ export default class EmailToOAuth extends React.PureComponent { state.error = null; this.setState(state); - this.props.checkMfa(this.props.email).then((result) => { - if (result.error) { - this.setState({ - error: result.error.message, - }); - return; - } - - const requiresMfa = result.data; - if (requiresMfa) { - this.setState({showMfa: true}); - } else { - this.submit(this.props.email, password, ''); - } - }); + this.submit(this.props.email, password, ''); } submit(loginId, password, token) { @@ -74,7 +59,11 @@ export default class EmailToOAuth extends React.PureComponent { } }, (err) => { - this.setState({error: err.message, showMfa: false}); + if (!this.state.showMfa && err.server_error_id === 'mfa.validate_token.authenticate.app_error') { + this.setState({showMfa: true}); + } else { + this.setState({error: err.message, showMfa: false}); + } } ); } diff --git a/components/claim/components/ldap_to_email.jsx b/components/claim/components/ldap_to_email.jsx index 228c372d203b..9faa6255c7c8 100644 --- a/components/claim/components/ldap_to_email.jsx +++ b/components/claim/components/ldap_to_email.jsx @@ -13,7 +13,6 @@ export default class LDAPToEmail extends React.Component { static propTypes = { email: PropTypes.string, passwordConfig: PropTypes.object, - checkMfa: PropTypes.func.isRequired, switchLdapToEmail: PropTypes.func.isRequired, }; @@ -74,49 +73,25 @@ export default class LDAPToEmail extends React.Component { state.ldapPassword = ldapPassword; this.setState(state); - this.props.checkMfa(this.props.email).then((result) => { - if (result.error) { - this.setState({ - error: result.error.message, - }); - return; - } - - const requiresMfa = result.data; - if (requiresMfa) { - this.setState({ - showMfa: true, - }); - } else { - this.submit(this.props.email, password, '', ldapPassword); - } - }); + this.submit(this.props.email, password, '', ldapPassword); } submit(loginId, password, token, ldapPassword) { - this.props.switchLdapToEmail( - ldapPassword || this.state.ldapPassword, - this.props.email, - password, - token). - then(({data, error: err}) => { - if (data && data.follow_link) { - window.location.href = data.follow_link; - } else if (err) { - if (err.server_error_id.startsWith('model.user.is_valid.pwd')) { - this.setState({passwordError: err.message, showMfa: false}); - } else { - switch (err.server_error_id) { - case 'ent.ldap.do_login.invalid_password.app_error': - this.setState({ldapPasswordError: err.message, showMfa: false}); - break; - default: - this.setState({serverError: err.message, showMfa: false}); - } - } + this.props.switchLdapToEmail(ldapPassword || this.state.ldapPassword, this.props.email, password, token).then(({data, error: err}) => { + if (data && data.follow_link) { + window.location.href = data.follow_link; + } else if (err) { + if (err.server_error_id.startsWith('model.user.is_valid.pwd')) { + this.setState({passwordError: err.message, showMfa: false}); + } else if (err.server_error_id === 'ent.ldap.do_login.invalid_password.app_error') { + this.setState({ldapPasswordError: err.message, showMfa: false}); + } else if (!this.state.showMfa && err.server_error_id === 'mfa.validate_token.authenticate.app_error') { + this.setState({showMfa: true}); + } else { + this.setState({serverError: err.message, showMfa: false}); } } - ); + }); } render() { diff --git a/components/claim/components/ldap_to_email.test.js b/components/claim/components/ldap_to_email.test.js index 7a08ac2b0e8e..7490e375ac58 100644 --- a/components/claim/components/ldap_to_email.test.js +++ b/components/claim/components/ldap_to_email.test.js @@ -10,7 +10,6 @@ describe('components/claim/components/ldap_to_email.jsx', () => { const requiredProps = { email: '', passwordConfig: {}, - checkMfa: jest.fn(), switchLdapToEmail: jest.fn(() => Promise.resolve({data: true})), }; diff --git a/components/claim/index.js b/components/claim/index.js index 8c3c5da010d8..2e06a49fd51e 100644 --- a/components/claim/index.js +++ b/components/claim/index.js @@ -7,7 +7,6 @@ import {bindActionCreators} from 'redux'; import {switchLdapToEmail} from 'mattermost-redux/actions/users'; import {getConfig} from 'mattermost-redux/selectors/entities/general'; -import {checkMfa} from 'actions/views/mfa'; import {getPasswordConfig} from 'utils/utils.jsx'; import ClaimController from './claim_controller.jsx'; @@ -27,7 +26,6 @@ function mapStateToProps(state) { function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ - checkMfa, switchLdapToEmail, }, dispatch), }; diff --git a/components/common/comment_icon.jsx b/components/common/comment_icon.jsx index e4591b1f889a..a55e25958c61 100644 --- a/components/common/comment_icon.jsx +++ b/components/common/comment_icon.jsx @@ -6,13 +6,13 @@ import React from 'react'; import {OverlayTrigger, Tooltip} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; +import {Locations} from 'utils/constants.jsx'; + import ReplyIcon from 'components/svg/reply_icon'; -import * as Utils from 'utils/utils.jsx'; export default class CommentIcon extends React.PureComponent { static propTypes = { - idPrefix: PropTypes.string.isRequired, - idCount: PropTypes.number, + location: PropTypes.oneOf([Locations.CENTER, Locations.SEARCH]).isRequired, handleCommentClick: PropTypes.func.isRequired, searchStyle: PropTypes.string, commentCount: PropTypes.number, @@ -21,10 +21,10 @@ export default class CommentIcon extends React.PureComponent { }; static defaultProps = { - idCount: -1, searchStyle: '', commentCount: 0, extraClass: '', + location: Locations.CENTER, }; render() { @@ -41,13 +41,6 @@ export default class CommentIcon extends React.PureComponent { iconStyle = iconStyle + ' ' + this.props.searchStyle; } - let selectorId = this.props.idPrefix; - if (this.props.idCount > -1) { - selectorId += this.props.idCount; - } - - const id = Utils.createSafeId(this.props.idPrefix + '_' + this.props.postId); - const tooltip = (