diff --git a/cmd/README.md b/cmd/README.md index 97ea787c9..72f202bf1 100644 --- a/cmd/README.md +++ b/cmd/README.md @@ -10,6 +10,7 @@ the commands, and give feedback and changes. ``` # keys help + Keys allows you to manage your local keystore for tendermint. These keys may be in any format supported by go-crypto and can be @@ -20,6 +21,7 @@ Usage: keys [command] Available Commands: + get Get details of one key list List all keys new Create a new public/private key pair serve Run the key manager as an http server @@ -30,7 +32,8 @@ Flags: -o, --output string Output format (text|json) (default "text") -r, --root string root directory for config and data (default "/Users/ethan/.tlc") -Use "keys [command] --help" for more information about a command.``` +Use "keys [command] --help" for more information about a command. +``` ## Getting the config file @@ -42,6 +45,8 @@ The first step is to load in root, by checking the following in order: Once the `rootDir` is established, the script looks for a config file named `keys.{json,toml,yaml,hcl}` in that directory and parses it. These values will provide defaults for flags of the same name. +There is an example config file for testing out locally, which writes keys to `./.mykeys`. You can + ## Getting/Setting variables When we want to get the value of a user-defined variable (eg. `output`), we can call `viper.GetString("output")`, which will do the following checks, until it finds a match: diff --git a/cmd/get.go b/cmd/get.go new file mode 100644 index 000000000..d945809f9 --- /dev/null +++ b/cmd/get.go @@ -0,0 +1,47 @@ +// Copyright © 2017 Ethan Frey +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// getCmd represents the get command +var getCmd = &cobra.Command{ + Use: "get ", + Short: "Get details of one key", + Long: `Return public details of one local key.`, + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 1 || len(args[0]) == 0 { + fmt.Println("You must provide a name for the key") + return + } + name := args[0] + + info, err := manager.Get(name) + if err != nil { + fmt.Println(err.Error()) + return + } + + printInfo(info) + }, +} + +func init() { + RootCmd.AddCommand(getCmd) +} diff --git a/cmd/root.go b/cmd/root.go index 7f5122af2..029c37f9d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -84,7 +84,8 @@ func bindFlags(cmd *cobra.Command, args []string) error { // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { - fmt.Println("Using config file:", viper.ConfigFileUsed()) + // stderr, so if we redirect output to json file, this doesn't appear + fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) } return validateFlags(cmd) diff --git a/cmd/update.go b/cmd/update.go index 9b5387cb9..0340944be 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -22,7 +22,7 @@ import ( // updateCmd represents the update command var updateCmd = &cobra.Command{ - Use: "update", + Use: "update ", Short: "Change the password for a private key", Long: `Change the password for a private key.`, Run: updatePassword, diff --git a/cmd/utils.go b/cmd/utils.go index 9a62fe7e8..01f9801ae 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -41,11 +41,15 @@ func getCheckPassword(prompt, prompt2 string) (string, error) { func printInfo(info keys.Info) { switch output { case "text": - key, err := data.ToText(info.PubKey) + addr, err := data.ToText(info.Address) if err != nil { panic(err) // really shouldn't happen... } - fmt.Printf("%s\t%s\n", info.Name, key) + sep := "\t\t" + if len(info.Name) > 7 { + sep = "\t" + } + fmt.Printf("%s%s%s\n", info.Name, sep, addr) case "json": json, err := data.ToJSON(info) if err != nil { diff --git a/cryptostore/enc_storage.go b/cryptostore/enc_storage.go index 759ca90e9..9589f4cc1 100644 --- a/cryptostore/enc_storage.go +++ b/cryptostore/enc_storage.go @@ -40,8 +40,10 @@ func (es encryptedStorage) Delete(name string) error { // info hardcodes the encoding of keys func info(name string, key crypto.PrivKey) keys.Info { + pub := key.PubKey() return keys.Info{ - Name: name, - PubKey: crypto.PubKeyS{key.PubKey()}, + Name: name, + Address: pub.Address(), + PubKey: crypto.PubKeyS{pub}, } } diff --git a/storage/filestorage/main.go b/storage/filestorage/main.go index 0396c9532..4b7dbe525 100644 --- a/storage/filestorage/main.go +++ b/storage/filestorage/main.go @@ -74,7 +74,7 @@ func (s FileStore) Get(name string) ([]byte, keys.Info, error) { } key, _, err := read(priv) - return key, info, err + return key, info.Format(), err } // List parses the key directory for public info and returns a list of @@ -99,7 +99,7 @@ func (s FileStore) List() (keys.Infos, error) { if err != nil { return nil, err } - infos = append(infos, info) + infos = append(infos, info.Format()) } } diff --git a/storage/filestorage/main_test.go b/storage/filestorage/main_test.go index b27fecfb7..c9c55eb02 100644 --- a/storage/filestorage/main_test.go +++ b/storage/filestorage/main_test.go @@ -49,11 +49,13 @@ func TestBasicCRUD(t *testing.T) { k, i, err := store.Get(name) require.Nil(err, "%+v", err) assert.Equal(key, k) - assert.Equal(info, i) + assert.Equal(info.Name, i.Name) + assert.Equal(info.PubKey, i.PubKey) + assert.NotEmpty(i.Address) l, err = store.List() require.Nil(err, "%+v", err) assert.Equal(1, len(l)) - assert.Equal(info, l[0]) + assert.Equal(i, l[0]) // querying a non-existent key fails _, _, err = store.Get("badname") diff --git a/storage/memstorage/main.go b/storage/memstorage/main.go index 9f671e484..69c8d9b03 100644 --- a/storage/memstorage/main.go +++ b/storage/memstorage/main.go @@ -44,7 +44,7 @@ func (s MemStore) Get(name string) ([]byte, keys.Info, error) { if !ok { err = errors.Errorf("Key named '%s' doesn't exist", name) } - return d.key, d.info, err + return d.key, d.info.Format(), err } // List returns the public info of all keys in the MemStore in unsorted order @@ -52,7 +52,7 @@ func (s MemStore) List() (keys.Infos, error) { res := make([]keys.Info, len(s)) i := 0 for _, d := range s { - res[i] = d.info + res[i] = d.info.Format() i++ } return res, nil diff --git a/storage/memstorage/main_test.go b/storage/memstorage/main_test.go index 2863bffad..7605c8225 100644 --- a/storage/memstorage/main_test.go +++ b/storage/memstorage/main_test.go @@ -41,11 +41,13 @@ func TestBasicCRUD(t *testing.T) { k, i, err := store.Get(name) assert.Nil(err) assert.Equal(key, k) - assert.Equal(info, i) + assert.Equal(info.Name, i.Name) + assert.Equal(info.PubKey, i.PubKey) + assert.NotEmpty(i.Address) l, err = store.List() assert.Nil(err) assert.Equal(1, len(l)) - assert.Equal(info, l[0]) + assert.Equal(i, l[0]) // querying a non-existent key fails _, _, err = store.Get("badname") diff --git a/transactions.go b/transactions.go index 3acb476cf..91dc0e273 100644 --- a/transactions.go +++ b/transactions.go @@ -4,12 +4,21 @@ import ( "sort" crypto "github.com/tendermint/go-crypto" + data "github.com/tendermint/go-data" ) // Info is the public information about a key type Info struct { - Name string - PubKey crypto.PubKeyS + Name string `json:"name"` + Address data.Bytes `json:"address"` + PubKey crypto.PubKeyS `json:"pubkey"` +} + +func (i *Info) Format() Info { + if !i.PubKey.Empty() { + i.Address = i.PubKey.Address() + } + return *i } // Infos is a wrapper to allows alphabetical sorting of the keys