github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/plugin_key_value_store.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 "crypto/sha256" 8 "encoding/base64" 9 "net/http" 10 11 "github.com/mattermost/mattermost-server/v5/mlog" 12 "github.com/mattermost/mattermost-server/v5/model" 13 ) 14 15 func getKeyHash(key string) string { 16 hash := sha256.New() 17 hash.Write([]byte(key)) 18 return base64.StdEncoding.EncodeToString(hash.Sum(nil)) 19 } 20 21 func (a *App) SetPluginKey(pluginId string, key string, value []byte) *model.AppError { 22 return a.SetPluginKeyWithExpiry(pluginId, key, value, 0) 23 } 24 25 func (a *App) SetPluginKeyWithExpiry(pluginId string, key string, value []byte, expireInSeconds int64) *model.AppError { 26 options := model.PluginKVSetOptions{ 27 ExpireInSeconds: expireInSeconds, 28 } 29 _, err := a.SetPluginKeyWithOptions(pluginId, key, value, options) 30 return err 31 } 32 33 func (a *App) CompareAndSetPluginKey(pluginId string, key string, oldValue, newValue []byte) (bool, *model.AppError) { 34 options := model.PluginKVSetOptions{ 35 Atomic: true, 36 OldValue: oldValue, 37 } 38 return a.SetPluginKeyWithOptions(pluginId, key, newValue, options) 39 } 40 41 func (a *App) SetPluginKeyWithOptions(pluginId string, key string, value []byte, options model.PluginKVSetOptions) (bool, *model.AppError) { 42 if err := options.IsValid(); err != nil { 43 mlog.Error("Failed to set plugin key value with options", mlog.String("plugin_id", pluginId), mlog.String("key", key), mlog.Err(err)) 44 return false, err 45 } 46 47 updated, err := a.Srv().Store.Plugin().SetWithOptions(pluginId, key, value, options) 48 if err != nil { 49 mlog.Error("Failed to set plugin key value with options", mlog.String("plugin_id", pluginId), mlog.String("key", key), mlog.Err(err)) 50 return updated, err 51 } 52 53 // Clean up a previous entry using the hashed key, if it exists. 54 if err := a.Srv().Store.Plugin().Delete(pluginId, getKeyHash(key)); err != nil { 55 mlog.Error("Failed to clean up previously hashed plugin key value", mlog.String("plugin_id", pluginId), mlog.String("key", key), mlog.Err(err)) 56 } 57 58 return updated, nil 59 } 60 61 func (a *App) CompareAndDeletePluginKey(pluginId string, key string, oldValue []byte) (bool, *model.AppError) { 62 kv := &model.PluginKeyValue{ 63 PluginId: pluginId, 64 Key: key, 65 } 66 67 deleted, err := a.Srv().Store.Plugin().CompareAndDelete(kv, oldValue) 68 if err != nil { 69 mlog.Error("Failed to compare and delete plugin key value", mlog.String("plugin_id", pluginId), mlog.String("key", key), mlog.Err(err)) 70 return deleted, err 71 } 72 73 // Clean up a previous entry using the hashed key, if it exists. 74 if err := a.Srv().Store.Plugin().Delete(pluginId, getKeyHash(key)); err != nil { 75 mlog.Error("Failed to clean up previously hashed plugin key value", mlog.String("plugin_id", pluginId), mlog.String("key", key), mlog.Err(err)) 76 } 77 78 return deleted, nil 79 } 80 81 func (a *App) GetPluginKey(pluginId string, key string) ([]byte, *model.AppError) { 82 if kv, err := a.Srv().Store.Plugin().Get(pluginId, key); err == nil { 83 return kv.Value, nil 84 } else if err.StatusCode != http.StatusNotFound { 85 mlog.Error("Failed to query plugin key value", mlog.String("plugin_id", pluginId), mlog.String("key", key), mlog.Err(err)) 86 return nil, err 87 } 88 89 // Lookup using the hashed version of the key for keys written prior to v5.6. 90 if kv, err := a.Srv().Store.Plugin().Get(pluginId, getKeyHash(key)); err == nil { 91 return kv.Value, nil 92 } else if err.StatusCode != http.StatusNotFound { 93 mlog.Error("Failed to query plugin key value using hashed key", mlog.String("plugin_id", pluginId), mlog.String("key", key), mlog.Err(err)) 94 return nil, err 95 } 96 97 return nil, nil 98 } 99 100 func (a *App) DeletePluginKey(pluginId string, key string) *model.AppError { 101 if err := a.Srv().Store.Plugin().Delete(pluginId, getKeyHash(key)); err != nil { 102 mlog.Error("Failed to delete plugin key value", mlog.String("plugin_id", pluginId), mlog.String("key", key), mlog.Err(err)) 103 return err 104 } 105 106 // Also delete the key without hashing 107 if err := a.Srv().Store.Plugin().Delete(pluginId, key); err != nil { 108 mlog.Error("Failed to delete plugin key value using hashed key", mlog.String("plugin_id", pluginId), mlog.String("key", key), mlog.Err(err)) 109 return err 110 } 111 112 return nil 113 } 114 115 func (a *App) DeleteAllKeysForPlugin(pluginId string) *model.AppError { 116 if err := a.Srv().Store.Plugin().DeleteAllForPlugin(pluginId); err != nil { 117 mlog.Error("Failed to delete all plugin key values", mlog.String("plugin_id", pluginId), mlog.Err(err)) 118 return err 119 } 120 121 return nil 122 } 123 124 func (a *App) DeleteAllExpiredPluginKeys() *model.AppError { 125 if a.Srv() == nil { 126 return nil 127 } 128 129 if err := a.Srv().Store.Plugin().DeleteAllExpired(); err != nil { 130 mlog.Error("Failed to delete all expired plugin key values", mlog.Err(err)) 131 return err 132 } 133 134 return nil 135 } 136 137 func (a *App) ListPluginKeys(pluginId string, page, perPage int) ([]string, *model.AppError) { 138 data, err := a.Srv().Store.Plugin().List(pluginId, page*perPage, perPage) 139 140 if err != nil { 141 mlog.Error("Failed to list plugin key values", mlog.Int("page", page), mlog.Int("perPage", perPage), mlog.Err(err)) 142 return nil, err 143 } 144 145 return data, nil 146 }