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 }