github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/config/secrets/secrets.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); 2 // you may not use this file except in compliance with the License. 3 // You may obtain a copy of the License at 4 // 5 // https://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, 9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 // See the License for the specific language governing permissions and 11 // limitations under the License. 12 // 13 // Original source: github.com/micro/go-micro/v3/config/secrets/secrets.go 14 15 package secrets 16 17 import ( 18 "encoding/base64" 19 "encoding/json" 20 "fmt" 21 22 "github.com/tickoalcantara12/micro/v3/service/config" 23 ) 24 25 // NewSecrets returns a config that encrypts values at rest 26 func NewSecrets(config config.Config, encryptionKey string) (config.Secrets, error) { 27 return newSecrets(config, encryptionKey) 28 } 29 30 type secretConf struct { 31 config config.Config 32 encryptionKey string 33 } 34 35 func newSecrets(config config.Config, encryptionKey string) (*secretConf, error) { 36 return &secretConf{ 37 config: config, 38 encryptionKey: encryptionKey, 39 }, nil 40 } 41 42 func (c *secretConf) Get(path string, options ...config.Option) (config.Value, error) { 43 val, err := c.config.Get(path, options...) 44 empty := config.NewJSONValue([]byte("null")) 45 if err != nil { 46 return empty, err 47 } 48 var v interface{} 49 err = json.Unmarshal(val.Bytes(), &v) 50 if err != nil { 51 return empty, err 52 } 53 v, err = convertElements(v, c.fromEncrypted) 54 if err != nil { 55 return empty, err 56 } 57 dat, err := json.Marshal(v) 58 if err != nil { 59 return empty, err 60 } 61 return config.NewJSONValue(dat), nil 62 } 63 64 func (c *secretConf) Set(path string, val interface{}, options ...config.Option) error { 65 // marshal to JSON and back so we can iterate on the 66 // value without reflection 67 JSON, err := json.Marshal(val) 68 if err != nil { 69 return err 70 } 71 var v interface{} 72 err = json.Unmarshal(JSON, &v) 73 if err != nil { 74 return err 75 } 76 v, err = convertElements(v, c.toEncrypted) 77 if err != nil { 78 return err 79 } 80 return c.config.Set(path, v) 81 } 82 83 func (c *secretConf) Delete(path string, options ...config.Option) error { 84 return c.config.Delete(path, options...) 85 } 86 87 func convertElements(elem interface{}, conversionFunc func(elem interface{}) (interface{}, error)) (interface{}, error) { 88 switch m := elem.(type) { 89 case map[string]interface{}: 90 for k, v := range m { 91 conv, err := convertElements(v, conversionFunc) 92 if err != nil { 93 return nil, err 94 } 95 m[k] = conv 96 97 } 98 return m, nil 99 } 100 101 return conversionFunc(elem) 102 } 103 104 func (c *secretConf) toEncrypted(elem interface{}) (interface{}, error) { 105 dat, err := json.Marshal(elem) 106 if err != nil { 107 return nil, err 108 } 109 encrypted, err := encrypt(string(dat), []byte(c.encryptionKey)) 110 if err != nil { 111 return nil, fmt.Errorf("Failed to encrypt: %v", err) 112 } 113 return string(base64.StdEncoding.EncodeToString([]byte(encrypted))), nil 114 } 115 116 func (c *secretConf) fromEncrypted(elem interface{}) (interface{}, error) { 117 s, ok := elem.(string) 118 if !ok { 119 // This bit decides if the Secrets implementation suppports nonencrypted values 120 // ie. we could do: 121 // return nil, fmt.Errorf("Encrypted values should be strings, but got: %v", elem) 122 // but let's go with not making nonencrypted values blow up the whole thing 123 return elem, nil 124 } 125 dec, err := base64.StdEncoding.DecodeString(s) 126 if err != nil { 127 return elem, nil 128 } 129 decrypted, err := decrypt(string(dec), []byte(c.encryptionKey)) 130 if err != nil { 131 return elem, nil 132 } 133 var ret interface{} 134 return ret, json.Unmarshal([]byte(decrypted), &ret) 135 }