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 }