diff --git a/cmd/thor/flags.go b/cmd/thor/flags.go index 645a6f44e..18dcc0a42 100644 --- a/cmd/thor/flags.go +++ b/cmd/thor/flags.go @@ -21,6 +21,11 @@ var ( Hidden: true, Usage: "directory for user global configurations", } + masterKeyStdinFlag = cli.BoolFlag{ + Name: "master-key-stdin", + Usage: "read master key from stdin", + Hidden: true, + } dataDirFlag = cli.StringFlag{ Name: "data-dir", Value: defaultDataDir(), diff --git a/cmd/thor/main.go b/cmd/thor/main.go index 00cb44977..d655ac963 100644 --- a/cmd/thor/main.go +++ b/cmd/thor/main.go @@ -69,6 +69,7 @@ func main() { Flags: []cli.Flag{ networkFlag, configDirFlag, + masterKeyStdinFlag, dataDirFlag, cacheFlag, beneficiaryFlag, diff --git a/cmd/thor/utils.go b/cmd/thor/utils.go index 89ac0212e..852cd42be 100644 --- a/cmd/thor/utils.go +++ b/cmd/thor/utils.go @@ -6,6 +6,7 @@ package main import ( + "bufio" "context" "crypto/ecdsa" "encoding/json" @@ -34,6 +35,7 @@ import ( "github.com/gorilla/handlers" "github.com/gorilla/mux" "github.com/inconshreveable/log15" + "github.com/mattn/go-isatty" "github.com/mattn/go-tty" "github.com/pkg/errors" "github.com/vechain/thor/v2/api/doc" @@ -405,15 +407,48 @@ func masterKeyPath(ctx *cli.Context) (string, error) { return filepath.Join(configDir, "master.key"), nil } -func loadNodeMaster(ctx *cli.Context) (*node.Master, error) { - path, err := masterKeyPath(ctx) - if err != nil { - return nil, err +func loadNodeMasterFromStdin() (*ecdsa.PrivateKey, error) { + var ( + input string + err error + ) + if isatty.IsTerminal(os.Stdin.Fd()) { + input, err = readPasswordFromNewTTY("Enter master key: ") + if err != nil { + return nil, err + } + } else { + reader := bufio.NewReader(os.Stdin) + input, err = reader.ReadString('\n') + if err != nil { + return nil, err + } } - key, err := loadOrGeneratePrivateKey(path) - if err != nil { - return nil, errors.Wrap(err, "load or generate master key") + + return crypto.HexToECDSA(strings.TrimSpace(input)) +} + +func loadNodeMaster(ctx *cli.Context) (*node.Master, error) { + var key *ecdsa.PrivateKey + var err error + + useStdin := ctx.Bool(masterKeyStdinFlag.Name) + if useStdin { + key, err = loadNodeMasterFromStdin() + if err != nil { + return nil, errors.Wrap(err, "read master key from stdin") + } + } else { + path, err := masterKeyPath(ctx) + if err != nil { + return nil, err + } + key, err = loadOrGeneratePrivateKey(path) + if err != nil { + return nil, errors.Wrap(err, "load or generate master key") + } } + master := &node.Master{PrivateKey: key} if master.Beneficiary, err = beneficiary(ctx); err != nil { return nil, err