github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/wrappers/wrappers.go (about)

     1  /*
     2  Copyright 2019 Gravitational, Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package wrappers provides protobuf wrappers for common teleport map and list types.
    18  package wrappers
    19  
    20  import (
    21  	"encoding/json"
    22  
    23  	"github.com/gogo/protobuf/proto"
    24  	"github.com/gravitational/trace"
    25  )
    26  
    27  // Traits is a wrapper around map with string
    28  // slices as values
    29  type Traits map[string][]string
    30  
    31  func (l Traits) protoType() *LabelValues {
    32  	v := &LabelValues{
    33  		Values: make(map[string]StringValues, len(l)),
    34  	}
    35  	for key, vals := range l {
    36  		stringValues := StringValues{
    37  			Values: make([]string, len(vals)),
    38  		}
    39  		copy(stringValues.Values, vals)
    40  		v.Values[key] = stringValues
    41  	}
    42  	return v
    43  }
    44  
    45  // MarshalTraits will marshal Traits as JSON. Used to embed traits into
    46  // certificates.
    47  func MarshalTraits(traits *Traits) ([]byte, error) {
    48  	return json.Marshal(traits)
    49  }
    50  
    51  // UnmarshalTraits will unmarshal JSON traits. Used to embed traits into
    52  // certificates.
    53  func UnmarshalTraits(data []byte, traits *Traits) error {
    54  	err := json.Unmarshal(data, traits)
    55  	if err != nil {
    56  		return traits.Unmarshal(data)
    57  	}
    58  	return nil
    59  }
    60  
    61  // Marshal marshals value into protobuf representation
    62  func (l Traits) Marshal() ([]byte, error) {
    63  	return proto.Marshal(l.protoType())
    64  }
    65  
    66  // MarshalTo marshals value to the array
    67  func (l Traits) MarshalTo(data []byte) (int, error) {
    68  	return l.protoType().MarshalTo(data)
    69  }
    70  
    71  // Unmarshal unmarshals value from protobuf
    72  func (l *Traits) Unmarshal(data []byte) error {
    73  	protoValues := &LabelValues{}
    74  	err := proto.Unmarshal(data, protoValues)
    75  	if err != nil {
    76  		return err
    77  	}
    78  	if protoValues.Values == nil {
    79  		return nil
    80  	}
    81  	*l = make(map[string][]string, len(protoValues.Values))
    82  	for key := range protoValues.Values {
    83  		(*l)[key] = protoValues.Values[key].Values
    84  	}
    85  	return nil
    86  }
    87  
    88  // Size returns protobuf size
    89  func (l Traits) Size() int {
    90  	return l.protoType().Size()
    91  }
    92  
    93  // Strings is a list of string that can unmarshal from list of strings
    94  // or a scalar string from scalar yaml or json property
    95  type Strings []string
    96  
    97  func (s *Strings) protoType() *StringValues {
    98  	return &StringValues{
    99  		Values: *s,
   100  	}
   101  }
   102  
   103  // Marshal marshals value into protobuf representation
   104  func (s Strings) Marshal() ([]byte, error) {
   105  	return proto.Marshal(s.protoType())
   106  }
   107  
   108  // MarshalTo marshals value to the array
   109  func (s Strings) MarshalTo(data []byte) (int, error) {
   110  	return s.protoType().MarshalTo(data)
   111  }
   112  
   113  // Unmarshal unmarshals value from protobuf
   114  func (s *Strings) Unmarshal(data []byte) error {
   115  	protoValues := &StringValues{}
   116  	err := proto.Unmarshal(data, protoValues)
   117  	if err != nil {
   118  		return err
   119  	}
   120  	if protoValues.Values != nil {
   121  		*s = protoValues.Values
   122  	}
   123  	return nil
   124  }
   125  
   126  // Size returns protobuf size
   127  func (s Strings) Size() int {
   128  	return s.protoType().Size()
   129  }
   130  
   131  // UnmarshalJSON unmarshals scalar string or strings slice to Strings
   132  func (s *Strings) UnmarshalJSON(data []byte) error {
   133  	if len(data) == 0 {
   134  		return nil
   135  	}
   136  	var stringVar string
   137  	if err := json.Unmarshal(data, &stringVar); err == nil {
   138  		*s = []string{stringVar}
   139  		return nil
   140  	}
   141  	var stringsVar []string
   142  	if err := json.Unmarshal(data, &stringsVar); err != nil {
   143  		return trace.Wrap(err)
   144  	}
   145  	*s = stringsVar
   146  	return nil
   147  }
   148  
   149  // UnmarshalYAML is used to allow Strings to unmarshal from
   150  // scalar string value or from the list
   151  func (s *Strings) UnmarshalYAML(unmarshal func(interface{}) error) error {
   152  	// try unmarshal as string
   153  	var val string
   154  	err := unmarshal(&val)
   155  	if err == nil {
   156  		*s = []string{val}
   157  		return nil
   158  	}
   159  
   160  	// try unmarshal as slice
   161  	var slice []string
   162  	err = unmarshal(&slice)
   163  	if err == nil {
   164  		*s = slice
   165  		return nil
   166  	}
   167  
   168  	return err
   169  }
   170  
   171  // MarshalJSON marshals to scalar value
   172  // if there is only one value in the list
   173  // to list otherwise
   174  func (s Strings) MarshalJSON() ([]byte, error) {
   175  	if len(s) == 1 {
   176  		return json.Marshal(s[0])
   177  	}
   178  	return json.Marshal([]string(s))
   179  }
   180  
   181  // MarshalYAML marshals to scalar value
   182  // if there is only one value in the list,
   183  // marshals to list otherwise
   184  func (s Strings) MarshalYAML() (interface{}, error) {
   185  	if len(s) == 1 {
   186  		return s[0], nil
   187  	}
   188  	return []string(s), nil
   189  }