MM-14575 - Automatically serve static files for plugins (#10476)
* MM-14575 - Automatically serve static files for plugins * Added static handler for plugin public files * Added StaticFilesPath method to Environment for use by MainRouter * Added "static_files" property to Manifest Server * Added unit tests for these changes * MM-14575: Adding comment for cache control value * MM-14575: Moved Static Plugin Request handler to plugin_requests * Updated testing * MM-14575: Removing the StaticFiles from Manifest Server * MM-14575: Removing static files from test * MM-14575: Updating static files test * MM14575: Removing cache directive from plugin static files * MM14575: Moving plugin public directory to root * MM-14575: Updating tests for changed public directory * MM-14575: Moved compileGo to a common utils package for tests * MM-14575: Moving plugins initialization to InitPlugins find in tests * Update utils/test_files_compiler.go Adding Copyright header Co-Authored-By: happygaijin <happygaijin@users.noreply.github.com> * MM-14575: Consistent usage of static vs public name * Removing spurious newline * Comment typo Co-Authored-By: happygaijin <happygaijin@users.noreply.github.com> * Removing spurious new line Co-Authored-By: happygaijin <happygaijin@users.noreply.github.com> * MM14575: Adding a test to make sure only public files can be requested * MM-14575 Adding a test for redirects on public files
Этот коммит содержится в:
коммит произвёл
Jesse Hallam
родитель
7c9837d9b1
Коммит
ba34b4607c
107
web/web_test.go
107
web/web_test.go
@@ -5,11 +5,22 @@ package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/testlib"
|
||||
|
||||
"github.com/mattermost/mattermost-server/app"
|
||||
"github.com/mattermost/mattermost-server/config"
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/plugin"
|
||||
"github.com/mattermost/mattermost-server/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var ApiClient *model.Client4
|
||||
@@ -18,12 +29,15 @@ var URL string
|
||||
type TestHelper struct {
|
||||
App *app.App
|
||||
Server *app.Server
|
||||
Web *Web
|
||||
|
||||
BasicUser *model.User
|
||||
BasicChannel *model.Channel
|
||||
BasicTeam *model.Team
|
||||
|
||||
SystemAdminUser *model.User
|
||||
|
||||
tempWorkspace string
|
||||
}
|
||||
|
||||
func Setup() *TestHelper {
|
||||
@@ -52,7 +66,7 @@ func Setup() *TestHelper {
|
||||
}
|
||||
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
|
||||
|
||||
New(s, s.AppOptions, s.Router)
|
||||
web := New(s, s.AppOptions, s.Router)
|
||||
URL = fmt.Sprintf("http://localhost:%v", a.Srv.ListenAddr.Port)
|
||||
ApiClient = model.NewAPIv4Client(URL)
|
||||
|
||||
@@ -68,11 +82,26 @@ func Setup() *TestHelper {
|
||||
th := &TestHelper{
|
||||
App: a,
|
||||
Server: s,
|
||||
Web: web,
|
||||
}
|
||||
|
||||
return th
|
||||
}
|
||||
|
||||
func (th *TestHelper) InitPlugins() *TestHelper {
|
||||
|
||||
if th.tempWorkspace == "" {
|
||||
th.tempWorkspace, _ = testlib.SetupTestResources()
|
||||
}
|
||||
|
||||
pluginDir := filepath.Join(th.tempWorkspace, "plugins")
|
||||
webappDir := filepath.Join(th.tempWorkspace, "webapp")
|
||||
|
||||
th.App.InitPlugins(pluginDir, webappDir)
|
||||
|
||||
return th
|
||||
}
|
||||
|
||||
func (th *TestHelper) InitBasic() *TestHelper {
|
||||
th.SystemAdminUser, _ = th.App.CreateUser(&model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", EmailVerified: true, Roles: model.SYSTEM_ADMIN_ROLE_ID})
|
||||
|
||||
@@ -98,6 +127,82 @@ func (th *TestHelper) TearDown() {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicFilesRequest(t *testing.T) {
|
||||
th := Setup().InitPlugins()
|
||||
defer th.TearDown()
|
||||
|
||||
pluginDir, err := ioutil.TempDir("", "")
|
||||
require.NoError(t, err)
|
||||
webappPluginDir, err := ioutil.TempDir("", "")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(pluginDir)
|
||||
defer os.RemoveAll(webappPluginDir)
|
||||
|
||||
env, err := plugin.NewEnvironment(th.App.NewPluginAPI, pluginDir, webappPluginDir, th.App.Log)
|
||||
require.NoError(t, err)
|
||||
|
||||
pluginID := "com.mattermost.sample"
|
||||
pluginCode :=
|
||||
`
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost-server/plugin"
|
||||
)
|
||||
|
||||
type MyPlugin struct {
|
||||
plugin.MattermostPlugin
|
||||
}
|
||||
|
||||
func main() {
|
||||
plugin.ClientMain(&MyPlugin{})
|
||||
}
|
||||
|
||||
`
|
||||
// Compile and write the plugin
|
||||
backend := filepath.Join(pluginDir, pluginID, "backend.exe")
|
||||
utils.CompileGo(t, pluginCode, backend)
|
||||
|
||||
// Write the plugin.json manifest
|
||||
pluginManifest := `{"id": "com.mattermost.sample", "server": {"executable": "backend.exe"}, "settings_schema": {"settings": []}}`
|
||||
ioutil.WriteFile(filepath.Join(pluginDir, pluginID, "plugin.json"), []byte(pluginManifest), 0600)
|
||||
|
||||
// Write the test public file
|
||||
helloHTML := `Hello from the static files public folder for the com.mattermost.sample plugin!`
|
||||
htmlFolderPath := filepath.Join(pluginDir, pluginID, "public")
|
||||
os.MkdirAll(htmlFolderPath, os.ModePerm)
|
||||
htmlFilePath := filepath.Join(htmlFolderPath, "hello.html")
|
||||
|
||||
htmlFileErr := ioutil.WriteFile(htmlFilePath, []byte(helloHTML), 0600)
|
||||
assert.NoError(t, htmlFileErr)
|
||||
|
||||
nefariousHTML := `You shouldn't be able to get here!`
|
||||
htmlFileErr = ioutil.WriteFile(filepath.Join(pluginDir, pluginID, "nefarious-file-access.html"), []byte(nefariousHTML), 0600)
|
||||
assert.NoError(t, htmlFileErr)
|
||||
|
||||
manifest, activated, reterr := env.Activate(pluginID)
|
||||
require.Nil(t, reterr)
|
||||
require.NotNil(t, manifest)
|
||||
require.True(t, activated)
|
||||
|
||||
th.App.SetPluginsEnvironment(env)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/plugins/com.mattermost.sample/public/hello.html", nil)
|
||||
res := httptest.NewRecorder()
|
||||
th.Web.MainRouter.ServeHTTP(res, req)
|
||||
assert.Equal(t, helloHTML, res.Body.String())
|
||||
|
||||
req, _ = http.NewRequest("GET", "/plugins/com.mattermost.sample/nefarious-file-access.html", nil)
|
||||
res = httptest.NewRecorder()
|
||||
th.Web.MainRouter.ServeHTTP(res, req)
|
||||
assert.Equal(t, 404, res.Code)
|
||||
|
||||
req, _ = http.NewRequest("GET", "/plugins/com.mattermost.sample/public/../nefarious-file-access.html", nil)
|
||||
res = httptest.NewRecorder()
|
||||
th.Web.MainRouter.ServeHTTP(res, req)
|
||||
assert.Equal(t, 301, res.Code)
|
||||
}
|
||||
|
||||
/* Test disabled for now so we don't requrie the client to build. Maybe re-enable after client gets moved out.
|
||||
func TestStatic(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
Ссылка в новой задаче
Block a user