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