cmd/signer: minor changes

This commit is contained in:
Martin Holst Swende 2017-11-30 14:59:06 +01:00
parent f88559e09f
commit 39d43a74b1
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
5 changed files with 57 additions and 56 deletions

View file

@ -11,13 +11,23 @@ synchronised with the chain or a particular Ethereum node that has no build in,
In its current form the signer is very limited and designed to work with Mist. It hasn't got a connection to an
Ethereum node. This restriction imposed many limitations such as the lack of ability to keep track of nonces, balances
or fetching additional information that can help the user to make a decision to sign a transaction or data. Currently
the signer only supports password protected accounts. Support for hardware tokens such as Trezor and Legder is planned.
or fetching additional information that can help the user to make a decision to sign a transaction or data.
## Command line flags
The signer accepts the following command line options:
- keystore, the directory where the password protected keystore stores keyfiles. The default directory is within geth's datadir. It is OS dependand, use `signer -h` to see where the location is on your system.
- chainid, the chain identifier. Default value is the Ethereum mainnet. See of a list of chain identifiers that are used https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md.
```
--chainid value chain identifier (default: 1)
--loglevel value log level to emit to the screen (default: 4)
--keystore value Directory for the keystore (default: "/home/martin/.ethereum/keystore")
--networkid value Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby) (default: 1)
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
--nousb Disables monitoring for and managing USB hardware wallets
--rpcaddr value HTTP-RPC server listening interface (default: "localhost")
--rpcport value HTTP-RPC server listening port (default: 8550)
--4bytedb value File containing 4byte-identifiers (default: "./4byte.json")
--help, -h show help
```
Example:
```
@ -25,7 +35,8 @@ signer -keystore /my/keystore -chainid 4
```
## Communicating
The signer listens on stdin for incoming requests and sends responses on stdout. Messages are expected to follow the
The signer listens to HTTP requests on `rpcaddr`:`rpcport`. The messages are expected to be JSON
[jsonrpc 2.0 standard](http://www.jsonrpc.org/specification).
Some of these call can require user interaction. Clients must be aware that responses may be deplayed significanlty or
@ -50,7 +61,8 @@ The client is responsible for creating a backup of the keystore. If the keystore
lost accounts.
#### Arguments
- passphrase [string]: passphrase that is used to protect the private key that is stored within the keystore
None
#### Result
- address [string]: account address that is derived from the generated key
@ -83,7 +95,8 @@ lost accounts.
List all accounts that this signer currently manages
#### Arguments
none
None
#### Result
- array with account records:
@ -120,11 +133,10 @@ lost accounts.
### account_signTransaction
#### Sign transactions
Signs a transactions and respons with the signed transaction in RLP encoded form.
Signs a transactions and responds with the signed transaction in RLP encoded form.
#### Arguments
- from [address]: account to send the transaction from
- passphrase [string]: passphrase to unlock the from account
- Transaction object:
- transaction.to [address]: receiver account
- gas [number]: maximum amount of gas to burn
@ -144,7 +156,6 @@ lost accounts.
"method": "account_signTransaction",
"params": [
"0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
"my password",
{
"gas": "0x55555",
"gasPrice": "0x1234",
@ -170,7 +181,6 @@ lost accounts.
#### Arguments
- account [address]: account to sign with
- passphrase [string]: passphrase to unlock the account
- data [data]: data to sign
#### Result
@ -184,7 +194,6 @@ lost accounts.
"method": "account_sign",
"params": [
"0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
"my password",
"0xaabbccdd"
]
}
@ -236,8 +245,6 @@ lost accounts.
#### Arguments
- account [object]: key in [web3 keystore format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) (retrieved with account_export)
- passphrase [string]: password to decrypt the given account
- newPassphrase [string]: password to encrypt the imported key in the keystore with
#### Result
- imported key [object]:
@ -273,8 +280,6 @@ lost accounts.
"id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9",
"version": 3
},
"my password",
"my password"
]
}
{

View file

@ -41,7 +41,6 @@ type SignerAPI struct {
am *accounts.Manager
ui SignerUI
abidb abiDb
audit *auditlogger
}
// Metadata about the request
@ -173,7 +172,7 @@ func (ui *HeadlessUI) ShowInfo(message string) {
// key that is generated when a new account is created.
// noUSB disables USB support that is required to support hardware devices such as
// ledger and trezor.
func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *abiDb, auditlog string) *SignerAPI {
func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *abiDb) *SignerAPI {
var backends []accounts.Backend
// support password based accounts
@ -197,11 +196,7 @@ func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abi
log.Debug("Trezor support enabled")
}
}
var al *auditlogger
if auditlog != ""{
al = &auditlogger{auditlog}
}
return &SignerAPI{big.NewInt(chainID), accounts.NewManager(backends...), ui, *abidb, al}
return &SignerAPI{big.NewInt(chainID), accounts.NewManager(backends...), ui, *abidb}
}
func metaData(ctx context.Context) Metadata {
@ -300,6 +295,7 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, from common.Address,
}
signedTx, err := wallet.SignTxWithPassphrase(acc, result.pw, tx, api.chainID)
if err != nil {
api.ui.ShowError(err.Error())
return nil, err
}
return rlp.EncodeToBytes(signedTx)
@ -337,6 +333,7 @@ func (api *SignerAPI) Sign(ctx context.Context, addr common.Address, data hexuti
// Assemble sign the data with the wallet
signature, err := wallet.SignHashWithPassphrase(account, res.pw, sighash)
if err != nil {
api.ui.ShowError(err.Error())
return nil, err
}
signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
@ -414,7 +411,8 @@ func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.Raw
// Imports tries to import the given keyJSON in the local keystore. The keyJSON data is expected to be
// in web3 keystore format. It will decrypt the keyJSON with the given passphrase and on successful
// decryption it will encrypt the key with the given newPassphrase and store it in the keystore.
func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) {
func (api *SignerAPI) Import(ctx context.Context, string, keyJSON json.RawMessage) (Account, error) {
be := api.am.Backends(keystore.KeyStoreType)
if len(be) == 0 {
@ -424,10 +422,12 @@ func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Acco
ch := make(chan ImportResponse, 1)
api.ui.ApproveImport(&ImportRequest{}, metaData(ctx), ch)
if resp := <-ch; resp.approved {
acc, err := be[0].(*keystore.KeyStore).Import(keyJSON, resp.oldPassword, resp.newPassword)
if err != nil {
api.ui.ShowError(err.Error())
return Account{}, err
}

View file

@ -1,23 +0,0 @@
package main
import (
"os"
"github.com/ethereum/go-ethereum/log"
)
type auditlogger struct{
filename string
}
func (al auditlogger) append(text string) error{
f, err := os.OpenFile(al.filename, os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
log.Crit("Failed to open audit log","err", err)
return err
}
defer f.Close()
if _, err = f.WriteString(text); err != nil {
log.Crit("Failed to write to audit log","err", err)
return err
}
}

View file

@ -54,21 +54,37 @@ func (ui *CommandlineUI) readString() string {
// readPassword reads a single line from stdin, trimming it from the trailing new
// line and returns it. The input will not be echoed.
func (ui *CommandlineUI) readPassword() string {
fmt.Printf("Enter password to approve:\n")
fmt.Printf("> ")
text, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
log.Crit("Failed to read password", "err", err)
}
fmt.Println()
fmt.Println("-----------------------")
return string(text)
}
// readPassword reads a single line from stdin, trimming it from the trailing new
// line and returns it. The input will not be echoed.
func (ui *CommandlineUI) readPasswordText(inputstring string) string {
fmt.Printf("Enter %s:\n", inputstring)
fmt.Printf("> ")
text, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
log.Crit("Failed to read password", "err", err)
}
fmt.Println("-----------------------")
return string(text)
}
// confirm returns true if user enters 'Yes', otherwise false
func (ui *CommandlineUI) confirm() bool {
fmt.Printf("Type 'Yes' to approve\n")
fmt.Printf("Type 'Yes' to approve:\n")
if ui.readString() == "Yes" {
return true
}
fmt.Println("-----------------------")
return false
}
@ -98,7 +114,7 @@ func (ui *CommandlineUI) ApproveTx(request *SignTxRequest, metadata Metadata, ch
showMetadata(metadata)
fmt.Printf("-------------------------------------------\n")
ch <- SignTxResponse{request.transaction.Hash(), ui.confirm(), ""}
ch <- SignTxResponse{request.transaction.Hash(), true ,ui.readPassword()}
}
// ApproveSignData prompt the user for confirmation to request to sign data
@ -113,7 +129,7 @@ func (ui *CommandlineUI) ApproveSignData(request *SignDataRequest, metadata Meta
fmt.Printf("message hash: %v\n", request.hash)
fmt.Printf("-------------------------------------------\n")
showMetadata(metadata)
ch <- SignDataResponse{ui.confirm(), ""}
ch <- SignDataResponse{true, ui.readPassword()}
}
// ApproveExport prompt the user for confirmation to export encrypted account json
@ -141,7 +157,11 @@ func (ui *CommandlineUI) ApproveImport(request *ImportRequest, metadata Metadata
fmt.Printf("A request has been made to import an encrypted keyfile\n")
fmt.Printf("-------------------------------------------\n")
showMetadata(metadata)
ch <- ImportResponse{ui.confirm(), "", ""}
if ui.confirm(){
ch <- ImportResponse{true, ui.readPasswordText("Old password"), ui.readPasswordText("New password")}
}else{
ch <- ImportResponse{false, "", ""}
}
}
// ApproveListing prompt the user for confirmation to list accounts
@ -177,17 +197,17 @@ func (ui *CommandlineUI) ApproveNewAccount(requst *NewAccountRequest, metadata M
fmt.Printf("Approving this operation means that a new account is created,\n")
fmt.Printf("and the address show to the caller\n")
showMetadata(metadata)
ch <- NewAccountResponse{ui.confirm(), ""}
ch <- NewAccountResponse{ui.confirm(), ui.readPassword()}
}
// ShowError displays error message to user
func (ui *CommandlineUI) ShowError(message string) {
fmt.Printf("ERROR: %v", message)
fmt.Printf("ERROR: %v\n", message)
}
// ShowInfo displays info message to user
func (ui *CommandlineUI) ShowInfo(message string) {
fmt.Printf("Info: %v", message)
fmt.Printf("Info: %v\n", message)
}

View file

@ -91,8 +91,7 @@ func main() {
c.Int64(utils.NetworkIdFlag.Name),
c.String("keystore"),
c.Bool(utils.NoUSBFlag.Name),
NewCommandlineUI(), db,
c.String("auditlog"))
NewCommandlineUI(), db)
listener net.Listener
//err error
)