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  }