summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2016-04-01 11:48:19 -0400
committerChristopher Speller <crspeller@gmail.com>2016-04-01 11:51:17 -0400
commit7e9c7ce60a90f3628888f178c27642561643abaa (patch)
tree5f4ec04e9d7d62213d8daac7ddafe8e864a5feff
parent36f611fac48536f26770357de8d5b6767bd46d2f (diff)
downloadchat-7e9c7ce60a90f3628888f178c27642561643abaa.tar.gz
chat-7e9c7ce60a90f3628888f178c27642561643abaa.tar.bz2
chat-7e9c7ce60a90f3628888f178c27642561643abaa.zip
Visiting invalid URLs and bad APIs causes redirect to error page
-rw-r--r--api/api.go2
-rw-r--r--api/context.go36
-rw-r--r--i18n/en.json24
-rw-r--r--templates/error.html24
-rw-r--r--webapp/components/error_page.jsx58
-rw-r--r--webapp/root.jsx25
6 files changed, 125 insertions, 44 deletions
diff --git a/api/api.go b/api/api.go
index 20f77e558..476047877 100644
--- a/api/api.go
+++ b/api/api.go
@@ -27,6 +27,8 @@ func InitApi() {
InitWebhook(r)
InitPreference(r)
InitLicense(r)
+ // 404 on any api route before web.go has a chance to serve it
+ Srv.Router.Handle("/api/{anything:.*}", http.HandlerFunc(Handle404))
utils.InitHTML()
}
diff --git a/api/context.go b/api/context.go
index eed035daf..0f7ba0fff 100644
--- a/api/context.go
+++ b/api/context.go
@@ -476,25 +476,23 @@ func IsPrivateIpAddress(ipAddress string) bool {
}
func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request) {
- T, locale := utils.GetTranslationsAndLocale(w, r)
- page := utils.NewHTMLTemplate("error", locale)
- page.Props["Message"] = err.Message
- page.Props["Details"] = err.DetailedError
-
- pathParts := strings.Split(r.URL.Path, "/")
- if len(pathParts) > 1 {
- page.Props["SiteURL"] = GetProtocol(r) + "://" + r.Host + "/" + pathParts[1]
- } else {
- page.Props["SiteURL"] = GetProtocol(r) + "://" + r.Host
- }
-
- page.Props["Title"] = T("api.templates.error.title", map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]})
- page.Props["Link"] = T("api.templates.error.link")
-
- w.WriteHeader(err.StatusCode)
- if rErr := page.RenderToWriter(w); rErr != nil {
- l4g.Error("Failed to create error page: " + rErr.Error() + ", Original error: " + err.Error())
- }
+ T, _ := utils.GetTranslationsAndLocale(w, r)
+
+ title := T("api.templates.error.title", map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]})
+ message := err.Message
+ details := err.DetailedError
+ link := "/"
+ linkMessage := T("api.templates.error.link")
+
+ http.Redirect(
+ w,
+ r,
+ "/error?title="+url.QueryEscape(title)+
+ "&message="+url.QueryEscape(message)+
+ "&details="+url.QueryEscape(details)+
+ "&link="+url.QueryEscape(link)+
+ "&linkmessage="+url.QueryEscape(linkMessage),
+ http.StatusTemporaryRedirect)
}
func Handle404(w http.ResponseWriter, r *http.Request) {
diff --git a/i18n/en.json b/i18n/en.json
index 7dcc351f1..41889ab3e 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -3734,5 +3734,29 @@
{
"id": "web.watcher_fail.error",
"translation": "Failed to add directory to watcher %v"
+ },
+ {
+ "id": "error.not_found.title",
+ "translation": "Page not found"
+ },
+ {
+ "id": "error.not_found.message",
+ "translation": "The page you where trying to reach does not exist."
+ },
+ {
+ "id": "error.not_found.link_message",
+ "translation": "Back to Mattermost"
+ },
+ {
+ "id": "error.generic.title",
+ "translation": "Error"
+ },
+ {
+ "id": "error.generic.message",
+ "translation": "An error has occoured."
+ },
+ {
+ "id": "error.generic.link_message",
+ "translation": "Back to Mattermost"
}
]
diff --git a/templates/error.html b/templates/error.html
deleted file mode 100644
index 5aa48098f..000000000
--- a/templates/error.html
+++ /dev/null
@@ -1,24 +0,0 @@
-{{define "error"}}
-<!DOCTYPE html>
-<html>
-{{template "head" . }}
-<body class="sticky error">
- <div class="container-fluid">
- <div class="error__container">
- <div class="error__icon">
- <i class="fa fa-exclamation-triangle"/>
- </div>
- <h2>{{.Props.Title}}</h2>
- <p>{{ .Props.Message }}</p>
- <a href="{{.Props.SiteURL}}">{{.Props.Link}}</a>
- </div>
- </div>
-</body>
-<script>
-var details = {{ .Props.Details }};
-if (details.length > 0) {
- console.log("error details: " + details);
-}
-</script>
-</html>
-{{end}}
diff --git a/webapp/components/error_page.jsx b/webapp/components/error_page.jsx
new file mode 100644
index 000000000..53f0fce82
--- /dev/null
+++ b/webapp/components/error_page.jsx
@@ -0,0 +1,58 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import $ from 'jquery';
+
+import React from 'react';
+import {Link} from 'react-router';
+
+import * as Utils from 'utils/utils.jsx';
+
+export default class ErrorPage extends React.Component {
+ componentDidMount() {
+ $('body').attr('class', 'sticky error');
+ }
+ componentWillUnmount() {
+ $('body').attr('class', '');
+ }
+ render() {
+ let title = this.props.location.query.title;
+ if (!title || title === '') {
+ title = Utils.localizeMessage('error.generic.title', 'Error');
+ }
+
+ let message = this.props.location.query.message;
+ if (!message || message === '') {
+ message = Utils.localizeMessage('error.generic.message', 'An error has occoured.');
+ }
+
+ let link = this.props.location.query.link;
+ if (!link || link === '') {
+ link = '/';
+ }
+
+ let linkMessage = this.props.location.query.linkmessage;
+ if (!linkMessage || linkMessage === '') {
+ linkMessage = Utils.localizeMessage('error.generic.link_message', 'Back to Mattermost');
+ }
+
+ return (
+ <div className='container-fluid'>
+ <div className='error__container'>
+ <div className='error__icon'>
+ <i className='fa fa-exclamation-triangle'/>
+ </div>
+ <h2>{title}</h2>
+ <p>{message}</p>
+ <Link to={link}>{linkMessage}</Link>
+ </div>
+ </div>
+ );
+ }
+}
+
+ErrorPage.defaultProps = {
+};
+ErrorPage.propTypes = {
+ location: React.PropTypes.object
+};
diff --git a/webapp/root.jsx b/webapp/root.jsx
index 9c2708506..da5980c33 100644
--- a/webapp/root.jsx
+++ b/webapp/root.jsx
@@ -10,7 +10,7 @@ import 'sass/styles.scss';
import React from 'react';
import ReactDOM from 'react-dom';
-import {Router, Route, IndexRoute, IndexRedirect, browserHistory} from 'react-router';
+import {Router, Route, IndexRoute, IndexRedirect, Redirect, browserHistory} from 'react-router';
import Root from 'components/root.jsx';
import LoggedIn from 'components/logged_in.jsx';
import NotLoggedIn from 'components/not_logged_in.jsx';
@@ -28,6 +28,7 @@ import BrowserStore from 'stores/browser_store.jsx';
import SignupTeam from 'components/signup_team.jsx';
import * as Client from 'utils/client.jsx';
import * as Websockets from 'action_creators/websocket_actions.jsx';
+import * as Utils from 'utils/utils.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import SignupTeamConfirm from 'components/signup_team_confirm.jsx';
import SignupUserComplete from 'components/signup_user_complete.jsx';
@@ -41,6 +42,7 @@ import InstalledIntegrations from 'components/backstage/installed_integrations.j
import AddIntegration from 'components/backstage/add_integration.jsx';
import AddIncomingWebhook from 'components/backstage/add_incoming_webhook.jsx';
import AddOutgoingWebhook from 'components/backstage/add_outgoing_webhook.jsx';
+import ErrorPage from 'components/error_page.jsx';
import SignupTeamComplete from 'components/signup_team_complete/components/signup_team_complete.jsx';
import WelcomePage from 'components/signup_team_complete/components/team_signup_welcome_page.jsx';
@@ -61,6 +63,13 @@ import Login from 'components/login/login.jsx';
import * as I18n from 'i18n/i18n.jsx';
+const notFoundParams = {
+ title: Utils.localizeMessage('error.not_found.title', 'Page not found'),
+ message: Utils.localizeMessage('error.not_found.message', 'The page you where trying to reach does not exist'),
+ link: '/',
+ linkmessage: Utils.localizeMessage('error.not_found.link_message', 'Back to Mattermost')
+};
+
// This is for anything that needs to be done for ALL react components.
// This runs before we start to render anything.
function preRenderSetup(callwhendone) {
@@ -219,6 +228,10 @@ function renderRootComponent() {
onEnter={onRootEnter}
>
<Route
+ path='error'
+ component={ErrorPage}
+ />
+ <Route
component={LoggedIn}
onEnter={preLoggedIn}
>
@@ -285,6 +298,11 @@ function renderRootComponent() {
}}
/>
</Route>
+ <Redirect
+ from='*'
+ to='/error'
+ query={notFoundParams}
+ />
</Route>
<Route
path='admin_console'
@@ -380,6 +398,11 @@ function renderRootComponent() {
component={LDAPToEmail}
/>
</Route>
+ <Redirect
+ from='*'
+ to='/error'
+ query={notFoundParams}
+ />
</Route>
</Route>
</Route>