github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/cmd/gwan/accountcmd.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum 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 // go-ethereum 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 go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 23 "github.com/wanchain/go-wanchain/accounts" 24 "github.com/wanchain/go-wanchain/accounts/keystore" 25 "github.com/wanchain/go-wanchain/cmd/utils" 26 "github.com/wanchain/go-wanchain/console" 27 "github.com/wanchain/go-wanchain/log" 28 "gopkg.in/urfave/cli.v1" 29 ) 30 31 var ( 32 walletCommand = cli.Command{ 33 Name: "wallet", 34 Usage: "Manage Ethereum presale wallets", 35 ArgsUsage: "", 36 Category: "ACCOUNT COMMANDS", 37 Description: ` 38 geth wallet import /path/to/my/presale.wallet 39 40 will prompt for your password and imports your ether presale account. 41 It can be used non-interactively with the --password option taking a 42 passwordfile as argument containing the wallet password in plaintext.`, 43 Subcommands: []cli.Command{ 44 { 45 46 Name: "import", 47 Usage: "Import Ethereum presale wallet", 48 ArgsUsage: "<keyFile>", 49 Action: utils.MigrateFlags(importWallet), 50 Category: "ACCOUNT COMMANDS", 51 Flags: []cli.Flag{ 52 utils.DataDirFlag, 53 utils.KeyStoreDirFlag, 54 utils.PasswordFileFlag, 55 utils.LightKDFFlag, 56 }, 57 Description: ` 58 geth wallet [options] /path/to/my/presale.wallet 59 60 will prompt for your password and imports your ether presale account. 61 It can be used non-interactively with the --password option taking a 62 passwordfile as argument containing the wallet password in plaintext.`, 63 }, 64 }, 65 } 66 67 accountCommand = cli.Command{ 68 Name: "account", 69 Usage: "Manage accounts", 70 Category: "ACCOUNT COMMANDS", 71 Description: ` 72 73 Manage accounts, list all existing accounts, import a private key into a new 74 account, create a new account or update an existing account. 75 76 It supports interactive mode, when you are prompted for password as well as 77 non-interactive mode where passwords are supplied via a given password file. 78 Non-interactive mode is only meant for scripted use on test networks or known 79 safe environments. 80 81 Make sure you remember the password you gave when creating a new account (with 82 either new or import). Without it you are not able to unlock your account. 83 84 Note that exporting your key in unencrypted format is NOT supported. 85 86 Keys are stored under <DATADIR>/keystore. 87 It is safe to transfer the entire directory or the individual keys therein 88 between ethereum nodes by simply copying. 89 90 Make sure you backup your keys regularly.`, 91 Subcommands: []cli.Command{ 92 { 93 Name: "list", 94 Usage: "Print summary of existing accounts", 95 Action: utils.MigrateFlags(accountList), 96 Flags: []cli.Flag{ 97 utils.DataDirFlag, 98 utils.KeyStoreDirFlag, 99 }, 100 Description: ` 101 Print a short summary of all accounts`, 102 }, 103 { 104 Name: "new", 105 Usage: "Create a new account", 106 Action: utils.MigrateFlags(accountCreate), 107 Flags: []cli.Flag{ 108 utils.DataDirFlag, 109 utils.KeyStoreDirFlag, 110 utils.PasswordFileFlag, 111 utils.LightKDFFlag, 112 }, 113 Description: ` 114 geth account new 115 116 Creates a new account and prints the address. 117 118 The account is saved in encrypted format, you are prompted for a passphrase. 119 120 You must remember this passphrase to unlock your account in the future. 121 122 For non-interactive use the passphrase can be specified with the --password flag: 123 124 Note, this is meant to be used for testing only, it is a bad idea to save your 125 password to file or expose in any other way. 126 `, 127 }, 128 { 129 Name: "update", 130 Usage: "Update an existing account", 131 Action: utils.MigrateFlags(accountUpdate), 132 ArgsUsage: "<address>", 133 Flags: []cli.Flag{ 134 utils.DataDirFlag, 135 utils.KeyStoreDirFlag, 136 utils.LightKDFFlag, 137 }, 138 Description: ` 139 geth account update <address> 140 141 Update an existing account. 142 143 The account is saved in the newest version in encrypted format, you are prompted 144 for a passphrase to unlock the account and another to save the updated file. 145 146 This same command can therefore be used to migrate an account of a deprecated 147 format to the newest format or change the password for an account. 148 149 For non-interactive use the passphrase can be specified with the --password flag: 150 151 geth account update [options] <address> 152 153 Since only one password can be given, only format update can be performed, 154 changing your password is only possible interactively. 155 `, 156 }, 157 { 158 Name: "import", 159 Usage: "Import a private key into a new account", 160 Action: utils.MigrateFlags(accountImport), 161 Flags: []cli.Flag{ 162 utils.DataDirFlag, 163 utils.KeyStoreDirFlag, 164 utils.PasswordFileFlag, 165 utils.LightKDFFlag, 166 }, 167 ArgsUsage: "<keyFile>", 168 Description: ` 169 geth account import <keyfile> 170 171 Imports an unencrypted private key from <keyfile> and creates a new account. 172 Prints the address. 173 174 The keyfile is assumed to be a json file which contains an unencrypted private key pair in hexencoded string format. 175 176 The account is saved in encrypted format, you are prompted for a passphrase. 177 178 You must remember this passphrase to unlock your account in the future. 179 180 For non-interactive use the passphrase can be specified with the -password flag: 181 182 geth account import [options] <keyfile> 183 184 Note: 185 As you can directly copy your encrypted accounts to another ethereum instance, 186 this import mechanism is not needed when you transfer an account between 187 nodes. 188 `, 189 }, 190 }, 191 } 192 ) 193 194 func accountList(ctx *cli.Context) error { 195 stack, _ := makeConfigNode(ctx) 196 var index int 197 for _, wallet := range stack.AccountManager().Wallets() { 198 for _, account := range wallet.Accounts() { 199 fmt.Printf("Account #%d: {%x} %s\n", index, account.Address, &account.URL) 200 index++ 201 } 202 } 203 return nil 204 } 205 206 // tries unlocking the specified account a few times. 207 func unlockAccount(ctx *cli.Context, ks *keystore.KeyStore, address string, i int, passwords []string) (accounts.Account, string) { 208 account, err := utils.MakeAddress(ks, address) 209 if err != nil { 210 utils.Fatalf("Could not list accounts: %v", err) 211 } 212 for trials := 0; trials < 3; trials++ { 213 prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3) 214 password := getPassPhrase(prompt, false, i, passwords) 215 err = ks.Unlock(account, password) 216 if err == nil { 217 log.Info("Unlocked account", "address", account.Address.Hex()) 218 return account, password 219 } 220 if err, ok := err.(*keystore.AmbiguousAddrError); ok { 221 log.Info("Unlocked account", "address", account.Address.Hex()) 222 return ambiguousAddrRecovery(ks, err, password), password 223 } 224 if err != keystore.ErrDecrypt { 225 // No need to prompt again if the error is not decryption-related. 226 break 227 } 228 } 229 // All trials expended to unlock account, bail out 230 utils.Fatalf("Failed to unlock account %s (%v)", address, err) 231 232 return accounts.Account{}, "" 233 } 234 235 // getPassPhrase retrieves the password associated with an account, either fetched 236 // from a list of preloaded passphrases, or requested interactively from the user. 237 func getPassPhrase(prompt string, confirmation bool, i int, passwords []string) string { 238 // If a list of passwords was supplied, retrieve from them 239 if len(passwords) > 0 { 240 if i < len(passwords) { 241 return passwords[i] 242 } 243 return passwords[len(passwords)-1] 244 } 245 // Otherwise prompt the user for the password 246 if prompt != "" { 247 fmt.Println(prompt) 248 } 249 password, err := console.Stdin.PromptPassword("Passphrase: ") 250 if err != nil { 251 utils.Fatalf("Failed to read passphrase: %v", err) 252 } 253 if confirmation { 254 confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ") 255 if err != nil { 256 utils.Fatalf("Failed to read passphrase confirmation: %v", err) 257 } 258 if password != confirm { 259 utils.Fatalf("Passphrases do not match") 260 } 261 } 262 return password 263 } 264 265 func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrError, auth string) accounts.Account { 266 fmt.Printf("Multiple key files exist for address %x:\n", err.Addr) 267 for _, a := range err.Matches { 268 fmt.Println(" ", a.URL) 269 } 270 fmt.Println("Testing your passphrase against all of them...") 271 var match *accounts.Account 272 for _, a := range err.Matches { 273 if err := ks.Unlock(a, auth); err == nil { 274 match = &a 275 break 276 } 277 } 278 if match == nil { 279 utils.Fatalf("None of the listed files could be unlocked.") 280 } 281 fmt.Printf("Your passphrase unlocked %s\n", match.URL) 282 fmt.Println("In order to avoid this warning, you need to remove the following duplicate key files:") 283 for _, a := range err.Matches { 284 if a != *match { 285 fmt.Println(" ", a.URL) 286 } 287 } 288 return *match 289 } 290 291 // accountCreate creates a new account into the keystore defined by the CLI flags. 292 func accountCreate(ctx *cli.Context) error { 293 stack, _ := makeConfigNode(ctx) 294 password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) 295 296 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 297 account, err := ks.NewAccount(password) 298 if err != nil { 299 utils.Fatalf("Failed to create account: %v", err) 300 } 301 fmt.Printf("Address: {%s}\n", account.Address.Hex()[2:]) 302 return nil 303 } 304 305 // accountUpdate transitions an account from a previous format to the current 306 // one, also providing the possibility to change the pass-phrase. 307 func accountUpdate(ctx *cli.Context) error { 308 if len(ctx.Args()) == 0 { 309 utils.Fatalf("No accounts specified to update") 310 } 311 stack, _ := makeConfigNode(ctx) 312 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 313 314 for _, addr := range ctx.Args() { 315 account, oldPassword := unlockAccount(ctx, ks, addr, 0, nil) 316 newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil) 317 if err := ks.Update(account, oldPassword, newPassword); err != nil { 318 utils.Fatalf("Could not update the account: %v", err) 319 } 320 } 321 return nil 322 } 323 324 func importWallet(ctx *cli.Context) error { 325 keyfile := ctx.Args().First() 326 if len(keyfile) == 0 { 327 utils.Fatalf("keyfile must be given as argument") 328 } 329 keyJson, err := ioutil.ReadFile(keyfile) 330 if err != nil { 331 utils.Fatalf("Could not read wallet file: %v", err) 332 } 333 334 stack, _ := makeConfigNode(ctx) 335 passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx)) 336 337 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 338 acct, err := ks.ImportPreSaleKey(keyJson, passphrase) 339 if err != nil { 340 utils.Fatalf("%v", err) 341 } 342 fmt.Printf("Address: {%x}\n", acct.Address) 343 return nil 344 } 345 346 func accountImport(ctx *cli.Context) error { 347 keyfile := ctx.Args().First() 348 if len(keyfile) == 0 { 349 utils.Fatalf("keyfile must be given as argument") 350 } 351 key, key1, err := keystore.LoadECDSAPair(keyfile) 352 if err != nil { 353 utils.Fatalf("Failed to load the private key: %v", err) 354 } 355 stack, _ := makeConfigNode(ctx) 356 passphrase := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) 357 358 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 359 acct, err := ks.ImportECDSA(key, key1, passphrase) 360 if err != nil { 361 utils.Fatalf("Could not create the account: %v", err) 362 } 363 fmt.Printf("Address: {%s}\n", acct.Address.Hex()[2:]) 364 return nil 365 }