// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. package app import ( "bytes" "crypto/sha256" "encoding/base64" "io/ioutil" "net/http" "net/http/httptest" "testing" "github.com/gorilla/mux" "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/plugin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func getHashedKey(key string) string { hash := sha256.New() hash.Write([]byte(key)) return base64.StdEncoding.EncodeToString(hash.Sum(nil)) } func TestPluginKeyValueStore(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() pluginId := "testpluginid" assert.Nil(t, th.App.SetPluginKey(pluginId, "key", []byte("test"))) ret, err := th.App.GetPluginKey(pluginId, "key") assert.Nil(t, err) assert.Equal(t, []byte("test"), ret) // Test inserting over existing entries assert.Nil(t, th.App.SetPluginKey(pluginId, "key", []byte("test2"))) // Test getting non-existent key ret, err = th.App.GetPluginKey(pluginId, "notakey") assert.Nil(t, err) assert.Nil(t, ret) assert.Nil(t, th.App.DeletePluginKey(pluginId, "stringkey")) assert.Nil(t, th.App.DeletePluginKey(pluginId, "intkey")) assert.Nil(t, th.App.DeletePluginKey(pluginId, "postkey")) assert.Nil(t, th.App.DeletePluginKey(pluginId, "notrealkey")) // Test ListKeys assert.Nil(t, th.App.SetPluginKey(pluginId, "key2", []byte("test"))) hashedKey := getHashedKey("key") hashedKey2 := getHashedKey("key2") list, err := th.App.ListPluginKeys(pluginId, 0, 1) assert.Nil(t, err) assert.Equal(t, 1, len(list)) assert.Equal(t, hashedKey, list[0]) list, err = th.App.ListPluginKeys(pluginId, 1, 1) assert.Nil(t, err) assert.Equal(t, 1, len(list)) assert.Equal(t, hashedKey2, list[0]) //List Keys bad input list, err = th.App.ListPluginKeys(pluginId, 0, 0) assert.Nil(t, err) assert.Equal(t, 2, len(list)) list, err = th.App.ListPluginKeys(pluginId, 0, -1) assert.Nil(t, err) assert.Equal(t, 2, len(list)) list, err = th.App.ListPluginKeys(pluginId, -1, 1) assert.Nil(t, err) assert.Equal(t, 1, len(list)) list, err = th.App.ListPluginKeys(pluginId, -1, 0) assert.Nil(t, err) assert.Equal(t, 2, len(list)) list, err = th.App.ListPluginKeys(pluginId, 2, 2) assert.Nil(t, err) assert.Equal(t, 0, len(list)) } func TestServePluginRequest(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false }) w := httptest.NewRecorder() r := httptest.NewRequest("GET", "/plugins/foo/bar", nil) th.App.ServePluginRequest(w, r) assert.Equal(t, http.StatusNotImplemented, w.Result().StatusCode) } func TestPrivateServePluginRequest(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() testCases := []struct { Description string ConfigFunc func(cfg *model.Config) URL string ExpectedURL string }{ { "no subpath", func(cfg *model.Config) {}, "/plugins/id/endpoint", "/endpoint", }, { "subpath", func(cfg *model.Config) { *cfg.ServiceSettings.SiteURL += "/subpath" }, "/subpath/plugins/id/endpoint", "/endpoint", }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { th.App.UpdateConfig(testCase.ConfigFunc) expectedBody := []byte("body") request := httptest.NewRequest(http.MethodGet, testCase.URL, bytes.NewReader(expectedBody)) recorder := httptest.NewRecorder() handler := func(context *plugin.Context, w http.ResponseWriter, r *http.Request) { assert.Equal(t, testCase.ExpectedURL, r.URL.Path) body, _ := ioutil.ReadAll(r.Body) assert.Equal(t, expectedBody, body) } request = mux.SetURLVars(request, map[string]string{"plugin_id": "id"}) th.App.servePluginRequest(recorder, request, handler) }) } } func TestHandlePluginRequest(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false *cfg.ServiceSettings.EnableUserAccessTokens = true }) token, err := th.App.CreateUserAccessToken(&model.UserAccessToken{ UserId: th.BasicUser.Id, }) require.Nil(t, err) var assertions func(*http.Request) router := mux.NewRouter() router.HandleFunc("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}/{anything:.*}", func(_ http.ResponseWriter, r *http.Request) { th.App.servePluginRequest(nil, r, func(_ *plugin.Context, _ http.ResponseWriter, r *http.Request) { assertions(r) }) }) r := httptest.NewRequest("GET", "/plugins/foo/bar", nil) r.Header.Add("Authorization", "Bearer "+token.Token) assertions = func(r *http.Request) { assert.Equal(t, "/bar", r.URL.Path) assert.Equal(t, th.BasicUser.Id, r.Header.Get("Mattermost-User-Id")) } router.ServeHTTP(nil, r) r = httptest.NewRequest("GET", "/plugins/foo/bar?a=b&access_token="+token.Token+"&c=d", nil) assertions = func(r *http.Request) { assert.Equal(t, "/bar", r.URL.Path) assert.Equal(t, "a=b&c=d", r.URL.RawQuery) assert.Equal(t, th.BasicUser.Id, r.Header.Get("Mattermost-User-Id")) } router.ServeHTTP(nil, r) r = httptest.NewRequest("GET", "/plugins/foo/bar?a=b&access_token=asdf&c=d", nil) assertions = func(r *http.Request) { assert.Equal(t, "/bar", r.URL.Path) assert.Equal(t, "a=b&c=d", r.URL.RawQuery) assert.Empty(t, r.Header.Get("Mattermost-User-Id")) } router.ServeHTTP(nil, r) } func TestGetPluginStatusesDisabled(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false }) _, err := th.App.GetPluginStatuses() require.EqualError(t, err, "GetPluginStatuses: Plugins have been disabled. Please check your logs for details., ") } func TestGetPluginStatuses(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true }) pluginStatuses, err := th.App.GetPluginStatuses() require.Nil(t, err) require.NotNil(t, pluginStatuses) }