cb1a686e3b
* Strip empty strings from database revocation stmts It's technically valid to give empty strings as statements to run on most databases. However, in the case of revocation statements, it's not only generally inadvisable but can lead to lack of revocations when you expect them. This strips empty strings from the array of revocation statements. It also makes two other changes: * Return statements on read as empty but valid arrays rather than nulls, so that typing information is inferred (this is more in line with the rest of Vault these days) * Changes field data for TypeStringSlice and TypeCommaStringSlice such that a client-supplied value of `""` doesn't turn into `[]string{""}` but rather `[]string{}`. The latter and the explicit revocation statement changes are related, and defense in depth.
168 lines
3.7 KiB
Go
168 lines
3.7 KiB
Go
package parseutil
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hashicorp/errwrap"
|
|
sockaddr "github.com/hashicorp/go-sockaddr"
|
|
"github.com/hashicorp/vault/helper/strutil"
|
|
"github.com/mitchellh/mapstructure"
|
|
)
|
|
|
|
func ParseDurationSecond(in interface{}) (time.Duration, error) {
|
|
var dur time.Duration
|
|
jsonIn, ok := in.(json.Number)
|
|
if ok {
|
|
in = jsonIn.String()
|
|
}
|
|
switch in.(type) {
|
|
case string:
|
|
inp := in.(string)
|
|
if inp == "" {
|
|
return time.Duration(0), nil
|
|
}
|
|
var err error
|
|
// Look for a suffix otherwise its a plain second value
|
|
if strings.HasSuffix(inp, "s") || strings.HasSuffix(inp, "m") || strings.HasSuffix(inp, "h") || strings.HasSuffix(inp, "ms") {
|
|
dur, err = time.ParseDuration(inp)
|
|
if err != nil {
|
|
return dur, err
|
|
}
|
|
} else {
|
|
// Plain integer
|
|
secs, err := strconv.ParseInt(inp, 10, 64)
|
|
if err != nil {
|
|
return dur, err
|
|
}
|
|
dur = time.Duration(secs) * time.Second
|
|
}
|
|
case int:
|
|
dur = time.Duration(in.(int)) * time.Second
|
|
case int32:
|
|
dur = time.Duration(in.(int32)) * time.Second
|
|
case int64:
|
|
dur = time.Duration(in.(int64)) * time.Second
|
|
case uint:
|
|
dur = time.Duration(in.(uint)) * time.Second
|
|
case uint32:
|
|
dur = time.Duration(in.(uint32)) * time.Second
|
|
case uint64:
|
|
dur = time.Duration(in.(uint64)) * time.Second
|
|
default:
|
|
return 0, errors.New("could not parse duration from input")
|
|
}
|
|
|
|
return dur, nil
|
|
}
|
|
|
|
func ParseInt(in interface{}) (int64, error) {
|
|
var ret int64
|
|
jsonIn, ok := in.(json.Number)
|
|
if ok {
|
|
in = jsonIn.String()
|
|
}
|
|
switch in.(type) {
|
|
case string:
|
|
inp := in.(string)
|
|
if inp == "" {
|
|
return 0, nil
|
|
}
|
|
var err error
|
|
left, err := strconv.ParseInt(inp, 10, 64)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
ret = left
|
|
case int:
|
|
ret = int64(in.(int))
|
|
case int32:
|
|
ret = int64(in.(int32))
|
|
case int64:
|
|
ret = in.(int64)
|
|
case uint:
|
|
ret = int64(in.(uint))
|
|
case uint32:
|
|
ret = int64(in.(uint32))
|
|
case uint64:
|
|
ret = int64(in.(uint64))
|
|
default:
|
|
return 0, errors.New("could not parse value from input")
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func ParseBool(in interface{}) (bool, error) {
|
|
var result bool
|
|
if err := mapstructure.WeakDecode(in, &result); err != nil {
|
|
return false, err
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func ParseCommaStringSlice(in interface{}) ([]string, error) {
|
|
rawString, ok := in.(string)
|
|
if ok && rawString == "" {
|
|
return []string{}, nil
|
|
}
|
|
var result []string
|
|
config := &mapstructure.DecoderConfig{
|
|
Result: &result,
|
|
WeaklyTypedInput: true,
|
|
DecodeHook: mapstructure.StringToSliceHookFunc(","),
|
|
}
|
|
decoder, err := mapstructure.NewDecoder(config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decoder.Decode(in); err != nil {
|
|
return nil, err
|
|
}
|
|
return strutil.TrimStrings(result), nil
|
|
}
|
|
|
|
func ParseAddrs(addrs interface{}) ([]*sockaddr.SockAddrMarshaler, error) {
|
|
out := make([]*sockaddr.SockAddrMarshaler, 0)
|
|
stringAddrs := make([]string, 0)
|
|
|
|
switch addrs.(type) {
|
|
case string:
|
|
stringAddrs = strutil.ParseArbitraryStringSlice(addrs.(string), ",")
|
|
if len(stringAddrs) == 0 {
|
|
return nil, fmt.Errorf("unable to parse addresses from %v", addrs)
|
|
}
|
|
|
|
case []string:
|
|
stringAddrs = addrs.([]string)
|
|
|
|
case []interface{}:
|
|
for _, v := range addrs.([]interface{}) {
|
|
stringAddr, ok := v.(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("error parsing %v as string", v)
|
|
}
|
|
stringAddrs = append(stringAddrs, stringAddr)
|
|
}
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unknown address input type %T", addrs)
|
|
}
|
|
|
|
for _, addr := range stringAddrs {
|
|
sa, err := sockaddr.NewSockAddr(addr)
|
|
if err != nil {
|
|
return nil, errwrap.Wrapf(fmt.Sprintf("error parsing address %q: {{err}}", addr), err)
|
|
}
|
|
out = append(out, &sockaddr.SockAddrMarshaler{
|
|
SockAddr: sa,
|
|
})
|
|
}
|
|
|
|
return out, nil
|
|
}
|