From c4ea921876b0535022882c568b5cc6b0269db7d4 Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 23 Mar 2015 13:00:06 +0000 Subject: import/export accounts - cli: add passwordfile flag - cli: change unlock flag only takes account - cli: with unlock you are prompted for password or use passfile with password flag - cli: unlockAccount used in normal client start (run) and accountExport - cli: getPassword used in accountCreate and accountImport - accounts: Manager.Import, Manager.Export - crypto: SaveECDSA (to complement LoadECDSA) to save to file - crypto: NewKeyFromECDSA added (used in accountImport and New = generated constructor) --- cmd/ethereum/main.go | 174 ++++++++++++++++++++++++++++++++++++++++++--------- cmd/utils/flags.go | 8 ++- 2 files changed, 152 insertions(+), 30 deletions(-) (limited to 'cmd') diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 2f417aacb..276480195 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -26,11 +26,11 @@ import ( "os" "runtime" "strconv" - "strings" "time" "github.com/codegangsta/cli" "github.com/ethereum/ethash" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" @@ -83,11 +83,62 @@ The output of this command is supposed to be machine-readable. Action: accountList, Name: "list", Usage: "print account addresses", + Description: ` + +`, }, { Action: accountCreate, Name: "new", Usage: "create a new account", + Description: ` + + ethereum account new + +Creates a new accountThe account is saved in encrypted format, you are prompted for a passphrase. +You must remember this passphrase to unlock your account in future. +For non-interactive use the passphrase can be specified with the --password flag: + + ethereum --password account new + + `, + }, + { + Action: accountImport, + Name: "import", + Usage: "import a private key into a new account", + Description: ` + + ethereum account import + +Imports a private key from and creates a new account with the address derived from the key. +The keyfile is assumed to contain an unencrypted private key in canonical EC format. + +The account is saved in encrypted format, you are prompted for a passphrase. +You must remember this passphrase to unlock your account in future. +For non-interactive use the passphrase can be specified with the --password flag: + + ethereum --password account import + + `, + }, + { + Action: accountExport, + Name: "export", + Usage: "export an account into key file", + Description: ` + + ethereum account export
+ +Exports the given account's private key into keyfile using the canonical EC format. +The account needs to be unlocked, if it is not the user is prompted for a passphrase to unlock it. +For non-interactive use, the password can be specified with the --unlock flag: + + ethereum --unlock account export
+ +Note: +Since you can directly copy your encrypted accounts to another ethereum instance, this import/export mechanism is not needed when you transfer an account between nodes. + `, }, }, }, @@ -130,6 +181,7 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja } app.Flags = []cli.Flag{ utils.UnlockedAccountFlag, + utils.PasswordFileFlag, utils.BootnodesFlag, utils.DataDirFlag, utils.JSpathFlag, @@ -218,23 +270,43 @@ func execJSFiles(ctx *cli.Context) { ethereum.WaitForShutdown() } -func startEth(ctx *cli.Context, eth *eth.Ethereum) { - utils.StartEthereum(eth) +func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) { + if !ctx.GlobalBool(utils.UnencryptedKeysFlag.Name) { + var err error + // Load startup keys. XXX we are going to need a different format + // Attempt to unlock the account + passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) + if len(passfile) == 0 { + fmt.Println("Please enter a passphrase now.") + auth, err := readPassword("Passphrase: ", true) + if err != nil { + utils.Fatalf("%v", err) + } - // Load startup keys. XXX we are going to need a different format - account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) - if len(account) > 0 { - split := strings.Split(account, ":") - if len(split) != 2 { - utils.Fatalf("Illegal 'unlock' format (address:password)") + passphrase = auth + + } else { + if passphrase, err = common.ReadAllFile(passfile); err != nil { + utils.Fatalf("Unable to read password file '%s': %v", passfile, err) + } } - am := eth.AccountManager() - // Attempt to unlock the account - err := am.Unlock(common.FromHex(split[0]), split[1]) + + err = am.Unlock(common.FromHex(account), passphrase) if err != nil { utils.Fatalf("Unlock account failed '%v'", err) } } + return +} + +func startEth(ctx *cli.Context, eth *eth.Ethereum) { + utils.StartEthereum(eth) + am := eth.AccountManager() + + account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) + if len(account) > 0 { + unlockAccount(ctx, am, account) + } // Start auxiliary services if enabled. if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { utils.StartRPC(eth, ctx) @@ -255,30 +327,74 @@ func accountList(ctx *cli.Context) { } } -func accountCreate(ctx *cli.Context) { - am := utils.GetAccountManager(ctx) - passphrase := "" +func getPassPhrase(ctx *cli.Context) (passphrase string) { if !ctx.GlobalBool(utils.UnencryptedKeysFlag.Name) { - fmt.Println("The new account will be encrypted with a passphrase.") - fmt.Println("Please enter a passphrase now.") - auth, err := readPassword("Passphrase: ", true) - if err != nil { - utils.Fatalf("%v", err) - } - confirm, err := readPassword("Repeat Passphrase: ", false) - if err != nil { - utils.Fatalf("%v", err) - } - if auth != confirm { - utils.Fatalf("Passphrases did not match.") + passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) + if len(passfile) == 0 { + fmt.Println("The new account will be encrypted with a passphrase.") + fmt.Println("Please enter a passphrase now.") + auth, err := readPassword("Passphrase: ", true) + if err != nil { + utils.Fatalf("%v", err) + } + confirm, err := readPassword("Repeat Passphrase: ", false) + if err != nil { + utils.Fatalf("%v", err) + } + if auth != confirm { + utils.Fatalf("Passphrases did not match.") + } + passphrase = auth + + } else { + var err error + if passphrase, err = common.ReadAllFile(passfile); err != nil { + utils.Fatalf("Unable to read password file '%s': %v", passfile, err) + } } - passphrase = auth } + return +} + +func accountCreate(ctx *cli.Context) { + am := utils.GetAccountManager(ctx) + passphrase := getPassPhrase(ctx) acct, err := am.NewAccount(passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) } - fmt.Printf("Address: %x\n", acct.Address) + fmt.Printf("Address: %x\n", acct) +} + +func accountImport(ctx *cli.Context) { + keyfile := ctx.Args().First() + if len(keyfile) == 0 { + utils.Fatalf("keyfile must be given as argument") + } + am := utils.GetAccountManager(ctx) + passphrase := getPassPhrase(ctx) + acct, err := am.Import(keyfile, passphrase) + if err != nil { + utils.Fatalf("Could not create the account: %v", err) + } + fmt.Printf("Address: %x\n", acct) +} + +func accountExport(ctx *cli.Context) { + account := ctx.Args().First() + if len(account) == 0 { + utils.Fatalf("account address must be given as first argument") + } + keyfile := ctx.Args().Get(1) + if len(keyfile) == 0 { + utils.Fatalf("keyfile must be given as second argument") + } + am := utils.GetAccountManager(ctx) + auth := unlockAccount(ctx, am, account) + err := am.Export(keyfile, common.FromHex(account), auth) + if err != nil { + utils.Fatalf("Account export failed: %v", err) + } } func importchain(ctx *cli.Context) { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 94b043d73..f94ec3a69 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -104,7 +104,13 @@ var ( } UnlockedAccountFlag = cli.StringFlag{ Name: "unlock", - Usage: "Unlock a given account untill this programs exits (address:password)", + Usage: "unlock the account given until this program exits (prompts for password).", + Value: "", + } + PasswordFileFlag = cli.StringFlag{ + Name: "password", + Usage: "Password used when saving a new account and unlocking an existing account. If you create a new account make sure you remember this password.", + Value: "", } // logging and debug settings -- cgit v1.2.3 From fd8d18ec280c3fe2c3d2651870c31c65b02039ba Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 24 Mar 2015 12:37:00 +0000 Subject: unlocking coinbase - extract accounts.getKey method - if given empty address it retrieves coinbase (first account) - cli -unlock coinbase will unlock coinbase --- cmd/ethereum/main.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 276480195..fea3fbf61 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -134,7 +134,7 @@ Exports the given account's private key into keyfile using the canonical EC form The account needs to be unlocked, if it is not the user is prompted for a passphrase to unlock it. For non-interactive use, the password can be specified with the --unlock flag: - ethereum --unlock account export
+ ethereum --password account export
Note: Since you can directly copy your encrypted accounts to another ethereum instance, this import/export mechanism is not needed when you transfer an account between nodes. @@ -305,6 +305,9 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) { account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) if len(account) > 0 { + if account == "coinbase" { + account = "" + } unlockAccount(ctx, am, account) } // Start auxiliary services if enabled. -- cgit v1.2.3 From 1c4c71dcff442e3ae30e510fef312d3c05341f30 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 24 Mar 2015 14:09:06 +0000 Subject: cli: fix liner not closing (spuriously opened) in noninteractive jsre --- cmd/ethereum/js.go | 4 ++-- cmd/ethereum/main.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'cmd') diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go index 1f0033daa..599af0a16 100644 --- a/cmd/ethereum/js.go +++ b/cmd/ethereum/js.go @@ -67,14 +67,14 @@ type jsre struct { prompter } -func newJSRE(ethereum *eth.Ethereum, libPath string) *jsre { +func newJSRE(ethereum *eth.Ethereum, libPath string, interactive bool) *jsre { js := &jsre{ethereum: ethereum, ps1: "> "} js.xeth = xeth.New(ethereum, js) js.re = re.New(libPath) js.apiBindings() js.adminBindings() - if !liner.TerminalSupported() { + if !liner.TerminalSupported() || !interactive { js.prompter = dumbterm{bufio.NewReader(os.Stdin)} } else { lr := liner.NewLiner() diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index fea3fbf61..59c6ef485 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -246,7 +246,7 @@ func console(ctx *cli.Context) { } startEth(ctx, ethereum) - repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name)) + repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), true) repl.interactive() ethereum.Stop() @@ -261,7 +261,7 @@ func execJSFiles(ctx *cli.Context) { } startEth(ctx, ethereum) - repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name)) + repl := newJSRE(ethereum, ctx.String(utils.JSpathFlag.Name), false) for _, file := range ctx.Args() { repl.exec(file) } -- cgit v1.2.3 From 34d5a6c156a014ce000b4f850f2b0f11533387f0 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 24 Mar 2015 16:05:27 +0000 Subject: cli: help formatting --- cmd/ethereum/main.go | 31 ++++++++++++++++++------------- cmd/utils/flags.go | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) (limited to 'cmd') diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 59c6ef485..39a0a9d7f 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -83,9 +83,6 @@ The output of this command is supposed to be machine-readable. Action: accountList, Name: "list", Usage: "print account addresses", - Description: ` - -`, }, { Action: accountCreate, @@ -111,12 +108,14 @@ For non-interactive use the passphrase can be specified with the --password flag ethereum account import -Imports a private key from and creates a new account with the address derived from the key. -The keyfile is assumed to contain an unencrypted private key in canonical EC format. +Imports a private key from and creates a new account with the address +derived from the key. +The keyfile is assumed to contain an unencrypted private key in canonical EC +format. The account is saved in encrypted format, you are prompted for a passphrase. You must remember this passphrase to unlock your account in future. -For non-interactive use the passphrase can be specified with the --password flag: +For non-interactive use the passphrase can be specified with the -password flag: ethereum --password account import @@ -130,14 +129,18 @@ For non-interactive use the passphrase can be specified with the --password flag ethereum account export
-Exports the given account's private key into keyfile using the canonical EC format. -The account needs to be unlocked, if it is not the user is prompted for a passphrase to unlock it. -For non-interactive use, the password can be specified with the --unlock flag: +Exports the given account's private key into keyfile using the canonical EC +format. +The account needs to be unlocked, if it is not the user is prompted for a +passphrase to unlock it. +For non-interactive use, the passphrase can be specified with the --unlock flag: ethereum --password account export
Note: -Since you can directly copy your encrypted accounts to another ethereum instance, this import/export mechanism is not needed when you transfer an account between nodes. +As you can directly copy your encrypted accounts to another ethereum instance, +this import/export mechanism is not needed when you transfer an account between +nodes. `, }, }, @@ -156,16 +159,18 @@ Use "ethereum dump 0" to dump the genesis block. Name: "console", Usage: `Ethereum Console: interactive JavaScript environment`, Description: ` -Console is an interactive shell for the Ethereum JavaScript runtime environment which exposes a node admin interface as well as the DAPP JavaScript API. +Console is an interactive shell for the Ethereum JavaScript runtime environment +which exposes a node admin interface as well as the DAPP JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console `, }, { Action: execJSFiles, Name: "js", - Usage: `executes the given JavaScript files in the Ethereum Frontier JavaScript VM`, + Usage: `executes the given JavaScript files in the Ethereum JavaScript VM`, Description: ` -The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Frontier-Console +The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP +JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console `, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index f94ec3a69..dda409502 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -109,7 +109,7 @@ var ( } PasswordFileFlag = cli.StringFlag{ Name: "password", - Usage: "Password used when saving a new account and unlocking an existing account. If you create a new account make sure you remember this password.", + Usage: "Path to password file for (un)locking an existing account.", Value: "", } -- cgit v1.2.3 From d1b52efdb581ca90613d2047b974d3a128f9bc58 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 24 Mar 2015 16:19:11 +0000 Subject: cli: implement ethereum presale wallet import via cli --- cmd/ethereum/main.go | 74 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 27 deletions(-) (limited to 'cmd') diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 39a0a9d7f..57729b206 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -23,6 +23,7 @@ package main import ( "bufio" "fmt" + "io/ioutil" "os" "runtime" "strconv" @@ -74,6 +75,19 @@ Regular users do not need to execute it. The output of this command is supposed to be machine-readable. `, }, + + { + Action: accountList, + Name: "wallet", + Usage: "ethereum presale wallet", + Subcommands: []cli.Command{ + { + Action: importWallet, + Name: "import", + Usage: "import ethereum presale wallet", + }, + }, + }, { Action: accountList, Name: "account", @@ -280,22 +294,7 @@ func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (pass var err error // Load startup keys. XXX we are going to need a different format // Attempt to unlock the account - passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) - if len(passfile) == 0 { - fmt.Println("Please enter a passphrase now.") - auth, err := readPassword("Passphrase: ", true) - if err != nil { - utils.Fatalf("%v", err) - } - - passphrase = auth - - } else { - if passphrase, err = common.ReadAllFile(passfile); err != nil { - utils.Fatalf("Unable to read password file '%s': %v", passfile, err) - } - } - + passphrase := getPassPhrase(ctx, "", false) err = am.Unlock(common.FromHex(account), passphrase) if err != nil { utils.Fatalf("Unlock account failed '%v'", err) @@ -335,22 +334,23 @@ func accountList(ctx *cli.Context) { } } -func getPassPhrase(ctx *cli.Context) (passphrase string) { +func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) { if !ctx.GlobalBool(utils.UnencryptedKeysFlag.Name) { passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) if len(passfile) == 0 { - fmt.Println("The new account will be encrypted with a passphrase.") - fmt.Println("Please enter a passphrase now.") + fmt.Println(desc) auth, err := readPassword("Passphrase: ", true) if err != nil { utils.Fatalf("%v", err) } - confirm, err := readPassword("Repeat Passphrase: ", false) - if err != nil { - utils.Fatalf("%v", err) - } - if auth != confirm { - utils.Fatalf("Passphrases did not match.") + if confirmation { + confirm, err := readPassword("Repeat Passphrase: ", false) + if err != nil { + utils.Fatalf("%v", err) + } + if auth != confirm { + utils.Fatalf("Passphrases did not match.") + } } passphrase = auth @@ -366,7 +366,7 @@ func getPassPhrase(ctx *cli.Context) (passphrase string) { func accountCreate(ctx *cli.Context) { am := utils.GetAccountManager(ctx) - passphrase := getPassPhrase(ctx) + passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true) acct, err := am.NewAccount(passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) @@ -374,13 +374,33 @@ func accountCreate(ctx *cli.Context) { fmt.Printf("Address: %x\n", acct) } +func importWallet(ctx *cli.Context) { + keyfile := ctx.Args().First() + if len(keyfile) == 0 { + utils.Fatalf("keyfile must be given as argument") + } + keyJson, err := ioutil.ReadFile(keyfile) + if err != nil { + utils.Fatalf("Could not read wallet file: %v", err) + } + + am := utils.GetAccountManager(ctx) + passphrase := getPassPhrase(ctx, "", false) + + acct, err := am.ImportPreSaleKey(keyJson, passphrase) + if err != nil { + utils.Fatalf("Could not create the account: %v", err) + } + fmt.Printf("Address: %x\n", acct) +} + func accountImport(ctx *cli.Context) { keyfile := ctx.Args().First() if len(keyfile) == 0 { utils.Fatalf("keyfile must be given as argument") } am := utils.GetAccountManager(ctx) - passphrase := getPassPhrase(ctx) + passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true) acct, err := am.Import(keyfile, passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) -- cgit v1.2.3 From fee224f07582a3f4c74f214347a89061ce75d2a1 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 24 Mar 2015 21:53:46 +0000 Subject: cli test: fix test newJSRE interactive argument --- cmd/ethereum/js_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/ethereum/js_test.go b/cmd/ethereum/js_test.go index a6058b318..580bc7a2b 100644 --- a/cmd/ethereum/js_test.go +++ b/cmd/ethereum/js_test.go @@ -47,7 +47,7 @@ func testJEthRE(t *testing.T) (repl *jsre, ethereum *eth.Ethereum, err error) { return } assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") - repl = newJSRE(ethereum, assetPath) + repl = newJSRE(ethereum, assetPath, false) return } -- cgit v1.2.3 From 23e41a57ad7e7cb4bc5a1cbad28bbf8d65907fdd Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Mar 2015 10:41:36 +0000 Subject: Applying: fix adming js test regression (maybe otto update?) --- cmd/ethereum/js.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go index 599af0a16..8e88a1c54 100644 --- a/cmd/ethereum/js.go +++ b/cmd/ethereum/js.go @@ -102,7 +102,7 @@ func (js *jsre) apiBindings() { jethObj := t.Object() jethObj.Set("send", jeth.Send) - err := js.re.Compile("bignum.js", re.BigNumber_JS) + err := js.re.Compile("bignumber.js", re.BigNumber_JS) if err != nil { utils.Fatalf("Error loading bignumber.js: %v", err) } -- cgit v1.2.3 From 4ec38e39320ee9abccd96da765a9c65fccd04151 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Mar 2015 14:58:52 +0000 Subject: common: remove WriteFile and ReadAllFile (use ioutil instead) --- cmd/ethereum/js_test.go | 6 +++--- cmd/ethereum/main.go | 5 +++-- cmd/mist/bindings.go | 7 ++++--- cmd/mist/gui.go | 5 +++-- 4 files changed, 13 insertions(+), 10 deletions(-) (limited to 'cmd') diff --git a/cmd/ethereum/js_test.go b/cmd/ethereum/js_test.go index 580bc7a2b..5b962f621 100644 --- a/cmd/ethereum/js_test.go +++ b/cmd/ethereum/js_test.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "io/ioutil" "os" "path" "testing" @@ -9,7 +10,6 @@ import ( "github.com/robertkrimen/otto" "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" ) @@ -30,8 +30,8 @@ func testJEthRE(t *testing.T) (repl *jsre, ethereum *eth.Ethereum, err error) { } // FIXME: this does not work ATM ks := crypto.NewKeyStorePlain("/tmp/eth/keys") - common.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d", - []byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`)) + ioutil.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d", + []byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`), os.ModePerm) port++ ethereum, err = eth.New(ð.Config{ diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 57729b206..6bbe1044f 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -355,10 +355,11 @@ func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase passphrase = auth } else { - var err error - if passphrase, err = common.ReadAllFile(passfile); err != nil { + passbytes, err := ioutil.ReadFile(passfile) + if err != nil { utils.Fatalf("Unable to read password file '%s': %v", passfile, err) } + passphrase = string(passbytes) } } return diff --git a/cmd/mist/bindings.go b/cmd/mist/bindings.go index 8a9ec7cb1..e7ce50c35 100644 --- a/cmd/mist/bindings.go +++ b/cmd/mist/bindings.go @@ -22,13 +22,14 @@ package main import ( "encoding/json" + "io/ioutil" "os" "strconv" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" ) type plugin struct { @@ -46,14 +47,14 @@ func (self *Gui) AddPlugin(pluginPath string) { self.plugins[pluginPath] = plugin{Name: pluginPath, Path: pluginPath} json, _ := json.MarshalIndent(self.plugins, "", " ") - common.WriteFile(self.eth.DataDir+"/plugins.json", json) + ioutil.WriteFile(self.eth.DataDir+"/plugins.json", json, os.ModePerm) } func (self *Gui) RemovePlugin(pluginPath string) { delete(self.plugins, pluginPath) json, _ := json.MarshalIndent(self.plugins, "", " ") - common.WriteFile(self.eth.DataDir+"/plugins.json", json) + ioutil.WriteFile(self.eth.DataDir+"/plugins.json", json, os.ModePerm) } func (self *Gui) DumpState(hash, path string) { diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go index 08f02f833..d37d6f81b 100644 --- a/cmd/mist/gui.go +++ b/cmd/mist/gui.go @@ -25,6 +25,7 @@ import "C" import ( "encoding/json" "fmt" + "io/ioutil" "math/big" "path" "runtime" @@ -91,8 +92,8 @@ func NewWindow(ethereum *eth.Ethereum) *Gui { plugins: make(map[string]plugin), serviceEvents: make(chan ServEv, 1), } - data, _ := common.ReadAllFile(path.Join(ethereum.DataDir, "plugins.json")) - json.Unmarshal([]byte(data), &gui.plugins) + data, _ := ioutil.ReadFile(path.Join(ethereum.DataDir, "plugins.json")) + json.Unmarshal(data, &gui.plugins) return gui } -- cgit v1.2.3 From 11d2ebc06ffffa8846d5d55cae5663fac6f685f1 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Mar 2015 15:45:56 +0000 Subject: unlocking coinbase without knowing address - accounts: remove Manager.getKey - cli: for -unlock coinbase, use account manager Coinbase() --- cmd/ethereum/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 6bbe1044f..8983b85a6 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -294,7 +294,7 @@ func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (pass var err error // Load startup keys. XXX we are going to need a different format // Attempt to unlock the account - passphrase := getPassPhrase(ctx, "", false) + passphrase = getPassPhrase(ctx, "", false) err = am.Unlock(common.FromHex(account), passphrase) if err != nil { utils.Fatalf("Unlock account failed '%v'", err) @@ -310,7 +310,11 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) { account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) if len(account) > 0 { if account == "coinbase" { - account = "" + accbytes, err := am.Coinbase() + if err != nil { + utils.Fatalf("no coinbase account: %v", err) + } + account = common.ToHex(accbytes) } unlockAccount(ctx, am, account) } @@ -420,6 +424,7 @@ func accountExport(ctx *cli.Context) { } am := utils.GetAccountManager(ctx) auth := unlockAccount(ctx, am, account) + err := am.Export(keyfile, common.FromHex(account), auth) if err != nil { utils.Fatalf("Account export failed: %v", err) -- cgit v1.2.3 From abbdf4156057de8a4f866b0840defc00c2c500db Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Mar 2015 16:10:44 +0000 Subject: output error message if unlock address is invalid (fixes the wierd "read /path: is a directory") msg --- cmd/ethereum/main.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 8983b85a6..2e721dc71 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -295,7 +295,11 @@ func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (pass // Load startup keys. XXX we are going to need a different format // Attempt to unlock the account passphrase = getPassPhrase(ctx, "", false) - err = am.Unlock(common.FromHex(account), passphrase) + accbytes := common.FromHex(account) + if len(accbytes) == 0 { + utils.Fatalf("Invalid account address '%s'", account) + } + err = am.Unlock(accbytes, passphrase) if err != nil { utils.Fatalf("Unlock account failed '%v'", err) } -- cgit v1.2.3 From 7577d1261403dbabdb30e21415d34b4e5da466ec Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 26 Mar 2015 18:55:39 +0000 Subject: max paranoia mode to UNsupport unencrypted keys entirely - remove account export functionality from CLI - remove accountExport method, - remove unencrypted-keys flag from everywhere - improve documentation --- cmd/ethereum/main.go | 149 ++++++++++++++++++++++++--------------------------- cmd/utils/flags.go | 14 +---- 2 files changed, 71 insertions(+), 92 deletions(-) (limited to 'cmd') diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 2e721dc71..42321e8bc 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -77,9 +77,8 @@ The output of this command is supposed to be machine-readable. }, { - Action: accountList, - Name: "wallet", - Usage: "ethereum presale wallet", + Name: "wallet", + Usage: "ethereum presale wallet", Subcommands: []cli.Command{ { Action: importWallet, @@ -92,6 +91,28 @@ The output of this command is supposed to be machine-readable. Action: accountList, Name: "account", Usage: "manage accounts", + Description: ` + +Manage accounts lets you create new accounts, list all existing accounts, +import a private key into a new account. + +It supports interactive mode, when you are prompted for password as well as +non-interactive mode where passwords are supplied via a given password file. +Non-interactive mode is only meant for scripted use on test networks or known +safe environments. + +Make sure you remember the password you gave when creating a new account (with +either new or import). Without it you are not able to unlock your account. + +Note that exporting your key in unencrypted format is NOT supported. + +Keys are stored under /keys. +It is safe to transfer the entire directory or the individual keys therein +between ethereum nodes. +Make sure you backup your keys regularly. + +And finally. DO NOT FORGET YOUR PASSWORD. +`, Subcommands: []cli.Command{ { Action: accountList, @@ -106,12 +127,18 @@ The output of this command is supposed to be machine-readable. ethereum account new -Creates a new accountThe account is saved in encrypted format, you are prompted for a passphrase. -You must remember this passphrase to unlock your account in future. +Creates a new account. Prints the address. + +The account is saved in encrypted format, you are prompted for a passphrase. + +You must remember this passphrase to unlock your account in the future. + For non-interactive use the passphrase can be specified with the --password flag: ethereum --password account new +Note, this is meant to be used for testing only, it is a bad idea to save your +password to file or expose in any other way. `, }, { @@ -122,38 +149,23 @@ For non-interactive use the passphrase can be specified with the --password flag ethereum account import -Imports a private key from and creates a new account with the address -derived from the key. +Imports an unencrypted private key from and creates a new account. +Prints the address. + The keyfile is assumed to contain an unencrypted private key in canonical EC -format. +raw bytes format. The account is saved in encrypted format, you are prompted for a passphrase. -You must remember this passphrase to unlock your account in future. -For non-interactive use the passphrase can be specified with the -password flag: - ethereum --password account import +You must remember this passphrase to unlock your account in the future. - `, - }, - { - Action: accountExport, - Name: "export", - Usage: "export an account into key file", - Description: ` - - ethereum account export
- -Exports the given account's private key into keyfile using the canonical EC -format. -The account needs to be unlocked, if it is not the user is prompted for a -passphrase to unlock it. -For non-interactive use, the passphrase can be specified with the --unlock flag: +For non-interactive use the passphrase can be specified with the -password flag: - ethereum --password account export
+ ethereum --password account import Note: As you can directly copy your encrypted accounts to another ethereum instance, -this import/export mechanism is not needed when you transfer an account between +this import mechanism is not needed when you transfer an account between nodes. `, }, @@ -217,7 +229,6 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.RPCEnabledFlag, utils.RPCListenAddrFlag, utils.RPCPortFlag, - utils.UnencryptedKeysFlag, utils.VMDebugFlag, utils.ProtocolVersionFlag, utils.NetworkIdFlag, @@ -290,19 +301,17 @@ func execJSFiles(ctx *cli.Context) { } func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) { - if !ctx.GlobalBool(utils.UnencryptedKeysFlag.Name) { - var err error - // Load startup keys. XXX we are going to need a different format - // Attempt to unlock the account - passphrase = getPassPhrase(ctx, "", false) - accbytes := common.FromHex(account) - if len(accbytes) == 0 { - utils.Fatalf("Invalid account address '%s'", account) - } - err = am.Unlock(accbytes, passphrase) - if err != nil { - utils.Fatalf("Unlock account failed '%v'", err) - } + var err error + // Load startup keys. XXX we are going to need a different format + // Attempt to unlock the account + passphrase = getPassPhrase(ctx, "", false) + accbytes := common.FromHex(account) + if len(accbytes) == 0 { + utils.Fatalf("Invalid account address '%s'", account) + } + err = am.Unlock(accbytes, passphrase) + if err != nil { + utils.Fatalf("Unlock account failed '%v'", err) } return } @@ -343,32 +352,30 @@ func accountList(ctx *cli.Context) { } func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) { - if !ctx.GlobalBool(utils.UnencryptedKeysFlag.Name) { - passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) - if len(passfile) == 0 { - fmt.Println(desc) - auth, err := readPassword("Passphrase: ", true) + passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) + if len(passfile) == 0 { + fmt.Println(desc) + auth, err := readPassword("Passphrase: ", true) + if err != nil { + utils.Fatalf("%v", err) + } + if confirmation { + confirm, err := readPassword("Repeat Passphrase: ", false) if err != nil { utils.Fatalf("%v", err) } - if confirmation { - confirm, err := readPassword("Repeat Passphrase: ", false) - if err != nil { - utils.Fatalf("%v", err) - } - if auth != confirm { - utils.Fatalf("Passphrases did not match.") - } + if auth != confirm { + utils.Fatalf("Passphrases did not match.") } - passphrase = auth + } + passphrase = auth - } else { - passbytes, err := ioutil.ReadFile(passfile) - if err != nil { - utils.Fatalf("Unable to read password file '%s': %v", passfile, err) - } - passphrase = string(passbytes) + } else { + passbytes, err := ioutil.ReadFile(passfile) + if err != nil { + utils.Fatalf("Unable to read password file '%s': %v", passfile, err) } + passphrase = string(passbytes) } return } @@ -417,24 +424,6 @@ func accountImport(ctx *cli.Context) { fmt.Printf("Address: %x\n", acct) } -func accountExport(ctx *cli.Context) { - account := ctx.Args().First() - if len(account) == 0 { - utils.Fatalf("account address must be given as first argument") - } - keyfile := ctx.Args().Get(1) - if len(keyfile) == 0 { - utils.Fatalf("keyfile must be given as second argument") - } - am := utils.GetAccountManager(ctx) - auth := unlockAccount(ctx, am, account) - - err := am.Export(keyfile, common.FromHex(account), auth) - if err != nil { - utils.Fatalf("Account export failed: %v", err) - } -} - func importchain(ctx *cli.Context) { if len(ctx.Args()) != 1 { utils.Fatalf("This command requires an argument.") diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index dda409502..f948cdb06 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -97,14 +97,9 @@ var ( Usage: "Enable mining", } - // key settings - UnencryptedKeysFlag = cli.BoolFlag{ - Name: "unencrypted-keys", - Usage: "disable private key disk encryption (for testing)", - } UnlockedAccountFlag = cli.StringFlag{ Name: "unlock", - Usage: "unlock the account given until this program exits (prompts for password).", + Usage: "unlock the account given until this program exits (prompts for password). '--unlock coinbase' unlocks the primary (coinbase) account", Value: "", } PasswordFileFlag = cli.StringFlag{ @@ -249,12 +244,7 @@ func GetChain(ctx *cli.Context) (*core.ChainManager, common.Database, common.Dat func GetAccountManager(ctx *cli.Context) *accounts.Manager { dataDir := ctx.GlobalString(DataDirFlag.Name) - var ks crypto.KeyStore2 - if ctx.GlobalBool(UnencryptedKeysFlag.Name) { - ks = crypto.NewKeyStorePlain(path.Join(dataDir, "plainkeys")) - } else { - ks = crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys")) - } + ks := crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys")) return accounts.NewManager(ks) } -- cgit v1.2.3