From 812f1d5a69ed21c6f18a9d8799cf449bfd0ccf25 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 4 Apr 2017 19:21:31 -0400 Subject: [PATCH] PLT-5702 Added special error page for private browsing error message (#5985) --- components/error_page.jsx | 112 +++++++++++++++++++++++++++++++------- i18n/en.json | 2 - stores/browser_store.jsx | 9 +-- utils/constants.jsx | 6 ++ utils/markdown.jsx | 4 ++ 5 files changed, 105 insertions(+), 28 deletions(-) diff --git a/components/error_page.jsx b/components/error_page.jsx index 7de488f06493..9bd2c722d5ba 100644 --- a/components/error_page.jsx +++ b/components/error_page.jsx @@ -2,14 +2,27 @@ // See License.txt for license information. import $ from 'jquery'; - import React from 'react'; +import {FormattedMessage} from 'react-intl'; import {Link} from 'react-router/es6'; -import * as Utils from 'utils/utils.jsx'; +import {ErrorPageTypes} from 'utils/constants.jsx'; import * as TextFormatting from 'utils/text_formatting.jsx'; +import * as Utils from 'utils/utils.jsx'; export default class ErrorPage extends React.Component { + static propTypes = { + location: React.PropTypes.object.isRequired + }; + + constructor(props) { + super(props); + + this.renderTitle = this.renderTitle.bind(this); + this.renderMessage = this.renderMessage.bind(this); + this.renderLink = this.renderLink.bind(this); + } + componentDidMount() { $('body').attr('class', 'sticky error'); } @@ -18,30 +31,97 @@ export default class ErrorPage extends React.Component { $('body').attr('class', ''); } - render() { - let title = this.props.location.query.title; - if (!title || title === '') { - title = Utils.localizeMessage('error.generic.title', 'Error'); + linkFilter(link) { + return link.startsWith('https://docs.mattermost.com') || link.startsWith('https://forum.mattermost.org'); + } + + renderTitle() { + if (this.props.location.query.type === ErrorPageTypes.LOCAL_STORAGE) { + return ( + + ); + } + + if (this.props.location.query.title) { + return this.props.location.query.title; + } + + return Utils.localizeMessage('error.generic.title', 'Error'); + } + + renderMessage() { + if (this.props.location.query.type === ErrorPageTypes.LOCAL_STORAGE) { + return ( +
+ +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ ); } let message = this.props.location.query.message; - if (!message || message === '') { + if (!message) { message = Utils.localizeMessage('error.generic.message', 'An error has occoured.'); } + return
; + } + + renderLink() { let link = this.props.location.query.link; - if (!link || link === '') { + if (link) { + link = link.trim(); + } else { link = '/'; - } else if (link.startsWith('javascript:') || link.startsWith('vbscript:') || link.startsWith('data:')) { // eslint-disable-line no-script-url - // Sanitize out any script links + } + + if (!link.startsWith('/')) { + // Only allow relative links link = '/'; } let linkMessage = this.props.location.query.linkmessage; - if (!linkMessage || linkMessage === '') { + if (!linkMessage) { linkMessage = Utils.localizeMessage('error.generic.link_message', 'Back to Mattermost'); } + return ( + + {linkMessage} + + ); + } + + render() { + const title = this.renderTitle(); + const message = this.renderMessage(); + const link = this.renderLink(); + return (
@@ -49,16 +129,10 @@ export default class ErrorPage extends React.Component {

{title}

-
- {linkMessage} + {message} + {link}
); } } - -ErrorPage.defaultProps = { -}; -ErrorPage.propTypes = { - location: React.PropTypes.object -}; diff --git a/i18n/en.json b/i18n/en.json index 1d304b52efab..47ff01f108fa 100755 --- a/i18n/en.json +++ b/i18n/en.json @@ -1307,8 +1307,6 @@ "error.not_found.link_message": "Back to Mattermost", "error.not_found.message": "The page you were trying to reach does not exist", "error.not_found.title": "Page not found", - "error.not_supported.message": "Private browsing is not supported", - "error.not_supported.title": "Browser not supported", "error_bar.expired": "Enterprise license is expired and some features may be disabled. Please renew.", "error_bar.expiring": "Enterprise license expires on {date}. Please renew.", "error_bar.past_grace": "Enterprise license is expired and some features may be disabled. Please contact your System Administrator for details.", diff --git a/stores/browser_store.jsx b/stores/browser_store.jsx index 2da6b896f6df..123a7d8b916e 100644 --- a/stores/browser_store.jsx +++ b/stores/browser_store.jsx @@ -3,12 +3,7 @@ import {browserHistory} from 'react-router/es6'; import * as Utils from 'utils/utils.jsx'; -import Constants from 'utils/constants.jsx'; - -const notSupportedParams = { - title: Utils.localizeMessage('error.not_supported.title', 'Browser not supported'), - message: Utils.localizeMessage('error.not_supported.message', 'Private browsing is not supported') -}; +import {Constants, ErrorPageTypes} from 'utils/constants.jsx'; function getPrefix() { if (global.window.mm_current_user_id) { @@ -200,7 +195,7 @@ class BrowserStoreClass { sessionStorage.removeItem('__testSession__'); } catch (e) { // Session storage not usable, website is unusable - browserHistory.push(window.location.origin + '/error?title=' + notSupportedParams.title + '&message=' + notSupportedParams.message); + browserHistory.push('/error?type=' + ErrorPageTypes.LOCAL_STORAGE); } this.hasCheckedLocalStorage = true; diff --git a/utils/constants.jsx b/utils/constants.jsx index 8428f7121343..3678b0b073f1 100644 --- a/utils/constants.jsx +++ b/utils/constants.jsx @@ -281,6 +281,10 @@ export const StatTypes = keyMirror({ MONTHLY_ACTIVE_USERS: null }); +export const ErrorPageTypes = { + LOCAL_STORAGE: 'local_storage' +}; + export const Constants = { Preferences, SocketEvents, @@ -290,6 +294,8 @@ export const Constants = { UserSearchOptions, TutorialSteps, PostTypes, + ErrorPageTypes, + IGNORE_POST_TYPES: [PostTypes.JOIN_LEAVE, PostTypes.JOIN_CHANNEL, PostTypes.LEAVE_CHANNEL, PostTypes.REMOVE_FROM_CHANNEL, PostTypes.ADD_TO_CHANNEL, PostTypes.ADD_REMOVE], PayloadSources: keyMirror({ diff --git a/utils/markdown.jsx b/utils/markdown.jsx index db8e739e67ff..29547b7e1cb0 100644 --- a/utils/markdown.jsx +++ b/utils/markdown.jsx @@ -163,6 +163,10 @@ class MattermostMarkdownRenderer extends marked.Renderer { link(href, title, text) { let outHref = href; + if (this.formattingOptions.linkFilter && !this.formattingOptions.linkFilter(outHref)) { + return text; + } + try { let unescaped = unescape(href); try {