// 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" "os" "path/filepath" "strings" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" data "github.com/tendermint/go-data" "github.com/tendermint/go-data/base58" keys "github.com/tendermint/go-keys" "github.com/tendermint/go-keys/cryptostore" "github.com/tendermint/go-keys/storage/filestorage" ) var ( rootDir string output string keyDir string manager keys.Manager ) // RootCmd represents the base command when called without any subcommands var RootCmd = &cobra.Command{ Use: "keys", Short: "Key manager for tendermint clients", Long: `Keys allows you to manage your local keystore for tendermint. These keys may be in any format supported by go-crypto and can be used by light-clients, full nodes, or any other application that needs to sign with a private key.`, PersistentPreRunE: bindFlags, } // Execute adds all child commands to the root command sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { if err := RootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(-1) } } func init() { cobra.OnInitialize(initEnv) RootCmd.PersistentFlags().StringP("root", "r", os.ExpandEnv("$HOME/.tlc"), "root directory for config and data") RootCmd.PersistentFlags().String("keydir", "keys", "Directory to store private keys (subdir of root)") RootCmd.PersistentFlags().StringP("output", "o", "text", "Output format (text|json)") RootCmd.PersistentFlags().StringP("encoding", "e", "hex", "Binary encoding (hex|b64|btc)") } // initEnv sets to use ENV variables if set. func initEnv() { // env variables with TM prefix (eg. TM_ROOT) viper.SetEnvPrefix("TM") viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) viper.AutomaticEnv() } func bindFlags(cmd *cobra.Command, args []string) error { // cmd.Flags() includes flags from this command and all persistent flags from the parent if err := viper.BindPFlags(cmd.Flags()); err != nil { return err } // rootDir is command line flag, env variable, or default $HOME/.tlc rootDir = viper.GetString("root") viper.SetConfigName("keys") // name of config file (without extension) viper.AddConfigPath(rootDir) // search root directory // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { // 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) } // validateFlags asserts all RootCmd flags are valid func validateFlags(cmd *cobra.Command) error { // validate output format output = viper.GetString("output") switch output { case "text", "json": default: return errors.Errorf("Unsupported output format: %s", output) } // validate and set encoding enc := viper.GetString("encoding") switch enc { case "hex": data.Encoder = data.HexEncoder case "b64": data.Encoder = data.B64Encoder case "btc": data.Encoder = base58.BTCEncoder default: return errors.Errorf("Unsupported encoding: %s", enc) } // store the keys directory keyDir = viper.GetString("keydir") if !filepath.IsAbs(keyDir) { keyDir = filepath.Join(rootDir, keyDir) } // and construct the key manager manager = cryptostore.New( cryptostore.SecretBox, filestorage.New(keyDir), ) return nil }