Swap out sdk/helper libs with implementations in go-secure-stdlib (#12088)

* Swap out sdk/helper libs with implementations in go-secure-stdlib

* Fix transit batch test
This commit is contained in:
Jeff Mitchell 2021-07-15 01:56:37 -04:00 committed by GitHub
parent 84da2424a7
commit fe18b6f9e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 192 additions and 2282 deletions

View File

@ -16,8 +16,8 @@ require (
github.com/hashicorp/go-rootcerts v1.0.2
github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/vault/sdk v0.2.1
github.com/mitchellh/mapstructure v1.3.2
golang.org/x/net v0.0.0-20200602114024-627f9648deb9
github.com/mitchellh/mapstructure v1.4.1
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
gopkg.in/square/go-jose.v2 v2.5.1
)

View File

@ -90,6 +90,14 @@ github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@ -128,8 +136,9 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -168,14 +177,15 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -186,12 +196,12 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -205,17 +215,21 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@ -253,7 +267,8 @@ gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"reflect"
"strings"
"testing"
"github.com/hashicorp/vault/sdk/logical"
@ -579,9 +580,10 @@ func TestTransit_BatchEncryptionCase12(t *testing.T) {
// Test that the fast path function decodeBatchRequestItems behave like mapstructure.Decode() to decode []BatchRequestItem.
func TestTransit_decodeBatchRequestItems(t *testing.T) {
tests := []struct {
name string
src interface{}
dest []BatchRequestItem
name string
src interface{}
dest []BatchRequestItem
wantErrContains string
}{
// basic edge cases of nil values
{name: "nil-nil", src: nil, dest: nil},
@ -611,9 +613,10 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
dest: []BatchRequestItem{},
},
{
name: "src_plaintext_invalid-dest",
src: []interface{}{map[string]interface{}{"plaintext": 666}},
dest: []BatchRequestItem{},
name: "src_plaintext_invalid-dest",
src: []interface{}{map[string]interface{}{"plaintext": 666}},
dest: []BatchRequestItem{},
wantErrContains: "expected type 'string', got unconvertible type 'int'",
},
{
name: "src_ciphertext-dest",
@ -621,9 +624,10 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
dest: []BatchRequestItem{},
},
{
name: "src_ciphertext_invalid-dest",
src: []interface{}{map[string]interface{}{"ciphertext": 666}},
dest: []BatchRequestItem{},
name: "src_ciphertext_invalid-dest",
src: []interface{}{map[string]interface{}{"ciphertext": 666}},
dest: []BatchRequestItem{},
wantErrContains: "expected type 'string', got unconvertible type 'int'",
},
{
name: "src_key_version-dest",
@ -631,14 +635,16 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
dest: []BatchRequestItem{},
},
{
name: "src_key_version_invalid-dest",
src: []interface{}{map[string]interface{}{"key_version": "666"}},
dest: []BatchRequestItem{},
name: "src_key_version_invalid-dest",
src: []interface{}{map[string]interface{}{"key_version": "666"}},
dest: []BatchRequestItem{},
wantErrContains: "expected type 'int', got unconvertible type 'string'",
},
{
name: "src_key_version_invalid-number-dest",
src: []interface{}{map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "key_version": json.Number("1.1")}},
dest: []BatchRequestItem{},
name: "src_key_version_invalid-number-dest",
src: []interface{}{map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "key_version": json.Number("1.1")}},
dest: []BatchRequestItem{},
wantErrContains: "error decoding json.Number into [0].key_version",
},
{
name: "src_nonce-dest",
@ -646,9 +652,10 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
dest: []BatchRequestItem{},
},
{
name: "src_nonce_invalid-dest",
src: []interface{}{map[string]interface{}{"nonce": 666}},
dest: []BatchRequestItem{},
name: "src_nonce_invalid-dest",
src: []interface{}{map[string]interface{}{"nonce": 666}},
dest: []BatchRequestItem{},
wantErrContains: "expected type 'string', got unconvertible type 'int'",
},
{
name: "src_context-dest",
@ -656,9 +663,10 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
dest: []BatchRequestItem{},
},
{
name: "src_context_invalid-dest",
src: []interface{}{map[string]interface{}{"context": 666}},
dest: []BatchRequestItem{},
name: "src_context_invalid-dest",
src: []interface{}{map[string]interface{}{"context": 666}},
dest: []BatchRequestItem{},
wantErrContains: "expected type 'string', got unconvertible type 'int'",
},
{
name: "src_multi_order-dest",
@ -676,7 +684,8 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
map[string]interface{}{"context": "2", "key_version": "666"},
map[string]interface{}{"context": "3"},
},
dest: []BatchRequestItem{},
dest: []BatchRequestItem{},
wantErrContains: "expected type 'int', got unconvertible type 'string'",
},
{
name: "src_multi_with_multi_invalid-dest",
@ -685,7 +694,8 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
map[string]interface{}{"context": "2", "key_version": "666"},
map[string]interface{}{"context": "3", "key_version": "1337"},
},
dest: []BatchRequestItem{},
dest: []BatchRequestItem{},
wantErrContains: "expected type 'int', got unconvertible type 'string'",
},
{
name: "src_plaintext-nil-nonce",
@ -701,8 +711,16 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
gotErr := decodeBatchRequestItems(tt.src, &tt.dest)
gotDest := tt.dest
if !reflect.DeepEqual(expectedErr, gotErr) {
t.Errorf("decodeBatchRequestItems unexpected error value, want: '%v', got: '%v'", expectedErr, gotErr)
if expectedErr != nil {
if gotErr == nil {
t.Fatal("decodeBatchRequestItems unexpected error value; expected error but got none")
}
if tt.wantErrContains == "" {
t.Fatal("missing error condition")
}
if !strings.Contains(gotErr.Error(), tt.wantErrContains) {
t.Errorf("decodeBatchRequestItems unexpected error value, want err contains: '%v', got: '%v'", tt.wantErrContains, gotErr)
}
}
if !reflect.DeepEqual(expectedDest, gotDest) {

6
go.mod
View File

@ -126,7 +126,7 @@ require (
github.com/mitchellh/go-testing-interface v1.14.0
github.com/mitchellh/go-wordwrap v1.0.0
github.com/mitchellh/gox v1.0.1
github.com/mitchellh/mapstructure v1.3.3
github.com/mitchellh/mapstructure v1.4.1
github.com/mitchellh/reflectwalk v1.0.1
github.com/mongodb/go-client-mongodb-atlas v0.1.2
github.com/morikuni/aec v1.0.0 // indirect
@ -167,11 +167,11 @@ require (
go.opentelemetry.io/otel/trace v0.20.0
go.uber.org/atomic v1.6.0
go.uber.org/goleak v1.1.10
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
golang.org/x/net v0.0.0-20210510120150-4163338589ed
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c
google.golang.org/api v0.29.0

24
go.sum
View File

@ -349,8 +349,8 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.4.0/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ=
github.com/frankban/quicktest v1.4.1/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ=
github.com/frankban/quicktest v1.10.0 h1:Gfh+GAJZOAoKZsIZeZbdn2JF10kN1XHNvjsvQK8gVkE=
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk=
github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=
@ -622,6 +622,18 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.1 h1:6KMBnfEv0/kLAz0O76sliN5mXbCDcLfs2kP7ssP7+DQ=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/password v0.1.1 h1:6JzmBqXprakgFEHwBgdchsjaA9x3GyjdI568bXKxa60=
github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 h1:Yc026VyMyIpq1UWRnakHRG01U8fJm+nEfEmjoAb00n8=
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
github.com/hashicorp/go-slug v0.4.1 h1:/jAo8dNuLgSImoLXaX7Od7QB4TfYCVPam+OpAt5bZqc=
github.com/hashicorp/go-slug v0.4.1/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
@ -897,8 +909,9 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.0.0 h1:ATSdz4NWrmWPOF1CeCBU4sMCno2hgqdbSrRPFWQSVZI=
github.com/mitchellh/pointerstructure v1.0.0/go.mod h1:k4XwG94++jLVsSiTxo7qdIfXA9pj9EAeo0QsNNJOLZ8=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
@ -1286,8 +1299,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -1455,8 +1469,10 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@ -20,6 +20,12 @@ require (
github.com/hashicorp/go-kms-wrapping/entropy v0.1.0
github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/go-plugin v1.0.1
github.com/hashicorp/go-secure-stdlib/base62 v0.1.1
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1
github.com/hashicorp/go-secure-stdlib/password v0.1.1
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1
github.com/hashicorp/go-sockaddr v1.0.2
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.2.0
@ -28,15 +34,14 @@ require (
github.com/hashicorp/vault/api v1.1.1
github.com/mitchellh/copystructure v1.0.0
github.com/mitchellh/go-testing-interface v1.0.0
github.com/mitchellh/mapstructure v1.3.2
github.com/mitchellh/mapstructure v1.4.1
github.com/pierrec/lz4 v2.5.2+incompatible
github.com/pkg/errors v0.9.1
github.com/ryanuber/go-glob v1.0.0
github.com/stretchr/testify v1.5.1
github.com/stretchr/testify v1.7.0
go.uber.org/atomic v1.6.0
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
golang.org/x/net v0.0.0-20200602114024-627f9648deb9
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
google.golang.org/grpc v1.29.1
google.golang.org/protobuf v1.25.0
)

View File

@ -142,6 +142,18 @@ github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.1 h1:6KMBnfEv0/kLAz0O76sliN5mXbCDcLfs2kP7ssP7+DQ=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/password v0.1.1 h1:6JzmBqXprakgFEHwBgdchsjaA9x3GyjdI568bXKxa60=
github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 h1:Yc026VyMyIpq1UWRnakHRG01U8fJm+nEfEmjoAb00n8=
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@ -204,8 +216,9 @@ github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdI
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -276,8 +289,9 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@ -287,8 +301,9 @@ golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -309,8 +324,9 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -338,11 +354,17 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -403,8 +425,9 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=

View File

@ -1,52 +1,16 @@
// Package base62 provides utilities for working with base62 strings.
// base62 strings will only contain characters: 0-9, a-z, A-Z
// DEPRECATED: this has been moved to go-secure-stdlib and will be removed
package base62
import (
"crypto/rand"
"io"
uuid "github.com/hashicorp/go-uuid"
extbase62 "github.com/hashicorp/go-secure-stdlib/base62"
)
const (
charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
csLen = byte(len(charset))
)
// Random generates a random string using base-62 characters.
// Resulting entropy is ~5.95 bits/character.
func Random(length int) (string, error) {
return RandomWithReader(length, rand.Reader)
return extbase62.Random(length)
}
// RandomWithReader generates a random string using base-62 characters and a given reader.
// Resulting entropy is ~5.95 bits/character.
func RandomWithReader(length int, reader io.Reader) (string, error) {
if length == 0 {
return "", nil
}
output := make([]byte, 0, length)
// Request a bit more than length to reduce the chance
// of needing more than one batch of random bytes
batchSize := length + length/4
for {
buf, err := uuid.GenerateRandomBytesWithReader(batchSize, reader)
if err != nil {
return "", err
}
for _, b := range buf {
// Avoid bias by using a value range that's a multiple of 62
if b < (csLen * 4) {
output = append(output, charset[b%csLen])
if len(output) == length {
return string(output), nil
}
}
}
}
return extbase62.RandomWithReader(length, reader)
}

View File

@ -1,31 +0,0 @@
package base62
import (
"testing"
)
func TestRandom(t *testing.T) {
strings := make(map[string]struct{})
for i := 0; i < 100000; i++ {
c, err := Random(16)
if err != nil {
t.Fatal(err)
}
if _, ok := strings[c]; ok {
t.Fatalf("Unexpected duplicate string: %s", c)
}
strings[c] = struct{}{}
}
for i := 0; i < 3000; i++ {
c, err := Random(i)
if err != nil {
t.Fatal(err)
}
if len(c) != i {
t.Fatalf("Expected length %d, got: %d", i, len(c))
}
}
}

View File

@ -1,15 +1,14 @@
// DEPRECATED: this has been moved to go-secure-stdlib and will be removed
package mlock
// This should be set by the OS-specific packages to tell whether LockMemory
// is supported or not.
var supported bool
import (
extmlock "github.com/hashicorp/go-secure-stdlib/mlock"
)
// Supported returns true if LockMemory is functional on this system.
func Supported() bool {
return supported
return extmlock.Supported()
}
// LockMemory prevents any memory from being swapped to disk.
func LockMemory() error {
return lockMemory()
return extmlock.LockMemory()
}

View File

@ -1,13 +0,0 @@
// +build android darwin nacl netbsd plan9 windows
package mlock
func init() {
supported = false
}
func lockMemory() error {
// XXX: No good way to do this on Windows. There is the VirtualLock
// method, but it requires a specific address and offset.
return nil
}

View File

@ -1,18 +0,0 @@
// +build dragonfly freebsd linux openbsd solaris
package mlock
import (
"syscall"
"golang.org/x/sys/unix"
)
func init() {
supported = true
}
func lockMemory() error {
// Mlockall prevents all current and future pages from being swapped out.
return unix.Mlockall(syscall.MCL_CURRENT | syscall.MCL_FUTURE)
}

View File

@ -1,309 +1,41 @@
// DEPRECATED: this has been moved to go-secure-stdlib and will be removed
package parseutil
import (
"encoding/json"
"errors"
"fmt"
"regexp"
"strconv"
"strings"
"time"
"github.com/hashicorp/errwrap"
extparseutil "github.com/hashicorp/go-secure-stdlib/parseutil"
sockaddr "github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/mitchellh/mapstructure"
)
var validCapacityString = regexp.MustCompile("^[\t ]*([0-9]+)[\t ]?([kmgtKMGT][iI]?[bB])?[\t ]*$")
// ParseCapacityString parses a capacity string and returns the number of bytes it represents.
// Capacity strings are things like 5gib or 10MB. Supported prefixes are kb, kib, mb, mib, gb,
// gib, tb, tib, which are not case sensitive. If no prefix is present, the number is assumed
// to be in bytes already.
func ParseCapacityString(in interface{}) (uint64, error) {
var cap uint64
jsonIn, ok := in.(json.Number)
if ok {
in = jsonIn.String()
}
switch inp := in.(type) {
case nil:
// return default of zero
case string:
if inp == "" {
return cap, nil
}
matches := validCapacityString.FindStringSubmatch(inp)
// no sub-groups means we couldn't parse it
if len(matches) <= 1 {
return cap, errors.New("could not parse capacity from input")
}
var multiplier uint64 = 1
switch strings.ToLower(matches[2]) {
case "kb":
multiplier = 1000
case "kib":
multiplier = 1024
case "mb":
multiplier = 1000 * 1000
case "mib":
multiplier = 1024 * 1024
case "gb":
multiplier = 1000 * 1000 * 1000
case "gib":
multiplier = 1024 * 1024 * 1024
case "tb":
multiplier = 1000 * 1000 * 1000 * 1000
case "tib":
multiplier = 1024 * 1024 * 1024 * 1024
}
size, err := strconv.ParseUint(matches[1], 10, 64)
if err != nil {
return cap, err
}
cap = size * multiplier
case int:
cap = uint64(inp)
case int32:
cap = uint64(inp)
case int64:
cap = uint64(inp)
case uint:
cap = uint64(inp)
case uint32:
cap = uint64(inp)
case uint64:
cap = uint64(inp)
case float32:
cap = uint64(inp)
case float64:
cap = uint64(inp)
default:
return cap, errors.New("could not parse capacity from input")
}
return cap, nil
return extparseutil.ParseCapacityString(in)
}
func ParseDurationSecond(in interface{}) (time.Duration, error) {
var dur time.Duration
jsonIn, ok := in.(json.Number)
if ok {
in = jsonIn.String()
}
switch inp := in.(type) {
case nil:
// return default of zero
case string:
if inp == "" {
return dur, 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(inp) * time.Second
case int32:
dur = time.Duration(inp) * time.Second
case int64:
dur = time.Duration(inp) * time.Second
case uint:
dur = time.Duration(inp) * time.Second
case uint32:
dur = time.Duration(inp) * time.Second
case uint64:
dur = time.Duration(inp) * time.Second
case float32:
dur = time.Duration(inp) * time.Second
case float64:
dur = time.Duration(inp) * time.Second
case time.Duration:
dur = inp
default:
return 0, errors.New("could not parse duration from input")
}
return dur, nil
return extparseutil.ParseDurationSecond(in)
}
func ParseAbsoluteTime(in interface{}) (time.Time, error) {
var t time.Time
switch inp := in.(type) {
case nil:
// return default of zero
return t, nil
case string:
// Allow RFC3339 with nanoseconds, or without,
// or an epoch time as an integer.
var err error
t, err = time.Parse(time.RFC3339Nano, inp)
if err == nil {
break
}
t, err = time.Parse(time.RFC3339, inp)
if err == nil {
break
}
epochTime, err := strconv.ParseInt(inp, 10, 64)
if err == nil {
t = time.Unix(epochTime, 0)
break
}
return t, errors.New("could not parse string as date and time")
case json.Number:
epochTime, err := inp.Int64()
if err != nil {
return t, err
}
t = time.Unix(epochTime, 0)
case int:
t = time.Unix(int64(inp), 0)
case int32:
t = time.Unix(int64(inp), 0)
case int64:
t = time.Unix(inp, 0)
case uint:
t = time.Unix(int64(inp), 0)
case uint32:
t = time.Unix(int64(inp), 0)
case uint64:
t = time.Unix(int64(inp), 0)
default:
return t, errors.New("could not parse time from input type")
}
return t, nil
return extparseutil.ParseAbsoluteTime(in)
}
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
return extparseutil.ParseInt(in)
}
func ParseBool(in interface{}) (bool, error) {
var result bool
if err := mapstructure.WeakDecode(in, &result); err != nil {
return false, err
}
return result, nil
return extparseutil.ParseBool(in)
}
func ParseString(in interface{}) (string, error) {
var result string
if err := mapstructure.WeakDecode(in, &result); err != nil {
return "", err
}
return result, nil
return extparseutil.ParseString(in)
}
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
return extparseutil.ParseCommaStringSlice(in)
}
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
return extparseutil.ParseAddrs(addrs)
}

View File

@ -1,284 +0,0 @@
package parseutil
import (
"encoding/json"
"testing"
"time"
)
func Test_ParseCapacityString(t *testing.T) {
testCases := []struct {
name string
inp interface{}
valid bool
expected uint64
}{
{
"bare number as an int",
5,
true,
uint64(5),
},
{
"bare number as a float",
5.0,
true,
uint64(5),
},
{
"bare number as a string",
"5",
true,
uint64(5),
},
{
"string",
"haha",
false,
uint64(0),
},
{
"random data structure",
struct{}{},
false,
uint64(0),
},
{
"kb",
"5kb",
true,
uint64(5000),
},
{
"kib",
"5kib",
true,
uint64(5120),
},
{
"KB",
"5KB",
true,
uint64(5000),
},
{
"KIB",
"5KIB",
true,
uint64(5120),
},
{
"kB",
"5kB",
true,
uint64(5000),
},
{
"Kb",
"5Kb",
true,
uint64(5000),
},
{
"space kb",
"5 kb",
true,
uint64(5000),
},
{
"space KB",
"5 KB",
true,
uint64(5000),
},
{
"kb surrounding spaces",
" 5 kb ",
true,
uint64(5000),
},
{
"mb",
"5mb",
true,
uint64(5000000),
},
{
"mib",
"5mib",
true,
uint64(5242880),
},
{
"gb",
"5gb",
true,
uint64(5000000000),
},
{
"gib",
"5gib",
true,
uint64(5368709120),
},
{
"tb",
"5tb",
true,
uint64(5000000000000),
},
{
"tib",
"5tib",
true,
uint64(5497558138880),
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
outp, err := ParseCapacityString(tc.inp)
if tc.valid && err != nil {
t.Errorf("failed to parse: %v. err: %v", tc.inp, err)
}
if !tc.valid && err == nil {
t.Errorf("no error for: %v", tc.inp)
}
if outp != tc.expected {
t.Errorf("input %v parsed as %v, expected %v", tc.inp, outp, tc.expected)
}
})
}
}
func Test_ParseDurationSecond(t *testing.T) {
outp, err := ParseDurationSecond("9876s")
if err != nil {
t.Fatal(err)
}
if outp != time.Duration(9876)*time.Second {
t.Fatal("not equivalent")
}
outp, err = ParseDurationSecond("9876")
if err != nil {
t.Fatal(err)
}
if outp != time.Duration(9876)*time.Second {
t.Fatal("not equivalent")
}
outp, err = ParseDurationSecond(json.Number("4352"))
if err != nil {
t.Fatal(err)
}
if outp != time.Duration(4352)*time.Second {
t.Fatal("not equivalent")
}
}
func Test_ParseAbsoluteTime(t *testing.T) {
testCases := []struct {
inp interface{}
valid bool
expected time.Time
}{
{
"2020-12-11T09:08:07.654321Z",
true,
time.Date(2020, 12, 11, 9, 8, 7, 654321000, time.UTC),
},
{
"2020-12-11T09:08:07+02:00",
true,
time.Date(2020, 12, 11, 7, 8, 7, 0, time.UTC),
},
{
"2021-12-11T09:08:07Z",
true,
time.Date(2021, 12, 11, 9, 8, 7, 0, time.UTC),
},
{
"2021-12-11T09:08:07",
false,
time.Time{},
},
{
"1670749687",
true,
time.Date(2022, 12, 11, 9, 8, 7, 0, time.UTC),
},
{
1670749687,
true,
time.Date(2022, 12, 11, 9, 8, 7, 0, time.UTC),
},
{
uint32(1670749687),
true,
time.Date(2022, 12, 11, 9, 8, 7, 0, time.UTC),
},
{
json.Number("1670749687"),
true,
time.Date(2022, 12, 11, 9, 8, 7, 0, time.UTC),
},
{
nil,
true,
time.Time{},
},
{
struct{}{},
false,
time.Time{},
},
{
true,
false,
time.Time{},
},
}
for _, tc := range testCases {
outp, err := ParseAbsoluteTime(tc.inp)
if err != nil {
if tc.valid {
t.Errorf("failed to parse: %v", tc.inp)
}
continue
}
if err == nil && !tc.valid {
t.Errorf("no error for: %v", tc.inp)
continue
}
if !outp.Equal(tc.expected) {
t.Errorf("input %v parsed as %v, expected %v", tc.inp, outp, tc.expected)
}
}
}
func Test_ParseBool(t *testing.T) {
outp, err := ParseBool("true")
if err != nil {
t.Fatal(err)
}
if !outp {
t.Fatal("wrong output")
}
outp, err = ParseBool(1)
if err != nil {
t.Fatal(err)
}
if !outp {
t.Fatal("wrong output")
}
outp, err = ParseBool(true)
if err != nil {
t.Fatal(err)
}
if !outp {
t.Fatal("wrong output")
}
}

View File

@ -1,69 +1,14 @@
// password is a package for reading a password securely from a terminal.
// The code in this package disables echo in the terminal so that the
// password is not echoed back in plaintext to the user.
// DEPRECATED: this has been moved to go-secure-stdlib and will be removed
package password
import (
"errors"
"io"
"os"
"os/signal"
"strings"
extpassword "github.com/hashicorp/go-secure-stdlib/password"
)
var ErrInterrupted = errors.New("interrupted")
var ErrInterrupted = extpassword.ErrInterrupted
// Read reads the password from the given os.File. The password
// will not be echoed back to the user. Ctrl-C will automatically return
// from this function with a blank string and an ErrInterrupted.
func Read(f *os.File) (string, error) {
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
defer signal.Stop(ch)
// Run the actual read in a go-routine so that we can still detect signals
var result string
var resultErr error
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
result, resultErr = read(f)
}()
// Wait on either the read to finish or the signal to come through
select {
case <-ch:
return "", ErrInterrupted
case <-doneCh:
return removeiTermDelete(result), resultErr
}
}
func readline(f *os.File) (string, error) {
var buf [1]byte
resultBuf := make([]byte, 0, 64)
for {
n, err := f.Read(buf[:])
if err != nil && err != io.EOF {
return "", err
}
if n == 0 || buf[0] == '\n' || buf[0] == '\r' {
break
}
// ASCII code 3 is what is sent for a Ctrl-C while reading raw.
// If we see that, then get the interrupt. We have to do this here
// because terminals in raw mode won't catch it at the shell level.
if buf[0] == 3 {
return "", ErrInterrupted
}
resultBuf = append(resultBuf, buf[0])
}
return string(resultBuf), nil
}
func removeiTermDelete(input string) string {
return strings.TrimPrefix(input, "\x20\x7f")
return extpassword.Read(f)
}

View File

@ -1,55 +0,0 @@
// +build solaris
package password
import (
"fmt"
"os"
"syscall"
"golang.org/x/sys/unix"
)
func read(f *os.File) (string, error) {
fd := int(f.Fd())
if !isTerminal(fd) {
return "", fmt.Errorf("file descriptor %d is not a terminal", fd)
}
oldState, err := makeRaw(fd)
if err != nil {
return "", err
}
defer unix.IoctlSetTermios(fd, unix.TCSETS, oldState)
return readline(f)
}
// isTerminal returns true if there is a terminal attached to the given
// file descriptor.
// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
func isTerminal(fd int) bool {
var termio unix.Termio
err := unix.IoctlSetTermio(fd, unix.TCGETA, &termio)
return err == nil
}
// makeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
func makeRaw(fd int) (*unix.Termios, error) {
oldTermiosPtr, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
if err != nil {
return nil, err
}
oldTermios := *oldTermiosPtr
newTermios := oldTermios
newTermios.Lflag &^= syscall.ECHO | syscall.ECHOE | syscall.ECHOK | syscall.ECHONL
if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
return nil, err
}
return oldTermiosPtr, nil
}

View File

@ -1,27 +0,0 @@
package password
import "testing"
type testCase struct {
name string
input string
expected string
}
func TestRemoveiTermDelete(t *testing.T) {
tests := []testCase{
{"NoDelete", "TestingStuff", "TestingStuff"},
{"SingleDelete", "Testing\x7fStuff", "Testing\x7fStuff"},
{"DeleteFirst", "\x7fTestingStuff", "\x7fTestingStuff"},
{"DoubleDelete", "\x7f\x7fTestingStuff", "\x7f\x7fTestingStuff"},
{"SpaceFirst", "\x20TestingStuff", "\x20TestingStuff"},
{"iTermDelete", "\x20\x7fTestingStuff", "TestingStuff"},
}
for _, test := range tests {
result := removeiTermDelete(test.input)
if result != test.expected {
t.Errorf("Test %s failed, input: '%s', expected: '%s', output: '%s'", test.name, test.input, test.expected, result)
}
}
}

View File

@ -1,25 +0,0 @@
// +build linux darwin freebsd netbsd openbsd dragonfly
package password
import (
"fmt"
"os"
"golang.org/x/crypto/ssh/terminal"
)
func read(f *os.File) (string, error) {
fd := int(f.Fd())
if !terminal.IsTerminal(fd) {
return "", fmt.Errorf("file descriptor %d is not a terminal", fd)
}
oldState, err := terminal.MakeRaw(fd)
if err != nil {
return "", err
}
defer terminal.Restore(fd, oldState)
return readline(f)
}

View File

@ -1,48 +0,0 @@
// +build windows
package password
import (
"os"
"syscall"
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
setConsoleModeProc = kernel32.MustFindProc("SetConsoleMode")
)
// Magic constant from MSDN to control whether characters read are
// repeated back on the console.
//
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
const ENABLE_ECHO_INPUT = 0x0004
func read(f *os.File) (string, error) {
handle := syscall.Handle(f.Fd())
// Grab the old console mode so we can reset it. We defer the reset
// right away because it doesn't matter (it is idempotent).
var oldMode uint32
if err := syscall.GetConsoleMode(handle, &oldMode); err != nil {
return "", err
}
defer setConsoleMode(handle, oldMode)
// The new mode is the old mode WITHOUT the echo input flag set.
var newMode uint32 = uint32(int(oldMode) & ^ENABLE_ECHO_INPUT)
if err := setConsoleMode(handle, newMode); err != nil {
return "", err
}
return readline(f)
}
func setConsoleMode(console syscall.Handle, mode uint32) error {
r, _, err := setConsoleModeProc.Call(uintptr(console), uintptr(mode))
if r == 0 {
return err
}
return nil
}

View File

@ -1,480 +1,94 @@
// DEPRECATED: this has been moved to go-secure-stdlib and will be removed
package strutil
import (
"encoding/base64"
"encoding/json"
"fmt"
"sort"
"strings"
"github.com/hashicorp/errwrap"
glob "github.com/ryanuber/go-glob"
extstrutil "github.com/hashicorp/go-secure-stdlib/strutil"
)
// StrListContainsGlob looks for a string in a list of strings and allows
// globs.
func StrListContainsGlob(haystack []string, needle string) bool {
for _, item := range haystack {
if glob.Glob(item, needle) {
return true
}
}
return false
return extstrutil.StrListContainsGlob(haystack, needle)
}
// StrListContains looks for a string in a list of strings.
func StrListContains(haystack []string, needle string) bool {
for _, item := range haystack {
if item == needle {
return true
}
}
return false
return extstrutil.StrListContains(haystack, needle)
}
// StrListContainsCaseInsensitive looks for a string in a list of strings.
func StrListContainsCaseInsensitive(haystack []string, needle string) bool {
for _, item := range haystack {
if strings.EqualFold(item, needle) {
return true
}
}
return false
return extstrutil.StrListContainsCaseInsensitive(haystack, needle)
}
// StrListSubset checks if a given list is a subset
// of another set
func StrListSubset(super, sub []string) bool {
for _, item := range sub {
if !StrListContains(super, item) {
return false
}
}
return true
return extstrutil.StrListSubset(super, sub)
}
// ParseDedupAndSortStrings parses a comma separated list of strings
// into a slice of strings. The return slice will be sorted and will
// not contain duplicate or empty items.
func ParseDedupAndSortStrings(input string, sep string) []string {
input = strings.TrimSpace(input)
parsed := []string{}
if input == "" {
// Don't return nil
return parsed
}
return RemoveDuplicates(strings.Split(input, sep), false)
return extstrutil.ParseDedupAndSortStrings(input, sep)
}
// ParseDedupLowercaseAndSortStrings parses a comma separated list of
// strings into a slice of strings. The return slice will be sorted and
// will not contain duplicate or empty items. The values will be converted
// to lower case.
func ParseDedupLowercaseAndSortStrings(input string, sep string) []string {
input = strings.TrimSpace(input)
parsed := []string{}
if input == "" {
// Don't return nil
return parsed
}
return RemoveDuplicates(strings.Split(input, sep), true)
return extstrutil.ParseDedupLowercaseAndSortStrings(input, sep)
}
// ParseKeyValues parses a comma separated list of `<key>=<value>` tuples
// into a map[string]string.
func ParseKeyValues(input string, out map[string]string, sep string) error {
if out == nil {
return fmt.Errorf("'out is nil")
}
keyValues := ParseDedupLowercaseAndSortStrings(input, sep)
if len(keyValues) == 0 {
return nil
}
for _, keyValue := range keyValues {
shards := strings.Split(keyValue, "=")
if len(shards) != 2 {
return fmt.Errorf("invalid <key,value> format")
}
key := strings.TrimSpace(shards[0])
value := strings.TrimSpace(shards[1])
if key == "" || value == "" {
return fmt.Errorf("invalid <key,value> pair: key: %q value: %q", key, value)
}
out[key] = value
}
return nil
return extstrutil.ParseKeyValues(input, out, sep)
}
// ParseArbitraryKeyValues parses arbitrary <key,value> tuples. The input
// can be one of the following:
// * JSON string
// * Base64 encoded JSON string
// * Comma separated list of `<key>=<value>` pairs
// * Base64 encoded string containing comma separated list of
// `<key>=<value>` pairs
//
// Input will be parsed into the output parameter, which should
// be a non-nil map[string]string.
func ParseArbitraryKeyValues(input string, out map[string]string, sep string) error {
input = strings.TrimSpace(input)
if input == "" {
return nil
}
if out == nil {
return fmt.Errorf("'out' is nil")
}
// Try to base64 decode the input. If successful, consider the decoded
// value as input.
inputBytes, err := base64.StdEncoding.DecodeString(input)
if err == nil {
input = string(inputBytes)
}
// Try to JSON unmarshal the input. If successful, consider that the
// metadata was supplied as JSON input.
err = json.Unmarshal([]byte(input), &out)
if err != nil {
// If JSON unmarshalling fails, consider that the input was
// supplied as a comma separated string of 'key=value' pairs.
if err = ParseKeyValues(input, out, sep); err != nil {
return errwrap.Wrapf("failed to parse the input: {{err}}", err)
}
}
// Validate the parsed input
for key, value := range out {
if key != "" && value == "" {
return fmt.Errorf("invalid value for key %q", key)
}
}
return nil
return extstrutil.ParseArbitraryKeyValues(input, out, sep)
}
// ParseStringSlice parses a `sep`-separated list of strings into a
// []string with surrounding whitespace removed.
//
// The output will always be a valid slice but may be of length zero.
func ParseStringSlice(input string, sep string) []string {
input = strings.TrimSpace(input)
if input == "" {
return []string{}
}
splitStr := strings.Split(input, sep)
ret := make([]string, len(splitStr))
for i, val := range splitStr {
ret[i] = strings.TrimSpace(val)
}
return ret
return extstrutil.ParseStringSlice(input, sep)
}
// ParseArbitraryStringSlice parses arbitrary string slice. The input
// can be one of the following:
// * JSON string
// * Base64 encoded JSON string
// * `sep` separated list of values
// * Base64-encoded string containing a `sep` separated list of values
//
// Note that the separator is ignored if the input is found to already be in a
// structured format (e.g., JSON)
//
// The output will always be a valid slice but may be of length zero.
func ParseArbitraryStringSlice(input string, sep string) []string {
input = strings.TrimSpace(input)
if input == "" {
return []string{}
}
// Try to base64 decode the input. If successful, consider the decoded
// value as input.
inputBytes, err := base64.StdEncoding.DecodeString(input)
if err == nil {
input = string(inputBytes)
}
ret := []string{}
// Try to JSON unmarshal the input. If successful, consider that the
// metadata was supplied as JSON input.
err = json.Unmarshal([]byte(input), &ret)
if err != nil {
// If JSON unmarshalling fails, consider that the input was
// supplied as a separated string of values.
return ParseStringSlice(input, sep)
}
if ret == nil {
return []string{}
}
return ret
return extstrutil.ParseArbitraryStringSlice(input, sep)
}
// TrimStrings takes a slice of strings and returns a slice of strings
// with trimmed spaces
func TrimStrings(items []string) []string {
ret := make([]string, len(items))
for i, item := range items {
ret[i] = strings.TrimSpace(item)
}
return ret
return extstrutil.TrimStrings(items)
}
// RemoveDuplicates removes duplicate and empty elements from a slice of
// strings. This also may convert the items in the slice to lower case and
// returns a sorted slice.
func RemoveDuplicates(items []string, lowercase bool) []string {
itemsMap := map[string]bool{}
for _, item := range items {
item = strings.TrimSpace(item)
if lowercase {
item = strings.ToLower(item)
}
if item == "" {
continue
}
itemsMap[item] = true
}
items = make([]string, 0, len(itemsMap))
for item := range itemsMap {
items = append(items, item)
}
sort.Strings(items)
return items
return extstrutil.RemoveDuplicates(items, lowercase)
}
// RemoveDuplicatesStable removes duplicate and empty elements from a slice of
// strings, preserving order (and case) of the original slice.
// In all cases, strings are compared after trimming whitespace
// If caseInsensitive, strings will be compared after ToLower()
func RemoveDuplicatesStable(items []string, caseInsensitive bool) []string {
itemsMap := make(map[string]bool, len(items))
deduplicated := make([]string, 0, len(items))
for _, item := range items {
key := strings.TrimSpace(item)
if caseInsensitive {
key = strings.ToLower(key)
}
if key == "" || itemsMap[key] {
continue
}
itemsMap[key] = true
deduplicated = append(deduplicated, item)
}
return deduplicated
return extstrutil.RemoveDuplicatesStable(items, caseInsensitive)
}
// RemoveEmpty removes empty elements from a slice of
// strings
func RemoveEmpty(items []string) []string {
if len(items) == 0 {
return items
}
itemsSlice := make([]string, 0, len(items))
for _, item := range items {
if item == "" {
continue
}
itemsSlice = append(itemsSlice, item)
}
return itemsSlice
return extstrutil.RemoveEmpty(items)
}
// EquivalentSlices checks whether the given string sets are equivalent, as in,
// they contain the same values.
func EquivalentSlices(a, b []string) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
// First we'll build maps to ensure unique values
mapA := map[string]bool{}
mapB := map[string]bool{}
for _, keyA := range a {
mapA[keyA] = true
}
for _, keyB := range b {
mapB[keyB] = true
}
// Now we'll build our checking slices
var sortedA, sortedB []string
for keyA := range mapA {
sortedA = append(sortedA, keyA)
}
for keyB := range mapB {
sortedB = append(sortedB, keyB)
}
sort.Strings(sortedA)
sort.Strings(sortedB)
// Finally, compare
if len(sortedA) != len(sortedB) {
return false
}
for i := range sortedA {
if sortedA[i] != sortedB[i] {
return false
}
}
return true
return extstrutil.EquivalentSlices(a, b)
}
// EqualStringMaps tests whether two map[string]string objects are equal.
// Equal means both maps have the same sets of keys and values. This function
// is 6-10x faster than a call to reflect.DeepEqual().
func EqualStringMaps(a, b map[string]string) bool {
if len(a) != len(b) {
return false
}
for k := range a {
v, ok := b[k]
if !ok || a[k] != v {
return false
}
}
return true
return extstrutil.EqualStringMaps(a, b)
}
// StrListDelete removes the first occurrence of the given item from the slice
// of strings if the item exists.
func StrListDelete(s []string, d string) []string {
if s == nil {
return s
}
for index, element := range s {
if element == d {
return append(s[:index], s[index+1:]...)
}
}
return s
return extstrutil.StrListDelete(s, d)
}
// GlobbedStringsMatch compares item to val with support for a leading and/or
// trailing wildcard '*' in item.
func GlobbedStringsMatch(item, val string) bool {
if len(item) < 2 {
return val == item
}
hasPrefix := strings.HasPrefix(item, "*")
hasSuffix := strings.HasSuffix(item, "*")
if hasPrefix && hasSuffix {
return strings.Contains(val, item[1:len(item)-1])
} else if hasPrefix {
return strings.HasSuffix(val, item[1:])
} else if hasSuffix {
return strings.HasPrefix(val, item[:len(item)-1])
}
return val == item
return extstrutil.GlobbedStringsMatch(item, val)
}
// AppendIfMissing adds a string to a slice if the given string is not present
func AppendIfMissing(slice []string, i string) []string {
if StrListContains(slice, i) {
return slice
}
return append(slice, i)
return extstrutil.AppendIfMissing(slice, i)
}
// MergeSlices adds an arbitrary number of slices together, uniquely
func MergeSlices(args ...[]string) []string {
all := map[string]struct{}{}
for _, slice := range args {
for _, v := range slice {
all[v] = struct{}{}
}
}
result := make([]string, 0, len(all))
for k := range all {
result = append(result, k)
}
sort.Strings(result)
return result
return extstrutil.MergeSlices(args...)
}
// Difference returns the set difference (A - B) of the two given slices. The
// result will also remove any duplicated values in set A regardless of whether
// that matches any values in set B.
func Difference(a, b []string, lowercase bool) []string {
if len(a) == 0 {
return a
}
if len(b) == 0 {
if !lowercase {
return a
}
newA := make([]string, len(a))
for i, v := range a {
newA[i] = strings.ToLower(v)
}
return newA
}
a = RemoveDuplicates(a, lowercase)
b = RemoveDuplicates(b, lowercase)
itemsMap := map[string]bool{}
for _, aVal := range a {
itemsMap[aVal] = true
}
// Perform difference calculation
for _, bVal := range b {
if _, ok := itemsMap[bVal]; ok {
itemsMap[bVal] = false
}
}
items := []string{}
for item, exists := range itemsMap {
if exists {
items = append(items, item)
}
}
sort.Strings(items)
return items
return extstrutil.Difference(a, b, lowercase)
}
// GetString attempts to retrieve a value from the provided map and assert that it is a string. If the key does not
// exist in the map, this will return an empty string. If the key exists, but the value is not a string type, this will
// return an error. If no map or key is provied, this will return an error
func GetString(m map[string]interface{}, key string) (string, error) {
if m == nil {
return "", fmt.Errorf("missing map")
}
if key == "" {
return "", fmt.Errorf("missing key")
}
rawVal, ok := m[key]
if !ok {
return "", nil
}
str, ok := rawVal.(string)
if !ok {
return "", fmt.Errorf("invalid value at %s: is a %T", key, rawVal)
}
return str, nil
return extstrutil.GetString(m, key)
}

View File

@ -1,666 +0,0 @@
package strutil
import (
"encoding/base64"
"encoding/json"
"reflect"
"testing"
)
func TestStrUtil_StrListDelete(t *testing.T) {
output := StrListDelete([]string{"item1", "item2", "item3"}, "item1")
if StrListContains(output, "item1") {
t.Fatal("bad: 'item1' should not have been present")
}
output = StrListDelete([]string{"item1", "item2", "item3"}, "item2")
if StrListContains(output, "item2") {
t.Fatal("bad: 'item2' should not have been present")
}
output = StrListDelete([]string{"item1", "item2", "item3"}, "item3")
if StrListContains(output, "item3") {
t.Fatal("bad: 'item3' should not have been present")
}
output = StrListDelete([]string{"item1", "item1", "item3"}, "item1")
if !StrListContains(output, "item1") {
t.Fatal("bad: 'item1' should have been present")
}
output = StrListDelete(output, "item1")
if StrListContains(output, "item1") {
t.Fatal("bad: 'item1' should not have been present")
}
output = StrListDelete(output, "random")
if len(output) != 1 {
t.Fatalf("bad: expected: 1, actual: %d", len(output))
}
output = StrListDelete(output, "item3")
if StrListContains(output, "item3") {
t.Fatal("bad: 'item3' should not have been present")
}
}
func TestStrutil_EquivalentSlices(t *testing.T) {
slice1 := []string{"test2", "test1", "test3"}
slice2 := []string{"test3", "test2", "test1"}
if !EquivalentSlices(slice1, slice2) {
t.Fatalf("bad: expected a match")
}
slice2 = append(slice2, "test4")
if EquivalentSlices(slice1, slice2) {
t.Fatalf("bad: expected a mismatch")
}
}
func TestStrutil_ListContainsGlob(t *testing.T) {
haystack := []string{
"dev",
"ops*",
"root/*",
"*-dev",
"_*_",
}
if StrListContainsGlob(haystack, "tubez") {
t.Fatalf("Value shouldn't exist")
}
if !StrListContainsGlob(haystack, "root/test") {
t.Fatalf("Value should exist")
}
if !StrListContainsGlob(haystack, "ops_test") {
t.Fatalf("Value should exist")
}
if !StrListContainsGlob(haystack, "ops") {
t.Fatalf("Value should exist")
}
if !StrListContainsGlob(haystack, "dev") {
t.Fatalf("Value should exist")
}
if !StrListContainsGlob(haystack, "test-dev") {
t.Fatalf("Value should exist")
}
if !StrListContainsGlob(haystack, "_test_") {
t.Fatalf("Value should exist")
}
}
func TestStrutil_ListContains(t *testing.T) {
haystack := []string{
"dev",
"ops",
"prod",
"root",
}
if StrListContains(haystack, "tubez") {
t.Fatalf("Bad")
}
if !StrListContains(haystack, "root") {
t.Fatalf("Bad")
}
}
func TestStrutil_ListSubset(t *testing.T) {
parent := []string{
"dev",
"ops",
"prod",
"root",
}
child := []string{
"prod",
"ops",
}
if !StrListSubset(parent, child) {
t.Fatalf("Bad")
}
if !StrListSubset(parent, parent) {
t.Fatalf("Bad")
}
if !StrListSubset(child, child) {
t.Fatalf("Bad")
}
if !StrListSubset(child, nil) {
t.Fatalf("Bad")
}
if StrListSubset(child, parent) {
t.Fatalf("Bad")
}
if StrListSubset(nil, child) {
t.Fatalf("Bad")
}
}
func TestStrutil_ParseKeyValues(t *testing.T) {
actual := make(map[string]string)
expected := map[string]string{
"key1": "value1",
"key2": "value2",
}
var input string
var err error
input = "key1=value1,key2=value2"
err = ParseKeyValues(input, actual, ",")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual)
}
for k := range actual {
delete(actual, k)
}
input = "key1 = value1, key2 = value2"
err = ParseKeyValues(input, actual, ",")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual)
}
for k := range actual {
delete(actual, k)
}
input = "key1 = value1, key2 = "
err = ParseKeyValues(input, actual, ",")
if err == nil {
t.Fatalf("expected an error")
}
for k := range actual {
delete(actual, k)
}
input = "key1 = value1, = value2 "
err = ParseKeyValues(input, actual, ",")
if err == nil {
t.Fatalf("expected an error")
}
for k := range actual {
delete(actual, k)
}
input = "key1"
err = ParseKeyValues(input, actual, ",")
if err == nil {
t.Fatalf("expected an error")
}
}
func TestStrutil_ParseArbitraryKeyValues(t *testing.T) {
actual := make(map[string]string)
expected := map[string]string{
"key1": "value1",
"key2": "value2",
}
var input string
var err error
// Test <key>=<value> as comma separated string
input = "key1=value1,key2=value2"
err = ParseArbitraryKeyValues(input, actual, ",")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual)
}
for k := range actual {
delete(actual, k)
}
// Test <key>=<value> as base64 encoded comma separated string
input = base64.StdEncoding.EncodeToString([]byte(input))
err = ParseArbitraryKeyValues(input, actual, ",")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual)
}
for k := range actual {
delete(actual, k)
}
// Test JSON encoded <key>=<value> tuples
input = `{"key1":"value1", "key2":"value2"}`
err = ParseArbitraryKeyValues(input, actual, ",")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual)
}
for k := range actual {
delete(actual, k)
}
// Test base64 encoded JSON string of <key>=<value> tuples
input = base64.StdEncoding.EncodeToString([]byte(input))
err = ParseArbitraryKeyValues(input, actual, ",")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual)
}
for k := range actual {
delete(actual, k)
}
}
func TestStrutil_ParseArbitraryStringSlice(t *testing.T) {
input := `CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';GRANT "foo-role" TO "{{name}}";ALTER ROLE "{{name}}" SET search_path = foo;GRANT CONNECT ON DATABASE "postgres" TO "{{name}}";`
jsonExpected := []string{
`DO $$
BEGIN
IF NOT EXISTS (SELECT * FROM pg_catalog.pg_roles WHERE rolname='foo-role') THEN
CREATE ROLE "foo-role";
CREATE SCHEMA IF NOT EXISTS foo AUTHORIZATION "foo-role";
ALTER ROLE "foo-role" SET search_path = foo;
GRANT TEMPORARY ON DATABASE "postgres" TO "foo-role";
GRANT ALL PRIVILEGES ON SCHEMA foo TO "foo-role";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA foo TO "foo-role";
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA foo TO "foo-role";
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA foo TO "foo-role";
END IF;
END
$$`,
`CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'`,
`GRANT "foo-role" TO "{{name}}"`,
`ALTER ROLE "{{name}}" SET search_path = foo`,
`GRANT CONNECT ON DATABASE "postgres" TO "{{name}}"`,
``,
}
nonJSONExpected := jsonExpected[1:]
var actual []string
var inputB64 string
var err error
// Test non-JSON string
actual = ParseArbitraryStringSlice(input, ";")
if !reflect.DeepEqual(nonJSONExpected, actual) {
t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", nonJSONExpected, actual)
}
// Test base64-encoded non-JSON string
inputB64 = base64.StdEncoding.EncodeToString([]byte(input))
actual = ParseArbitraryStringSlice(inputB64, ";")
if !reflect.DeepEqual(nonJSONExpected, actual) {
t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", nonJSONExpected, actual)
}
// Test JSON encoded
inputJSON, err := json.Marshal(jsonExpected)
if err != nil {
t.Fatal(err)
}
actual = ParseArbitraryStringSlice(string(inputJSON), ";")
if !reflect.DeepEqual(jsonExpected, actual) {
t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", string(inputJSON), actual)
}
// Test base64 encoded JSON string of <key>=<value> tuples
inputB64 = base64.StdEncoding.EncodeToString(inputJSON)
actual = ParseArbitraryStringSlice(inputB64, ";")
if !reflect.DeepEqual(jsonExpected, actual) {
t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", jsonExpected, actual)
}
}
func TestGlobbedStringsMatch(t *testing.T) {
type tCase struct {
item string
val string
expect bool
}
tCases := []tCase{
{"", "", true},
{"*", "*", true},
{"**", "**", true},
{"*t", "t", true},
{"*t", "test", true},
{"t*", "test", true},
{"*test", "test", true},
{"*test", "a test", true},
{"test", "a test", false},
{"*test", "tests", false},
{"test*", "test", true},
{"test*", "testsss", true},
{"test**", "testsss", false},
{"test**", "test*", true},
{"**test", "*test", true},
{"TEST", "test", false},
{"test", "test", true},
}
for _, tc := range tCases {
actual := GlobbedStringsMatch(tc.item, tc.val)
if actual != tc.expect {
t.Fatalf("Bad testcase %#v, expected %t, got %t", tc, tc.expect, actual)
}
}
}
func TestTrimStrings(t *testing.T) {
input := []string{"abc", "123", "abcd ", "123 "}
expected := []string{"abc", "123", "abcd", "123"}
actual := TrimStrings(input)
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("Bad TrimStrings: expected:%#v, got:%#v", expected, actual)
}
}
func TestRemoveEmpty(t *testing.T) {
input := []string{"abc", "", "abc", ""}
expected := []string{"abc", "abc"}
actual := RemoveEmpty(input)
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("Bad TrimStrings: expected:%#v, got:%#v", expected, actual)
}
input = []string{""}
expected = []string{}
actual = RemoveEmpty(input)
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("Bad TrimStrings: expected:%#v, got:%#v", expected, actual)
}
}
func TestStrutil_AppendIfMissing(t *testing.T) {
keys := []string{}
keys = AppendIfMissing(keys, "foo")
if len(keys) != 1 {
t.Fatalf("expected slice to be length of 1: %v", keys)
}
if keys[0] != "foo" {
t.Fatalf("expected slice to contain key 'foo': %v", keys)
}
keys = AppendIfMissing(keys, "bar")
if len(keys) != 2 {
t.Fatalf("expected slice to be length of 2: %v", keys)
}
if keys[0] != "foo" {
t.Fatalf("expected slice to contain key 'foo': %v", keys)
}
if keys[1] != "bar" {
t.Fatalf("expected slice to contain key 'bar': %v", keys)
}
keys = AppendIfMissing(keys, "foo")
if len(keys) != 2 {
t.Fatalf("expected slice to still be length of 2: %v", keys)
}
if keys[0] != "foo" {
t.Fatalf("expected slice to still contain key 'foo': %v", keys)
}
if keys[1] != "bar" {
t.Fatalf("expected slice to still contain key 'bar': %v", keys)
}
}
func TestStrUtil_RemoveDuplicates(t *testing.T) {
type tCase struct {
input []string
expect []string
lowercase bool
}
tCases := []tCase{
{[]string{}, []string{}, false},
{[]string{}, []string{}, true},
{[]string{"a", "b", "a"}, []string{"a", "b"}, false},
{[]string{"A", "b", "a"}, []string{"A", "a", "b"}, false},
{[]string{"A", "b", "a"}, []string{"a", "b"}, true},
}
for _, tc := range tCases {
actual := RemoveDuplicates(tc.input, tc.lowercase)
if !reflect.DeepEqual(actual, tc.expect) {
t.Fatalf("Bad testcase %#v, expected %v, got %v", tc, tc.expect, actual)
}
}
}
func TestStrUtil_RemoveDuplicatesStable(t *testing.T) {
type tCase struct {
input []string
expect []string
caseInsensitive bool
}
tCases := []tCase{
{[]string{}, []string{}, false},
{[]string{}, []string{}, true},
{[]string{"a", "b", "a"}, []string{"a", "b"}, false},
{[]string{"A", "b", "a"}, []string{"A", "b", "a"}, false},
{[]string{"A", "b", "a"}, []string{"A", "b"}, true},
{[]string{" ", "d", "c", "d"}, []string{"d", "c"}, false},
{[]string{"Z ", " z", " z ", "y"}, []string{"Z ", "y"}, true},
{[]string{"Z ", " z", " z ", "y"}, []string{"Z ", " z", "y"}, false},
}
for _, tc := range tCases {
actual := RemoveDuplicatesStable(tc.input, tc.caseInsensitive)
if !reflect.DeepEqual(actual, tc.expect) {
t.Fatalf("Bad testcase %#v, expected %v, got %v", tc, tc.expect, actual)
}
}
}
func TestStrUtil_ParseStringSlice(t *testing.T) {
type tCase struct {
input string
sep string
expect []string
}
tCases := []tCase{
{"", "", []string{}},
{" ", ",", []string{}},
{", ", ",", []string{"", ""}},
{"a", ",", []string{"a"}},
{" a, b, c ", ",", []string{"a", "b", "c"}},
{" a; b; c ", ";", []string{"a", "b", "c"}},
{" a :: b :: c ", "::", []string{"a", "b", "c"}},
}
for _, tc := range tCases {
actual := ParseStringSlice(tc.input, tc.sep)
if !reflect.DeepEqual(actual, tc.expect) {
t.Fatalf("Bad testcase %#v, expected %v, got %v", tc, tc.expect, actual)
}
}
}
func TestStrUtil_MergeSlices(t *testing.T) {
res := MergeSlices([]string{"a", "c", "d"}, []string{}, []string{"c", "f", "a"}, nil, []string{"foo"})
expect := []string{"a", "c", "d", "f", "foo"}
if !reflect.DeepEqual(res, expect) {
t.Fatalf("expected %v, got %v", expect, res)
}
}
func TestDifference(t *testing.T) {
testCases := []struct {
Name string
SetA []string
SetB []string
Lowercase bool
ExpectedResult []string
}{
{
Name: "case_sensitive",
SetA: []string{"a", "b", "c"},
SetB: []string{"b", "c"},
Lowercase: false,
ExpectedResult: []string{"a"},
},
{
Name: "case_insensitive",
SetA: []string{"a", "B", "c"},
SetB: []string{"b", "C"},
Lowercase: true,
ExpectedResult: []string{"a"},
},
{
Name: "no_match",
SetA: []string{"a", "b", "c"},
SetB: []string{"d"},
Lowercase: false,
ExpectedResult: []string{"a", "b", "c"},
},
{
Name: "empty_set_a",
SetA: []string{},
SetB: []string{"d", "e"},
Lowercase: false,
ExpectedResult: []string{},
},
{
Name: "empty_set_b",
SetA: []string{"a", "b"},
SetB: []string{},
Lowercase: false,
ExpectedResult: []string{"a", "b"},
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
actualResult := Difference(tc.SetA, tc.SetB, tc.Lowercase)
if !reflect.DeepEqual(actualResult, tc.ExpectedResult) {
t.Fatalf("expected %v, got %v", tc.ExpectedResult, actualResult)
}
})
}
}
func TestStrUtil_EqualStringMaps(t *testing.T) {
m1 := map[string]string{
"foo": "a",
}
m2 := map[string]string{
"foo": "a",
"bar": "b",
}
var m3 map[string]string
m4 := map[string]string{
"dog": "",
}
m5 := map[string]string{
"cat": "",
}
tests := []struct {
a map[string]string
b map[string]string
result bool
}{
{m1, m1, true},
{m2, m2, true},
{m1, m2, false},
{m2, m1, false},
{m2, m2, true},
{m3, m1, false},
{m3, m3, true},
{m4, m5, false},
}
for i, test := range tests {
actual := EqualStringMaps(test.a, test.b)
if actual != test.result {
t.Fatalf("case %d, expected %v, got %v", i, test.result, actual)
}
}
}
func TestGetString(t *testing.T) {
type testCase struct {
m map[string]interface{}
key string
expectedStr string
expectErr bool
}
tests := map[string]testCase{
"nil map": {
m: nil,
key: "foo",
expectedStr: "",
expectErr: true,
},
"empty key": {
m: map[string]interface{}{
"foo": "bar",
},
key: "",
expectedStr: "",
expectErr: true,
},
"missing key": {
m: map[string]interface{}{
"foo": "bar",
},
key: "baz",
expectedStr: "",
expectErr: false,
},
"value is not a string": {
m: map[string]interface{}{
"foo": 42,
},
key: "foo",
expectedStr: "",
expectErr: true,
},
"happy path": {
m: map[string]interface{}{
"foo": "bar",
},
key: "foo",
expectedStr: "bar",
expectErr: false,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
actual, err := GetString(test.m, test.key)
if test.expectErr && err == nil {
t.Fatalf("err expected, got nil")
}
if !test.expectErr && err != nil {
t.Fatalf("no error expected, got: %s", err)
}
if actual != test.expectedStr {
t.Fatalf("Actual: [%s] Expected: [%s]", actual, test.expectedStr)
}
})
}
}

View File

@ -1,238 +1,32 @@
// DEPRECATED: this has been moved to go-secure-stdlib and will be removed
package tlsutil
import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io/ioutil"
"net"
"strings"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/sdk/helper/parseutil"
"github.com/hashicorp/vault/sdk/helper/strutil"
exttlsutil "github.com/hashicorp/go-secure-stdlib/tlsutil"
)
var ErrInvalidCertParams = errors.New("invalid certificate parameters")
var ErrInvalidCertParams = exttlsutil.ErrInvalidCertParams
// TLSLookup maps the tls_min_version configuration to the internal value
var TLSLookup = map[string]uint16{
"tls10": tls.VersionTLS10,
"tls11": tls.VersionTLS11,
"tls12": tls.VersionTLS12,
"tls13": tls.VersionTLS13,
}
var TLSLookup = exttlsutil.TLSLookup
// cipherMap maps the cipher suite names to the internal cipher suite code.
var cipherMap = map[string]uint16{
"TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA,
"TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
"TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
"TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
"TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
"TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
"TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
"TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
"TLS_AES_128_GCM_SHA256": tls.TLS_AES_128_GCM_SHA256,
"TLS_AES_256_GCM_SHA384": tls.TLS_AES_256_GCM_SHA384,
"TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256,
}
// ParseCiphers parse ciphersuites from the comma-separated string into recognized slice
func ParseCiphers(cipherStr string) ([]uint16, error) {
suites := []uint16{}
ciphers := strutil.ParseStringSlice(cipherStr, ",")
for _, cipher := range ciphers {
if v, ok := cipherMap[cipher]; ok {
suites = append(suites, v)
} else {
return suites, fmt.Errorf("unsupported cipher %q", cipher)
}
}
return suites, nil
return exttlsutil.ParseCiphers(cipherStr)
}
// GetCipherName returns the name of a given cipher suite code or an error if the
// given cipher is unsupported.
func GetCipherName(cipher uint16) (string, error) {
for cipherStr, cipherCode := range cipherMap {
if cipherCode == cipher {
return cipherStr, nil
}
}
return "", fmt.Errorf("unsupported cipher %d", cipher)
return exttlsutil.GetCipherName(cipher)
}
// ClientTLSConfig parses the CA certificate, and optionally a public/private
// client certificate key pair. The certificates must be in PEM encoded format.
func ClientTLSConfig(caCert []byte, clientCert []byte, clientKey []byte) (*tls.Config, error) {
var tlsConfig *tls.Config
var pool *x509.CertPool
switch {
case len(caCert) != 0:
// Valid
case len(clientCert) != 0 && len(clientKey) != 0:
// Valid
default:
return nil, ErrInvalidCertParams
}
if len(caCert) != 0 {
pool = x509.NewCertPool()
pool.AppendCertsFromPEM(caCert)
}
tlsConfig = &tls.Config{
RootCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
MinVersion: tls.VersionTLS12,
}
var cert tls.Certificate
var err error
if len(clientCert) != 0 && len(clientKey) != 0 {
cert, err = tls.X509KeyPair(clientCert, clientKey)
if err != nil {
return nil, err
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
tlsConfig.BuildNameToCertificate()
return tlsConfig, nil
return exttlsutil.ClientTLSConfig(caCert, clientCert, clientKey)
}
// LoadClientTLSConfig loads and parse the CA certificate, and optionally a
// public/private client certificate key pair. The certificates must be in PEM
// encoded format.
func LoadClientTLSConfig(caCert, clientCert, clientKey string) (*tls.Config, error) {
var tlsConfig *tls.Config
var pool *x509.CertPool
switch {
case len(caCert) != 0:
// Valid
case len(clientCert) != 0 && len(clientKey) != 0:
// Valid
default:
return nil, ErrInvalidCertParams
}
if len(caCert) != 0 {
pool = x509.NewCertPool()
data, err := ioutil.ReadFile(caCert)
if err != nil {
return nil, errwrap.Wrapf("failed to read CA file: {{err}}", err)
}
if !pool.AppendCertsFromPEM(data) {
return nil, fmt.Errorf("failed to parse CA certificate")
}
}
tlsConfig = &tls.Config{
RootCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
MinVersion: tls.VersionTLS12,
}
var cert tls.Certificate
var err error
if len(clientCert) != 0 && len(clientKey) != 0 {
cert, err = tls.LoadX509KeyPair(clientCert, clientKey)
if err != nil {
return nil, err
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
tlsConfig.BuildNameToCertificate()
return tlsConfig, nil
return exttlsutil.LoadClientTLSConfig(caCert, clientCert, clientKey)
}
func SetupTLSConfig(conf map[string]string, address string) (*tls.Config, error) {
serverName, _, err := net.SplitHostPort(address)
switch {
case err == nil:
case strings.Contains(err.Error(), "missing port"):
serverName = conf["address"]
default:
return nil, err
}
insecureSkipVerify := false
tlsSkipVerify := conf["tls_skip_verify"]
if tlsSkipVerify != "" {
b, err := parseutil.ParseBool(tlsSkipVerify)
if err != nil {
return nil, errwrap.Wrapf("failed parsing tls_skip_verify parameter: {{err}}", err)
}
insecureSkipVerify = b
}
tlsMinVersionStr, ok := conf["tls_min_version"]
if !ok {
// Set the default value
tlsMinVersionStr = "tls12"
}
tlsMinVersion, ok := TLSLookup[tlsMinVersionStr]
if !ok {
return nil, fmt.Errorf("invalid 'tls_min_version'")
}
tlsClientConfig := &tls.Config{
MinVersion: tlsMinVersion,
InsecureSkipVerify: insecureSkipVerify,
ServerName: serverName,
}
_, okCert := conf["tls_cert_file"]
_, okKey := conf["tls_key_file"]
if okCert && okKey {
tlsCert, err := tls.LoadX509KeyPair(conf["tls_cert_file"], conf["tls_key_file"])
if err != nil {
return nil, errwrap.Wrapf("client tls setup failed: {{err}}", err)
}
tlsClientConfig.Certificates = []tls.Certificate{tlsCert}
} else if okCert || okKey {
return nil, fmt.Errorf("both tls_cert_file and tls_key_file must be provided")
}
if tlsCaFile, ok := conf["tls_ca_file"]; ok {
caPool := x509.NewCertPool()
data, err := ioutil.ReadFile(tlsCaFile)
if err != nil {
return nil, errwrap.Wrapf("failed to read CA file: {{err}}", err)
}
if !caPool.AppendCertsFromPEM(data) {
return nil, fmt.Errorf("failed to parse CA certificate")
}
tlsClientConfig.RootCAs = caPool
}
return tlsClientConfig, nil
return exttlsutil.SetupTLSConfig(conf, address)
}

View File

@ -1,48 +0,0 @@
package tlsutil
import (
"crypto/tls"
"reflect"
"testing"
)
func TestParseCiphers(t *testing.T) {
testOk := "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
v, err := ParseCiphers(testOk)
if err != nil {
t.Fatal(err)
}
if len(v) != 17 {
t.Fatal("missed ciphers after parse")
}
testBad := "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,cipherX"
if _, err := ParseCiphers(testBad); err == nil {
t.Fatal("should fail on unsupported cipherX")
}
testOrder := "TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256"
v, _ = ParseCiphers(testOrder)
expected := []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_RSA_WITH_AES_128_GCM_SHA256}
if !reflect.DeepEqual(expected, v) {
t.Fatal("cipher order is not preserved")
}
}
func TestGetCipherName(t *testing.T) {
testOkCipherStr := "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"
testOkCipher := tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
cipherStr, err := GetCipherName(testOkCipher)
if err != nil {
t.Fatal(err)
}
if cipherStr != testOkCipherStr {
t.Fatalf("cipher string should be %s but is %s", testOkCipherStr, cipherStr)
}
var testBadCipher uint16 = 0xC022
cipherStr, err = GetCipherName(testBadCipher)
if err == nil {
t.Fatal("should fail on unsupported cipher 0xC022")
}
}