diff --git a/cmd/admin/admin.go b/cmd/admin/admin.go index d8d3d2ba8..9001ea7d4 100644 --- a/cmd/admin/admin.go +++ b/cmd/admin/admin.go @@ -2,6 +2,7 @@ package main import ( "context" + "errors" "fmt" "github.com/jmhodges/clock" @@ -94,3 +95,22 @@ func newAdmin(configFile string, dryRun bool) (*admin, error) { log: logger, }, nil } + +// findActiveInputMethodFlag returns a single key from setInputs with a value of `true`, +// if exactly one exists. Otherwise it returns an error. +func findActiveInputMethodFlag(setInputs map[string]bool) (string, error) { + var activeFlags []string + for flag, isSet := range setInputs { + if isSet { + activeFlags = append(activeFlags, flag) + } + } + + if len(activeFlags) == 0 { + return "", errors.New("at least one input method flag must be specified") + } else if len(activeFlags) > 1 { + return "", fmt.Errorf("more than one input method flag specified: %v", activeFlags) + } + + return activeFlags[0], nil +} diff --git a/cmd/admin/admin_test.go b/cmd/admin/admin_test.go new file mode 100644 index 000000000..1e0ba3d2e --- /dev/null +++ b/cmd/admin/admin_test.go @@ -0,0 +1,59 @@ +package main + +import ( + "testing" + + "github.com/letsencrypt/boulder/test" +) + +func Test_findActiveInputMethodFlag(t *testing.T) { + tests := []struct { + name string + setInputs map[string]bool + expected string + wantErr bool + }{ + { + name: "No active flags", + setInputs: map[string]bool{ + "-private-key": false, + "-spki-file": false, + "-cert-file": false, + }, + expected: "", + wantErr: true, + }, + { + name: "Multiple active flags", + setInputs: map[string]bool{ + "-private-key": true, + "-spki-file": true, + "-cert-file": false, + }, + expected: "", + wantErr: true, + }, + { + name: "Single active flag", + setInputs: map[string]bool{ + "-private-key": true, + "-spki-file": false, + "-cert-file": false, + }, + expected: "-private-key", + wantErr: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := findActiveInputMethodFlag(tc.setInputs) + if tc.wantErr { + test.AssertError(t, err, "findActiveInputMethodFlag() should have errored") + } else { + test.AssertNotError(t, err, "findActiveInputMethodFlag() should not have errored") + test.AssertEquals(t, result, tc.expected) + } + }) + } +} diff --git a/cmd/admin/cert.go b/cmd/admin/cert.go index dc9c48884..0fb2e0690 100644 --- a/cmd/admin/cert.go +++ b/cmd/admin/cert.go @@ -15,7 +15,6 @@ import ( "unicode" "golang.org/x/crypto/ocsp" - "golang.org/x/exp/maps" core "github.com/letsencrypt/boulder/core" berrors "github.com/letsencrypt/boulder/errors" @@ -109,16 +108,13 @@ func (s *subcommandRevokeCert) Run(ctx context.Context, a *admin) error { "-reg-id": s.regID != 0, "-cert-file": s.certFile != "", } - maps.DeleteFunc(setInputs, func(_ string, v bool) bool { return !v }) - if len(setInputs) == 0 { - return errors.New("at least one input method flag must be specified") - } else if len(setInputs) > 1 { - return fmt.Errorf("more than one input method flag specified: %v", maps.Keys(setInputs)) + activeFlag, err := findActiveInputMethodFlag(setInputs) + if err != nil { + return err } var serials []string - var err error - switch maps.Keys(setInputs)[0] { + switch activeFlag { case "-serial": serials, err = []string{s.serial}, nil case "-incident-table": diff --git a/cmd/admin/key.go b/cmd/admin/key.go index 250eb0225..d0b0a3b25 100644 --- a/cmd/admin/key.go +++ b/cmd/admin/key.go @@ -15,7 +15,6 @@ import ( "sync" "sync/atomic" - "golang.org/x/exp/maps" "google.golang.org/protobuf/types/known/timestamppb" "github.com/letsencrypt/boulder/core" @@ -69,16 +68,13 @@ func (s *subcommandBlockKey) Run(ctx context.Context, a *admin) error { "-cert-file": s.certFile != "", "-csr-file": s.csrFile != "", } - maps.DeleteFunc(setInputs, func(_ string, v bool) bool { return !v }) - if len(setInputs) == 0 { - return errors.New("at least one input method flag must be specified") - } else if len(setInputs) > 1 { - return fmt.Errorf("more than one input method flag specified: %v", maps.Keys(setInputs)) + activeFlag, err := findActiveInputMethodFlag(setInputs) + if err != nil { + return err } var spkiHashes [][]byte - var err error - switch maps.Keys(setInputs)[0] { + switch activeFlag { case "-private-key": var spkiHash []byte spkiHash, err = a.spkiHashFromPrivateKey(s.privKey) diff --git a/cmd/admin/unpause_account.go b/cmd/admin/unpause_account.go index 9a56dde05..ee6db3cc6 100644 --- a/cmd/admin/unpause_account.go +++ b/cmd/admin/unpause_account.go @@ -14,7 +14,6 @@ import ( sapb "github.com/letsencrypt/boulder/sa/proto" "github.com/letsencrypt/boulder/unpause" - "golang.org/x/exp/maps" ) // subcommandUnpauseAccount encapsulates the "admin unpause-account" command. @@ -44,16 +43,13 @@ func (u *subcommandUnpauseAccount) Run(ctx context.Context, a *admin) error { "-account": u.accountID != 0, "-batch-file": u.batchFile != "", } - maps.DeleteFunc(setInputs, func(_ string, v bool) bool { return !v }) - if len(setInputs) == 0 { - return errors.New("at least one input method flag must be specified") - } else if len(setInputs) > 1 { - return fmt.Errorf("more than one input method flag specified: %v", maps.Keys(setInputs)) + activeFlag, err := findActiveInputMethodFlag(setInputs) + if err != nil { + return err } var regIDs []int64 - var err error - switch maps.Keys(setInputs)[0] { + switch activeFlag { case "-account": regIDs = []int64{u.accountID} case "-batch-file": diff --git a/go.mod b/go.mod index 2795da5de..1352f46b1 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,6 @@ require ( go.opentelemetry.io/otel/sdk v1.30.0 go.opentelemetry.io/otel/trace v1.30.0 golang.org/x/crypto v0.27.0 - golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 golang.org/x/net v0.29.0 golang.org/x/sync v0.8.0 golang.org/x/term v0.24.0 diff --git a/go.sum b/go.sum index 114cda1b6..390afaf5d 100644 --- a/go.sum +++ b/go.sum @@ -309,8 +309,6 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= -golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= diff --git a/vendor/golang.org/x/exp/LICENSE b/vendor/golang.org/x/exp/LICENSE deleted file mode 100644 index 6a66aea5e..000000000 --- a/vendor/golang.org/x/exp/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/exp/PATENTS b/vendor/golang.org/x/exp/PATENTS deleted file mode 100644 index 733099041..000000000 --- a/vendor/golang.org/x/exp/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/exp/maps/maps.go b/vendor/golang.org/x/exp/maps/maps.go deleted file mode 100644 index ecc0dabb7..000000000 --- a/vendor/golang.org/x/exp/maps/maps.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package maps defines various functions useful with maps of any type. -package maps - -// Keys returns the keys of the map m. -// The keys will be in an indeterminate order. -func Keys[M ~map[K]V, K comparable, V any](m M) []K { - r := make([]K, 0, len(m)) - for k := range m { - r = append(r, k) - } - return r -} - -// Values returns the values of the map m. -// The values will be in an indeterminate order. -func Values[M ~map[K]V, K comparable, V any](m M) []V { - r := make([]V, 0, len(m)) - for _, v := range m { - r = append(r, v) - } - return r -} - -// Equal reports whether two maps contain the same key/value pairs. -// Values are compared using ==. -func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool { - if len(m1) != len(m2) { - return false - } - for k, v1 := range m1 { - if v2, ok := m2[k]; !ok || v1 != v2 { - return false - } - } - return true -} - -// EqualFunc is like Equal, but compares values using eq. -// Keys are still compared with ==. -func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool { - if len(m1) != len(m2) { - return false - } - for k, v1 := range m1 { - if v2, ok := m2[k]; !ok || !eq(v1, v2) { - return false - } - } - return true -} - -// Clear removes all entries from m, leaving it empty. -func Clear[M ~map[K]V, K comparable, V any](m M) { - for k := range m { - delete(m, k) - } -} - -// Clone returns a copy of m. This is a shallow clone: -// the new keys and values are set using ordinary assignment. -func Clone[M ~map[K]V, K comparable, V any](m M) M { - // Preserve nil in case it matters. - if m == nil { - return nil - } - r := make(M, len(m)) - for k, v := range m { - r[k] = v - } - return r -} - -// Copy copies all key/value pairs in src adding them to dst. -// When a key in src is already present in dst, -// the value in dst will be overwritten by the value associated -// with the key in src. -func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) { - for k, v := range src { - dst[k] = v - } -} - -// DeleteFunc deletes any key/value pairs from m for which del returns true. -func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) { - for k, v := range m { - if del(k, v) { - delete(m, k) - } - } -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 190235174..0a2d3187c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -369,9 +369,6 @@ golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/ed25519 golang.org/x/crypto/ocsp golang.org/x/crypto/pbkdf2 -# golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 -## explicit; go 1.20 -golang.org/x/exp/maps # golang.org/x/mod v0.18.0 ## explicit; go 1.18 golang.org/x/mod/semver diff --git a/wfe2/wfe.go b/wfe2/wfe.go index 351c27c02..482bc131a 100644 --- a/wfe2/wfe.go +++ b/wfe2/wfe.go @@ -13,7 +13,6 @@ import ( "math/rand/v2" "net" "net/http" - "slices" "strconv" "strings" "time" @@ -22,7 +21,6 @@ import ( "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel/trace" - "golang.org/x/exp/maps" "google.golang.org/protobuf/types/known/emptypb" "github.com/letsencrypt/boulder/core" @@ -2273,7 +2271,7 @@ func (wfe *WebFrontEndImpl) validateCertificateProfileName(profile string) error // No profile name is specified. return nil } - if !slices.Contains(maps.Keys(wfe.certProfiles), profile) { + if _, ok := wfe.certProfiles[profile]; !ok { // The profile name is not in the list of configured profiles. return errors.New("not a recognized profile name") }