diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 438443f..d284b19 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -47,5 +47,5 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: v1.31 + version: v1.45.2 args: $GOLANGCI_LINT_EXRA_ARGS diff --git a/.golangci.yml b/.golangci.yml index d6162c9..d7a88ec 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -15,14 +15,22 @@ linters-settings: linters: enable: - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers + - bidichk # Checks for dangerous unicode character sequences - bodyclose # checks whether HTTP response body is closed successfully + - contextcheck # check the function whether use a non-inherited context - deadcode # Finds unused code + - decorder # check declaration order and count of types, constants, variables and functions - depguard # Go linter that checks if package imports are in a list of acceptable packages - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) - dupl # Tool for code clone detection + - durationcheck # check for two durations multiplied together - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases + - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occations, where the check for the returned error can be omitted. + - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. + - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. - exhaustive # check exhaustiveness of enum switch statements - exportloopref # checks for pointers to enclosing loop variables + - forcetypeassert # finds forced type assertions - gci # Gci control golang package import order and make it always deterministic. - gochecknoglobals # Checks that no globals are present in Go code - gochecknoinits # Checks that no init functions are present in Go code @@ -35,40 +43,62 @@ linters: - gofumpt # Gofumpt checks whether code was gofumpt-ed. - goheader # Checks is file header matches to pattern - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports - - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes + - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. - goprintffuncname # Checks that printf-like functions are named with `f` at the end - gosec # Inspects source code for security problems - gosimple # Linter for Go source code that specializes in simplifying a code - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string + - grouper # An analyzer to analyze expression groups. + - importas # Enforces consistent import aliases - ineffassign # Detects when assignments to existing variables are not used - misspell # Finds commonly misspelled English words in comments - nakedret # Finds naked returns in functions greater than a specified function length + - nilerr # Finds the code that returns nil even if it checks that the error is not nil. + - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. - noctx # noctx finds sending http request without context.Context - - scopelint # Scopelint checks for unpinned variables in go programs + - predeclared # find code that shadows one of Go's predeclared identifiers + - revive # golint replacement, finds style mistakes - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks - structcheck # Finds unused struct fields - stylecheck # Stylecheck is a replacement for golint + - tagliatelle # Checks the struct tags. + - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 + - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code - unconvert # Remove unnecessary type conversions - unparam # Reports unused function parameters - unused # Checks Go code for unused constants, variables, functions and types - varcheck # Finds unused global variables and constants + - wastedassign # wastedassign finds wasted assignment statements - whitespace # Tool for detection of leading and trailing whitespace disable: + - containedctx # containedctx is a linter that detects struct contained context.Context field + - cyclop # checks function and package cyclomatic complexity + - exhaustivestruct # Checks if all struct's fields are initialized + - forbidigo # Forbids identifiers - funlen # Tool for detection of long functions - gocyclo # Computes and checks the cyclomatic complexity of functions - godot # Check if comments end in a period - gomnd # An analyzer to detect magic numbers. + - ifshort # Checks that your code uses short syntax for if-statements whenever possible + - ireturn # Accept Interfaces, Return Concrete Types - lll # Reports long lines + - maintidx # maintidx measures the maintainability index of each function. + - makezero # Finds slice declarations with non-zero initial length - maligned # Tool to detect Go structs that would take less memory if their fields were sorted - nestif # Reports deeply nested if statements - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity - nolintlint # Reports ill-formed or insufficient nolint directives + - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test - prealloc # Finds slice declarations that could potentially be preallocated + - promlinter # Check Prometheus metrics naming via promlint - rowserrcheck # checks whether Err of rows is checked successfully - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. - testpackage # linter that makes you use a separate _test package + - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers + - varnamelen # checks that the length of a variable's name matches its scope + - wrapcheck # Checks that errors returned from external packages are wrapped - wsl # Whitespace Linter - Forces you to use empty lines! issues: diff --git a/checks.go b/checks.go index e86a302..0acea02 100644 --- a/checks.go +++ b/checks.go @@ -1,3 +1,4 @@ +//go:build !debug // +build !debug package stun diff --git a/client.go b/client.go index 80c0395..3e0ca8b 100644 --- a/client.go +++ b/client.go @@ -236,7 +236,7 @@ var clientTransactionPool = &sync.Pool{ // nolint:gochecknoglobals } func acquireClientTransaction() *clientTransaction { - return clientTransactionPool.Get().(*clientTransaction) + return clientTransactionPool.Get().(*clientTransaction) //nolint:forcetypeassert } func putClientTransaction(t *clientTransaction) { @@ -288,6 +288,7 @@ func (c *Client) SetRTO(rto time.Duration) { // StopErr occurs when Client fails to stop transaction while // processing error. +// nolint:errname type StopErr struct { Err error // value returned by Stop() Cause error // error that caused Stop() call @@ -298,6 +299,7 @@ func (e StopErr) Error() string { } // CloseErr indicates client close failure. +// nolint:errname type CloseErr struct { AgentErr error ConnectionErr error @@ -489,7 +491,7 @@ func (c *Client) Do(m *Message, f func(Event)) error { if f == nil { return c.Indicate(m) } - h := callbackWaitHandlerPool.Get().(*callbackWaitHandler) + h := callbackWaitHandlerPool.Get().(*callbackWaitHandler) //nolint:forcetypeassert h.setCallback(f) defer func() { callbackWaitHandlerPool.Put(h) @@ -545,7 +547,7 @@ func (c *Client) handleAgentCallback(e Event) { } // Doing re-transmission. t.attempt++ - b := bufferPool.Get().(*buffer) + b := bufferPool.Get().(*buffer) //nolint:forcetypeassert b.buf = b.buf[:copy(b.buf[:cap(b.buf)], t.raw)] defer bufferPool.Put(b) var ( diff --git a/client_test.go b/client_test.go index 66ea530..e5018cd 100644 --- a/client_test.go +++ b/client_test.go @@ -1,3 +1,4 @@ +//go:build !js // +build !js package stun @@ -152,8 +153,8 @@ func TestClosedOrPanic(t *testing.T) { closedOrPanic(ErrAgentClosed) func() { defer func() { - r := recover() - if r != io.EOF { + r, ok := recover().(error) + if !ok || !errors.Is(r, io.EOF) { t.Error(r) } }() @@ -492,7 +493,7 @@ func TestClientCloseErr(t *testing.T) { log.Fatal(err) } defer func() { - if err, ok := c.Close().(CloseErr); !ok || !errors.Is(err.AgentErr, io.ErrUnexpectedEOF) { + if err, ok := c.Close().(CloseErr); !ok || !errors.Is(err.AgentErr, io.ErrUnexpectedEOF) { //nolint:errorlint t.Error("unexpected close err") } }() @@ -659,7 +660,7 @@ func TestClientFinalizer(t *testing.T) { } func TestCallbackWaitHandler(t *testing.T) { - h := callbackWaitHandlerPool.Get().(*callbackWaitHandler) + h := callbackWaitHandlerPool.Get().(*callbackWaitHandler) //nolint:forcetypeassert for i := 0; i < 100; i++ { h.setCallback(func(event Event) {}) go func() { @@ -847,7 +848,7 @@ func testClientDoConcurrent(t *testing.T, concurrency int) { for { readN, readErr := connL.Read(buf) if readErr != nil { - if readErr == io.EOF { + if errors.Is(readErr, io.EOF) { break } t.Error(readErr) @@ -877,7 +878,6 @@ func testClientDoConcurrent(t *testing.T, concurrency int) { } func TestClient_DoConcurrent(t *testing.T) { - t.Parallel() for _, concurrency := range []int{ 1, 5, 10, 25, 100, 500, } { @@ -1288,7 +1288,8 @@ func TestClientRTOWriteErr(t *testing.T) { done := make(chan struct{}) go func() { if doErr := c.Do(MustBuild(response, BindingRequest), func(event Event) { - if e, ok := event.Error.(StopErr); !ok { + var e StopErr + if !errors.As(event.Error, &e) { t.Error(event.Error) } else { if !errors.Is(e.Err, agentStopErr) { diff --git a/cmd/stun-nat-behaviour/main.go b/cmd/stun-nat-behaviour/main.go index 09e03af..45b5529 100644 --- a/cmd/stun-nat-behaviour/main.go +++ b/cmd/stun-nat-behaviour/main.go @@ -205,7 +205,8 @@ func parse(msg *stun.Message) (ret struct { respOrigin *stun.ResponseOrigin mappedAddr *stun.MappedAddress software *stun.Software -}) { +}, +) { ret.mappedAddr = &stun.MappedAddress{} ret.xorAddr = &stun.XORMappedAddress{} ret.respOrigin = &stun.ResponseOrigin{} diff --git a/errorcode_test.go b/errorcode_test.go index 817ef34..2246d9e 100644 --- a/errorcode_test.go +++ b/errorcode_test.go @@ -1,3 +1,4 @@ +//go:build !js // +build !js package stun diff --git a/errors.go b/errors.go index 182c48c..8313f11 100644 --- a/errors.go +++ b/errors.go @@ -3,6 +3,7 @@ package stun import "errors" // DecodeErr records an error and place when it is occurred. +// nolint:errname type DecodeErr struct { Place DecodeErrPlace Message string diff --git a/errors_test.go b/errors_test.go index 289bff7..f21e4aa 100644 --- a/errors_test.go +++ b/errors_test.go @@ -1,6 +1,9 @@ package stun -import "testing" +import ( + "errors" + "testing" +) func TestDecodeErr_IsInvalidCookie(t *testing.T) { m := new(Message) @@ -16,8 +19,8 @@ func TestDecodeErr_IsInvalidCookie(t *testing.T) { if err.Error() != expected { t.Error(err, "!=", expected) } - dErr, ok := err.(*DecodeErr) - if !ok { + var dErr *DecodeErr + if !errors.As(err, &dErr) { t.Error("not decode error") } if !dErr.IsInvalidCookie() { diff --git a/fingerprint_test.go b/fingerprint_test.go index 3b0d8b1..4015b5c 100644 --- a/fingerprint_test.go +++ b/fingerprint_test.go @@ -1,3 +1,4 @@ +//go:build !js // +build !js package stun diff --git a/helpers_test.go b/helpers_test.go index e391b42..86a0f30 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -108,7 +108,7 @@ func TestHelpersErrorHandling(t *testing.T) { MustBuild(NewTransactionIDSetter(transactionID{})) }) defer func() { - if p := recover(); !errors.Is(p.(error), e.Err) { + if p, ok := recover().(error); !ok || !errors.Is(p, e.Err) { t.Errorf("%s != %s", p, e.Err, ) diff --git a/iana_test.go b/iana_test.go index ff82135..e5c3a5f 100644 --- a/iana_test.go +++ b/iana_test.go @@ -1,3 +1,4 @@ +//go:build !js // +build !js package stun diff --git a/internal/hmac/hmac.go b/internal/hmac/hmac.go index b189305..5e12480 100644 --- a/internal/hmac/hmac.go +++ b/internal/hmac/hmac.go @@ -57,7 +57,7 @@ func (h *hmac) Sum(in []byte) []byte { in = h.inner.Sum(in) if h.marshaled { - if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil { + if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil { //nolint:forcetypeassert panic(err) // nolint } } else { @@ -77,7 +77,7 @@ func (h *hmac) BlockSize() int { return h.inner.BlockSize() } func (h *hmac) Reset() { if h.marshaled { - if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil { + if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil { //nolint:forcetypeassert panic(err) // nolint } return diff --git a/internal/hmac/hmac_test.go b/internal/hmac/hmac_test.go index 0d1edc3..d481ad4 100644 --- a/internal/hmac/hmac_test.go +++ b/internal/hmac/hmac_test.go @@ -552,7 +552,7 @@ func TestHMAC(t *testing.T) { // Third and fourth iteration: make sure hmac works on // hashes without MarshalBinary/UnmarshalBinary if j == 1 { - h = New(func() hash.Hash { return justHash{tt.hash()} }, tt.key) //nolint: scopecheck + h = New(func() hash.Hash { return justHash{tt.hash()} }, tt.key) } } } diff --git a/internal/hmac/pool.go b/internal/hmac/pool.go index c514fca..d190543 100644 --- a/internal/hmac/pool.go +++ b/internal/hmac/pool.go @@ -43,7 +43,7 @@ var hmacSHA1Pool = &sync.Pool{ // nolint:gochecknoglobals // AcquireSHA1 returns new HMAC from pool. func AcquireSHA1(key []byte) hash.Hash { - h := hmacSHA1Pool.Get().(*hmac) + h := hmacSHA1Pool.Get().(*hmac) //nolint:forcetypeassert assertHMACSize(h, sha1.Size, sha1.BlockSize) h.resetTo(key) return h @@ -51,7 +51,7 @@ func AcquireSHA1(key []byte) hash.Hash { // PutSHA1 puts h to pool. func PutSHA1(h hash.Hash) { - hm := h.(*hmac) + hm := h.(*hmac) //nolint:forcetypeassert assertHMACSize(hm, sha1.Size, sha1.BlockSize) hmacSHA1Pool.Put(hm) } @@ -65,7 +65,7 @@ var hmacSHA256Pool = &sync.Pool{ // nolint:gochecknoglobals // AcquireSHA256 returns new HMAC from SHA256 pool. func AcquireSHA256(key []byte) hash.Hash { - h := hmacSHA256Pool.Get().(*hmac) + h := hmacSHA256Pool.Get().(*hmac) //nolint:forcetypeassert assertHMACSize(h, sha256.Size, sha256.BlockSize) h.resetTo(key) return h @@ -73,7 +73,7 @@ func AcquireSHA256(key []byte) hash.Hash { // PutSHA256 puts h to SHA256 pool. func PutSHA256(h hash.Hash) { - hm := h.(*hmac) + hm := h.(*hmac) //nolint:forcetypeassert assertHMACSize(hm, sha256.Size, sha256.BlockSize) hmacSHA256Pool.Put(hm) } diff --git a/internal/hmac/pool_test.go b/internal/hmac/pool_test.go index b88fd78..dba0f39 100644 --- a/internal/hmac/pool_test.go +++ b/internal/hmac/pool_test.go @@ -40,7 +40,7 @@ func BenchmarkHMACSHA1_512_Pool(b *testing.B) { func TestHMACReset(t *testing.T) { for i, tt := range hmacTests() { h := New(tt.hash, tt.key) - h.(*hmac).resetTo(tt.key) + h.(*hmac).resetTo(tt.key) //nolint:forcetypeassert if s := h.Size(); s != tt.size { t.Errorf("Size: got %v, want %v", s, tt.size) } @@ -139,7 +139,7 @@ func TestHMACPool_SHA256(t *testing.T) { // nolint:dupl func TestAssertBlockSize(t *testing.T) { t.Run("Positive", func(t *testing.T) { h := AcquireSHA1(make([]byte, 0, 1024)) - assertHMACSize(h.(*hmac), sha1.Size, sha1.BlockSize) + assertHMACSize(h.(*hmac), sha1.Size, sha1.BlockSize) //nolint:forcetypeassert }) t.Run("Negative", func(t *testing.T) { defer func() { @@ -148,6 +148,6 @@ func TestAssertBlockSize(t *testing.T) { } }() h := AcquireSHA256(make([]byte, 0, 1024)) - assertHMACSize(h.(*hmac), sha1.Size, sha1.BlockSize) + assertHMACSize(h.(*hmac), sha1.Size, sha1.BlockSize) //nolint:forcetypeassert }) } diff --git a/internal/testutil/norace.go b/internal/testutil/norace.go index e716b5f..d55aa17 100644 --- a/internal/testutil/norace.go +++ b/internal/testutil/norace.go @@ -1,3 +1,4 @@ +//go:build !race // +build !race package testutil diff --git a/message.go b/message.go index 474ba15..3834efb 100644 --- a/message.go +++ b/message.go @@ -450,7 +450,7 @@ func (c MessageClass) String() string { case ClassErrorResponse: return "error response" default: - panic("unknown message class") // nolint: never happens unless wrongly casted + panic("unknown message class") // nolint } } diff --git a/message_test.go b/message_test.go index 64c0e19..b753813 100644 --- a/message_test.go +++ b/message_test.go @@ -1,3 +1,4 @@ +//go:build !js // +build !js package stun @@ -191,12 +192,12 @@ func TestMessage_AttrLengthLessThanHeader(t *testing.T) { mDecoded := New() binary.BigEndian.PutUint16(m.Raw[2:4], 2) // rewrite to bad length _, err := mDecoded.ReadFrom(bytes.NewReader(m.Raw[:20+2])) - switch e := err.(type) { - case *DecodeErr: + var e *DecodeErr + if errors.As(err, &e) { if !e.IsPlace(DecodeErrPlace{"attribute", "header"}) { t.Error(e, "bad place") } - default: + } else { t.Error(err, "should be bad format") } } @@ -220,12 +221,12 @@ func TestMessage_AttrSizeLessThanLength(t *testing.T) { bin.PutUint16(m.Raw[2:4], 5) // rewrite to bad length mDecoded := New() _, err := mDecoded.ReadFrom(bytes.NewReader(m.Raw[:20+5])) - switch e := err.(type) { - case *DecodeErr: + var e *DecodeErr + if errors.As(err, &e) { if !e.IsPlace(DecodeErrPlace{"attribute", "value"}) { t.Error(e, "bad place") } - default: + } else { t.Error(err, "should be bad format") } } @@ -582,7 +583,7 @@ func TestMessageFromBrowsers(t *testing.T) { m := New() for { line, err := reader.Read() - if err == io.EOF { + if errors.Is(err, io.EOF) { break } if err != nil { diff --git a/stuntest/udp_server.go b/stuntest/udp_server.go index c1367ef..2d0629f 100644 --- a/stuntest/udp_server.go +++ b/stuntest/udp_server.go @@ -34,7 +34,7 @@ func NewUDPServer( } // necessary for ipv6 - address := fmt.Sprintf("%s:%d", ip, udpConn.LocalAddr().(*net.UDPAddr).Port) + address := fmt.Sprintf("%s:%d", ip, udpConn.LocalAddr().(*net.UDPAddr).Port) //nolint:forcetypeassert serverAddr, err := net.ResolveUDPAddr(network, address) if err != nil { return nil, nil, fmt.Errorf("failed to resolve stun host: %s: %w", address, err) diff --git a/textattrs_test.go b/textattrs_test.go index 221ec13..417fd15 100644 --- a/textattrs_test.go +++ b/textattrs_test.go @@ -1,3 +1,4 @@ +//go:build !js // +build !js package stun diff --git a/xoraddr_test.go b/xoraddr_test.go index 206c502..5646752 100644 --- a/xoraddr_test.go +++ b/xoraddr_test.go @@ -1,3 +1,4 @@ +//go:build !js // +build !js package stun