github.com/nhannv/mattermost-server@v5.11.1+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 pluginsEnvironment := a.GetPluginsEnvironment() 26 if pluginsEnvironment == nil { 27 return nil, model.NewAppError("installPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) 28 } 29 30 tmpDir, err := ioutil.TempDir("", "plugintmp") 31 if err != nil { 32 return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError) 33 } 34 defer os.RemoveAll(tmpDir) 35 36 if err = utils.ExtractTarGz(pluginFile, tmpDir); err != nil { 37 return nil, model.NewAppError("installPlugin", "app.plugin.extract.app_error", nil, err.Error(), http.StatusBadRequest) 38 } 39 40 tmpPluginDir := tmpDir 41 dir, err := ioutil.ReadDir(tmpDir) 42 if err != nil { 43 return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError) 44 } 45 46 if len(dir) == 1 && dir[0].IsDir() { 47 tmpPluginDir = filepath.Join(tmpPluginDir, dir[0].Name()) 48 } 49 50 manifest, _, err := model.FindManifest(tmpPluginDir) 51 if err != nil { 52 return nil, model.NewAppError("installPlugin", "app.plugin.manifest.app_error", nil, err.Error(), http.StatusBadRequest) 53 } 54 55 if !plugin.IsValidId(manifest.Id) { 56 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) 57 } 58 59 // Stash the previous state of the plugin, if available 60 stashed := a.Config().PluginSettings.PluginStates[manifest.Id] 61 62 bundles, err := pluginsEnvironment.Available() 63 if err != nil { 64 return nil, model.NewAppError("installPlugin", "app.plugin.install.app_error", nil, err.Error(), http.StatusInternalServerError) 65 } 66 67 // Check that there is no plugin with the same ID 68 for _, bundle := range bundles { 69 if bundle.Manifest != nil && bundle.Manifest.Id == manifest.Id { 70 if !replace { 71 return nil, model.NewAppError("installPlugin", "app.plugin.install_id.app_error", nil, "", http.StatusBadRequest) 72 } 73 74 if err := a.RemovePlugin(manifest.Id); err != nil { 75 return nil, model.NewAppError("installPlugin", "app.plugin.install_id_failed_remove.app_error", nil, "", http.StatusBadRequest) 76 } 77 } 78 } 79 80 pluginPath := filepath.Join(*a.Config().PluginSettings.Directory, manifest.Id) 81 err = utils.CopyDir(tmpPluginDir, pluginPath) 82 if err != nil { 83 return nil, model.NewAppError("installPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError) 84 } 85 86 if stashed != nil && stashed.Enable { 87 a.EnablePlugin(manifest.Id) 88 } 89 90 if err := a.notifyPluginStatusesChanged(); err != nil { 91 mlog.Error("failed to notify plugin status changed", mlog.Err(err)) 92 } 93 94 return manifest, nil 95 } 96 97 func (a *App) RemovePlugin(id string) *model.AppError { 98 return a.removePlugin(id) 99 } 100 101 func (a *App) removePlugin(id string) *model.AppError { 102 pluginsEnvironment := a.GetPluginsEnvironment() 103 if pluginsEnvironment == nil { 104 return model.NewAppError("removePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) 105 } 106 107 plugins, err := pluginsEnvironment.Available() 108 if err != nil { 109 return model.NewAppError("removePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest) 110 } 111 112 var manifest *model.Manifest 113 var pluginPath string 114 for _, p := range plugins { 115 if p.Manifest != nil && p.Manifest.Id == id { 116 manifest = p.Manifest 117 pluginPath = filepath.Dir(p.ManifestPath) 118 break 119 } 120 } 121 122 if manifest == nil { 123 return model.NewAppError("removePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest) 124 } 125 126 if pluginsEnvironment.IsActive(id) && manifest.HasClient() { 127 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DISABLED, "", "", "", nil) 128 message.Add("manifest", manifest.ClientManifest()) 129 a.Publish(message) 130 } 131 132 pluginsEnvironment.Deactivate(id) 133 a.UnregisterPluginCommands(id) 134 135 err = os.RemoveAll(pluginPath) 136 if err != nil { 137 return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError) 138 } 139 140 return nil 141 }