[MM-16376] Allow server to download and install a plugin from… (#11372)
* Initial implementation of plugin remote source * Implement API route * Test API route * Add i18n * Handle different error cases in API route * Include missing i18n translation * Include AllowInsecureDownloadUrl in telemetry capture * Updates from PR feedback * Use HTTPService instead of http.Get * Remove InstallPluginFromUrlForced from client4 * Use net/url library to inspect url scheme * remove PluginDownloadUrl from web/params.go * Allow plugin downloads from internal sources
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
44b9fe3110
Коммит
8cdf5ffe67
@@ -7,6 +7,7 @@ package api4
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/mattermost/mattermost-server/mlog"
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
@@ -22,6 +23,7 @@ func (api *API) InitPlugin() {
|
||||
api.BaseRoutes.Plugins.Handle("", api.ApiSessionRequired(uploadPlugin)).Methods("POST")
|
||||
api.BaseRoutes.Plugins.Handle("", api.ApiSessionRequired(getPlugins)).Methods("GET")
|
||||
api.BaseRoutes.Plugin.Handle("", api.ApiSessionRequired(removePlugin)).Methods("DELETE")
|
||||
api.BaseRoutes.Plugins.Handle("/install_from_url", api.ApiSessionRequired(installPluginFromUrl)).Methods("POST")
|
||||
|
||||
api.BaseRoutes.Plugins.Handle("/statuses", api.ApiSessionRequired(getPluginStatuses)).Methods("GET")
|
||||
api.BaseRoutes.Plugin.Handle("/enable", api.ApiSessionRequired(enablePlugin)).Methods("POST")
|
||||
@@ -81,6 +83,58 @@ func uploadPlugin(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(manifest.ToJson()))
|
||||
}
|
||||
|
||||
func installPluginFromUrl(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if !*c.App.Config().PluginSettings.Enable {
|
||||
c.Err = model.NewAppError("installPluginFromUrl", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_SYSTEM) {
|
||||
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
|
||||
return
|
||||
}
|
||||
|
||||
downloadUrl := r.URL.Query().Get("plugin_download_url")
|
||||
|
||||
if !model.IsValidHttpUrl(downloadUrl) {
|
||||
c.Err = model.NewAppError("installPluginFromUrl", "api.plugin.install.invalid_url.app_error", nil, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
u, err := url.ParseRequestURI(downloadUrl)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("installPluginFromUrl", "api.plugin.install.invalid_url.app_error", nil, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if !*c.App.Config().PluginSettings.AllowInsecureDownloadUrl && u.Scheme != "https" {
|
||||
c.Err = model.NewAppError("installPluginFromUrl", "api.plugin.install.insecure_url.app_error", nil, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
client := c.App.HTTPService.MakeClient(true)
|
||||
resp, err := client.Get(downloadUrl)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("installPluginFromUrl", "api.plugin.install.download_failed.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
force := false
|
||||
if r.URL.Query().Get("force") == "true" {
|
||||
force = true
|
||||
}
|
||||
manifest, unpackErr := c.App.InstallPlugin(resp.Body, force)
|
||||
|
||||
if unpackErr != nil {
|
||||
c.Err = unpackErr
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte(manifest.ToJson()))
|
||||
}
|
||||
|
||||
func getPlugins(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if !*c.App.Config().PluginSettings.Enable {
|
||||
c.Err = model.NewAppError("getPlugins", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
|
||||
Ссылка в новой задаче
Block a user