1package parseutil 2 3import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/hashicorp/errwrap" 12 sockaddr "github.com/hashicorp/go-sockaddr" 13 "github.com/hashicorp/vault/sdk/helper/strutil" 14 "github.com/mitchellh/mapstructure" 15) 16 17func ParseDurationSecond(in interface{}) (time.Duration, error) { 18 var dur time.Duration 19 jsonIn, ok := in.(json.Number) 20 if ok { 21 in = jsonIn.String() 22 } 23 switch inp := in.(type) { 24 case nil: 25 // return default of zero 26 case string: 27 if inp == "" { 28 return dur, nil 29 } 30 var err error 31 // Look for a suffix otherwise its a plain second value 32 if strings.HasSuffix(inp, "s") || strings.HasSuffix(inp, "m") || strings.HasSuffix(inp, "h") || strings.HasSuffix(inp, "ms") { 33 dur, err = time.ParseDuration(inp) 34 if err != nil { 35 return dur, err 36 } 37 } else { 38 // Plain integer 39 secs, err := strconv.ParseInt(inp, 10, 64) 40 if err != nil { 41 return dur, err 42 } 43 dur = time.Duration(secs) * time.Second 44 } 45 case int: 46 dur = time.Duration(inp) * time.Second 47 case int32: 48 dur = time.Duration(inp) * time.Second 49 case int64: 50 dur = time.Duration(inp) * time.Second 51 case uint: 52 dur = time.Duration(inp) * time.Second 53 case uint32: 54 dur = time.Duration(inp) * time.Second 55 case uint64: 56 dur = time.Duration(inp) * time.Second 57 case float32: 58 dur = time.Duration(inp) * time.Second 59 case float64: 60 dur = time.Duration(inp) * time.Second 61 case time.Duration: 62 dur = inp 63 default: 64 return 0, errors.New("could not parse duration from input") 65 } 66 67 return dur, nil 68} 69 70func ParseAbsoluteTime(in interface{}) (time.Time, error) { 71 var t time.Time 72 switch inp := in.(type) { 73 case nil: 74 // return default of zero 75 return t, nil 76 case string: 77 // Allow RFC3339 with nanoseconds, or without, 78 // or an epoch time as an integer. 79 var err error 80 t, err = time.Parse(time.RFC3339Nano, inp) 81 if err == nil { 82 break 83 } 84 t, err = time.Parse(time.RFC3339, inp) 85 if err == nil { 86 break 87 } 88 epochTime, err := strconv.ParseInt(inp, 10, 64) 89 if err == nil { 90 t = time.Unix(epochTime, 0) 91 break 92 } 93 return t, errors.New("could not parse string as date and time") 94 case json.Number: 95 epochTime, err := inp.Int64() 96 if err != nil { 97 return t, err 98 } 99 t = time.Unix(epochTime, 0) 100 case int: 101 t = time.Unix(int64(inp), 0) 102 case int32: 103 t = time.Unix(int64(inp), 0) 104 case int64: 105 t = time.Unix(inp, 0) 106 case uint: 107 t = time.Unix(int64(inp), 0) 108 case uint32: 109 t = time.Unix(int64(inp), 0) 110 case uint64: 111 t = time.Unix(int64(inp), 0) 112 default: 113 return t, errors.New("could not parse time from input type") 114 } 115 return t, nil 116} 117 118func ParseInt(in interface{}) (int64, error) { 119 var ret int64 120 jsonIn, ok := in.(json.Number) 121 if ok { 122 in = jsonIn.String() 123 } 124 switch in.(type) { 125 case string: 126 inp := in.(string) 127 if inp == "" { 128 return 0, nil 129 } 130 var err error 131 left, err := strconv.ParseInt(inp, 10, 64) 132 if err != nil { 133 return ret, err 134 } 135 ret = left 136 case int: 137 ret = int64(in.(int)) 138 case int32: 139 ret = int64(in.(int32)) 140 case int64: 141 ret = in.(int64) 142 case uint: 143 ret = int64(in.(uint)) 144 case uint32: 145 ret = int64(in.(uint32)) 146 case uint64: 147 ret = int64(in.(uint64)) 148 default: 149 return 0, errors.New("could not parse value from input") 150 } 151 152 return ret, nil 153} 154 155func ParseBool(in interface{}) (bool, error) { 156 var result bool 157 if err := mapstructure.WeakDecode(in, &result); err != nil { 158 return false, err 159 } 160 return result, nil 161} 162 163func ParseString(in interface{}) (string, error) { 164 var result string 165 if err := mapstructure.WeakDecode(in, &result); err != nil { 166 return "", err 167 } 168 return result, nil 169} 170 171func ParseCommaStringSlice(in interface{}) ([]string, error) { 172 rawString, ok := in.(string) 173 if ok && rawString == "" { 174 return []string{}, nil 175 } 176 var result []string 177 config := &mapstructure.DecoderConfig{ 178 Result: &result, 179 WeaklyTypedInput: true, 180 DecodeHook: mapstructure.StringToSliceHookFunc(","), 181 } 182 decoder, err := mapstructure.NewDecoder(config) 183 if err != nil { 184 return nil, err 185 } 186 if err := decoder.Decode(in); err != nil { 187 return nil, err 188 } 189 return strutil.TrimStrings(result), nil 190} 191 192func ParseAddrs(addrs interface{}) ([]*sockaddr.SockAddrMarshaler, error) { 193 out := make([]*sockaddr.SockAddrMarshaler, 0) 194 stringAddrs := make([]string, 0) 195 196 switch addrs.(type) { 197 case string: 198 stringAddrs = strutil.ParseArbitraryStringSlice(addrs.(string), ",") 199 if len(stringAddrs) == 0 { 200 return nil, fmt.Errorf("unable to parse addresses from %v", addrs) 201 } 202 203 case []string: 204 stringAddrs = addrs.([]string) 205 206 case []interface{}: 207 for _, v := range addrs.([]interface{}) { 208 stringAddr, ok := v.(string) 209 if !ok { 210 return nil, fmt.Errorf("error parsing %v as string", v) 211 } 212 stringAddrs = append(stringAddrs, stringAddr) 213 } 214 215 default: 216 return nil, fmt.Errorf("unknown address input type %T", addrs) 217 } 218 219 for _, addr := range stringAddrs { 220 sa, err := sockaddr.NewSockAddr(addr) 221 if err != nil { 222 return nil, errwrap.Wrapf(fmt.Sprintf("error parsing address %q: {{err}}", addr), err) 223 } 224 out = append(out, &sockaddr.SockAddrMarshaler{ 225 SockAddr: sa, 226 }) 227 } 228 229 return out, nil 230} 231