MM-16368 - Plugin Signing (#13017)
* [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
Этот коммит содержится в:
@@ -4462,6 +4462,21 @@ func (c *Client4) InstallPluginFromUrl(downloadUrl string, force bool) (*Manifes
|
||||
return ManifestFromJson(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
// InstallMarketplacePlugin will install marketplace plugin.
|
||||
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
|
||||
func (c *Client4) InstallMarketplacePlugin(request *InstallMarketplacePluginRequest) (*Manifest, *Response) {
|
||||
json, err := request.ToJson()
|
||||
if err != nil {
|
||||
return nil, &Response{Error: NewAppError("InstallMarketplacePlugin", "model.client.plugin_request_to_json.app_error", nil, err.Error(), http.StatusBadRequest)}
|
||||
}
|
||||
r, appErr := c.DoApiPost(c.GetPluginsRoute()+"/marketplace", json)
|
||||
if appErr != nil {
|
||||
return nil, BuildErrorResponse(r, appErr)
|
||||
}
|
||||
defer closeBody(r)
|
||||
return ManifestFromJson(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
// GetPlugins will return a list of plugin manifests for currently active plugins.
|
||||
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
|
||||
func (c *Client4) GetPlugins() (*PluginsResponse, *Response) {
|
||||
|
||||
@@ -2245,7 +2245,9 @@ type PluginSettings struct {
|
||||
Plugins map[string]map[string]interface{}
|
||||
PluginStates map[string]*PluginState
|
||||
EnableMarketplace *bool
|
||||
RequirePluginSignature *bool
|
||||
MarketplaceUrl *string
|
||||
SignaturePublicKeyFiles []string
|
||||
}
|
||||
|
||||
func (s *PluginSettings) SetDefaults(ls LogSettings) {
|
||||
@@ -2293,6 +2295,14 @@ func (s *PluginSettings) SetDefaults(ls LogSettings) {
|
||||
if s.MarketplaceUrl == nil || *s.MarketplaceUrl == "" || *s.MarketplaceUrl == PLUGIN_SETTINGS_OLD_MARKETPLACE_URL {
|
||||
s.MarketplaceUrl = NewString(PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL)
|
||||
}
|
||||
|
||||
if s.RequirePluginSignature == nil {
|
||||
s.RequirePluginSignature = NewBool(false)
|
||||
}
|
||||
|
||||
if s.SignaturePublicKeyFiles == nil {
|
||||
s.SignaturePublicKeyFiles = []string{}
|
||||
}
|
||||
}
|
||||
|
||||
type GlobalRelayMessageExportSettings struct {
|
||||
|
||||
@@ -4,19 +4,25 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// BaseMarketplacePlugin is a Mattermost plugin received from the marketplace server.
|
||||
type BaseMarketplacePlugin struct {
|
||||
HomepageURL string `json:"homepage_url"`
|
||||
DownloadURL string `json:"download_url"`
|
||||
ReleaseNotesURL string `json:"release_notes_url"`
|
||||
IconData string `json:"icon_data"`
|
||||
Manifest *Manifest `json:"manifest"`
|
||||
HomepageURL string `json:"homepage_url"`
|
||||
IconData string `json:"icon_data"`
|
||||
DownloadURL string `json:"download_url"`
|
||||
ReleaseNotesURL string `json:"release_notes_url"`
|
||||
// Signature represents a signature of a plugin saved in base64 encoding.
|
||||
Signature string `json:"signature"`
|
||||
Manifest *Manifest `json:"manifest"`
|
||||
}
|
||||
|
||||
// MarketplacePlugin is a state aware marketplace plugin.
|
||||
@@ -49,6 +55,15 @@ func MarketplacePluginsFromReader(reader io.Reader) ([]*MarketplacePlugin, error
|
||||
return plugins, nil
|
||||
}
|
||||
|
||||
// DecodeSignature Decodes signature and returns ReadSeeker.
|
||||
func (plugin *BaseMarketplacePlugin) DecodeSignature() (io.ReadSeeker, error) {
|
||||
signatureBytes, err := base64.StdEncoding.DecodeString(plugin.Signature)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to decode base64 signature.")
|
||||
}
|
||||
return bytes.NewReader(signatureBytes), nil
|
||||
}
|
||||
|
||||
// MarketplacePluginFilter describes the parameters to request a list of plugins.
|
||||
type MarketplacePluginFilter struct {
|
||||
Page int
|
||||
@@ -68,3 +83,28 @@ func (filter *MarketplacePluginFilter) ApplyToURL(u *url.URL) {
|
||||
q.Add("server_version", filter.ServerVersion)
|
||||
u.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
// InstallMarketplacePluginRequest struct describes parameters of the requested plugin.
|
||||
type InstallMarketplacePluginRequest struct {
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// PluginRequestFromReader decodes a json-encoded plugin request from the given io.Reader.
|
||||
func PluginRequestFromReader(reader io.Reader) (*InstallMarketplacePluginRequest, error) {
|
||||
var r *InstallMarketplacePluginRequest
|
||||
err := json.NewDecoder(reader).Decode(&r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// ToJson method will return json from plugin request.
|
||||
func (r *InstallMarketplacePluginRequest) ToJson() (string, error) {
|
||||
b, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
@@ -624,3 +624,8 @@ func GetPreferredTimezone(timezone StringMap) string {
|
||||
|
||||
return timezone["manualTimezone"]
|
||||
}
|
||||
|
||||
// IsSamlFile checks if filename is a SAML file.
|
||||
func IsSamlFile(saml *SamlSettings, filename string) bool {
|
||||
return filename == *saml.PublicCertificateFile || filename == *saml.PrivateKeyFile || filename == *saml.IdpCertificateFile
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user