From 956291773406fc719001c66b2e18d7a51ac7facf Mon Sep 17 00:00:00 2001
From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com>
Date: Thu, 15 Aug 2019 14:30:40 -0400
Subject: [PATCH] [MM-16677] New unsupported browser page (#11858)
* Added OSVersion to unsupported browser template (and some test code)
* [MM-17569] Working prototype (not functional) of unsupported browser page
* WIP
* WIP
* [MM-17571] Unsupported browser page template logic
* WIP
* [MM-17572][MM-17573] Added browsers and tested for unsupported under IE and Safari
* Clean-up
* Added missing license header
* Fixed a test
* Blank commit to force CI update
* PR feedback
* oops
---
i18n/en.json | 96 +++++-
templates/unsupported_browser.html | 475 ++++++++++++++++++-----------
templates/unsupported_browser.js | 38 +++
web/static.go | 17 +-
web/unsupported_browser.go | 156 ++++++++++
web/web.go | 5 +-
web/web_test.go | 4 +-
7 files changed, 602 insertions(+), 189 deletions(-)
create mode 100644 templates/unsupported_browser.js
create mode 100644 web/unsupported_browser.go
diff --git a/i18n/en.json b/i18n/en.json
index f223f309f9..dbc99b2e2c 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -7323,12 +7323,100 @@
"translation": "Unable to parse incoming data"
},
{
- "id": "web.error.unsupported_browser.message",
- "translation": "Your current browser is not supported. Please upgrade to one of the following browsers:"
+ "id": "web.error.unsupported_browser.browser_get_latest.chrome",
+ "translation": "Get the latest Chrome browser"
},
{
- "id": "web.error.unsupported_browser.title",
- "translation": "Unsupported Browser"
+ "id": "web.error.unsupported_browser.browser_get_latest.firefox",
+ "translation": "Get the latest Firefox browser"
+ },
+ {
+ "id": "web.error.unsupported_browser.browser_get_latest.safari",
+ "translation": "Get the latest Safari browser"
+ },
+ {
+ "id": "web.error.unsupported_browser.browser_title.chrome",
+ "translation": "Google Chrome"
+ },
+ {
+ "id": "web.error.unsupported_browser.browser_title.edge",
+ "translation": "Microsoft Edge"
+ },
+ {
+ "id": "web.error.unsupported_browser.browser_title.firefox",
+ "translation": "Firefox"
+ },
+ {
+ "id": "web.error.unsupported_browser.browser_title.safari",
+ "translation": "Safari"
+ },
+ {
+ "id": "web.error.unsupported_browser.download",
+ "translation": "Download the App"
+ },
+ {
+ "id": "web.error.unsupported_browser.download_app_or_upgrade_browser",
+ "translation": "Download the Mattermost app or use a supported browser for a better experience."
+ },
+ {
+ "id": "web.error.unsupported_browser.download_the_app",
+ "translation": "Download the App"
+ },
+ {
+ "id": "web.error.unsupported_browser.install_guide.mac",
+ "translation": "Install Guide"
+ },
+ {
+ "id": "web.error.unsupported_browser.install_guide.windows",
+ "translation": "Install Guide"
+ },
+ {
+ "id": "web.error.unsupported_browser.learn_more",
+ "translation": "Learn more about supported browsers."
+ },
+ {
+ "id": "web.error.unsupported_browser.min_browser_version.chrome",
+ "translation": "Version 61+"
+ },
+ {
+ "id": "web.error.unsupported_browser.min_browser_version.edge",
+ "translation": "Version 44+"
+ },
+ {
+ "id": "web.error.unsupported_browser.min_browser_version.firefox",
+ "translation": "Version 60+"
+ },
+ {
+ "id": "web.error.unsupported_browser.min_browser_version.safari",
+ "translation": "Version 12+"
+ },
+ {
+ "id": "web.error.unsupported_browser.min_os_version.mac",
+ "translation": "macOS 10.9+"
+ },
+ {
+ "id": "web.error.unsupported_browser.min_os_version.windows",
+ "translation": "Windows 7+"
+ },
+ {
+ "id": "web.error.unsupported_browser.no_longer_support",
+ "translation": "We no longer support this browser"
+ },
+ {
+ "id": "web.error.unsupported_browser.no_longer_support_version",
+ "translation": "We no longer support this version of your browser"
+ },
+ {
+ "id": "web.error.unsupported_browser.open_system_browser.edge",
+ "translation": "Open Edge"
+ },
+ {
+ "id": "web.error.unsupported_browser.system_browser_make_default",
+ "translation": "Make default"
+ },
+ {
+ "id": "web.error.unsupported_browser.system_browser_or",
+ "translation": "or"
},
{
"id": "web.get_access_token.internal_saving.app_error",
diff --git a/templates/unsupported_browser.html b/templates/unsupported_browser.html
index f5c515230a..dc901b7e0a 100644
--- a/templates/unsupported_browser.html
+++ b/templates/unsupported_browser.html
@@ -1,178 +1,301 @@
-{{define "unsupported_browser"}}
-
-
-
-
-
-
-
-

-
-
- {{.Props.Title}}
-
-
-
-
-
+{{define "unsupported_browser-browser"}}
+
+
+

+
{{.Title}}
+
{{.SupportedVersionString}}
+
+
+

+
{{.GetLatestString}}
+
+
+{{end}}
+{{define "unsupported_browser-system_browser"}}
+
+
+

+
{{.Title}}
+
{{.SupportedVersionString}}
+
+
+

+
+
{{.OrString}}
+
+
{{.MakeDefaultString}}
+
+
+
+{{end}}
+{{define "unsupported_browser-app"}}
+
+
+

+
{{.Title}}
+
{{.SupportedVersionString}}
+
+
+

+
+
+
+
+{{end}}
+{{define "unsupported_browser"}}
+
+
+
+
+
+
+
+
+
+
+ {{.Props.NoLongerSupportString}}
+
+
+ {{.Props.DownloadAppOrUpgradeBrowserString}}
+
+
+ {{template "unsupported_browser-app" .Props.App}}
+
+ {{range .Props.Browsers}}
+ {{template "unsupported_browser-browser" .}}
+ {{end}}
+ {{if .Props.SystemBrowser}}
+ {{template "unsupported_browser-system_browser" .Props.SystemBrowser}}
+ {{end}}
+
+
+
+
+
{{end}}
diff --git a/templates/unsupported_browser.js b/templates/unsupported_browser.js
new file mode 100644
index 0000000000..ecd82fca7d
--- /dev/null
+++ b/templates/unsupported_browser.js
@@ -0,0 +1,38 @@
+function onHover(element, prefix) {
+ element.className += " container-hover";
+ var unHoverElement = element.querySelector('.' + prefix + ':not(.hidden)');
+ var hoverElement = element.querySelector('.' + prefix + '-hover.hidden');
+ if (unHoverElement && hoverElement) {
+ unHoverElement.className += " hidden";
+ hoverElement.className = hoverElement.className.replace(/\bhidden\b/g, "");
+ }
+}
+function onUnHover(element, prefix) {
+ element.className = element.className.replace(/\bcontainer-hover\b/g, "");
+ var unHoverElement = element.querySelector('.' + prefix + '.hidden');
+ var hoverElement = element.querySelector('.' + prefix + '-hover:not(.hidden)');
+ if (unHoverElement && hoverElement) {
+ hoverElement.className += " hidden";
+ unHoverElement.className = unHoverElement.className.replace(/\bhidden\b/g, "");
+ }
+}
+
+document.addEventListener('DOMContentLoaded', function () {
+ var hovers = document.querySelectorAll("div[data-mattermost-hover]");
+ for (var i = 0; i < hovers.length; i++) {
+ var element = hovers[i];
+ element.addEventListener("mouseover", function(e) {
+ onHover(e.currentTarget, e.currentTarget.getAttribute("data-mattermost-hover"));
+ });
+ element.addEventListener("mouseout", function(e) {
+ onUnHover(e.currentTarget, e.currentTarget.getAttribute("data-mattermost-hover"))
+ });
+ }
+ var clicks = document.querySelectorAll("div[data-mattermost-click], button[data-mattermost-click]");
+ for (var i = 0; i < clicks.length; i++) {
+ var element = clicks[i];
+ element.addEventListener("click", function(e) {
+ window.open(e.currentTarget.getAttribute('data-mattermost-click'), '_blank');
+ });
+ };
+});
\ No newline at end of file
diff --git a/web/static.go b/web/static.go
index 57267ab80a..847f962d76 100644
--- a/web/static.go
+++ b/web/static.go
@@ -45,6 +45,7 @@ func (w *Web) InitStatic() {
w.MainRouter.PathPrefix("/static/plugins/").Handler(pluginHandler)
w.MainRouter.PathPrefix("/static/").Handler(staticHandler)
w.MainRouter.Handle("/robots.txt", http.HandlerFunc(robotsHandler))
+ w.MainRouter.Handle("/unsupported_browser.js", http.HandlerFunc(unsupportedBrowserScriptHandler))
w.MainRouter.Handle("/{anything:.*}", w.NewStaticHandler(root)).Methods("GET")
// When a subpath is defined, it's necessary to handle redirects without a
@@ -60,11 +61,7 @@ func (w *Web) InitStatic() {
func root(c *Context, w http.ResponseWriter, r *http.Request) {
if !CheckClientCompatability(r.UserAgent()) {
- w.Header().Set("Cache-Control", "no-store")
- page := utils.NewHTMLTemplate(c.App.HTMLTemplates(), "unsupported_browser")
- page.Props["Title"] = c.App.T("web.error.unsupported_browser.title")
- page.Props["Message"] = c.App.T("web.error.unsupported_browser.message")
- page.RenderToWriter(w)
+ renderUnsuppportedBrowser(c.App, w, r)
return
}
@@ -97,3 +94,13 @@ func robotsHandler(w http.ResponseWriter, r *http.Request) {
}
w.Write(robotsTxt)
}
+
+func unsupportedBrowserScriptHandler(w http.ResponseWriter, r *http.Request) {
+ if strings.HasSuffix(r.URL.Path, "/") {
+ http.NotFound(w, r)
+ return
+ }
+
+ templatesDir, _ := fileutils.FindDir("templates")
+ http.ServeFile(w, r, filepath.Join(templatesDir, "unsupported_browser.js"))
+}
diff --git a/web/unsupported_browser.go b/web/unsupported_browser.go
new file mode 100644
index 0000000000..8e5f09d64e
--- /dev/null
+++ b/web/unsupported_browser.go
@@ -0,0 +1,156 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package web
+
+import (
+ "net/http"
+
+ "github.com/avct/uasurfer"
+
+ "github.com/mattermost/mattermost-server/app"
+ "github.com/mattermost/mattermost-server/utils"
+)
+
+// MattermostApp describes downloads for the Mattermost App
+type MattermostApp struct {
+ LogoSrc string
+ Title string
+ SupportedVersionString string
+ Label string
+ Link string
+ InstallGuide string
+ InstallGuideLink string
+}
+
+// Browser describes a browser with a download link
+type Browser struct {
+ LogoSrc string
+ Title string
+ SupportedVersionString string
+ Src string
+ GetLatestString string
+}
+
+// SystemBrowser describes a browser but includes 2 links: one to open the local browser, and one to make it default
+type SystemBrowser struct {
+ LogoSrc string
+ Title string
+ SupportedVersionString string
+ LabelOpen string
+ LinkOpen string
+ LinkMakeDefault string
+ OrString string
+ MakeDefaultString string
+}
+
+func renderUnsuppportedBrowser(app *app.App, w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Cache-Control", "no-store")
+ page := utils.NewHTMLTemplate(app.HTMLTemplates(), "unsupported_browser")
+
+ // User Agent info
+ ua := uasurfer.Parse(r.UserAgent())
+ isWindows := ua.OS.Platform.String() == "PlatformWindows"
+ isWindows10 := isWindows && ua.OS.Version.Major == 10
+ isMacOSX := ua.OS.Name.String() == "OSMacOSX" && ua.OS.Version.Major == 10
+ isSafari := ua.Browser.Name.String() == "BrowserSafari"
+
+ // Basic heading translations
+ if isSafari {
+ page.Props["NoLongerSupportString"] = app.T("web.error.unsupported_browser.no_longer_support_version")
+ } else {
+ page.Props["NoLongerSupportString"] = app.T("web.error.unsupported_browser.no_longer_support")
+ }
+ page.Props["DownloadAppOrUpgradeBrowserString"] = app.T("web.error.unsupported_browser.download_app_or_upgrade_browser")
+ page.Props["LearnMoreString"] = app.T("web.error.unsupported_browser.learn_more")
+
+ // Mattermost app version
+ if isWindows {
+ page.Props["App"] = renderMattermostAppWindows(app)
+ } else if isMacOSX {
+ page.Props["App"] = renderMattermostAppMac(app)
+ }
+
+ // Browsers to download
+ // Show a link to Safari if you're using safari and it's outdated
+ // Can't show on Mac all the time because there's no way to open it via URI
+ browsers := []Browser{renderBrowserChrome(app), renderBrowserFirefox(app)}
+ if isSafari {
+ browsers = append(browsers, renderBrowserSafari(app))
+ }
+ page.Props["Browsers"] = browsers
+
+ // If on Windows 10, show link to Edge
+ if isWindows10 {
+ page.Props["SystemBrowser"] = renderSystemBrowserEdge(app, r)
+ }
+
+ page.RenderToWriter(w)
+}
+
+func renderMattermostAppMac(app *app.App) MattermostApp {
+ return MattermostApp{
+ "/static/images/browser-icons/mac.png",
+ app.T("web.error.unsupported_browser.download_the_app"),
+ app.T("web.error.unsupported_browser.min_os_version.mac"),
+ app.T("web.error.unsupported_browser.download"),
+ "https://mattermost.com/download/#mattermostApps",
+ app.T("web.error.unsupported_browser.install_guide.mac"),
+ "https://docs.mattermost.com/install/desktop.html#mac-os-x-10-9",
+ }
+}
+
+func renderMattermostAppWindows(app *app.App) MattermostApp {
+ return MattermostApp{
+ "/static/images/browser-icons/windows.svg",
+ app.T("web.error.unsupported_browser.download_the_app"),
+ app.T("web.error.unsupported_browser.min_os_version.windows"),
+ app.T("web.error.unsupported_browser.download"),
+ "https://mattermost.com/download/#mattermostApps",
+ app.T("web.error.unsupported_browser.install_guide.windows"),
+ "https://docs.mattermost.com/install/desktop.html#windows-10-windows-8-1-windows-7",
+ }
+}
+
+func renderBrowserChrome(app *app.App) Browser {
+ return Browser{
+ "/static/images/browser-icons/chrome.svg",
+ app.T("web.error.unsupported_browser.browser_title.chrome"),
+ app.T("web.error.unsupported_browser.min_browser_version.chrome"),
+ "http://www.google.com/chrome",
+ app.T("web.error.unsupported_browser.browser_get_latest.chrome"),
+ }
+}
+
+func renderBrowserFirefox(app *app.App) Browser {
+ return Browser{
+ "/static/images/browser-icons/firefox.svg",
+ app.T("web.error.unsupported_browser.browser_title.firefox"),
+ app.T("web.error.unsupported_browser.min_browser_version.firefox"),
+ "https://www.mozilla.org/en-CA/firefox/new/",
+ app.T("web.error.unsupported_browser.browser_get_latest.firefox"),
+ }
+}
+
+func renderBrowserSafari(app *app.App) Browser {
+ return Browser{
+ "/static/images/browser-icons/safari.svg",
+ app.T("web.error.unsupported_browser.browser_title.safari"),
+ app.T("web.error.unsupported_browser.min_browser_version.safari"),
+ "macappstore://showUpdatesPage",
+ app.T("web.error.unsupported_browser.browser_get_latest.safari"),
+ }
+}
+
+func renderSystemBrowserEdge(app *app.App, r *http.Request) SystemBrowser {
+ return SystemBrowser{
+ "/static/images/browser-icons/edge.svg",
+ app.T("web.error.unsupported_browser.browser_title.edge"),
+ app.T("web.error.unsupported_browser.min_browser_version.edge"),
+ app.T("web.error.unsupported_browser.open_system_browser.edge"),
+ "microsoft-edge:http://" + r.Host + r.RequestURI, //TODO: Can we get HTTP or HTTPS? If someone's server doesn't have a redirect this won't work
+ "ms-settings:defaultapps",
+ app.T("web.error.unsupported_browser.system_browser_or"),
+ app.T("web.error.unsupported_browser.system_browser_make_default"),
+ }
+}
diff --git a/web/web.go b/web/web.go
index fdbc74db0e..cf750055d1 100644
--- a/web/web.go
+++ b/web/web.go
@@ -44,15 +44,16 @@ func New(config configservice.ConfigService, globalOptions app.AppOptionCreator,
// Due to the complexities of UA detection and the ramifications of a misdetection
// only older Safari and IE browsers throw incompatibility errors.
// Map should be of minimum required browser version.
+// -1 means that the browser is not supported in any version.
var browserMinimumSupported = map[string]int{
- "BrowserIE": 11,
+ "BrowserIE": 12,
"BrowserSafari": 9,
}
func CheckClientCompatability(agentString string) bool {
ua := uasurfer.Parse(agentString)
- if version, exist := browserMinimumSupported[ua.Browser.Name.String()]; exist && ua.Browser.Version.Major < version {
+ if version, exist := browserMinimumSupported[ua.Browser.Name.String()]; exist && (ua.Browser.Version.Major < version || version < 0) {
return false
}
diff --git a/web/web_test.go b/web/web_test.go
index 9464f3b81a..f9c663ec81 100644
--- a/web/web_test.go
+++ b/web/web_test.go
@@ -244,8 +244,8 @@ func TestCheckClientCompatability(t *testing.T) {
{"Franz 4.0.4", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Franz/4.0.4 Chrome/52.0.2743.82 Electron/1.3.1 Safari/537.36", true},
{"Edge 14", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393", true},
{"Internet Explorer 9", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0", false},
- {"Internet Explorer 11", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", true},
- {"Internet Explorer 11 2", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; Zoom 3.6.0; rv:11.0) like Gecko", true},
+ {"Internet Explorer 11", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", false},
+ {"Internet Explorer 11 2", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; Zoom 3.6.0; rv:11.0) like Gecko", false},
{"Internet Explorer 11 (Compatibility Mode) 1", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET CLR 1.1.4322; InfoPath.3; Zoom 3.6.0)", false},
{"Internet Explorer 11 (Compatibility Mode) 2", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; Zoom 3.6.0)", false},
{"Safari 9", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Safari/604.1.38", true},