Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: move --generate-key to a generate-key subcommand #637

Merged
merged 1 commit into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions cmd/waku/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,6 @@ var (
Destination: &options.KeyPasswd,
EnvVars: []string{"WAKUNODE2_KEY_PASSWORD"},
})
GenerateKey = altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "generate-key",
Usage: "Generate private key file at path specified in --key-file with the password defined by --key-password",
Destination: &options.GenerateKey,
})
Overwrite = altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "overwrite",
Usage: "When generating a keyfile, overwrite the nodekey file if it already exists",
Destination: &options.Overwrite,
})
StaticNode = cliutils.NewGenericFlagMultiValue(&cli.GenericFlag{
Name: "staticnode",
Usage: "Multiaddr of peer to directly connect with. Option may be repeated",
Expand Down
80 changes: 80 additions & 0 deletions cmd/waku/keygen/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package keygen

import (
"encoding/json"
"fmt"
"os"

"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/crypto"
"github.com/urfave/cli/v2"
"github.com/waku-org/go-waku/waku/v2/utils"
"go.uber.org/zap"
)

// Command generates a key file used to generate the node's peerID, encrypted with an optional password
var Command = cli.Command{
Name: "generate-key",
Usage: "Generate private key file at path specified in --key-file with the password defined by --key-password",
Action: func(cCtx *cli.Context) error {
if err := generateKeyFile(Options.KeyFile, []byte(Options.KeyPasswd), Options.Overwrite); err != nil {
utils.Logger().Fatal("could not write keyfile", zap.Error(err))
}
return nil
},
Flags: []cli.Flag{
KeyFile,
KeyPassword,
Overwrite,
},
}

func checkForFileExistence(path string, overwrite bool) error {
_, err := os.Stat(path)

if err == nil && !overwrite {
return fmt.Errorf("%s already exists. Use --overwrite to overwrite the file", path)
}

if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
return err
}

return nil
}

func generatePrivateKey() ([]byte, error) {
key, err := crypto.GenerateKey()
if err != nil {
return nil, err
}

return key.D.Bytes(), nil
}

func writeKeyFile(path string, key []byte, passwd []byte) error {
encryptedK, err := keystore.EncryptDataV3(key, passwd, keystore.StandardScryptN, keystore.StandardScryptP)
if err != nil {
return err
}

output, err := json.Marshal(encryptedK)
if err != nil {
return err
}

return os.WriteFile(path, output, 0600)
}

func generateKeyFile(path string, passwd []byte, overwrite bool) error {
if err := checkForFileExistence(path, overwrite); err != nil {
return err
}

key, err := generatePrivateKey()
if err != nil {
return err
}

return writeKeyFile(path, key, passwd)
}
35 changes: 35 additions & 0 deletions cmd/waku/keygen/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package keygen

import (
cli "github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
)

// Options contain the settings used for generating a key file
var Options GenerateKeyOptions

var (
// KeyFile is a flag that contains the path where the node key will be written
KeyFile = altsrc.NewPathFlag(&cli.PathFlag{
Name: "key-file",
Value: "./nodekey",
Usage: "Path to a file containing the private key for the P2P node",
Destination: &Options.KeyFile,
EnvVars: []string{"WAKUNODE2_KEY_FILE"},
})
// KeyPassword is a flag to set the password used to encrypt the file
KeyPassword = altsrc.NewStringFlag(&cli.StringFlag{
Name: "key-password",
Value: "secret",
Usage: "Password used for the private key file",
Destination: &Options.KeyPasswd,
EnvVars: []string{"WAKUNODE2_KEY_PASSWORD"},
})
// Overwrite is a flag used to overwrite an existing key file
Overwrite = altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "overwrite",
Value: false,
Usage: "Overwrite the nodekey file if it already exists",
Destination: &Options.Overwrite,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe set default to false.

})
)
9 changes: 9 additions & 0 deletions cmd/waku/keygen/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package keygen

// GenerateKeyOptions contains all the settings that can be used when generating
// a keyfile with the generate-key command
type GenerateKeyOptions struct {
KeyFile string
KeyPasswd string
Overwrite bool
}
8 changes: 5 additions & 3 deletions cmd/waku/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import (

cli "github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
"github.com/waku-org/go-waku/cmd/waku/keygen"
"github.com/waku-org/go-waku/waku/v2/node"
)

var options Options
var options NodeOptions

func main() {
// Defaults
Expand All @@ -31,8 +32,6 @@ func main() {
NodeKey,
KeyFile,
KeyPassword,
GenerateKey,
Overwrite,
StaticNode,
KeepAlive,
PersistPeers,
Expand Down Expand Up @@ -111,6 +110,9 @@ func main() {
Execute(options)
return nil
},
Commands: []*cli.Command{
&keygen.Command,
},
}

err := app.Run(os.Args)
Expand Down
61 changes: 4 additions & 57 deletions cmd/waku/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func failOnErr(err error, msg string) {
}
}

func requiresDB(options Options) bool {
func requiresDB(options NodeOptions) bool {
return options.Store.Enable || options.Rendezvous.Enable
}

Expand All @@ -83,14 +83,7 @@ func scalePerc(value float64) float64 {
const dialTimeout = 7 * time.Second

// Execute starts a go-waku node with settings determined by the Options parameter
func Execute(options Options) {
if options.GenerateKey {
if err := writePrivateKeyToFile(options.KeyFile, []byte(options.KeyPasswd), options.Overwrite); err != nil {
failOnErr(err, "nodekey error")
}
return
}

func Execute(options NodeOptions) {
hostAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", options.Address, options.Port))
failOnErr(err, "invalid host address")

Expand Down Expand Up @@ -528,53 +521,7 @@ func loadPrivateKeyFromFile(path string, passwd string) (*ecdsa.PrivateKey, erro
return crypto.ToECDSA(pKey)
}

func checkForFileExistence(path string, overwrite bool) error {
_, err := os.Stat(path)

if err == nil && !overwrite {
return fmt.Errorf("%s already exists. Use --overwrite to overwrite the file", path)
}

if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
return err
}

return nil
}

func generatePrivateKey() ([]byte, error) {
key, err := crypto.GenerateKey()
if err != nil {
return nil, err
}

return key.D.Bytes(), nil
}

func writePrivateKeyToFile(path string, passwd []byte, overwrite bool) error {
if err := checkForFileExistence(path, overwrite); err != nil {
return err
}

key, err := generatePrivateKey()
if err != nil {
return err
}

encryptedK, err := keystore.EncryptDataV3(key, passwd, keystore.StandardScryptN, keystore.StandardScryptP)
if err != nil {
return err
}

output, err := json.Marshal(encryptedK)
if err != nil {
return err
}

return os.WriteFile(path, output, 0600)
}

func getPrivKey(options Options) (*ecdsa.PrivateKey, error) {
func getPrivKey(options NodeOptions) (*ecdsa.PrivateKey, error) {
var prvKey *ecdsa.PrivateKey
// get private key from nodeKey or keyFile
if options.NodeKey != nil {
Expand All @@ -597,7 +544,7 @@ func getPrivKey(options Options) (*ecdsa.PrivateKey, error) {
return prvKey, nil
}

func printListeningAddresses(ctx context.Context, nodeOpts []node.WakuNodeOption, options Options) {
func printListeningAddresses(ctx context.Context, nodeOpts []node.WakuNodeOption, options NodeOptions) {
params := new(node.WakuNodeParameters)
for _, opt := range nodeOpts {
err := opt(params)
Expand Down
2 changes: 1 addition & 1 deletion cmd/waku/node_no_rln.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ import (
"go.uber.org/zap"
)

func checkForRLN(logger *zap.Logger, options Options, nodeOpts *[]node.WakuNodeOption) {
func checkForRLN(logger *zap.Logger, options NodeOptions, nodeOpts *[]node.WakuNodeOption) {
// Do nothing
}
2 changes: 1 addition & 1 deletion cmd/waku/node_rln.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"go.uber.org/zap"
)

func checkForRLN(logger *zap.Logger, options Options, nodeOpts *[]node.WakuNodeOption) {
func checkForRLN(logger *zap.Logger, options NodeOptions, nodeOpts *[]node.WakuNodeOption) {
if options.RLNRelay.Enable {
if !options.Relay.Enable {
failOnErr(errors.New("relay not available"), "Could not enable RLN Relay")
Expand Down
6 changes: 2 additions & 4 deletions cmd/waku/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,15 @@ type RendezvousOptions struct {
Nodes []multiaddr.Multiaddr
}

// Options contains all the available features and settings that can be
// NodeOptions contains all the available features and settings that can be
// configured via flags when executing go-waku as a service.
type Options struct {
type NodeOptions struct {
Port int
Address string
DNS4DomainName string
NodeKey *ecdsa.PrivateKey
KeyFile string
KeyPasswd string
GenerateKey bool
Overwrite bool
StaticNodes []multiaddr.Multiaddr
KeepAlive time.Duration
AdvertiseAddresses []multiaddr.Multiaddr
Expand Down