cli: implement wallet WIF/NEP2 export

One positional argument can be provided. If so, it is
interpreted as address and only WIFs corresponding to it
are exported. If address is provided '--decrypt' flag can be
specified to export unencrypted WIFs.
This commit is contained in:
Evgenii Stratonikov 2020-02-20 16:14:14 +03:00
parent a030411310
commit 20c98411fd

View file

@ -9,6 +9,7 @@ import (
"syscall" "syscall"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/encoding/address"
"github.com/CityOfZion/neo-go/pkg/wallet" "github.com/CityOfZion/neo-go/pkg/wallet"
"github.com/urfave/cli" "github.com/urfave/cli"
"golang.org/x/crypto/ssh/terminal" "golang.org/x/crypto/ssh/terminal"
@ -28,6 +29,10 @@ var (
Name: "wif", Name: "wif",
Usage: "WIF to import", Usage: "WIF to import",
} }
decryptFlag = cli.BoolFlag{
Name: "decrypt, d",
Usage: "Decrypt encrypted keys.",
}
) )
// NewCommands returns 'wallet' command. // NewCommands returns 'wallet' command.
@ -54,10 +59,17 @@ func NewCommands() []cli.Command {
Action: dumpWallet, Action: dumpWallet,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
cli.BoolFlag{ decryptFlag,
Name: "decrypt, d", },
Usage: "Decrypt encrypted keys.", },
}, {
Name: "export",
Usage: "export keys for address",
UsageText: "export --path <path> [--decrypt] [<address>]",
Action: exportKeys,
Flags: []cli.Flag{
walletPathFlag,
decryptFlag,
}, },
}, },
{ {
@ -96,6 +108,69 @@ func NewCommands() []cli.Command {
}} }}
} }
func exportKeys(ctx *cli.Context) error {
path := ctx.String("path")
if len(path) == 0 {
return cli.NewExitError(errNoPath, 1)
}
wall, err := wallet.NewWalletFromFile(path)
if err != nil {
return cli.NewExitError(err, 1)
}
var addr string
decrypt := ctx.Bool("decrypt")
if ctx.NArg() == 0 && decrypt {
return cli.NewExitError(errors.New("address must be provided if '--decrypt' flag is used"), 1)
} else if ctx.NArg() > 0 {
// check address format just to catch possible typos
addr = ctx.Args().First()
_, err := address.StringToUint160(addr)
if err != nil {
return cli.NewExitError(fmt.Errorf("can't parse address: %v", err), 1)
}
}
var wifs []string
loop:
for _, a := range wall.Accounts {
if addr != "" && a.Address != addr {
continue
}
for i := range wifs {
if a.EncryptedWIF == wifs[i] {
continue loop
}
}
wifs = append(wifs, a.EncryptedWIF)
}
for _, wif := range wifs {
if decrypt {
pass, err := readPassword("Enter password > ")
if err != nil {
return cli.NewExitError(err, 1)
}
pk, err := keys.NEP2Decrypt(wif, pass)
if err != nil {
return cli.NewExitError(err, 1)
}
wif = pk.WIF()
}
fmt.Println(wif)
}
return nil
}
func importMultisig(ctx *cli.Context) error { func importMultisig(ctx *cli.Context) error {
path := ctx.String("path") path := ctx.String("path")
if len(path) == 0 { if len(path) == 0 {