mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -05:00
Implement generate-auth-secret on beacon node CLI (#10733)
* s * s * typo * typo * s * s * fixes based on PR feedback * PR feedback * reverting log changes * adding flag per feedback * conventions * main fixes * Update cmd/beacon-chain/jwt/jwt.go Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> * Update cmd/beacon-chain/jwt/jwt.go Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> * Update cmd/flags.go Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> * s * tests * test attempt * test * Update cmd/beacon-chain/jwt/jwt.go Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com> * err fix * s * further simplify * cleanup * namefix * tests pass * gaz * rem deadcode * Gaz * shorthand * naming * test pass * dedup * success * Ignore jwt.hex file * logrus * feedback * junk * Also check that no file was written * local run config * small fix * jwt * testfix * s * disabling test * reverting main changes * main revert * removing temp folder * comment * gaz * clarity * rem Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com> Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -35,3 +35,6 @@ bin
|
||||
|
||||
# p2p metaData
|
||||
metaData
|
||||
|
||||
# execution API authentication
|
||||
jwt.hex
|
||||
|
||||
29
cmd/beacon-chain/jwt/BUILD.bazel
Normal file
29
cmd/beacon-chain/jwt/BUILD.bazel
Normal file
@@ -0,0 +1,29 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["jwt.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/cmd/beacon-chain/jwt",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd:go_default_library",
|
||||
"//crypto/rand:go_default_library",
|
||||
"//io/file:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["jwt_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd:go_default_library",
|
||||
"//io/file:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
],
|
||||
)
|
||||
71
cmd/beacon-chain/jwt/jwt.go
Normal file
71
cmd/beacon-chain/jwt/jwt.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/prysmaticlabs/prysm/cmd"
|
||||
"github.com/prysmaticlabs/prysm/crypto/rand"
|
||||
"github.com/prysmaticlabs/prysm/io/file"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
secretFileName = "jwt.hex"
|
||||
)
|
||||
|
||||
var Commands = &cli.Command{
|
||||
Name: "generate-auth-secret",
|
||||
Usage: "creates a random, 32 byte hex string in a plaintext file to be used for authenticating JSON-RPC requests. If no --output-file flag is defined, the file will be created in the current working directory",
|
||||
Description: `creates a random, 32 byte hex string in a plaintext file to be used for authenticating JSON-RPC requests. If no --output-file flag is defined, the file will be created in the current working directory`,
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
cmd.JwtOutputFileFlag,
|
||||
}),
|
||||
Action: generateAuthSecretInFile,
|
||||
}
|
||||
|
||||
func generateAuthSecretInFile(c *cli.Context) error {
|
||||
fileName := secretFileName
|
||||
specifiedFilePath := c.String(cmd.JwtOutputFileFlag.Name)
|
||||
if len(specifiedFilePath) > 0 {
|
||||
fileName = specifiedFilePath
|
||||
}
|
||||
var err error
|
||||
fileName, err = file.ExpandPath(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileDir := filepath.Dir(fileName)
|
||||
exists, err := file.HasDir(fileDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
if err := file.MkdirAll(fileDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
secret, err := generateRandomHexString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.WriteFile(fileName, []byte(secret)); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Infof("Successfully wrote JSON-RPC authentication secret to file %s", fileName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateRandomHexString() (string, error) {
|
||||
secret := make([]byte, 32)
|
||||
randGen := rand.NewGenerator()
|
||||
n, err := randGen.Read(secret)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if n <= 0 {
|
||||
return "", errors.New("rand: unexpected length")
|
||||
}
|
||||
return hexutil.Encode(secret), nil
|
||||
}
|
||||
86
cmd/beacon-chain/jwt/jwt_test.go
Normal file
86
cmd/beacon-chain/jwt/jwt_test.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/prysmaticlabs/prysm/cmd"
|
||||
"github.com/prysmaticlabs/prysm/io/file"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func Test_generateJWTSecret(t *testing.T) {
|
||||
t.Run("command should be available", func(t *testing.T) {
|
||||
generateJwtCommand := Commands
|
||||
require.Equal(t, true, generateJwtCommand.Name == "generate-auth-secret")
|
||||
})
|
||||
t.Run("should create proper file in current directory", func(t *testing.T) {
|
||||
require.NoError(t, os.RemoveAll(secretFileName))
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, os.RemoveAll(secretFileName))
|
||||
})
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
cliCtx := cli.NewContext(&app, set, nil)
|
||||
err := generateAuthSecretInFile(cliCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We check the file has the contents we expect.
|
||||
checkAuthFileIntegrity(t, secretFileName)
|
||||
})
|
||||
t.Run("should create proper file in specified folder", func(t *testing.T) {
|
||||
customOutput := filepath.Join("data", "item.txt")
|
||||
require.NoError(t, os.RemoveAll(filepath.Dir(customOutput)))
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, os.RemoveAll(filepath.Dir(customOutput)))
|
||||
})
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(cmd.JwtOutputFileFlag.Name, customOutput, "")
|
||||
require.NoError(t, set.Set(cmd.JwtOutputFileFlag.Name, customOutput))
|
||||
|
||||
cliCtx := cli.NewContext(&app, set, nil)
|
||||
err := generateAuthSecretInFile(cliCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We check the file has the contents we expect.
|
||||
checkAuthFileIntegrity(t, customOutput)
|
||||
})
|
||||
t.Run("creates proper file in nested specified folder", func(t *testing.T) {
|
||||
rootDirectory := "data"
|
||||
customOutputPath := filepath.Join(rootDirectory, "nest", "nested", "item.txt")
|
||||
require.NoError(t, os.RemoveAll(filepath.Dir(customOutputPath)))
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, os.RemoveAll(rootDirectory))
|
||||
_, err := os.Stat(customOutputPath)
|
||||
require.Equal(t, true, err != nil)
|
||||
})
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(cmd.JwtOutputFileFlag.Name, customOutputPath, "")
|
||||
require.NoError(t, set.Set(cmd.JwtOutputFileFlag.Name, customOutputPath))
|
||||
|
||||
cliCtx := cli.NewContext(&app, set, nil)
|
||||
err := generateAuthSecretInFile(cliCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We check the file has the contents we expect.
|
||||
checkAuthFileIntegrity(t, customOutputPath)
|
||||
})
|
||||
}
|
||||
|
||||
func checkAuthFileIntegrity(t testing.TB, fPath string) {
|
||||
fileInfo, err := os.Stat(fPath)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, fileInfo != nil)
|
||||
|
||||
enc, err := file.ReadFileAsBytes(fPath)
|
||||
require.NoError(t, err)
|
||||
decoded, err := hexutil.Decode(string(enc))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 32, len(decoded))
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Package cmd defines the command line flags for the shared utlities.
|
||||
// Package cmd defines the command line flags for the shared utilities.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
@@ -255,6 +255,12 @@ var (
|
||||
Usage: "Specifies the timeout value for API requests in seconds",
|
||||
Value: 120,
|
||||
}
|
||||
// JwtOutputFileFlag specifies the JWT file path that gets generated into when invoked by generate-jwt-secret.
|
||||
JwtOutputFileFlag = &cli.StringFlag{
|
||||
Name: "output-file",
|
||||
Usage: "Target file path for outputting a generated JWT secret to be used for JSON-RPC authentication",
|
||||
Aliases: []string{"o"},
|
||||
}
|
||||
)
|
||||
|
||||
// LoadFlagsFromConfig sets flags values from config file if ConfigFileFlag is set.
|
||||
|
||||
Reference in New Issue
Block a user