diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index c813409..9a3fee6 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,29 +11,21 @@ jobs: build: name: Build runs-on: ubuntu-latest + strategy: + matrix: + go: ['v1.17.x', 'v1.18.x'] steps: - - - name: Set up Go 1.x - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: - go-version: ^1.14 - id: go - - - name: Check out code into the Go module directory - uses: actions/checkout@v2 - - - name: Debug - run: | + go-version: ${{ matrix.go }} + check-latest: true + - uses: actions/checkout@v2 + - run: | pwd echo ${HOME} echo ${GITHUB_WORKSPACE} echo ${GOPATH} echo ${GOROOT} - env: - GOPATH: /home/runner/work/go - - - name: Build - run: | mkdir -p $GOPATH/bin echo 'export PATH=$PATH:$GOPATH/bin' > runme.sh echo 'make tools all' >> runme.sh diff --git a/.golangci.yml b/.golangci.yml index 93ce311..70e5d87 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,50 +3,10 @@ # options for analysis running run: - # default concurrency is a available CPU number -# concurrency: 4 - - # timeout for analysis, e.g. 30s, 5m, default is 1m -# deadline: 1m - - # exit code when at least one issue was found, default is 1 -# issues-exit-code: 1 - - # include test files or not, default is true tests: true - - # list of build tags, all linters use it. Default is empty list. -# build-tags: -# - mytag - - # which dirs to skip: they won't be analyzed; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but next dirs are always skipped independently - # from this option's value: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ -# skip-dirs: -# - src/external_libs -# - autogenerated_by_my_lib - - # which files to skip: they will be analyzed, but issues from them - # won't be reported. Default value is empty list, but there is - # no need to include all autogenerated files, we confidently recognize - # autogenerated files. If it's not please let us know. skip-files: -# - ".*\\.my\\.go$" - requests.go - # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": - # If invoked with -mod=readonly, the go command is disallowed from the implicit - # automatic updating of go.mod described above. Instead, it fails when any changes - # to go.mod are needed. This setting is most useful to check that go.mod does - # not need updates, such as in a continuous integration and testing system. - # If invoked with -mod=vendor, the go command assumes that the vendor - # directory holds the correct copies of dependencies and ignores - # the dependency descriptions in go.mod. - # modules-download-mode: - - # output configuration options output: # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" @@ -61,54 +21,14 @@ output: # all available settings of specific linters linters-settings: - errcheck: - # report about not checking of errors in type assetions: `a := b.(MyStruct)`; - # default is false: such cases aren't reported by default. -# check-type-assertions: false - - # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; - # default is false: such cases aren't reported by default. -# check-blank: false - - # [deprecated] comma-separated list of pairs of the form pkg:regex - # the regex is used to ignore names within pkg. (default "fmt:.*"). - # see https://github.com/kisielk/errcheck#the-deprecated-method for details -# ignore: fmt:.*,io/ioutil:^Read.* - - # path to a file containing a list of functions to exclude from checking - # see https://github.com/kisielk/errcheck#excluding-functions for details -# exclude: /path/to/file.txt govet: # report about shadowed variables check-shadowing: false - - # settings per analyzer -# settings: -# printf: # analyzer name, run `go tool vet help` to see all analyzers -# funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer -# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof -# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf -# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf -# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf - golint: - # minimal confidence for issues, default is 0.8 -# min-confidence: 0.8 - gofmt: - # simplify code: gofmt with `-s` option, true by default -# simplify: true - goimports: - # put imports beginning with prefix after 3rd-party packages; - # it's a comma-separated list of prefixes -# local-prefixes: github.com/org/project - gocyclo: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 - maligned: - # print struct with more effective memory layout or not, false by default - suggest-new: true dupl: # tokens count to trigger issue, 150 by default threshold: 100 + exhaustive: + default-signifies-exhaustive: true goconst: # minimal length of string constant, 3 by default min-len: 3 @@ -129,64 +49,27 @@ linters-settings: # Default is to use a neutral variety of English. # Setting locale to US will correct the British spelling of 'colour' to 'color'. locale: US -# ignore-words: -# - someword - lll: - # max line length, lines longer will be reported. Default is 120. - # '\t' is counted as 1 character by default, and can be changed with the tab-width option -# line-length: 120 - # tab width in spaces. Default to 1. -# tab-width: 1 unused: # treat code as a program (not a library) and report unused exported identifiers; default is false. # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: # if it's called for subdir of a project it can't find funcs usages. All text editor integrations # with golangci-lint call it on a directory with the changed file. check-exported: false - unparam: - # Inspect exported functions, default is false. Set to true if no external program/library imports your code. - # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find external interfaces. All text editor integrations - # with golangci-lint call it on a directory with the changed file. - check-exported: false - nakedret: - # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 -# max-func-lines: 30 - prealloc: - # XXX: we don't recommend using this linter before doing performance profiling. - # For most programs usage of prealloc will be a premature optimization. - - # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. - # True by default. - simple: true - range-loops: true # Report preallocation suggestions on range loops, true by default - for-loops: false # Report preallocation suggestions on for loops, false by default gocritic: - # Which checks should be enabled; can't be combined with 'disabled-checks'; - # See https://go-critic.github.io/overview#checks-overview - # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` - # By default list of stable checks is used. -# enabled-checks: -# - rangeValCopy - # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty disabled-checks: - commentFormatting - - # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint` run to see all tags and checks. - # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". -# enabled-tags: -# - performance - -# settings: # settings passed to gocritic -# captLocal: # must be valid enabled check name -# paramsOnly: true -# rangeValCopy: -# sizeThreshold: 32 + revive: + ignore-generated-header: true + wsl: + allow-cuddle-declarations: true + allow-separated-leading-comment: true + allow-assign-and-anything: true linters: # to try out individual linters: golangci-lint run -E gocyclo,gosimple enable: + # default linters - staticcheck - deadcode - errcheck @@ -194,33 +77,82 @@ linters: - govet - ineffassign - structcheck -## - typecheck # redundant? compiler does this - unused - varcheck + + # additional linters + - asciicheck + - bidichk ## - bodyclose # its all false positives with requester and sling, which both close the body already + - containedctx + - contextcheck +# - cyclop # need to analyze findings + - decorder - depguard ## - dogsled # checks for too many blank identifiers. don't care - dupl + - durationcheck + - errchkjson + - errname + - errorlint + - exhaustive + - exportloopref + - forbidigo + - forcetypeassert ## - funlen # checks function length. don't care +# - gci # not sure why this is complaining ## - gochecknoglobals # too common - gochecknoinits +# - gocognit # too many findings, will take time to evaluate - goconst - gocritic ## - gocyclo # checks cyclomatic complexity. don't care -## - godox # checks for TODO comments. not standardized +# - godot # too many false positives +# - godox # doesn't allow TODO comments. We allow those to be committed. +# - goerr113 # good practice, but it doesn't recognize that we're already wrapping errors with merry ## - gofmt # checks code is formatted, handled by make prep + - gofumpt + - goheader ## - goimports # checks import order. We're not using goimports - - golint +# - gomnd # too aggressive + - gomoddirectives +# - gomodguard + - goprintffuncname - gosec - - interfacer + - grouper + - ifshort + - importas +# - ireturn # there are valid use cases for this pattern. too strict. ## - lll # checks line length. not enforced +# - maintidx # look at this later + - makezero ## - maligned # optimizies struct field order, but structs are usually ordered for legibility - misspell - nakedret +# - nestif # need to evaluate the findings + - nilerr + - nilnil +# - nlreturn # a little too aggressive. wsl covers the same ground. + - noctx + - nolintlint +# - paralleltest # look at this later # - prealloc # slice optimizations, but promotes too much premature optimization - - scopelint + - predeclared + - promlinter + - revive + - rowserrcheck + - sqlclosecheck - stylecheck + - tagliatelle + - thelper + - tparallel - unconvert + - unparam +# - varnamelen # take a look later + - wastedassign + - whitespace +# - wrapcheck # way too aggressive + - wsl ## - unparam # too many false positives ## - whitespace # not enforced disable-all: true @@ -240,6 +172,8 @@ issues: # Excluding configuration per-path, per-linter, per-text and per-source exclude-rules: + # Explicitly exclude the typecheck plugin. There is some bug in golangci which is + # enabling this checker, even though it isn't listed above. # Exclude some linters from running on tests files. - path: _test\.go linters: @@ -247,14 +181,19 @@ issues: - errcheck - dupl - gosec - - scopelint + - exportloopref - gochecknoinits - gochecknoglobals + - wsl + - nlreturn + - errchkjson + - forcetypeassert - path: cmd linters: - # init() functions are pretty common in main packages + # init(), globals, and prints are pretty common in main packages - gochecknoinits - gochecknoglobals + - forbidigo # Exclude known linters from partially hard-vendored code, # which is impossible to exclude via "nolint" comments. @@ -268,10 +207,6 @@ issues: # - staticcheck # text: "SA9003:" - # Exclude lll issues for long lines with go:generate - - linters: - - lll - source: "^//go:generate " # Independently from option `exclude` we use default exclude patterns, # it can be disabled by this option. To list all diff --git a/Makefile b/Makefile index b6d1bc2..c5b8a54 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ clean: rm -rf build/* fmt: - go fmt ./... + gofumpt -w -l . # generates go code structures representing all the enums, mask, and tags defined # in the KMIP spec. The source specifications are stored in kmip14/kmip_1_4.json @@ -90,7 +90,8 @@ update: # install tools used by the build. typically only needs to be run once # to initialize a workspace. tools: kmipgen - go get -u golang.org/x/tools/cmd/cover + go install mvdan.cc/gofumpt@latest + go install golang.org/x/tools/cmd/cover@latest sh -c "$$(wget -O - -q https://install.goreleaser.com/github.com/golangci/golangci-lint.sh || echo exit 2)" -- -b $(shell go env GOPATH)/bin $(GOLANGCI_LINT_VERSION) pykmip-server: up diff --git a/base_objects.go b/base_objects.go index 00ece2b..e75737e 100644 --- a/base_objects.go +++ b/base_objects.go @@ -1,9 +1,10 @@ package kmip import ( + "math/big" + "github.com/gemalto/kmip-go/kmip14" "github.com/gemalto/kmip-go/ttlv" - "math/big" ) // 2.1 Base Objects @@ -192,7 +193,7 @@ type KeyValue struct { // · TR-31. // · Extensions. // -//The following encoding options are currently defined: +// The following encoding options are currently defined: // // · No Encoding (i.e., the wrapped un-encoded value of the Byte String Key Material field in the Key Value structure). // · TTLV Encoding (i.e., the wrapped TTLV-encoded Key Value structure). @@ -396,9 +397,9 @@ type TransparentECPublicKey struct { // // The Template-Attribute, Common Template-Attribute, Private Key Template-Attribute, and Public Key // Template-Attribute structures are defined identically as follows: -//type TemplateAttribute struct { +// type TemplateAttribute struct { // Attribute []Attribute -//} +// } type TemplateAttribute struct { Name []Name @@ -411,11 +412,13 @@ func (t *TemplateAttribute) Get(s string) *Attribute { if t == nil { return nil } + for i := range t.Attribute { if t.Attribute[i].AttributeName == s { return &t.Attribute[i] } } + return nil } @@ -431,6 +434,7 @@ func (t *TemplateAttribute) GetIdx(s string, idx int) *Attribute { return &t.Attribute[i] } } + return nil } @@ -450,7 +454,9 @@ func (t *TemplateAttribute) GetAll(s string) []Attribute { if t == nil { return nil } + var ret []Attribute + for i := range t.Attribute { if t.Attribute[i].AttributeName == s { ret = append(ret, t.Attribute[i]) diff --git a/base_objects_test.go b/base_objects_test.go index e5a2736..b0c5ae1 100644 --- a/base_objects_test.go +++ b/base_objects_test.go @@ -3,16 +3,19 @@ package kmip import ( "bufio" "crypto/tls" + "testing" + "github.com/gemalto/kmip-go/kmip14" "github.com/gemalto/kmip-go/ttlv" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "testing" ) // clientConn returns a connection to the test kmip server. Should be closed at end of test. func clientConn(t *testing.T) *tls.Conn { + t.Helper() + cert, err := tls.LoadX509KeyPair("./pykmip-server/server.cert", "./pykmip-server/server.key") require.NoError(t, err) diff --git a/cmd/kmipgen/main.go b/cmd/kmipgen/main.go index 0fcb084..b21f112 100644 --- a/cmd/kmipgen/main.go +++ b/cmd/kmipgen/main.go @@ -6,8 +6,6 @@ import ( "encoding/json" "flag" "fmt" - "github.com/ansel1/merry" - "github.com/gemalto/kmip-go/internal/kmiputil" "go/format" "log" "os" @@ -16,6 +14,9 @@ import ( "strconv" "strings" "text/template" + + "github.com/ansel1/merry" + "github.com/gemalto/kmip-go/internal/kmiputil" ) // Specifications is the struct which the specifications JSON is unmarshaled into. @@ -54,7 +55,6 @@ type EnumDef struct { } func main() { - flag.Usage = func() { _, _ = fmt.Fprintln(flag.CommandLine.Output(), "Usage of kmipgen:") _, _ = fmt.Fprintln(flag.CommandLine.Output(), "") @@ -133,6 +133,7 @@ func run(inFilename, outFilename, packageName string) error { if err != nil { fmt.Println("error syncing file: ", err.Error()) } + err = f.Close() if err != nil { fmt.Println("error closing file: ", err.Error()) @@ -185,6 +186,7 @@ func parseUint32(v interface{}) (uint32, error) { if err != nil { return 0, err } + if b != nil { return kmiputil.DecodeUint32(b), nil } @@ -216,7 +218,6 @@ func prepareInput(s *Specifications) (*inputs, error) { // prepare tag inputs // normalize all the value names for key, value := range s.Tags { - i, err := parseUint32(value) if err != nil { return nil, merry.Prependf(err, "invalid tag value (%v)", value) @@ -260,6 +261,7 @@ func prepareInput(s *Specifications) (*inputs, error) { for _, t := range v.Tags { ev.Tags = append(ev.Tags, kmiputil.NormalizeName(t)) } + return ev, nil } @@ -269,6 +271,7 @@ func prepareInput(s *Specifications) (*inputs, error) { if err != nil { return nil, merry.Prependf(err, "error parsing enum %v", v.Name) } + in.Enums = append(in.Enums, ev) } @@ -277,6 +280,7 @@ func prepareInput(s *Specifications) (*inputs, error) { if err != nil { return nil, merry.Prependf(err, "error parsing mask %v", v.Name) } + ev.BitMask = true in.Masks = append(in.Masks, ev) } @@ -285,7 +289,6 @@ func prepareInput(s *Specifications) (*inputs, error) { } func genCode(s *Specifications) (string, error) { - buf := bytes.NewBuffer(nil) in, err := prepareInput(s) @@ -316,6 +319,7 @@ func genCode(s *Specifications) (string, error) { // The user can compile the output to see the error. log.Printf("warning: internal error: invalid Go generated: %s", err) log.Printf("warning: compile the package to analyze the error") + return buf.String(), nil } diff --git a/cmd/ppkmip/main.go b/cmd/ppkmip/main.go index 9520cb8..05aef40 100644 --- a/cmd/ppkmip/main.go +++ b/cmd/ppkmip/main.go @@ -9,21 +9,23 @@ import ( "errors" "flag" "fmt" - _ "github.com/gemalto/kmip-go/kmip14" - _ "github.com/gemalto/kmip-go/kmip20" - "github.com/gemalto/kmip-go/ttlv" "io" "io/ioutil" "os" "strings" + + _ "github.com/gemalto/kmip-go/kmip14" + _ "github.com/gemalto/kmip-go/kmip20" + "github.com/gemalto/kmip-go/ttlv" ) -const FormatJSON = "json" -const FormatXML = "xml" -const FormatHex = "hex" +const ( + FormatJSON = "json" + FormatXML = "xml" + FormatHex = "hex" +) func main() { - flag.Usage = func() { s := `ppkmip - kmip pretty printer @@ -100,6 +102,7 @@ xml format: var inFormat string var outFormat string var inFile string + flag.StringVar(&inFormat, "i", "", "input format: hex|json|xml, defaults to auto detect") flag.StringVar(&outFormat, "o", "", "output format: text|hex|prettyhex|json|xml, defaults to text") flag.StringVar(&inFile, "f", "", "input file name, defaults to stdin") @@ -113,6 +116,7 @@ xml format: if err != nil { fail("error reading input file", err) } + buf = bytes.NewBuffer(file) } else if inArg := flag.Arg(0); inArg != "" { buf.WriteString(inArg) @@ -150,9 +154,12 @@ xml format: switch strings.ToLower(inFormat) { case FormatJSON: var raw ttlv.TTLV + decoder := json.NewDecoder(buf) + for { err := decoder.Decode(&raw) + switch { case errors.Is(err, io.EOF): return @@ -160,6 +167,7 @@ xml format: default: fail("error parsing JSON", err) } + printTTLV(outFormat, raw, count) count++ } @@ -167,8 +175,10 @@ xml format: case FormatXML: var raw ttlv.TTLV decoder := xml.NewDecoder(buf) + for { err := decoder.Decode(&raw) + switch { case errors.Is(err, io.EOF): return @@ -176,11 +186,13 @@ xml format: default: fail("error parsing XML", err) } + printTTLV(outFormat, raw, count) count++ } case FormatHex: raw := ttlv.TTLV(ttlv.Hex2bytes(buf.String())) + for len(raw) > 0 { printTTLV(outFormat, raw, count) count++ @@ -195,6 +207,7 @@ func printTTLV(outFormat string, raw ttlv.TTLV, count int) { if count > 0 { fmt.Println("") } + switch outFormat { case "text": if err := ttlv.Print(os.Stdout, "", " ", raw); err != nil { @@ -205,12 +218,14 @@ func printTTLV(outFormat string, raw ttlv.TTLV, count int) { if err != nil { fail("error printing JSON", err) } + fmt.Print(string(s)) case "xml": s, err := xml.MarshalIndent(raw, "", " ") if err != nil { fail("error printing XML", err) } + fmt.Print(string(s)) case "hex": fmt.Print(hex.EncodeToString(raw)) @@ -227,5 +242,6 @@ func fail(msg string, err error) { } else { _, _ = fmt.Fprintln(os.Stderr, msg) } + os.Exit(1) } diff --git a/errors.go b/errors.go index 31a6348..8be2630 100644 --- a/errors.go +++ b/errors.go @@ -3,6 +3,7 @@ package kmip import ( "errors" "fmt" + "github.com/ansel1/merry" "github.com/gemalto/kmip-go/kmip14" ) diff --git a/examples_test.go b/examples_test.go index 8e5de5d..7f5763c 100644 --- a/examples_test.go +++ b/examples_test.go @@ -3,16 +3,16 @@ package kmip_test import ( "bufio" "fmt" + "net" + "time" + "github.com/gemalto/kmip-go" "github.com/gemalto/kmip-go/kmip14" "github.com/gemalto/kmip-go/ttlv" "github.com/google/uuid" - "net" - "time" ) func Example_client() { - conn, err := net.DialTimeout("tcp", "localhost:5696", 3*time.Second) if err != nil { panic(err) @@ -61,7 +61,6 @@ func Example_client() { resp := ttlv.TTLV(buf) fmt.Println(resp) - } func ExampleServer() { @@ -90,5 +89,4 @@ func ExampleServer() { }) srv := kmip.Server{} panic(srv.Serve(listener)) - } diff --git a/go.mod b/go.mod index f4509a2..67547f0 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,25 @@ module github.com/gemalto/kmip-go -go 1.14 +go 1.17 require ( - github.com/ansel1/merry v1.5.1 - github.com/gemalto/flume v0.12.0 - github.com/google/uuid v1.1.1 - github.com/mattn/go-colorable v0.1.7 // indirect + github.com/ansel1/merry v1.6.2 + github.com/gemalto/flume v0.13.0 + github.com/google/uuid v1.3.0 + github.com/stretchr/testify v1.7.0 + golang.org/x/text v0.3.7 +) + +require ( + github.com/ansel1/merry/v2 v2.0.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect - github.com/stretchr/testify v1.4.0 - go.uber.org/zap v1.15.0 // indirect - golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 // indirect - golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index c0dc16c..e5e8033 100644 --- a/go.sum +++ b/go.sum @@ -1,100 +1,208 @@ -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ansel1/merry v1.5.0/go.mod h1:wUy/yW0JX0ix9GYvUbciq+bi3jW/vlKPlbpI7qdZpOw= -github.com/ansel1/merry v1.5.1 h1:/MlZd3Irx2HQsUlOcXTTYev7N1t1Rsdnxwg6xkOVJp4= github.com/ansel1/merry v1.5.1/go.mod h1:wUy/yW0JX0ix9GYvUbciq+bi3jW/vlKPlbpI7qdZpOw= +github.com/ansel1/merry v1.6.1/go.mod h1:ioJjPJ/IsjxH+cC0lpf5TmbKnbcGa9qTk0fDbeRfnGQ= +github.com/ansel1/merry v1.6.2 h1:0xr40haRrfVzmOH/JVOu7KOKGEI1c/7q5EmgTEbn+Ng= +github.com/ansel1/merry v1.6.2/go.mod h1:pAcMW+2uxIgpzEON021vMtFsrymREY6faJWiiz1QGVQ= +github.com/ansel1/merry/v2 v2.0.0-beta.10/go.mod h1:OUvUYh4KLVhf3+sR9Hk8QxCukijznkpheEd837b7vLg= +github.com/ansel1/merry/v2 v2.0.1 h1:WeiKZdslHPAPFYxTtgX7clC2Vh75NCoWs5OjCZbIA0A= +github.com/ansel1/merry/v2 v2.0.1/go.mod h1:dD5OhpiPrVkvgseRYd+xgYlx7s6ytU3v9BTTJlDA7FM= +github.com/ansel1/vespucci/v4 v4.1.1/go.mod h1:zzdrO4IgBfgcGMbGTk/qNGL8JPslmW3nPpcBHKReFYY= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gemalto/flume v0.12.0 h1:775A38U9lbdUt0sv4NjvOgbrF292dgHXqdI7BaNN4Vk= -github.com/gemalto/flume v0.12.0/go.mod h1:CvecD9VlsuK3PMRV7Rr4zuUSlnZj3dvgC2BCvDxazbE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/gemalto/flume v0.13.0 h1:EEeQvAxyFys3BH8IxEU7ZpM6Kr1sYn20HuZq6dgyMR8= +github.com/gemalto/flume v0.13.0/go.mod h1:3iOEZiK/HD8SnFTqHCQoOHQKaHlBY0b6z55P8SLaOzk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.1.1 h1:ljK/pL5ltg3qoN+OtN6yCv9HWSfMwxSx90GJCZQxYNg= +github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/tebeka/go2xunit v1.4.10/go.mod h1:wmc9jKT7KlU4QLU6DNTaIXNnYNOjKKNlp6mjOS0UrqY= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +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/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +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= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190919044723-0c1ff786ef13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/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-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE= -golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 h1:eJv7u3ksNXoLbGSKuv2s/SIO4tJVxc/A+MTpzxDgz/Q= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +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= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190919180025-928b73f71f9b/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6 h1:qKpj8TpV+LEhel7H/fR788J+KvhWZ3o3V6N2fU/iuLU= -golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20210224155714-063164c882e6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20220208230804-65c12eb4c068/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +gopkg.in/yaml.v2 v2.2.3/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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= diff --git a/internal/kmiputil/hex_values.go b/internal/kmiputil/hex_values.go index 6f61782..b754255 100644 --- a/internal/kmiputil/hex_values.go +++ b/internal/kmiputil/hex_values.go @@ -3,8 +3,9 @@ package kmiputil import ( "encoding/binary" "encoding/hex" - "github.com/ansel1/merry" "strings" + + "github.com/ansel1/merry" ) var ErrInvalidHexString = merry.New("invalid hex string") @@ -25,6 +26,7 @@ func pad(b []byte, l int) []byte { copy(b2[l-len(b):], b) b = b2 } + return b } @@ -42,9 +44,10 @@ func ParseHexValue(s string, max int) ([]byte, error) { if !strings.HasPrefix(s, "0x") { return nil, nil } + b, err := hex.DecodeString(s[2:]) if err != nil { - return nil, merry.WithCause(ErrInvalidHexString, err) + return nil, merry.WithCause(ErrInvalidHexString, err).Append(err.Error()) } if max > 0 { diff --git a/internal/kmiputil/names.go b/internal/kmiputil/names.go index 3dc3807..9a05ad0 100644 --- a/internal/kmiputil/names.go +++ b/internal/kmiputil/names.go @@ -3,12 +3,19 @@ package kmiputil import ( "regexp" "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" ) -var nonWordAtWordBoundary = regexp.MustCompile(`(\W)([a-zA-Z][a-z])`) -var startingDigits = regexp.MustCompile(`^([\d]+)(.*)`) +var ( + nonWordAtWordBoundary = regexp.MustCompile(`(\W)([a-zA-Z][a-z])`) + startingDigits = regexp.MustCompile(`^([\d]+)(.*)`) +) -// implementation of 5.4.1.1 and 5.5.1.1 +// NormalizeName converts a string into the CamelCase format required for the XML and JSON encoding +// of KMIP values. It should be used for tag names, type names, and enumeration value names. +// Implementation of 5.4.1.1 and 5.5.1.1 from the KMIP Profiles specification. func NormalizeName(s string) string { // 1. Replace round brackets ‘(‘, ‘)’ with spaces s = strings.Map(func(r rune) rune { @@ -16,6 +23,7 @@ func NormalizeName(s string) string { case '(', ')': return ' ' } + return r }, s) @@ -33,23 +41,22 @@ func NormalizeName(s string) string { default: return '_' } + return r }, s) words := strings.Split(s, " ") for i, w := range words { - if i == 0 { // 4. If the first word begins with a digit, move all digits at start of first word to end of first word w = startingDigits.ReplaceAllString(w, `$2$1`) } // 5. Capitalize the first letter of each word - words[i] = strings.Title(w) + words[i] = cases.Title(language.AmericanEnglish, cases.NoLower).String(w) } // 6. Concatenate all words with spaces removed return strings.Join(words, "") - } diff --git a/kmip20/payloads_test.go b/kmip20/payloads_test.go index 5544e75..03aee26 100644 --- a/kmip20/payloads_test.go +++ b/kmip20/payloads_test.go @@ -1,10 +1,11 @@ package kmip20 import ( + "testing" + "github.com/gemalto/kmip-go/kmip14" "github.com/gemalto/kmip-go/ttlv" "github.com/stretchr/testify/require" - "testing" ) func TestCreateRequestPayload(t *testing.T) { diff --git a/kmip20/unique_identifier.go b/kmip20/unique_identifier.go index 4031f38..bc8bda4 100644 --- a/kmip20/unique_identifier.go +++ b/kmip20/unique_identifier.go @@ -43,5 +43,6 @@ func (u UniqueIdentifierValue) MarshalTTLV(e *ttlv.Encoder, tag ttlv.Tag) error case u.Index != 0: e.EncodeInteger(tag, u.Index) } + return nil } diff --git a/managed_objects.go b/managed_objects.go index d91cb8c..a557432 100644 --- a/managed_objects.go +++ b/managed_objects.go @@ -1,8 +1,9 @@ package kmip import ( - "github.com/gemalto/kmip-go/kmip14" "math/big" + + "github.com/gemalto/kmip-go/kmip14" ) // 2.2 diff --git a/op_create.go b/op_create.go index 9ccf484..dd55f34 100644 --- a/op_create.go +++ b/op_create.go @@ -2,6 +2,9 @@ package kmip import ( "context" + + "github.com/ansel1/merry" + "github.com/gemalto/kmip-go/kmip14" ) @@ -45,6 +48,7 @@ type CreateHandler struct { func (h *CreateHandler) HandleItem(ctx context.Context, req *Request) (*ResponseBatchItem, error) { var payload CreateRequestPayload + err := req.DecodePayload(&payload) if err != nil { return nil, err @@ -55,7 +59,14 @@ func (h *CreateHandler) HandleItem(ctx context.Context, req *Request) (*Response return nil, err } - req.IDPlaceholder = respPayload.TemplateAttribute.GetTag(kmip14.TagUniqueIdentifier).AttributeValue.(string) + var ok bool + + idAttr := respPayload.TemplateAttribute.GetTag(kmip14.TagUniqueIdentifier) + + req.IDPlaceholder, ok = idAttr.AttributeValue.(string) + if !ok { + return nil, merry.Errorf("invalid response returned by CreateHandler: unique identifier tag in attributes should have been a string, was %t", idAttr.AttributeValue) + } return &ResponseBatchItem{ ResponsePayload: respPayload, diff --git a/op_destroy.go b/op_destroy.go index e09d90d..ad9ca55 100755 --- a/op_destroy.go +++ b/op_destroy.go @@ -2,18 +2,17 @@ package kmip import ( "context" - //"github.com/gemalto/kmip-go/kmip14" ) // DestroyRequestPayload //////////////////////////////////////// // type DestroyRequestPayload struct { - UniqueIdentifier string + UniqueIdentifier string } -// DestroyResponsePayload +// DestroyResponsePayload type DestroyResponsePayload struct { - UniqueIdentifier string + UniqueIdentifier string } type DestroyHandler struct { @@ -22,6 +21,7 @@ type DestroyHandler struct { func (h *DestroyHandler) HandleItem(ctx context.Context, req *Request) (*ResponseBatchItem, error) { var payload DestroyRequestPayload + err := req.DecodePayload(&payload) if err != nil { return nil, err @@ -32,7 +32,7 @@ func (h *DestroyHandler) HandleItem(ctx context.Context, req *Request) (*Respons return nil, err } - //req.Key = respPayload.Key + // req.Key = respPayload.Key return &ResponseBatchItem{ ResponsePayload: respPayload, diff --git a/op_discover_versions.go b/op_discover_versions.go index 1809440..f95050b 100644 --- a/op_discover_versions.go +++ b/op_discover_versions.go @@ -20,6 +20,7 @@ type DiscoverVersionsHandler struct { func (h *DiscoverVersionsHandler) HandleItem(ctx context.Context, req *Request) (item *ResponseBatchItem, err error) { var payload DiscoverVersionsRequestPayload + err = req.DecodePayload(&payload) if err != nil { return nil, err @@ -39,6 +40,7 @@ func (h *DiscoverVersionsHandler) HandleItem(ctx context.Context, req *Request) } } } + return &ResponseBatchItem{ ResponsePayload: respPayload, }, nil diff --git a/op_get.go b/op_get.go index d4145ea..8a981b4 100755 --- a/op_get.go +++ b/op_get.go @@ -2,20 +2,21 @@ package kmip import ( "context" + "github.com/gemalto/kmip-go/kmip14" ) // GetRequestPayload //////////////////////////////////////// // type GetRequestPayload struct { - UniqueIdentifier string + UniqueIdentifier string } -// GetResponsePayload +// GetResponsePayload type GetResponsePayload struct { - ObjectType kmip14.ObjectType - UniqueIdentifier string - Key string + ObjectType kmip14.ObjectType + UniqueIdentifier string + Key string } type GetHandler struct { @@ -24,17 +25,18 @@ type GetHandler struct { func (h *GetHandler) HandleItem(ctx context.Context, req *Request) (*ResponseBatchItem, error) { var payload GetRequestPayload + err := req.DecodePayload(&payload) if err != nil { return nil, err } - respPayload, err := h.Get(ctx, &payload) + respPayload, err := h.Get(ctx, &payload) if err != nil { return nil, err } - //req.Key = respPayload.Key + // req.Key = respPayload.Key return &ResponseBatchItem{ ResponsePayload: respPayload, diff --git a/op_register.go b/op_register.go index e93c90e..1d3a95d 100644 --- a/op_register.go +++ b/op_register.go @@ -2,6 +2,7 @@ package kmip import ( "context" + "github.com/ansel1/merry" "github.com/gemalto/kmip-go/kmip14" ) @@ -37,6 +38,7 @@ type RegisterHandler struct { func (h *RegisterHandler) HandleItem(ctx context.Context, req *Request) (item *ResponseBatchItem, err error) { var payload RegisterRequestPayload + err = req.DecodePayload(&payload) if err != nil { return nil, merry.Prepend(err, "decoding request") @@ -44,6 +46,7 @@ func (h *RegisterHandler) HandleItem(ctx context.Context, req *Request) (item *R if !h.SkipValidation { var payloadPresent bool + switch payload.ObjectType { default: return nil, WithResultReason(merry.UserError("Object Type is not recognized"), kmip14.ResultReasonInvalidField) @@ -64,6 +67,7 @@ func (h *RegisterHandler) HandleItem(ctx context.Context, req *Request) (item *R case kmip14.ObjectTypeOpaqueObject: payloadPresent = payload.OpaqueObject != nil } + if !payloadPresent { return nil, WithResultReason(merry.UserErrorf("Object Type %s does not match type of cryptographic object provided", payload.ObjectType.String()), kmip14.ResultReasonInvalidField) } diff --git a/requests.go b/requests.go index a4846fc..752cd34 100644 --- a/requests.go +++ b/requests.go @@ -17,17 +17,18 @@ import ( "crypto/tls" "errors" "fmt" - "github.com/ansel1/merry" - "github.com/gemalto/flume" - "github.com/gemalto/kmip-go/kmip14" - "github.com/gemalto/kmip-go/ttlv" - "github.com/google/uuid" "io" "net" "runtime" "sync" "sync/atomic" "time" + + "github.com/ansel1/merry" + "github.com/gemalto/flume" + "github.com/gemalto/kmip-go/kmip14" + "github.com/gemalto/kmip-go/ttlv" + "github.com/google/uuid" ) var serverLog = flume.New("kmip_server") @@ -83,7 +84,7 @@ func (srv *Server) Serve(l net.Listener) error { var tempDelay time.Duration // how long to sleep on accept failure baseCtx := context.Background() // base is always background, per Issue 16220 ctx := baseCtx - //ctx := context.WithValue(baseCtx, ServerContextKey, srv) + // ctx := context.WithValue(baseCtx, ServerContextKey, srv) for { rw, e := l.Accept() if e != nil { @@ -99,7 +100,7 @@ func (srv *Server) Serve(l net.Listener) error { if max := 1 * time.Second; tempDelay > max { tempDelay = max } - //srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay) + // srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } @@ -107,7 +108,7 @@ func (srv *Server) Serve(l net.Listener) error { } tempDelay = 0 c := &conn{server: srv, rwc: rw} - //c.setState(c.rwc, StateNew) // before Serve can return + // c.setState(c.rwc, StateNew) // before Serve can return go c.serve(ctx) } } @@ -125,7 +126,7 @@ func (srv *Server) Close() error { atomic.StoreInt32(&srv.inShutdown, 1) srv.mu.Lock() defer srv.mu.Unlock() - //srv.closeDoneChanLocked() + // srv.closeDoneChanLocked() err := srv.closeListenersLocked() //for c := range srv.activeConn { // c.rwc.Close() @@ -253,17 +254,16 @@ func (c *conn) close() { // Serve a new connection. func (c *conn) serve(ctx context.Context) { - ctx = flume.WithLogger(ctx, serverLog) ctx, cancelCtx := context.WithCancel(ctx) c.cancelCtx = cancelCtx c.remoteAddr = c.rwc.RemoteAddr().String() c.localAddr = c.rwc.LocalAddr().String() - //ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr()) + // ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr()) defer func() { if err := recover(); err != nil { // TODO: logging support - //if err := recover(); err != nil && err != ErrAbortHandler { + // if err := recover(); err != nil && err != ErrAbortHandler { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] @@ -273,10 +273,10 @@ func (c *conn) serve(ctx context.Context) { fmt.Printf("kmip: panic serving %v: %v\n%s", c.remoteAddr, err, buf) } - //c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf) + // c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf) } cancelCtx() - //if !c.hijacked() { + // if !c.hijacked() { c.close() // c.setState(c.rwc, StateClosed) //} @@ -292,7 +292,7 @@ func (c *conn) serve(ctx context.Context) { if err := tlsConn.Handshake(); err != nil { // TODO: logging support fmt.Printf("kmip: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err) - //c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err) + // c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err) return } c.tlsState = new(tls.ConnectionState) @@ -309,7 +309,7 @@ func (c *conn) serve(ctx context.Context) { // TODO: do we really need instance pooling here? We expect KMIP connections to be long lasting c.dec = ttlv.NewDecoder(c.rwc) c.bufr = bufio.NewReader(c.rwc) - //c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) + // c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) for { w, err := c.readRequest(ctx) @@ -363,7 +363,7 @@ func (c *conn) serve(ctx context.Context) { // return //} - //c.curReq.Store(w) + // c.curReq.Store(w) //if requestBodyRemains(req.Body) { // registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead) @@ -384,11 +384,11 @@ func (c *conn) serve(ctx context.Context) { h = DefaultProtocolHandler } - //var resp ResponseMessage - //err = c.server.MessageHandler.Handle(ctx, w, &resp) + // var resp ResponseMessage + // err = c.server.MessageHandler.Handle(ctx, w, &resp) // TODO: this cancelCtx() was created at the connection level, not the request level. Need to // figure out how to handle connection vs request timeouts and cancels. - //cancelCtx() + // cancelCtx() // TODO: use recycled buffered writer writer := bufio.NewWriter(c.rwc) @@ -480,7 +480,7 @@ func (c *conn) readRequest(ctx context.Context) (w *Request, err error) { TLS: c.tlsState, } - //c.r.setInfiniteReadLimit() + // c.r.setInfiniteReadLimit() // Adjust the read deadline if necessary. //if !hdrDeadline.Equal(wholeReqDeadline) { @@ -760,11 +760,9 @@ func (h *StandardProtocolHandler) handleRequest(ctx context.Context, req *Reques } return - } func (h *StandardProtocolHandler) ServeKMIP(ctx context.Context, req *Request, writer ResponseWriter) { - // we precreate the response object and pass it down to handlers, because due // the guidance in the spec on the Maximum Response Size, it will be necessary // for handlers to recalculate the response size after each batch item, which @@ -848,7 +846,6 @@ func newFailedResponseBatchItem(reason kmip14.ResultReason, msg string) *Respons } func (m *OperationMux) bi(ctx context.Context, req *Request, reqItem *RequestBatchItem) *ResponseBatchItem { - req.CurrentItem = reqItem h := m.handlerForOp(reqItem.Operation) if h == nil { diff --git a/ttlv/decoder.go b/ttlv/decoder.go index bef2ae3..b497c5a 100644 --- a/ttlv/decoder.go +++ b/ttlv/decoder.go @@ -4,9 +4,10 @@ import ( "bufio" "bytes" "errors" - "github.com/ansel1/merry" "io" "reflect" + + "github.com/ansel1/merry" ) var ErrUnexpectedValue = errors.New("no field was found to unmarshal value into") @@ -179,6 +180,7 @@ func (dec *Decoder) Decode(v interface{}) error { if err != nil { return err } + return dec.DecodeValue(v, ttlv) } @@ -190,6 +192,7 @@ func (dec *Decoder) DecodeValue(v interface{}, ttlv TTLV) error { if val.Kind() != reflect.Ptr { return merry.New("non-pointer passed to Decode") } + return dec.unmarshal(val, ttlv) } @@ -211,17 +214,18 @@ func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error { if val.IsNil() { val.Set(reflect.New(val.Type().Elem())) } + val = val.Elem() } if val.Type().Implements(unmarshalerType) { - return val.Interface().(Unmarshaler).UnmarshalTTLV(dec, ttlv) + return val.Interface().(Unmarshaler).UnmarshalTTLV(dec, ttlv) //nolint:forcetypeassert } if val.CanAddr() { valAddr := val.Addr() if valAddr.CanInterface() && valAddr.Type().Implements(unmarshalerType) { - return valAddr.Interface().(Unmarshaler).UnmarshalTTLV(dec, ttlv) + return valAddr.Interface().(Unmarshaler).UnmarshalTTLV(dec, ttlv) //nolint:forcetypeassert } } @@ -235,6 +239,7 @@ func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error { // set blank interface equal to the TTLV.Value() val.Set(reflect.ValueOf(ttlv.Value())) } + return nil case reflect.Slice: typ := val.Type() @@ -253,7 +258,9 @@ func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error { val.SetLen(n) return err } + return nil + default: } typeMismatchErr := func() error { @@ -265,6 +272,7 @@ func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error { Val: val.Type(), } err := merry.WrapSkipping(e, 1).WithCause(ErrUnsupportedTypeError) + return err } @@ -278,31 +286,37 @@ func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error { err := dec.unmarshalStructure(ttlv, val) // restore currStruct dec.currStruct = currStruct + return err case TypeInterval: if val.Kind() != reflect.Int64 { return typeMismatchErr() } + val.SetInt(int64(ttlv.ValueInterval())) case TypeDateTime, TypeDateTimeExtended: if val.Type() != timeType { return typeMismatchErr() } + val.Set(reflect.ValueOf(ttlv.ValueDateTime())) case TypeByteString: if val.Kind() != reflect.Slice && val.Type().Elem() != byteType { return typeMismatchErr() } + val.SetBytes(ttlv.ValueByteString()) case TypeTextString: if val.Kind() != reflect.String { return typeMismatchErr() } + val.SetString(ttlv.ValueTextString()) case TypeBoolean: if val.Kind() != reflect.Bool { return typeMismatchErr() } + val.SetBool(ttlv.ValueBoolean()) // nolint:dupl case TypeEnumeration: @@ -312,12 +326,14 @@ func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error { if val.OverflowInt(i) { return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow) } + val.SetInt(i) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: i := uint64(ttlv.ValueEnumeration()) if val.OverflowUint(i) { return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow) } + val.SetUint(i) default: return typeMismatchErr() @@ -330,12 +346,14 @@ func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error { if val.OverflowInt(i) { return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow) } + val.SetInt(i) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: i := uint64(ttlv.ValueInteger()) if val.OverflowUint(i) { return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow) } + val.SetUint(i) default: return typeMismatchErr() @@ -353,16 +371,16 @@ func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error { if val.Type() != bigIntType { return typeMismatchErr() } + val.Set(reflect.ValueOf(*ttlv.ValueBigInteger())) default: return dec.newUnmarshalerError(ttlv, val.Type(), ErrInvalidType) } - return nil + return nil } func (dec *Decoder) unmarshalStructure(ttlv TTLV, val reflect.Value) error { - ti, err := getTypeInfo(val.Type()) if err != nil { return dec.newUnmarshalerError(ttlv, val.Type(), err) @@ -376,8 +394,10 @@ func (dec *Decoder) unmarshalStructure(ttlv TTLV, val reflect.Value) error { // push currStruct (caller will pop) dec.currStruct = val.Type() + for n := ttlv.ValueStructure(); n != nil; n = n.Next() { fldIdx := -1 + for i := range fields { if fields[i].flags.any() { // if this is the first any field found, keep track @@ -401,6 +421,7 @@ func (dec *Decoder) unmarshalStructure(ttlv TTLV, val reflect.Value) error { err := dec.unmarshal(val.FieldByIndex(fields[fldIdx].index), n) // restore currField dec.currField = currField + if err != nil { return err } @@ -408,6 +429,7 @@ func (dec *Decoder) unmarshalStructure(ttlv TTLV, val reflect.Value) error { return dec.newUnmarshalerError(ttlv, val.Type(), ErrUnexpectedValue) } } + return nil } @@ -429,6 +451,7 @@ func (dec *Decoder) NextTTLV() (TTLV, error) { buf := make([]byte, fullLen) var totRead int + for { n, err := dec.bufr.Read(buf[totRead:]) if err != nil { @@ -438,9 +461,8 @@ func (dec *Decoder) NextTTLV() (TTLV, error) { totRead += n if totRead >= fullLen { // we've read off a single full message - return TTLV(buf), nil - } - // keep reading + return buf, nil + } // else keep reading } } @@ -452,6 +474,7 @@ func (dec *Decoder) newUnmarshalerError(ttlv TTLV, valType reflect.Type, cause e Type: ttlv.Type(), Val: valType, } + return merry.WrapSkipping(e, 1).WithCause(cause) } @@ -471,5 +494,6 @@ func (e *UnmarshalerError) Error() string { if e.Struct != nil { msg += " in struct field " + e.Struct.Name() + "." + e.Field } + return msg } diff --git a/ttlv/decoder_test.go b/ttlv/decoder_test.go index 03860e4..a1f312c 100644 --- a/ttlv/decoder_test.go +++ b/ttlv/decoder_test.go @@ -4,16 +4,17 @@ import ( "bytes" "errors" "fmt" - "github.com/ansel1/merry" - . "github.com/gemalto/kmip-go/kmip14" - . "github.com/gemalto/kmip-go/ttlv" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "math" "math/big" "reflect" "testing" "time" + + "github.com/ansel1/merry" + . "github.com/gemalto/kmip-go/kmip14" + . "github.com/gemalto/kmip-go/ttlv" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestUnmarshal_known(t *testing.T) { @@ -39,14 +40,11 @@ func TestUnmarshal_known(t *testing.T) { default: require.Equal(t, sample.v, reflect.ValueOf(v).Elem().Interface()) } - }) - } } func TestUnmarshal(t *testing.T) { - type unmarshalTest struct { name string in, ptr, expected interface{} @@ -197,6 +195,7 @@ func TestUnmarshal(t *testing.T) { type A struct { Comment string } + tests = append(tests, unmarshalTest{ name: "simplestruct", @@ -323,7 +322,6 @@ func TestUnmarshal(t *testing.T) { test.name = fmt.Sprintf("%T into %T", test.in, test.ptr) } t.Run(test.name, func(t *testing.T) { - b, err := Marshal(Value{Tag: TagBatchCount, Value: test.in}) require.NoError(t, err) @@ -379,9 +377,7 @@ func TestUnmarshal(t *testing.T) { assert.Equal(t, v.Elem().Interface(), vv.Elem().Interface()) }) }) - } - } func TestUnmarshal_tagfield(t *testing.T) { @@ -403,7 +399,6 @@ func TestUnmarshal_tagfield(t *testing.T) { require.NoError(t, err) assert.Equal(t, M{TagComment, "red"}, m) - } func TestUnmarshal_tagPrecedence(t *testing.T) { @@ -582,7 +577,6 @@ func TestDecoder_DisallowUnknownFields(t *testing.T) { err = dec.Decode(&a) require.Error(t, err) require.True(t, merry.Is(err, ErrUnexpectedValue)) - }) } } diff --git a/ttlv/encoder.go b/ttlv/encoder.go index ac8c937..618029c 100644 --- a/ttlv/encoder.go +++ b/ttlv/encoder.go @@ -5,22 +5,25 @@ import ( "encoding/binary" "errors" "fmt" - "github.com/ansel1/merry" "io" "math" "math/big" "reflect" "strings" "time" + + "github.com/ansel1/merry" ) const structFieldTag = "ttlv" -var ErrIntOverflow = fmt.Errorf("value exceeds max int value %d", math.MaxInt32) -var ErrUnsupportedEnumTypeError = errors.New("unsupported type for enums, must be string, or int types") -var ErrUnsupportedTypeError = errors.New("marshaling/unmarshaling is not supported for this type") -var ErrNoTag = errors.New("unable to determine tag for field") -var ErrTagConflict = errors.New("tag conflict") +var ( + ErrIntOverflow = fmt.Errorf("value exceeds max int value %d", math.MaxInt32) + ErrUnsupportedEnumTypeError = errors.New("unsupported type for enums, must be string, or int types") + ErrUnsupportedTypeError = errors.New("marshaling/unmarshaling is not supported for this type") + ErrNoTag = errors.New("unable to determine tag for field") + ErrTagConflict = errors.New("tag conflict") +) // Marshal encodes a golang value into a KMIP value. // @@ -88,13 +91,15 @@ var ErrTagConflict = errors.New("tag conflict") // 17. structs marshal to Structure. Each field of the struct will be marshaled into the // values of the Structure according to the above rules. // -// Any other golang type will return *MarshalerError with cause ErrUnsupportedTypeError +// Any other golang type will return *MarshalerError with cause ErrUnsupportedTypeError. func Marshal(v interface{}) (TTLV, error) { buf := bytes.NewBuffer(nil) + err := NewEncoder(buf).Encode(v) if err != nil { return nil, err } + return buf.Bytes(), nil } @@ -127,6 +132,7 @@ func (e *Encoder) EncodeValue(tag Tag, v interface{}) error { if err != nil { return err } + return e.Flush() } @@ -139,6 +145,7 @@ func (e *Encoder) EncodeStructure(tag Tag, f func(e *Encoder) error) error { err := f(e) e.encBuf.end(i) e.encodeDepth-- + return err } @@ -190,8 +197,10 @@ func (e *Encoder) Flush() error { if e.encodeDepth > 0 { return nil } + _, err := e.encBuf.WriteTo(e.w) e.encBuf.Reset() + return err } @@ -210,9 +219,11 @@ func (e *MarshalerError) Error() string { if e.Type != nil { msg += " of type " + e.Type.String() } + if e.Struct != "" { msg += " in struct field " + e.Struct + "." + e.Field } + return msg } @@ -223,42 +234,51 @@ func (e *Encoder) marshalingError(tag Tag, t reflect.Type, cause error) merry.Er Field: e.currField, Tag: tag, } + return merry.WrapSkipping(err, 1).WithCause(cause) } -var byteType = reflect.TypeOf(byte(0)) -var marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() -var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() -var timeType = reflect.TypeOf((*time.Time)(nil)).Elem() -var bigIntPtrType = reflect.TypeOf((*big.Int)(nil)) -var bigIntType = bigIntPtrType.Elem() -var durationType = reflect.TypeOf(time.Nanosecond) -var ttlvType = reflect.TypeOf((*TTLV)(nil)).Elem() -var tagType = reflect.TypeOf(Tag(0)) +var ( + byteType = reflect.TypeOf(byte(0)) + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() + timeType = reflect.TypeOf((*time.Time)(nil)).Elem() + bigIntPtrType = reflect.TypeOf((*big.Int)(nil)) + bigIntType = bigIntPtrType.Elem() + durationType = reflect.TypeOf(time.Nanosecond) + ttlvType = reflect.TypeOf((*TTLV)(nil)).Elem() + tagType = reflect.TypeOf(Tag(0)) +) var invalidValue = reflect.Value{} // indirect dives into interfaces values, and one level deep into pointers -// returns an invalid value if the resolved value is nil or invalid +// returns an invalid value if the resolved value is nil or invalid. func indirect(v reflect.Value) reflect.Value { if !v.IsValid() { return v } + if v.Kind() == reflect.Interface { v = v.Elem() } + if !v.IsValid() { return v } + if v.Kind() == reflect.Ptr { v = v.Elem() } + switch v.Kind() { case reflect.Func, reflect.Slice, reflect.Map, reflect.Chan, reflect.Ptr, reflect.Interface: if v.IsNil() { return invalidValue } + default: } + return v } @@ -278,20 +298,21 @@ func isEmptyValue(v reflect.Value) bool { return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() + default: } switch v.Type() { case timeType: - return v.Interface().(time.Time).IsZero() + return v.Interface().(time.Time).IsZero() //nolint:forcetypeassert case bigIntType: - i := v.Interface().(big.Int) + i := v.Interface().(big.Int) //nolint:forcetypeassert return zeroBigInt.Cmp(&i) == 0 } + return false } func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { - // if pointer or interface v = indirect(v) if !v.IsValid() { @@ -310,6 +331,7 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { if err != nil { return err } + if tag == TagNone { tag = tagForMarshal(v, typeInfo, fi) } @@ -325,15 +347,18 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { if flags.omitEmpty() && isEmptyValue(v) { return nil } - return v.Interface().(Marshaler).MarshalTTLV(e, tag) + + return v.Interface().(Marshaler).MarshalTTLV(e, tag) //nolint:forcetypeassert case v.CanAddr(): pv := v.Addr() + pvtyp := pv.Type() if pvtyp.Implements(marshalerType) { if flags.omitEmpty() && isEmptyValue(v) { return nil } - return pv.Interface().(Marshaler).MarshalTTLV(e, tag) + + return pv.Interface().(Marshaler).MarshalTTLV(e, tag) //nolint:forcetypeassert } } @@ -345,6 +370,7 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { reflect.Complex128, reflect.Interface: return e.marshalingError(tag, v.Type(), ErrUnsupportedTypeError) + default: } // skip if value is empty and tags include omitempty @@ -359,6 +385,7 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { // special case, encode as a ByteString, handled below break } + fallthrough case reflect.Array: for i := 0; i < v.Len(); i++ { @@ -372,12 +399,15 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { *fi2 = *fi fi2.flags &^= fOmitEmpty } + err := e.encode(tag, v.Index(i), fi2) if err != nil { return err } } + return nil + default: } if tag == TagNone { @@ -396,22 +426,27 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { switch typ.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: i := v.Int() + if flags.bitmask() || (enumMap != nil && enumMap.Bitmask()) { e.encBuf.encodeInt(tag, int32(i)) } else { e.encBuf.encodeEnum(tag, uint32(i)) } + return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: i := v.Uint() + if flags.bitmask() || (enumMap != nil && enumMap.Bitmask()) { e.encBuf.encodeInt(tag, int32(i)) } else { e.encBuf.encodeEnum(tag, uint32(i)) } + return nil case reflect.String: s := v.String() + if flags.bitmask() || (enumMap != nil && enumMap.Bitmask()) { i, err := ParseInt(s, enumMap) if err == nil { @@ -424,7 +459,6 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { // if we couldn't parse the string as an enum value return e.marshalingError(tag, typ, err) } - } else { i, err := ParseEnum(s, enumMap) if err == nil { @@ -437,7 +471,6 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { // if we couldn't parse the string as an enum value return e.marshalingError(tag, typ, err) } - } default: if flags.enum() || flags.bitmask() { @@ -450,17 +483,19 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { switch typ { case timeType: if flags.dateTimeExt() { - e.encBuf.encodeDateTimeExtended(tag, v.Interface().(time.Time)) + e.encBuf.encodeDateTimeExtended(tag, v.Interface().(time.Time)) //nolint:forcetypeassert } else { - e.encBuf.encodeDateTime(tag, v.Interface().(time.Time)) + e.encBuf.encodeDateTime(tag, v.Interface().(time.Time)) //nolint:forcetypeassert } + return nil case bigIntType: - bi := v.Interface().(big.Int) + bi := v.Interface().(big.Int) //nolint:forcetypeassert e.encBuf.encodeBigInt(tag, &bi) + return nil case bigIntPtrType: - e.encBuf.encodeBigInt(tag, v.Interface().(*big.Int)) + e.encBuf.encodeBigInt(tag, v.Interface().(*big.Int)) //nolint:forcetypeassert return nil case durationType: e.encBuf.encodeInterval(tag, time.Duration(v.Int())) @@ -520,10 +555,12 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { return err } } + return nil }) // pop current struct e.currStruct = currStruct + return err case reflect.String: e.encBuf.encodeTextString(tag, v.String()) @@ -537,20 +574,24 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { if i > math.MaxInt32 { return e.marshalingError(tag, typ, ErrIntOverflow) } + e.encBuf.encodeInt(tag, int32(i)) + return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: u := v.Uint() if u > math.MaxInt32 { return e.marshalingError(tag, typ, ErrIntOverflow) } + e.encBuf.encodeInt(tag, int32(u)) + return nil case reflect.Uint64: u := v.Uint() e.encBuf.encodeLongInt(tag, int64(u)) - return nil + return nil case reflect.Int64: e.encBuf.encodeLongInt(tag, v.Int()) return nil @@ -560,6 +601,7 @@ func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error { // all kinds should have been handled by now panic(errors.New("should never get here")) } + return nil } @@ -571,7 +613,7 @@ func tagForMarshal(v reflect.Value, ti typeInfo, fi *fieldInfo) Tag { // the value of the TTLVTag field of type Tag if v.IsValid() && ti.tagField != nil && ti.tagField.ti.typ == tagType { - tag := v.FieldByIndex(ti.tagField.index).Interface().(Tag) + tag := v.FieldByIndex(ti.tagField.index).Interface().(Tag) //nolint:forcetypeassert if tag != TagNone { return tag } @@ -582,10 +624,11 @@ func tagForMarshal(v reflect.Value, ti typeInfo, fi *fieldInfo) Tag { if fi != nil { return fi.tag } + return ti.inferredTag } -// encBuf encodes basic KMIP types into TTLV +// encBuf encodes basic KMIP types into TTLV. type encBuf struct { bytes.Buffer } @@ -596,6 +639,7 @@ func (h *encBuf) begin(tag Tag, typ Type) int { _ = h.WriteByte(byte(tag)) _ = h.WriteByte(byte(typ)) _, _ = h.Write(zeros[:4]) + return h.Len() } @@ -604,6 +648,7 @@ func (h *encBuf) end(i int) { if m := n % 8; m > 0 { _, _ = h.Write(zeros[:8-m]) } + binary.BigEndian.PutUint32(h.Bytes()[i-4:], uint32(n)) } @@ -623,8 +668,10 @@ func (h *encBuf) writeIntVal(tag Tag, typ Type, val uint32) { h.end(s) } -var ones = [8]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} -var zeros = [8]byte{} +var ( + ones = [8]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} + zeros = [8]byte{} +) func (h *encBuf) encodeBigInt(tag Tag, i *big.Int) { if i == nil { @@ -649,6 +696,7 @@ func (h *encBuf) encodeBigInt(tag Tag, i *big.Int) { if m := l % 8; m > 0 { _, _ = h.Write(zeros[:8-m]) } + _, _ = h.Write(b) case -1: length := uint(i.BitLen()/8+1) * 8 @@ -660,13 +708,16 @@ func (h *encBuf) encodeBigInt(tag Tag, i *big.Int) { if len(b) >= 2 && b[0] == 0xff && b[1]&0x80 != 0 { b = b[1:] } + l := len(b) // pad front with ones to multiple of 8 if m := l % 8; m > 0 { _, _ = h.Write(ones[:8-m]) } + _, _ = h.Write(b) } + h.end(ii) } @@ -721,6 +772,7 @@ func (h *encBuf) encodeByteString(tag Tag, b []byte) { if b == nil { return } + i := h.begin(tag, TypeByteString) _, _ = h.Write(b) h.end(i) @@ -730,13 +782,13 @@ func getTypeInfo(typ reflect.Type) (ti typeInfo, err error) { ti.inferredTag, _ = DefaultRegistry.ParseTag(typ.Name()) ti.typ = typ err = ti.getFieldsInfo() + return ti, err } var errSkip = errors.New("skip") func getFieldInfo(typ reflect.Type, sf reflect.StructField) (fieldInfo, error) { - var fi fieldInfo // skip anonymous and unexported fields @@ -761,6 +813,7 @@ func getFieldInfo(typ reflect.Type, sf reflect.StructField) (fieldInfo, error) { case "": default: var err error + fi.explicitTag, err = DefaultRegistry.ParseTag(value) if err != nil { return fi, err @@ -791,6 +844,7 @@ func getFieldInfo(typ reflect.Type, sf reflect.StructField) (fieldInfo, error) { // for this field is derived from either the field name, // the field tags, or the field type. var err error + fi.ti, err = getTypeInfo(sf.Type) if err != nil { return fi, err @@ -811,22 +865,24 @@ func getFieldInfo(typ reflect.Type, sf reflect.StructField) (fieldInfo, error) { if fi.tag == TagNone { fi.tag = fi.explicitTag } + if fi.tag == TagNone { fi.tag, _ = DefaultRegistry.ParseTag(fi.name) } + return fi, nil } func (ti *typeInfo) getFieldsInfo() error { - if ti.typ.Kind() != reflect.Struct { return nil } for i := 0; i < ti.typ.NumField(); i++ { fi, err := getFieldInfo(ti.typ, ti.typ.Field(i)) + switch { - case err == errSkip: + case err == errSkip: //nolint:errorlint // skip case err != nil: return err @@ -839,16 +895,19 @@ func (ti *typeInfo) getFieldsInfo() error { // verify that multiple fields don't have the same tag names := map[Tag]string{} + for _, f := range ti.valueFields { if f.flags.any() { // ignore any fields continue } + tag := f.tag if tag != TagNone { if fname, ok := names[tag]; ok { return merry.Here(ErrTagConflict).Appendf("field resolves to the same tag (%s) as other field (%s)", tag, fname) } + names[tag] = f.name } } diff --git a/ttlv/encoder_test.go b/ttlv/encoder_test.go index 21f0349..b324c51 100644 --- a/ttlv/encoder_test.go +++ b/ttlv/encoder_test.go @@ -5,10 +5,6 @@ import ( "encoding/hex" "errors" "fmt" - . "github.com/gemalto/kmip-go/kmip14" - . "github.com/gemalto/kmip-go/ttlv" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "io" "io/ioutil" "math" @@ -16,12 +12,17 @@ import ( "reflect" "testing" "time" + + . "github.com/gemalto/kmip-go/kmip14" + . "github.com/gemalto/kmip-go/ttlv" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func parseBigInt(s string) *big.Int { i := &big.Int{} - _, ok := i.SetString(s, 10) - if !ok { + + if _, ok := i.SetString(s, 10); !ok { panic(fmt.Errorf("can't parse as big int: %v", s)) } return i @@ -205,10 +206,8 @@ func (MarshalerStruct) MarshalTTLV(e *Encoder, _ Tag) error { return e.EncodeStructure(TagMaskGenerator, func(e *Encoder) error { return e.EncodeValue(TagBatchCount, 3) }) - }) }) - } type MarshalerFunc func(e *Encoder, tag Tag) error @@ -262,7 +261,6 @@ func TestMarshal_tagPrecedence(t *testing.T) { // for values not originating in a field, infer tag from the type name type Name struct { - // for fields: // infer from field name @@ -462,7 +460,6 @@ func (*MarshalableSlicePtr) MarshalTTLV(e *Encoder, tag Tag) error { } func TestEncoder_EncodeValue(t *testing.T) { - type AttributeValue string type Attribute struct { AttributeValue string @@ -786,9 +783,10 @@ func TestEncoder_EncodeValue(t *testing.T) { v: struct { AttributeValue string }{"red"}, - expected: Value{Tag: TagCancellationResult, Value: Values{ - Value{Tag: TagAttributeValue, Value: "red"}, - }, + expected: Value{ + Tag: TagCancellationResult, Value: Values{ + Value{Tag: TagAttributeValue, Value: "red"}, + }, }, }, { @@ -796,9 +794,10 @@ func TestEncoder_EncodeValue(t *testing.T) { v: struct { Color string `ttlv:"ArchiveDate"` }{"red"}, - expected: Value{Tag: TagCancellationResult, Value: Values{ - Value{Tag: TagArchiveDate, Value: "red"}, - }, + expected: Value{ + Tag: TagCancellationResult, Value: Values{ + Value{Tag: TagArchiveDate, Value: "red"}, + }, }, }, { @@ -806,9 +805,10 @@ func TestEncoder_EncodeValue(t *testing.T) { v: struct { AttributeValue string `ttlv:"ArchiveDate"` }{"red"}, - expected: Value{Tag: TagCancellationResult, Value: Values{ - Value{Tag: TagArchiveDate, Value: "red"}, - }, + expected: Value{ + Tag: TagCancellationResult, Value: Values{ + Value{Tag: TagArchiveDate, Value: "red"}, + }, }, }, { @@ -816,9 +816,10 @@ func TestEncoder_EncodeValue(t *testing.T) { v: struct { Color AttributeValue `ttlv:"ArchiveDate"` }{"red"}, - expected: Value{Tag: TagCancellationResult, Value: Values{ - Value{Tag: TagArchiveDate, Value: "red"}, - }, + expected: Value{ + Tag: TagCancellationResult, Value: Values{ + Value{Tag: TagArchiveDate, Value: "red"}, + }, }, }, { @@ -826,9 +827,10 @@ func TestEncoder_EncodeValue(t *testing.T) { v: struct { ArchiveDate AttributeValue }{"red"}, - expected: Value{Tag: TagCancellationResult, Value: Values{ - Value{Tag: TagArchiveDate, Value: "red"}, - }, + expected: Value{ + Tag: TagCancellationResult, Value: Values{ + Value{Tag: TagArchiveDate, Value: "red"}, + }, }, }, { @@ -1336,7 +1338,6 @@ func TestEncoder_EncodeValue(t *testing.T) { } for _, tc := range tests { - testName := tc.name if testName == "" { testName = fmt.Sprintf("%T", tc.v) @@ -1364,13 +1365,10 @@ func TestEncoder_EncodeValue(t *testing.T) { require.Equal(t, TTLV(buf2.Bytes()), TTLV(buf.Bytes())) }) - } - } func TestEncoder_EncodeStructure(t *testing.T) { - type testCase struct { name string f func(*Encoder) error @@ -1424,10 +1422,8 @@ func TestEncoder_EncodeStructure(t *testing.T) { require.NoError(t, enc2.EncodeValue(TagNone, tc.expected)) require.Equal(t, TTLV(buf2.Bytes()), TTLV(buf.Bytes())) - }) } - } func TestTaggedValue_UnmarshalTTLV(t *testing.T) { @@ -1454,7 +1450,6 @@ func TestTaggedValue_UnmarshalTTLV(t *testing.T) { require.NoError(t, err) assert.Equal(t, s, tv) - } func TestTaggedValue_MarshalTTLV(t *testing.T) { @@ -1490,7 +1485,7 @@ func TestTaggedValue_MarshalTTLV(t *testing.T) { assert.Equal(t, TypeInteger, ttlv.Type()) assert.Equal(t, int32(5), ttlv.ValueInteger()) - fmt.Println(hex.EncodeToString(buf.Bytes())) + t.Log(hex.EncodeToString(buf.Bytes())) buf.Reset() tv.Tag = TagNone @@ -1518,7 +1513,6 @@ func TestTaggedValue_MarshalTTLV(t *testing.T) { assert.Equal(t, TypeTextString, ttlv2.Type()) assert.Equal(t, TagComment, ttlv2.Tag()) assert.Equal(t, "red", ttlv2.ValueTextString()) - } func parseTime(s string) time.Time { @@ -1613,7 +1607,7 @@ func BenchmarkMarshal_struct(b *testing.B) { v.CancellationResult.CancellationResult = &s4 v.Attribute.Attribute.Attribute = &s5 v.CancellationResult.CancellationResult.CancellationResult = &s6 - //v.CertificateRequest = append(v.CertificateRequest, s7, s8, s9) + // v.CertificateRequest = append(v.CertificateRequest, s7, s8, s9) v.CertificateRequest = append(v.CertificateRequest, &s7, &s8, &s9) _, e := Marshal(v) @@ -1637,7 +1631,6 @@ func BenchmarkEncoder_EncodeByteString(b *testing.B) { for i := 0; i < b.N; i++ { enc.EncodeTextString(TagCertificateIssuer, "al;kjsaflksjdflakjsdfl;aksjdflaksjdflaksjdfl;ksjd") require.NoError(b, enc.Flush()) - } } @@ -1646,6 +1639,5 @@ func BenchmarkEncoder_EncodeInt(b *testing.B) { for i := 0; i < b.N; i++ { enc.EncodeInteger(TagCertificateIssuer, 8) require.NoError(b, enc.Flush()) - } } diff --git a/ttlv/formatting.go b/ttlv/formatting.go index d4bb1c9..69506dc 100644 --- a/ttlv/formatting.go +++ b/ttlv/formatting.go @@ -2,10 +2,11 @@ package ttlv import ( "fmt" - "github.com/ansel1/merry" - "github.com/gemalto/kmip-go/internal/kmiputil" "strconv" "strings" + + "github.com/ansel1/merry" + "github.com/gemalto/kmip-go/internal/kmiputil" ) // FormatType formats a byte as a KMIP Type string, @@ -24,6 +25,7 @@ func FormatType(b byte, enumMap EnumMap) string { return s } } + return fmt.Sprintf("%#02x", b) } @@ -40,6 +42,7 @@ func FormatTag(v uint32, enumMap EnumMap) string { return s } } + return fmt.Sprintf("%#06x", v) } @@ -58,6 +61,7 @@ func FormatTagCanonical(v uint32, enumMap EnumMap) string { return s } } + return fmt.Sprintf("%#06x", v) } @@ -74,6 +78,7 @@ func FormatEnum(v uint32, enumMap EnumMap) string { return s } } + return fmt.Sprintf("%#08x", v) } @@ -89,10 +94,12 @@ func FormatInt(i int32, enumMap EnumMap) string { if enumMap == nil { return fmt.Sprintf("%#08x", i) } + values := enumMap.Values() if len(values) == 0 { return fmt.Sprintf("%#08x", i) } + v := uint32(i) // bitmask @@ -101,27 +108,33 @@ func FormatInt(i int32, enumMap EnumMap) string { // the remaining value as hex. var sb strings.Builder + for _, v1 := range values { if v1&v == v1 { if name, ok := enumMap.Name(v1); ok { if sb.Len() > 0 { sb.WriteString("|") } + sb.WriteString(name) + v ^= v1 } - } + if v == 0 { break } } + if v != 0 { if sb.Len() > 0 { sb.WriteString("|") } + _, _ = fmt.Fprintf(&sb, "%#08x", v) } + return sb.String() } @@ -146,10 +159,12 @@ func ParseEnum(s string, enumMap EnumMap) (uint32, error) { // it was a raw number return uint32(u), nil } + v, err := parseHexOrName(s, 4, enumMap) if err != nil { return 0, merry.Here(err) } + return v, nil } @@ -170,11 +185,13 @@ func ParseInt(s string, enumMap EnumMap) (int32, error) { // it was a raw number return int32(i), nil } + if !strings.ContainsAny(s, "| ") { v, err := parseHexOrName(s, 4, enumMap) if err != nil { return 0, merry.Here(err) } + return int32(v), nil } @@ -182,16 +199,20 @@ func ParseInt(s string, enumMap EnumMap) (int32, error) { s = strings.ReplaceAll(s, "|", " ") parts := strings.Split(s, " ") var v uint32 + for _, part := range parts { if len(part) == 0 { continue } + i, err := parseHexOrName(part, 4, enumMap) if err != nil { return 0, merry.Here(err) } + v |= i } + return int32(v), nil } @@ -200,14 +221,17 @@ func parseHexOrName(s string, max int, enumMap EnumMap) (uint32, error) { if err != nil { return 0, err } + if b != nil { return kmiputil.DecodeUint32(b), nil } + if enumMap != nil { if v, ok := enumMap.Value(s); ok { return v, nil } } + return 0, merry.Append(ErrUnregisteredEnumName, s) } @@ -226,6 +250,7 @@ func ParseTag(s string, enumMap EnumMap) (Tag, error) { if err != nil { return 0, merry.Here(err) } + return Tag(v), nil } @@ -246,14 +271,17 @@ func ParseType(s string, enumMap EnumMap) (Type, error) { if err != nil { return 0, merry.Here(err) } + if b != nil { return Type(b[0]), nil } + if enumMap != nil { if v, ok := enumMap.Value(s); ok { return Type(v), nil } } + return 0, merry.Here(ErrUnregisteredEnumName).Append(s) } diff --git a/ttlv/registry.go b/ttlv/registry.go index df560d8..6b6260e 100644 --- a/ttlv/registry.go +++ b/ttlv/registry.go @@ -1,9 +1,10 @@ package ttlv import ( + "sort" + "github.com/ansel1/merry" "github.com/gemalto/kmip-go/internal/kmiputil" - "sort" ) // DefaultRegistry holds the default mappings of types, tags, enums, and bitmasks @@ -19,8 +20,10 @@ func init() { RegisterTypes(&DefaultRegistry) } -var ErrInvalidHexString = kmiputil.ErrInvalidHexString -var ErrUnregisteredEnumName = merry.New("unregistered enum name") +var ( + ErrInvalidHexString = kmiputil.ErrInvalidHexString + ErrUnregisteredEnumName = merry.New("unregistered enum name") +) // NormalizeName tranforms KMIP names from the spec into the // normalized form of the name. Typically, this means removing spaces, @@ -72,12 +75,14 @@ func NewBitmask() Enum { // in the KMIP spec. func (e *Enum) RegisterValue(v uint32, name string) { nn := NormalizeName(name) + if e.valuesToName == nil { e.valuesToName = map[uint32]string{} e.nameToValue = map[string]uint32{} e.valuesToCanonicalName = map[uint32]string{} e.canonicalNamesToValue = map[string]uint32{} } + e.valuesToName[v] = nn e.nameToValue[nn] = v e.valuesToCanonicalName[v] = name @@ -88,7 +93,9 @@ func (e *Enum) Name(v uint32) (string, bool) { if e == nil { return "", false } + name, ok := e.valuesToName[v] + return name, ok } @@ -96,7 +103,9 @@ func (e *Enum) CanonicalName(v uint32) (string, bool) { if e == nil { return "", false } + name, ok := e.valuesToCanonicalName[v] + return name, ok } @@ -104,10 +113,12 @@ func (e *Enum) Value(name string) (uint32, bool) { if e == nil { return 0, false } + v, ok := e.nameToValue[name] if !ok { v, ok = e.canonicalNamesToValue[name] } + return v, ok } @@ -118,6 +129,7 @@ func (e *Enum) Values() []uint32 { } // Always list them in order of value so output is stable. sort.Sort(uint32Slice(values)) + return values } @@ -125,6 +137,7 @@ func (e *Enum) Bitmask() bool { if e == nil { return false } + return e.bitMask } @@ -149,6 +162,7 @@ func (r *Registry) RegisterEnum(t Tag, def EnumMap) { if r.enums == nil { r.enums = map[Tag]EnumMap{} } + r.enums[t] = def } @@ -158,6 +172,7 @@ func (r *Registry) EnumForTag(t Tag) EnumMap { if r.enums == nil { return nil } + return r.enums[t] } @@ -165,6 +180,7 @@ func (r *Registry) IsBitmask(t Tag) bool { if e := r.EnumForTag(t); e != nil { return e.Bitmask() } + return false } @@ -172,6 +188,7 @@ func (r *Registry) IsEnum(t Tag) bool { if e := r.EnumForTag(t); e != nil { return !e.Bitmask() } + return false } @@ -211,8 +228,10 @@ func (r *Registry) ParseInt(t Tag, s string) (int32, error) { return ParseInt(s, r.EnumForTag(t)) } -// returns TagNone if not found. -// returns error if s is a malformed hex string, or a hex string of incorrect length +// ParseTag parses a string into Tag according the rules +// in the KMIP Profiles regarding encoding tag values. +// Returns TagNone if not found. +// Returns error if s is a malformed hex string, or a hex string of incorrect length func (r *Registry) ParseTag(s string) (Tag, error) { return ParseTag(s, &r.tags) } diff --git a/ttlv/registry_test.go b/ttlv/registry_test.go index 5433af7..74ac05f 100644 --- a/ttlv/registry_test.go +++ b/ttlv/registry_test.go @@ -1,11 +1,12 @@ package ttlv_test import ( + "testing" + . "github.com/gemalto/kmip-go/kmip14" . "github.com/gemalto/kmip-go/ttlv" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "testing" ) func TestBitMaskString(t *testing.T) { diff --git a/ttlv/tag.go b/ttlv/tag.go index da81928..cfeadf4 100644 --- a/ttlv/tag.go +++ b/ttlv/tag.go @@ -1,8 +1,10 @@ package ttlv -const TagNone = Tag(0) -const tagAttributeName Tag = 0x42000a -const tagAttributeValue Tag = 0x42000b +const ( + TagNone = Tag(0) + tagAttributeName Tag = 0x42000a + tagAttributeValue Tag = 0x42000b +) // Tag // 9.1.3.1 diff --git a/ttlv/tag_test.go b/ttlv/tag_test.go index 688dd28..5939aa0 100644 --- a/ttlv/tag_test.go +++ b/ttlv/tag_test.go @@ -1,9 +1,10 @@ package ttlv_test import ( + "testing" + "github.com/gemalto/kmip-go/kmip14" "github.com/stretchr/testify/assert" - "testing" ) func TestTag_CanonicalName(t *testing.T) { diff --git a/ttlv/ttlv.go b/ttlv/ttlv.go index c211c5a..4b82125 100644 --- a/ttlv/ttlv.go +++ b/ttlv/ttlv.go @@ -7,13 +7,14 @@ import ( "encoding/xml" "errors" "fmt" - "github.com/ansel1/merry" - "github.com/gemalto/kmip-go/internal/kmiputil" "io" "math/big" "strconv" "strings" "time" + + "github.com/ansel1/merry" + "github.com/gemalto/kmip-go/internal/kmiputil" ) //nolint:deadcode,varcheck @@ -29,11 +30,13 @@ const ( lenHeader = lenTag + 1 + lenLen // tag + type + len ) -var ErrValueTruncated = errors.New("value truncated") -var ErrHeaderTruncated = errors.New("header truncated") -var ErrInvalidLen = errors.New("invalid length") -var ErrInvalidType = errors.New("invalid KMIP type") -var ErrInvalidTag = errors.New("invalid tag") +var ( + ErrValueTruncated = errors.New("value truncated") + ErrHeaderTruncated = errors.New("header truncated") + ErrInvalidLen = errors.New("invalid length") + ErrInvalidType = errors.New("invalid KMIP type") + ErrInvalidTag = errors.New("invalid tag") +) // TTLV is a byte slice that begins with a TTLV encoded block. The methods of TTLV operate on the // TTLV value located at the beginning of the slice. Any bytes in the slice after @@ -53,6 +56,7 @@ func (t TTLV) Tag() Tag { if len(t) < 3 { return Tag(0) } + return Tag(uint32(t[2]) | uint32(t[1])<<8 | uint32(t[0])<<16) } @@ -61,8 +65,9 @@ func (t TTLV) Tag() Tag { func (t TTLV) Type() Type { // don't panic if header is truncated if len(t) < 4 { - return Type(0) + return 0 } + return Type(t[3]) } @@ -80,6 +85,7 @@ func (t TTLV) Len() int { if len(t) < lenHeader { return 0 } + return int(binary.BigEndian.Uint32(t[4:8])) } @@ -99,10 +105,12 @@ func (t TTLV) FullLen() int { if m := l % 8; m > 0 { return l + (8 - m) } + return l case TypeBigInteger, TypeStructure: return t.Len() + lenHeader } + panic(fmt.Sprintf("invalid type: %x", byte(t.Type()))) } @@ -117,9 +125,11 @@ func (t TTLV) ValueRaw() []byte { if l == 0 { return nil } + if len(t) < lenHeader+l { return t[lenHeader:] } + return t[lenHeader : lenHeader+l] } @@ -150,6 +160,7 @@ func (t TTLV) Value() interface{} { case TypeStructure: return t.ValueStructure() } + panic(fmt.Sprintf("invalid type: %x", byte(t.Type()))) } @@ -167,7 +178,9 @@ func (t TTLV) ValueLongInteger() int64 { func (t TTLV) ValueBigInteger() *big.Int { i := new(big.Int) + unmarshalBigInt(i, unpadBigInt(t.ValueRaw())) + return i } @@ -191,17 +204,21 @@ func (t TTLV) ValueByteString() []byte { func (t TTLV) ValueDateTime() time.Time { i := t.ValueLongInteger() + if t.Type() == TypeDateTimeExtended { return time.Unix(0, i*1000).UTC() } + return time.Unix(i, 0).UTC() } func (t TTLV) ValueDateTimeExtended() DateTimeExtended { i := t.ValueLongInteger() + if t.Type() == TypeDateTimeExtended { return DateTimeExtended{Time: time.Unix(0, i*1000).UTC()} } + return DateTimeExtended{Time: time.Unix(i, 0).UTC()} } @@ -232,13 +249,16 @@ func (t TTLV) Valid() error { if t.Type() == TypeStructure { inner := t.ValueStructure() + for { if len(inner) == 0 { break } + if err := inner.Valid(); err != nil { return merry.Prepend(err, t.Tag().String()) } + inner = inner.Next() } } @@ -251,6 +271,7 @@ func (t TTLV) validTag() bool { case 0x42, 0x54: // valid return true } + return false } @@ -287,18 +308,20 @@ func (t TTLV) ValidHeader() error { default: return ErrInvalidType } - return nil + return nil } func (t TTLV) Next() TTLV { if t.Valid() != nil { return nil } + n := t[t.FullLen():] if len(n) == 0 { return nil } + return n } @@ -306,6 +329,7 @@ func (t TTLV) Next() TTLV { func (t TTLV) String() string { var sb strings.Builder _ = Print(&sb, "", " ", t) + return sb.String() } @@ -323,8 +347,7 @@ func (t TTLV) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { Inner []byte `xml:",innerxml"` }{} - tagS := t.Tag().String() - if strings.HasPrefix(tagS, "0x") { + if tagS := t.Tag().String(); strings.HasPrefix(tagS, "0x") { out.XMLName.Local = "TTLV" out.Tag = tagS } else { @@ -341,13 +364,15 @@ func (t TTLV) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { if out.Type != "" { se.Attr = append(se.Attr, xml.Attr{Name: xml.Name{Local: "type"}, Value: out.Type}) } + err := e.EncodeToken(se) if err != nil { return err } - n := t.ValueStructure() var attrTag Tag + + n := t.ValueStructure() for len(n) > 0 { // if the struct contains an attribute name, followed by an // attribute value, use the name to try and map enumeration values @@ -356,15 +381,18 @@ func (t TTLV) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { // try to map the attribute name to a tag attrTag, _ = DefaultRegistry.ParseTag(kmiputil.NormalizeName(n.ValueTextString())) } + if n.Tag() == tagAttributeValue && (n.Type() == TypeEnumeration || n.Type() == TypeInteger) { valAttr := xml.Attr{ Name: xml.Name{Local: "value"}, } + if n.Type() == TypeEnumeration { valAttr.Value = DefaultRegistry.FormatEnum(attrTag, uint32(n.ValueEnumeration())) } else { valAttr.Value = DefaultRegistry.FormatInt(attrTag, n.ValueInteger()) } + err := e.EncodeToken(xml.StartElement{ Name: xml.Name{Local: tagAttributeValue.String()}, Attr: []xml.Attr{ @@ -378,14 +406,17 @@ func (t TTLV) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { if err != nil { return err } + if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "AttributeValue"}}); err != nil { return err } } else if err := e.Encode(n); err != nil { return err } + n = n.Next() } + return e.EncodeToken(xml.EndElement{Name: out.XMLName}) case TypeInteger: @@ -457,6 +488,7 @@ func unmarshalXMLTval(buf *encBuf, tval *xmltval, attrTag Tag) error { if err != nil { return syntaxError(merry.Prepend(err, "must be 0, 1, true, or false")) } + buf.encodeBool(tag, b) case TypeTextString: buf.encodeTextString(tag, tval.Value) @@ -466,22 +498,26 @@ func unmarshalXMLTval(buf *encBuf, tval *xmltval, attrTag Tag) error { if strings.HasPrefix(tval.Value, "0x") { return syntaxError(errors.New("should not have 0x prefix")) } + b, err := hex.DecodeString(tval.Value) if err != nil { return syntaxError(err) } + buf.encodeByteString(tag, b) case TypeInterval: u, err := strconv.ParseUint(tval.Value, 10, 64) if err != nil { return syntaxError(merry.Prepend(err, "must be a number")) } + buf.encodeInterval(tag, time.Duration(u)*time.Second) case TypeDateTime, TypeDateTimeExtended: d, err := time.Parse(time.RFC3339Nano, tval.Value) if err != nil { return syntaxError(merry.Prepend(err, "must be ISO8601 format")) } + if tp == TypeDateTime { buf.encodeDateTime(tag, d) } else { @@ -492,16 +528,19 @@ func unmarshalXMLTval(buf *encBuf, tval *xmltval, attrTag Tag) error { if tag == tagAttributeValue && attrTag != TagNone { enumTag = attrTag } + i, err := DefaultRegistry.ParseInt(enumTag, strings.ReplaceAll(tval.Value, " ", "|")) if err != nil { return syntaxError(err) } + buf.encodeInt(tag, i) case TypeLongInteger: i, err := strconv.ParseInt(tval.Value, 10, 64) if err != nil { return syntaxError(merry.Prepend(err, "must be number")) } + buf.encodeLongInt(tag, i) case TypeBigInteger: // TODO: consider allowing this, just strip off the 0x prefix @@ -509,13 +548,16 @@ func unmarshalXMLTval(buf *encBuf, tval *xmltval, attrTag Tag) error { if strings.HasPrefix(tval.Value, "0x") { return syntaxError(merry.New("should not have 0x prefix")) } + b, err := hex.DecodeString(tval.Value) if err != nil { return syntaxError(err) } + if len(b)%8 != 0 { return syntaxError(errors.New("must be multiple of 8 bytes")) } + n := &big.Int{} unmarshalBigInt(n, b) buf.encodeBigInt(tag, n) @@ -524,16 +566,20 @@ func unmarshalXMLTval(buf *encBuf, tval *xmltval, attrTag Tag) error { if tag == tagAttributeValue && attrTag != TagNone { enumTag = attrTag } + e, err := DefaultRegistry.ParseEnum(enumTag, tval.Value) if err != nil { return syntaxError(err) } + buf.encodeEnum(tag, e) case TypeStructure: i := buf.begin(tag, TypeStructure) var attrTag Tag + for _, c := range tval.Children { offset := buf.Len() + err := unmarshalXMLTval(buf, c, attrTag) if err != nil { return err @@ -546,30 +592,37 @@ func unmarshalXMLTval(buf *encBuf, tval *xmltval, attrTag Tag) error { attrTag, _ = DefaultRegistry.ParseTag(kmiputil.NormalizeName(ttlv.ValueTextString())) } } + buf.end(i) } + return nil } func (t *TTLV) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { - var out xmltval + err := d.DecodeElement(&out, &start) if err != nil { return err } var buf encBuf + err = unmarshalXMLTval(&buf, &out, TagNone) if err != nil { return err } + *t = buf.Bytes() + return nil } -var maxJSONInt = int64(1) << 52 -var maxJSONBigInt = big.NewInt(maxJSONInt) +var ( + maxJSONInt = int64(1) << 52 + maxJSONBigInt = big.NewInt(maxJSONInt) +) func (t *TTLV) UnmarshalJSON(b []byte) error { return t.unmarshalJSON(b, TagNone) @@ -585,7 +638,9 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { Type string `json:"type,omitempty"` Value json.RawMessage `json:"value"` } + var ttl tval + err := json.Unmarshal(b, &ttl) if err != nil { return err @@ -598,6 +653,7 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { var tp Type var v interface{} + if ttl.Type == "" { tp = TypeStructure } else { @@ -625,6 +681,7 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { // additional set of paths to test. Wasn't worth it. enc := encBuf{} + switch tp { case TypeBoolean: switch tv := v.(type) { @@ -659,10 +716,12 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { if strings.HasPrefix(tv, "0x") { return syntaxError(errors.New("should not have 0x prefix")) } + b, err := hex.DecodeString(tv) if err != nil { return syntaxError(err) } + enc.encodeByteString(tag, b) } case TypeInterval: @@ -674,9 +733,11 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { if err != nil { return syntaxError(err) } + if b == nil { return syntaxError(errors.New("hex value must start with 0x")) } + enc.encodeInterval(tag, time.Duration(kmiputil.DecodeUint32(b))*time.Second) case float64: enc.encodeInterval(tag, time.Duration(tv)*time.Second) @@ -687,10 +748,12 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { return syntaxError(errors.New("must be string")) case string: var tm time.Time + b, err := kmiputil.ParseHexValue(tv, 8) if err != nil { return syntaxError(err) } + if b != nil { u := kmiputil.DecodeUint64(b) if tp == TypeDateTime { @@ -705,6 +768,7 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { return syntaxError(merry.Prepend(err, "must be ISO8601 format")) } } + if tp == TypeDateTime { enc.encodeDateTime(tag, tm) } else { @@ -720,10 +784,12 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { if tag == tagAttributeValue && attrTag != TagNone { enumTag = attrTag } + i, err := DefaultRegistry.ParseInt(enumTag, tv) if err != nil { return syntaxError(err) } + enc.encodeInt(tag, i) case float64: enc.encodeInt(tag, int32(tv)) @@ -737,9 +803,11 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { if err != nil { return syntaxError(err) } + if b == nil { return syntaxError(errors.New("hex value must start with 0x")) } + enc.encodeLongInt(tag, int64(kmiputil.DecodeUint64(b))) case float64: enc.encodeLongInt(tag, int64(tv)) @@ -752,13 +820,16 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { if !strings.HasPrefix(tv, "0x") { return syntaxError(errors.New("hex value must start with 0x")) } + b, err := hex.DecodeString(tv[2:]) if err != nil { return syntaxError(err) } + if len(b)%8 != 0 { return syntaxError(errors.New("must be multiple of 8 bytes (16 hex characters)")) } + i := &big.Int{} unmarshalBigInt(i, unpadBigInt(b)) enc.encodeBigInt(tag, i) @@ -774,10 +845,12 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { if tag == tagAttributeValue && attrTag != TagNone { enumTag = attrTag } + u, err := DefaultRegistry.ParseEnum(enumTag, tv) if err != nil { return syntaxError(err) } + enc.encodeEnum(tag, u) case float64: enc.encodeEnum(tag, uint32(tv)) @@ -785,26 +858,35 @@ func (t *TTLV) unmarshalJSON(b []byte, attrTag Tag) error { case TypeStructure: // unmarshal each sub value var children []json.RawMessage + err := json.Unmarshal(ttl.Value, &children) if err != nil { return syntaxError(err) } + var scratch TTLV + s := enc.begin(tag, TypeStructure) + var attrTag Tag for _, c := range children { err := (&scratch).unmarshalJSON(c, attrTag) if err != nil { return syntaxError(err) } + if tagAttributeName == scratch.Tag() { attrTag, _ = DefaultRegistry.ParseTag(kmiputil.NormalizeName(scratch.ValueTextString())) } + _, _ = enc.Write(scratch) } + enc.end(s) } + *t = enc.Bytes() + return nil } @@ -812,6 +894,7 @@ func (t TTLV) MarshalJSON() ([]byte, error) { if len(t) == 0 { return []byte("null"), nil } + if err := t.Valid(); err != nil { return nil, err } @@ -820,10 +903,12 @@ func (t TTLV) MarshalJSON() ([]byte, error) { sb.WriteString(`{"tag":"`) sb.WriteString(t.Tag().String()) + if t.Type() != TypeStructure { sb.WriteString(`","type":"`) sb.WriteString(t.Type().String()) } + sb.WriteString(`","value":`) switch t.Type() { @@ -861,6 +946,7 @@ func (t TTLV) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } + sb.Write(val) } else { sb.WriteString(`"0x`) @@ -872,6 +958,7 @@ func (t TTLV) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } + sb.Write(val) case TypeByteString: sb.WriteString(`"`) @@ -879,8 +966,10 @@ func (t TTLV) MarshalJSON() ([]byte, error) { sb.WriteString(`"`) case TypeStructure: sb.WriteString("[") + c := t.ValueStructure() var attrTag Tag + for len(c) > 0 { // if the struct contains an attribute name, followed by an // attribute value, use the name to try and map enumeration values @@ -897,6 +986,7 @@ func (t TTLV) MarshalJSON() ([]byte, error) { sb.WriteString(`"}`) case c.Tag() == tagAttributeValue && c.Type() == TypeInteger: sb.WriteString(`{"tag":"AttributeValue","type":"Integer","value":`) + if enum := DefaultRegistry.EnumForTag(attrTag); enum != nil { sb.WriteString(`"`) sb.WriteString(FormatInt(c.ValueInteger(), enum)) @@ -904,14 +994,17 @@ func (t TTLV) MarshalJSON() ([]byte, error) { } else { sb.WriteString(strconv.Itoa(int(c.ValueInteger()))) } + sb.WriteString(`}`) default: v, err := c.MarshalJSON() if err != nil { return nil, err } + sb.Write(v) } + c = c.Next() if len(c) > 0 { sb.WriteString(",") @@ -923,12 +1016,14 @@ func (t TTLV) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } + sb.Write(val) case TypeInterval: sb.WriteString(strconv.FormatUint(uint64(binary.BigEndian.Uint32(t.ValueRaw())), 10)) } sb.WriteString(`}`) + return []byte(sb.String()), nil } @@ -938,17 +1033,18 @@ func (t TTLV) MarshalJSON() ([]byte, error) { func (t *TTLV) UnmarshalTTLV(_ *Decoder, ttlv TTLV) error { if ttlv == nil { *t = nil + return nil } - l := len(ttlv) - if len(*t) < l { + if l := len(ttlv); len(*t) < l { *t = make([]byte, l) } else { *t = (*t)[:l] } copy(*t, ttlv) + return nil } @@ -960,7 +1056,6 @@ func (t *TTLV) UnmarshalTTLV(_ *Decoder, ttlv TTLV) error { // try and print as much of the value as it can decode, and return // a parsing error. func Print(w io.Writer, prefix, indent string, t TTLV) error { - currIndent := prefix tag := t.Tag() @@ -975,18 +1070,19 @@ func Print(w io.Writer, prefix, indent string, t TTLV) error { if _, err := fmt.Fprintf(w, " (%s)", verr.Error()); err != nil { return err } - switch verr { - case ErrHeaderTruncated: + + if errors.Is(verr, ErrHeaderTruncated) { // print the err, and as much of the truncated header as we have if _, err := fmt.Fprintf(w, " %#x", []byte(t)); err != nil { return err } - default: + } else { // Something is wrong with the value. Print the error, and the value if _, err := fmt.Fprintf(w, " %#x", t.ValueRaw()); err != nil { return err } } + return verr } @@ -997,16 +1093,19 @@ func Print(w io.Writer, prefix, indent string, t TTLV) error { } case TypeStructure: currIndent += indent + s := t.ValueStructure() for s != nil { if _, err := fmt.Fprint(w, "\n"); err != nil { return err } + if err := Print(w, currIndent, indent, s); err != nil { // an error means we've hit invalid bytes in the stream // there are no markers to pick back up again, so we have to give up return err } + s = s.Next() } case TypeEnumeration: @@ -1028,6 +1127,7 @@ func Print(w io.Writer, prefix, indent string, t TTLV) error { return err } } + return nil } @@ -1035,25 +1135,27 @@ func Print(w io.Writer, prefix, indent string, t TTLV) error { // the segments of the TTLV. Like Print, this is safe to call even on invalid TTLV // values. An error will only be returned if there is a problem with the writer. func PrintPrettyHex(w io.Writer, prefix, indent string, t TTLV) error { - currIndent := prefix b := []byte(t) if t.ValidHeader() != nil { // print the entire value as hex, un-indented _, err := fmt.Fprint(w, hex.EncodeToString(t)) + return err } if t.Valid() != nil { // print the header, then dump the rest of the value on the next line _, err := fmt.Fprintf(w, "%s%x | %x | %x\n%x", currIndent, b[0:3], b[3:4], b[4:8], b[8:]) + return err } if t.Type() != TypeStructure { // print the entire value _, err := fmt.Fprintf(w, "%s%x | %x | %x | %x", currIndent, b[0:3], b[3:4], b[4:8], b[lenHeader:t.FullLen()]) + return err } @@ -1064,20 +1166,23 @@ func PrintPrettyHex(w io.Writer, prefix, indent string, t TTLV) error { } currIndent += indent + s := t.ValueStructure() for s != nil { if _, werr := fmt.Fprint(w, "\n"); werr != nil { return werr } + if err := PrintPrettyHex(w, currIndent, indent, s); err != nil { // an error means we've hit invalid bytes in the stream // there are no markers to pick back up again, so we have to give up return err } + s = s.Next() } - return nil + return nil } var one = big.NewInt(1) @@ -1109,6 +1214,7 @@ func unpadBigInt(data []byte) []byte { // is negative. If data is empty, the result will be 0. func unmarshalBigInt(n *big.Int, data []byte) { n.SetBytes(data) + if len(data) > 0 && data[0]&0x80 > 0 { // first byte is 1, so number is negative. // left shifting 1 by the length in bits of the data @@ -1133,8 +1239,10 @@ func Hex2bytes(s string) []byte { default: return -1 // drop } + return r }, s) + b, err := hex.DecodeString(s) if err != nil { panic(err) diff --git a/ttlv/ttlv_test.go b/ttlv/ttlv_test.go index e959fcd..50e0a51 100644 --- a/ttlv/ttlv_test.go +++ b/ttlv/ttlv_test.go @@ -7,15 +7,16 @@ import ( "encoding/json" "encoding/xml" "fmt" - . "github.com/gemalto/kmip-go/kmip14" - . "github.com/gemalto/kmip-go/ttlv" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "math" "math/big" "strconv" "testing" "time" + + . "github.com/gemalto/kmip-go/kmip14" + . "github.com/gemalto/kmip-go/ttlv" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var sample = ` @@ -183,7 +184,6 @@ func TestTTLV(t *testing.T) { for _, tc := range tests { t.Run("", func(t *testing.T) { - b := Hex2bytes(tc.bs) tt := TTLV(b) assert.NoError(t, tt.Valid()) @@ -238,7 +238,6 @@ func TestTTLV(t *testing.T) { default: assert.EqualValues(t, test.v, tt.Value()) } - }) } } @@ -282,7 +281,6 @@ func TestTTLV_UnmarshalTTLV(t *testing.T) { require.NoError(t, err) require.Equal(t, TTLV(buf.Bytes()), ttlv) - } func TestTTLV_UnmarshalJSON_errors(t *testing.T) { @@ -458,7 +456,6 @@ func TestTTLV_UnmarshalJSON_errors(t *testing.T) { err := json.Unmarshal([]byte(testcase.input), &TTLV{}) require.EqualError(t, err, testcase.msg) }) - } } @@ -527,14 +524,14 @@ func TestTTLV_UnmarshalJSON(t *testing.T) { inputs: []string{ `{"tag":"BatchCount","type":"DateTime","value":"2001-01-01T10:00:00+10:00"}`, }, - exp: Value{Tag: TagBatchCount, Value: time.Date(2001, 01, 01, 0, 0, 0, 0, time.FixedZone("UTC", 0))}, + exp: Value{Tag: TagBatchCount, Value: time.Date(2001, 0o1, 0o1, 0, 0, 0, 0, time.FixedZone("UTC", 0))}, }, { name: "datetimehex", inputs: []string{ `{"tag":"BatchCount","type":"DateTime","value":"0x0000000047DA67F8"}`, }, - exp: Value{Tag: TagBatchCount, Value: time.Date(2008, 03, 14, 11, 56, 40, 0, time.FixedZone("UTC", 0))}, + exp: Value{Tag: TagBatchCount, Value: time.Date(2008, 0o3, 14, 11, 56, 40, 0, time.FixedZone("UTC", 0))}, }, { name: "integer", @@ -638,7 +635,6 @@ func TestTTLV_UnmarshalJSON(t *testing.T) { assert.Equal(t, expTTLV, ttlv) } - }) } } @@ -861,7 +857,7 @@ func TestTTLV_MarshalXML(t *testing.T) { }, { name: "datetime", - in: Value{Tag: TagBatchCount, Value: time.Date(2001, 01, 01, 0, 0, 0, 0, time.FixedZone("UTC", 0))}, + in: Value{Tag: TagBatchCount, Value: time.Date(2001, 0o1, 0o1, 0, 0, 0, 0, time.FixedZone("UTC", 0))}, exp: ``, }, { @@ -973,7 +969,7 @@ func TestTTLV_UnmarshalXML(t *testing.T) { inputs: []string{ ``, }, - exp: Value{Tag: TagBatchCount, Value: time.Date(2001, 01, 01, 0, 0, 0, 0, time.FixedZone("UTC", 0))}, + exp: Value{Tag: TagBatchCount, Value: time.Date(2001, 0o1, 0o1, 0, 0, 0, 0, time.FixedZone("UTC", 0))}, }, { name: "integer", @@ -1070,7 +1066,6 @@ func TestTTLV_UnmarshalXML(t *testing.T) { assert.Equal(t, expTTLV, ttlv) } - }) } } @@ -1173,6 +1168,5 @@ func TestTTLV_UnmarshalXML_errors(t *testing.T) { err := xml.Unmarshal([]byte(testcase.input), &TTLV{}) require.EqualError(t, err, testcase.msg) }) - } } diff --git a/ttlv/types.go b/ttlv/types.go index ead72ed..d1ee6e7 100644 --- a/ttlv/types.go +++ b/ttlv/types.go @@ -6,7 +6,7 @@ import ( ) func RegisterTypes(r *Registry) { - var m = map[string]Type{ + m := map[string]Type{ "BigInteger": TypeBigInteger, "Boolean": TypeBoolean, "ByteString": TypeByteString, @@ -78,6 +78,7 @@ func (t *DateTimeExtended) UnmarshalTTLV(d *Decoder, ttlv TTLV) error { if err != nil { return err } + return nil } @@ -111,6 +112,7 @@ type Value struct { // UnmarshalTTLV implements Unmarshaler func (t *Value) UnmarshalTTLV(d *Decoder, ttlv TTLV) error { t.Tag = ttlv.Tag() + switch ttlv.Type() { case TypeStructure: var v Values @@ -121,6 +123,7 @@ func (t *Value) UnmarshalTTLV(d *Decoder, ttlv TTLV) error { if err != nil { return err } + ttlv = ttlv.Next() } @@ -128,6 +131,7 @@ func (t *Value) UnmarshalTTLV(d *Decoder, ttlv TTLV) error { default: t.Value = ttlv.Value() } + return nil } @@ -145,6 +149,7 @@ func (t Value) MarshalTTLV(e *Encoder, tag Tag) error { return err } } + return nil }) } diff --git a/types_messages.go b/types_messages.go index 45ae136..9333066 100644 --- a/types_messages.go +++ b/types_messages.go @@ -1,8 +1,9 @@ package kmip import ( - "github.com/gemalto/kmip-go/kmip14" "time" + + "github.com/gemalto/kmip-go/kmip14" ) // 7.1