github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/mobile/accounts.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 // Contains all the wrappers from the accounts package to support client side key 13 // management on mobile platforms. 14 15 package geth 16 17 import ( 18 "errors" 19 "time" 20 21 "github.com/Sberex/go-sberex/accounts" 22 "github.com/Sberex/go-sberex/accounts/keystore" 23 "github.com/Sberex/go-sberex/common" 24 "github.com/Sberex/go-sberex/crypto" 25 ) 26 27 const ( 28 // StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB 29 // memory and taking approximately 1s CPU time on a modern processor. 30 StandardScryptN = int(keystore.StandardScryptN) 31 32 // StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB 33 // memory and taking approximately 1s CPU time on a modern processor. 34 StandardScryptP = int(keystore.StandardScryptP) 35 36 // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB 37 // memory and taking approximately 100ms CPU time on a modern processor. 38 LightScryptN = int(keystore.LightScryptN) 39 40 // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB 41 // memory and taking approximately 100ms CPU time on a modern processor. 42 LightScryptP = int(keystore.LightScryptP) 43 ) 44 45 // Account represents a stored key. 46 type Account struct{ account accounts.Account } 47 48 // Accounts represents a slice of accounts. 49 type Accounts struct{ accounts []accounts.Account } 50 51 // Size returns the number of accounts in the slice. 52 func (a *Accounts) Size() int { 53 return len(a.accounts) 54 } 55 56 // Get returns the account at the given index from the slice. 57 func (a *Accounts) Get(index int) (account *Account, _ error) { 58 if index < 0 || index >= len(a.accounts) { 59 return nil, errors.New("index out of bounds") 60 } 61 return &Account{a.accounts[index]}, nil 62 } 63 64 // Set sets the account at the given index in the slice. 65 func (a *Accounts) Set(index int, account *Account) error { 66 if index < 0 || index >= len(a.accounts) { 67 return errors.New("index out of bounds") 68 } 69 a.accounts[index] = account.account 70 return nil 71 } 72 73 // GetAddress retrieves the address associated with the account. 74 func (a *Account) GetAddress() *Address { 75 return &Address{a.account.Address} 76 } 77 78 // GetURL retrieves the canonical URL of the account. 79 func (a *Account) GetURL() string { 80 return a.account.URL.String() 81 } 82 83 // KeyStore manages a key storage directory on disk. 84 type KeyStore struct{ keystore *keystore.KeyStore } 85 86 // NewKeyStore creates a keystore for the given directory. 87 func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore { 88 return &KeyStore{keystore: keystore.NewKeyStore(keydir, scryptN, scryptP)} 89 } 90 91 // HasAddress reports whether a key with the given address is present. 92 func (ks *KeyStore) HasAddress(address *Address) bool { 93 return ks.keystore.HasAddress(address.address) 94 } 95 96 // GetAccounts returns all key files present in the directory. 97 func (ks *KeyStore) GetAccounts() *Accounts { 98 return &Accounts{ks.keystore.Accounts()} 99 } 100 101 // DeleteAccount deletes the key matched by account if the passphrase is correct. 102 // If a contains no filename, the address must match a unique key. 103 func (ks *KeyStore) DeleteAccount(account *Account, passphrase string) error { 104 return ks.keystore.Delete(account.account, passphrase) 105 } 106 107 // SignHash calculates a ECDSA signature for the given hash. The produced signature 108 // is in the [R || S || V] format where V is 0 or 1. 109 func (ks *KeyStore) SignHash(address *Address, hash []byte) (signature []byte, _ error) { 110 return ks.keystore.SignHash(accounts.Account{Address: address.address}, common.CopyBytes(hash)) 111 } 112 113 // SignTx signs the given transaction with the requested account. 114 func (ks *KeyStore) SignTx(account *Account, tx *Transaction, chainID *BigInt) (*Transaction, error) { 115 if chainID == nil { // Null passed from mobile app 116 chainID = new(BigInt) 117 } 118 signed, err := ks.keystore.SignTx(account.account, tx.tx, chainID.bigint) 119 if err != nil { 120 return nil, err 121 } 122 return &Transaction{signed}, nil 123 } 124 125 // SignHashPassphrase signs hash if the private key matching the given address can 126 // be decrypted with the given passphrase. The produced signature is in the 127 // [R || S || V] format where V is 0 or 1. 128 func (ks *KeyStore) SignHashPassphrase(account *Account, passphrase string, hash []byte) (signature []byte, _ error) { 129 return ks.keystore.SignHashWithPassphrase(account.account, passphrase, common.CopyBytes(hash)) 130 } 131 132 // SignTxPassphrase signs the transaction if the private key matching the 133 // given address can be decrypted with the given passphrase. 134 func (ks *KeyStore) SignTxPassphrase(account *Account, passphrase string, tx *Transaction, chainID *BigInt) (*Transaction, error) { 135 if chainID == nil { // Null passed from mobile app 136 chainID = new(BigInt) 137 } 138 signed, err := ks.keystore.SignTxWithPassphrase(account.account, passphrase, tx.tx, chainID.bigint) 139 if err != nil { 140 return nil, err 141 } 142 return &Transaction{signed}, nil 143 } 144 145 // Unlock unlocks the given account indefinitely. 146 func (ks *KeyStore) Unlock(account *Account, passphrase string) error { 147 return ks.keystore.TimedUnlock(account.account, passphrase, 0) 148 } 149 150 // Lock removes the private key with the given address from memory. 151 func (ks *KeyStore) Lock(address *Address) error { 152 return ks.keystore.Lock(address.address) 153 } 154 155 // TimedUnlock unlocks the given account with the passphrase. The account stays 156 // unlocked for the duration of timeout (nanoseconds). A timeout of 0 unlocks the 157 // account until the program exits. The account must match a unique key file. 158 // 159 // If the account address is already unlocked for a duration, TimedUnlock extends or 160 // shortens the active unlock timeout. If the address was previously unlocked 161 // indefinitely the timeout is not altered. 162 func (ks *KeyStore) TimedUnlock(account *Account, passphrase string, timeout int64) error { 163 return ks.keystore.TimedUnlock(account.account, passphrase, time.Duration(timeout)) 164 } 165 166 // NewAccount generates a new key and stores it into the key directory, 167 // encrypting it with the passphrase. 168 func (ks *KeyStore) NewAccount(passphrase string) (*Account, error) { 169 account, err := ks.keystore.NewAccount(passphrase) 170 if err != nil { 171 return nil, err 172 } 173 return &Account{account}, nil 174 } 175 176 // UpdateAccount changes the passphrase of an existing account. 177 func (ks *KeyStore) UpdateAccount(account *Account, passphrase, newPassphrase string) error { 178 return ks.keystore.Update(account.account, passphrase, newPassphrase) 179 } 180 181 // ExportKey exports as a JSON key, encrypted with newPassphrase. 182 func (ks *KeyStore) ExportKey(account *Account, passphrase, newPassphrase string) (key []byte, _ error) { 183 return ks.keystore.Export(account.account, passphrase, newPassphrase) 184 } 185 186 // ImportKey stores the given encrypted JSON key into the key directory. 187 func (ks *KeyStore) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (account *Account, _ error) { 188 acc, err := ks.keystore.Import(common.CopyBytes(keyJSON), passphrase, newPassphrase) 189 if err != nil { 190 return nil, err 191 } 192 return &Account{acc}, nil 193 } 194 195 // ImportECDSAKey stores the given encrypted JSON key into the key directory. 196 func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Account, _ error) { 197 privkey, err := crypto.ToECDSA(common.CopyBytes(key)) 198 if err != nil { 199 return nil, err 200 } 201 acc, err := ks.keystore.ImportECDSA(privkey, passphrase) 202 if err != nil { 203 return nil, err 204 } 205 return &Account{acc}, nil 206 } 207 208 // ImportPreSaleKey decrypts the given Sberex presale wallet and stores 209 // a key file in the key directory. The key file is encrypted with the same passphrase. 210 func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (ccount *Account, _ error) { 211 account, err := ks.keystore.ImportPreSaleKey(common.CopyBytes(keyJSON), passphrase) 212 if err != nil { 213 return nil, err 214 } 215 return &Account{account}, nil 216 }