mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 01:43:47 +00:00
cmd/signer: add json 4byte directory, remove passwords from api
This commit is contained in:
parent
a601b38e40
commit
f88559e09f
7 changed files with 109 additions and 39 deletions
1
cmd/signer/4byte.json
Normal file
1
cmd/signer/4byte.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -17,11 +17,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"strings"
|
||||
"bytes"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type decodedArgument struct {
|
||||
|
|
@ -97,17 +99,40 @@ func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) {
|
|||
}
|
||||
encoded, err = abispec.Pack(method.Name, gotypedArguments...)
|
||||
|
||||
if !bytes.Equal(encoded, calldata){
|
||||
if !bytes.Equal(encoded, calldata) {
|
||||
exp := common.Bytes2Hex(encoded)
|
||||
was := common.Bytes2Hex(calldata)
|
||||
return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. %v \nWant %s\nHave %s", decoded,was, exp)
|
||||
return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. %v \nWant %s\nHave %s", decoded, was, exp)
|
||||
}
|
||||
return &decoded, nil
|
||||
}
|
||||
|
||||
func lookupABI(id []byte) (string, error){
|
||||
if len(id) != 4{
|
||||
type abiDb struct {
|
||||
db map[string]string
|
||||
}
|
||||
|
||||
func NewAbiDBFromFile(path string) (*abiDb, error) {
|
||||
raw, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db := new(abiDb)
|
||||
json.Unmarshal(raw, &db.db)
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// LookupABI checks the given 4byte-sequence against the known ABI methods.
|
||||
// OBS: This method does not validate the match, it's assumed the caller will do so
|
||||
func (db *abiDb) LookupABI(id []byte) (string, error) {
|
||||
if len(id) != 4 {
|
||||
return "", fmt.Errorf("Expected 4-byte id, got %d", len(id))
|
||||
}
|
||||
return `[{"type":"function","name":"send","inputs":[{"name":"a","type":"uint256"}]}]`, nil
|
||||
}
|
||||
sig := common.ToHex(id)
|
||||
if key, exists := db.db[sig]; exists {
|
||||
return key, nil
|
||||
}
|
||||
return "", fmt.Errorf("Signature %v not found", sig)
|
||||
}
|
||||
func (db *abiDb) Size() int{
|
||||
return len(db.db)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ func TestCalldataDecoding(t *testing.T) {
|
|||
// From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
||||
// contains a bool with illegal values
|
||||
"a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
|
||||
|
||||
} {
|
||||
_, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
|
||||
if err == nil {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ type SignerAPI struct {
|
|||
chainID *big.Int
|
||||
am *accounts.Manager
|
||||
ui SignerUI
|
||||
abidb abiDb
|
||||
audit *auditlogger
|
||||
}
|
||||
|
||||
// Metadata about the request
|
||||
|
|
@ -171,7 +173,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) *SignerAPI {
|
||||
func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *abiDb, auditlog string) *SignerAPI {
|
||||
var backends []accounts.Backend
|
||||
|
||||
// support password based accounts
|
||||
|
|
@ -195,8 +197,11 @@ func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI) *Si
|
|||
log.Debug("Trezor support enabled")
|
||||
}
|
||||
}
|
||||
|
||||
return &SignerAPI{big.NewInt(chainID), accounts.NewManager(backends...), ui}
|
||||
var al *auditlogger
|
||||
if auditlog != ""{
|
||||
al = &auditlogger{auditlog}
|
||||
}
|
||||
return &SignerAPI{big.NewInt(chainID), accounts.NewManager(backends...), ui, *abidb, al}
|
||||
}
|
||||
|
||||
func metaData(ctx context.Context) Metadata {
|
||||
|
|
@ -220,15 +225,15 @@ func (api *SignerAPI) List(ctx context.Context) ([]Account, error) {
|
|||
|
||||
ch := make(chan ListResponse, 1)
|
||||
|
||||
var accounts []Account
|
||||
var accs []Account
|
||||
for _, wallet := range api.am.Wallets() {
|
||||
for _, acc := range wallet.Accounts() {
|
||||
acc := Account{Typ: "account", URL: wallet.URL(), Address: acc.Address}
|
||||
accounts = append(accounts, acc)
|
||||
accs = append(accs, acc)
|
||||
}
|
||||
}
|
||||
|
||||
api.ui.ApproveListing(&ListRequest{accounts: accounts}, metaData(ctx), ch)
|
||||
api.ui.ApproveListing(&ListRequest{accounts: accs}, metaData(ctx), ch)
|
||||
if result := <-ch; result.accounts != nil {
|
||||
return result.accounts, nil
|
||||
}
|
||||
|
|
@ -238,7 +243,7 @@ func (api *SignerAPI) List(ctx context.Context) ([]Account, error) {
|
|||
// New creates a new password protected account. The private key is protected with
|
||||
// the given password. Users are responsible to backup the private key that is stored
|
||||
// in the keystore location thas was specified when this API was created.
|
||||
func (api *SignerAPI) New(ctx context.Context, passphrase string) (accounts.Account, error) {
|
||||
func (api *SignerAPI) New(ctx context.Context) (accounts.Account, error) {
|
||||
be := api.am.Backends(keystore.KeyStoreType)
|
||||
if len(be) == 0 {
|
||||
return accounts.Account{}, errors.New("password based accounts not supported")
|
||||
|
|
@ -247,14 +252,14 @@ func (api *SignerAPI) New(ctx context.Context, passphrase string) (accounts.Acco
|
|||
api.ui.ApproveNewAccount(&NewAccountRequest{}, metaData(ctx), ch)
|
||||
|
||||
if resp := <-ch; resp.approved {
|
||||
return be[0].(*keystore.KeyStore).NewAccount(passphrase)
|
||||
return be[0].(*keystore.KeyStore).NewAccount(resp.pw)
|
||||
}
|
||||
return accounts.Account{}, fmt.Errorf("Request denied")
|
||||
}
|
||||
|
||||
// SignTransaction signs the given transaction and returns it in an RLP encoded form
|
||||
// that can be posted to `eth_sendRawTransaction`.
|
||||
func (api *SignerAPI) SignTransaction(ctx context.Context, from common.Address, passwd string, args TransactionArg) (hexutil.Bytes, error) {
|
||||
func (api *SignerAPI) SignTransaction(ctx context.Context, from common.Address, args TransactionArg) (hexutil.Bytes, error) {
|
||||
acc := accounts.Account{Address: from}
|
||||
|
||||
wallet, err := api.am.Find(acc)
|
||||
|
|
@ -274,7 +279,7 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, from common.Address,
|
|||
var abidef string
|
||||
|
||||
// Try to make sense of the data
|
||||
abidef, err = lookupABI(tx.Data()[:4])
|
||||
abidef, err = api.abidb.LookupABI(tx.Data()[:4])
|
||||
if err != nil {
|
||||
req.callinfo = errorWrapper{"Warning! Could not locate ABI", err}
|
||||
} else {
|
||||
|
|
@ -293,7 +298,7 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, from common.Address,
|
|||
if result.hash != tx.Hash() {
|
||||
return nil, fmt.Errorf("Transaction hash mismatch")
|
||||
}
|
||||
signedTx, err := wallet.SignTxWithPassphrase(acc, passwd, tx, api.chainID)
|
||||
signedTx, err := wallet.SignTxWithPassphrase(acc, result.pw, tx, api.chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -313,7 +318,7 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, from common.Address,
|
|||
// The key used to calculate the signature is decrypted with the given password.
|
||||
//
|
||||
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign
|
||||
func (api *SignerAPI) Sign(ctx context.Context, addr common.Address, passwd string, data hexutil.Bytes) (hexutil.Bytes, error) {
|
||||
func (api *SignerAPI) Sign(ctx context.Context, addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
|
||||
// Look up the wallet containing the requested signer
|
||||
account := accounts.Account{Address: addr}
|
||||
|
||||
|
|
@ -327,10 +332,10 @@ func (api *SignerAPI) Sign(ctx context.Context, addr common.Address, passwd stri
|
|||
|
||||
api.ui.ApproveSignData(&SignDataRequest{account: account, rawdata: data, message: msg, hash: sighash}, metaData(ctx), ch)
|
||||
|
||||
if (<-ch).approved {
|
||||
if res := <-ch; res.approved {
|
||||
|
||||
// Assemble sign the data with the wallet
|
||||
signature, err := wallet.SignHashWithPassphrase(account, passwd, sighash)
|
||||
signature, err := wallet.SignHashWithPassphrase(account, res.pw, sighash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -409,7 +414,7 @@ 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, passphrase, newPassphrase string) (Account, error) {
|
||||
func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) {
|
||||
be := api.am.Backends(keystore.KeyStoreType)
|
||||
|
||||
if len(be) == 0 {
|
||||
|
|
@ -421,7 +426,7 @@ func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage, passp
|
|||
api.ui.ApproveImport(&ImportRequest{}, metaData(ctx), ch)
|
||||
if resp := <-ch; resp.approved {
|
||||
|
||||
acc, err := be[0].(*keystore.KeyStore).Import(keyJSON, passphrase, newPassphrase)
|
||||
acc, err := be[0].(*keystore.KeyStore).Import(keyJSON, resp.oldPassword, resp.newPassword)
|
||||
if err != nil {
|
||||
return Account{}, err
|
||||
}
|
||||
|
|
|
|||
23
cmd/signer/auditlog.go
Normal file
23
cmd/signer/auditlog.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ func (ui *CommandlineUI) ApproveTx(request *SignTxRequest, metadata Metadata, ch
|
|||
fmt.Printf("to: %v\n", request.transaction.To().Hex())
|
||||
fmt.Printf("from: %v\n", request.from.Address.Hex())
|
||||
fmt.Printf("value: %v wei\n", weival)
|
||||
if len(request.transaction.Data()) > 0{
|
||||
if len(request.transaction.Data()) > 0 {
|
||||
fmt.Printf("data: %v\n", common.Bytes2Hex(request.transaction.Data()))
|
||||
}
|
||||
if request.callinfo != nil {
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
|
@ -61,7 +61,17 @@ func main() {
|
|||
cli.IntFlag{
|
||||
Name: "rpcport",
|
||||
Usage: "HTTP-RPC server listening port",
|
||||
Value: node.DefaultHTTPPort+5,
|
||||
Value: node.DefaultHTTPPort + 5,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "4bytedb",
|
||||
Usage: "File containing 4byte-identifiers",
|
||||
Value: "./4byte.json",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "auditlog",
|
||||
Usage: "File used to emit audit logs. Set to '' to disable",
|
||||
Value: "audit.log",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -69,15 +79,22 @@ func main() {
|
|||
// Set up the logger to print everything and the random generator
|
||||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
|
||||
|
||||
db, err := NewAbiDBFromFile(c.String("4bytedb"))
|
||||
if err != nil {
|
||||
utils.Fatalf(err.Error())
|
||||
}
|
||||
log.Info("Loaded 4byte db", "signatures", db.Size(), "file", c.String("4bytedb"))
|
||||
|
||||
var (
|
||||
server = rpc.NewServer()
|
||||
api = NewSignerAPI(
|
||||
c.Int64(utils.NetworkIdFlag.Name),
|
||||
c.String("keystore"),
|
||||
c.Bool(utils.NoUSBFlag.Name),
|
||||
NewCommandlineUI())
|
||||
server = rpc.NewServer()
|
||||
api = NewSignerAPI(
|
||||
c.Int64(utils.NetworkIdFlag.Name),
|
||||
c.String("keystore"),
|
||||
c.Bool(utils.NoUSBFlag.Name),
|
||||
NewCommandlineUI(), db,
|
||||
c.String("auditlog"))
|
||||
listener net.Listener
|
||||
err error
|
||||
//err error
|
||||
)
|
||||
|
||||
// register signer API with server
|
||||
|
|
@ -107,9 +124,9 @@ func main() {
|
|||
// curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_list","params":[""],"id":67}' http://localhost:8550/
|
||||
|
||||
// Make transaction
|
||||
// send(0x12)
|
||||
// a52c101e0000000000000000000000000000000000000000000000000000000000000012
|
||||
// curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":["0x82A2A876D39022B3019932D30Cd9c97ad5616813","pw",{"gas":"0x333","gasPrice":"0x123","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x10", "input":"0xa52c101e0000000000000000000000000000000000000000000000000000000000000012"}],"id":67}' http://localhost:8550/
|
||||
// safeSend(0x12)
|
||||
// 4401a6e40000000000000000000000000000000000000000000000000000000000000012
|
||||
// curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":["0x82A2A876D39022B3019932D30Cd9c97ad5616813","pw",{"gas":"0x333","gasPrice":"0x123","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x10", "input":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"}],"id":67}' http://localhost:8550/
|
||||
|
||||
type rwc struct {
|
||||
io.Reader
|
||||
|
|
|
|||
Loading…
Reference in a new issue