github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/api4/plugin_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package api4
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/base64"
     9  	"encoding/json"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"net/http"
    13  	"net/http/httptest"
    14  	"os"
    15  	"path/filepath"
    16  	"sort"
    17  	"strings"
    18  	"testing"
    19  	"time"
    20  
    21  	svg "github.com/h2non/go-is-svg"
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  
    25  	"github.com/masterhung0112/hk_server/v5/model"
    26  	"github.com/masterhung0112/hk_server/v5/plugin"
    27  	"github.com/masterhung0112/hk_server/v5/testlib"
    28  	"github.com/masterhung0112/hk_server/v5/utils/fileutils"
    29  )
    30  
    31  func TestPlugin(t *testing.T) {
    32  	th := Setup(t)
    33  	defer th.TearDown()
    34  
    35  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
    36  		statesJson, err := json.Marshal(th.App.Config().PluginSettings.PluginStates)
    37  		require.NoError(t, err)
    38  		states := map[string]*model.PluginState{}
    39  		json.Unmarshal(statesJson, &states)
    40  		th.App.UpdateConfig(func(cfg *model.Config) {
    41  			*cfg.PluginSettings.Enable = true
    42  			*cfg.PluginSettings.EnableUploads = true
    43  			*cfg.PluginSettings.AllowInsecureDownloadUrl = true
    44  		})
    45  
    46  		path, _ := fileutils.FindDir("tests")
    47  		tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
    48  		require.NoError(t, err)
    49  
    50  		// Install from URL
    51  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
    52  			res.WriteHeader(http.StatusOK)
    53  			res.Write(tarData)
    54  		}))
    55  		defer func() { testServer.Close() }()
    56  
    57  		url := testServer.URL
    58  
    59  		manifest, resp := client.InstallPluginFromUrl(url, false)
    60  		CheckNoError(t, resp)
    61  		assert.Equal(t, "testplugin", manifest.Id)
    62  
    63  		_, resp = client.InstallPluginFromUrl(url, false)
    64  		CheckBadRequestStatus(t, resp)
    65  
    66  		manifest, resp = client.InstallPluginFromUrl(url, true)
    67  		CheckNoError(t, resp)
    68  		assert.Equal(t, "testplugin", manifest.Id)
    69  
    70  		// Stored in File Store: Install Plugin from URL case
    71  		pluginStored, appErr := th.App.FileExists("./plugins/" + manifest.Id + ".tar.gz")
    72  		assert.Nil(t, appErr)
    73  		assert.True(t, pluginStored)
    74  
    75  		ok, resp := client.RemovePlugin(manifest.Id)
    76  		CheckNoError(t, resp)
    77  		require.True(t, ok)
    78  
    79  		t.Run("install plugin from URL with slow response time", func(t *testing.T) {
    80  			if testing.Short() {
    81  				t.Skip("skipping test to install plugin from a slow response server")
    82  			}
    83  
    84  			// Install from URL - slow server to simulate longer bundle download times
    85  			slowTestServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
    86  				time.Sleep(60 * time.Second) // Wait longer than the previous default 30 seconds timeout
    87  				res.WriteHeader(http.StatusOK)
    88  				res.Write(tarData)
    89  			}))
    90  			defer func() { slowTestServer.Close() }()
    91  
    92  			manifest, resp = client.InstallPluginFromUrl(slowTestServer.URL, true)
    93  			CheckNoError(t, resp)
    94  			assert.Equal(t, "testplugin", manifest.Id)
    95  		})
    96  
    97  		th.App.RemovePlugin(manifest.Id)
    98  
    99  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
   100  
   101  		_, resp = client.InstallPluginFromUrl(url, false)
   102  		CheckNotImplementedStatus(t, resp)
   103  
   104  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
   105  
   106  		_, resp = th.Client.InstallPluginFromUrl(url, false)
   107  		CheckForbiddenStatus(t, resp)
   108  
   109  		_, resp = client.InstallPluginFromUrl("http://nodata", false)
   110  		CheckBadRequestStatus(t, resp)
   111  
   112  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.AllowInsecureDownloadUrl = false })
   113  
   114  		_, resp = client.InstallPluginFromUrl(url, false)
   115  		CheckBadRequestStatus(t, resp)
   116  
   117  		// Successful upload
   118  		manifest, resp = client.UploadPlugin(bytes.NewReader(tarData))
   119  		CheckNoError(t, resp)
   120  
   121  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.EnableUploads = true })
   122  
   123  		manifest, resp = client.UploadPluginForced(bytes.NewReader(tarData))
   124  		defer os.RemoveAll("plugins/testplugin")
   125  		CheckNoError(t, resp)
   126  
   127  		assert.Equal(t, "testplugin", manifest.Id)
   128  
   129  		// Stored in File Store: Upload Plugin case
   130  		pluginStored, appErr = th.App.FileExists("./plugins/" + manifest.Id + ".tar.gz")
   131  		assert.Nil(t, appErr)
   132  		assert.True(t, pluginStored)
   133  
   134  		// Upload error cases
   135  		_, resp = client.UploadPlugin(bytes.NewReader([]byte("badfile")))
   136  		CheckBadRequestStatus(t, resp)
   137  
   138  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
   139  		_, resp = client.UploadPlugin(bytes.NewReader(tarData))
   140  		CheckNotImplementedStatus(t, resp)
   141  
   142  		th.App.UpdateConfig(func(cfg *model.Config) {
   143  			*cfg.PluginSettings.Enable = true
   144  			*cfg.PluginSettings.EnableUploads = false
   145  		})
   146  		_, resp = client.UploadPlugin(bytes.NewReader(tarData))
   147  		CheckNotImplementedStatus(t, resp)
   148  
   149  		_, resp = client.InstallPluginFromUrl(url, false)
   150  		CheckNotImplementedStatus(t, resp)
   151  
   152  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.EnableUploads = true })
   153  		_, resp = th.Client.UploadPlugin(bytes.NewReader(tarData))
   154  		CheckForbiddenStatus(t, resp)
   155  
   156  		// Successful gets
   157  		pluginsResp, resp := client.GetPlugins()
   158  		CheckNoError(t, resp)
   159  
   160  		found := false
   161  		for _, m := range pluginsResp.Inactive {
   162  			if m.Id == manifest.Id {
   163  				found = true
   164  			}
   165  		}
   166  
   167  		assert.True(t, found)
   168  
   169  		found = false
   170  		for _, m := range pluginsResp.Active {
   171  			if m.Id == manifest.Id {
   172  				found = true
   173  			}
   174  		}
   175  
   176  		assert.False(t, found)
   177  
   178  		// Successful activate
   179  		ok, resp = client.EnablePlugin(manifest.Id)
   180  		CheckNoError(t, resp)
   181  		assert.True(t, ok)
   182  
   183  		pluginsResp, resp = client.GetPlugins()
   184  		CheckNoError(t, resp)
   185  
   186  		found = false
   187  		for _, m := range pluginsResp.Active {
   188  			if m.Id == manifest.Id {
   189  				found = true
   190  			}
   191  		}
   192  
   193  		assert.True(t, found)
   194  
   195  		// Activate error case
   196  		ok, resp = client.EnablePlugin("junk")
   197  		CheckNotFoundStatus(t, resp)
   198  		assert.False(t, ok)
   199  
   200  		ok, resp = client.EnablePlugin("JUNK")
   201  		CheckNotFoundStatus(t, resp)
   202  		assert.False(t, ok)
   203  
   204  		// Successful deactivate
   205  		ok, resp = client.DisablePlugin(manifest.Id)
   206  		CheckNoError(t, resp)
   207  		assert.True(t, ok)
   208  
   209  		pluginsResp, resp = client.GetPlugins()
   210  		CheckNoError(t, resp)
   211  
   212  		found = false
   213  		for _, m := range pluginsResp.Inactive {
   214  			if m.Id == manifest.Id {
   215  				found = true
   216  			}
   217  		}
   218  
   219  		assert.True(t, found)
   220  
   221  		// Deactivate error case
   222  		ok, resp = client.DisablePlugin("junk")
   223  		CheckNotFoundStatus(t, resp)
   224  		assert.False(t, ok)
   225  
   226  		// Get error cases
   227  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
   228  		_, resp = client.GetPlugins()
   229  		CheckNotImplementedStatus(t, resp)
   230  
   231  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
   232  		_, resp = th.Client.GetPlugins()
   233  		CheckForbiddenStatus(t, resp)
   234  
   235  		// Successful webapp get
   236  		_, resp = client.EnablePlugin(manifest.Id)
   237  		CheckNoError(t, resp)
   238  
   239  		manifests, resp := th.Client.GetWebappPlugins()
   240  		CheckNoError(t, resp)
   241  
   242  		found = false
   243  		for _, m := range manifests {
   244  			if m.Id == manifest.Id {
   245  				found = true
   246  			}
   247  		}
   248  
   249  		assert.True(t, found)
   250  
   251  		// Successful remove
   252  		ok, resp = client.RemovePlugin(manifest.Id)
   253  		CheckNoError(t, resp)
   254  		assert.True(t, ok)
   255  
   256  		// Remove error cases
   257  		ok, resp = client.RemovePlugin(manifest.Id)
   258  		CheckNotFoundStatus(t, resp)
   259  		assert.False(t, ok)
   260  
   261  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
   262  		_, resp = client.RemovePlugin(manifest.Id)
   263  		CheckNotImplementedStatus(t, resp)
   264  
   265  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
   266  		_, resp = th.Client.RemovePlugin(manifest.Id)
   267  		CheckForbiddenStatus(t, resp)
   268  
   269  		_, resp = client.RemovePlugin("bad.id")
   270  		CheckNotFoundStatus(t, resp)
   271  	})
   272  }
   273  
   274  func TestNotifyClusterPluginEvent(t *testing.T) {
   275  	th := Setup(t)
   276  	defer th.TearDown()
   277  
   278  	testCluster := &testlib.FakeClusterInterface{}
   279  	th.Server.Cluster = testCluster
   280  
   281  	th.App.UpdateConfig(func(cfg *model.Config) {
   282  		*cfg.PluginSettings.Enable = true
   283  		*cfg.PluginSettings.EnableUploads = true
   284  	})
   285  
   286  	path, _ := fileutils.FindDir("tests")
   287  	tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
   288  	require.NoError(t, err)
   289  
   290  	testCluster.ClearMessages()
   291  
   292  	// Successful upload
   293  	manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
   294  	CheckNoError(t, resp)
   295  	require.Equal(t, "testplugin", manifest.Id)
   296  
   297  	// Stored in File Store: Upload Plugin case
   298  	expectedPath := filepath.Join("./plugins", manifest.Id) + ".tar.gz"
   299  	pluginStored, appErr := th.App.FileExists(expectedPath)
   300  	require.Nil(t, appErr)
   301  	require.True(t, pluginStored)
   302  
   303  	messages := testCluster.GetMessages()
   304  	expectedPluginData := model.PluginEventData{
   305  		Id: manifest.Id,
   306  	}
   307  	expectedInstallMessage := &model.ClusterMessage{
   308  		Event:            model.CLUSTER_EVENT_INSTALL_PLUGIN,
   309  		SendType:         model.CLUSTER_SEND_RELIABLE,
   310  		WaitForAllToSend: true,
   311  		Data:             expectedPluginData.ToJson(),
   312  	}
   313  	actualMessages := findClusterMessages(model.CLUSTER_EVENT_INSTALL_PLUGIN, messages)
   314  	require.Equal(t, []*model.ClusterMessage{expectedInstallMessage}, actualMessages)
   315  
   316  	// Upgrade
   317  	testCluster.ClearMessages()
   318  	manifest, resp = th.SystemAdminClient.UploadPluginForced(bytes.NewReader(tarData))
   319  	CheckNoError(t, resp)
   320  	require.Equal(t, "testplugin", manifest.Id)
   321  
   322  	// Successful remove
   323  	webSocketClient, appErr := th.CreateWebSocketSystemAdminClient()
   324  	require.Nil(t, appErr)
   325  	webSocketClient.Listen()
   326  	defer webSocketClient.Close()
   327  	done := make(chan bool)
   328  	go func() {
   329  		for {
   330  			select {
   331  			case resp := <-webSocketClient.EventChannel:
   332  				if resp.EventType() == model.WEBSOCKET_EVENT_PLUGIN_STATUSES_CHANGED && len(resp.GetData()["plugin_statuses"].([]interface{})) == 0 {
   333  					done <- true
   334  					return
   335  				}
   336  			case <-time.After(5 * time.Second):
   337  				done <- false
   338  				return
   339  			}
   340  		}
   341  	}()
   342  
   343  	testCluster.ClearMessages()
   344  	ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
   345  	CheckNoError(t, resp)
   346  	require.True(t, ok)
   347  
   348  	result := <-done
   349  	require.True(t, result, "plugin_statuses_changed websocket event was not received")
   350  
   351  	messages = testCluster.GetMessages()
   352  
   353  	expectedRemoveMessage := &model.ClusterMessage{
   354  		Event:            model.CLUSTER_EVENT_REMOVE_PLUGIN,
   355  		SendType:         model.CLUSTER_SEND_RELIABLE,
   356  		WaitForAllToSend: true,
   357  		Data:             expectedPluginData.ToJson(),
   358  	}
   359  	actualMessages = findClusterMessages(model.CLUSTER_EVENT_REMOVE_PLUGIN, messages)
   360  	require.Equal(t, []*model.ClusterMessage{expectedRemoveMessage}, actualMessages)
   361  
   362  	pluginStored, appErr = th.App.FileExists(expectedPath)
   363  	require.Nil(t, appErr)
   364  	require.False(t, pluginStored)
   365  }
   366  
   367  func TestDisableOnRemove(t *testing.T) {
   368  	path, _ := fileutils.FindDir("tests")
   369  	tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
   370  	require.NoError(t, err)
   371  
   372  	testCases := []struct {
   373  		Description string
   374  		Upgrade     bool
   375  	}{
   376  		{
   377  			"Remove without upgrading",
   378  			false,
   379  		},
   380  		{
   381  			"Remove after upgrading",
   382  			true,
   383  		},
   384  	}
   385  
   386  	th := Setup(t).InitBasic()
   387  	defer th.TearDown()
   388  
   389  	for _, tc := range testCases {
   390  		t.Run(tc.Description, func(t *testing.T) {
   391  			th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   392  				th.App.UpdateConfig(func(cfg *model.Config) {
   393  					*cfg.PluginSettings.Enable = true
   394  					*cfg.PluginSettings.EnableUploads = true
   395  				})
   396  
   397  				// Upload
   398  				manifest, resp := client.UploadPlugin(bytes.NewReader(tarData))
   399  				CheckNoError(t, resp)
   400  				require.Equal(t, "testplugin", manifest.Id)
   401  
   402  				// Check initial status
   403  				pluginsResp, resp := client.GetPlugins()
   404  				CheckNoError(t, resp)
   405  				require.Empty(t, pluginsResp.Active)
   406  				require.Equal(t, pluginsResp.Inactive, []*model.PluginInfo{{
   407  					Manifest: *manifest,
   408  				}})
   409  
   410  				// Enable plugin
   411  				ok, resp := client.EnablePlugin(manifest.Id)
   412  				CheckNoError(t, resp)
   413  				require.True(t, ok)
   414  
   415  				// Confirm enabled status
   416  				pluginsResp, resp = client.GetPlugins()
   417  				CheckNoError(t, resp)
   418  				require.Empty(t, pluginsResp.Inactive)
   419  				require.Equal(t, pluginsResp.Active, []*model.PluginInfo{{
   420  					Manifest: *manifest,
   421  				}})
   422  
   423  				if tc.Upgrade {
   424  					// Upgrade
   425  					manifest, resp = client.UploadPluginForced(bytes.NewReader(tarData))
   426  					CheckNoError(t, resp)
   427  					require.Equal(t, "testplugin", manifest.Id)
   428  
   429  					// Plugin should remain active
   430  					pluginsResp, resp = client.GetPlugins()
   431  					CheckNoError(t, resp)
   432  					require.Empty(t, pluginsResp.Inactive)
   433  					require.Equal(t, pluginsResp.Active, []*model.PluginInfo{{
   434  						Manifest: *manifest,
   435  					}})
   436  				}
   437  
   438  				// Remove plugin
   439  				ok, resp = client.RemovePlugin(manifest.Id)
   440  				CheckNoError(t, resp)
   441  				require.True(t, ok)
   442  
   443  				// Plugin should have no status
   444  				pluginsResp, resp = client.GetPlugins()
   445  				CheckNoError(t, resp)
   446  				require.Empty(t, pluginsResp.Inactive)
   447  				require.Empty(t, pluginsResp.Active)
   448  
   449  				// Upload same plugin
   450  				manifest, resp = client.UploadPlugin(bytes.NewReader(tarData))
   451  				CheckNoError(t, resp)
   452  				require.Equal(t, "testplugin", manifest.Id)
   453  
   454  				// Plugin should be inactive
   455  				pluginsResp, resp = client.GetPlugins()
   456  				CheckNoError(t, resp)
   457  				require.Empty(t, pluginsResp.Active)
   458  				require.Equal(t, pluginsResp.Inactive, []*model.PluginInfo{{
   459  					Manifest: *manifest,
   460  				}})
   461  
   462  				// Clean up
   463  				ok, resp = client.RemovePlugin(manifest.Id)
   464  				CheckNoError(t, resp)
   465  				require.True(t, ok)
   466  			})
   467  		})
   468  	}
   469  }
   470  
   471  func TestGetMarketplacePlugins(t *testing.T) {
   472  	th := Setup(t)
   473  	defer th.TearDown()
   474  
   475  	th.App.UpdateConfig(func(cfg *model.Config) {
   476  		*cfg.PluginSettings.Enable = true
   477  		*cfg.PluginSettings.EnableUploads = true
   478  		*cfg.PluginSettings.EnableMarketplace = false
   479  	})
   480  
   481  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   482  		th.App.UpdateConfig(func(cfg *model.Config) {
   483  			*cfg.PluginSettings.EnableMarketplace = false
   484  			*cfg.PluginSettings.MarketplaceUrl = "invalid.com"
   485  		})
   486  
   487  		plugins, resp := client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   488  		CheckNotImplementedStatus(t, resp)
   489  		require.Nil(t, plugins)
   490  	}, "marketplace disabled")
   491  
   492  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   493  		th.App.UpdateConfig(func(cfg *model.Config) {
   494  			*cfg.PluginSettings.EnableMarketplace = true
   495  			*cfg.PluginSettings.MarketplaceUrl = "invalid.com"
   496  		})
   497  
   498  		plugins, resp := client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   499  		CheckInternalErrorStatus(t, resp)
   500  		require.Nil(t, plugins)
   501  	}, "no server")
   502  
   503  	t.Run("no permission", func(t *testing.T) {
   504  		th.App.UpdateConfig(func(cfg *model.Config) {
   505  			*cfg.PluginSettings.EnableMarketplace = true
   506  			*cfg.PluginSettings.MarketplaceUrl = "invalid.com"
   507  		})
   508  
   509  		plugins, resp := th.Client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   510  		CheckForbiddenStatus(t, resp)
   511  		require.Nil(t, plugins)
   512  	})
   513  
   514  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   515  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   516  			res.WriteHeader(http.StatusOK)
   517  			json, err := json.Marshal([]*model.MarketplacePlugin{})
   518  			require.NoError(t, err)
   519  			res.Write(json)
   520  		}))
   521  		defer func() { testServer.Close() }()
   522  
   523  		th.App.UpdateConfig(func(cfg *model.Config) {
   524  			*cfg.PluginSettings.EnableMarketplace = true
   525  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   526  		})
   527  
   528  		plugins, resp := client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   529  		CheckNoError(t, resp)
   530  		require.Empty(t, plugins)
   531  	}, "empty response from server")
   532  
   533  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   534  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   535  			serverVersion, ok := req.URL.Query()["server_version"]
   536  			require.True(t, ok)
   537  			require.Len(t, serverVersion, 1)
   538  			require.Equal(t, model.CurrentVersion, serverVersion[0])
   539  			require.NotEqual(t, 0, len(serverVersion[0]))
   540  
   541  			res.WriteHeader(http.StatusOK)
   542  			json, err := json.Marshal([]*model.MarketplacePlugin{})
   543  			require.NoError(t, err)
   544  			res.Write(json)
   545  		}))
   546  		defer func() { testServer.Close() }()
   547  
   548  		th.App.UpdateConfig(func(cfg *model.Config) {
   549  			*cfg.PluginSettings.EnableMarketplace = true
   550  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   551  		})
   552  
   553  		plugins, resp := client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   554  		CheckNoError(t, resp)
   555  		require.Empty(t, plugins)
   556  	}, "verify server version is passed through")
   557  
   558  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   559  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   560  			licenseType, ok := req.URL.Query()["enterprise_plugins"]
   561  			require.True(t, ok)
   562  			require.Len(t, licenseType, 1)
   563  			require.Equal(t, "false", licenseType[0])
   564  
   565  			res.WriteHeader(http.StatusOK)
   566  			json, err := json.Marshal([]*model.MarketplacePlugin{})
   567  			require.NoError(t, err)
   568  			res.Write(json)
   569  		}))
   570  		defer func() { testServer.Close() }()
   571  
   572  		th.App.UpdateConfig(func(cfg *model.Config) {
   573  			*cfg.PluginSettings.EnableMarketplace = true
   574  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   575  		})
   576  
   577  		plugins, resp := client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   578  		CheckNoError(t, resp)
   579  		require.Empty(t, plugins)
   580  	}, "verify EnterprisePlugins is false for TE")
   581  
   582  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   583  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   584  			licenseType, ok := req.URL.Query()["enterprise_plugins"]
   585  			require.True(t, ok)
   586  			require.Len(t, licenseType, 1)
   587  			require.Equal(t, "false", licenseType[0])
   588  
   589  			res.WriteHeader(http.StatusOK)
   590  			json, err := json.Marshal([]*model.MarketplacePlugin{})
   591  			require.NoError(t, err)
   592  			res.Write(json)
   593  		}))
   594  		defer func() { testServer.Close() }()
   595  
   596  		th.App.UpdateConfig(func(cfg *model.Config) {
   597  			*cfg.PluginSettings.EnableMarketplace = true
   598  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   599  		})
   600  
   601  		l := model.NewTestLicense()
   602  		// model.NewTestLicense generates a E20 license
   603  		*l.Features.EnterprisePlugins = false
   604  		th.App.Srv().SetLicense(l)
   605  
   606  		plugins, resp := client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   607  		CheckNoError(t, resp)
   608  		require.Empty(t, plugins)
   609  	}, "verify EnterprisePlugins is false for E10")
   610  
   611  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   612  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   613  			licenseType, ok := req.URL.Query()["enterprise_plugins"]
   614  			require.True(t, ok)
   615  			require.Len(t, licenseType, 1)
   616  			require.Equal(t, "true", licenseType[0])
   617  
   618  			res.WriteHeader(http.StatusOK)
   619  			json, err := json.Marshal([]*model.MarketplacePlugin{})
   620  			require.NoError(t, err)
   621  			res.Write(json)
   622  		}))
   623  		defer func() { testServer.Close() }()
   624  
   625  		th.App.UpdateConfig(func(cfg *model.Config) {
   626  			*cfg.PluginSettings.EnableMarketplace = true
   627  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   628  		})
   629  
   630  		th.App.Srv().SetLicense(model.NewTestLicense("enterprise_plugins"))
   631  
   632  		plugins, resp := client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   633  		CheckNoError(t, resp)
   634  		require.Empty(t, plugins)
   635  	}, "verify EnterprisePlugins is true for E20")
   636  
   637  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   638  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   639  			cloud, ok := req.URL.Query()["cloud"]
   640  			require.True(t, ok)
   641  			require.Len(t, cloud, 1)
   642  			require.Equal(t, "false", cloud[0])
   643  
   644  			res.WriteHeader(http.StatusOK)
   645  			json, err := json.Marshal([]*model.MarketplacePlugin{})
   646  			require.NoError(t, err)
   647  			res.Write(json)
   648  		}))
   649  		defer func() { testServer.Close() }()
   650  
   651  		th.App.UpdateConfig(func(cfg *model.Config) {
   652  			*cfg.PluginSettings.EnableMarketplace = true
   653  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   654  		})
   655  
   656  		plugins, resp := client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   657  		CheckNoError(t, resp)
   658  		require.Empty(t, plugins)
   659  	}, "verify EnterprisePlugins is false if there is no license")
   660  
   661  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   662  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   663  			cloud, ok := req.URL.Query()["cloud"]
   664  			require.True(t, ok)
   665  			require.Len(t, cloud, 1)
   666  			require.Equal(t, "true", cloud[0])
   667  
   668  			res.WriteHeader(http.StatusOK)
   669  			json, err := json.Marshal([]*model.MarketplacePlugin{})
   670  			require.NoError(t, err)
   671  			res.Write(json)
   672  		}))
   673  		defer func() { testServer.Close() }()
   674  
   675  		th.App.UpdateConfig(func(cfg *model.Config) {
   676  			*cfg.PluginSettings.EnableMarketplace = true
   677  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   678  		})
   679  
   680  		th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
   681  
   682  		plugins, resp := client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   683  		CheckNoError(t, resp)
   684  		require.Empty(t, plugins)
   685  	}, "verify Cloud is true for cloud license")
   686  }
   687  
   688  func TestGetInstalledMarketplacePlugins(t *testing.T) {
   689  	samplePlugins := []*model.MarketplacePlugin{
   690  		{
   691  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
   692  				HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
   693  				IconData:    "https://example.com/icon.svg",
   694  				DownloadURL: "https://example.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.4/com.mattermost.nps-1.0.4.tar.gz",
   695  				Labels: []model.MarketplaceLabel{
   696  					{
   697  						Name:        "someName",
   698  						Description: "some Description",
   699  					},
   700  				},
   701  				Manifest: &model.Manifest{
   702  					Id:               "com.mattermost.nps",
   703  					Name:             "User Satisfaction Surveys",
   704  					Description:      "This plugin sends quarterly user satisfaction surveys to gather feedback and help improve Mattermost.",
   705  					Version:          "1.0.4",
   706  					MinServerVersion: "5.14.0",
   707  				},
   708  			},
   709  			InstalledVersion: "",
   710  		},
   711  	}
   712  
   713  	path, _ := fileutils.FindDir("tests")
   714  	tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
   715  	require.NoError(t, err)
   716  
   717  	t.Run("marketplace client returns not-installed plugin", func(t *testing.T) {
   718  		th := Setup(t)
   719  		defer th.TearDown()
   720  
   721  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   722  			res.WriteHeader(http.StatusOK)
   723  			json, err := json.Marshal(samplePlugins)
   724  			require.NoError(t, err)
   725  			res.Write(json)
   726  		}))
   727  		defer func() { testServer.Close() }()
   728  
   729  		th.App.UpdateConfig(func(cfg *model.Config) {
   730  			*cfg.PluginSettings.Enable = true
   731  			*cfg.PluginSettings.EnableUploads = true
   732  			*cfg.PluginSettings.EnableMarketplace = true
   733  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   734  		})
   735  
   736  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   737  		CheckNoError(t, resp)
   738  		require.Equal(t, samplePlugins, plugins)
   739  
   740  		manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
   741  		CheckNoError(t, resp)
   742  
   743  		testIcon, err := ioutil.ReadFile(filepath.Join(path, "test.svg"))
   744  		require.NoError(t, err)
   745  		require.True(t, svg.Is(testIcon))
   746  		testIconData := fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(testIcon))
   747  
   748  		expectedPlugins := append(samplePlugins, &model.MarketplacePlugin{
   749  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
   750  				HomepageURL:     "https://example.com/homepage",
   751  				IconData:        testIconData,
   752  				DownloadURL:     "",
   753  				ReleaseNotesURL: "https://example.com/releases/v0.0.1",
   754  				Labels: []model.MarketplaceLabel{{
   755  					Name:        "Local",
   756  					Description: "This plugin is not listed in the marketplace",
   757  				}},
   758  				Manifest: manifest,
   759  			},
   760  			InstalledVersion: manifest.Version,
   761  		})
   762  		sort.SliceStable(expectedPlugins, func(i, j int) bool {
   763  			return strings.ToLower(expectedPlugins[i].Manifest.Name) < strings.ToLower(expectedPlugins[j].Manifest.Name)
   764  		})
   765  
   766  		plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   767  		CheckNoError(t, resp)
   768  		require.Equal(t, expectedPlugins, plugins)
   769  
   770  		ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
   771  		CheckNoError(t, resp)
   772  		assert.True(t, ok)
   773  
   774  		plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   775  		CheckNoError(t, resp)
   776  		require.Equal(t, samplePlugins, plugins)
   777  	})
   778  
   779  	t.Run("marketplace client returns installed plugin", func(t *testing.T) {
   780  		th := Setup(t)
   781  		defer th.TearDown()
   782  
   783  		th.App.UpdateConfig(func(cfg *model.Config) {
   784  			*cfg.PluginSettings.Enable = true
   785  			*cfg.PluginSettings.EnableUploads = true
   786  			*cfg.PluginSettings.EnableMarketplace = true
   787  		})
   788  
   789  		manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
   790  		CheckNoError(t, resp)
   791  
   792  		newPlugin := &model.MarketplacePlugin{
   793  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
   794  				HomepageURL: "HomepageURL",
   795  				IconData:    "IconData",
   796  				DownloadURL: "DownloadURL",
   797  				Manifest:    manifest,
   798  			},
   799  			InstalledVersion: manifest.Version,
   800  		}
   801  		expectedPlugins := append(samplePlugins, newPlugin)
   802  		sort.SliceStable(expectedPlugins, func(i, j int) bool {
   803  			return strings.ToLower(expectedPlugins[i].Manifest.Name) < strings.ToLower(expectedPlugins[j].Manifest.Name)
   804  		})
   805  
   806  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   807  			res.WriteHeader(http.StatusOK)
   808  			json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0], newPlugin})
   809  			require.NoError(t, err)
   810  			res.Write(json)
   811  		}))
   812  		defer func() { testServer.Close() }()
   813  		th.App.UpdateConfig(func(cfg *model.Config) {
   814  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   815  		})
   816  
   817  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   818  		CheckNoError(t, resp)
   819  		require.Equal(t, expectedPlugins, plugins)
   820  
   821  		ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
   822  		CheckNoError(t, resp)
   823  		assert.True(t, ok)
   824  
   825  		plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   826  		CheckNoError(t, resp)
   827  		newPlugin.InstalledVersion = ""
   828  		require.Equal(t, expectedPlugins, plugins)
   829  	})
   830  }
   831  
   832  func TestSearchGetMarketplacePlugins(t *testing.T) {
   833  	samplePlugins := []*model.MarketplacePlugin{
   834  		{
   835  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
   836  				HomepageURL: "example.com/mattermost/mattermost-plugin-nps",
   837  				IconData:    "Cjxzdmcgdmlld0JveD0nMCAwIDEwNSA5MycgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJz4KPHBhdGggZD0nTTY2LDBoMzl2OTN6TTM4LDBoLTM4djkzek01MiwzNWwyNSw1OGgtMTZsLTgtMThoLTE4eicgZmlsbD0nI0VEMUMyNCcvPgo8L3N2Zz4K",
   838  				DownloadURL: "example.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.4/com.mattermost.nps-1.0.4.tar.gz",
   839  				Manifest: &model.Manifest{
   840  					Id:               "com.mattermost.nps",
   841  					Name:             "User Satisfaction Surveys",
   842  					Description:      "This plugin sends quarterly user satisfaction surveys to gather feedback and help improve Mattermost.",
   843  					Version:          "1.0.4",
   844  					MinServerVersion: "5.14.0",
   845  				},
   846  			},
   847  			InstalledVersion: "",
   848  		},
   849  	}
   850  
   851  	path, _ := fileutils.FindDir("tests")
   852  	tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
   853  	require.NoError(t, err)
   854  
   855  	tarDataV2, err := ioutil.ReadFile(filepath.Join(path, "testplugin2.tar.gz"))
   856  	require.NoError(t, err)
   857  
   858  	testIcon, err := ioutil.ReadFile(filepath.Join(path, "test.svg"))
   859  	require.NoError(t, err)
   860  	require.True(t, svg.Is(testIcon))
   861  	testIconData := fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(testIcon))
   862  
   863  	t.Run("search installed plugin", func(t *testing.T) {
   864  		th := Setup(t).InitBasic()
   865  		defer th.TearDown()
   866  
   867  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   868  			res.WriteHeader(http.StatusOK)
   869  			json, err := json.Marshal(samplePlugins)
   870  			require.NoError(t, err)
   871  			res.Write(json)
   872  		}))
   873  		defer func() { testServer.Close() }()
   874  
   875  		th.App.UpdateConfig(func(cfg *model.Config) {
   876  			*cfg.PluginSettings.Enable = true
   877  			*cfg.PluginSettings.EnableUploads = true
   878  			*cfg.PluginSettings.EnableMarketplace = true
   879  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   880  		})
   881  
   882  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   883  		CheckNoError(t, resp)
   884  		require.Equal(t, samplePlugins, plugins)
   885  
   886  		manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
   887  		CheckNoError(t, resp)
   888  
   889  		plugin1 := &model.MarketplacePlugin{
   890  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
   891  				HomepageURL:     "https://example.com/homepage",
   892  				IconData:        testIconData,
   893  				DownloadURL:     "",
   894  				ReleaseNotesURL: "https://example.com/releases/v0.0.1",
   895  				Labels: []model.MarketplaceLabel{{
   896  					Name:        "Local",
   897  					Description: "This plugin is not listed in the marketplace",
   898  				}},
   899  				Manifest: manifest,
   900  			},
   901  			InstalledVersion: manifest.Version,
   902  		}
   903  		expectedPlugins := append(samplePlugins, plugin1)
   904  
   905  		manifest, resp = th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarDataV2))
   906  		CheckNoError(t, resp)
   907  
   908  		plugin2 := &model.MarketplacePlugin{
   909  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
   910  				IconData:        testIconData,
   911  				HomepageURL:     "https://example.com/homepage",
   912  				DownloadURL:     "",
   913  				ReleaseNotesURL: "https://example.com/releases/v1.2.3",
   914  				Labels: []model.MarketplaceLabel{{
   915  					Name:        "Local",
   916  					Description: "This plugin is not listed in the marketplace",
   917  				}},
   918  				Manifest: manifest,
   919  			},
   920  			InstalledVersion: manifest.Version,
   921  		}
   922  		expectedPlugins = append(expectedPlugins, plugin2)
   923  		sort.SliceStable(expectedPlugins, func(i, j int) bool {
   924  			return strings.ToLower(expectedPlugins[i].Manifest.Name) < strings.ToLower(expectedPlugins[j].Manifest.Name)
   925  		})
   926  
   927  		plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
   928  		CheckNoError(t, resp)
   929  		require.Equal(t, expectedPlugins, plugins)
   930  
   931  		// Search for plugins from the server
   932  		plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "testplugin2"})
   933  		CheckNoError(t, resp)
   934  		require.Equal(t, []*model.MarketplacePlugin{plugin2}, plugins)
   935  
   936  		plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "a second plugin"})
   937  		CheckNoError(t, resp)
   938  		require.Equal(t, []*model.MarketplacePlugin{plugin2}, plugins)
   939  
   940  		plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "User Satisfaction Surveys"})
   941  		CheckNoError(t, resp)
   942  		require.Equal(t, samplePlugins, plugins)
   943  
   944  		plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "NOFILTER"})
   945  		CheckNoError(t, resp)
   946  		require.Nil(t, plugins)
   947  
   948  		// cleanup
   949  		ok, resp := th.SystemAdminClient.RemovePlugin(plugin1.Manifest.Id)
   950  		CheckNoError(t, resp)
   951  		assert.True(t, ok)
   952  
   953  		ok, resp = th.SystemAdminClient.RemovePlugin(plugin2.Manifest.Id)
   954  		CheckNoError(t, resp)
   955  		assert.True(t, ok)
   956  	})
   957  }
   958  
   959  func TestGetLocalPluginInMarketplace(t *testing.T) {
   960  	th := Setup(t)
   961  	defer th.TearDown()
   962  
   963  	samplePlugins := []*model.MarketplacePlugin{
   964  		{
   965  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
   966  				HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
   967  				IconData:    "https://example.com/icon.svg",
   968  				DownloadURL: "www.github.com/example",
   969  				Manifest: &model.Manifest{
   970  					Id:               "testplugin2",
   971  					Name:             "testplugin2",
   972  					Description:      "a second plugin",
   973  					Version:          "1.2.2",
   974  					MinServerVersion: "",
   975  				},
   976  			},
   977  			InstalledVersion: "",
   978  		},
   979  	}
   980  
   981  	testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   982  		res.WriteHeader(http.StatusOK)
   983  		json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0]})
   984  		require.NoError(t, err)
   985  		res.Write(json)
   986  	}))
   987  	defer testServer.Close()
   988  
   989  	th.App.UpdateConfig(func(cfg *model.Config) {
   990  		*cfg.PluginSettings.Enable = true
   991  		*cfg.PluginSettings.EnableMarketplace = true
   992  		*cfg.PluginSettings.MarketplaceUrl = testServer.URL
   993  	})
   994  
   995  	t.Run("Get plugins with EnableRemoteMarketplace enabled", func(t *testing.T) {
   996  		th.App.UpdateConfig(func(cfg *model.Config) {
   997  			*cfg.PluginSettings.EnableRemoteMarketplace = true
   998  		})
   999  
  1000  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  1001  		CheckNoError(t, resp)
  1002  
  1003  		require.Len(t, plugins, len(samplePlugins))
  1004  		require.Equal(t, samplePlugins, plugins)
  1005  	})
  1006  
  1007  	t.Run("get remote and local plugins", func(t *testing.T) {
  1008  		th.App.UpdateConfig(func(cfg *model.Config) {
  1009  			*cfg.PluginSettings.EnableRemoteMarketplace = true
  1010  			*cfg.PluginSettings.EnableUploads = true
  1011  		})
  1012  
  1013  		// Upload one local plugin
  1014  		path, _ := fileutils.FindDir("tests")
  1015  		tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  1016  		require.NoError(t, err)
  1017  
  1018  		manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  1019  		CheckNoError(t, resp)
  1020  
  1021  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  1022  		CheckNoError(t, resp)
  1023  
  1024  		require.Len(t, plugins, 2)
  1025  
  1026  		ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  1027  		CheckNoError(t, resp)
  1028  		assert.True(t, ok)
  1029  	})
  1030  
  1031  	t.Run("EnableRemoteMarketplace disabled", func(t *testing.T) {
  1032  		th.App.UpdateConfig(func(cfg *model.Config) {
  1033  			*cfg.PluginSettings.EnableRemoteMarketplace = false
  1034  			*cfg.PluginSettings.EnableUploads = true
  1035  		})
  1036  
  1037  		// No marketplace plugins returned
  1038  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  1039  		CheckNoError(t, resp)
  1040  
  1041  		require.Len(t, plugins, 0)
  1042  
  1043  		// Upload one local plugin
  1044  		path, _ := fileutils.FindDir("tests")
  1045  		tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  1046  		require.NoError(t, err)
  1047  
  1048  		manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  1049  		CheckNoError(t, resp)
  1050  
  1051  		testIcon, err := ioutil.ReadFile(filepath.Join(path, "test.svg"))
  1052  		require.NoError(t, err)
  1053  		require.True(t, svg.Is(testIcon))
  1054  		testIconData := fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(testIcon))
  1055  
  1056  		newPlugin := &model.MarketplacePlugin{
  1057  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  1058  				IconData:        testIconData,
  1059  				HomepageURL:     "https://example.com/homepage",
  1060  				ReleaseNotesURL: "https://example.com/releases/v0.0.1",
  1061  				Manifest:        manifest,
  1062  			},
  1063  			InstalledVersion: manifest.Version,
  1064  		}
  1065  
  1066  		plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  1067  		CheckNoError(t, resp)
  1068  
  1069  		// Only get the local plugins
  1070  		require.Len(t, plugins, 1)
  1071  		require.Equal(t, newPlugin, plugins[0])
  1072  
  1073  		ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  1074  		CheckNoError(t, resp)
  1075  		assert.True(t, ok)
  1076  	})
  1077  
  1078  	t.Run("local_only true", func(t *testing.T) {
  1079  		th.App.UpdateConfig(func(cfg *model.Config) {
  1080  			*cfg.PluginSettings.EnableRemoteMarketplace = true
  1081  			*cfg.PluginSettings.EnableUploads = true
  1082  		})
  1083  
  1084  		// Upload one local plugin
  1085  		path, _ := fileutils.FindDir("tests")
  1086  		tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  1087  		require.NoError(t, err)
  1088  
  1089  		manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  1090  		CheckNoError(t, resp)
  1091  
  1092  		testIcon, err := ioutil.ReadFile(filepath.Join(path, "test.svg"))
  1093  		require.NoError(t, err)
  1094  		require.True(t, svg.Is(testIcon))
  1095  		testIconData := fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(testIcon))
  1096  
  1097  		newPlugin := &model.MarketplacePlugin{
  1098  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  1099  				Manifest:        manifest,
  1100  				IconData:        testIconData,
  1101  				HomepageURL:     "https://example.com/homepage",
  1102  				ReleaseNotesURL: "https://example.com/releases/v0.0.1",
  1103  				Labels: []model.MarketplaceLabel{{
  1104  					Name:        "Local",
  1105  					Description: "This plugin is not listed in the marketplace",
  1106  				}},
  1107  			},
  1108  			InstalledVersion: manifest.Version,
  1109  		}
  1110  
  1111  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{LocalOnly: true})
  1112  		CheckNoError(t, resp)
  1113  
  1114  		require.Len(t, plugins, 1)
  1115  		require.Equal(t, newPlugin, plugins[0])
  1116  
  1117  		ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  1118  		CheckNoError(t, resp)
  1119  		assert.True(t, ok)
  1120  	})
  1121  }
  1122  
  1123  func TestGetPrepackagedPluginInMarketplace(t *testing.T) {
  1124  	th := Setup(t)
  1125  	defer th.TearDown()
  1126  
  1127  	marketplacePlugins := []*model.MarketplacePlugin{
  1128  		{
  1129  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  1130  				HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
  1131  				IconData:    "https://example.com/icon.svg",
  1132  				DownloadURL: "www.github.com/example",
  1133  				Manifest: &model.Manifest{
  1134  					Id:               "marketplace.test",
  1135  					Name:             "marketplacetest",
  1136  					Description:      "a marketplace plugin",
  1137  					Version:          "0.1.2",
  1138  					MinServerVersion: "",
  1139  				},
  1140  			},
  1141  			InstalledVersion: "",
  1142  		},
  1143  	}
  1144  
  1145  	testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1146  		res.WriteHeader(http.StatusOK)
  1147  		json, err := json.Marshal([]*model.MarketplacePlugin{marketplacePlugins[0]})
  1148  		require.NoError(t, err)
  1149  		res.Write(json)
  1150  	}))
  1151  	defer testServer.Close()
  1152  
  1153  	th.App.UpdateConfig(func(cfg *model.Config) {
  1154  		*cfg.PluginSettings.Enable = true
  1155  		*cfg.PluginSettings.EnableMarketplace = true
  1156  		*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1157  	})
  1158  
  1159  	prepackagePlugin := &plugin.PrepackagedPlugin{
  1160  		Manifest: &model.Manifest{
  1161  			Version: "0.0.1",
  1162  			Id:      "prepackaged.test",
  1163  		},
  1164  	}
  1165  
  1166  	env := th.App.GetPluginsEnvironment()
  1167  	env.SetPrepackagedPlugins([]*plugin.PrepackagedPlugin{prepackagePlugin})
  1168  
  1169  	t.Run("get remote and prepackaged plugins", func(t *testing.T) {
  1170  		th.App.UpdateConfig(func(cfg *model.Config) {
  1171  			*cfg.PluginSettings.EnableRemoteMarketplace = true
  1172  			*cfg.PluginSettings.EnableUploads = true
  1173  		})
  1174  
  1175  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  1176  		CheckNoError(t, resp)
  1177  
  1178  		expectedPlugins := marketplacePlugins
  1179  		expectedPlugins = append(expectedPlugins, &model.MarketplacePlugin{
  1180  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  1181  				Manifest: prepackagePlugin.Manifest,
  1182  			},
  1183  		})
  1184  
  1185  		require.ElementsMatch(t, expectedPlugins, plugins)
  1186  		require.Len(t, plugins, 2)
  1187  	})
  1188  
  1189  	t.Run("EnableRemoteMarketplace disabled", func(t *testing.T) {
  1190  		th.App.UpdateConfig(func(cfg *model.Config) {
  1191  			*cfg.PluginSettings.EnableRemoteMarketplace = false
  1192  			*cfg.PluginSettings.EnableUploads = true
  1193  		})
  1194  
  1195  		// No marketplace plugins returned
  1196  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  1197  		CheckNoError(t, resp)
  1198  
  1199  		// Only returns the prepackaged plugins
  1200  		require.Len(t, plugins, 1)
  1201  		require.Equal(t, prepackagePlugin.Manifest, plugins[0].Manifest)
  1202  	})
  1203  
  1204  	t.Run("get prepackaged plugin if newer", func(t *testing.T) {
  1205  		th.App.UpdateConfig(func(cfg *model.Config) {
  1206  			*cfg.PluginSettings.EnableRemoteMarketplace = true
  1207  			*cfg.PluginSettings.EnableUploads = true
  1208  		})
  1209  
  1210  		manifest := &model.Manifest{
  1211  			Version: "1.2.3",
  1212  			Id:      "marketplace.test",
  1213  		}
  1214  
  1215  		newerPrepackagePlugin := &plugin.PrepackagedPlugin{
  1216  			Manifest: manifest,
  1217  		}
  1218  
  1219  		env := th.App.GetPluginsEnvironment()
  1220  		env.SetPrepackagedPlugins([]*plugin.PrepackagedPlugin{newerPrepackagePlugin})
  1221  
  1222  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  1223  		CheckNoError(t, resp)
  1224  
  1225  		require.Len(t, plugins, 1)
  1226  		require.Equal(t, newerPrepackagePlugin.Manifest, plugins[0].Manifest)
  1227  	})
  1228  
  1229  	t.Run("prepackaged plugins are not shown in Cloud", func(t *testing.T) {
  1230  		th.App.UpdateConfig(func(cfg *model.Config) {
  1231  			*cfg.PluginSettings.EnableRemoteMarketplace = true
  1232  			*cfg.PluginSettings.EnableUploads = true
  1233  		})
  1234  
  1235  		th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
  1236  
  1237  		plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  1238  		CheckNoError(t, resp)
  1239  
  1240  		require.ElementsMatch(t, marketplacePlugins, plugins)
  1241  		require.Len(t, plugins, 1)
  1242  	})
  1243  }
  1244  
  1245  func TestInstallMarketplacePlugin(t *testing.T) {
  1246  	th := Setup(t).InitBasic()
  1247  	defer th.TearDown()
  1248  
  1249  	th.App.UpdateConfig(func(cfg *model.Config) {
  1250  		*cfg.PluginSettings.Enable = true
  1251  		*cfg.PluginSettings.EnableUploads = true
  1252  		*cfg.PluginSettings.EnableMarketplace = false
  1253  	})
  1254  
  1255  	path, _ := fileutils.FindDir("tests")
  1256  	signatureFilename := "testplugin2.tar.gz.sig"
  1257  	signatureFileReader, err := os.Open(filepath.Join(path, signatureFilename))
  1258  	require.NoError(t, err)
  1259  	sigFile, err := ioutil.ReadAll(signatureFileReader)
  1260  	require.NoError(t, err)
  1261  	pluginSignature := base64.StdEncoding.EncodeToString(sigFile)
  1262  
  1263  	tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin2.tar.gz"))
  1264  	require.NoError(t, err)
  1265  	pluginServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1266  		res.WriteHeader(http.StatusOK)
  1267  		res.Write(tarData)
  1268  	}))
  1269  	defer pluginServer.Close()
  1270  
  1271  	samplePlugins := []*model.MarketplacePlugin{
  1272  		{
  1273  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  1274  				HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
  1275  				IconData:    "https://example.com/icon.svg",
  1276  				DownloadURL: pluginServer.URL,
  1277  				Manifest: &model.Manifest{
  1278  					Id:               "testplugin2",
  1279  					Name:             "testplugin2",
  1280  					Description:      "a second plugin",
  1281  					Version:          "1.2.2",
  1282  					MinServerVersion: "",
  1283  				},
  1284  			},
  1285  			InstalledVersion: "",
  1286  		},
  1287  		{
  1288  			BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  1289  				HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
  1290  				IconData:    "https://example.com/icon.svg",
  1291  				DownloadURL: pluginServer.URL,
  1292  				Manifest: &model.Manifest{
  1293  					Id:               "testplugin2",
  1294  					Name:             "testplugin2",
  1295  					Description:      "a second plugin",
  1296  					Version:          "1.2.3",
  1297  					MinServerVersion: "",
  1298  				},
  1299  				Signature: pluginSignature,
  1300  			},
  1301  			InstalledVersion: "",
  1302  		},
  1303  	}
  1304  
  1305  	request := &model.InstallMarketplacePluginRequest{Id: "", Version: ""}
  1306  
  1307  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1308  		th.App.UpdateConfig(func(cfg *model.Config) {
  1309  			*cfg.PluginSettings.EnableMarketplace = false
  1310  			*cfg.PluginSettings.MarketplaceUrl = "invalid.com"
  1311  		})
  1312  		plugin, resp := client.InstallMarketplacePlugin(request)
  1313  		CheckNotImplementedStatus(t, resp)
  1314  		require.Nil(t, plugin)
  1315  	}, "marketplace disabled")
  1316  
  1317  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1318  		th.App.UpdateConfig(func(cfg *model.Config) {
  1319  			*cfg.PluginSettings.Enable = true
  1320  			*cfg.PluginSettings.RequirePluginSignature = true
  1321  		})
  1322  		manifest, resp := client.UploadPlugin(bytes.NewReader(tarData))
  1323  		CheckNotImplementedStatus(t, resp)
  1324  		require.Nil(t, manifest)
  1325  
  1326  		manifest, resp = client.InstallPluginFromUrl("some_url", true)
  1327  		CheckNotImplementedStatus(t, resp)
  1328  		require.Nil(t, manifest)
  1329  	}, "RequirePluginSignature enabled")
  1330  
  1331  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1332  		th.App.UpdateConfig(func(cfg *model.Config) {
  1333  			*cfg.PluginSettings.EnableMarketplace = true
  1334  			*cfg.PluginSettings.MarketplaceUrl = "invalid.com"
  1335  		})
  1336  
  1337  		plugin, resp := client.InstallMarketplacePlugin(request)
  1338  		CheckInternalErrorStatus(t, resp)
  1339  		require.Nil(t, plugin)
  1340  	}, "no server")
  1341  
  1342  	t.Run("no permission", func(t *testing.T) {
  1343  		th.App.UpdateConfig(func(cfg *model.Config) {
  1344  			*cfg.PluginSettings.EnableMarketplace = true
  1345  			*cfg.PluginSettings.MarketplaceUrl = "invalid.com"
  1346  		})
  1347  
  1348  		plugin, resp := th.Client.InstallMarketplacePlugin(request)
  1349  		CheckForbiddenStatus(t, resp)
  1350  		require.Nil(t, plugin)
  1351  	})
  1352  
  1353  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1354  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1355  			res.WriteHeader(http.StatusOK)
  1356  			json, err := json.Marshal([]*model.MarketplacePlugin{})
  1357  			require.NoError(t, err)
  1358  			res.Write(json)
  1359  		}))
  1360  		defer testServer.Close()
  1361  
  1362  		th.App.UpdateConfig(func(cfg *model.Config) {
  1363  			*cfg.PluginSettings.EnableMarketplace = true
  1364  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1365  		})
  1366  		pRequest := &model.InstallMarketplacePluginRequest{Id: "some_plugin_id", Version: "0.0.1"}
  1367  		plugin, resp := client.InstallMarketplacePlugin(pRequest)
  1368  		CheckInternalErrorStatus(t, resp)
  1369  		require.Nil(t, plugin)
  1370  	}, "plugin not found on the server")
  1371  
  1372  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1373  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1374  			res.WriteHeader(http.StatusOK)
  1375  			json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0]})
  1376  			require.NoError(t, err)
  1377  			res.Write(json)
  1378  		}))
  1379  		defer testServer.Close()
  1380  
  1381  		th.App.UpdateConfig(func(cfg *model.Config) {
  1382  			*cfg.PluginSettings.EnableMarketplace = true
  1383  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1384  			*cfg.PluginSettings.AllowInsecureDownloadUrl = true
  1385  		})
  1386  		pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.2"}
  1387  		plugin, resp := client.InstallMarketplacePlugin(pRequest)
  1388  		CheckInternalErrorStatus(t, resp)
  1389  		require.Nil(t, plugin)
  1390  	}, "plugin not verified")
  1391  
  1392  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1393  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1394  			serverVersion := req.URL.Query().Get("server_version")
  1395  			require.NotEmpty(t, serverVersion)
  1396  			require.Equal(t, model.CurrentVersion, serverVersion)
  1397  			res.WriteHeader(http.StatusOK)
  1398  			json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[1]})
  1399  			require.NoError(t, err)
  1400  			res.Write(json)
  1401  		}))
  1402  		defer testServer.Close()
  1403  
  1404  		th.App.UpdateConfig(func(cfg *model.Config) {
  1405  			*cfg.PluginSettings.EnableMarketplace = true
  1406  			*cfg.PluginSettings.EnableRemoteMarketplace = true
  1407  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1408  		})
  1409  
  1410  		key, err := os.Open(filepath.Join(path, "development-private-key.asc"))
  1411  		require.NoError(t, err)
  1412  		appErr := th.App.AddPublicKey("pub_key", key)
  1413  		require.Nil(t, appErr)
  1414  
  1415  		pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.3"}
  1416  		manifest, resp := client.InstallMarketplacePlugin(pRequest)
  1417  		CheckNoError(t, resp)
  1418  		require.NotNil(t, manifest)
  1419  		require.Equal(t, "testplugin2", manifest.Id)
  1420  		require.Equal(t, "1.2.3", manifest.Version)
  1421  
  1422  		filePath := filepath.Join("plugins", "testplugin2.tar.gz.sig")
  1423  		savedSigFile, appErr := th.App.ReadFile(filePath)
  1424  		require.Nil(t, appErr)
  1425  		require.EqualValues(t, sigFile, savedSigFile)
  1426  
  1427  		ok, resp := client.RemovePlugin(manifest.Id)
  1428  		CheckNoError(t, resp)
  1429  		assert.True(t, ok)
  1430  		exists, appErr := th.App.FileExists(filePath)
  1431  		require.Nil(t, appErr)
  1432  		require.False(t, exists)
  1433  
  1434  		appErr = th.App.DeletePublicKey("pub_key")
  1435  		require.Nil(t, appErr)
  1436  	}, "verify, install and remove plugin")
  1437  
  1438  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1439  		requestHandled := false
  1440  
  1441  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1442  			licenseType, ok := req.URL.Query()["enterprise_plugins"]
  1443  			require.True(t, ok)
  1444  			require.Len(t, licenseType, 1)
  1445  			require.Equal(t, "false", licenseType[0])
  1446  
  1447  			res.WriteHeader(http.StatusOK)
  1448  			json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0]})
  1449  			require.NoError(t, err)
  1450  			_, err = res.Write(json)
  1451  			require.NoError(t, err)
  1452  
  1453  			requestHandled = true
  1454  		}))
  1455  		defer func() { testServer.Close() }()
  1456  
  1457  		th.App.UpdateConfig(func(cfg *model.Config) {
  1458  			*cfg.PluginSettings.EnableMarketplace = true
  1459  			*cfg.PluginSettings.EnableRemoteMarketplace = true
  1460  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1461  		})
  1462  
  1463  		// The content of the request is irrelevant. This test only cares about enterprise_plugins.
  1464  		pRequest := &model.InstallMarketplacePluginRequest{}
  1465  		manifest, resp := client.InstallMarketplacePlugin(pRequest)
  1466  		CheckInternalErrorStatus(t, resp)
  1467  		require.Nil(t, manifest)
  1468  		assert.True(t, requestHandled)
  1469  	}, "verify EnterprisePlugins is false for TE")
  1470  
  1471  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1472  		requestHandled := false
  1473  
  1474  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1475  			licenseType, ok := req.URL.Query()["enterprise_plugins"]
  1476  			require.True(t, ok)
  1477  			require.Len(t, licenseType, 1)
  1478  			require.Equal(t, "false", licenseType[0])
  1479  
  1480  			res.WriteHeader(http.StatusOK)
  1481  			json, err := json.Marshal([]*model.MarketplacePlugin{})
  1482  			require.NoError(t, err)
  1483  			_, err = res.Write(json)
  1484  			require.NoError(t, err)
  1485  
  1486  			requestHandled = true
  1487  		}))
  1488  		defer func() { testServer.Close() }()
  1489  
  1490  		th.App.UpdateConfig(func(cfg *model.Config) {
  1491  			*cfg.PluginSettings.EnableMarketplace = true
  1492  			*cfg.PluginSettings.EnableRemoteMarketplace = true
  1493  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1494  		})
  1495  
  1496  		l := model.NewTestLicense()
  1497  		// model.NewTestLicense generates a E20 license
  1498  		*l.Features.EnterprisePlugins = false
  1499  		th.App.Srv().SetLicense(l)
  1500  
  1501  		// The content of the request is irrelevant. This test only cares about enterprise_plugins.
  1502  		pRequest := &model.InstallMarketplacePluginRequest{}
  1503  		manifest, resp := client.InstallMarketplacePlugin(pRequest)
  1504  		CheckInternalErrorStatus(t, resp)
  1505  		require.Nil(t, manifest)
  1506  		assert.True(t, requestHandled)
  1507  	}, "verify EnterprisePlugins is false for E10")
  1508  
  1509  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1510  		requestHandled := false
  1511  
  1512  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1513  			licenseType, ok := req.URL.Query()["enterprise_plugins"]
  1514  			require.True(t, ok)
  1515  			require.Len(t, licenseType, 1)
  1516  			require.Equal(t, "true", licenseType[0])
  1517  
  1518  			res.WriteHeader(http.StatusOK)
  1519  			json, err := json.Marshal([]*model.MarketplacePlugin{})
  1520  			require.NoError(t, err)
  1521  			_, err = res.Write(json)
  1522  			require.NoError(t, err)
  1523  
  1524  			requestHandled = true
  1525  		}))
  1526  		defer func() { testServer.Close() }()
  1527  
  1528  		th.App.UpdateConfig(func(cfg *model.Config) {
  1529  			*cfg.PluginSettings.EnableMarketplace = true
  1530  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1531  		})
  1532  
  1533  		th.App.Srv().SetLicense(model.NewTestLicense("enterprise_plugins"))
  1534  
  1535  		// The content of the request is irrelevant. This test only cares about enterprise_plugins.
  1536  		pRequest := &model.InstallMarketplacePluginRequest{}
  1537  		manifest, resp := client.InstallMarketplacePlugin(pRequest)
  1538  		CheckInternalErrorStatus(t, resp)
  1539  		require.Nil(t, manifest)
  1540  		assert.True(t, requestHandled)
  1541  	}, "verify EnterprisePlugins is true for E20")
  1542  
  1543  	t.Run("install prepackaged and remote plugins through marketplace", func(t *testing.T) {
  1544  		prepackagedPluginsDir := "prepackaged_plugins"
  1545  
  1546  		os.RemoveAll(prepackagedPluginsDir)
  1547  		err := os.Mkdir(prepackagedPluginsDir, os.ModePerm)
  1548  		require.NoError(t, err)
  1549  		defer os.RemoveAll(prepackagedPluginsDir)
  1550  
  1551  		prepackagedPluginsDir, found := fileutils.FindDir(prepackagedPluginsDir)
  1552  		require.True(t, found, "failed to find prepackaged plugins directory")
  1553  
  1554  		err = testlib.CopyFile(filepath.Join(path, "testplugin.tar.gz"), filepath.Join(prepackagedPluginsDir, "testplugin.tar.gz"))
  1555  		require.NoError(t, err)
  1556  		err = testlib.CopyFile(filepath.Join(path, "testplugin.tar.gz.asc"), filepath.Join(prepackagedPluginsDir, "testplugin.tar.gz.sig"))
  1557  		require.NoError(t, err)
  1558  
  1559  		th2 := SetupConfig(t, func(cfg *model.Config) {
  1560  			// Disable auto-installing prepackaged plugins
  1561  			*cfg.PluginSettings.AutomaticPrepackagedPlugins = false
  1562  		}).InitBasic()
  1563  		defer th2.TearDown()
  1564  
  1565  		th2.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1566  			pluginSignatureFile, err := os.Open(filepath.Join(path, "testplugin.tar.gz.asc"))
  1567  			require.NoError(t, err)
  1568  			pluginSignatureData, err := ioutil.ReadAll(pluginSignatureFile)
  1569  			require.NoError(t, err)
  1570  
  1571  			key, err := os.Open(filepath.Join(path, "development-private-key.asc"))
  1572  			require.NoError(t, err)
  1573  			appErr := th2.App.AddPublicKey("pub_key", key)
  1574  			require.Nil(t, appErr)
  1575  
  1576  			testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1577  				serverVersion := req.URL.Query().Get("server_version")
  1578  				require.NotEmpty(t, serverVersion)
  1579  				require.Equal(t, model.CurrentVersion, serverVersion)
  1580  				res.WriteHeader(http.StatusOK)
  1581  				json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[1]})
  1582  				require.NoError(t, err)
  1583  				res.Write(json)
  1584  			}))
  1585  			defer testServer.Close()
  1586  
  1587  			th2.App.UpdateConfig(func(cfg *model.Config) {
  1588  				*cfg.PluginSettings.EnableMarketplace = true
  1589  				*cfg.PluginSettings.EnableRemoteMarketplace = false
  1590  				*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1591  				*cfg.PluginSettings.AllowInsecureDownloadUrl = false
  1592  			})
  1593  
  1594  			env := th2.App.GetPluginsEnvironment()
  1595  
  1596  			pluginsResp, resp := client.GetPlugins()
  1597  			CheckNoError(t, resp)
  1598  			require.Len(t, pluginsResp.Active, 0)
  1599  			require.Len(t, pluginsResp.Inactive, 0)
  1600  
  1601  			// Should fail to install unknown prepackaged plugin
  1602  			pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin", Version: "0.0.2"}
  1603  			manifest, resp := client.InstallMarketplacePlugin(pRequest)
  1604  			CheckInternalErrorStatus(t, resp)
  1605  			require.Nil(t, manifest)
  1606  
  1607  			plugins := env.PrepackagedPlugins()
  1608  			require.Len(t, plugins, 1)
  1609  			require.Equal(t, "testplugin", plugins[0].Manifest.Id)
  1610  			require.Equal(t, pluginSignatureData, plugins[0].Signature)
  1611  
  1612  			pluginsResp, resp = client.GetPlugins()
  1613  			CheckNoError(t, resp)
  1614  			require.Len(t, pluginsResp.Active, 0)
  1615  			require.Len(t, pluginsResp.Inactive, 0)
  1616  
  1617  			pRequest = &model.InstallMarketplacePluginRequest{Id: "testplugin", Version: "0.0.1"}
  1618  			manifest1, resp := client.InstallMarketplacePlugin(pRequest)
  1619  			CheckNoError(t, resp)
  1620  			require.NotNil(t, manifest1)
  1621  			require.Equal(t, "testplugin", manifest1.Id)
  1622  			require.Equal(t, "0.0.1", manifest1.Version)
  1623  
  1624  			pluginsResp, resp = client.GetPlugins()
  1625  			CheckNoError(t, resp)
  1626  			require.Len(t, pluginsResp.Active, 0)
  1627  			require.Equal(t, pluginsResp.Inactive, []*model.PluginInfo{{
  1628  				Manifest: *manifest1,
  1629  			}})
  1630  
  1631  			// Try to install remote marketplace plugin
  1632  			pRequest = &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.3"}
  1633  			manifest, resp = client.InstallMarketplacePlugin(pRequest)
  1634  			CheckInternalErrorStatus(t, resp)
  1635  			require.Nil(t, manifest)
  1636  
  1637  			// Enable remote marketplace
  1638  			th2.App.UpdateConfig(func(cfg *model.Config) {
  1639  				*cfg.PluginSettings.EnableMarketplace = true
  1640  				*cfg.PluginSettings.EnableRemoteMarketplace = true
  1641  				*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1642  				*cfg.PluginSettings.AllowInsecureDownloadUrl = true
  1643  			})
  1644  
  1645  			pRequest = &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.3"}
  1646  			manifest2, resp := client.InstallMarketplacePlugin(pRequest)
  1647  			CheckNoError(t, resp)
  1648  			require.NotNil(t, manifest2)
  1649  			require.Equal(t, "testplugin2", manifest2.Id)
  1650  			require.Equal(t, "1.2.3", manifest2.Version)
  1651  
  1652  			pluginsResp, resp = client.GetPlugins()
  1653  			CheckNoError(t, resp)
  1654  			require.Len(t, pluginsResp.Active, 0)
  1655  			require.ElementsMatch(t, pluginsResp.Inactive, []*model.PluginInfo{
  1656  				{
  1657  					Manifest: *manifest1,
  1658  				},
  1659  				{
  1660  					Manifest: *manifest2,
  1661  				},
  1662  			})
  1663  
  1664  			// Clean up
  1665  			ok, resp := client.RemovePlugin(manifest1.Id)
  1666  			CheckNoError(t, resp)
  1667  			assert.True(t, ok)
  1668  
  1669  			ok, resp = client.RemovePlugin(manifest2.Id)
  1670  			CheckNoError(t, resp)
  1671  			assert.True(t, ok)
  1672  
  1673  			appErr = th2.App.DeletePublicKey("pub_key")
  1674  			require.Nil(t, appErr)
  1675  		})
  1676  	})
  1677  
  1678  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  1679  		prepackagedPluginsDir := "prepackaged_plugins"
  1680  
  1681  		os.RemoveAll(prepackagedPluginsDir)
  1682  		err := os.Mkdir(prepackagedPluginsDir, os.ModePerm)
  1683  		require.NoError(t, err)
  1684  		defer os.RemoveAll(prepackagedPluginsDir)
  1685  
  1686  		prepackagedPluginsDir, found := fileutils.FindDir(prepackagedPluginsDir)
  1687  		require.True(t, found, "failed to find prepackaged plugins directory")
  1688  
  1689  		err = testlib.CopyFile(filepath.Join(path, "testplugin.tar.gz"), filepath.Join(prepackagedPluginsDir, "testplugin.tar.gz"))
  1690  		require.NoError(t, err)
  1691  
  1692  		th := SetupConfig(t, func(cfg *model.Config) {
  1693  			// Disable auto-installing prepackged plugins
  1694  			*cfg.PluginSettings.AutomaticPrepackagedPlugins = false
  1695  		}).InitBasic()
  1696  		defer th.TearDown()
  1697  
  1698  		key, err := os.Open(filepath.Join(path, "development-private-key.asc"))
  1699  		require.NoError(t, err)
  1700  		appErr := th.App.AddPublicKey("pub_key", key)
  1701  		require.Nil(t, appErr)
  1702  
  1703  		testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1704  			serverVersion := req.URL.Query().Get("server_version")
  1705  			require.NotEmpty(t, serverVersion)
  1706  			require.Equal(t, model.CurrentVersion, serverVersion)
  1707  
  1708  			mPlugins := []*model.MarketplacePlugin{samplePlugins[0]}
  1709  			require.Empty(t, mPlugins[0].Signature)
  1710  			res.WriteHeader(http.StatusOK)
  1711  			json, err := json.Marshal(mPlugins)
  1712  			require.NoError(t, err)
  1713  			res.Write(json)
  1714  		}))
  1715  		defer testServer.Close()
  1716  
  1717  		th.App.UpdateConfig(func(cfg *model.Config) {
  1718  			*cfg.PluginSettings.EnableMarketplace = true
  1719  			*cfg.PluginSettings.EnableRemoteMarketplace = true
  1720  			*cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1721  			*cfg.PluginSettings.AllowInsecureDownloadUrl = true
  1722  		})
  1723  
  1724  		env := th.App.GetPluginsEnvironment()
  1725  		plugins := env.PrepackagedPlugins()
  1726  		require.Len(t, plugins, 1)
  1727  		require.Equal(t, "testplugin", plugins[0].Manifest.Id)
  1728  		require.Empty(t, plugins[0].Signature)
  1729  
  1730  		pluginsResp, resp := client.GetPlugins()
  1731  		CheckNoError(t, resp)
  1732  		require.Len(t, pluginsResp.Active, 0)
  1733  		require.Len(t, pluginsResp.Inactive, 0)
  1734  
  1735  		pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin", Version: "0.0.1"}
  1736  		manifest, resp := client.InstallMarketplacePlugin(pRequest)
  1737  		CheckInternalErrorStatus(t, resp)
  1738  		require.Nil(t, manifest)
  1739  
  1740  		pluginsResp, resp = client.GetPlugins()
  1741  		CheckNoError(t, resp)
  1742  		require.Len(t, pluginsResp.Active, 0)
  1743  		require.Len(t, pluginsResp.Inactive, 0)
  1744  
  1745  		pRequest = &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.3"}
  1746  		manifest, resp = client.InstallMarketplacePlugin(pRequest)
  1747  		CheckInternalErrorStatus(t, resp)
  1748  		require.Nil(t, manifest)
  1749  
  1750  		pluginsResp, resp = client.GetPlugins()
  1751  		CheckNoError(t, resp)
  1752  		require.Len(t, pluginsResp.Active, 0)
  1753  		require.Len(t, pluginsResp.Inactive, 0)
  1754  
  1755  		// Clean up
  1756  		appErr = th.App.DeletePublicKey("pub_key")
  1757  		require.Nil(t, appErr)
  1758  	}, "missing prepackaged and remote plugin signatures")
  1759  }
  1760  
  1761  func findClusterMessages(event string, msgs []*model.ClusterMessage) []*model.ClusterMessage {
  1762  	var result []*model.ClusterMessage
  1763  	for _, msg := range msgs {
  1764  		if msg.Event == event {
  1765  			result = append(result, msg)
  1766  		}
  1767  	}
  1768  	return result
  1769  }