...
1
16
17 package api
18
19 import (
20 "encoding/base64"
21 "errors"
22 "fmt"
23 "os"
24 "path"
25 "path/filepath"
26 "reflect"
27 "strings"
28 )
29
30 func init() {
31 sDec, _ := base64.StdEncoding.DecodeString("REDACTED+")
32 redactedBytes = []byte(string(sDec))
33 sDec, _ = base64.StdEncoding.DecodeString("DATA+OMITTED")
34 dataOmittedBytes = []byte(string(sDec))
35 }
36
37
38 func IsConfigEmpty(config *Config) bool {
39 return len(config.AuthInfos) == 0 && len(config.Clusters) == 0 && len(config.Contexts) == 0 &&
40 len(config.CurrentContext) == 0 &&
41 len(config.Preferences.Extensions) == 0 && !config.Preferences.Colors &&
42 len(config.Extensions) == 0
43 }
44
45
46
47 func MinifyConfig(config *Config) error {
48 if len(config.CurrentContext) == 0 {
49 return errors.New("current-context must exist in order to minify")
50 }
51
52 currContext, exists := config.Contexts[config.CurrentContext]
53 if !exists {
54 return fmt.Errorf("cannot locate context %v", config.CurrentContext)
55 }
56
57 newContexts := map[string]*Context{}
58 newContexts[config.CurrentContext] = currContext
59
60 newClusters := map[string]*Cluster{}
61 if len(currContext.Cluster) > 0 {
62 if _, exists := config.Clusters[currContext.Cluster]; !exists {
63 return fmt.Errorf("cannot locate cluster %v", currContext.Cluster)
64 }
65
66 newClusters[currContext.Cluster] = config.Clusters[currContext.Cluster]
67 }
68
69 newAuthInfos := map[string]*AuthInfo{}
70 if len(currContext.AuthInfo) > 0 {
71 if _, exists := config.AuthInfos[currContext.AuthInfo]; !exists {
72 return fmt.Errorf("cannot locate user %v", currContext.AuthInfo)
73 }
74
75 newAuthInfos[currContext.AuthInfo] = config.AuthInfos[currContext.AuthInfo]
76 }
77
78 config.AuthInfos = newAuthInfos
79 config.Clusters = newClusters
80 config.Contexts = newContexts
81
82 return nil
83 }
84
85 var (
86 dataOmittedBytes []byte
87 redactedBytes []byte
88 )
89
90
91 func ShortenConfig(config *Config) {
92
93
94
95 for key, authInfo := range config.AuthInfos {
96 if len(authInfo.ClientKeyData) > 0 {
97 authInfo.ClientKeyData = dataOmittedBytes
98 }
99 if len(authInfo.ClientCertificateData) > 0 {
100 authInfo.ClientCertificateData = dataOmittedBytes
101 }
102 if len(authInfo.Token) > 0 {
103 authInfo.Token = "REDACTED"
104 }
105 config.AuthInfos[key] = authInfo
106 }
107 for key, cluster := range config.Clusters {
108 if len(cluster.CertificateAuthorityData) > 0 {
109 cluster.CertificateAuthorityData = dataOmittedBytes
110 }
111 config.Clusters[key] = cluster
112 }
113 }
114
115
116 func FlattenConfig(config *Config) error {
117 for key, authInfo := range config.AuthInfos {
118 baseDir, err := MakeAbs(path.Dir(authInfo.LocationOfOrigin), "")
119 if err != nil {
120 return err
121 }
122
123 if err := FlattenContent(&authInfo.ClientCertificate, &authInfo.ClientCertificateData, baseDir); err != nil {
124 return err
125 }
126 if err := FlattenContent(&authInfo.ClientKey, &authInfo.ClientKeyData, baseDir); err != nil {
127 return err
128 }
129
130 config.AuthInfos[key] = authInfo
131 }
132 for key, cluster := range config.Clusters {
133 baseDir, err := MakeAbs(path.Dir(cluster.LocationOfOrigin), "")
134 if err != nil {
135 return err
136 }
137
138 if err := FlattenContent(&cluster.CertificateAuthority, &cluster.CertificateAuthorityData, baseDir); err != nil {
139 return err
140 }
141
142 config.Clusters[key] = cluster
143 }
144
145 return nil
146 }
147
148 func FlattenContent(path *string, contents *[]byte, baseDir string) error {
149 if len(*path) != 0 {
150 if len(*contents) > 0 {
151 return errors.New("cannot have values for both path and contents")
152 }
153
154 var err error
155 absPath := ResolvePath(*path, baseDir)
156 *contents, err = os.ReadFile(absPath)
157 if err != nil {
158 return err
159 }
160
161 *path = ""
162 }
163
164 return nil
165 }
166
167
168 func ResolvePath(path string, base string) string {
169
170 if len(path) > 0 {
171
172 if !filepath.IsAbs(path) {
173 return filepath.Join(base, path)
174 }
175 }
176
177 return path
178 }
179
180 func MakeAbs(path, base string) (string, error) {
181 if filepath.IsAbs(path) {
182 return path, nil
183 }
184 if len(base) == 0 {
185 cwd, err := os.Getwd()
186 if err != nil {
187 return "", err
188 }
189 base = cwd
190 }
191 return filepath.Join(base, path), nil
192 }
193
194
195 func RedactSecrets(config *Config) error {
196 return redactSecrets(reflect.ValueOf(config), false)
197 }
198
199 func redactSecrets(curr reflect.Value, redact bool) error {
200 redactedBytes = []byte("REDACTED")
201 if !curr.IsValid() {
202 return nil
203 }
204
205 actualCurrValue := curr
206 if curr.Kind() == reflect.Ptr {
207 actualCurrValue = curr.Elem()
208 }
209
210 switch actualCurrValue.Kind() {
211 case reflect.Map:
212 for _, v := range actualCurrValue.MapKeys() {
213 err := redactSecrets(actualCurrValue.MapIndex(v), false)
214 if err != nil {
215 return err
216 }
217 }
218 return nil
219
220 case reflect.String:
221 if redact {
222 if !actualCurrValue.IsZero() {
223 actualCurrValue.SetString("REDACTED")
224 }
225 }
226 return nil
227
228 case reflect.Slice:
229 if actualCurrValue.Type() == reflect.TypeOf([]byte{}) && redact {
230 if !actualCurrValue.IsNil() {
231 actualCurrValue.SetBytes(redactedBytes)
232 }
233 return nil
234 }
235 for i := 0; i < actualCurrValue.Len(); i++ {
236 err := redactSecrets(actualCurrValue.Index(i), false)
237 if err != nil {
238 return err
239 }
240 }
241 return nil
242
243 case reflect.Struct:
244 for fieldIndex := 0; fieldIndex < actualCurrValue.NumField(); fieldIndex++ {
245 currFieldValue := actualCurrValue.Field(fieldIndex)
246 currFieldType := actualCurrValue.Type().Field(fieldIndex)
247 currYamlTag := currFieldType.Tag.Get("datapolicy")
248 currFieldTypeYamlName := strings.Split(currYamlTag, ",")[0]
249 if currFieldTypeYamlName != "" {
250 err := redactSecrets(currFieldValue, true)
251 if err != nil {
252 return err
253 }
254 } else {
255 err := redactSecrets(currFieldValue, false)
256 if err != nil {
257 return err
258 }
259 }
260 }
261 return nil
262
263 default:
264 return nil
265 }
266 }
267
View as plain text