github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/identity/keystore_mock.go (about)

     1  /*
     2   * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package identity
    19  
    20  import (
    21  	"crypto/ecdsa"
    22  	crand "crypto/rand"
    23  	"encoding/hex"
    24  	"sync"
    25  
    26  	"github.com/ethereum/go-ethereum/accounts"
    27  	ethKs "github.com/ethereum/go-ethereum/accounts/keystore"
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  )
    31  
    32  type mockKeystore struct {
    33  	keys map[common.Address]MockKey
    34  	lock sync.Mutex
    35  }
    36  
    37  // MockKeys represents the mocked keys
    38  var MockKeys = map[common.Address]MockKey{
    39  	common.HexToAddress("53a835143c0ef3bbcbfa796d7eb738ca7dd28f68"): {
    40  		PkHex: "6f88637b68ee88816e73f663aef709d7009836c98ae91ef31e3dfac7be3a1657",
    41  		Pass:  "",
    42  	},
    43  }
    44  
    45  // NewMockKeystore returns empty mock keystore
    46  func NewMockKeystore() *mockKeystore {
    47  	return NewMockKeystoreWith(map[common.Address]MockKey{})
    48  }
    49  
    50  // NewMockKeystoreWith returns a new mock keystore with specified keys
    51  func NewMockKeystoreWith(keys map[common.Address]MockKey) *mockKeystore {
    52  	copied := make(map[common.Address]MockKey)
    53  	for key, value := range keys {
    54  		copied[key] = value
    55  	}
    56  	return &mockKeystore{
    57  		keys: copied,
    58  	}
    59  }
    60  
    61  // MockKey represents a mocked key
    62  type MockKey struct {
    63  	PkHex      string
    64  	Pass       string
    65  	pk         *ecdsa.PrivateKey
    66  	isUnlocked bool
    67  }
    68  
    69  func (mk *mockKeystore) Accounts() []accounts.Account {
    70  	mk.lock.Lock()
    71  	defer mk.lock.Unlock()
    72  	res := make([]accounts.Account, 0)
    73  	for k := range mk.keys {
    74  		res = append(res, accounts.Account{
    75  			Address: k,
    76  		})
    77  	}
    78  	return res
    79  }
    80  
    81  func (mk *mockKeystore) SignHash(a accounts.Account, hash []byte) ([]byte, error) {
    82  	mk.lock.Lock()
    83  	defer mk.lock.Unlock()
    84  
    85  	if v, ok := mk.keys[a.Address]; ok {
    86  		if !v.isUnlocked {
    87  			return nil, ethKs.ErrLocked
    88  		}
    89  		return crypto.Sign(hash, v.pk)
    90  	}
    91  	return nil, ethKs.ErrNoMatch
    92  }
    93  
    94  func (mk *mockKeystore) Export(a accounts.Account, passphrase, newPassphrase string) (keyJSON []byte, err error) {
    95  	mk.lock.Lock()
    96  	defer mk.lock.Unlock()
    97  	if v, ok := mk.keys[a.Address]; ok {
    98  		if v.Pass != passphrase {
    99  			return nil, ethKs.ErrDecrypt
   100  		}
   101  		return common.Hex2Bytes(v.PkHex), nil
   102  	}
   103  	return nil, ethKs.ErrNoMatch
   104  }
   105  
   106  func (mk *mockKeystore) NewAccount(passphrase string) (accounts.Account, error) {
   107  	mk.lock.Lock()
   108  	defer mk.lock.Unlock()
   109  
   110  	privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), crand.Reader)
   111  	if err != nil {
   112  		return accounts.Account{}, err
   113  	}
   114  
   115  	address := crypto.PubkeyToAddress(privateKeyECDSA.PublicKey)
   116  	mk.keys[address] = MockKey{
   117  		Pass:       passphrase,
   118  		PkHex:      hex.EncodeToString(crypto.FromECDSA(privateKeyECDSA)),
   119  		pk:         privateKeyECDSA,
   120  		isUnlocked: false,
   121  	}
   122  	return accounts.Account{
   123  		Address: address,
   124  	}, nil
   125  }
   126  
   127  func (mk *mockKeystore) Unlock(a accounts.Account, passphrase string) error {
   128  	mk.lock.Lock()
   129  	defer mk.lock.Unlock()
   130  
   131  	if v, ok := mk.keys[a.Address]; ok {
   132  		if v.isUnlocked {
   133  			return nil
   134  		}
   135  
   136  		if v.Pass != passphrase {
   137  			return ethKs.ErrDecrypt
   138  		}
   139  
   140  		pk, err := crypto.HexToECDSA(v.PkHex)
   141  		if err != nil {
   142  			return err
   143  		}
   144  
   145  		v.isUnlocked = true
   146  		v.pk = pk
   147  		mk.keys[a.Address] = v
   148  		return nil
   149  	}
   150  
   151  	return ethKs.ErrNoMatch
   152  }
   153  
   154  func (mk *mockKeystore) Lock(addr common.Address) error {
   155  	mk.lock.Lock()
   156  	defer mk.lock.Unlock()
   157  
   158  	if v, ok := mk.keys[addr]; ok {
   159  		v.isUnlocked = false
   160  		mk.keys[addr] = v
   161  	}
   162  	return nil
   163  }
   164  
   165  func (mk *mockKeystore) Find(a accounts.Account) (accounts.Account, error) {
   166  	mk.lock.Lock()
   167  	defer mk.lock.Unlock()
   168  
   169  	if _, ok := mk.keys[a.Address]; ok {
   170  		return a, nil
   171  	}
   172  	return accounts.Account{}, ethKs.ErrNoMatch
   173  }
   174  
   175  // MockDecryptFunc represents the mock decrypt func
   176  var MockDecryptFunc = func(keyjson []byte, auth string) (*ethKs.Key, error) {
   177  	pk, err := crypto.HexToECDSA(common.Bytes2Hex(keyjson))
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	return &ethKs.Key{
   182  		PrivateKey: pk,
   183  	}, nil
   184  }