Skip to content

Commit c3ffda6

Browse files
authored
use a single validator library in rekor-cli (#1818)
* use a single validator library in rekor-cli Signed-off-by: Bob Callaway <[email protected]> * fix lint issues Signed-off-by: Bob Callaway <[email protected]> --------- Signed-off-by: Bob Callaway <[email protected]>
1 parent b681a14 commit c3ffda6

File tree

4 files changed

+93
-92
lines changed

4 files changed

+93
-92
lines changed

cmd/rekor-cli/app/pflags.go

Lines changed: 69 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ package app
1717

1818
import (
1919
"encoding/base64"
20+
"errors"
2021
"fmt"
2122
"log"
23+
"os"
24+
"path/filepath"
2225
"strconv"
2326
"strings"
2427
"time"
@@ -28,7 +31,7 @@ import (
2831

2932
"github.com/spf13/pflag"
3033

31-
validator "github.com/go-playground/validator/v10"
34+
validator "github.com/asaskevich/govalidator"
3235
)
3336

3437
type FlagType string
@@ -71,31 +74,59 @@ func initializePFlagMap() {
7174
},
7275
operatorFlag: func() pflag.Value {
7376
// this validates a valid operator name
74-
return valueFactory(operatorFlag, validateString("oneof=and or"), "")
77+
operatorFlagValidator := func(val string) error {
78+
o := struct {
79+
Value string `valid:"in(and|or)"`
80+
}{val}
81+
_, err := validator.ValidateStruct(o)
82+
return err
83+
}
84+
return valueFactory(operatorFlag, operatorFlagValidator, "")
7585
},
7686
emailFlag: func() pflag.Value {
7787
// this validates an email address
78-
return valueFactory(emailFlag, validateString("required,email"), "")
88+
emailValidator := func(val string) error {
89+
if !validator.IsEmail(val) {
90+
return fmt.Errorf("'%v' is not a valid email address", val)
91+
}
92+
return nil
93+
}
94+
return valueFactory(emailFlag, emailValidator, "")
7995
},
8096
logIndexFlag: func() pflag.Value {
8197
// this checks for a valid integer >= 0
82-
return valueFactory(logIndexFlag, validateLogIndex, "")
98+
return valueFactory(logIndexFlag, validateUint, "")
8399
},
84100
pkiFormatFlag: func() pflag.Value {
85101
// this ensures a PKI implementation exists for the requested format
86-
return valueFactory(pkiFormatFlag, validateString(fmt.Sprintf("required,oneof=%v", strings.Join(pki.SupportedFormats(), " "))), "pgp")
102+
pkiFormatValidator := func(val string) error {
103+
if !validator.IsIn(val, pki.SupportedFormats()...) {
104+
return fmt.Errorf("'%v' is not a valid pki format", val)
105+
}
106+
return nil
107+
}
108+
return valueFactory(pkiFormatFlag, pkiFormatValidator, "pgp")
87109
},
88110
typeFlag: func() pflag.Value {
89111
// this ensures the type of the log entry matches a type supported in the CLI
90112
return valueFactory(typeFlag, validateTypeFlag, "rekord")
91113
},
92114
fileFlag: func() pflag.Value {
93115
// this validates that the file exists and can be opened by the current uid
94-
return valueFactory(fileFlag, validateString("required,file"), "")
116+
return valueFactory(fileFlag, validateFile, "")
95117
},
96118
urlFlag: func() pflag.Value {
97119
// this validates that the string is a valid http/https URL
98-
return valueFactory(urlFlag, validateString("required,url,startswith=http|startswith=https"), "")
120+
httpHTTPSValidator := func(val string) error {
121+
if !validator.IsURL(val) {
122+
return fmt.Errorf("'%v' is not a valid url", val)
123+
}
124+
if !(strings.HasPrefix(val, "http") || strings.HasPrefix(val, "https")) {
125+
return errors.New("URL must be for http or https scheme")
126+
}
127+
return nil
128+
}
129+
return valueFactory(urlFlag, httpHTTPSValidator, "")
99130
},
100131
fileOrURLFlag: func() pflag.Value {
101132
// applies logic of fileFlag OR urlFlag validators from above
@@ -111,7 +142,13 @@ func initializePFlagMap() {
111142
},
112143
formatFlag: func() pflag.Value {
113144
// this validates the output format requested
114-
return valueFactory(formatFlag, validateString("required,oneof=json default tle"), "")
145+
formatValidator := func(val string) error {
146+
if !validator.IsIn(val, "json", "default", "tle") {
147+
return fmt.Errorf("'%v' is not a valid output format", val)
148+
}
149+
return nil
150+
}
151+
return valueFactory(formatFlag, formatValidator, "")
115152
},
116153
timeoutFlag: func() pflag.Value {
117154
// this validates the timeout is >= 0
@@ -257,33 +294,23 @@ func validateID(v string) error {
257294
return fmt.Errorf("ID len error, expected %v (EntryID) or %v (UUID) but got len %v for ID %v", sharding.EntryIDHexStringLen, sharding.UUIDHexStringLen, len(v), v)
258295
}
259296

260-
if err := validateString("required,hexadecimal")(v); err != nil {
297+
if !validator.IsHexadecimal(v) {
261298
return fmt.Errorf("invalid uuid: %v", v)
262299
}
263300

264301
return nil
265302
}
266303

267-
// validateLogIndex ensures that the supplied string is a valid log index (integer >= 0)
268-
func validateLogIndex(v string) error {
269-
i, err := strconv.Atoi(v)
270-
if err != nil {
271-
return err
272-
}
273-
l := struct {
274-
Index int `validate:"gte=0"`
275-
}{i}
276-
277-
return useValidator(logIndexFlag, l)
278-
}
279-
280304
// validateOID ensures that the supplied string is a valid ASN.1 object identifier
281305
func validateOID(v string) error {
282-
o := struct {
283-
Oid []string `validate:"dive,numeric"`
284-
}{strings.Split(v, ".")}
306+
values := strings.Split(v, ".")
307+
for _, value := range values {
308+
if !validator.IsNumeric(value) {
309+
return fmt.Errorf("field '%v' is not a valid number", value)
310+
}
311+
}
285312

286-
return useValidator(oidFlag, o)
313+
return nil
287314
}
288315

289316
// validateTimeout ensures that the supplied string is a valid time.Duration value >= 0
@@ -292,10 +319,10 @@ func validateTimeout(v string) error {
292319
if err != nil {
293320
return err
294321
}
295-
d := struct {
296-
Duration time.Duration `validate:"min=0"`
297-
}{duration}
298-
return useValidator(timeoutFlag, d)
322+
if duration < 0 {
323+
return errors.New("timeout must be a positive value")
324+
}
325+
return nil
299326
}
300327

301328
// validateBase64 ensures that the supplied string is valid base64 encoded data
@@ -312,26 +339,6 @@ func validateTypeFlag(v string) error {
312339
return err
313340
}
314341

315-
// validateString returns a function that validates an input string against the specified tag,
316-
// as defined in the format supported by go-playground/validator
317-
func validateString(tag string) validationFunc {
318-
return func(v string) error {
319-
validator := validator.New()
320-
return validator.Var(v, tag)
321-
}
322-
}
323-
324-
// useValidator performs struct level validation on s as defined in the struct's tags using
325-
// the go-playground/validator library
326-
func useValidator(flagType FlagType, s interface{}) error {
327-
validate := validator.New()
328-
if err := validate.Struct(s); err != nil {
329-
return fmt.Errorf("error parsing %v flag: %w", flagType, err)
330-
}
331-
332-
return nil
333-
}
334-
335342
// validateUint ensures that the supplied string is a valid unsigned integer >= 0
336343
func validateUint(v string) error {
337344
i, err := strconv.Atoi(v)
@@ -341,9 +348,17 @@ func validateUint(v string) error {
341348
if i < 0 {
342349
return fmt.Errorf("invalid unsigned int: %v", v)
343350
}
344-
u := struct {
345-
Uint uint `validate:"gte=0"`
346-
}{uint(i)}
351+
return nil
352+
}
347353

348-
return useValidator(uintFlag, u)
354+
// validateFile ensures that the supplied string is a valid path to a file that exists
355+
func validateFile(v string) error {
356+
fileInfo, err := os.Stat(filepath.Clean(v))
357+
if err != nil {
358+
return err
359+
}
360+
if fileInfo.IsDir() {
361+
return errors.New("path to a directory was provided")
362+
}
363+
return nil
349364
}

cmd/rekor-cli/app/validate.go

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
package app
1717

1818
import (
19+
"errors"
20+
"fmt"
1921
"strings"
2022

21-
validator "github.com/go-playground/validator/v10"
23+
validator "github.com/asaskevich/govalidator"
2224
)
2325

2426
// validateSHA512Value ensures that the supplied string matches the
@@ -36,13 +38,14 @@ func validateSHA512Value(v string) error {
3638
hash = split[1]
3739
}
3840

39-
s := struct {
40-
Prefix string `validate:"omitempty,oneof=sha512"`
41-
Hash string `validate:"required,len=128,hexadecimal"`
42-
}{prefix, hash}
41+
if strings.TrimSpace(prefix) != "" && prefix != "sha512" {
42+
return fmt.Errorf("invalid prefix '%v'", prefix)
43+
}
4344

44-
validate := validator.New()
45-
return validate.Struct(s)
45+
if !validator.IsSHA512(strings.ToLower(hash)) {
46+
return errors.New("invalid SHA512 value")
47+
}
48+
return nil
4649
}
4750

4851
// validateSHA256Value ensures that the supplied string matches the following format:
@@ -60,13 +63,14 @@ func validateSHA256Value(v string) error {
6063
hash = split[1]
6164
}
6265

63-
s := struct {
64-
Prefix string `validate:"omitempty,oneof=sha256"`
65-
Hash string `validate:"required,len=64,hexadecimal"`
66-
}{prefix, hash}
66+
if strings.TrimSpace(prefix) != "" && prefix != "sha256" {
67+
return fmt.Errorf("invalid prefix '%v'", prefix)
68+
}
6769

68-
validate := validator.New()
69-
return validate.Struct(s)
70+
if !validator.IsSHA256(strings.ToLower(hash)) {
71+
return errors.New("invalid SHA256 value")
72+
}
73+
return nil
7074
}
7175

7276
func validateSHA1Value(v string) error {
@@ -81,12 +85,12 @@ func validateSHA1Value(v string) error {
8185
hash = split[1]
8286
}
8387

84-
s := struct {
85-
Prefix string `validate:"omitempty,oneof=sha1"`
86-
Hash string `validate:"required,len=40,hexadecimal"`
87-
}{prefix, hash}
88-
89-
validate := validator.New()
90-
return validate.Struct(s)
88+
if strings.TrimSpace(prefix) != "" && prefix != "sha1" {
89+
return fmt.Errorf("invalid prefix '%v'", prefix)
90+
}
9191

92+
if !validator.IsSHA1(strings.ToLower(hash)) {
93+
return errors.New("invalid SHA1 value")
94+
}
95+
return nil
9296
}

go.mod

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ require (
1414
github.com/go-openapi/strfmt v0.21.7
1515
github.com/go-openapi/swag v0.22.4
1616
github.com/go-openapi/validate v0.22.1
17-
github.com/go-playground/validator/v10 v10.16.0
1817
github.com/google/go-cmp v0.6.0
1918
github.com/google/rpmpack v0.5.0
2019
github.com/google/trillian v1.5.3
@@ -97,7 +96,6 @@ require (
9796
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
9897
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
9998
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
100-
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
10199
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
102100
github.com/go-logr/logr v1.2.4 // indirect
103101
github.com/go-logr/stdr v1.2.2 // indirect
@@ -147,8 +145,6 @@ require (
147145
github.com/go-openapi/analysis v0.21.4 // indirect
148146
github.com/go-openapi/jsonpointer v0.19.6 // indirect
149147
github.com/go-openapi/jsonreference v0.20.2 // indirect
150-
github.com/go-playground/locales v0.14.1 // indirect
151-
github.com/go-playground/universal-translator v0.18.1 // indirect
152148
github.com/godbus/dbus/v5 v5.1.0 // indirect
153149
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
154150
github.com/golang/protobuf v1.5.3 // indirect
@@ -161,7 +157,6 @@ require (
161157
github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef // indirect
162158
github.com/inconshreveable/mousetrap v1.1.0 // indirect
163159
github.com/josharian/intern v1.0.0 // indirect
164-
github.com/leodido/go-urn v1.2.4 // indirect
165160
github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect
166161
github.com/magiconair/properties v1.8.7 // indirect
167162
github.com/mailru/easyjson v0.7.7 // indirect

go.sum

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,6 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4
188188
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
189189
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
190190
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
191-
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
192-
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
193191
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
194192
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
195193
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -241,14 +239,6 @@ github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogB
241239
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
242240
github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU=
243241
github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
244-
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
245-
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
246-
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
247-
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
248-
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
249-
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
250-
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
251-
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
252242
github.com/go-redis/redismock/v9 v9.2.0 h1:ZrMYQeKPECZPjOj5u9eyOjg8Nnb0BS9lkVIZ6IpsKLw=
253243
github.com/go-redis/redismock/v9 v9.2.0/go.mod h1:18KHfGDK4Y6c2R0H38EUGWAdc7ZQS9gfYxc94k7rWT0=
254244
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
@@ -458,8 +448,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
458448
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
459449
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
460450
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
461-
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
462-
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
463451
github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf h1:ndns1qx/5dL43g16EQkPV/i8+b3l5bYQwLeoSBe7tS8=
464452
github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf/go.mod h1:aGkAgvWY/IUcVFfuly53REpfv5edu25oij+qHRFaraA=
465453
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
@@ -596,7 +584,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
596584
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
597585
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
598586
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
599-
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
600587
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
601588
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
602589
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=

0 commit comments

Comments
 (0)