github.com/adacta-ru/mattermost-server/v6@v6.0.0/utils/subpath_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package utils_test 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 "testing" 13 14 "github.com/stretchr/testify/require" 15 16 "github.com/adacta-ru/mattermost-server/v6/model" 17 "github.com/adacta-ru/mattermost-server/v6/utils" 18 ) 19 20 func TestUpdateAssetsSubpathFromConfig(t *testing.T) { 21 t.Run("dev build", func(t *testing.T) { 22 var oldBuildNumber = model.BuildNumber 23 model.BuildNumber = "dev" 24 defer func() { 25 model.BuildNumber = oldBuildNumber 26 }() 27 28 err := utils.UpdateAssetsSubpathFromConfig(nil) 29 require.NoError(t, err) 30 }) 31 32 t.Run("IS_CI=true", func(t *testing.T) { 33 err := os.Setenv("IS_CI", "true") 34 require.NoError(t, err) 35 defer func() { 36 os.Unsetenv("IS_CI") 37 }() 38 39 err = utils.UpdateAssetsSubpathFromConfig(nil) 40 require.NoError(t, err) 41 }) 42 43 t.Run("no config", func(t *testing.T) { 44 tempDir, err := ioutil.TempDir("", "test_update_assets_subpath") 45 require.NoError(t, err) 46 defer os.RemoveAll(tempDir) 47 os.Chdir(tempDir) 48 49 err = utils.UpdateAssetsSubpathFromConfig(nil) 50 require.Error(t, err) 51 }) 52 } 53 54 func TestUpdateAssetsSubpath(t *testing.T) { 55 t.Run("no client dir", func(t *testing.T) { 56 tempDir, err := ioutil.TempDir("", "test_update_assets_subpath") 57 require.NoError(t, err) 58 defer os.RemoveAll(tempDir) 59 os.Chdir(tempDir) 60 61 err = utils.UpdateAssetsSubpath("/") 62 require.Error(t, err) 63 }) 64 65 t.Run("valid", func(t *testing.T) { 66 tempDir, err := ioutil.TempDir("", "test_update_assets_subpath") 67 require.NoError(t, err) 68 defer os.RemoveAll(tempDir) 69 os.Chdir(tempDir) 70 71 err = os.Mkdir(model.CLIENT_DIR, 0700) 72 require.NoError(t, err) 73 74 testCases := []struct { 75 Description string 76 RootHTML string 77 MainCSS string 78 ManifestJSON string 79 Subpath string 80 ExpectedError error 81 ExpectedRootHTML string 82 ExpectedMainCSS string 83 ExpectedManifestJSON string 84 }{ 85 { 86 "no changes required, empty subpath provided", 87 baseRootHtml, 88 baseCss, 89 baseManifestJson, 90 "", 91 nil, 92 baseRootHtml, 93 baseCss, 94 baseManifestJson, 95 }, 96 { 97 "no changes required", 98 baseRootHtml, 99 baseCss, 100 baseManifestJson, 101 "/", 102 nil, 103 baseRootHtml, 104 baseCss, 105 baseManifestJson, 106 }, 107 { 108 "content security policy not found (missing quotes)", 109 contentSecurityPolicyNotFoundHtml, 110 baseCss, 111 baseManifestJson, 112 "/subpath", 113 fmt.Errorf("failed to find 'Content-Security-Policy' meta tag to rewrite"), 114 contentSecurityPolicyNotFoundHtml, 115 baseCss, 116 baseManifestJson, 117 }, 118 { 119 "content security policy not found (missing unsafe-eval)", 120 contentSecurityPolicyNotFound2Html, 121 baseCss, 122 baseManifestJson, 123 "/subpath", 124 fmt.Errorf("failed to find 'Content-Security-Policy' meta tag to rewrite"), 125 contentSecurityPolicyNotFound2Html, 126 baseCss, 127 baseManifestJson, 128 }, 129 { 130 "subpath", 131 baseRootHtml, 132 baseCss, 133 baseManifestJson, 134 "/subpath", 135 nil, 136 subpathRootHtml, 137 subpathCss, 138 subpathManifestJson, 139 }, 140 { 141 "new subpath from old", 142 subpathRootHtml, 143 subpathCss, 144 subpathManifestJson, 145 "/nested/subpath", 146 nil, 147 newSubpathRootHtml, 148 newSubpathCss, 149 newSubpathManifestJson, 150 }, 151 { 152 "resetting to /", 153 subpathRootHtml, 154 subpathCss, 155 baseManifestJson, 156 "/", 157 nil, 158 baseRootHtml, 159 baseCss, 160 baseManifestJson, 161 }, 162 } 163 164 for _, testCase := range testCases { 165 t.Run(testCase.Description, func(t *testing.T) { 166 ioutil.WriteFile(filepath.Join(tempDir, model.CLIENT_DIR, "root.html"), []byte(testCase.RootHTML), 0700) 167 ioutil.WriteFile(filepath.Join(tempDir, model.CLIENT_DIR, "main.css"), []byte(testCase.MainCSS), 0700) 168 ioutil.WriteFile(filepath.Join(tempDir, model.CLIENT_DIR, "manifest.json"), []byte(testCase.ManifestJSON), 0700) 169 err := utils.UpdateAssetsSubpath(testCase.Subpath) 170 if testCase.ExpectedError != nil { 171 require.Equal(t, testCase.ExpectedError, err) 172 } else { 173 require.NoError(t, err) 174 } 175 176 contents, err := ioutil.ReadFile(filepath.Join(tempDir, model.CLIENT_DIR, "root.html")) 177 require.NoError(t, err) 178 179 // Rewrite the expected and contents for simpler diffs when failed. 180 expectedRootHTML := strings.Replace(testCase.ExpectedRootHTML, ">", ">\n", -1) 181 contentsStr := strings.Replace(string(contents), ">", ">\n", -1) 182 require.Equal(t, expectedRootHTML, contentsStr) 183 184 contents, err = ioutil.ReadFile(filepath.Join(tempDir, model.CLIENT_DIR, "main.css")) 185 require.NoError(t, err) 186 require.Equal(t, testCase.ExpectedMainCSS, string(contents)) 187 188 contents, err = ioutil.ReadFile(filepath.Join(tempDir, model.CLIENT_DIR, "manifest.json")) 189 require.NoError(t, err) 190 require.Equal(t, testCase.ExpectedManifestJSON, string(contents)) 191 }) 192 } 193 }) 194 } 195 196 func TestGetSubpathFromConfig(t *testing.T) { 197 testCases := []struct { 198 Description string 199 SiteURL *string 200 ExpectedError bool 201 ExpectedSubpath string 202 }{ 203 { 204 "empty SiteURL", 205 sToP(""), 206 false, 207 "/", 208 }, 209 { 210 "invalid SiteURL", 211 sToP("cache_object:foo/bar"), 212 true, 213 "", 214 }, 215 { 216 "nil SiteURL", 217 nil, 218 false, 219 "/", 220 }, 221 { 222 "no trailing slash", 223 sToP("http://localhost:8065"), 224 false, 225 "/", 226 }, 227 { 228 "trailing slash", 229 sToP("http://localhost:8065/"), 230 false, 231 "/", 232 }, 233 { 234 "subpath, no trailing slash", 235 sToP("http://localhost:8065/subpath"), 236 false, 237 "/subpath", 238 }, 239 { 240 "trailing slash", 241 sToP("http://localhost:8065/subpath/"), 242 false, 243 "/subpath", 244 }, 245 } 246 247 for _, testCase := range testCases { 248 t.Run(testCase.Description, func(t *testing.T) { 249 config := &model.Config{ 250 ServiceSettings: model.ServiceSettings{ 251 SiteURL: testCase.SiteURL, 252 }, 253 } 254 255 subpath, err := utils.GetSubpathFromConfig(config) 256 if testCase.ExpectedError { 257 require.Error(t, err) 258 } else { 259 require.NoError(t, err) 260 } 261 262 require.Equal(t, testCase.ExpectedSubpath, subpath) 263 }) 264 } 265 } 266 267 func sToP(s string) *string { 268 return &s 269 } 270 271 const contentSecurityPolicyNotFoundHtml = `<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <meta http-equiv=Content-Security-Policy content="script-src 'self' cdn.rudderlabs.com/ js.stripe.com/v3"> <meta http-equiv=X-UA-Compatible content="IE=edge"> <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> <meta name=robots content="noindex, nofollow"> <meta name=referrer content=no-referrer> <title>Mattermost</title> <meta name=apple-mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-status-bar-style content=default> <meta name=mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-title content=Mattermost> <meta name=application-name content=Mattermost> <meta name=format-detection content="telephone=no"> <link rel=apple-touch-icon sizes=57x57 href=/static/files/78b7e73b41b8731ce2c41c870ecc8886.png> <link rel=apple-touch-icon sizes=60x60 href=/static/files/51d00ffd13afb6d74fd8f6dfdeef768a.png> <link rel=apple-touch-icon sizes=72x72 href=/static/files/23645596f8f78f017bd4d457abb855c4.png> <link rel=apple-touch-icon sizes=76x76 href=/static/files/26e9d72f472663a00b4b206149459fab.png> <link rel=apple-touch-icon sizes=144x144 href=/static/files/7bd91659bf3fc8c68fcd45fc1db9c630.png> <link rel=apple-touch-icon sizes=120x120 href=/static/files/fa69ffe11eb334aaef5aece8d848ca62.png> <link rel=apple-touch-icon sizes=152x152 href=/static/files/f046777feb6ab12fc43b8f9908b1db35.png> <link rel=icon type=image/png sizes=16x16 href=/static/files/02b96247d275680adaaabf01c71c571d.png> <link rel=icon type=image/png sizes=32x32 href=/static/files/1d9020f201a6762421cab8d30624fdd8.png> <link rel=icon type=image/png sizes=96x96 href=/static/files/fe23af39ae98d77dc26ae8586565970f.png> <link rel=icon type=image/png sizes=192x192 href=/static/files/d7ff68a7675f84337cc154c3d4abe713.png> <link rel=manifest href=/static/files/a985ad72552ad069537d6eea81e719c7.json> <link rel=stylesheet class=code_theme> <style>.error-screen{font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding-top:50px;max-width:750px;font-size:14px;color:#333;margin:auto;display:none;line-height:1.5}.error-screen h2{font-size:30px;font-weight:400;line-height:1.2}.error-screen ul{padding-left:15px;line-height:1.7;margin-top:0;margin-bottom:10px}.error-screen hr{color:#ddd;margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.error-screen-visible{display:block}</style> <link href="/static/main.364fd054d7a6d741efc6.css" rel="stylesheet"><script type="text/javascript" src="/static/main.e49599ac425584ffead5.js"></script></head> <body class=font--open_sans> <div id=root> <div class=error-screen> <h2>Cannot connect to Mattermost</h2> <hr/> <p>We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.</p> <br/> </div> <div class=loading-screen style=position:relative> <div class=loading__content> <div class="round round-1"></div> <div class="round round-2"></div> <div class="round round-3"></div> </div> </div> </div> <noscript> To use Mattermost, please enable JavaScript. </noscript> </body> </html>` 272 273 const contentSecurityPolicyNotFound2Html = `<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <meta http-equiv=Content-Security-Policy content="script-src 'self' cdn.rudderlabs.com/ js.stripe.com/v3 'unsafe-eval'"> <meta http-equiv=X-UA-Compatible content="IE=edge"> <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> <meta name=robots content="noindex, nofollow"> <meta name=referrer content=no-referrer> <title>Mattermost</title> <meta name=apple-mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-status-bar-style content=default> <meta name=mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-title content=Mattermost> <meta name=application-name content=Mattermost> <meta name=format-detection content="telephone=no"> <link rel=apple-touch-icon sizes=57x57 href=/static/files/78b7e73b41b8731ce2c41c870ecc8886.png> <link rel=apple-touch-icon sizes=60x60 href=/static/files/51d00ffd13afb6d74fd8f6dfdeef768a.png> <link rel=apple-touch-icon sizes=72x72 href=/static/files/23645596f8f78f017bd4d457abb855c4.png> <link rel=apple-touch-icon sizes=76x76 href=/static/files/26e9d72f472663a00b4b206149459fab.png> <link rel=apple-touch-icon sizes=144x144 href=/static/files/7bd91659bf3fc8c68fcd45fc1db9c630.png> <link rel=apple-touch-icon sizes=120x120 href=/static/files/fa69ffe11eb334aaef5aece8d848ca62.png> <link rel=apple-touch-icon sizes=152x152 href=/static/files/f046777feb6ab12fc43b8f9908b1db35.png> <link rel=icon type=image/png sizes=16x16 href=/static/files/02b96247d275680adaaabf01c71c571d.png> <link rel=icon type=image/png sizes=32x32 href=/static/files/1d9020f201a6762421cab8d30624fdd8.png> <link rel=icon type=image/png sizes=96x96 href=/static/files/fe23af39ae98d77dc26ae8586565970f.png> <link rel=icon type=image/png sizes=192x192 href=/static/files/d7ff68a7675f84337cc154c3d4abe713.png> <link rel=manifest href=/static/files/a985ad72552ad069537d6eea81e719c7.json> <link rel=stylesheet class=code_theme> <style>.error-screen{font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding-top:50px;max-width:750px;font-size:14px;color:#333;margin:auto;display:none;line-height:1.5}.error-screen h2{font-size:30px;font-weight:400;line-height:1.2}.error-screen ul{padding-left:15px;line-height:1.7;margin-top:0;margin-bottom:10px}.error-screen hr{color:#ddd;margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.error-screen-visible{display:block}</style> <link href="/static/main.364fd054d7a6d741efc6.css" rel="stylesheet"><script type="text/javascript" src="/static/main.e49599ac425584ffead5.js"></script></head> <body class=font--open_sans> <div id=root> <div class=error-screen> <h2>Cannot connect to Mattermost</h2> <hr/> <p>We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.</p> <br/> </div> <div class=loading-screen style=position:relative> <div class=loading__content> <div class="round round-1"></div> <div class="round round-2"></div> <div class="round round-3"></div> </div> </div> </div> <noscript> To use Mattermost, please enable JavaScript. </noscript> </body> </html>` 274 275 const baseRootHtml = `<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <meta http-equiv="Content-Security-Policy" content="script-src 'self' cdn.rudderlabs.com/ js.stripe.com/v3"> <meta http-equiv=X-UA-Compatible content="IE=edge"> <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> <meta name=robots content="noindex, nofollow"> <meta name=referrer content=no-referrer> <title>Mattermost</title> <meta name=apple-mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-status-bar-style content=default> <meta name=mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-title content=Mattermost> <meta name=application-name content=Mattermost> <meta name=format-detection content="telephone=no"> <link rel=apple-touch-icon sizes=57x57 href=/static/files/78b7e73b41b8731ce2c41c870ecc8886.png> <link rel=apple-touch-icon sizes=60x60 href=/static/files/51d00ffd13afb6d74fd8f6dfdeef768a.png> <link rel=apple-touch-icon sizes=72x72 href=/static/files/23645596f8f78f017bd4d457abb855c4.png> <link rel=apple-touch-icon sizes=76x76 href=/static/files/26e9d72f472663a00b4b206149459fab.png> <link rel=apple-touch-icon sizes=144x144 href=/static/files/7bd91659bf3fc8c68fcd45fc1db9c630.png> <link rel=apple-touch-icon sizes=120x120 href=/static/files/fa69ffe11eb334aaef5aece8d848ca62.png> <link rel=apple-touch-icon sizes=152x152 href=/static/files/f046777feb6ab12fc43b8f9908b1db35.png> <link rel=icon type=image/png sizes=16x16 href=/static/files/02b96247d275680adaaabf01c71c571d.png> <link rel=icon type=image/png sizes=32x32 href=/static/files/1d9020f201a6762421cab8d30624fdd8.png> <link rel=icon type=image/png sizes=96x96 href=/static/files/fe23af39ae98d77dc26ae8586565970f.png> <link rel=icon type=image/png sizes=192x192 href=/static/files/d7ff68a7675f84337cc154c3d4abe713.png> <link rel=manifest href=/static/files/a985ad72552ad069537d6eea81e719c7.json> <link rel=stylesheet class=code_theme> <style>.error-screen{font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding-top:50px;max-width:750px;font-size:14px;color:#333;margin:auto;display:none;line-height:1.5}.error-screen h2{font-size:30px;font-weight:400;line-height:1.2}.error-screen ul{padding-left:15px;line-height:1.7;margin-top:0;margin-bottom:10px}.error-screen hr{color:#ddd;margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.error-screen-visible{display:block}</style> <link href="/static/main.364fd054d7a6d741efc6.css" rel="stylesheet"><script type="text/javascript" src="/static/main.e49599ac425584ffead5.js"></script></head> <body class=font--open_sans> <div id=root> <div class=error-screen> <h2>Cannot connect to Mattermost</h2> <hr/> <p>We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.</p> <br/> </div> <div class=loading-screen style=position:relative> <div class=loading__content> <div class="round round-1"></div> <div class="round round-2"></div> <div class="round round-3"></div> </div> </div> </div> <noscript> To use Mattermost, please enable JavaScript. </noscript> </body> </html>` 276 277 const baseCss = `@font-face{font-family:FontAwesome;src:url(/static/files/674f50d287a8c48dc19ba404d20fe713.eot);src:url(/static/files/674f50d287a8c48dc19ba404d20fe713.eot?#iefix&v=4.7.0) format("embedded-opentype"),url(/static/files/af7ae505a9eed503f8b8e6982036873e.woff2) format("woff2"),url(/static/files/fee66e712a8a08eef5805a46892932ad.woff) format("woff"),url(/static/files/b06871f281fee6b241d60582ae9369b9.ttf) format("truetype"),url(/static/files/677433a0892aaed7b7d2628c313c9775.svg#fontawesomeregular) format("svg");font-weight:400;font-style:normal}` 278 279 const subpathRootHtml = `<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <meta http-equiv="Content-Security-Policy" content="script-src 'self' cdn.rudderlabs.com/ js.stripe.com/v3 'sha256-tPOjw+tkVs9axL78ZwGtYl975dtyPHB6LYKAO2R3gR4='"> <meta http-equiv=X-UA-Compatible content="IE=edge"> <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> <meta name=robots content="noindex, nofollow"> <meta name=referrer content=no-referrer> <title>Mattermost</title> <meta name=apple-mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-status-bar-style content=default> <meta name=mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-title content=Mattermost> <meta name=application-name content=Mattermost> <meta name=format-detection content="telephone=no"> <link rel=apple-touch-icon sizes=57x57 href=/subpath/static/files/78b7e73b41b8731ce2c41c870ecc8886.png> <link rel=apple-touch-icon sizes=60x60 href=/subpath/static/files/51d00ffd13afb6d74fd8f6dfdeef768a.png> <link rel=apple-touch-icon sizes=72x72 href=/subpath/static/files/23645596f8f78f017bd4d457abb855c4.png> <link rel=apple-touch-icon sizes=76x76 href=/subpath/static/files/26e9d72f472663a00b4b206149459fab.png> <link rel=apple-touch-icon sizes=144x144 href=/subpath/static/files/7bd91659bf3fc8c68fcd45fc1db9c630.png> <link rel=apple-touch-icon sizes=120x120 href=/subpath/static/files/fa69ffe11eb334aaef5aece8d848ca62.png> <link rel=apple-touch-icon sizes=152x152 href=/subpath/static/files/f046777feb6ab12fc43b8f9908b1db35.png> <link rel=icon type=image/png sizes=16x16 href=/subpath/static/files/02b96247d275680adaaabf01c71c571d.png> <link rel=icon type=image/png sizes=32x32 href=/subpath/static/files/1d9020f201a6762421cab8d30624fdd8.png> <link rel=icon type=image/png sizes=96x96 href=/subpath/static/files/fe23af39ae98d77dc26ae8586565970f.png> <link rel=icon type=image/png sizes=192x192 href=/subpath/static/files/d7ff68a7675f84337cc154c3d4abe713.png> <link rel=manifest href=/subpath/static/files/a985ad72552ad069537d6eea81e719c7.json> <link rel=stylesheet class=code_theme> <style>.error-screen{font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding-top:50px;max-width:750px;font-size:14px;color:#333;margin:auto;display:none;line-height:1.5}.error-screen h2{font-size:30px;font-weight:400;line-height:1.2}.error-screen ul{padding-left:15px;line-height:1.7;margin-top:0;margin-bottom:10px}.error-screen hr{color:#ddd;margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.error-screen-visible{display:block}</style><script>window.publicPath='/subpath/static/'</script> <link href="/subpath/static/main.364fd054d7a6d741efc6.css" rel="stylesheet"><script type="text/javascript" src="/subpath/static/main.e49599ac425584ffead5.js"></script></head> <body class=font--open_sans> <div id=root> <div class=error-screen> <h2>Cannot connect to Mattermost</h2> <hr/> <p>We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.</p> <br/> </div> <div class=loading-screen style=position:relative> <div class=loading__content> <div class="round round-1"></div> <div class="round round-2"></div> <div class="round round-3"></div> </div> </div> </div> <noscript> To use Mattermost, please enable JavaScript. </noscript> </body> </html>` 280 281 const subpathCss = `@font-face{font-family:FontAwesome;src:url(/subpath/static/files/674f50d287a8c48dc19ba404d20fe713.eot);src:url(/subpath/static/files/674f50d287a8c48dc19ba404d20fe713.eot?#iefix&v=4.7.0) format("embedded-opentype"),url(/subpath/static/files/af7ae505a9eed503f8b8e6982036873e.woff2) format("woff2"),url(/subpath/static/files/fee66e712a8a08eef5805a46892932ad.woff) format("woff"),url(/subpath/static/files/b06871f281fee6b241d60582ae9369b9.ttf) format("truetype"),url(/subpath/static/files/677433a0892aaed7b7d2628c313c9775.svg#fontawesomeregular) format("svg");font-weight:400;font-style:normal}` 282 283 const newSubpathRootHtml = `<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <meta http-equiv="Content-Security-Policy" content="script-src 'self' cdn.rudderlabs.com/ js.stripe.com/v3 'sha256-mbRaPRRpWz6MNkX9SyXWMJ8XnWV4w/DoqK2M0ryUAvc='"> <meta http-equiv=X-UA-Compatible content="IE=edge"> <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> <meta name=robots content="noindex, nofollow"> <meta name=referrer content=no-referrer> <title>Mattermost</title> <meta name=apple-mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-status-bar-style content=default> <meta name=mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-title content=Mattermost> <meta name=application-name content=Mattermost> <meta name=format-detection content="telephone=no"> <link rel=apple-touch-icon sizes=57x57 href=/nested/subpath/static/files/78b7e73b41b8731ce2c41c870ecc8886.png> <link rel=apple-touch-icon sizes=60x60 href=/nested/subpath/static/files/51d00ffd13afb6d74fd8f6dfdeef768a.png> <link rel=apple-touch-icon sizes=72x72 href=/nested/subpath/static/files/23645596f8f78f017bd4d457abb855c4.png> <link rel=apple-touch-icon sizes=76x76 href=/nested/subpath/static/files/26e9d72f472663a00b4b206149459fab.png> <link rel=apple-touch-icon sizes=144x144 href=/nested/subpath/static/files/7bd91659bf3fc8c68fcd45fc1db9c630.png> <link rel=apple-touch-icon sizes=120x120 href=/nested/subpath/static/files/fa69ffe11eb334aaef5aece8d848ca62.png> <link rel=apple-touch-icon sizes=152x152 href=/nested/subpath/static/files/f046777feb6ab12fc43b8f9908b1db35.png> <link rel=icon type=image/png sizes=16x16 href=/nested/subpath/static/files/02b96247d275680adaaabf01c71c571d.png> <link rel=icon type=image/png sizes=32x32 href=/nested/subpath/static/files/1d9020f201a6762421cab8d30624fdd8.png> <link rel=icon type=image/png sizes=96x96 href=/nested/subpath/static/files/fe23af39ae98d77dc26ae8586565970f.png> <link rel=icon type=image/png sizes=192x192 href=/nested/subpath/static/files/d7ff68a7675f84337cc154c3d4abe713.png> <link rel=manifest href=/nested/subpath/static/files/a985ad72552ad069537d6eea81e719c7.json> <link rel=stylesheet class=code_theme> <style>.error-screen{font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding-top:50px;max-width:750px;font-size:14px;color:#333;margin:auto;display:none;line-height:1.5}.error-screen h2{font-size:30px;font-weight:400;line-height:1.2}.error-screen ul{padding-left:15px;line-height:1.7;margin-top:0;margin-bottom:10px}.error-screen hr{color:#ddd;margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.error-screen-visible{display:block}</style><script>window.publicPath='/nested/subpath/static/'</script> <link href="/nested/subpath/static/main.364fd054d7a6d741efc6.css" rel="stylesheet"><script type="text/javascript" src="/nested/subpath/static/main.e49599ac425584ffead5.js"></script></head> <body class=font--open_sans> <div id=root> <div class=error-screen> <h2>Cannot connect to Mattermost</h2> <hr/> <p>We're having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work, please verify that your computer is connected to the internet.</p> <br/> </div> <div class=loading-screen style=position:relative> <div class=loading__content> <div class="round round-1"></div> <div class="round round-2"></div> <div class="round round-3"></div> </div> </div> </div> <noscript> To use Mattermost, please enable JavaScript. </noscript> </body> </html>` 284 285 const newSubpathCss = `@font-face{font-family:FontAwesome;src:url(/nested/subpath/static/files/674f50d287a8c48dc19ba404d20fe713.eot);src:url(/nested/subpath/static/files/674f50d287a8c48dc19ba404d20fe713.eot?#iefix&v=4.7.0) format("embedded-opentype"),url(/nested/subpath/static/files/af7ae505a9eed503f8b8e6982036873e.woff2) format("woff2"),url(/nested/subpath/static/files/fee66e712a8a08eef5805a46892932ad.woff) format("woff"),url(/nested/subpath/static/files/b06871f281fee6b241d60582ae9369b9.ttf) format("truetype"),url(/nested/subpath/static/files/677433a0892aaed7b7d2628c313c9775.svg#fontawesomeregular) format("svg");font-weight:400;font-style:normal}` 286 287 const baseManifestJson = `{ 288 "icons": [ 289 { 290 "src": "/static/icon_96x96.png", 291 "sizes": "96x96", 292 "type": "image/png" 293 }, 294 { 295 "src": "/static/icon_32x32.png", 296 "sizes": "32x32", 297 "type": "image/png" 298 }, 299 { 300 "src": "/static/icon_16x16.png", 301 "sizes": "16x16", 302 "type": "image/png" 303 }, 304 { 305 "src": "/static/icon_76x76.png", 306 "sizes": "76x76", 307 "type": "image/png" 308 }, 309 { 310 "src": "/static/icon_72x72.png", 311 "sizes": "72x72", 312 "type": "image/png" 313 }, 314 { 315 "src": "/static/icon_60x60.png", 316 "sizes": "60x60", 317 "type": "image/png" 318 }, 319 { 320 "src": "/static/icon_57x57.png", 321 "sizes": "57x57", 322 "type": "image/png" 323 }, 324 { 325 "src": "/static/icon_152x152.png", 326 "sizes": "152x152", 327 "type": "image/png" 328 }, 329 { 330 "src": "/static/icon_144x144.png", 331 "sizes": "144x144", 332 "type": "image/png" 333 }, 334 { 335 "src": "/static/icon_120x120.png", 336 "sizes": "120x120", 337 "type": "image/png" 338 }, 339 { 340 "src": "/static/icon_192x192.png", 341 "sizes": "192x192", 342 "type": "image/png" 343 } 344 ], 345 "name": "Mattermost", 346 "short_name": "Mattermost", 347 "orientation": "any", 348 "display": "standalone", 349 "start_url": ".", 350 "description": "Mattermost is an open source, self-hosted Slack-alternative", 351 "background_color": "#ffffff" 352 } 353 ` 354 355 const subpathManifestJson = `{ 356 "icons": [ 357 { 358 "src": "/subpath/static/icon_96x96.png", 359 "sizes": "96x96", 360 "type": "image/png" 361 }, 362 { 363 "src": "/subpath/static/icon_32x32.png", 364 "sizes": "32x32", 365 "type": "image/png" 366 }, 367 { 368 "src": "/subpath/static/icon_16x16.png", 369 "sizes": "16x16", 370 "type": "image/png" 371 }, 372 { 373 "src": "/subpath/static/icon_76x76.png", 374 "sizes": "76x76", 375 "type": "image/png" 376 }, 377 { 378 "src": "/subpath/static/icon_72x72.png", 379 "sizes": "72x72", 380 "type": "image/png" 381 }, 382 { 383 "src": "/subpath/static/icon_60x60.png", 384 "sizes": "60x60", 385 "type": "image/png" 386 }, 387 { 388 "src": "/subpath/static/icon_57x57.png", 389 "sizes": "57x57", 390 "type": "image/png" 391 }, 392 { 393 "src": "/subpath/static/icon_152x152.png", 394 "sizes": "152x152", 395 "type": "image/png" 396 }, 397 { 398 "src": "/subpath/static/icon_144x144.png", 399 "sizes": "144x144", 400 "type": "image/png" 401 }, 402 { 403 "src": "/subpath/static/icon_120x120.png", 404 "sizes": "120x120", 405 "type": "image/png" 406 }, 407 { 408 "src": "/subpath/static/icon_192x192.png", 409 "sizes": "192x192", 410 "type": "image/png" 411 } 412 ], 413 "name": "Mattermost", 414 "short_name": "Mattermost", 415 "orientation": "any", 416 "display": "standalone", 417 "start_url": ".", 418 "description": "Mattermost is an open source, self-hosted Slack-alternative", 419 "background_color": "#ffffff" 420 } 421 ` 422 423 const newSubpathManifestJson = `{ 424 "icons": [ 425 { 426 "src": "/nested/subpath/static/icon_96x96.png", 427 "sizes": "96x96", 428 "type": "image/png" 429 }, 430 { 431 "src": "/nested/subpath/static/icon_32x32.png", 432 "sizes": "32x32", 433 "type": "image/png" 434 }, 435 { 436 "src": "/nested/subpath/static/icon_16x16.png", 437 "sizes": "16x16", 438 "type": "image/png" 439 }, 440 { 441 "src": "/nested/subpath/static/icon_76x76.png", 442 "sizes": "76x76", 443 "type": "image/png" 444 }, 445 { 446 "src": "/nested/subpath/static/icon_72x72.png", 447 "sizes": "72x72", 448 "type": "image/png" 449 }, 450 { 451 "src": "/nested/subpath/static/icon_60x60.png", 452 "sizes": "60x60", 453 "type": "image/png" 454 }, 455 { 456 "src": "/nested/subpath/static/icon_57x57.png", 457 "sizes": "57x57", 458 "type": "image/png" 459 }, 460 { 461 "src": "/nested/subpath/static/icon_152x152.png", 462 "sizes": "152x152", 463 "type": "image/png" 464 }, 465 { 466 "src": "/nested/subpath/static/icon_144x144.png", 467 "sizes": "144x144", 468 "type": "image/png" 469 }, 470 { 471 "src": "/nested/subpath/static/icon_120x120.png", 472 "sizes": "120x120", 473 "type": "image/png" 474 }, 475 { 476 "src": "/nested/subpath/static/icon_192x192.png", 477 "sizes": "192x192", 478 "type": "image/png" 479 } 480 ], 481 "name": "Mattermost", 482 "short_name": "Mattermost", 483 "orientation": "any", 484 "display": "standalone", 485 "start_url": ".", 486 "description": "Mattermost is an open source, self-hosted Slack-alternative", 487 "background_color": "#ffffff" 488 } 489 `