diff --git a/PENDING.md b/PENDING.md index fd326e8ad5a3..3412e72f236f 100644 --- a/PENDING.md +++ b/PENDING.md @@ -25,6 +25,7 @@ BREAKING CHANGES * `gaiacli gov vote --voter` * [x/gov] Added tags sub-package, changed tags to use dash-case * [x/gov] Governance parameters are now stored in globalparams store +* [cli] Genesis/key creation (`init`) now supports user-provided key passwords FEATURES * [lcd] Can now query governance proposals by ProposalStatus diff --git a/client/input.go b/client/input.go index 03140a33c327..e7d13f3bfdbe 100644 --- a/client/input.go +++ b/client/input.go @@ -28,12 +28,17 @@ func GetPassword(prompt string, buf *bufio.Reader) (pass string, err error) { } else { pass, err = readLineFromBuf(buf) } + if err != nil { return "", err } + if len(pass) < MinPassLength { - return "", errors.Errorf("password must be at least %d characters", MinPassLength) + // Return the given password to the upstream client so it can handle a + // non-STDIN failure gracefully. + return pass, errors.Errorf("password must be at least %d characters", MinPassLength) } + return pass, nil } diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index af547e844620..f2d64ef1553e 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -3,11 +3,13 @@ package app import ( "encoding/json" "errors" + "fmt" "github.com/spf13/pflag" "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/config" sdk "github.com/cosmos/cosmos-sdk/types" @@ -20,6 +22,8 @@ var ( // bonded tokens given to genesis validators/accounts freeFermionVal = int64(100) freeFermionsAcc = int64(50) + + DefaultKeyPass = "12345678" ) // State to Unmarshal @@ -81,30 +85,49 @@ type GaiaGenTx struct { PubKey string `json:"pub_key"` } -// Generate a gaia genesis transaction with flags -func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey, genTxConfig config.GenTx) ( - appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { +// GaiaAppGenTx generates a Gaia genesis transaction. +func GaiaAppGenTx( + cdc *wire.Codec, pk crypto.PubKey, genTxConfig config.GenTx, +) (json.RawMessage, json.RawMessage, tmtypes.GenesisValidator, error) { if genTxConfig.Name == "" { return nil, nil, tmtypes.GenesisValidator{}, errors.New("Must specify --name (validator moniker)") } - var addr sdk.AccAddress - var secret string - addr, secret, err = server.GenerateSaveCoinKey(genTxConfig.CliRoot, genTxConfig.Name, "1234567890", genTxConfig.Overwrite) + buf := client.BufferStdin() + prompt := fmt.Sprintf("Password for account '%s' (default %s):", genTxConfig.Name, DefaultKeyPass) + + keyPass, err := client.GetPassword(prompt, buf) + if err != nil && keyPass != "" { + // An error was returned that either failed to read the password from + // STDIN or the given password is not empty but failed to meet minimum + // length requirements. + return nil, nil, tmtypes.GenesisValidator{}, err + } + + if keyPass == "" { + keyPass = DefaultKeyPass + } + + addr, secret, err := server.GenerateSaveCoinKey( + genTxConfig.CliRoot, + genTxConfig.Name, + keyPass, + genTxConfig.Overwrite, + ) if err != nil { - return + return nil, nil, tmtypes.GenesisValidator{}, err } + mm := map[string]string{"secret": secret} - var bz []byte - bz, err = cdc.MarshalJSON(mm) + bz, err := cdc.MarshalJSON(mm) if err != nil { - return + return nil, nil, tmtypes.GenesisValidator{}, err } - cliPrint = json.RawMessage(bz) + cliPrint := json.RawMessage(bz) + appGenTx, _, validator, err := GaiaAppGenTxNF(cdc, pk, addr, genTxConfig.Name) - appGenTx, _, validator, err = GaiaAppGenTxNF(cdc, pk, addr, genTxConfig.Name) - return + return appGenTx, cliPrint, validator, err } // Generate a gaia genesis transaction without flags diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 7fa438e9dcb1..542a0e1a5154 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -25,7 +25,6 @@ import ( ) var ( - pass = "1234567890" gaiadHome = "" gaiacliHome = "" ) @@ -35,11 +34,12 @@ func init() { } func TestGaiaCLISend(t *testing.T) { - tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome), "") + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), app.DefaultKeyPass) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), app.DefaultKeyPass) + chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass) // get a free port, also setup some common flags servAddr, port, err := server.FreeTCPAddr() @@ -59,7 +59,7 @@ func TestGaiaCLISend(t *testing.T) { fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -68,7 +68,7 @@ func TestGaiaCLISend(t *testing.T) { require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) // test autosequencing - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -77,7 +77,7 @@ func TestGaiaCLISend(t *testing.T) { require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64()) // test memo - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo --memo 'testmemo'", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo --memo 'testmemo'", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -87,11 +87,11 @@ func TestGaiaCLISend(t *testing.T) { } func TestGaiaCLICreateValidator(t *testing.T) { - tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome), "") + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), app.DefaultKeyPass) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), app.DefaultKeyPass) chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass) // get a free port, also setup some common flags servAddr, port, err := server.FreeTCPAddr() @@ -109,7 +109,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) barCeshPubKey := sdk.MustBech32ifyValPub(barPubKey) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -124,7 +124,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { cvStr += fmt.Sprintf(" --amount=%v", "2steak") cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally") - executeWrite(t, cvStr, pass) + executeWrite(t, cvStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -140,7 +140,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { unbondStr += fmt.Sprintf(" --address-validator=%s", barAddr) unbondStr += fmt.Sprintf(" --shares-amount=%v", "1") - success := executeWrite(t, unbondStr, pass) + success := executeWrite(t, unbondStr, app.DefaultKeyPass) require.True(t, success) tests.WaitForNextNBlocksTM(2, port) @@ -153,11 +153,11 @@ func TestGaiaCLICreateValidator(t *testing.T) { } func TestGaiaCLISubmitProposal(t *testing.T) { - tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome), "") + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), app.DefaultKeyPass) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), app.DefaultKeyPass) chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass) // get a free port, also setup some common flags servAddr, port, err := server.FreeTCPAddr() @@ -184,7 +184,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { spStr += fmt.Sprintf(" --title=%s", "Test") spStr += fmt.Sprintf(" --description=%s", "test") - executeWrite(t, spStr, pass) + executeWrite(t, spStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) @@ -199,7 +199,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { depositStr += fmt.Sprintf(" --deposit=%s", "10steak") depositStr += fmt.Sprintf(" --proposal-id=%s", "1") - executeWrite(t, depositStr, pass) + executeWrite(t, depositStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) @@ -213,7 +213,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { voteStr += fmt.Sprintf(" --proposal-id=%s", "1") voteStr += fmt.Sprintf(" --option=%s", "Yes") - executeWrite(t, voteStr, pass) + executeWrite(t, voteStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags)) @@ -265,7 +265,7 @@ func executeWrite(t *testing.T, cmdStr string, writes ...string) bool { } func executeInit(t *testing.T, cmdStr string) (chainID string) { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, app.DefaultKeyPass) var initRes map[string]json.RawMessage err := json.Unmarshal([]byte(out), &initRes) @@ -278,7 +278,7 @@ func executeInit(t *testing.T, cmdStr string) (chainID string) { } func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.AccAddress, crypto.PubKey) { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var ko keys.KeyOutput keys.UnmarshalJSON([]byte(out), &ko) @@ -289,7 +289,7 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.AccAddress, crypto.PubKe } func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var initRes map[string]json.RawMessage err := json.Unmarshal([]byte(out), &initRes) require.NoError(t, err, "out %v, err %v", out, err) @@ -303,7 +303,7 @@ func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount { } func executeGetValidator(t *testing.T, cmdStr string) stake.Validator { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var validator stake.Validator cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &validator) @@ -312,7 +312,7 @@ func executeGetValidator(t *testing.T, cmdStr string) stake.Validator { } func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var proposal gov.Proposal cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &proposal) @@ -321,7 +321,7 @@ func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal { } func executeGetVote(t *testing.T, cmdStr string) gov.Vote { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var vote gov.Vote cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &vote) @@ -330,7 +330,7 @@ func executeGetVote(t *testing.T, cmdStr string) gov.Vote { } func executeGetVotes(t *testing.T, cmdStr string) []gov.Vote { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var votes []gov.Vote cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &votes) diff --git a/tests/gobash.go b/tests/gobash.go index 71db2d2ddaca..11f4407f2332 100644 --- a/tests/gobash.go +++ b/tests/gobash.go @@ -2,6 +2,7 @@ package tests import ( "fmt" + "io" "io/ioutil" "strings" "testing" @@ -10,11 +11,12 @@ import ( cmn "github.com/tendermint/tendermint/libs/common" ) -// Execute the command, return stdout, logging stdout/err to t. -func ExecuteT(t *testing.T, cmd string) (out string) { +// ExecuteT executes the command, pipes any input to STDIN and return STDOUT, +// logging STDOUT/STDERR to t. +func ExecuteT(t *testing.T, cmd, input string) (out string) { t.Log("Running", cmn.Cyan(cmd)) - // Split cmd to name and args. + // split cmd to name and args split := strings.Split(cmd, " ") require.True(t, len(split) > 0, "no command provided") name, args := split[0], []string(nil) @@ -22,27 +24,32 @@ func ExecuteT(t *testing.T, cmd string) (out string) { args = split[1:] } - // Start process and wait. proc, err := StartProcess("", name, args) require.NoError(t, err) - // Get the output. + // if input is provided, pass it to STDIN and close the pipe + if input != "" { + _, err = io.WriteString(proc.StdinPipe, input) + require.NoError(t, err) + proc.StdinPipe.Close() + } + outbz, errbz, err := proc.ReadAll() if err != nil { fmt.Println("Err on proc.ReadAll()", err, args) } + proc.Wait() - // Log output. if len(outbz) > 0 { t.Log("Stdout:", cmn.Green(string(outbz))) } + if len(errbz) > 0 { t.Log("Stderr:", cmn.Red(string(errbz))) } - // Collect STDOUT output. - out = strings.Trim(string(outbz), "\n") //trim any new lines + out = strings.Trim(string(outbz), "\n") return out }