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
nodekey
# Binaries for programs and plugins
*.exe

View File

@ -2,11 +2,12 @@ package waku
import (
"context"
"crypto/rand"
"crypto/ecdsa"
"database/sql"
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"os/signal"
@ -19,7 +20,9 @@ import (
logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p"
libp2pcrypto "github.com/libp2p/go-libp2p-core/crypto"
libp2pdisc "github.com/libp2p/go-libp2p-core/discovery"
"github.com/libp2p/go-libp2p-core/protocol"
"github.com/libp2p/go-libp2p-peerstore/pstoreds"
"github.com/multiformats/go-multiaddr"
@ -40,14 +43,6 @@ import (
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) {
if err != nil {
if msg != "" {
@ -58,17 +53,19 @@ func failOnErr(err error, msg string) {
}
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))
var err error
if options.NodeKey == "" {
options.NodeKey, err = randomHex(32)
failOnErr(err, "could not generate random key")
}
prvKey, err := crypto.HexToECDSA(options.NodeKey)
failOnErr(err, "error converting key into valid ecdsa key")
prvKey, err := getPrivKey(options)
failOnErr(err, "nodekey error")
if options.DBPath == "" && options.UseDB {
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")
}
}
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"`
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"`
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"`
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"`