github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/crypto/keys/client/export.go (about)

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"flag"
     7  	"fmt"
     8  	"os"
     9  
    10  	"github.com/gnolang/gno/tm2/pkg/commands"
    11  	"github.com/gnolang/gno/tm2/pkg/crypto/keys"
    12  )
    13  
    14  type ExportCfg struct {
    15  	RootCfg *BaseCfg
    16  
    17  	NameOrBech32 string
    18  	OutputPath   string
    19  	Unsafe       bool
    20  }
    21  
    22  func NewExportCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command {
    23  	cfg := &ExportCfg{
    24  		RootCfg: rootCfg,
    25  	}
    26  
    27  	return commands.NewCommand(
    28  		commands.Metadata{
    29  			Name:       "export",
    30  			ShortUsage: "export [flags]",
    31  			ShortHelp:  "exports private key armor",
    32  		},
    33  		cfg,
    34  		func(_ context.Context, args []string) error {
    35  			return execExport(cfg, io)
    36  		},
    37  	)
    38  }
    39  
    40  func (c *ExportCfg) RegisterFlags(fs *flag.FlagSet) {
    41  	fs.StringVar(
    42  		&c.NameOrBech32,
    43  		"key",
    44  		"",
    45  		"name or bech32 address of the private key",
    46  	)
    47  
    48  	fs.StringVar(
    49  		&c.OutputPath,
    50  		"output-path",
    51  		"",
    52  		"the desired output path for the armor file",
    53  	)
    54  
    55  	fs.BoolVar(
    56  		&c.Unsafe,
    57  		"unsafe",
    58  		false,
    59  		"export the private key armor as unencrypted",
    60  	)
    61  }
    62  
    63  func execExport(cfg *ExportCfg, io commands.IO) error {
    64  	// check keyname
    65  	if cfg.NameOrBech32 == "" {
    66  		return errors.New("key to be exported shouldn't be empty")
    67  	}
    68  
    69  	// Create a new instance of the key-base
    70  	kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.Home)
    71  	if err != nil {
    72  		return fmt.Errorf(
    73  			"unable to create a key base from directory %s, %w",
    74  			cfg.RootCfg.Home,
    75  			err,
    76  		)
    77  	}
    78  
    79  	// Get the key-base decrypt password
    80  	decryptPassword, err := io.GetPassword(
    81  		"Enter a passphrase to decrypt your private key from disk:",
    82  		cfg.RootCfg.InsecurePasswordStdin,
    83  	)
    84  	if err != nil {
    85  		return fmt.Errorf(
    86  			"unable to retrieve decrypt password from user, %w",
    87  			err,
    88  		)
    89  	}
    90  
    91  	var (
    92  		armor     string
    93  		exportErr error
    94  	)
    95  
    96  	if cfg.Unsafe {
    97  		// Generate the unencrypted armor
    98  		armor, exportErr = kb.ExportPrivKeyUnsafe(
    99  			cfg.NameOrBech32,
   100  			decryptPassword,
   101  		)
   102  
   103  		privk, err := kb.ExportPrivateKeyObject(cfg.NameOrBech32, decryptPassword)
   104  		if err != nil {
   105  			panic(err)
   106  		}
   107  
   108  		fmt.Printf("privk:\n%x\n", privk.Bytes())
   109  	} else {
   110  		// Get the armor encrypt password
   111  		encryptPassword, err := io.GetCheckPassword(
   112  			[2]string{
   113  				"Enter a passphrase to encrypt your private key armor:",
   114  				"Repeat the passphrase:",
   115  			},
   116  			cfg.RootCfg.InsecurePasswordStdin,
   117  		)
   118  		if err != nil {
   119  			return fmt.Errorf(
   120  				"unable to retrieve armor encrypt password from user, %w",
   121  				err,
   122  			)
   123  		}
   124  
   125  		// Generate the encrypted armor
   126  		armor, exportErr = kb.ExportPrivKey(
   127  			cfg.NameOrBech32,
   128  			decryptPassword,
   129  			encryptPassword,
   130  		)
   131  	}
   132  
   133  	if exportErr != nil {
   134  		return fmt.Errorf(
   135  			"unable to export the private key, %w",
   136  			exportErr,
   137  		)
   138  	}
   139  
   140  	// Write the armor to disk
   141  	if err := os.WriteFile(
   142  		cfg.OutputPath,
   143  		[]byte(armor),
   144  		0o644,
   145  	); err != nil {
   146  		return fmt.Errorf(
   147  			"unable to write encrypted armor to file, %w",
   148  			err,
   149  		)
   150  	}
   151  
   152  	io.Printfln("Private key armor successfully outputted to %s", cfg.OutputPath)
   153  
   154  	return nil
   155  }