Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
lmoe committed Jul 17, 2023
1 parent a384dba commit 78fe729
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 82 deletions.
12 changes: 8 additions & 4 deletions tools/wasp-cli/cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/iotaledger/wasp/packages/isc"
"github.com/iotaledger/wasp/packages/parameters"
"github.com/iotaledger/wasp/packages/testutil/privtangle/privtangledefaults"
"github.com/iotaledger/wasp/tools/wasp-cli/cli/keychain"
"github.com/iotaledger/wasp/tools/wasp-cli/log"
)

Expand Down Expand Up @@ -123,15 +124,13 @@ func L1FaucetAddress() string {
}

func GetToken(node string) string {
keyChain := NewKeyChain()
token, err := keyChain.GetJWTAuthToken(node)
token, err := keychain.GetJWTAuthToken(node)
log.Check(err)
return token
}

func SetToken(node, token string) {
keyChain := NewKeyChain()
err := keyChain.SetJWTAuthToken(node, token)
err := keychain.SetJWTAuthToken(node, token)
log.Check(err)
}

Expand Down Expand Up @@ -193,3 +192,8 @@ func GetWalletSchemeString() string {
func SetWalletSchemeString(scheme string) {
Set("wallet.scheme", scheme)
}

// GetSeedForMigration is used to migrate the seed of the config file to a certain wallet provider.
func GetSeedForMigration() string {
return viper.GetString("wallet.seed")
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package config
package keychain

import (
"errors"
"fmt"
"runtime"

"github.com/99designs/keyring"
"github.com/awnumar/memguard"

"github.com/iotaledger/wasp/packages/cryptolib"
)
Expand All @@ -22,31 +24,41 @@ var (
ErrSeedDoesNotMatchLength = errors.New("returned seed does not have a valid length")
)

type KeyChain struct {
type keyChain struct {
Keyring keyring.Keyring
}

func NewKeyChain() *KeyChain {
func newKeyRing() *keyChain {
ring, _ := keyring.Open(keyring.Config{
ServiceName: "IOTAFoundation.WaspCLI",
})

return &KeyChain{
return &keyChain{
Keyring: ring,
}
}

func (k *KeyChain) SetSeed(seed cryptolib.Seed) error {
err := k.Keyring.Set(keyring.Item{
func (k *keyChain) Close() {
runtime.KeepAlive(k.Keyring)
k.Keyring = nil
}

func SetSeed(seed cryptolib.Seed) error {
store := newKeyRing()
defer store.Close()

err := store.Keyring.Set(keyring.Item{
Key: seedKey,
Data: seed[:],
})

return err
}

func (k *KeyChain) GetSeed() (*cryptolib.Seed, error) {
seedItem, err := k.Keyring.Get(seedKey)
func GetSeed() (*cryptolib.Seed, error) {
store := newKeyRing()
defer store.Close()

seedItem, err := store.Keyring.Get(seedKey)
if errors.Is(err, keyring.ErrKeyNotFound) {
return nil, ErrSeedDoesNotExist
}
Expand All @@ -64,35 +76,53 @@ func (k *KeyChain) GetSeed() (*cryptolib.Seed, error) {
return &seed, nil
}

func (k *KeyChain) SetStrongholdPassword(password string) error {
return k.Keyring.Set(keyring.Item{
func SetStrongholdPassword(password *memguard.Enclave) error {
store := newKeyRing()
defer store.Close()

buffer, err := password.Open()
if err != nil {
return err
}
defer buffer.Destroy()

return store.Keyring.Set(keyring.Item{
Key: strongholdKey,
Data: []byte(password),
Data: buffer.Data(),
})
}

func (k *KeyChain) GetStrongholdPassword() (string, error) {
seedItem, err := k.Keyring.Get(strongholdKey)
func GetStrongholdPassword() (*memguard.Enclave, error) {
store := newKeyRing()
defer store.Close()

seedItem, err := store.Keyring.Get(strongholdKey)
if errors.Is(err, keyring.ErrKeyNotFound) {
return "", ErrPasswordDoesNotExist
return nil, ErrPasswordDoesNotExist
}

return string(seedItem.Data), nil
return memguard.NewEnclave(seedItem.Data), nil
}

func jwtTokenKey(node string) string {
return fmt.Sprintf("%s.%s", jwtTokenKeyPrefix, node)
}

func (k *KeyChain) SetJWTAuthToken(node string, token string) error {
return k.Keyring.Set(keyring.Item{
func SetJWTAuthToken(node string, token string) error {
store := newKeyRing()
defer store.Close()

return store.Keyring.Set(keyring.Item{
Key: jwtTokenKey(node),
Data: []byte(token),
})
}

func (k *KeyChain) GetJWTAuthToken(node string) (string, error) {
seedItem, err := k.Keyring.Get(jwtTokenKey(node))
func GetJWTAuthToken(node string) (string, error) {
store := newKeyRing()
defer store.Close()

seedItem, err := store.Keyring.Get(jwtTokenKey(node))
// Special case. If the key is not found, return an empty token.
if errors.Is(err, keyring.ErrKeyNotFound) {
return "", nil
Expand Down
101 changes: 101 additions & 0 deletions tools/wasp-cli/cli/keychain/keychain_zalando_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package keychain

import (
"errors"
"fmt"
"unsafe"

"github.com/awnumar/memguard"
"github.com/zalando/go-keyring"

iotago "github.com/iotaledger/iota.go/v3"
"github.com/iotaledger/wasp/packages/cryptolib"
)

const (
strongholdKey = "wasp-cli.stronghold.key"
jwtTokenKeyPrefix = "wasp-cli.auth.jwt"
seedKey = "wasp-cli.seed"
)

var (
ErrTokenDoesNotExist = errors.New("jwt token not found, call 'login'")
ErrPasswordDoesNotExist = errors.New("stronghold entry not found, call 'init'")
ErrSeedDoesNotExist = errors.New("seed not found, call 'init'")
ErrSeedDoesNotMatchLength = errors.New("returned seed does not have a valid length")
)

const WaspCliServiceName = "IOTAFoundation.WaspCLI"

func SetSeed(seed cryptolib.Seed) error {
err := keyring.Set(WaspCliServiceName, seedKey, iotago.EncodeHex(seed[:]))
return err
}

func GetSeed() (*cryptolib.Seed, error) {
seedItem, err := keyring.Get(WaspCliServiceName, seedKey)
if errors.Is(err, keyring.ErrNotFound) {
return nil, ErrSeedDoesNotExist
}
if err != nil {
return nil, err
}

seedBytes, err := iotago.DecodeHex(seedItem)
if len(seedBytes) != cryptolib.SeedSize {
return nil, ErrSeedDoesNotMatchLength
}

seed := cryptolib.SeedFromBytes(seedBytes)
return &seed, nil
}

func SetStrongholdPassword(password *memguard.Enclave) error {
buffer, err := password.Open()
if err != nil {
return err
}
defer buffer.Destroy()

return keyring.Set(WaspCliServiceName, strongholdKey, buffer.String())
}

func GetStrongholdPassword() (*memguard.Enclave, error) {
enclave, err := Get("service", "user")
if err != nil {
panic(err)
}

secretPassword, err := enclave.Open()
if err != nil {
panic(err)
}
defer secretPassword.Destroy()

seedItem, err := keyring.Get(WaspCliServiceName, strongholdKey)
if errors.Is(err, keyring.ErrNotFound) {
return nil, ErrPasswordDoesNotExist
}

memguard.WipeBytes(*(*[]byte)(unsafe.Pointer(&seedItem)))

return memguard.NewEnclave([]byte(seedItem)), nil
}

func jwtTokenKey(node string) string {
return fmt.Sprintf("%s.%s", jwtTokenKeyPrefix, node)
}

func SetJWTAuthToken(node string, token string) error {
return keyring.Set(WaspCliServiceName, jwtTokenKey(node), token)
}

func GetJWTAuthToken(node string) (string, error) {
seedItem, err := keyring.Get(WaspCliServiceName, jwtTokenKey(node))
// Special case. If the key is not found, return an empty token.
if errors.Is(err, keyring.ErrNotFound) {
return "", nil
}

return seedItem, nil
}
49 changes: 49 additions & 0 deletions tools/wasp-cli/cli/test/wallet_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package test

import (
"fmt"
"os"
"path"
"testing"

"github.com/awnumar/memguard"
"github.com/stretchr/testify/require"
"github.com/tyler-smith/go-bip39"

iotago "github.com/iotaledger/iota.go/v3"
wasp_wallet_sdk "github.com/iotaledger/wasp-wallet-sdk"
"github.com/iotaledger/wasp-wallet-sdk/types"
"github.com/iotaledger/wasp/packages/cryptolib"
)

func TestMnemonic(t *testing.T) {
seedBytes, _ := iotago.DecodeHex("0xbc278147b72c6af948eced45252c496901e194c9610bfbffea639e18769c7715")
seed := cryptolib.SeedFromBytes(seedBytes)
kp := cryptolib.KeyPairFromSeed(seed)
address := kp.Address().Bech32("rms")
require.Equal(t, address, "rms1qzy0uqyzcm6asngsjxwc76nuar479uukvxa4dapzaz8fx5e3234wxw5mlmz")
fmt.Println(address)

mnemonic, err := bip39.NewMnemonic(seed[:])
require.NoError(t, err)

cwd, err := os.Getwd()
require.NoError(t, err)

sdk, err := wasp_wallet_sdk.NewIotaSDK(path.Join(cwd, "../../../../libiota_sdk_native.so"))
require.NoError(t, err)

manager, err := wasp_wallet_sdk.NewStrongholdSecretManager(sdk, memguard.NewEnclaveRandom(32), "./test.snapshot")
defer os.Remove("./test.snapshot")

require.NoError(t, err)

mnemonicBytes := []byte(mnemonic)
success, err := manager.StoreMnemonic(memguard.NewEnclave(mnemonicBytes))
require.NoError(t, err)
require.True(t, success)

strongholdAddress, err := manager.GenerateEd25519Address(0, 0, "rms", types.CoinTypeSMR, nil)
require.NoError(t, err)
fmt.Println(strongholdAddress)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,46 @@ package providers

import (
"github.com/iotaledger/wasp/packages/cryptolib"
"github.com/iotaledger/wasp/tools/wasp-cli/cli/config"
"github.com/iotaledger/wasp/tools/wasp-cli/cli/keychain"
"github.com/iotaledger/wasp/tools/wasp-cli/cli/wallet/wallets"
"github.com/iotaledger/wasp/tools/wasp-cli/log"
)

type InMemoryWallet struct {
type KeyChainWallet struct {
cryptolib.VariantKeyPair
addressIndex uint32
}

func newInMemoryWallet(keyPair *cryptolib.KeyPair, addressIndex uint32) *InMemoryWallet {
return &InMemoryWallet{
func newInMemoryWallet(keyPair *cryptolib.KeyPair, addressIndex uint32) *KeyChainWallet {
return &KeyChainWallet{
VariantKeyPair: keyPair,
addressIndex: addressIndex,
}
}

func (i *InMemoryWallet) AddressIndex() uint32 {
func (i *KeyChainWallet) AddressIndex() uint32 {
return i.addressIndex
}

func LoadInMemory(addressIndex uint32) wallets.Wallet {
keyChain := config.NewKeyChain()
seed, err := keyChain.GetSeed()
func LoadKeyChain(addressIndex uint32) wallets.Wallet {
seed, err := keychain.GetSeed()
log.Check(err)

keyPair := cryptolib.KeyPairFromSeed(seed.SubSeed(uint64(addressIndex)))

return newInMemoryWallet(keyPair, addressIndex)
}

func CreateNewInMemory() {
keyChain := config.NewKeyChain()
func CreateKeyChain() {
seed := cryptolib.NewSeed()
err := keyChain.SetSeed(seed)
err := keychain.SetSeed(seed)
log.Check(err)

log.Printf("In memory seed saved in the keychain.\n")
log.Printf("Seed stored in the keychain.\n")
}

func MigrateKeyChain(seed cryptolib.Seed) {
err := keychain.SetSeed(seed)
log.Check(err)
log.Printf("Seed migrated to keychain")
}
4 changes: 1 addition & 3 deletions tools/wasp-cli/cli/wallet/providers/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import (
)

func LoadLedgerWallet(sdk *walletsdk.IOTASDK, addressIndex uint32) wallets.Wallet {
secretManager, err := walletsdk.NewLedgerSecretManager(sdk, types.LedgerNanoSecretManager{
LedgerNano: false,
})
secretManager, err := walletsdk.NewLedgerSecretManager(sdk, false)
log.Check(err)

status, err := secretManager.GetLedgerStatus()
Expand Down
Loading

0 comments on commit 78fe729

Please sign in to comment.