github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/azure/value.go (about)

     1  package azure
     2  
     3  import (
     4  	"strings"
     5  	"time"
     6  
     7  	"github.com/khulnasoft-lab/defsec/pkg/scanners/azure/arm/parser/armjson"
     8  	"github.com/khulnasoft-lab/defsec/pkg/types"
     9  	"k8s.io/utils/strings/slices"
    10  )
    11  
    12  type EvalContext struct{}
    13  
    14  type Kind string
    15  
    16  const (
    17  	KindUnresolvable Kind = "unresolvable"
    18  	KindNull         Kind = "null"
    19  	KindBoolean      Kind = "boolean"
    20  	KindString       Kind = "string"
    21  	KindNumber       Kind = "number"
    22  	KindObject       Kind = "object"
    23  	KindArray        Kind = "array"
    24  	KindExpression   Kind = "expression"
    25  )
    26  
    27  type Value struct {
    28  	types.Metadata
    29  	rLit     interface{}
    30  	rMap     map[string]Value
    31  	rArr     []Value
    32  	Kind     Kind
    33  	Comments []string
    34  }
    35  
    36  var NullValue = Value{
    37  	Kind: KindNull,
    38  }
    39  
    40  func NewValue(value interface{}, metadata types.Metadata) Value {
    41  
    42  	v := Value{
    43  		Metadata: metadata,
    44  	}
    45  
    46  	switch ty := value.(type) {
    47  	case []interface{}:
    48  		v.Kind = KindArray
    49  		for _, child := range ty {
    50  			if internal, ok := child.(Value); ok {
    51  				v.rArr = append(v.rArr, internal)
    52  			} else {
    53  				v.rArr = append(v.rArr, NewValue(child, metadata))
    54  			}
    55  		}
    56  	case []Value:
    57  		v.Kind = KindArray
    58  		v.rArr = append(v.rArr, ty...)
    59  
    60  	case map[string]interface{}:
    61  		v.Kind = KindObject
    62  		v.rMap = make(map[string]Value)
    63  		for key, val := range ty {
    64  			if internal, ok := val.(Value); ok {
    65  				v.rMap[key] = internal
    66  			} else {
    67  				v.rMap[key] = NewValue(val, metadata)
    68  			}
    69  		}
    70  	case map[string]Value:
    71  		v.Kind = KindObject
    72  		v.rMap = make(map[string]Value)
    73  		for key, val := range ty {
    74  			v.rMap[key] = val
    75  		}
    76  	case string:
    77  		v.Kind = KindString
    78  		v.rLit = ty
    79  	case int, int64, int32, float32, float64, int8, int16, uint8, uint16, uint32, uint64:
    80  		v.Kind = KindNumber
    81  		v.rLit = ty
    82  	case bool:
    83  		v.Kind = KindBoolean
    84  		v.rLit = ty
    85  	case nil:
    86  		v.Kind = KindNull
    87  		v.rLit = ty
    88  	default:
    89  		v.Kind = KindUnresolvable
    90  		v.rLit = ty
    91  	}
    92  
    93  	return v
    94  }
    95  
    96  func (v *Value) GetMetadata() types.Metadata {
    97  	return v.Metadata
    98  }
    99  
   100  func (v *Value) UnmarshalJSONWithMetadata(node armjson.Node) error {
   101  
   102  	v.updateValueKind(node)
   103  
   104  	v.Metadata = node.Metadata()
   105  
   106  	switch node.Kind() {
   107  	case armjson.KindArray:
   108  		err := v.unmarshallArray(node)
   109  		if err != nil {
   110  			return err
   111  		}
   112  	case armjson.KindObject:
   113  		err := v.unmarshalObject(node)
   114  		if err != nil {
   115  			return err
   116  		}
   117  	case armjson.KindString:
   118  		err := v.unmarshalString(node)
   119  		if err != nil {
   120  			return err
   121  		}
   122  	default:
   123  		if err := node.Decode(&v.rLit); err != nil {
   124  			return err
   125  		}
   126  	}
   127  
   128  	for _, comment := range node.Comments() {
   129  		var str string
   130  		if err := comment.Decode(&str); err != nil {
   131  			return err
   132  		}
   133  		// remove `\r` from comment when running windows
   134  		str = strings.ReplaceAll(str, "\r", "")
   135  
   136  		v.Comments = append(v.Comments, str)
   137  	}
   138  	return nil
   139  }
   140  
   141  func (v *Value) unmarshalString(node armjson.Node) error {
   142  	var str string
   143  	if err := node.Decode(&str); err != nil {
   144  		return err
   145  	}
   146  	if strings.HasPrefix(str, "[") && !strings.HasPrefix(str, "[[") && strings.HasSuffix(str, "]") {
   147  		// function!
   148  		v.Kind = KindExpression
   149  		v.rLit = str[1 : len(str)-1]
   150  	} else {
   151  		v.rLit = str
   152  	}
   153  	return nil
   154  }
   155  
   156  func (v *Value) unmarshalObject(node armjson.Node) error {
   157  	obj := make(map[string]Value)
   158  	for i := 0; i < len(node.Content()); i += 2 {
   159  		var key string
   160  		if err := node.Content()[i].Decode(&key); err != nil {
   161  			return err
   162  		}
   163  		var val Value
   164  		if err := val.UnmarshalJSONWithMetadata(node.Content()[i+1]); err != nil {
   165  			return err
   166  		}
   167  		obj[key] = val
   168  	}
   169  	v.rMap = obj
   170  	return nil
   171  }
   172  
   173  func (v *Value) unmarshallArray(node armjson.Node) error {
   174  	var arr []Value
   175  	for _, child := range node.Content() {
   176  		var val Value
   177  		if err := val.UnmarshalJSONWithMetadata(child); err != nil {
   178  			return err
   179  		}
   180  		arr = append(arr, val)
   181  	}
   182  	v.rArr = arr
   183  	return nil
   184  }
   185  
   186  func (v *Value) updateValueKind(node armjson.Node) {
   187  	switch node.Kind() {
   188  	case armjson.KindString:
   189  		v.Kind = KindString
   190  	case armjson.KindNumber:
   191  		v.Kind = KindNumber
   192  	case armjson.KindBoolean:
   193  		v.Kind = KindBoolean
   194  	case armjson.KindObject:
   195  		v.Kind = KindObject
   196  	case armjson.KindNull:
   197  		v.Kind = KindNull
   198  	case armjson.KindArray:
   199  		v.Kind = KindArray
   200  	default:
   201  		panic(node.Kind())
   202  	}
   203  }
   204  
   205  func (v Value) AsString() string {
   206  	v.Resolve()
   207  
   208  	if v.Kind != KindString {
   209  		return ""
   210  	}
   211  
   212  	return v.rLit.(string)
   213  }
   214  
   215  func (v Value) AsBool() bool {
   216  	v.Resolve()
   217  	if v.Kind != KindBoolean {
   218  		return false
   219  	}
   220  	return v.rLit.(bool)
   221  }
   222  
   223  func (v Value) AsInt() int {
   224  	v.Resolve()
   225  	if v.Kind != KindNumber {
   226  		return 0
   227  	}
   228  	return int(v.rLit.(int64))
   229  }
   230  
   231  func (v Value) AsFloat() float64 {
   232  	v.Resolve()
   233  	if v.Kind != KindNumber {
   234  		return 0
   235  	}
   236  	return v.rLit.(float64)
   237  }
   238  
   239  func (v Value) AsIntValue(defaultValue int, metadata types.Metadata) types.IntValue {
   240  	v.Resolve()
   241  	if v.Kind != KindNumber {
   242  		return types.Int(defaultValue, metadata)
   243  	}
   244  	return types.Int(v.AsInt(), metadata)
   245  }
   246  
   247  func (v Value) AsBoolValue(defaultValue bool, metadata types.Metadata) types.BoolValue {
   248  	v.Resolve()
   249  	if v.Kind == KindString {
   250  		possibleValue := strings.ToLower(v.rLit.(string))
   251  		if slices.Contains([]string{"true", "1", "yes", "on", "enabled"}, possibleValue) {
   252  			return types.Bool(true, metadata)
   253  		}
   254  	}
   255  
   256  	if v.Kind != KindBoolean {
   257  		return types.Bool(defaultValue, metadata)
   258  	}
   259  
   260  	return types.Bool(v.rLit.(bool), v.GetMetadata())
   261  }
   262  
   263  func (v Value) EqualTo(value interface{}) bool {
   264  	switch ty := value.(type) {
   265  	case string:
   266  		return v.AsString() == ty
   267  	default:
   268  		panic("not supported")
   269  	}
   270  }
   271  
   272  func (v Value) AsStringValue(defaultValue string, metadata types.Metadata) types.StringValue {
   273  	v.Resolve()
   274  	if v.Kind != KindString {
   275  		return types.StringDefault(defaultValue, metadata)
   276  	}
   277  	return types.String(v.rLit.(string), v.Metadata)
   278  }
   279  
   280  func (v Value) GetMapValue(key string) Value {
   281  	v.Resolve()
   282  	if v.Kind != KindObject {
   283  		return NullValue
   284  	}
   285  	return v.rMap[key]
   286  }
   287  
   288  func (v Value) AsMap() map[string]Value {
   289  	v.Resolve()
   290  	if v.Kind != KindObject {
   291  		return nil
   292  	}
   293  	return v.rMap
   294  }
   295  
   296  func (v Value) AsList() []Value {
   297  	v.Resolve()
   298  	if v.Kind != KindArray {
   299  		return nil
   300  	}
   301  	return v.rArr
   302  }
   303  
   304  func (v Value) Raw() interface{} {
   305  	switch v.Kind {
   306  	case KindArray:
   307  		// TODO: recursively build raw array
   308  		return nil
   309  	case KindObject:
   310  		// TODO: recursively build raw object
   311  		return nil
   312  	default:
   313  		return v.rLit
   314  	}
   315  }
   316  
   317  func (v *Value) Resolve() {
   318  	if v.Kind != KindExpression {
   319  		return
   320  	}
   321  	// if resolver, ok := v.Metadata.Internal().(Resolver); ok {
   322  	// 	*v = resolver.ResolveExpression(*v)
   323  	// }
   324  }
   325  
   326  func (v Value) HasKey(key string) bool {
   327  	v.Resolve()
   328  	_, ok := v.rMap[key]
   329  	return ok
   330  }
   331  
   332  func (v Value) AsTimeValue(metadata types.Metadata) types.TimeValue {
   333  	v.Resolve()
   334  	if v.Kind != KindString {
   335  		return types.Time(time.Time{}, metadata)
   336  	}
   337  	if v.Kind == KindNumber {
   338  		return types.Time(time.Unix(int64(v.AsFloat()), 0), metadata)
   339  	}
   340  	t, err := time.Parse(time.RFC3339, v.rLit.(string))
   341  	if err != nil {
   342  		return types.Time(time.Time{}, metadata)
   343  	}
   344  	return types.Time(t, metadata)
   345  }
   346  
   347  func (v Value) AsStringValuesList(defaultValue string) (stringValues []types.StringValue) {
   348  	v.Resolve()
   349  	if v.Kind != KindArray {
   350  		return
   351  	}
   352  	for _, item := range v.rArr {
   353  		stringValues = append(stringValues, item.AsStringValue(defaultValue, item.Metadata))
   354  	}
   355  
   356  	return stringValues
   357  }