2018-03-21 22:02:41 +00:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2018-04-04 02:35:45 +00:00
|
|
|
"io"
|
2018-03-21 22:02:41 +00:00
|
|
|
"net/http"
|
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/hashicorp/vault/api"
|
|
|
|
"github.com/hashicorp/vault/helper/consts"
|
2018-04-04 00:58:42 +00:00
|
|
|
"github.com/hashicorp/vault/helper/strutil"
|
2018-03-21 22:02:41 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func kvReadRequest(client *api.Client, path string, params map[string]string) (*api.Secret, error) {
|
|
|
|
r := client.NewRequest("GET", "/v1/"+path)
|
|
|
|
if r.Headers == nil {
|
|
|
|
r.Headers = http.Header{}
|
|
|
|
}
|
2018-04-09 16:39:32 +00:00
|
|
|
r.Headers.Add(consts.VaultKVCLIClientHeader, "v2")
|
2018-03-21 22:02:41 +00:00
|
|
|
|
|
|
|
for k, v := range params {
|
|
|
|
r.Params.Set(k, v)
|
|
|
|
}
|
|
|
|
resp, err := client.RawRequest(r)
|
|
|
|
if resp != nil {
|
|
|
|
defer resp.Body.Close()
|
|
|
|
}
|
|
|
|
if resp != nil && resp.StatusCode == 404 {
|
2018-04-04 16:26:06 +00:00
|
|
|
secret, parseErr := api.ParseSecret(resp.Body)
|
|
|
|
switch parseErr {
|
2018-04-04 02:35:45 +00:00
|
|
|
case nil:
|
|
|
|
case io.EOF:
|
|
|
|
return nil, nil
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
|
|
|
|
return secret, nil
|
|
|
|
}
|
2018-03-21 22:02:41 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return api.ParseSecret(resp.Body)
|
|
|
|
}
|
|
|
|
|
|
|
|
func kvListRequest(client *api.Client, path string) (*api.Secret, error) {
|
|
|
|
r := client.NewRequest("LIST", "/v1/"+path)
|
|
|
|
if r.Headers == nil {
|
|
|
|
r.Headers = http.Header{}
|
|
|
|
}
|
2018-04-09 16:39:32 +00:00
|
|
|
r.Headers.Add(consts.VaultKVCLIClientHeader, "v2")
|
2018-03-21 22:02:41 +00:00
|
|
|
|
|
|
|
// Set this for broader compatibility, but we use LIST above to be able to
|
|
|
|
// handle the wrapping lookup function
|
|
|
|
r.Method = "GET"
|
|
|
|
r.Params.Set("list", "true")
|
|
|
|
resp, err := client.RawRequest(r)
|
|
|
|
if resp != nil {
|
|
|
|
defer resp.Body.Close()
|
|
|
|
}
|
|
|
|
if resp != nil && resp.StatusCode == 404 {
|
2018-04-04 16:26:06 +00:00
|
|
|
secret, parseErr := api.ParseSecret(resp.Body)
|
|
|
|
switch parseErr {
|
2018-04-04 02:35:45 +00:00
|
|
|
case nil:
|
|
|
|
case io.EOF:
|
|
|
|
return nil, nil
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
|
|
|
|
return secret, nil
|
|
|
|
}
|
2018-03-21 22:02:41 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return api.ParseSecret(resp.Body)
|
|
|
|
}
|
|
|
|
|
|
|
|
func kvWriteRequest(client *api.Client, path string, data map[string]interface{}) (*api.Secret, error) {
|
|
|
|
r := client.NewRequest("PUT", "/v1/"+path)
|
|
|
|
if r.Headers == nil {
|
|
|
|
r.Headers = http.Header{}
|
|
|
|
}
|
2018-04-09 16:39:32 +00:00
|
|
|
r.Headers.Add(consts.VaultKVCLIClientHeader, "v2")
|
2018-03-21 22:02:41 +00:00
|
|
|
if err := r.SetJSONBody(data); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := client.RawRequest(r)
|
|
|
|
if resp != nil {
|
|
|
|
defer resp.Body.Close()
|
|
|
|
}
|
2018-04-04 02:35:45 +00:00
|
|
|
if resp != nil && resp.StatusCode == 404 {
|
2018-04-04 16:26:06 +00:00
|
|
|
secret, parseErr := api.ParseSecret(resp.Body)
|
|
|
|
switch parseErr {
|
2018-04-04 02:35:45 +00:00
|
|
|
case nil:
|
|
|
|
case io.EOF:
|
|
|
|
return nil, nil
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
|
2018-04-04 16:26:06 +00:00
|
|
|
return secret, err
|
2018-04-04 02:35:45 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-21 22:02:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode == 200 {
|
|
|
|
return api.ParseSecret(resp.Body)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func kvDeleteRequest(client *api.Client, path string) (*api.Secret, error) {
|
|
|
|
r := client.NewRequest("DELETE", "/v1/"+path)
|
|
|
|
if r.Headers == nil {
|
|
|
|
r.Headers = http.Header{}
|
|
|
|
}
|
2018-04-09 16:39:32 +00:00
|
|
|
r.Headers.Add(consts.VaultKVCLIClientHeader, "v2")
|
2018-03-21 22:02:41 +00:00
|
|
|
resp, err := client.RawRequest(r)
|
|
|
|
if resp != nil {
|
|
|
|
defer resp.Body.Close()
|
|
|
|
}
|
2018-04-04 02:35:45 +00:00
|
|
|
if resp != nil && resp.StatusCode == 404 {
|
2018-04-04 16:26:06 +00:00
|
|
|
secret, parseErr := api.ParseSecret(resp.Body)
|
|
|
|
switch parseErr {
|
2018-04-04 02:35:45 +00:00
|
|
|
case nil:
|
|
|
|
case io.EOF:
|
|
|
|
return nil, nil
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
|
2018-04-04 16:26:06 +00:00
|
|
|
return secret, err
|
2018-04-04 02:35:45 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-21 22:02:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode == 200 {
|
|
|
|
return api.ParseSecret(resp.Body)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func addPrefixToVKVPath(p, apiPrefix string) (string, error) {
|
|
|
|
parts := strings.SplitN(p, "/", 2)
|
|
|
|
if len(parts) != 2 {
|
2018-04-09 18:35:21 +00:00
|
|
|
return "", errors.New("invalid path")
|
2018-03-21 22:02:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return path.Join(parts[0], apiPrefix, parts[1]), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getHeaderForMap(header string, data map[string]interface{}) string {
|
|
|
|
maxKey := 0
|
|
|
|
for k := range data {
|
|
|
|
if len(k) > maxKey {
|
|
|
|
maxKey = len(k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 4 for the column spaces and 5 for the len("value")
|
|
|
|
totalLen := maxKey + 4 + 5
|
|
|
|
|
|
|
|
equalSigns := totalLen - (len(header) + 2)
|
|
|
|
|
|
|
|
// If we have zero or fewer equal signs bump it back up to two on either
|
|
|
|
// side of the header.
|
|
|
|
if equalSigns <= 0 {
|
|
|
|
equalSigns = 4
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the number of equal signs is not divisible by two add a sign.
|
|
|
|
if equalSigns%2 != 0 {
|
|
|
|
equalSigns = equalSigns + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s %s %s", strings.Repeat("=", equalSigns/2), header, strings.Repeat("=", equalSigns/2))
|
|
|
|
}
|
2018-04-04 00:58:42 +00:00
|
|
|
|
|
|
|
func kvParseVersionsFlags(versions []string) []string {
|
|
|
|
versionsOut := make([]string, 0, len(versions))
|
|
|
|
for _, v := range versions {
|
|
|
|
versionsOut = append(versionsOut, strutil.ParseStringSlice(v, ",")...)
|
|
|
|
}
|
|
|
|
|
|
|
|
return versionsOut
|
|
|
|
}
|