helpers.go raw
1 // Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved.
2 // This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
3
4 //lint:file-ignore SA1019 older versions of staticcheck (those compatible with Golang 1.17) falsely flag x509.IsEncryptedPEMBlock and x509.DecryptPEMBlock.
5
6 package common
7
8 import (
9 "crypto/rand"
10 "crypto/rsa"
11 "crypto/x509"
12 "encoding/pem"
13 "errors"
14 "fmt"
15 "net/textproto"
16 "os"
17 "reflect"
18 "strconv"
19 "strings"
20 "time"
21
22 "github.com/youmark/pkcs8"
23 )
24
25 // String returns a pointer to the provided string
26 func String(value string) *string {
27 return &value
28 }
29
30 // Int returns a pointer to the provided int
31 func Int(value int) *int {
32 return &value
33 }
34
35 // Int64 returns a pointer to the provided int64
36 func Int64(value int64) *int64 {
37 return &value
38 }
39
40 // Uint returns a pointer to the provided uint
41 func Uint(value uint) *uint {
42 return &value
43 }
44
45 // Float32 returns a pointer to the provided float32
46 func Float32(value float32) *float32 {
47 return &value
48 }
49
50 // Float64 returns a pointer to the provided float64
51 func Float64(value float64) *float64 {
52 return &value
53 }
54
55 // Bool returns a pointer to the provided bool
56 func Bool(value bool) *bool {
57 return &value
58 }
59
60 // PointerString prints the values of pointers in a struct
61 // Producing a human friendly string for an struct with pointers.
62 // useful when debugging the values of a struct
63 func PointerString(datastruct interface{}) (representation string) {
64 val := reflect.ValueOf(datastruct)
65 typ := reflect.TypeOf(datastruct)
66 all := make([]string, 2)
67 all = append(all, "{")
68 for i := 0; i < typ.NumField(); i++ {
69 sf := typ.Field(i)
70
71 //unexported
72 if sf.PkgPath != "" && !sf.Anonymous {
73 continue
74 }
75
76 sv := val.Field(i)
77 stringValue := ""
78 if isNil(sv) {
79 stringValue = fmt.Sprintf("%s=<nil>", sf.Name)
80 } else {
81 if sv.Type().Kind() == reflect.Ptr {
82 sv = sv.Elem()
83 }
84 stringValue = fmt.Sprintf("%s=%v", sf.Name, sv)
85 }
86 all = append(all, stringValue)
87 }
88 all = append(all, "}")
89 representation = strings.TrimSpace(strings.Join(all, " "))
90 return
91 }
92
93 // SDKTime a struct that parses/renders to/from json using RFC339 date-time information
94 type SDKTime struct {
95 time.Time
96 }
97
98 // SDKDate a struct that parses/renders to/from json using only date information
99 type SDKDate struct {
100 //Date date information
101 Date time.Time
102 }
103
104 func sdkTimeFromTime(t time.Time) SDKTime {
105 return SDKTime{t}
106 }
107
108 func sdkDateFromTime(t time.Time) SDKDate {
109 return SDKDate{Date: t}
110 }
111
112 func formatTime(t SDKTime) string {
113 return t.Format(sdkTimeFormat)
114 }
115
116 func formatDate(t SDKDate) string {
117 return t.Date.Format(sdkDateFormat)
118 }
119
120 func now() *SDKTime {
121 t := SDKTime{time.Now()}
122 return &t
123 }
124
125 var timeType = reflect.TypeOf(SDKTime{})
126 var timeTypePtr = reflect.TypeOf(&SDKTime{})
127
128 var sdkDateType = reflect.TypeOf(SDKDate{})
129 var sdkDateTypePtr = reflect.TypeOf(&SDKDate{})
130
131 // Formats for sdk supported time representations
132 const sdkTimeFormat = time.RFC3339Nano
133 const rfc1123OptionalLeadingDigitsInDay = "Mon, _2 Jan 2006 15:04:05 MST"
134 const sdkDateFormat = "2006-01-02"
135
136 func tryParsingTimeWithValidFormatsForHeaders(data []byte, headerName string) (t time.Time, err error) {
137 header := strings.ToLower(headerName)
138 switch header {
139 case "lastmodified", "date":
140 t, err = tryParsing(data, time.RFC3339Nano, time.RFC3339, time.RFC1123, rfc1123OptionalLeadingDigitsInDay, time.RFC850, time.ANSIC)
141 return
142 default: //By default we parse with RFC3339
143 t, err = time.Parse(sdkTimeFormat, string(data))
144 return
145 }
146 }
147
148 func tryParsing(data []byte, layouts ...string) (tm time.Time, err error) {
149 datestring := string(data)
150 for _, l := range layouts {
151 tm, err = time.Parse(l, datestring)
152 if err == nil {
153 return
154 }
155 }
156 err = fmt.Errorf("could not parse time: %s with formats: %s", datestring, layouts[:])
157 return
158 }
159
160 // String returns string representation of SDKDate
161 func (t *SDKDate) String() string {
162 return t.Date.Format(sdkDateFormat)
163 }
164
165 // NewSDKDateFromString parses the dateString into SDKDate
166 func NewSDKDateFromString(dateString string) (*SDKDate, error) {
167 parsedTime, err := time.Parse(sdkDateFormat, dateString)
168 if err != nil {
169 return nil, err
170 }
171
172 return &SDKDate{Date: parsedTime}, nil
173 }
174
175 // UnmarshalJSON unmarshals from json
176 func (t *SDKTime) UnmarshalJSON(data []byte) (e error) {
177 s := string(data)
178 if s == "null" {
179 t.Time = time.Time{}
180 } else {
181 //Try parsing with RFC3339
182 t.Time, e = time.Parse(`"`+sdkTimeFormat+`"`, string(data))
183 }
184 return
185 }
186
187 // MarshalJSON marshals to JSON
188 func (t *SDKTime) MarshalJSON() (buff []byte, e error) {
189 s := t.Format(sdkTimeFormat)
190 buff = []byte(`"` + s + `"`)
191 return
192 }
193
194 // UnmarshalJSON unmarshals from json
195 func (t *SDKDate) UnmarshalJSON(data []byte) (e error) {
196 if string(data) == `"null"` {
197 t.Date = time.Time{}
198 return
199 }
200
201 t.Date, e = tryParsing(data,
202 strconv.Quote(sdkDateFormat),
203 )
204 return
205 }
206
207 // MarshalJSON marshals to JSON
208 func (t *SDKDate) MarshalJSON() (buff []byte, e error) {
209 s := t.Date.Format(sdkDateFormat)
210 buff = []byte(strconv.Quote(s))
211 return
212 }
213
214 // PrivateKeyFromBytes is a helper function that will produce a RSA private
215 // key from bytes. This function is deprecated in favour of PrivateKeyFromBytesWithPassword
216 // Deprecated
217 func PrivateKeyFromBytes(pemData []byte, password *string) (key *rsa.PrivateKey, e error) {
218 if password == nil {
219 return PrivateKeyFromBytesWithPassword(pemData, nil)
220 }
221
222 return PrivateKeyFromBytesWithPassword(pemData, []byte(*password))
223 }
224
225 // PrivateKeyFromBytesWithPassword is a helper function that will produce a RSA private
226 // key from bytes and a password.
227 func PrivateKeyFromBytesWithPassword(pemData, password []byte) (key *rsa.PrivateKey, e error) {
228 pemBlock, _ := pem.Decode(pemData)
229 if pemBlock == nil {
230 e = fmt.Errorf("PEM data was not found in buffer")
231 return
232 }
233
234 decrypted := pemBlock.Bytes
235 // Support for encrypted PKCS8 format, this format can not be handled by x509.IsEncryptedPEMBlock func
236 if key, e = pkcs8.ParsePKCS8PrivateKeyRSA(pemBlock.Bytes, password); key != nil {
237 return
238 }
239 // if pemBlock.Type == "ENCRYPTED PRIVATE KEY" {
240 // return pkcs8.ParsePKCS8PrivateKeyRSA(pemData, password)
241 // }
242 if x509.IsEncryptedPEMBlock(pemBlock) {
243 if password == nil {
244 return nil, errors.New("private key password is required for encrypted private keys")
245 }
246
247 if decrypted, e = x509.DecryptPEMBlock(pemBlock, password); e != nil {
248 return
249 }
250 }
251 key, e = parsePKCSPrivateKey(decrypted)
252 return
253 }
254
255 // ParsePrivateKey using PKCS1 or PKCS8
256 func parsePKCSPrivateKey(decryptedKey []byte) (*rsa.PrivateKey, error) {
257 if key, err := x509.ParsePKCS1PrivateKey(decryptedKey); err == nil {
258 return key, nil
259 }
260 if key, err := x509.ParsePKCS8PrivateKey(decryptedKey); err == nil {
261 switch key := key.(type) {
262 case *rsa.PrivateKey:
263 return key, nil
264 default:
265 return nil, fmt.Errorf("unsupportesd private key type in PKCS8 wrapping")
266 }
267 }
268 return nil, fmt.Errorf("failed to parse private key")
269 }
270
271 // parseContentLength trims whitespace from cl and returns -1 if can't purse uint, or the value if it's no less than 0
272 func parseContentLength(cl string) int64 {
273 cl = textproto.TrimString(cl)
274 n, err := strconv.ParseUint(cl, 10, 63)
275 if err != nil {
276 return -1
277 }
278 return int64(n)
279 }
280
281 func generateRandUUID() (string, error) {
282 b := make([]byte, 16)
283 _, err := rand.Read(b)
284 if err != nil {
285 return "", err
286 }
287 uuid := fmt.Sprintf("%x%x%x%x%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
288
289 return uuid, nil
290 }
291
292 func makeACopy(original []string) []string {
293 tmp := make([]string, len(original))
294 copy(tmp, original)
295 return tmp
296 }
297
298 // IsEnvVarFalse is used for checking if an environment variable is explicitly set to false, otherwise would set it true by default
299 func IsEnvVarFalse(envVarKey string) bool {
300 val, existed := os.LookupEnv(envVarKey)
301 return existed && strings.ToLower(val) == "false"
302 }
303
304 // IsEnvVarTrue is used for checking if an environment variable is explicitly set to true, otherwise would set it true by default
305 func IsEnvVarTrue(envVarKey string) bool {
306 val, existed := os.LookupEnv(envVarKey)
307 return existed && strings.ToLower(val) == "true"
308 }
309