github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/client/keys/migrate.go (about)

     1  package keys
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  
     9  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags"
    10  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/input"
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/keys"
    12  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    13  
    14  	"github.com/pkg/errors"
    15  	"github.com/spf13/cobra"
    16  	"github.com/spf13/viper"
    17  )
    18  
    19  // migratePassphrase is used as a no-op migration key passphrase as a passphrase
    20  // is not needed for importing into the Keyring keystore.
    21  const migratePassphrase = "NOOP_PASSPHRASE"
    22  
    23  // MigrateCommand migrates key information from legacy keybase to OS secret store.
    24  func MigrateCommand() *cobra.Command {
    25  	cmd := &cobra.Command{
    26  		Use:   "migrate",
    27  		Short: "Migrate keys from the legacy (db-based) Keybase",
    28  		Long: `Migrate key information from the legacy (db-based) Keybase to the new keyring-based Keybase.
    29  For each key material entry, the command will prompt if the key should be skipped or not. If the key
    30  is not to be skipped, the passphrase must be entered. The key will only be migrated if the passphrase
    31  is correct. Otherwise, the command will exit and migration must be repeated.
    32  
    33  It is recommended to run in 'dry-run' mode first to verify all key migration material.
    34  `,
    35  		Args: cobra.ExactArgs(0),
    36  		RunE: runMigrateCmd,
    37  	}
    38  
    39  	cmd.Flags().Bool(flags.FlagDryRun, false, "Run migration without actually persisting any changes to the new Keybase")
    40  	return cmd
    41  }
    42  
    43  func runMigrateCmd(cmd *cobra.Command, args []string) error {
    44  	// instantiate legacy keybase
    45  	rootDir := viper.GetString(flags.FlagHome)
    46  	legacyKb, err := NewKeyBaseFromDir(rootDir)
    47  	if err != nil {
    48  		return err
    49  	}
    50  
    51  	// fetch list of keys from legacy keybase
    52  	oldKeys, err := legacyKb.List()
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	buf := bufio.NewReader(cmd.InOrStdin())
    58  	keyringServiceName := sdk.KeyringServiceName()
    59  
    60  	var (
    61  		tmpDir  string
    62  		keybase keys.Keybase
    63  	)
    64  
    65  	if viper.GetBool(flags.FlagDryRun) {
    66  		tmpDir, err = ioutil.TempDir("", "keybase-migrate-dryrun")
    67  		if err != nil {
    68  			return errors.Wrap(err, "failed to create temporary directory for dryrun migration")
    69  		}
    70  
    71  		defer os.RemoveAll(tmpDir)
    72  
    73  		keybase, err = keys.NewKeyring(keyringServiceName, "test", tmpDir, buf)
    74  	} else {
    75  		keybase, err = keys.NewKeyring(keyringServiceName, viper.GetString(flags.FlagKeyringBackend), rootDir, buf)
    76  	}
    77  	if err != nil {
    78  		return errors.Wrap(err, fmt.Sprintf(
    79  			"failed to initialize keybase for service %s at directory %s",
    80  			keyringServiceName, rootDir,
    81  		))
    82  	}
    83  
    84  	for _, key := range oldKeys {
    85  		legKeyInfo, err := legacyKb.Export(key.GetName())
    86  		if err != nil {
    87  			return err
    88  		}
    89  
    90  		keyName := key.GetName()
    91  		keyType := key.GetType()
    92  
    93  		// skip key if already migrated
    94  		if _, err := keybase.Get(keyName); err == nil {
    95  			cmd.PrintErrf("Key '%s (%s)' already exists; skipping ...\n", key.GetName(), keyType)
    96  			continue
    97  		}
    98  
    99  		cmd.PrintErrf("Migrating key: '%s (%s)' ...\n", key.GetName(), keyType)
   100  
   101  		// allow user to skip migrating specific keys
   102  		ok, err := input.GetConfirmation("Skip key migration?", buf)
   103  		if err != nil {
   104  			return err
   105  		}
   106  		if ok {
   107  			continue
   108  		}
   109  
   110  		if keyType != keys.TypeLocal {
   111  			if err := keybase.Import(keyName, legKeyInfo); err != nil {
   112  				return err
   113  			}
   114  
   115  			continue
   116  		}
   117  
   118  		password, err := input.GetPassword("Enter passphrase to decrypt key:", buf)
   119  		if err != nil {
   120  			return err
   121  		}
   122  
   123  		// NOTE: A passphrase is not actually needed here as when the key information
   124  		// is imported into the Keyring-based Keybase it only needs the password
   125  		// (see: writeLocalKey).
   126  		armoredPriv, err := legacyKb.ExportPrivKey(keyName, password, migratePassphrase)
   127  		if err != nil {
   128  			return err
   129  		}
   130  
   131  		if err := keybase.ImportPrivKey(keyName, armoredPriv, migratePassphrase); err != nil {
   132  			return err
   133  		}
   134  	}
   135  
   136  	return err
   137  }