Files
prysm/validator/rpc/auth_token_test.go
Preston Van Loon 2fd6bd8150 Add golang.org/x/tools modernize static analyzer and fix violations (#15946)
* Ran gopls modernize to fix everything

go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...

* Override rules_go provided dependency for golang.org/x/tools to v0.38.0.

To update this, checked out rules_go, then ran `bazel run //go/tools/releaser -- upgrade-dep -mirror=false org_golang_x_tools` and copied the patches.

* Fix buildtag violations and ignore buildtag violations in external

* Introduce modernize analyzer package.

* Add modernize "any" analyzer.

* Fix violations of any analyzer

* Add modernize "appendclipped" analyzer.

* Fix violations of appendclipped

* Add modernize "bloop" analyzer.

* Add modernize "fmtappendf" analyzer.

* Add modernize "forvar" analyzer.

* Add modernize "mapsloop" analyzer.

* Add modernize "minmax" analyzer.

* Fix violations of minmax analyzer

* Add modernize "omitzero" analyzer.

* Add modernize "rangeint" analyzer.

* Fix violations of rangeint.

* Add modernize "reflecttypefor" analyzer.

* Fix violations of reflecttypefor analyzer.

* Add modernize "slicescontains" analyzer.

* Add modernize "slicessort" analyzer.

* Add modernize "slicesdelete" analyzer. This is disabled by default for now. See https://go.dev/issue/73686.

* Add modernize "stringscutprefix" analyzer.

* Add modernize "stringsbuilder" analyzer.

* Fix violations of stringsbuilder analyzer.

* Add modernize "stringsseq" analyzer.

* Add modernize "testingcontext" analyzer.

* Add modernize "waitgroup" analyzer.

* Changelog fragment

* gofmt

* gazelle

* Add modernize "newexpr" analyzer.

* Disable newexpr until go1.26

* Add more details in WORKSPACE on how to update the override

* @nalepae feedback on min()

* gofmt

* Fix violations of forvar
2025-11-14 01:27:22 +00:00

234 lines
7.4 KiB
Go

package rpc
import (
"bufio"
"bytes"
"context"
"encoding/hex"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/OffchainLabs/prysm/v7/api"
"github.com/OffchainLabs/prysm/v7/io/file"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/golang-jwt/jwt/v4"
logTest "github.com/sirupsen/logrus/hooks/test"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func setupWalletDir(t testing.TB) string {
walletDir := filepath.Join(t.TempDir(), "wallet")
require.NoError(t, os.MkdirAll(walletDir, os.ModePerm))
return walletDir
}
func TestServer_AuthenticateUsingExistingToken(t *testing.T) {
// Initializing for the first time, there is no auth token file in
// the wallet directory, so we generate a jwt token and secret from scratch.
walletDir := setupWalletDir(t)
authTokenPath := filepath.Join(walletDir, api.AuthTokenFileName)
srv := &Server{
authTokenPath: authTokenPath,
}
err := srv.initializeAuthToken()
require.NoError(t, err)
unaryInfo := &grpc.UnaryServerInfo{
FullMethod: "Proto.CreateWallet",
}
unaryHandler := func(ctx context.Context, req any) (any, error) {
return nil, nil
}
ctxMD := map[string][]string{
"authorization": {"Bearer " + srv.authToken},
}
ctx := t.Context()
ctx = metadata.NewIncomingContext(ctx, ctxMD)
_, err = srv.AuthTokenInterceptor()(ctx, "xyz", unaryInfo, unaryHandler)
require.NoError(t, err)
// Next up, we make the same request but reinitialize the server and we should still
// pass with the same auth token.
srv = &Server{
authTokenPath: authTokenPath,
}
err = srv.initializeAuthToken()
require.NoError(t, err)
_, err = srv.AuthTokenInterceptor()(ctx, "xyz", unaryInfo, unaryHandler)
require.NoError(t, err)
}
func TestServer_RefreshAuthTokenOnFileChange(t *testing.T) {
// Initializing for the first time, there is no auth token file in
// the wallet directory, so we generate a jwt token and secret from scratch.
walletDir := setupWalletDir(t)
authTokenPath := filepath.Join(walletDir, api.AuthTokenFileName)
srv := &Server{
authTokenPath: authTokenPath,
}
err := srv.initializeAuthToken()
require.NoError(t, err)
currentToken := srv.authToken
ctx, cancel := context.WithCancel(t.Context())
defer cancel()
go srv.refreshAuthTokenFromFileChanges(ctx, srv.authTokenPath)
// Wait for service to be ready.
time.Sleep(time.Millisecond * 250)
// Update the auth token file with a new secret.
require.NoError(t, CreateAuthToken(srv.authTokenPath, "localhost:7500"))
// The service should have picked up the file change and set the jwt secret to the new one.
time.Sleep(time.Millisecond * 500)
newToken := srv.authToken
require.Equal(t, true, currentToken != newToken)
err = os.Remove(srv.authTokenPath)
require.NoError(t, err)
}
// TODO: remove this test when legacy files are removed
func TestServer_LegacyTokensStillWork(t *testing.T) {
hook := logTest.NewGlobal()
// Initializing for the first time, there is no auth token file in
// the wallet directory, so we generate a jwt token and secret from scratch.
walletDir := setupWalletDir(t)
authTokenPath := filepath.Join(walletDir, api.AuthTokenFileName)
bytesBuf := new(bytes.Buffer)
_, err := bytesBuf.WriteString("b5bbbaf533b625a93741978857f13d7adeca58445a1fb00ecf3373420b92776c")
require.NoError(t, err)
_, err = bytesBuf.WriteString("\n")
require.NoError(t, err)
_, err = bytesBuf.WriteString("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.MxwOozSH-TLbW_XKepjyYDHm2IT8Ki0tD3AHuajfNMg")
require.NoError(t, err)
_, err = bytesBuf.WriteString("\n")
require.NoError(t, err)
err = file.MkdirAll(walletDir)
require.NoError(t, err)
err = file.WriteFile(authTokenPath, bytesBuf.Bytes())
require.NoError(t, err)
srv := &Server{
authTokenPath: authTokenPath,
}
err = srv.initializeAuthToken()
require.NoError(t, err)
require.Equal(t, hexutil.Encode(srv.jwtSecret), "0xb5bbbaf533b625a93741978857f13d7adeca58445a1fb00ecf3373420b92776c")
require.Equal(t, srv.authToken, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.MxwOozSH-TLbW_XKepjyYDHm2IT8Ki0tD3AHuajfNMg")
f, err := os.Open(filepath.Clean(srv.authTokenPath))
require.NoError(t, err)
scanner := bufio.NewScanner(f)
var lines []string
// Scan the file and collect lines, excluding empty lines
for scanner.Scan() {
line := scanner.Text()
if strings.TrimSpace(line) != "" {
lines = append(lines, line)
}
}
require.Equal(t, len(lines), 2)
require.LogsContain(t, hook, "Auth token does not follow our standards and should be regenerated")
// Check for scanning errors
err = scanner.Err()
require.NoError(t, err)
err = f.Close()
require.NoError(t, err)
err = os.Remove(srv.authTokenPath)
require.NoError(t, err)
}
// TODO: remove this test when legacy files are removed
func TestServer_LegacyTokensBadSecret(t *testing.T) {
// Initializing for the first time, there is no auth token file in
// the wallet directory, so we generate a jwt token and secret from scratch.
walletDir := setupWalletDir(t)
authTokenPath := filepath.Join(walletDir, api.AuthTokenFileName)
bytesBuf := new(bytes.Buffer)
_, err := bytesBuf.WriteString("----------------")
require.NoError(t, err)
_, err = bytesBuf.WriteString("\n")
require.NoError(t, err)
_, err = bytesBuf.WriteString("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.MxwOozSH-TLbW_XKepjyYDHm2IT8Ki0tD3AHuajfNMg")
require.NoError(t, err)
_, err = bytesBuf.WriteString("\n")
require.NoError(t, err)
err = file.MkdirAll(walletDir)
require.NoError(t, err)
err = file.WriteFile(authTokenPath, bytesBuf.Bytes())
require.NoError(t, err)
srv := &Server{
authTokenPath: authTokenPath,
}
err = srv.initializeAuthToken()
require.ErrorContains(t, "could not decode JWT secret", err)
}
func Test_initializeAuthToken(t *testing.T) {
// Initializing for the first time, there is no auth token file in
// the wallet directory, so we generate a jwt token and secret from scratch.
walletDir := setupWalletDir(t)
authTokenPath := filepath.Join(walletDir, api.AuthTokenFileName)
srv := &Server{
authTokenPath: authTokenPath,
}
err := srv.initializeAuthToken()
require.NoError(t, err)
// Initializing second time, we generate something from the initial file.
srv2 := &Server{
authTokenPath: authTokenPath,
}
err = srv2.initializeAuthToken()
require.NoError(t, err)
require.Equal(t, srv.authToken, srv2.authToken)
// Deleting the auth token and re-initializing means we create a jwt token
// and secret from scratch again.
walletDir = setupWalletDir(t)
authTokenPath = filepath.Join(walletDir, api.AuthTokenFileName)
srv3 := &Server{
authTokenPath: authTokenPath,
}
err = srv3.initializeAuthToken()
require.NoError(t, err)
require.NotEqual(t, srv.authToken, srv3.authToken)
}
// "createTokenString" now uses jwt.RegisteredClaims instead of jwt.StandardClaims (deprecated),
// make sure empty jwt.RegisteredClaims and empty jwt.StandardClaims generates the same token.
func Test_UseRegisteredClaimInsteadOfStandClaims(t *testing.T) {
jwtsecret, err := hex.DecodeString("12345678900123456789abcdeffedcba")
require.NoError(t, err)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{}) // jwt.StandardClaims is deprecated
wantedTokenString, err := token.SignedString(jwtsecret)
require.NoError(t, err)
gotTokenString, err := createTokenString(jwtsecret)
require.NoError(t, err)
if wantedTokenString != gotTokenString {
t.Errorf("%s != %s", wantedTokenString, gotTokenString)
}
}