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:
parent
84da2424a7
commit
fe18b6f9e0
|
@ -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
|
||||
)
|
||||
|
|
37
api/go.sum
37
api/go.sum
|
@ -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=
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/sdk/logical"
|
||||
|
@ -582,6 +583,7 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
|
|||
name string
|
||||
src interface{}
|
||||
dest []BatchRequestItem
|
||||
wantErrContains string
|
||||
}{
|
||||
// basic edge cases of nil values
|
||||
{name: "nil-nil", src: nil, dest: nil},
|
||||
|
@ -614,6 +616,7 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
|
|||
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",
|
||||
|
@ -624,6 +627,7 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
|
|||
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",
|
||||
|
@ -634,11 +638,13 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
|
|||
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{},
|
||||
wantErrContains: "error decoding json.Number into [0].key_version",
|
||||
},
|
||||
{
|
||||
name: "src_nonce-dest",
|
||||
|
@ -649,6 +655,7 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
|
|||
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",
|
||||
|
@ -659,6 +666,7 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
|
|||
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",
|
||||
|
@ -677,6 +685,7 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
|
|||
map[string]interface{}{"context": "3"},
|
||||
},
|
||||
dest: []BatchRequestItem{},
|
||||
wantErrContains: "expected type 'int', got unconvertible type 'string'",
|
||||
},
|
||||
{
|
||||
name: "src_multi_with_multi_invalid-dest",
|
||||
|
@ -686,6 +695,7 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
|
|||
map[string]interface{}{"context": "3", "key_version": "1337"},
|
||||
},
|
||||
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
6
go.mod
|
@ -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
24
go.sum
|
@ -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=
|
||||
|
|
15
sdk/go.mod
15
sdk/go.mod
|
@ -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
|
||||
)
|
||||
|
|
37
sdk/go.sum
37
sdk/go.sum
|
@ -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=
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue