* [MM-18757] POST handler for `/plugins/marketplace` (#12372)

* Implement installMarketplacePlugin

* Add InstallMarketplacePlugin endpoint

* Fix go.mod

* merge with master

* Fix go.mod

* Fix plugin tests

* Move get plugin to marketplace client

* Fix stylistic concerns

* Add trailing newline to the go.mod

* [MM-16586] Add plugin signature settings (#12390)

* MM-17149 - Extend config.json for marketplace settings (#11933)

* MM-17149 - Extend config.json for marketplace settings

* Renamed MarketplaceUrl, tracking default marketplace url

* Added EnableMarketplace to the client config

* Revert "Added EnableMarketplace to the client config"

This reverts commit 0f982c4c661c2cd9bb96264e9a01a2363c40d9c5.

* MM-17149 - Added EnableMarketplace to the client config (#11958)

* Added EnableMarketplace to the client config

* Moved EnableMarketplace setting out of limited client configuration

* Add public key settings to the config.json

* Rename PublicKeys to SignaturePublicKeyFiles

* Change filepath.Split to Base

* Remove additional prints

* Force extention of a public key file

* Remove config validation

* Remove error on delete

* Remove config cloning

* Add error messages

* Add plugin public key tests

* Rename extension to PluginSignaturePublicKeyFileExtention

* Remove EnforceVerification

* Change []*PublicKeyDescription to []string

* Change .asc extension to .plugin.asc

* Change ordering of public methods

* Change plugin key commands

* Update examples in the plugin key commands

* Remove forcing extention

* Add verify signature in settings

* Fix tabbing

* Fix naming

* Remove unused text

* Remove unused text

* Update command examples

* Fix unit tests

* Change errors.New to errors.Wrap

* Fix verbose flag

* Change .asc to .gpg

* Fix }

* Change AddPublicKey signature

* Change public.key extension

* Add plugin public key command tests

* Update en.json

* Bootstrap the public keys

* Update en.json

* Fix en.json

* Fix en.json

* Bootstrap hard-coded public key

* Remove unused texts in en.json

* Change file to name

* Add license header

* Update development public key

* Remove writeFile method

* Remove .plugin.asc extension

* Rename publiKey to mattermostPublicKey

* Remove init_public_keys string

* GolangCI

* Closing file handlers

* Fixed test that was installing nps plugin

* [MM-19798] Implement plugin signature verification (#12768)

* MM-17149 - Extend config.json for marketplace settings (#11933)

* MM-17149 - Extend config.json for marketplace settings

* Renamed MarketplaceUrl, tracking default marketplace url

* Added EnableMarketplace to the client config

* Revert "Added EnableMarketplace to the client config"

This reverts commit 0f982c4c661c2cd9bb96264e9a01a2363c40d9c5.

* MM-17149 - Added EnableMarketplace to the client config (#11958)

* Added EnableMarketplace to the client config

* Moved EnableMarketplace setting out of limited client configuration

* Add public key settings to the config.json

* Rename PublicKeys to SignaturePublicKeyFiles

* Change filepath.Split to Base

* Remove additional prints

* Force extention of a public key file

* Remove config validation

* Remove error on delete

* Remove config cloning

* Add error messages

* Add plugin public key tests

* Rename extension to PluginSignaturePublicKeyFileExtention

* Remove EnforceVerification

* Change []*PublicKeyDescription to []string

* Change .asc extension to .plugin.asc

* Change ordering of public methods

* Change plugin key commands

* Update examples in the plugin key commands

* Remove forcing extention

* Add verify signature in settings

* Fix tabbing

* Fix naming

* Remove unused text

* Remove unused text

* Update command examples

* Fix unit tests

* Change errors.New to errors.Wrap

* Fix verbose flag

* Change .asc to .gpg

* Fix }

* Change AddPublicKey signature

* Change public.key extension

* Add plugin public key command tests

* Update en.json

* Bootstrap the public keys

* Update en.json

* Fix en.json

* Fix en.json

* Bootstrap hard-coded public key

* Remove unused texts in en.json

* Change file to name

* Add license header

* Implement plugin signature verification

* Remove benburker openpgp

* Update en.json

* Update development public key

* Add support of multiple signatures in filestore

* Update en.json

* Run go mod vendor

* Fix style

* Remove writeFile method

* Remove .plugin.asc extension

* Rename publiKey to mattermostPublicKey

* Verify plugin with mattermost public key

* Remove init_public_keys string

* Add InstallPluginWithSignature method and  Refactor

* Add signature verification on claster notification

* Remove armored signature headers

* Add error strings

* Fix en.json

* Change signatureStorePath

* Implement minor fixes

* Refactor plugin install methods

* Add installPlugin method to uploadPlugin

* Update en.json

* Refactor installPlugin

* Limit number of signatures

* Close signatures

* Fix helper function

* Fix fromReadCloseSeekerToReadSeeker

* Cleaned up ReadCloseSeeker for signatures

* Remove signature truncation on FS

* GolangCI

* Add tests for armored signatures and plugin uploads

* Fix nil slice issue

* Fix TestPluginSync

* Fixed tests

* Return io.ReadSeeker from downloadFromUrl

* Add log for the found plugins in the file store

* Remove logging plugin detection info

* [MM-20134] Consume and store single-signature for each plugin (#13081)

* Consume and store single-signature for each plugin

* Fix en.json

* Remove saveSignature method

* Remove public key hash

* PR Feedback

* refactored config

* PR feedback
Этот коммит содержится в:
Ali Farooq
2019-11-18 19:02:41 -05:00
коммит произвёл GitHub
родитель d44d563ef3
Коммит a6e992ae74
56 изменённых файлов: 8692 добавлений и 80 удалений

Просмотреть файл

@@ -5,6 +5,7 @@ package api4
import (
"bytes"
"encoding/base64"
"encoding/json"
"io/ioutil"
"net/http"
@@ -543,9 +544,9 @@ func TestGetInstalledMarketplacePlugins(t *testing.T) {
samplePlugins := []*model.MarketplacePlugin{
{
BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
HomepageURL: "https://github.com/mattermost/mattermost-plugin-nps",
IconData: "http://example.com/icon.svg",
DownloadURL: "https://github.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.3/com.mattermost.nps-1.0.3.tar.gz",
HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
IconData: "https://example.com/icon.svg",
DownloadURL: "https://example.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.3/com.mattermost.nps-1.0.3.tar.gz",
Manifest: &model.Manifest{
Id: "com.mattermost.nps",
Name: "User Satisfaction Surveys",
@@ -671,9 +672,9 @@ func TestSearchGetMarketplacePlugins(t *testing.T) {
samplePlugins := []*model.MarketplacePlugin{
{
BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
HomepageURL: "https://github.com/mattermost/mattermost-plugin-nps",
HomepageURL: "example.com/mattermost/mattermost-plugin-nps",
IconData: "Cjxzdmcgdmlld0JveD0nMCAwIDEwNSA5MycgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJz4KPHBhdGggZD0nTTY2LDBoMzl2OTN6TTM4LDBoLTM4djkzek01MiwzNWwyNSw1OGgtMTZsLTgtMThoLTE4eicgZmlsbD0nI0VEMUMyNCcvPgo8L3N2Zz4K",
DownloadURL: "https://github.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.3/com.mattermost.nps-1.0.3.tar.gz",
DownloadURL: "example.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.3/com.mattermost.nps-1.0.3.tar.gz",
Manifest: &model.Manifest{
Id: "com.mattermost.nps",
Name: "User Satisfaction Surveys",
@@ -769,6 +770,184 @@ func TestSearchGetMarketplacePlugins(t *testing.T) {
})
}
func TestInstallMarketplacePlugin(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.Enable = true
*cfg.PluginSettings.EnableUploads = true
*cfg.PluginSettings.EnableMarketplace = false
})
path, _ := fileutils.FindDir("tests")
signatureFilename := "testpluginv2.tar.gz.sig"
signatureFileReader, err := os.Open(filepath.Join(path, signatureFilename))
require.Nil(t, err)
sigFile, err := ioutil.ReadAll(signatureFileReader)
require.Nil(t, err)
pluginSignature := base64.StdEncoding.EncodeToString(sigFile)
tarData, err := ioutil.ReadFile(filepath.Join(path, "testpluginv2.tar.gz"))
require.NoError(t, err)
pluginServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusOK)
res.Write(tarData)
}))
defer pluginServer.Close()
samplePlugins := []*model.MarketplacePlugin{
{
BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
IconData: "https://example.com/icon.svg",
DownloadURL: pluginServer.URL,
Manifest: &model.Manifest{
Id: "testplugin_v2",
Name: "testplugin_v2",
Description: "dsgsdg_v2",
Version: "1.2.2",
MinServerVersion: "",
},
},
InstalledVersion: "",
},
{
BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
IconData: "https://example.com/icon.svg",
DownloadURL: pluginServer.URL,
Manifest: &model.Manifest{
Id: "testplugin_v2",
Name: "testplugin_v2",
Description: "dsgsdg_v2",
Version: "1.2.3",
MinServerVersion: "",
},
Signature: pluginSignature,
},
InstalledVersion: "",
},
}
request := &model.InstallMarketplacePluginRequest{Id: "", Version: ""}
t.Run("marketplace disabled", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.EnableMarketplace = false
*cfg.PluginSettings.MarketplaceUrl = "invalid.com"
})
plugin, resp := th.SystemAdminClient.InstallMarketplacePlugin(request)
CheckNotImplementedStatus(t, resp)
require.Nil(t, plugin)
})
t.Run("RequirePluginSignature enabled", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.Enable = true
*cfg.PluginSettings.RequirePluginSignature = true
})
manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
CheckNotImplementedStatus(t, resp)
require.Nil(t, manifest)
manifest, resp = th.SystemAdminClient.InstallPluginFromUrl("some_url", true)
CheckNotImplementedStatus(t, resp)
require.Nil(t, manifest)
})
t.Run("no server", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.EnableMarketplace = true
*cfg.PluginSettings.MarketplaceUrl = "invalid.com"
})
plugin, resp := th.SystemAdminClient.InstallMarketplacePlugin(request)
CheckInternalErrorStatus(t, resp)
require.Nil(t, plugin)
})
t.Run("no permission", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.EnableMarketplace = true
*cfg.PluginSettings.MarketplaceUrl = "invalid.com"
})
plugin, resp := th.Client.InstallMarketplacePlugin(request)
CheckForbiddenStatus(t, resp)
require.Nil(t, plugin)
})
t.Run("plugin not found on the server", func(t *testing.T) {
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusOK)
json, err := json.Marshal([]*model.MarketplacePlugin{})
require.NoError(t, err)
res.Write(json)
}))
defer testServer.Close()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.EnableMarketplace = true
*cfg.PluginSettings.MarketplaceUrl = testServer.URL
})
pRequest := &model.InstallMarketplacePluginRequest{Id: "some_plugin_id", Version: "0.0.1"}
plugin, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
CheckInternalErrorStatus(t, resp)
require.Nil(t, plugin)
})
t.Run("plugin not verified", func(t *testing.T) {
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusOK)
json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0]})
require.NoError(t, err)
res.Write(json)
}))
defer testServer.Close()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.EnableMarketplace = true
*cfg.PluginSettings.MarketplaceUrl = testServer.URL
*cfg.PluginSettings.AllowInsecureDownloadUrl = true
})
pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin_v2", Version: "1.2.2"}
plugin, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
CheckInternalErrorStatus(t, resp)
require.Nil(t, plugin)
})
t.Run("verify, install and remove plugin", func(t *testing.T) {
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusOK)
json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[1]})
require.NoError(t, err)
res.Write(json)
}))
defer testServer.Close()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.EnableMarketplace = true
*cfg.PluginSettings.MarketplaceUrl = testServer.URL
})
pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin_v2", Version: "1.2.3"}
manifest, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
CheckNoError(t, resp)
require.NotNil(t, manifest)
require.Equal(t, "testplugin_v2", manifest.Id)
require.Equal(t, "1.2.3", manifest.Version)
filePath := filepath.Join(*th.App.Config().PluginSettings.Directory, "testplugin_v2.sig")
savedSigFile, err := th.App.ReadFile(filePath)
require.Nil(t, err)
require.EqualValues(t, sigFile, savedSigFile)
ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
CheckNoError(t, resp)
assert.True(t, ok)
exists, err := th.App.FileExists(filePath)
require.Nil(t, err)
require.False(t, exists)
})
}
func findClusterMessages(event string, msgs []*model.ClusterMessage) []*model.ClusterMessage {
var result []*model.ClusterMessage
for _, msg := range msgs {