github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/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/mattermost/mattermost-server/v5/model"
    17  	"github.com/mattermost/mattermost-server/v5/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  `