mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 18:48:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			226 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package command
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/hashicorp/vault/api"
 | |
| 	kvbuilder "github.com/hashicorp/vault/helper/kv-builder"
 | |
| 	homedir "github.com/mitchellh/go-homedir"
 | |
| 	"github.com/mitchellh/mapstructure"
 | |
| 	"github.com/pkg/errors"
 | |
| 	"github.com/ryanuber/columnize"
 | |
| )
 | |
| 
 | |
| var ErrMissingID = fmt.Errorf("Missing ID!")
 | |
| var ErrMissingPath = fmt.Errorf("Missing PATH!")
 | |
| var ErrMissingThing = fmt.Errorf("Missing THING!")
 | |
| 
 | |
| // extractListData reads the secret and returns a typed list of data and a
 | |
| // boolean indicating whether the extraction was successful.
 | |
| func extractListData(secret *api.Secret) ([]interface{}, bool) {
 | |
| 	if secret == nil || secret.Data == nil {
 | |
| 		return nil, false
 | |
| 	}
 | |
| 
 | |
| 	k, ok := secret.Data["keys"]
 | |
| 	if !ok || k == nil {
 | |
| 		return nil, false
 | |
| 	}
 | |
| 
 | |
| 	i, ok := k.([]interface{})
 | |
| 	return i, ok
 | |
| }
 | |
| 
 | |
| // extractPath extracts the path and list of arguments from the args. If there
 | |
| // are no extra arguments, the remaining args will be nil.
 | |
| func extractPath(args []string) (string, []string, error) {
 | |
| 	str, remaining, err := extractThings(args)
 | |
| 	if err == ErrMissingThing {
 | |
| 		err = ErrMissingPath
 | |
| 	}
 | |
| 	return str, remaining, err
 | |
| }
 | |
| 
 | |
| // extractID extracts the path and list of arguments from the args. If there
 | |
| // are no extra arguments, the remaining args will be nil.
 | |
| func extractID(args []string) (string, []string, error) {
 | |
| 	str, remaining, err := extractThings(args)
 | |
| 	if err == ErrMissingThing {
 | |
| 		err = ErrMissingID
 | |
| 	}
 | |
| 	return str, remaining, err
 | |
| }
 | |
| 
 | |
| func extractThings(args []string) (string, []string, error) {
 | |
| 	if len(args) < 1 {
 | |
| 		return "", nil, ErrMissingThing
 | |
| 	}
 | |
| 
 | |
| 	// Path is always the first argument after all flags
 | |
| 	thing := args[0]
 | |
| 
 | |
| 	// Strip leading and trailing slashes
 | |
| 	thing = sanitizePath(thing)
 | |
| 
 | |
| 	// Verify we have a thing
 | |
| 	if thing == "" {
 | |
| 		return "", nil, ErrMissingThing
 | |
| 	}
 | |
| 
 | |
| 	// Splice remaining args
 | |
| 	var remaining []string
 | |
| 	if len(args) > 1 {
 | |
| 		remaining = args[1:]
 | |
| 	}
 | |
| 
 | |
| 	return thing, remaining, nil
 | |
| }
 | |
| 
 | |
| // sanitizePath removes any leading or trailing things from a "path".
 | |
| func sanitizePath(s string) string {
 | |
| 	return ensureNoTrailingSlash(ensureNoLeadingSlash(s))
 | |
| }
 | |
| 
 | |
| // ensureTrailingSlash ensures the given string has a trailing slash.
 | |
| func ensureTrailingSlash(s string) string {
 | |
| 	s = strings.TrimSpace(s)
 | |
| 	if s == "" {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	for len(s) > 0 && s[len(s)-1] != '/' {
 | |
| 		s = s + "/"
 | |
| 	}
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| // ensureNoTrailingSlash ensures the given string has a trailing slash.
 | |
| func ensureNoTrailingSlash(s string) string {
 | |
| 	s = strings.TrimSpace(s)
 | |
| 	if s == "" {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	for len(s) > 0 && s[len(s)-1] == '/' {
 | |
| 		s = s[:len(s)-1]
 | |
| 	}
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| // ensureNoLeadingSlash ensures the given string has a trailing slash.
 | |
| func ensureNoLeadingSlash(s string) string {
 | |
| 	s = strings.TrimSpace(s)
 | |
| 	if s == "" {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	for len(s) > 0 && s[0] == '/' {
 | |
| 		s = s[1:]
 | |
| 	}
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| // columnOuput prints the list of items as a table with no headers.
 | |
| func columnOutput(list []string) string {
 | |
| 	if len(list) == 0 {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	return columnize.Format(list, &columnize.Config{
 | |
| 		Glue:  "    ",
 | |
| 		Empty: "n/a",
 | |
| 	})
 | |
| }
 | |
| 
 | |
| // tableOutput prints the list of items as columns, where the first row is
 | |
| // the list of headers.
 | |
| func tableOutput(list []string) string {
 | |
| 	if len(list) == 0 {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	underline := ""
 | |
| 	headers := strings.Split(list[0], "|")
 | |
| 	for i, h := range headers {
 | |
| 		h = strings.TrimSpace(h)
 | |
| 		u := strings.Repeat("-", len(h))
 | |
| 
 | |
| 		underline = underline + u
 | |
| 		if i != len(headers)-1 {
 | |
| 			underline = underline + " | "
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	list = append(list, "")
 | |
| 	copy(list[2:], list[1:])
 | |
| 	list[1] = underline
 | |
| 
 | |
| 	return columnOutput(list)
 | |
| }
 | |
| 
 | |
| // parseArgsData parses the given args in the format key=value into a map of
 | |
| // the provided arguments. The given reader can also supply key=value pairs.
 | |
| func parseArgsData(stdin io.Reader, args []string) (map[string]interface{}, error) {
 | |
| 	builder := &kvbuilder.Builder{Stdin: stdin}
 | |
| 	if err := builder.Add(args...); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return builder.Map(), nil
 | |
| }
 | |
| 
 | |
| // parseArgsDataString parses the args data and returns the values as strings.
 | |
| // If the values cannot be represented as strings, an error is returned.
 | |
| func parseArgsDataString(stdin io.Reader, args []string) (map[string]string, error) {
 | |
| 	raw, err := parseArgsData(stdin, args)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	var result map[string]string
 | |
| 	if err := mapstructure.WeakDecode(raw, &result); err != nil {
 | |
| 		return nil, errors.Wrap(err, "failed to convert values to strings")
 | |
| 	}
 | |
| 	return result, nil
 | |
| }
 | |
| 
 | |
| // truncateToSeconds truncates the given duaration to the number of seconds. If
 | |
| // the duration is less than 1s, it is returned as 0. The integer represents
 | |
| // the whole number unit of seconds for the duration.
 | |
| func truncateToSeconds(d time.Duration) int {
 | |
| 	d = d.Truncate(1 * time.Second)
 | |
| 
 | |
| 	// Handle the case where someone requested a ridiculously short increment -
 | |
| 	// incremenents must be larger than a second.
 | |
| 	if d < 1*time.Second {
 | |
| 		return 0
 | |
| 	}
 | |
| 
 | |
| 	return int(d.Seconds())
 | |
| }
 | |
| 
 | |
| // printKeyStatus prints the KeyStatus response from the API.
 | |
| func printKeyStatus(ks *api.KeyStatus) string {
 | |
| 	return columnOutput([]string{
 | |
| 		fmt.Sprintf("Key Term | %d", ks.Term),
 | |
| 		fmt.Sprintf("Install Time | %s", ks.InstallTime.UTC().Format(time.RFC822)),
 | |
| 	})
 | |
| }
 | |
| 
 | |
| // expandPath takes a filepath and returns the full expanded path, accounting
 | |
| // for user-relative things like ~/.
 | |
| func expandPath(s string) string {
 | |
| 	if s == "" {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	e, err := homedir.Expand(s)
 | |
| 	if err != nil {
 | |
| 		return s
 | |
| 	}
 | |
| 	return e
 | |
| }
 | 
