feat: options to generate/specify/load node privatekey

This commit is contained in:
Richard Ramos 2021-10-04 18:38:27 -04:00
parent f82732cd19
commit de0b63f4a2
3 changed files with 110 additions and 17 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.db *.db
nodekey
# Binaries for programs and plugins # Binaries for programs and plugins
*.exe *.exe

View File

@ -2,11 +2,12 @@ package waku
import ( import (
"context" "context"
"crypto/rand" "crypto/ecdsa"
"database/sql" "database/sql"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"os/signal" "os/signal"
@ -19,7 +20,9 @@ import (
logging "github.com/ipfs/go-log" logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p"
libp2pcrypto "github.com/libp2p/go-libp2p-core/crypto"
libp2pdisc "github.com/libp2p/go-libp2p-core/discovery" libp2pdisc "github.com/libp2p/go-libp2p-core/discovery"
"github.com/libp2p/go-libp2p-core/protocol" "github.com/libp2p/go-libp2p-core/protocol"
"github.com/libp2p/go-libp2p-peerstore/pstoreds" "github.com/libp2p/go-libp2p-peerstore/pstoreds"
"github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr"
@ -40,14 +43,6 @@ import (
var log = logging.Logger("wakunode") var log = logging.Logger("wakunode")
func randomHex(n int) (string, error) {
bytes := make([]byte, n)
if _, err := rand.Read(bytes); err != nil {
return "", err
}
return hex.EncodeToString(bytes), nil
}
func failOnErr(err error, msg string) { func failOnErr(err error, msg string) {
if err != nil { if err != nil {
if msg != "" { if msg != "" {
@ -58,17 +53,19 @@ func failOnErr(err error, msg string) {
} }
func Execute(options Options) { func Execute(options Options) {
if options.GenerateKey {
if err := writePrivateKeyToFile(options.KeyFile, options.Overwrite); err != nil {
failOnErr(err, "nodekey error")
}
return
}
hostAddr, _ := net.ResolveTCPAddr("tcp", fmt.Sprint("0.0.0.0:", options.Port)) hostAddr, _ := net.ResolveTCPAddr("tcp", fmt.Sprint("0.0.0.0:", options.Port))
var err error var err error
if options.NodeKey == "" { prvKey, err := getPrivKey(options)
options.NodeKey, err = randomHex(32) failOnErr(err, "nodekey error")
failOnErr(err, "could not generate random key")
}
prvKey, err := crypto.HexToECDSA(options.NodeKey)
failOnErr(err, "error converting key into valid ecdsa key")
if options.DBPath == "" && options.UseDB { if options.DBPath == "" && options.UseDB {
failOnErr(errors.New("dbpath can't be null"), "") failOnErr(errors.New("dbpath can't be null"), "")
@ -245,3 +242,95 @@ func addPeers(wakuNode *node.WakuNode, addresses []string, protocol protocol.ID)
failOnErr(err, "error adding peer") failOnErr(err, "error adding peer")
} }
} }
func loadPrivateKeyFromFile(path string) (*ecdsa.PrivateKey, error) {
src, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
dst := make([]byte, hex.DecodedLen(len(src)))
_, err = hex.Decode(dst, src)
if err != nil {
return nil, err
}
p, err := libp2pcrypto.UnmarshalSecp256k1PrivateKey(dst)
if err != nil {
return nil, err
}
privKey := (*ecdsa.PrivateKey)(p.(*libp2pcrypto.Secp256k1PrivateKey))
privKey.Curve = crypto.S256()
return privKey, nil
}
func writePrivateKeyToFile(path string, force bool) error {
_, err := os.Stat(path)
if err == nil && !force {
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
}
key, err := crypto.GenerateKey()
if err != nil {
return err
}
privKey := libp2pcrypto.PrivKey((*libp2pcrypto.Secp256k1PrivateKey)(key))
b, err := privKey.Raw()
if err != nil {
return err
}
output := make([]byte, hex.EncodedLen(len(b)))
hex.Encode(output, b)
return ioutil.WriteFile(path, output, 0600)
}
func getPrivKey(options Options) (*ecdsa.PrivateKey, error) {
var prvKey *ecdsa.PrivateKey
var err error
if options.KeyFile != "" {
prvKey, err = loadPrivateKeyFromFile(options.KeyFile)
if err != nil {
return nil, fmt.Errorf("could not read keyfile: %w", err)
}
} else if options.NodeKey != "" {
prvKey, err = crypto.HexToECDSA(options.NodeKey)
if err != nil {
return nil, fmt.Errorf("error converting key into valid ecdsa key: %w", err)
}
} else {
keyString := os.Getenv("GOWAKU-NODEKEY")
if keyString != "" {
prvKey, err = crypto.HexToECDSA(keyString)
if err != nil {
return nil, fmt.Errorf("error converting key into valid ecdsa key: %w", err)
}
} else {
if _, err := os.Stat(options.KeyFile); err == nil {
prvKey, err = loadPrivateKeyFromFile(options.KeyFile)
if err != nil {
return nil, fmt.Errorf("could not read keyfile: %w", err)
}
} else {
if os.IsNotExist(err) {
prvKey, err = crypto.GenerateKey()
if err != nil {
return nil, fmt.Errorf("error generating key: %w", err)
}
} else {
return nil, fmt.Errorf("could not read keyfile: %w", err)
}
}
}
}
return prvKey, nil
}

View File

@ -47,7 +47,10 @@ type Options struct {
Port int `short:"p" long:"port" description:"Libp2p TCP listening port (0 for random)" default:"9000"` Port int `short:"p" long:"port" description:"Libp2p TCP listening port (0 for random)" default:"9000"`
EnableWS bool `long:"ws" description:"Enable websockets support"` EnableWS bool `long:"ws" description:"Enable websockets support"`
WSPort int `long:"ws-port" description:"Libp2p TCP listening port for websocket connection (0 for random)" default:"9001"` WSPort int `long:"ws-port" description:"Libp2p TCP listening port for websocket connection (0 for random)" default:"9001"`
NodeKey string `long:"nodekey" description:"P2P node private key as hex (UNSAFE!, default random)"` NodeKey string `long:"nodekey" description:"P2P node private key as hex. Can also be set with GOWAKU-NODEKEY env variable (default random)"`
KeyFile string `long:"key-file" description:"Path to a file containing the private key for the P2P node" default:"./nodekey"`
GenerateKey bool `long:"generate-key" description:"Generate private key file at path specified in --key-file"`
Overwrite bool `long:"overwrite" description:"When generating a keyfile, overwrite the nodekey file if it already exists"`
StaticNodes []string `long:"staticnodes" description:"Multiaddr of peer to directly connect with. Argument may be repeated"` StaticNodes []string `long:"staticnodes" description:"Multiaddr of peer to directly connect with. Argument may be repeated"`
KeepAlive int `long:"keep-alive" default:"300" description:"Interval in seconds for pinging peers to keep the connection alive."` KeepAlive int `long:"keep-alive" default:"300" description:"Interval in seconds for pinging peers to keep the connection alive."`
UseDB bool `long:"use-db" description:"Use SQLiteDB to persist information"` UseDB bool `long:"use-db" description:"Use SQLiteDB to persist information"`