Skip to content

Commit

Permalink
feat(cmd/wallet): Import key from PEM file
Browse files Browse the repository at this point in the history
  • Loading branch information
matevz committed Oct 19, 2023
1 parent 29c7813 commit e8d552c
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 11 deletions.
14 changes: 11 additions & 3 deletions cmd/wallet/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ var createCmd = &cobra.Command{
cfg := config.Global()
name := args[0]

checkAccountExists(cfg, name)

af, err := wallet.Load(accKind)
cobra.CheckErr(err)

Expand All @@ -37,9 +39,6 @@ var createCmd = &cobra.Command{
err = accCfg.SetConfigFromFlags()
cobra.CheckErr(err)

if _, exists := cfg.AddressBook.All[name]; exists {
cobra.CheckErr(fmt.Errorf("address named '%s' already exists in address book", name))
}
err = cfg.Wallet.Create(name, passphrase, accCfg)
cobra.CheckErr(err)

Expand All @@ -48,6 +47,15 @@ var createCmd = &cobra.Command{
},
}

func checkAccountExists(cfg *config.Config, name string) {
if _, exists := cfg.Wallet.All[name]; exists {
cobra.CheckErr(fmt.Errorf("account '%s' already exists in the wallet", name))
}
if _, exists := cfg.AddressBook.All[name]; exists {
cobra.CheckErr(fmt.Errorf("address named '%s' already exists in the address book", name))
}
}

func init() {
flags := flag.NewFlagSet("", flag.ContinueOnError)
kinds := make([]string, 0, len(wallet.AvailableKinds()))
Expand Down
9 changes: 1 addition & 8 deletions cmd/wallet/import.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package wallet

import (
"fmt"

"github.com/AlecAivazis/survey/v2"
"github.com/spf13/cobra"

Expand All @@ -20,12 +18,7 @@ var importCmd = &cobra.Command{
cfg := config.Global()
name := args[0]

if _, exists := cfg.Wallet.All[name]; exists {
cobra.CheckErr(fmt.Errorf("account '%s' already exists in the wallet", name))
}
if _, exists := cfg.AddressBook.All[name]; exists {
cobra.CheckErr(fmt.Errorf("address named '%s' already exists in the address book", name))
}
checkAccountExists(cfg, name)

// NOTE: We only support importing into the file-based wallet for now.
af, err := wallet.Load(walletFile.Kind)
Expand Down
88 changes: 88 additions & 0 deletions cmd/wallet/import_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package wallet

import (
"encoding/base64"
"encoding/hex"
"encoding/pem"
"fmt"
"os"

"github.com/spf13/cobra"

"github.com/oasisprotocol/cli/cmd/common"
"github.com/oasisprotocol/cli/config"
"github.com/oasisprotocol/cli/wallet"
walletFile "github.com/oasisprotocol/cli/wallet/file"
)

var importFileCmd = &cobra.Command{
Use: "import-file <file_name> <account_name>",
Short: "Import an existing account from file",
Long: "Import the private key from an existing PEM file",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
cfg := config.Global()
filename := args[0]
name := args[1]

checkAccountExists(cfg, name)

rawFile, err := os.ReadFile(filename)
cobra.CheckErr(err)

block, _ := pem.Decode(rawFile)
if block == nil {

Check failure on line 34 in cmd/wallet/import_file.go

View workflow job for this annotation

GitHub Actions / lint

SA5011(related information): this check suggests that the pointer can be nil (staticcheck)
cobra.CheckErr(fmt.Errorf("failed to decode PEM file"))
}

algorithm, err := detectAlgorithm(block.Type)

Check failure on line 38 in cmd/wallet/import_file.go

View workflow job for this annotation

GitHub Actions / lint

SA5011: possible nil pointer dereference (staticcheck)
cobra.CheckErr(err)

// Ask for passphrase.
passphrase := common.AskNewPassphrase()

accCfg := &config.Account{
Kind: walletFile.Kind,
Config: map[string]interface{}{
"algorithm": algorithm,
},
}

src := &wallet.ImportSource{
Kind: wallet.ImportKindPrivateKey,
Data: encodeKeyData(algorithm, block.Bytes),

Check failure on line 53 in cmd/wallet/import_file.go

View workflow job for this annotation

GitHub Actions / lint

SA5011: possible nil pointer dereference (staticcheck)
}

err = cfg.Wallet.Import(name, passphrase, accCfg, src)
cobra.CheckErr(err)

err = cfg.Save()
cobra.CheckErr(err)
},
}

// detectAlgorithm detects the key type based on the PEM type.
func detectAlgorithm(pemType string) (string, error) {
switch pemType {
case "ED25519 PRIVATE KEY":
return wallet.AlgorithmEd25519Raw, nil
case "EC PRIVATE KEY":
return wallet.AlgorithmSecp256k1Raw, nil
case "SR25519 PRIVATE KEY":
return wallet.AlgorithmSr25519Raw, nil
}

return "", fmt.Errorf("unsupported PEM type: %s", pemType)
}

// encodeKeyData re-encodes the key in raw bytes back to the user-readable string for import.
func encodeKeyData(algorithm string, rawKey []byte) string {
switch algorithm {
case wallet.AlgorithmEd25519Raw, wallet.AlgorithmSr25519Raw:
return base64.StdEncoding.EncodeToString(rawKey)
case wallet.AlgorithmSecp256k1Raw:
return hex.EncodeToString(rawKey)
}

return ""
}
1 change: 1 addition & 0 deletions cmd/wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func init() {
Cmd.AddCommand(renameCmd)
Cmd.AddCommand(setDefaultCmd)
Cmd.AddCommand(importCmd)
Cmd.AddCommand(importFileCmd)
Cmd.AddCommand(exportCmd)
Cmd.AddCommand(remoteSignerCmd)
}

0 comments on commit e8d552c

Please sign in to comment.