aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/ethereum/main.go174
-rw-r--r--cmd/utils/flags.go8
2 files changed, 152 insertions, 30 deletions
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 <passwordfile> account new
+
+ `,
+ },
+ {
+ Action: accountImport,
+ Name: "import",
+ Usage: "import a private key into a new account",
+ Description: `
+
+ ethereum account import <keyfile>
+
+Imports a private key from <keyfile> 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 <passwordfile> account import <keyfile>
+
+ `,
+ },
+ {
+ Action: accountExport,
+ Name: "export",
+ Usage: "export an account into key file",
+ Description: `
+
+ ethereum account export <address> <keyfile>
+
+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 <passwrdfile> account export <address> <keyfile>
+
+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