github.com/lologarithm/mattermost-server@v5.3.2-0.20181002060438-c82a84ed765b+incompatible/app/plugin_install.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "io" 8 "io/ioutil" 9 "net/http" 10 "os" 11 "path/filepath" 12 13 "github.com/mattermost/mattermost-server/mlog" 14 "github.com/mattermost/mattermost-server/model" 15 "github.com/mattermost/mattermost-server/plugin" 16 "github.com/mattermost/mattermost-server/utils" 17 ) 18 19 // InstallPlugin unpacks and installs a plugin but does not enable or activate it. 20 func (a *App) InstallPlugin(pluginFile io.Reader, replace bool) (*model.Manifest, *model.AppError) { 21 return a.installPlugin(pluginFile, replace) 22 } 23 24 func (a *App) installPlugin(pluginFile io.Reader, replace bool) (*model.Manifest, *model.AppError) { 25 if a.Plugins == nil || !*a.Config().PluginSettings.Enable { 26 return nil, model.NewAppError("installPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) 27 } 28 29 tmpDir, err := ioutil.TempDir("", "plugintmp") 30 if err != nil { 31 return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError) 32 } 33 defer os.RemoveAll(tmpDir) 34 35 if err := utils.ExtractTarGz(pluginFile, tmpDir); err != nil { 36 return nil, model.NewAppError("installPlugin", "app.plugin.extract.app_error", nil, err.Error(), http.StatusBadRequest) 37 } 38 39 tmpPluginDir := tmpDir 40 dir, err := ioutil.ReadDir(tmpDir) 41 if err != nil { 42 return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError) 43 } 44 45 if len(dir) == 1 && dir[0].IsDir() { 46 tmpPluginDir = filepath.Join(tmpPluginDir, dir[0].Name()) 47 } 48 49 manifest, _, err := model.FindManifest(tmpPluginDir) 50 if err != nil { 51 return nil, model.NewAppError("installPlugin", "app.plugin.manifest.app_error", nil, err.Error(), http.StatusBadRequest) 52 } 53 54 if !plugin.IsValidId(manifest.Id) { 55 return nil, model.NewAppError("installPlugin", "app.plugin.invalid_id.app_error", map[string]interface{}{"Min": plugin.MinIdLength, "Max": plugin.MaxIdLength, "Regex": plugin.ValidIdRegex}, "", http.StatusBadRequest) 56 } 57 58 bundles, err := a.Plugins.Available() 59 if err != nil { 60 return nil, model.NewAppError("installPlugin", "app.plugin.install.app_error", nil, err.Error(), http.StatusInternalServerError) 61 } 62 63 // Check that there is no plugin with the same ID 64 for _, bundle := range bundles { 65 if bundle.Manifest != nil && bundle.Manifest.Id == manifest.Id { 66 if !replace { 67 return nil, model.NewAppError("installPlugin", "app.plugin.install_id.app_error", nil, "", http.StatusBadRequest) 68 } 69 70 if err := a.RemovePlugin(manifest.Id); err != nil { 71 return nil, model.NewAppError("installPlugin", "app.plugin.install_id_failed_remove.app_error", nil, "", http.StatusBadRequest) 72 } 73 } 74 } 75 76 pluginPath := filepath.Join(*a.Config().PluginSettings.Directory, manifest.Id) 77 err = utils.CopyDir(tmpPluginDir, pluginPath) 78 if err != nil { 79 return nil, model.NewAppError("installPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError) 80 } 81 82 if err := a.notifyPluginStatusesChanged(); err != nil { 83 mlog.Error("failed to notify plugin status changed", mlog.Err(err)) 84 } 85 86 return manifest, nil 87 } 88 89 func (a *App) RemovePlugin(id string) *model.AppError { 90 return a.removePlugin(id) 91 } 92 93 func (a *App) removePlugin(id string) *model.AppError { 94 if a.Plugins == nil || !*a.Config().PluginSettings.Enable { 95 return model.NewAppError("removePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) 96 } 97 98 plugins, err := a.Plugins.Available() 99 if err != nil { 100 return model.NewAppError("removePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest) 101 } 102 103 var manifest *model.Manifest 104 var pluginPath string 105 for _, p := range plugins { 106 if p.Manifest != nil && p.Manifest.Id == id { 107 manifest = p.Manifest 108 pluginPath = filepath.Dir(p.ManifestPath) 109 break 110 } 111 } 112 113 if manifest == nil { 114 return model.NewAppError("removePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest) 115 } 116 117 if a.Plugins.IsActive(id) && manifest.HasClient() { 118 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DISABLED, "", "", "", nil) 119 message.Add("manifest", manifest.ClientManifest()) 120 a.Publish(message) 121 } 122 123 a.Plugins.Deactivate(id) 124 125 err = os.RemoveAll(pluginPath) 126 if err != nil { 127 return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError) 128 } 129 130 return nil 131 }