unlock multiple passes and obsolete primary

* multiple passwords allowed in password file
* split on "\n", sideeffect: chop trailing slashes. fixes common mistake <(echo 'pass')
* remove accounts.Primary method
* do not fall back to primary account for mining
This commit is contained in:
zelig 2015-06-18 16:20:00 +01:00
parent 1d72aaa0cd
commit fc2e33c594
6 changed files with 27 additions and 41 deletions

View File

@ -81,19 +81,6 @@ func (am *Manager) HasAccount(addr common.Address) bool {
return false return false
} }
func (am *Manager) Primary() (addr common.Address, err error) {
addrs, err := am.keyStore.GetKeyAddresses()
if os.IsNotExist(err) {
return common.Address{}, ErrNoKeys
} else if err != nil {
return common.Address{}, err
}
if len(addrs) == 0 {
return common.Address{}, ErrNoKeys
}
return addrs[0], nil
}
func (am *Manager) DeleteAccount(address common.Address, auth string) error { func (am *Manager) DeleteAccount(address common.Address, auth string) error {
return am.keyStore.DeleteKey(address, auth) return am.keyStore.DeleteKey(address, auth)
} }

View File

@ -18,7 +18,7 @@ func TestSign(t *testing.T) {
pass := "" // not used but required by API pass := "" // not used but required by API
a1, err := am.NewAccount(pass) a1, err := am.NewAccount(pass)
toSign := randentropy.GetEntropyCSPRNG(32) toSign := randentropy.GetEntropyCSPRNG(32)
am.Unlock(a1.Address, "", 0) am.Unlock(a1.Address, "")
_, err = am.Sign(a1, toSign) _, err = am.Sign(a1, toSign)
if err != nil { if err != nil {

View File

@ -140,7 +140,7 @@ func TestAccounts(t *testing.T) {
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`) checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`)
checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`) checkEvalJSON(t, repl, `eth.coinbase`, `"`+common.Address{}.Hex()+`"`)
val, err := repl.re.Run(`personal.newAccount("password")`) val, err := repl.re.Run(`personal.newAccount("password")`)
if err != nil { if err != nil {

View File

@ -153,9 +153,12 @@ Note that exporting your key in unencrypted format is NOT supported.
Keys are stored under <DATADIR>/keys. Keys are stored under <DATADIR>/keys.
It is safe to transfer the entire directory or the individual keys therein It is safe to transfer the entire directory or the individual keys therein
between ethereum nodes. between ethereum nodes by simply copying.
Make sure you backup your keys regularly. Make sure you backup your keys regularly.
In order to use your account to send transactions, you need to unlock them using the
'--unlock' option. The argument is a comma
And finally. DO NOT FORGET YOUR PASSWORD. And finally. DO NOT FORGET YOUR PASSWORD.
`, `,
Subcommands: []cli.Command{ Subcommands: []cli.Command{
@ -430,7 +433,7 @@ func execJSFiles(ctx *cli.Context) {
ethereum.WaitForShutdown() ethereum.WaitForShutdown()
} }
func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) { func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string, i int) {
var err error var err error
// Load startup keys. XXX we are going to need a different format // Load startup keys. XXX we are going to need a different format
@ -441,7 +444,7 @@ func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (pass
attempts := 3 attempts := 3
for tries := 0; tries < attempts; tries++ { for tries := 0; tries < attempts; tries++ {
msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", account, tries+1, attempts) msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", account, tries+1, attempts)
passphrase = getPassPhrase(ctx, msg, false) passphrase := getPassPhrase(ctx, msg, false, i)
err = am.Unlock(common.HexToAddress(account), passphrase) err = am.Unlock(common.HexToAddress(account), passphrase)
if err == nil { if err == nil {
break break
@ -451,7 +454,6 @@ func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (pass
utils.Fatalf("Unlock account failed '%v'", err) utils.Fatalf("Unlock account failed '%v'", err)
} }
fmt.Printf("Account '%s' unlocked.\n", account) fmt.Printf("Account '%s' unlocked.\n", account)
return
} }
func blockRecovery(ctx *cli.Context) { func blockRecovery(ctx *cli.Context) {
@ -492,16 +494,12 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
accounts := strings.Split(account, " ") accounts := strings.Split(account, " ")
for _, account := range accounts { for i, account := range accounts {
if len(account) > 0 { if len(account) > 0 {
if account == "primary" { if account == "primary" {
primaryAcc, err := am.Primary() utils.Fatalf("the 'primary' keyword is deprecated. You can use indexes, but the indexes are not permanent, they can change if you add external keys, export your keys or copy your keystore to another node.")
if err != nil {
utils.Fatalf("no primary account: %v", err)
}
account = primaryAcc.Hex()
} }
unlockAccount(ctx, am, account) unlockAccount(ctx, am, account, i)
} }
} }
// Start auxiliary services if enabled. // Start auxiliary services if enabled.
@ -535,7 +533,7 @@ func accountList(ctx *cli.Context) {
} }
} }
func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) { func getPassPhrase(ctx *cli.Context, desc string, confirmation bool, i int) (passphrase string) {
passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
if len(passfile) == 0 { if len(passfile) == 0 {
fmt.Println(desc) fmt.Println(desc)
@ -559,14 +557,22 @@ func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase
if err != nil { if err != nil {
utils.Fatalf("Unable to read password file '%s': %v", passfile, err) utils.Fatalf("Unable to read password file '%s': %v", passfile, err)
} }
passphrase = string(passbytes) // this is backwards compatible if the same password unlocks several accounts
// it also has the consequence that trailing newlines will not count as part
// of the password, so --password <(echo -n 'pass') will now work without -n
passphrases := strings.Split(string(passbytes), "\n")
if i >= len(passphrases) {
passphrase = passphrases[len(passphrases)-1]
} else {
passphrase = passphrases[i]
}
} }
return return
} }
func accountCreate(ctx *cli.Context) { func accountCreate(ctx *cli.Context) {
am := utils.MakeAccountManager(ctx) am := utils.MakeAccountManager(ctx)
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true) passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0)
acct, err := am.NewAccount(passphrase) acct, err := am.NewAccount(passphrase)
if err != nil { if err != nil {
utils.Fatalf("Could not create the account: %v", err) utils.Fatalf("Could not create the account: %v", err)
@ -585,7 +591,7 @@ func importWallet(ctx *cli.Context) {
} }
am := utils.MakeAccountManager(ctx) am := utils.MakeAccountManager(ctx)
passphrase := getPassPhrase(ctx, "", false) passphrase := getPassPhrase(ctx, "", false, 0)
acct, err := am.ImportPreSaleKey(keyJson, passphrase) acct, err := am.ImportPreSaleKey(keyJson, passphrase)
if err != nil { if err != nil {
@ -600,7 +606,7 @@ func accountImport(ctx *cli.Context) {
utils.Fatalf("keyfile must be given as argument") utils.Fatalf("keyfile must be given as argument")
} }
am := utils.MakeAccountManager(ctx) am := utils.MakeAccountManager(ctx)
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true) passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0)
acct, err := am.Import(keyfile, passphrase) acct, err := am.Import(keyfile, passphrase)
if err != nil { if err != nil {
utils.Fatalf("Could not create the account: %v", err) utils.Fatalf("Could not create the account: %v", err)

View File

@ -133,7 +133,7 @@ var (
UnlockedAccountFlag = cli.StringFlag{ UnlockedAccountFlag = cli.StringFlag{
Name: "unlock", Name: "unlock",
Usage: "Unlock the account given until this program exits (prompts for password). '--unlock primary' unlocks the primary account", Usage: "Unlock the account given until this program exits (prompts for password). '--unlock n' unlocks the n-th account in order or creation.",
Value: "", Value: "",
} }
PasswordFileFlag = cli.StringFlag{ PasswordFileFlag = cli.StringFlag{

View File

@ -464,15 +464,8 @@ func (s *Ethereum) StartMining(threads int) error {
func (s *Ethereum) Etherbase() (eb common.Address, err error) { func (s *Ethereum) Etherbase() (eb common.Address, err error) {
eb = s.etherbase eb = s.etherbase
if (eb == common.Address{}) { if (eb == common.Address{}) {
primary, err := s.accountManager.Primary() err = fmt.Errorf("no accounts found")
if err != nil { return eb, err
return eb, err
}
if (primary == common.Address{}) {
err = fmt.Errorf("no accounts found")
return eb, err
}
eb = primary
} }
return eb, nil return eb, nil
} }