From 86828188267c589725e995f10fd8c0ce7a39e5c4 Mon Sep 17 00:00:00 2001 From: lestrrat <49281+lestrrat@users.noreply.github.com> Date: Mon, 29 Aug 2022 16:27:02 +0900 Subject: [PATCH] Update module structure to use workspaces (#809) * Update module structure to use workspaces * fix usage order * Remove t.Parallel * Update go versions * Update golangci-lint version * go1.19 -> golangci-lint run upgrade -> gave us a lot of new warnings * turn GOWORK=off, tweak * Add gofmt.sh * Fix tests * tweak Changes * only run gofmt for go1.19 * fix generation source * tweak order * tweak spacing * tweak spacing * tweak spacing * tweak spacing * tweak spacing * tweak spacing --- .github/workflows/benchmark.yml | 2 +- .github/workflows/ci.yml | 6 ++-- .github/workflows/lint.yml | 4 +-- .github/workflows/smoke.yml | 6 ++-- .golangci.yml | 6 ++++ Changes | 15 +++++++++ Makefile | 1 + bench/performance/go.mod | 6 ++-- bench/performance/go.sum | 2 ++ cert/cert_test.go | 6 +--- cmd/jwx/go.mod | 4 +-- cmd/jwx/go.sum | 2 ++ examples/go.mod | 6 ++-- examples/go.sum | 2 ++ examples/jwx_with_number_example_test.go | 1 + internal/json/goccy.go | 1 + jwa/elliptic_gen.go | 2 +- jwa/secp2561k.go | 1 + jwa/secp2561k_test.go | 1 + jwe/decrypt.go | 1 + jwe/interface.go | 7 ++-- jwe/jwe.go | 10 +++--- jwe/key_provider.go | 28 ++++++++-------- jwe/options_gen.go | 2 +- jwe/options_gen_test.go | 2 +- jwk/cache.go | 6 ++-- jwk/es256k.go | 1 + jwk/es256k_test.go | 1 + jwk/interface.go | 1 + jwk/jwk.go | 17 +++++----- jwk/set.go | 5 +-- jws/es256k.go | 1 + jws/es256k_test.go | 1 + jws/interface.go | 8 ++--- jws/jws.go | 15 ++++----- jws/jws_test.go | 20 +++++------ jws/key_provider.go | 28 ++++++++-------- jwt/http.go | 12 +++---- jwt/jwt.go | 7 ++-- jwt/openid/openid.go | 9 +++-- jwt/options.go | 9 +++-- jwt/options.yaml | 18 +++++----- jwt/options_gen.go | 14 ++++---- jwt/serialize.go | 14 ++++---- jwx.go | 10 +++--- scripts/release.sh | 39 ++++++++++++++++++++++ tools/cmd/genjwa.sh | 2 +- tools/cmd/genjwa/main.go | 2 +- tools/cmd/genjwe.sh | 2 +- tools/cmd/genjwk.sh | 2 +- tools/cmd/genjws.sh | 2 +- tools/cmd/genjwt.sh | 2 +- tools/cmd/genoptions.sh | 2 +- tools/cmd/genoptions/main.go | 42 ++++++++++++++++++++---- tools/cmd/genreadfile.sh | 1 + tools/cmd/gofmt.sh | 3 ++ 56 files changed, 256 insertions(+), 164 deletions(-) create mode 100755 scripts/release.sh create mode 100755 tools/cmd/gofmt.sh diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index b2414fcd6..98f6d12d7 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.18', '1.17', '1.16' ] + go: [ '1.19', '1.18', '1.17' ] name: "Test [ Go ${{ matrix.go }} / JSON Backend ${{ matrix.json_backend }} ]" steps: - name: Checkout repository diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3083d468f..cb5051298 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: go_tags: [ 'stdlib', 'goccy', 'es256k', 'all'] - go: [ '1.18', '1.17', '1.16' ] + go: [ '1.19', '1.18', '1.17' ] name: "Test [ Go ${{ matrix.go }} / Tags ${{ matrix.go_tags }} ]" steps: - name: Checkout repository @@ -45,10 +45,12 @@ jobs: - name: Install jose run: sudo apt-get install -y --no-install-recommends jose - run: make generate + - name: make tidy + run: make tidy - name: Test with coverage run: make cover-${{ matrix.go_tags }} - name: Upload code coverage to codecov - if: matrix.go == '1.18' + if: matrix.go == '1.19' uses: codecov/codecov-action@v1 with: file: ./coverage.out diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fd5769962..66bf61d5e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,11 +8,11 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.18 + go-version: 1.19 check-latest: true - uses: golangci/golangci-lint-action@v3 with: - version: v1.45.2 + version: v1.49.0 - name: Run go vet run: | go vet ./... diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index 4a6008a36..a2593da75 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: go_tags: [ 'stdlib', 'goccy', 'es256k', 'all' ] - go: [ '1.18', '1.17', '1.16' ] + go: [ '1.19', '1.18', '1.17' ] name: "Smoke [ Go ${{ matrix.go }} / Tags ${{ matrix.go_tags }} ]" steps: - name: Checkout repository @@ -41,9 +41,9 @@ jobs: - name: Install jose run: sudo apt-get install -y --no-install-recommends jose - run: make generate + - name: make tidy + run: make tidy - name: Run smoke tests run: make smoke-${{ matrix.go_tags }} - name: Check difference between generation code and commit code run: make check_diffs - - name: Run go mod tidy - run: go mod tidy diff --git a/.golangci.yml b/.golangci.yml index 33508e1ea..aa4a7a65b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -40,6 +40,8 @@ linters: - nakedret - nestif - nlreturn + - nonamedreturns # visit this back later + - nosnakecase - paralleltest - scopelint # deprecated - tagliatelle @@ -60,6 +62,10 @@ issues: text: "don't use an underscore in package name" linters: - revive + - path: /*.go + linters: + - contextcheck + - exhaustruct - path: /main.go linters: - errcheck diff --git a/Changes b/Changes index ee1cafb08..227867017 100644 --- a/Changes +++ b/Changes @@ -4,6 +4,21 @@ Changes v2 has many incompatibilities with v1. To see the full list of differences between v1 and v2, please read the Changes-v2.md file (https://github.com/lestrrat-go/jwx/blob/develop/v2/Changes-v2.md) +v2.0.7 - UNRELEASED +[Miscellaneous] + * WithCompact's stringification should have been that of the + internal indentity struct ("WithSerialization"), but it was + wrongly producing "WithCompact". This has been fixed. + * Go Workspaces have been enabled within this module. + - When developing, modules will refer to the main jwx module that they + are part of. This allows us to explicitly specify the dependency version + in, for example, ./cmd/jwx/go.mod but still develop against the local version. + - If you are using `goimports` and other tools, you might want to upgrade + binaries -- for example, when using vim-go's auto-format-on-save feature, + my old binaries took well over 5~10 seconds to compute the import paths. + This was fixed when I switched to using go1.19, and upgraded the binaries + used by vim-go + v2.0.6 - 25 Aug 2022 [Bug fixes][Security] * [jwe] Agreement Party UInfo and VInfo (apv/apu) were not properly being diff --git a/Makefile b/Makefile index f1077257f..b6a0a2284 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ generate: @go generate @$(MAKE) generate-jwa generate-jwe generate-jwk generate-jws generate-jwt + @./tools/cmd/gofmt.sh generate-%: @go generate $(shell pwd -P)/$(patsubst generate-%,%,$@) diff --git a/bench/performance/go.mod b/bench/performance/go.mod index a5d179732..b18c93cb7 100644 --- a/bench/performance/go.mod +++ b/bench/performance/go.mod @@ -1,7 +1,5 @@ module github.com/lestrrat-go/jwx/v2/bench/performance -go 1.15 +go 1.16 -replace github.com/lestrrat-go/jwx/v2 => ../.. - -require github.com/lestrrat-go/jwx/v2 v2.0.0-00010101000000-000000000000 +require github.com/lestrrat-go/jwx/v2 v2.0.6 diff --git a/bench/performance/go.sum b/bench/performance/go.sum index 818cfefed..f3a6bc9ef 100644 --- a/bench/performance/go.sum +++ b/bench/performance/go.sum @@ -14,6 +14,8 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= +github.com/lestrrat-go/jwx/v2 v2.0.6 h1:RlyYNLV892Ed7+FTfj1ROoF6x7WxL965PGTHso/60G0= +github.com/lestrrat-go/jwx/v2 v2.0.6/go.mod h1:aVrGuwEr3cp2Prw6TtQvr8sQxe+84gruID5C9TxT64Q= github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/cert/cert_test.go b/cert/cert_test.go index 205e67c33..43d5e98d4 100644 --- a/cert/cert_test.go +++ b/cert/cert_test.go @@ -45,11 +45,7 @@ func TestCert(t *testing.T) { commonName := "test.example.com" template := x509.Certificate{ - // SerialNumber is negative to ensure that negative - // values are parsed. This is due to the prevalence of - // buggy code that produces certificates with negative - // serial numbers. - SerialNumber: big.NewInt(-1), + SerialNumber: big.NewInt(1), // SerialNumbers must be non-negative since go1.19 Subject: pkix.Name{ CommonName: commonName, Organization: []string{"Σ Acme Co"}, diff --git a/cmd/jwx/go.mod b/cmd/jwx/go.mod index caaab3780..999852a9e 100644 --- a/cmd/jwx/go.mod +++ b/cmd/jwx/go.mod @@ -3,7 +3,7 @@ module github.com/lestrrat-go/jwx/v2/cmd/jwx go 1.17 require ( - github.com/lestrrat-go/jwx/v2 v2.0.0-00010101000000-000000000000 + github.com/lestrrat-go/jwx/v2 v2.0.6 github.com/urfave/cli/v2 v2.3.0 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f ) @@ -19,5 +19,3 @@ require ( github.com/lestrrat-go/option v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect ) - -replace github.com/lestrrat-go/jwx/v2 => ../.. diff --git a/cmd/jwx/go.sum b/cmd/jwx/go.sum index 18397315e..f0a5f1e07 100644 --- a/cmd/jwx/go.sum +++ b/cmd/jwx/go.sum @@ -18,6 +18,8 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= +github.com/lestrrat-go/jwx/v2 v2.0.6 h1:RlyYNLV892Ed7+FTfj1ROoF6x7WxL965PGTHso/60G0= +github.com/lestrrat-go/jwx/v2 v2.0.6/go.mod h1:aVrGuwEr3cp2Prw6TtQvr8sQxe+84gruID5C9TxT64Q= github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/examples/go.mod b/examples/go.mod index 82eb27149..4d94f6165 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,12 +1,10 @@ module github.com/lestrrat-go/jwx/v2/examples -go 1.15 +go 1.16 require ( github.com/cloudflare/circl v1.1.0 - github.com/lestrrat-go/jwx/v2 v2.0.0-00010101000000-000000000000 + github.com/lestrrat-go/jwx/v2 v2.0.6 ) -replace github.com/lestrrat-go/jwx/v2 => ../ - replace github.com/cloudflare/circl v1.0.0 => github.com/cloudflare/circl v1.0.1-0.20210104183656-96a0695de3c3 diff --git a/examples/go.sum b/examples/go.sum index e2f410751..5922b3ec9 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -17,6 +17,8 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= +github.com/lestrrat-go/jwx/v2 v2.0.6 h1:RlyYNLV892Ed7+FTfj1ROoF6x7WxL965PGTHso/60G0= +github.com/lestrrat-go/jwx/v2 v2.0.6/go.mod h1:aVrGuwEr3cp2Prw6TtQvr8sQxe+84gruID5C9TxT64Q= github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/examples/jwx_with_number_example_test.go b/examples/jwx_with_number_example_test.go index d8800f872..1124b25bd 100644 --- a/examples/jwx_with_number_example_test.go +++ b/examples/jwx_with_number_example_test.go @@ -1,3 +1,4 @@ +//go:build ignore // +build ignore package examples_test diff --git a/internal/json/goccy.go b/internal/json/goccy.go index f575f2656..59682104b 100644 --- a/internal/json/goccy.go +++ b/internal/json/goccy.go @@ -1,3 +1,4 @@ +//go:build jwx_goccy // +build jwx_goccy package json diff --git a/jwa/elliptic_gen.go b/jwa/elliptic_gen.go index e899086ce..d948e0798 100644 --- a/jwa/elliptic_gen.go +++ b/jwa/elliptic_gen.go @@ -8,7 +8,7 @@ import ( "sync" ) -// EllipticCurveAlgorithm represents the algorithms used for EC keys +// EllipticCurveAlgorithm represents the algorithms used for EC keys type EllipticCurveAlgorithm string // Supported values for EllipticCurveAlgorithm diff --git a/jwa/secp2561k.go b/jwa/secp2561k.go index 594f75905..a6da0dde9 100644 --- a/jwa/secp2561k.go +++ b/jwa/secp2561k.go @@ -1,3 +1,4 @@ +//go:build jwx_es256k // +build jwx_es256k package jwa diff --git a/jwa/secp2561k_test.go b/jwa/secp2561k_test.go index ed92971b0..2647e058f 100644 --- a/jwa/secp2561k_test.go +++ b/jwa/secp2561k_test.go @@ -1,3 +1,4 @@ +//go:build jwx_es256k // +build jwx_es256k package jwa_test diff --git a/jwe/decrypt.go b/jwe/decrypt.go index a3443e2a6..1988f8095 100644 --- a/jwe/decrypt.go +++ b/jwe/decrypt.go @@ -22,6 +22,7 @@ import ( // decrypter is responsible for taking various components to decrypt a message. // its operation is not concurrency safe. You must provide locking yourself +// //nolint:govet type decrypter struct { aad []byte diff --git a/jwe/interface.go b/jwe/interface.go index 99ecb40ac..d1044ce1d 100644 --- a/jwe/interface.go +++ b/jwe/interface.go @@ -49,15 +49,16 @@ type stdRecipient struct { // For example, it is totally valid for if the protected header's // integrity was calculated using a non-standard line breaks: // -// {"a dummy": -// "protected header"} +// {"a dummy": +// "protected header"} // // Once parsed, though, we can only serialize the protected header as: // -// {"a dummy":"protected header"} +// {"a dummy":"protected header"} // // which would obviously result in a contradicting integrity value // if we tried to re-calculate it from a parsed message. +// //nolint:govet type Message struct { // Comments on each field are taken from https://datatracker.ietf.org/doc/html/rfc7516 diff --git a/jwe/jwe.go b/jwe/jwe.go index be11b3dfd..dfd86132e 100644 --- a/jwe/jwe.go +++ b/jwe/jwe.go @@ -213,8 +213,8 @@ func (b *recipientBuilder) Build(cek []byte, calg jwa.ContentEncryptionAlgorithm // You must pass at least one key to `jwe.Encrypt()` by using `jwe.WithKey()` // option. // -// jwe.Encrypt(payload, jwe.WithKey(alg, key)) -// jwe.Encrypt(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2)) +// jwe.Encrypt(payload, jwe.WithKey(alg, key)) +// jwe.Encrypt(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2)) // // Note that in the second example the `jws.WithJSON()` option is // specified as well. This is because the compact serialization @@ -793,13 +793,13 @@ func parseCompact(buf []byte, storeProtectedHeaders bool) (*Message, error) { // // In that case you would register a custom field as follows // -// jwe.RegisterCustomField(`x-birthday`, timeT) +// jwe.RegisterCustomField(`x-birthday`, timeT) // // Then `hdr.Get("x-birthday")` will still return an `interface{}`, // but you can convert its type to `time.Time` // -// bdayif, _ := hdr.Get(`x-birthday`) -// bday := bdayif.(time.Time) +// bdayif, _ := hdr.Get(`x-birthday`) +// bday := bdayif.(time.Time) func RegisterCustomField(name string, object interface{}) { registry.Register(name, object) } diff --git a/jwe/key_provider.go b/jwe/key_provider.go index 5302c3926..746980fca 100644 --- a/jwe/key_provider.go +++ b/jwe/key_provider.go @@ -30,18 +30,18 @@ import ( // The first thing that `jwe.Decrypt()` needs to do is to collect the // KeyProviders from the option list that the user provided (presented in pseudocode): // -// keyProviders := filterKeyProviders(options) +// keyProviders := filterKeyProviders(options) // // Then, remember that a JWE message may contain multiple recipients in the // message. For each recipient, we call on the KeyProviders to give us // the key(s) to use on this signature: // -// for r in msg.Recipients { -// for kp in keyProviders { -// kp.FetcKeys(ctx, sink, r, msg) -// ... -// } -// } +// for r in msg.Recipients { +// for kp in keyProviders { +// kp.FetcKeys(ctx, sink, r, msg) +// ... +// } +// } // // The `sink` argument passed to the KeyProvider is a temporary storage // for the keys (either a jwk.Key or a "raw" key). The `KeyProvider` @@ -54,17 +54,17 @@ import ( // you should execute the necessary checks or retrieval of keys, and // then send the key(s) to the sink: // -// sink.Key(alg, key) +// sink.Key(alg, key) // // These keys are then retrieved and tried for each signature, until // a match is found: // -// keys := sink.Keys() -// for key in keys { -// if decryptJWEKey(recipient.EncryptedKey(), key) { -// return OK -// } -// } +// keys := sink.Keys() +// for key in keys { +// if decryptJWEKey(recipient.EncryptedKey(), key) { +// return OK +// } +// } type KeyProvider interface { FetchKeys(context.Context, KeySink, Recipient, *Message) error } diff --git a/jwe/options_gen.go b/jwe/options_gen.go index 41b43895c..9adb9753e 100644 --- a/jwe/options_gen.go +++ b/jwe/options_gen.go @@ -173,7 +173,7 @@ func (identRequireKid) String() string { } func (identSerialization) String() string { - return "WithCompact" + return "WithSerialization" } // WithCompress specifies the compression algorithm to use when encrypting diff --git a/jwe/options_gen_test.go b/jwe/options_gen_test.go index a1d2590f1..f58bfa574 100644 --- a/jwe/options_gen_test.go +++ b/jwe/options_gen_test.go @@ -21,5 +21,5 @@ func TestOptionIdent(t *testing.T) { require.Equal(t, "WithPretty", identPretty{}.String()) require.Equal(t, "WithProtectedHeaders", identProtectedHeaders{}.String()) require.Equal(t, "WithRequireKid", identRequireKid{}.String()) - require.Equal(t, "WithCompact", identSerialization{}.String()) + require.Equal(t, "WithSerialization", identSerialization{}.String()) } diff --git a/jwk/cache.go b/jwk/cache.go index 1c9efae26..4daed89b2 100644 --- a/jwk/cache.go +++ b/jwk/cache.go @@ -24,8 +24,8 @@ type Whitelist = httprc.Whitelist // Before retrieving the Set objects, the user must pre-register the // URLs they intend to use by calling `Register()` // -// c := jwk.NewCache(ctx) -// c.Register(url, options...) +// c := jwk.NewCache(ctx) +// c.Register(url, options...) // // Once registered, you can call `Get()` to retrieve the Set object. // @@ -310,7 +310,6 @@ func (cs *CachedSet) Index(key Key) int { } func (cs *CachedSet) Keys(ctx context.Context) KeyIterator { - //nolint:contextcheck set, err := cs.cached() if err != nil { return arrayiter.New(nil) @@ -320,7 +319,6 @@ func (cs *CachedSet) Keys(ctx context.Context) KeyIterator { } func (cs *CachedSet) Iterate(ctx context.Context) HeaderIterator { - //nolint:contextcheck set, err := cs.cached() if err != nil { return mapiter.New(nil) diff --git a/jwk/es256k.go b/jwk/es256k.go index 66f822bfb..1a9d2346a 100644 --- a/jwk/es256k.go +++ b/jwk/es256k.go @@ -1,3 +1,4 @@ +//go:build jwx_es256k // +build jwx_es256k package jwk diff --git a/jwk/es256k_test.go b/jwk/es256k_test.go index 873603b0f..777709c41 100644 --- a/jwk/es256k_test.go +++ b/jwk/es256k_test.go @@ -1,3 +1,4 @@ +//go:build jwx_es256k // +build jwx_es256k package jwk_test diff --git a/jwk/interface.go b/jwk/interface.go index 6dbc0db7a..729a0ec6c 100644 --- a/jwk/interface.go +++ b/jwk/interface.go @@ -48,6 +48,7 @@ const ( // If a resource contains a single JWK instead of a JWK set, private parameters // are stored in _both_ the resulting `jwk.Set` object and the `jwk.Key` object . // +//nolint:interfacebloat type Set interface { // AddKey adds the specified key. If the key already exists in the set, // an error is returned. diff --git a/jwk/jwk.go b/jwk/jwk.go index a5070a2ae..3d4671c1f 100644 --- a/jwk/jwk.go +++ b/jwk/jwk.go @@ -37,10 +37,10 @@ func bigIntToBytes(n *big.Int) ([]byte, error) { // The constructor auto-detects the type of key to be instantiated // based on the input type: // -// * "crypto/rsa".PrivateKey and "crypto/rsa".PublicKey creates an RSA based key -// * "crypto/ecdsa".PrivateKey and "crypto/ecdsa".PublicKey creates an EC based key -// * "crypto/ed25519".PrivateKey and "crypto/ed25519".PublicKey creates an OKP based key -// * []byte creates a symmetric key +// - "crypto/rsa".PrivateKey and "crypto/rsa".PublicKey creates an RSA based key +// - "crypto/ecdsa".PrivateKey and "crypto/ecdsa".PublicKey creates an EC based key +// - "crypto/ed25519".PrivateKey and "crypto/ed25519".PublicKey creates an OKP based key +// - []byte creates a symmetric key func FromRaw(key interface{}) (Key, error) { if key == nil { return nil, fmt.Errorf(`jwk.New requires a non-nil key`) @@ -635,7 +635,7 @@ func cloneKey(src Key) (Key, error) { // using either PKCS8 for private keys and PKIX for public keys. // If you need to encode using PKCS1 or SEC1, you must do it yourself. // -// Argument must be of type jwk.Key or jwk.Set +// # Argument must be of type jwk.Key or jwk.Set // // Currently only EC (including Ed25519) and RSA keys (and jwk.Set // comprised of these key types) are supported. @@ -706,14 +706,13 @@ func asnEncode(key Key) (string, []byte, error) { // // In that case you would register a custom field as follows // -// jwk.RegisterCustomField(`x-birthday`, timeT) +// jwk.RegisterCustomField(`x-birthday`, timeT) // // Then `key.Get("x-birthday")` will still return an `interface{}`, // but you can convert its type to `time.Time` // -// bdayif, _ := key.Get(`x-birthday`) -// bday := bdayif.(time.Time) -// +// bdayif, _ := key.Get(`x-birthday`) +// bday := bdayif.(time.Time) func RegisterCustomField(name string, object interface{}) { registry.Register(name, object) } diff --git a/jwk/set.go b/jwk/set.go index 6a2615663..ab535104d 100644 --- a/jwk/set.go +++ b/jwk/set.go @@ -305,10 +305,7 @@ func (s *set) Clone() (Set, error) { defer s.mu.RUnlock() s2.keys = make([]Key, len(s.keys)) - - for i := 0; i < len(s.keys); i++ { - s2.keys[i] = s.keys[i] - } + copy(s2.keys, s.keys) return s2, nil } diff --git a/jws/es256k.go b/jws/es256k.go index d342df5b1..c5043805a 100644 --- a/jws/es256k.go +++ b/jws/es256k.go @@ -1,3 +1,4 @@ +//go:build jwx_es256k // +build jwx_es256k package jws diff --git a/jws/es256k_test.go b/jws/es256k_test.go index d5cb3b5d1..913a2bd19 100644 --- a/jws/es256k_test.go +++ b/jws/es256k_test.go @@ -1,3 +1,4 @@ +//go:build jwx_es256k // +build jwx_es256k package jws_test diff --git a/jws/interface.go b/jws/interface.go index 5fc1fcd1e..3e9d680cf 100644 --- a/jws/interface.go +++ b/jws/interface.go @@ -26,13 +26,13 @@ type DecodeCtx interface { // For example, the protected header `eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9` // decodes to // -// {"typ":"JWT", -// "alg":"HS256"} +// {"typ":"JWT", +// "alg":"HS256"} // // However, when we parse this into a message, we create a jws.Header object, // which, when we marshal into a JSON object again, becomes // -// {"typ":"JWT","alg":"HS256"} +// {"typ":"JWT","alg":"HS256"} // // Notice that serialization lacks a line break and a space between `"JWT",` // and `"alg"`. This causes a problem when verifying the signatures AFTER @@ -42,7 +42,7 @@ type DecodeCtx interface { // manifest itself. However, you may see this discrepancy when you manually // go through these conversions, and/or use the `jwx` tool like so: // -// jwx jws parse message.jws | jwx jws verify --key somekey.jwk --stdin +// jwx jws parse message.jws | jwx jws verify --key somekey.jwk --stdin // // In this scenario, the first `jwx jws parse` outputs a parsed jws.Message // which is marshaled into JSON. At this point the message's protected diff --git a/jws/jws.go b/jws/jws.go index 77e21fc40..6778b3867 100644 --- a/jws/jws.go +++ b/jws/jws.go @@ -6,8 +6,8 @@ // If you do not care about the details, the only things that you // would need to use are the following functions: // -// jws.Sign(payload, jws.WithKey(algorithm, key)) -// jws.Verify(serialized, jws.WithKey(algorithm, key)) +// jws.Sign(payload, jws.WithKey(algorithm, key)) +// jws.Verify(serialized, jws.WithKey(algorithm, key)) // // To sign, simply use `jws.Sign`. `payload` is a []byte buffer that // contains whatever data you want to sign. `alg` is one of the @@ -114,8 +114,8 @@ var _ = fmtMax // You must pass at least one key to `jws.Sign()` by using `jws.WithKey()` // option. // -// jws.Sign(payload, jws.WithKey(alg, key)) -// jws.Sign(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2)) +// jws.Sign(payload, jws.WithKey(alg, key)) +// jws.Sign(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2)) // // Note that in the second example the `jws.WithJSON()` option is // specified as well. This is because the compact serialization @@ -647,14 +647,13 @@ func parse(protected, payload, signature []byte) (*Message, error) { // // In that case you would register a custom field as follows // -// jwe.RegisterCustomField(`x-birthday`, timeT) +// jwe.RegisterCustomField(`x-birthday`, timeT) // // Then `hdr.Get("x-birthday")` will still return an `interface{}`, // but you can convert its type to `time.Time` // -// bdayif, _ := hdr.Get(`x-birthday`) -// bday := bdayif.(time.Time) -// +// bdayif, _ := hdr.Get(`x-birthday`) +// bday := bdayif.(time.Time) func RegisterCustomField(name string, object interface{}) { registry.Register(name, object) } diff --git a/jws/jws_test.go b/jws/jws_test.go index 36fa2f9ed..3e2ae2ea5 100644 --- a/jws/jws_test.go +++ b/jws/jws_test.go @@ -1067,7 +1067,6 @@ func TestReadFile(t *testing.T) { } func TestVerifyNonUniqueKid(t *testing.T) { - t.Parallel() const payload = "Lorem ipsum" const kid = "notUniqueKid" privateKey, err := jwxtest.GenerateRsaJwk() @@ -1136,19 +1135,18 @@ func TestVerifyNonUniqueKid(t *testing.T) { } for _, tc := range testcases { - t.Run(tc.Name, func(t *testing.T) { - t.Parallel() - wrongKey := tc.Key() - // Try matching in different orders - for _, set := range []jwk.Set{makeSet(wrongKey, correctKey), makeSet(correctKey, wrongKey)} { + tc := tc + wrongKey := tc.Key() + for _, set := range []jwk.Set{makeSet(wrongKey, correctKey), makeSet(correctKey, wrongKey)} { + set := set + t.Run(tc.Name, func(t *testing.T) { + // Try matching in different orders var usedKey jwk.Key _, err = jws.Verify(signed, jws.WithKeySet(set, jws.WithMultipleKeysPerKeyID(true)), jws.WithKeyUsed(&usedKey)) - if !assert.NoError(t, err, `jws.Verify should succeed`) { - return - } + require.NoError(t, err, `jws.Verify should succeed`) require.Equal(t, usedKey, correctKey) - } - }) + }) + } } } diff --git a/jws/key_provider.go b/jws/key_provider.go index 3bb27c3e5..7d7518af1 100644 --- a/jws/key_provider.go +++ b/jws/key_provider.go @@ -29,18 +29,18 @@ import ( // The first thing that `jws.Verify()` does is to collect the // KeyProviders from the option list that the user provided (presented in pseudocode): // -// keyProviders := filterKeyProviders(options) +// keyProviders := filterKeyProviders(options) // // Then, remember that a JWS message may contain multiple signatures in the // message. For each signature, we call on the KeyProviders to give us // the key(s) to use on this signature: // -// for sig in msg.Signatures { -// for kp in keyProviders { -// kp.FetcKeys(ctx, sink, sig, msg) -// ... -// } -// } +// for sig in msg.Signatures { +// for kp in keyProviders { +// kp.FetcKeys(ctx, sink, sig, msg) +// ... +// } +// } // // The `sink` argument passed to the KeyProvider is a temporary storage // for the keys (either a jwk.Key or a "raw" key). The `KeyProvider` @@ -54,17 +54,17 @@ import ( // you should execute the necessary checks or retrieval of keys, and // then send the key(s) to the sink: // -// sink.Key(alg, key) +// sink.Key(alg, key) // // These keys are then retrieved and tried for each signature, until // a match is found: // -// keys := sink.Keys() -// for key in keys { -// if givenSignature == makeSignatre(key, payload, ...)) { -// return OK -// } -// } +// keys := sink.Keys() +// for key in keys { +// if givenSignature == makeSignatre(key, payload, ...)) { +// return OK +// } +// } type KeyProvider interface { FetchKeys(context.Context, KeySink, *Signature, *Message) error } diff --git a/jwt/http.go b/jwt/http.go index 08b73bca8..a8edc6036 100644 --- a/jwt/http.go +++ b/jwt/http.go @@ -50,14 +50,14 @@ func ParseForm(values url.Values, name string, options ...ParseOption) (Token, e // // If WithHeaderKey() is used, you must explicitly re-enable searching for "Authorization" header. // -// # searches for "Authorization" -// jwt.ParseRequest(req) +// # searches for "Authorization" +// jwt.ParseRequest(req) // -// # searches for "x-my-token" ONLY. -// jwt.ParseRequest(req, jwt.WithHeaderKey("x-my-token")) +// # searches for "x-my-token" ONLY. +// jwt.ParseRequest(req, jwt.WithHeaderKey("x-my-token")) // -// # searches for "Authorization" AND "x-my-token" -// jwt.ParseRequest(req, jwt.WithHeaderKey("Authorization"), jwt.WithHeaderKey("x-my-token")) +// # searches for "Authorization" AND "x-my-token" +// jwt.ParseRequest(req, jwt.WithHeaderKey("Authorization"), jwt.WithHeaderKey("x-my-token")) func ParseRequest(req *http.Request, options ...ParseOption) (Token, error) { var hdrkeys []string var formkeys []string diff --git a/jwt/jwt.go b/jwt/jwt.go index 5846a8ff4..b1bc9d666 100644 --- a/jwt/jwt.go +++ b/jwt/jwt.go @@ -445,14 +445,13 @@ func (t *stdToken) Clone() (Token, error) { // // In that case you would register a custom field as follows // -// jwt.RegisterCustomField(`x-birthday`, timeT) +// jwt.RegisterCustomField(`x-birthday`, timeT) // // Then `token.Get("x-birthday")` will still return an `interface{}`, // but you can convert its type to `time.Time` // -// bdayif, _ := token.Get(`x-birthday`) -// bday := bdayif.(time.Time) -// +// bdayif, _ := token.Get(`x-birthday`) +// bday := bdayif.(time.Time) func RegisterCustomField(name string, object interface{}) { registry.Register(name, object) } diff --git a/jwt/openid/openid.go b/jwt/openid/openid.go index 414507aa6..3df7a1216 100644 --- a/jwt/openid/openid.go +++ b/jwt/openid/openid.go @@ -4,7 +4,7 @@ // In order to use OpenID claims, you specify the token to use in the // jwt.Parse method // -// jwt.Parse(data, jwt.WithToken(openid.New()) +// jwt.Parse(data, jwt.WithToken(openid.New()) package openid import ( @@ -39,14 +39,13 @@ func (t *stdToken) Clone() (jwt.Token, error) { // // In that case you would register a custom field as follows // -// jwt.RegisterCustomField(`x-birthday`, timeT) +// jwt.RegisterCustomField(`x-birthday`, timeT) // // Then `token.Get("x-birthday")` will still return an `interface{}`, // but you can convert its type to `time.Time` // -// bdayif, _ := token.Get(`x-birthday`) -// bday := bdayif.(time.Time) -// +// bdayif, _ := token.Get(`x-birthday`) +// bday := bdayif.(time.Time) func RegisterCustomField(name string, object interface{}) { registry.Register(name, object) } diff --git a/jwt/options.go b/jwt/options.go index a83f47680..fe61faeec 100644 --- a/jwt/options.go +++ b/jwt/options.go @@ -115,7 +115,7 @@ type withKey struct { // It is the caller's responsibility to match the suboptions to the operation that they // are performing. For example, you are not allowed to do this: // -// jwt.Sign(token, jwt.WithKey(alg, key, jweOptions...)) +// jwt.Sign(token, jwt.WithKey(alg, key, jweOptions...)) // // In the above example, the creation of the option via `jwt.WithKey()` will work, but // when `jwt.Sign()` is called, the fact that you passed JWE suboptions will be @@ -250,7 +250,7 @@ func WithRequiredClaim(name string) ValidateOption { // // For example, in order to specify that `exp` - `iat` should be less than 10*time.Second, you would write // -// jwt.Validate(token, jwt.WithMaxDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) +// jwt.Validate(token, jwt.WithMaxDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) // // If AcceptableSkew of 2 second is specified, the above will return valid for any value of // `exp` - `iat` between 8 (10-2) and 12 (10+2). @@ -263,10 +263,9 @@ func WithMaxDelta(dur time.Duration, c1, c2 string) ValidateOption { // // For example, in order to specify that `exp` - `iat` should be greater than 10*time.Second, you would write // -// jwt.Validate(token, jwt.WithMinDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) +// jwt.Validate(token, jwt.WithMinDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) // // The validation would fail if the difference is less than 10 seconds. -// func WithMinDelta(dur time.Duration, c1, c2 string) ValidateOption { return WithValidator(MinDeltaIs(c1, c2, dur)) } @@ -288,7 +287,7 @@ func WithMinDelta(dur time.Duration, c1, c2 string) ValidateOption { // Therefore, when you use this option you WILL have to specify at least // the `jwk.WithFetchWhitelist()` suboption: as: // -// jwt.Parse(data, jwt.WithVerifyAuto(nil, jwk.WithFetchWhitelist(...))) +// jwt.Parse(data, jwt.WithVerifyAuto(nil, jwk.WithFetchWhitelist(...))) // // See the list of available options that you can pass to `jwk.Fetch()` // in the `jwk` package diff --git a/jwt/options.yaml b/jwt/options.yaml index 7380123d2..78311eb24 100644 --- a/jwt/options.yaml +++ b/jwt/options.yaml @@ -165,17 +165,17 @@ options: interface: ValidateOption argument_type: Validator comment: | - WithValidator validates the token with the given Validator. + WithValidator validates the token with the given Validator. - For example, in order to validate tokens that are only valid during August, you would write + For example, in order to validate tokens that are only valid during August, you would write - validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error { - if time.Now().Month() != 8 { - return fmt.Errorf(`tokens are only valid during August!`) - } - return nil - }) - err := jwt.Validate(token, jwt.WithValidator(validator)) + validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error { + if time.Now().Month() != 8 { + return fmt.Errorf(`tokens are only valid during August!`) + } + return nil + }) + err := jwt.Validate(token, jwt.WithValidator(validator)) - ident: FS interface: ReadFileOption argument_type: fs.FS diff --git a/jwt/options_gen.go b/jwt/options_gen.go index dd40995ca..078f660e8 100644 --- a/jwt/options_gen.go +++ b/jwt/options_gen.go @@ -359,13 +359,13 @@ func WithValidate(v bool) ParseOption { // // For example, in order to validate tokens that are only valid during August, you would write // -// validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error { -// if time.Now().Month() != 8 { -// return fmt.Errorf(`tokens are only valid during August!`) -// } -// return nil -// }) -// err := jwt.Validate(token, jwt.WithValidator(validator)) +// validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error { +// if time.Now().Month() != 8 { +// return fmt.Errorf(`tokens are only valid during August!`) +// } +// return nil +// }) +// err := jwt.Validate(token, jwt.WithValidator(validator)) func WithValidator(v Validator) ValidateOption { return &validateOption{option.New(identValidator{}, v)} } diff --git a/jwt/serialize.go b/jwt/serialize.go index 84f3e71fd..1a5e467d0 100644 --- a/jwt/serialize.go +++ b/jwt/serialize.go @@ -51,16 +51,16 @@ func (e errStep) Serialize(_ SerializeCtx, _ interface{}) (interface{}, error) { // For example, to marshal the token into JSON, then apply JWS and JWE // in that order, you would do: // -// serialized, err := jwt.NewSerialer(). -// Sign(jwa.RS256, key). -// Encrypt(jwa.RSA_OAEP, key.PublicKey). -// Serialize(token) +// serialized, err := jwt.NewSerialer(). +// Sign(jwa.RS256, key). +// Encrypt(jwa.RSA_OAEP, key.PublicKey). +// Serialize(token) // // The `jwt.Sign()` function is equivalent to // -// serialized, err := jwt.NewSerializer(). -// Sign(...args...). -// Serialize(token) +// serialized, err := jwt.NewSerializer(). +// Sign(...args...). +// Serialize(token) type Serializer struct { steps []SerializeStep } diff --git a/jwx.go b/jwx.go index 7e4358fb2..03e83c836 100644 --- a/jwx.go +++ b/jwx.go @@ -6,11 +6,11 @@ // Package jwx contains tools that deal with the various JWx (JOSE) // technologies such as JWT, JWS, JWE, etc in Go. // -// JWS (https://tools.ietf.org/html/rfc7515) -// JWE (https://tools.ietf.org/html/rfc7516) -// JWK (https://tools.ietf.org/html/rfc7517) -// JWA (https://tools.ietf.org/html/rfc7518) -// JWT (https://tools.ietf.org/html/rfc7519) +// JWS (https://tools.ietf.org/html/rfc7515) +// JWE (https://tools.ietf.org/html/rfc7516) +// JWK (https://tools.ietf.org/html/rfc7517) +// JWA (https://tools.ietf.org/html/rfc7518) +// JWT (https://tools.ietf.org/html/rfc7519) // // Examples are stored in a separate Go module (to avoid adding // dependencies to this module), and thus does not appear in the diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 000000000..ae8d06ca0 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +set -e + +TAG="$1" +if [[ -z "$TAG" ]]; then + echo "tag name must be provided" +fi + +# Make sure Changes file contains an entry for this release +relentry=$(grep "$TAG" Changes) +if [[ "$?" -ne 0 ]]; then + echo "$TAG does not exist in Changes file"; + exit 1; +fi + +reldate=${relentry#$TAG - } +parseddate=$(date --date="$reldate" "+%d %b %Y") + +if [[ "$reldate" != "$parseddate" ]]; then + echo "$TAG does not seem to exist in Changes file (wrong entry format?)"; + exit 1; +fi + +# Update dependency in ./cmd/jwx ./examples +for dir in ./cmd/jwx ./examples ./bench/performance; do + echo "👉 $dir" + pushd $dir > /dev/null + + go mod edit -require=github.com/lestrrat-go/jwx/v2@"$TAG" + go mod tidy + + popd > /dev/null +done + +# set up tag +git tag "$TAG" + +echo "tag $TAG has been created. Make sure to commit/push/push --tags afterwards" diff --git a/tools/cmd/genjwa.sh b/tools/cmd/genjwa.sh index 2885ca6bc..3bcee7426 100755 --- a/tools/cmd/genjwa.sh +++ b/tools/cmd/genjwa.sh @@ -11,7 +11,7 @@ echo "👉 Generating JWA files..." DIR=../tools/cmd/genjwa pushd "$DIR" > /dev/null -go build -o .genjwa main.go +GOWORK=off go build -o .genjwa main.go popd > /dev/null EXE="${DIR}/.genjwa" diff --git a/tools/cmd/genjwa/main.go b/tools/cmd/genjwa/main.go index fd4458c55..6f89ed9d0 100644 --- a/tools/cmd/genjwa/main.go +++ b/tools/cmd/genjwa/main.go @@ -110,7 +110,7 @@ func _main() error { }, { name: `EllipticCurveAlgorithm`, - comment: ` EllipticCurveAlgorithm represents the algorithms used for EC keys`, + comment: `EllipticCurveAlgorithm represents the algorithms used for EC keys`, filename: `elliptic_gen.go`, elements: []element{ { diff --git a/tools/cmd/genjwe.sh b/tools/cmd/genjwe.sh index 4870fff8e..185f5b0f1 100755 --- a/tools/cmd/genjwe.sh +++ b/tools/cmd/genjwe.sh @@ -10,7 +10,7 @@ set -e echo "👉 Generating JWE files..." DIR=../tools/cmd/genjwe pushd "$DIR" > /dev/null -go build -o .genjwe main.go +GOWORK=off go build -o .genjwe main.go popd > /dev/null EXE="${DIR}/.genjwe" diff --git a/tools/cmd/genjwk.sh b/tools/cmd/genjwk.sh index 4922b68e6..6d0c59412 100755 --- a/tools/cmd/genjwk.sh +++ b/tools/cmd/genjwk.sh @@ -10,7 +10,7 @@ set -e echo "👉 Generating JWK files..." DIR=../tools/cmd/genjwk pushd "$DIR" > /dev/null -go build -o .genjwk main.go +GOWORK=off go build -o .genjwk main.go popd > /dev/null EXE="${DIR}/.genjwk" diff --git a/tools/cmd/genjws.sh b/tools/cmd/genjws.sh index e819176b0..953260a0e 100755 --- a/tools/cmd/genjws.sh +++ b/tools/cmd/genjws.sh @@ -10,7 +10,7 @@ set -e echo "👉 Generating JWS files..." DIR=../tools/cmd/genjws pushd "$DIR" > /dev/null -go build -o .genjws main.go +GOWORK=off go build -o .genjws main.go popd > /dev/null EXE="${DIR}/.genjws" diff --git a/tools/cmd/genjwt.sh b/tools/cmd/genjwt.sh index 457f56500..e05ad6360 100755 --- a/tools/cmd/genjwt.sh +++ b/tools/cmd/genjwt.sh @@ -10,7 +10,7 @@ set -e echo "👉 Generating JWT files..." DIR=../tools/cmd/genjwt pushd "$DIR" > /dev/null -go build -o .genjwt main.go +GOWORK=off go build -o .genjwt main.go popd > /dev/null EXE="${DIR}/.genjwt" diff --git a/tools/cmd/genoptions.sh b/tools/cmd/genoptions.sh index e20f8176b..b3c11ca7b 100755 --- a/tools/cmd/genoptions.sh +++ b/tools/cmd/genoptions.sh @@ -11,7 +11,7 @@ echo "👉 Generating options..." DIR=tools/cmd/genoptions pushd "$DIR" > /dev/null -go build -o .genoptions main.go +GOWORK=off go build -o .genoptions main.go popd > /dev/null EXE="$DIR/.genoptions" diff --git a/tools/cmd/genoptions/main.go b/tools/cmd/genoptions/main.go index d32969615..e4a07c6c4 100644 --- a/tools/cmd/genoptions/main.go +++ b/tools/cmd/genoptions/main.go @@ -5,8 +5,10 @@ import ( "flag" "fmt" "os" + "regexp" "sort" "strings" + "unicode" "github.com/goccy/go-yaml" "github.com/lestrrat-go/codegen" @@ -24,12 +26,28 @@ func main() { } } +var reLooksLikeCodeBlock = regexp.MustCompile(`^\s+`) + func writeComment(o *codegen.Output, comment string) bool { comment = strings.TrimSpace(comment) if comment == "" { return false } for i, line := range strings.Split(comment, "\n") { + if reLooksLikeCodeBlock.MatchString(line) { + o.L("//") + var nonSpace int + for j, r := range line { + if !unicode.IsSpace(r) { + nonSpace = j + break + } + o.R("\t") + } + o.R(line[nonSpace:]) + continue + } + if i == 0 { o.LL(`// %s`, line) } else { @@ -179,12 +197,19 @@ func genOptions(objects *Objects) error { seen := make(map[string]struct{}) for _, option := range objects.Options { _, ok := seen[option.Ident] - if !ok { - o.LL(`func (ident%s) String() string {`, option.Ident) - o.L(`return %q`, option.OptionName) - o.L(`}`) - seen[option.Ident] = struct{}{} + if ok { + continue } + + // WithCompact is a weird case.... + optionName := option.OptionName + if option.OptionName == `WithCompact` { + optionName = `WithSerialization` + } + o.LL(`func (ident%s) String() string {`, option.Ident) + o.L(`return %q`, optionName) + o.L(`}`) + seen[option.Ident] = struct{}{} } } @@ -238,7 +263,12 @@ func genOptionTests(objects *Objects) error { continue } - o.L(`require.Equal(t, %q, ident%s{}.String())`, option.OptionName, option.Ident) + // WithCompact is a weird case.... + optionName := option.OptionName + if option.OptionName == `WithCompact` { + optionName = `WithSerialization` + } + o.L(`require.Equal(t, %q, ident%s{}.String())`, optionName, option.Ident) seen[option.Ident] = struct{}{} } diff --git a/tools/cmd/genreadfile.sh b/tools/cmd/genreadfile.sh index 98ced414d..1a3371d42 100755 --- a/tools/cmd/genreadfile.sh +++ b/tools/cmd/genreadfile.sh @@ -6,6 +6,7 @@ set -e echo "👉 Generating ReadFile() for each package..." +export GOWORK=off DIR="tools/cmd/genreadfile" pushd "$DIR" > /dev/null go build -o .genreadfile main.go diff --git a/tools/cmd/gofmt.sh b/tools/cmd/gofmt.sh new file mode 100755 index 000000000..31c0f863a --- /dev/null +++ b/tools/cmd/gofmt.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +find . -name '*.go' | xargs gofmt -w -s