Skip to content

Commit

Permalink
Improve key list and add key recovery (#376)
Browse files Browse the repository at this point in the history
* Fix spacing issue when listing keys (#269)
* Add recover command to recover keys
* cmd/key: improve output and documentation
  • Loading branch information
gosuri authored Apr 8, 2019
1 parent 561bb32 commit 48c4583
Show file tree
Hide file tree
Showing 21 changed files with 283 additions and 70 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ image: image-bins
_build

install:
go install $(BUILD_FLAGS) ./cmd/akash
go install $(BUILD_FLAGS) ./cmd/akashd
GO111MODULE=off go install $(BUILD_FLAGS) ./cmd/akash
GO111MODULE=off go install $(BUILD_FLAGS) ./cmd/akashd

image-minikube:
eval $$(minikube docker-env) && make image
Expand Down
4 changes: 2 additions & 2 deletions _run/multi/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ do_init(){
mkdir -p "$AKASH_DIR"
mkdir -p "$AKASHD_DIR"

_akash key create master > "$DATA_ROOT/master.key"
_akash key create other > "$DATA_ROOT/other.key"
_akash key create master | grep "Public Key" | awk '{print $3}' > "$DATA_ROOT/master.key"
_akash key create other | grep "Public Key" | awk '{print $3}' > "$DATA_ROOT/other.key"

_akashd init "$(cat "$DATA_ROOT/master.key")" -t helm -c "${HELM_NODE_COUNT:-4}"
}
Expand Down
6 changes: 3 additions & 3 deletions _run/single/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ do_init() {
mkdir -p "$AKASH_DIR"
mkdir -p "$AKASHD_DIR"

akash key create master > "$DATA_ROOT/master.key"
akash key create other > "$DATA_ROOT/other.key"
akash key create master | grep "Public Key" | awk '{print $3}' > "$DATA_ROOT/master.key"
akash key create other | grep "Public Key" | awk '{print $3}' > "$DATA_ROOT/other.key"
akashd init "$(cat "$DATA_ROOT/master.key")"

akash_provider key create master > "$DATA_ROOT/provider-master.key"
akash_provider key create master | grep "Public Key" | awk '{print $3}' > "$DATA_ROOT/provider-master.key"
}

case "$1" in
Expand Down
5 changes: 2 additions & 3 deletions cmd/akash/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ import (
)

func deploymentCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "deployment",
Short: "manage deployments",
Short: "Manage deployments",
}

cmd.AddCommand(createDeploymentCommand())
Expand All @@ -40,7 +39,7 @@ func createDeploymentCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "create <deployment-file>",
Short: "create a deployment",
Short: "Create a deployment",
Args: cobra.ExactArgs(1),
RunE: session.WithSession(
session.RequireKey(session.RequireNode(createDeployment))),
Expand Down
107 changes: 88 additions & 19 deletions cmd/akash/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package main
import (
"errors"
"fmt"
"os"
"text/tabwriter"
"strings"

"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/gosuri/uitable"
"github.com/ovrclk/akash/cmd/akash/session"
"github.com/ovrclk/akash/cmd/common"
"github.com/ovrclk/akash/util/uiutil"
"github.com/spf13/cobra"

. "github.com/ovrclk/akash/util"
Expand All @@ -16,28 +19,28 @@ import (
func keyCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "key",
Short: "Key commands",
Short: "Manage keys",
}
cmd.AddCommand(keyCreateCommand())
cmd.AddCommand(keyListCommand())
cmd.AddCommand(keyShowCommand())
cmd.AddCommand(keyRecoverCommand())
return cmd
}
func keyCreateCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "create [name]",
Short: "Create new key",
RunE: session.WithSession(session.RequireRootDir(doKeyCreateCommand)),
Use: "create <name>",
Short: "create a new key locally",
Long: "Create a new key and store it locally.\nTo recover a key using the recovery codes generated by the command, see 'akash help key recover'",
Example: keyCreateHelp,
Args: cobra.ExactArgs(1),
RunE: session.WithSession(session.RequireRootDir(doKeyCreateCommand)),
}
session.AddFlagKeyType(cmd, cmd.Flags())
return cmd
}

func doKeyCreateCommand(session session.Session, cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return errors.New("name argument required")
}

kmgr, err := session.KeyManager()
if err != nil {
return err
Expand All @@ -53,43 +56,85 @@ func doKeyCreateCommand(session session.Session, cmd *cobra.Command, args []stri
return err
}

info, _, err := kmgr.CreateMnemonic(args[0], common.DefaultCodec, password, ktype)
info, seed, err := kmgr.CreateMnemonic(args[0], common.DefaultCodec, password, ktype)
if err != nil {
return err
}

fmt.Println(X(info.GetPubKey().Address()))
fmt.Println(string(uiutil.NewTitle(fmt.Sprintf("Successfully created key for '%s'", args[0])).Bytes()))
table := uitable.New()
table.AddRow("Public Key:", X(info.GetPubKey().Address()))
table.AddRow("Recovery Codes:", seed)
fmt.Println(table)

return nil
}

func keyListCommand() *cobra.Command {
return &cobra.Command{
Use: "list",
Short: "list keys",
Short: "list all the keys stored locally",
RunE: session.WithSession(session.RequireKeyManager(doKeyListCommand)),
}
}

func doKeyListCommand(session session.Session, cmd *cobra.Command, args []string) error {
func keyRecoverCommand() *cobra.Command {
return &cobra.Command{
Use: "recover <name> <recovery-codes>...",
Short: "recover a key using recovery codes",
Long: "Recover a key using the recovery code generated during key creation and store it locally. For help with creating a key, see 'akash help key create'",
Example: keyRecoverExample,
Args: cobra.ExactArgs(25),
RunE: session.WithSession(session.RequireKeyManager(doKeyRecoverCommand)),
}
}

func doKeyRecoverCommand(session session.Session, cmd *cobra.Command, args []string) error {
// the first arg is the key name and the rest are mnemonic codes
name, args := args[0], args[1:]
seed := strings.Join(args, " ")

password, err := session.Password()
if err != nil {
return err
}

kmgr, _ := session.KeyManager()
params := *hd.NewFundraiserParams(0, 0)
info, err := kmgr.Derive(name, seed, keys.DefaultBIP39Passphrase, password, params)
if err != nil {
return err
}

title := uiutil.NewTitle(fmt.Sprintf("Successfully recovered key, stored locally as '%s'", name))
fmt.Println(string(title.Bytes()))
table := uitable.New()
table.AddRow("Public Key:", X(info.GetPubKey().Address()))
fmt.Println(table)
return nil

}

func doKeyListCommand(session session.Session, cmd *cobra.Command, args []string) error {
kmgr, _ := session.KeyManager()
infos, err := kmgr.List()
if err != nil {
return err
}

tw := tabwriter.NewWriter(os.Stdout, 0, 4, 0, '\t', 0)
table := uitable.New()
table.MaxColWidth = 80
table.Wrap = true
table.AddRow(uiutil.NewTitle("NAME").String(), uiutil.NewTitle("PUBLIC KEY").String())
for _, info := range infos {
fmt.Fprintf(tw, "%v\t%v\n", info.GetName(), X(info.GetPubKey().Address()))
table.AddRow(info.GetName(), X(info.GetPubKey().Address()))
}
tw.Flush()
fmt.Println(table)
return nil
}

func keyShowCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "show [name]",
Use: "show <name>",
Short: "display a key",
Args: cobra.ExactArgs(1),
RunE: session.WithSession(session.RequireRootDir(doKeyShowCommand)),
Expand Down Expand Up @@ -122,3 +167,27 @@ func doKeyShowCommand(session session.Session, cmd *cobra.Command, args []string
fmt.Println(X(info.GetPubKey().Address()))
return nil
}

var (
keyCreateHelp = `
- Create a key with the name 'greg':
$ akash key create greg
Successfully created key for 'greg'
===================================
Public Key: f4e03226c054b1adafaa2739bad720c095500a49
Recovery Codes: figure share industry canal...
`

keyRecoverExample = `
- Recover a key with the name 'my-key':
$ akash key recover my-key today napkin arch \
picnic fox case thrive table journey ill \
any enforce awesome desert chapter regret \
narrow capable advice skull pipe giraffe \
clown outside
`
)
2 changes: 1 addition & 1 deletion cmd/akash/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func logsCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "logs <service> <lease>",
Short: "service logs",
Short: "Service logs",
Args: cobra.ExactArgs(2),
RunE: session.WithSession(session.RequireNode(logs)),
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/akash/marketplace.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func marketplaceCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "marketplace",
Short: "monitor marketplace",
Short: "Monitor marketplace",
Args: cobra.NoArgs,
RunE: session.WithSession(session.RequireNode(doMarketplaceMonitorCommand)),
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/akash/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func providerCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "provider",
Short: "manage provider",
Short: "Manage provider",
Args: cobra.ExactArgs(1),
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/akash/query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func QueryCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "query [something]",
Short: "query something",
Short: "Query something",
Args: cobra.ExactArgs(1),
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/akash/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func sendCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "send [amount] [to account]",
Short: "send tokens",
Short: "Send tokens",
Args: cobra.ExactArgs(2),
RunE: session.WithSession(
session.RequireKey(session.RequireNode(doSendCommand))),
Expand Down
2 changes: 2 additions & 0 deletions cmd/akash/session/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
flagNoWait = "no-wait"
flagHost = "host"
flagPassword = "password"
flagMode = "mode"
keyDir = "keys"

defaultKeyType = keys.Secp256k1
Expand All @@ -32,6 +33,7 @@ func SetupBaseCommand(cmd *cobra.Command) {
return initCommandConfig(root)
}
cmd.PersistentFlags().StringP(flagRootDir, "d", defaultRootDir(), "data directory")
cmd.PersistentFlags().StringP(flagMode, "m", "interactive", "output mode (interactive|text|json)")
}

func initCommandConfig(root string) error {
Expand Down
2 changes: 1 addition & 1 deletion cmd/akash/session/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func AddFlagNonce(cmd *cobra.Command, flags *pflag.FlagSet) {
}

func AddFlagKeyType(cmd *cobra.Command, flags *pflag.FlagSet) {
flags.StringP(flagKeyType, "t", string(defaultKeyType), "Type of key (secp256k1|ed25519|ledger)")
flags.StringP(flagKeyType, "t", string(defaultKeyType), "type of key (secp256k1|ed25519|ledger)")
}

func AddFlagWait(cmd *cobra.Command, flags *pflag.FlagSet) {
Expand Down
37 changes: 27 additions & 10 deletions cmd/akash/session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ovrclk/akash/cmd/common"
"github.com/ovrclk/akash/query"
"github.com/ovrclk/akash/txutil"
"github.com/ovrclk/akash/util/uiutil"

"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/spf13/cobra"
Expand All @@ -20,6 +21,9 @@ import (
tmclient "github.com/tendermint/tendermint/rpc/client"
)

// KeybaseName is the default name of the Keybase
var KeybaseName = "akash"

type Session interface {
RootDir() string
KeyManager() (keys.Keybase, error)
Expand All @@ -37,6 +41,7 @@ type Session interface {
NoWait() bool
Host() string
Password() (string, error)
Printer() uiutil.Printer
}

type cmdRunner func(cmd *cobra.Command, args []string) error
Expand All @@ -55,6 +60,13 @@ func WithSession(fn Runner) cmdRunner {
}
}

func WithPrinter(fn Runner) Runner {
return func(session Session, cmd *cobra.Command, args []string) error {
defer session.Printer().Flush()
return fn(session, cmd, args)
}
}

func RequireHost(fn Runner) Runner {
return func(session Session, cmd *cobra.Command, args []string) error {
if host := session.Host(); host == "" {
Expand Down Expand Up @@ -105,12 +117,13 @@ func newSession(ctx context.Context, cmd *cobra.Command) *session {
}

type session struct {
cmd *cobra.Command
kmgr keys.Keybase
kdb tmdb.DB
log log.Logger
ctx context.Context
mtx sync.Mutex
cmd *cobra.Command
kmgr keys.Keybase
kdb tmdb.DB
log log.Logger
ctx context.Context
mtx sync.Mutex
printer uiutil.Printer
}

func (s *session) shutdown() {
Expand Down Expand Up @@ -256,11 +269,8 @@ func (s *session) Ctx() context.Context {
}

func loadKeyManager(root string) (keys.Keybase, tmdb.DB, error) {

db := tmdb.NewDB(keyDir, tmdb.GoLevelDBBackend, root)
// TODO: Code review required
manager := keys.New("default", path.Join(root, keyDir))

manager := keys.New(KeybaseName, path.Join(root, keyDir))
return manager, db, nil
}

Expand All @@ -270,3 +280,10 @@ func (s *session) Host() string {
}
return viper.GetString(flagHost)
}

func (s *session) Printer() uiutil.Printer {
if s.printer == nil {
s.printer = uiutil.NewPrinter(nil)
}
return s.printer
}
2 changes: 1 addition & 1 deletion cmd/akash/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
func statusCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "status",
Short: "get remote node status",
Short: "Display node status",
Args: cobra.NoArgs,
RunE: session.WithSession(session.RequireNode(doStatusCommand)),
}
Expand Down
Loading

0 comments on commit 48c4583

Please sign in to comment.