summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2018-07-27 05:25:53 -0700
committerJoram Wilander <jwawilander@gmail.com>2018-07-27 08:25:53 -0400
commit026f0152a8fdc81d9d96c9d62321a78ef65d837b (patch)
treef986df6073db16b6ce3ca0bfeb3cfe328960125d /app
parent90e5e279c175b238d58432acb5eb6422ddfe22e7 (diff)
downloadchat-026f0152a8fdc81d9d96c9d62321a78ef65d837b.tar.gz
chat-026f0152a8fdc81d9d96c9d62321a78ef65d837b.tar.bz2
chat-026f0152a8fdc81d9d96c9d62321a78ef65d837b.zip
Adding FileWillBeUploaded plugin hook (#9169)
* Adding file upload hook. * Adding hook test for FileWillBeUploaded * Some debugging fixes. * Fix typo. * Fixing double close * Fix capitalization on docs.
Diffstat (limited to 'app')
-rw-r--r--app/file.go36
-rw-r--r--app/plugin_api.go9
-rw-r--r--app/plugin_hooks_test.go68
3 files changed, 105 insertions, 8 deletions
diff --git a/app/file.go b/app/file.go
index 8cee3d740..b0c80da16 100644
--- a/app/file.go
+++ b/app/file.go
@@ -28,6 +28,7 @@ import (
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/utils"
)
@@ -366,7 +367,7 @@ func (a *App) UploadFiles(teamId string, channelId string, userId string, files
io.Copy(buf, file)
data := buf.Bytes()
- info, err := a.DoUploadFile(time.Now(), teamId, channelId, userId, filenames[i], data)
+ info, data, err := a.DoUploadFileExpectModification(time.Now(), teamId, channelId, userId, filenames[i], data)
if err != nil {
return nil, err
}
@@ -390,6 +391,11 @@ func (a *App) UploadFiles(teamId string, channelId string, userId string, files
}
func (a *App) DoUploadFile(now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, *model.AppError) {
+ info, _, err := a.DoUploadFileExpectModification(now, rawTeamId, rawChannelId, rawUserId, rawFilename, data)
+ return info, err
+}
+
+func (a *App) DoUploadFileExpectModification(now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, []byte, *model.AppError) {
filename := filepath.Base(rawFilename)
teamId := filepath.Base(rawTeamId)
channelId := filepath.Base(rawChannelId)
@@ -398,7 +404,7 @@ func (a *App) DoUploadFile(now time.Time, rawTeamId string, rawChannelId string,
info, err := model.GetInfoForBytes(filename, data)
if err != nil {
err.StatusCode = http.StatusBadRequest
- return nil, err
+ return nil, data, err
}
if orientation, err := getImageOrientation(bytes.NewReader(data)); err == nil &&
@@ -419,7 +425,7 @@ func (a *App) DoUploadFile(now time.Time, rawTeamId string, rawChannelId string,
// Check dimensions before loading the whole thing into memory later on
if info.Width*info.Height > MaxImageSize {
err := model.NewAppError("uploadFile", "api.file.upload_file.large_image.app_error", map[string]interface{}{"Filename": filename}, "", http.StatusBadRequest)
- return nil, err
+ return nil, data, err
}
nameWithoutExtension := filename[:strings.LastIndex(filename, ".")]
@@ -427,15 +433,33 @@ func (a *App) DoUploadFile(now time.Time, rawTeamId string, rawChannelId string,
info.ThumbnailPath = pathPrefix + nameWithoutExtension + "_thumb.jpg"
}
+ if a.PluginsReady() {
+ pluginContext := &plugin.Context{}
+ var rejectionReason string
+ a.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
+ var newBytes bytes.Buffer
+ info, rejectionReason = hooks.FileWillBeUploaded(pluginContext, info, bytes.NewReader(data), &newBytes)
+ rejected := info == nil
+ if !rejected && newBytes.Len() != 0 {
+ data = newBytes.Bytes()
+ info.Size = int64(len(data))
+ }
+ return !rejected
+ }, plugin.FileWillBeUploadedId)
+ if info == nil {
+ return nil, data, model.NewAppError("DoUploadFile", "File rejected by plugin. "+rejectionReason, nil, "", http.StatusBadRequest)
+ }
+ }
+
if _, err := a.WriteFile(bytes.NewReader(data), info.Path); err != nil {
- return nil, err
+ return nil, data, err
}
if result := <-a.Srv.Store.FileInfo().Save(info); result.Err != nil {
- return nil, result.Err
+ return nil, data, result.Err
}
- return info, nil
+ return info, data, nil
}
func (a *App) HandleImages(previewPathList []string, thumbnailPathList []string, fileData [][]byte) {
diff --git a/app/plugin_api.go b/app/plugin_api.go
index 5e603a44e..414ce4d6e 100644
--- a/app/plugin_api.go
+++ b/app/plugin_api.go
@@ -45,9 +45,14 @@ func (api *PluginAPI) LoadPluginConfiguration(dest interface{}) error {
}
if pluginSettingsJsonBytes, err := json.Marshal(finalConfig); err != nil {
- return err
+ api.logger.Error("Error marshaling config for plugin", mlog.Err(err))
+ return nil
} else {
- return json.Unmarshal(pluginSettingsJsonBytes, dest)
+ err := json.Unmarshal(pluginSettingsJsonBytes, dest)
+ if err != nil {
+ api.logger.Error("Error unmarshaling config for plugin", mlog.Err(err))
+ }
+ return nil
}
}
diff --git a/app/plugin_hooks_test.go b/app/plugin_hooks_test.go
index 4b4e657ef..9846d628c 100644
--- a/app/plugin_hooks_test.go
+++ b/app/plugin_hooks_test.go
@@ -4,6 +4,8 @@
package app
import (
+ "bytes"
+ "io"
"io/ioutil"
"os"
"os/exec"
@@ -302,3 +304,69 @@ func TestHookMessageHasBeenUpdated(t *testing.T) {
t.Fatal(err)
}
}
+
+func TestHookFileWillBeUploaded(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+
+ var mockAPI plugintest.API
+ mockAPI.On("LoadPluginConfiguration", mock.Anything).Return(nil)
+ mockAPI.On("DeleteUser", "testhook.txt").Return(nil)
+ mockAPI.On("DeleteTeam", "inputfile").Return(nil)
+ SetAppEnvironmentWithPlugins(t,
+ []string{
+ `
+ package main
+
+ import (
+ "io"
+ "bytes"
+ "github.com/mattermost/mattermost-server/plugin"
+ "github.com/mattermost/mattermost-server/model"
+ )
+
+ type MyPlugin struct {
+ plugin.MattermostPlugin
+ }
+
+ func (p *MyPlugin) FileWillBeUploaded(c *plugin.Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string) {
+ p.API.DeleteUser(info.Name)
+ var buf bytes.Buffer
+ buf.ReadFrom(file)
+ p.API.DeleteTeam(buf.String())
+
+ outbuf := bytes.NewBufferString("changedtext")
+ io.Copy(output, outbuf)
+ info.Name = "modifiedinfo"
+ return info, ""
+ }
+
+ func main() {
+ plugin.ClientMain(&MyPlugin{})
+ }
+ `}, th.App, func(*model.Manifest) plugin.API { return &mockAPI })
+
+ response, err := th.App.UploadFiles(
+ "noteam",
+ th.BasicChannel.Id,
+ th.BasicUser.Id,
+ []io.ReadCloser{ioutil.NopCloser(bytes.NewBufferString("inputfile"))},
+ []string{"testhook.txt"},
+ []string{},
+ )
+ assert.Nil(t, err)
+ assert.NotNil(t, response)
+ assert.Equal(t, 1, len(response.FileInfos))
+ fileId := response.FileInfos[0].Id
+
+ fileInfo, err := th.App.GetFileInfo(fileId)
+ assert.Nil(t, err)
+ assert.NotNil(t, fileInfo)
+ assert.Equal(t, "modifiedinfo", fileInfo.Name)
+
+ fileReader, err := th.App.FileReader(fileInfo.Path)
+ assert.Nil(t, err)
+ var resultBuf bytes.Buffer
+ io.Copy(&resultBuf, fileReader)
+ assert.Equal(t, "changedtext", resultBuf.String())
+}