github.com/epsagon/epsagon-go@v1.39.0/tracer/mask_ignored_keys.go (about)

     1  package tracer
     2  
     3  import (
     4  	"encoding/json"
     5  	"reflect"
     6  
     7  	"github.com/epsagon/epsagon-go/protocol"
     8  )
     9  
    10  const maskedValue = "****"
    11  
    12  func arrayToHitMap(arr []string) map[string]bool {
    13  	hitMap := make(map[string]bool)
    14  	for _, k := range arr {
    15  		hitMap[k] = true
    16  	}
    17  	return hitMap
    18  }
    19  
    20  func maskNestedJSONKeys(decodedJSON interface{}, ignoredKeysMap map[string]bool) (interface{}, bool) {
    21  	var changed bool
    22  	decodedValue := reflect.ValueOf(decodedJSON)
    23  	if decodedValue.Kind() == reflect.Invalid || decodedValue.IsZero() {
    24  		return decodedJSON, false
    25  	}
    26  	switch decodedValue.Kind() {
    27  	case reflect.Array, reflect.Slice:
    28  		for i := 0; i < decodedValue.Len(); i++ {
    29  			nestedValue := decodedValue.Index(i)
    30  			newNestedValue, indexChanged := maskNestedJSONKeys(nestedValue.Interface(), ignoredKeysMap)
    31  			if indexChanged {
    32  				nestedValue.Set(reflect.ValueOf(newNestedValue))
    33  				changed = true
    34  			}
    35  		}
    36  	case reflect.Map:
    37  		for _, key := range decodedValue.MapKeys() {
    38  			if ignoredKeysMap[key.String()] {
    39  				decodedValue.SetMapIndex(key, reflect.ValueOf(maskedValue))
    40  				changed = true
    41  			} else {
    42  				nestedValue := decodedValue.MapIndex(key)
    43  				newNestedValue, valueChanged := maskNestedJSONKeys(nestedValue.Interface(), ignoredKeysMap)
    44  				if valueChanged {
    45  					decodedValue.SetMapIndex(key, reflect.ValueOf(newNestedValue))
    46  					changed = true
    47  				}
    48  			}
    49  		}
    50  	}
    51  	return decodedValue.Interface(), changed
    52  }
    53  
    54  // maskIgnoredKeys masks all the keys in the
    55  // event resource metadata that are in ignoredKeys, swapping them with '****'.
    56  // Metadata values that are json decodable will have their nested keys masked as well.
    57  func (tracer *epsagonTracer) maskEventIgnoredKeys(event *protocol.Event, ignoredKeys []string) {
    58  	ignoredKeysMap := arrayToHitMap(ignoredKeys)
    59  	for key, value := range event.Resource.Metadata {
    60  		if ignoredKeysMap[key] {
    61  			event.Resource.Metadata[key] = maskedValue
    62  		} else {
    63  			var decodedJSON interface{}
    64  			err := json.Unmarshal([]byte(value), &decodedJSON)
    65  			if err == nil {
    66  				newValue, changed := maskNestedJSONKeys(decodedJSON, ignoredKeysMap)
    67  				if changed {
    68  					encodedNewValue, err := json.Marshal(newValue)
    69  					if err == nil {
    70  						event.Resource.Metadata[key] = string(encodedNewValue)
    71  					} else {
    72  						exception := createException("internal json encode error", err.Error())
    73  						if tracer.Stopped() {
    74  							tracer.exceptions = append(tracer.exceptions, exception)
    75  						} else {
    76  							tracer.AddException(exception)
    77  						}
    78  					}
    79  				}
    80  			}
    81  		}
    82  	}
    83  }