signer/rules: implement dispatching to next handler

This commit is contained in:
Martin Holst Swende 2018-02-15 12:10:29 +01:00
parent 99dd0a1b58
commit 3ade6cb242
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
2 changed files with 82 additions and 21 deletions

View file

@ -19,6 +19,7 @@ package rules
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/cmd/signer/core"
"github.com/ethereum/go-ethereum/cmd/signer/rules/deps" "github.com/ethereum/go-ethereum/cmd/signer/rules/deps"
"github.com/ethereum/go-ethereum/cmd/signer/storage" "github.com/ethereum/go-ethereum/cmd/signer/storage"
"github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/ethapi"
@ -26,7 +27,6 @@ import (
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
"os" "os"
"strings" "strings"
"github.com/ethereum/go-ethereum/cmd/signer/core"
) )
var ( var (
@ -47,14 +47,15 @@ func consoleOutput(call otto.FunctionCall) otto.Value {
// rulesetUi provides an implementation of SignerUI that evaluates a javascript // rulesetUi provides an implementation of SignerUI that evaluates a javascript
// file for each defined UI-method // file for each defined UI-method
type rulesetUi struct { type rulesetUi struct {
vm *otto.Otto // The JS vm vm *otto.Otto // The JS vm
next core.SignerUI // The next handler, for manual processing next core.SignerUI // The next handler, for manual processing
storage storage.Storage storage storage.Storage
} }
func NewRuleEvaluator() (*rulesetUi, error) { func NewRuleEvaluator(next core.SignerUI) (*rulesetUi, error) {
c := &rulesetUi{ c := &rulesetUi{
vm: otto.New(), vm: otto.New(),
next: next,
storage: storage.NewEphemeralStorage(), storage: storage.NewEphemeralStorage(),
} }
consoleObj, _ := c.vm.Get("console") consoleObj, _ := c.vm.Get("console")
@ -81,32 +82,38 @@ func (r *rulesetUi) Init(javascriptRules string) error {
return err return err
} }
func (r *rulesetUi) checkApproval(jsfunc string, jsarg []byte, err error) error { func (r *rulesetUi) checkApproval(jsfunc string, jsarg []byte, err error) (bool, error) {
if err != nil { if err != nil {
return err return false, err
} }
v, err := r.vm.Call(jsfunc, nil, string(jsarg)) v, err := r.vm.Call(jsfunc, nil, string(jsarg))
if err != nil { if err != nil {
log.Info("error occurred during execution", "error", err) log.Info("error occurred during execution", "error", err)
return err return false, err
} }
result, err := v.ToString() result, err := v.ToString()
if err != nil { if err != nil {
log.Info("error occurred during response unmarshalling", "error", err) log.Info("error occurred during response unmarshalling", "error", err)
return err return false, err
} }
if result == "Approve" { if result == "Approve" {
log.Info("Op approved") log.Info("Op approved")
return nil return true, nil
} else if result == "Reject" {
log.Info("Op rejected")
return false, nil
} }
return fmt.Errorf("rejected") return false, fmt.Errorf("Unknown response")
} }
func (r *rulesetUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { func (r *rulesetUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
jsonreq, err := json.Marshal(request) jsonreq, err := json.Marshal(request)
if err = r.checkApproval("ApproveTx", jsonreq, err); err == nil { approved, err := r.checkApproval("ApproveTx", jsonreq, err)
if err != nil {
log.Info("Rule-based approval error, going to manual", "error", "err")
return r.next.ApproveTx(request)
}
if approved {
return core.SignTxResponse{Transaction: request.Transaction, Approved: true, Password: ""}, nil return core.SignTxResponse{Transaction: request.Transaction, Approved: true, Password: ""}, nil
} }
return core.SignTxResponse{Approved: false}, err return core.SignTxResponse{Approved: false}, err
@ -114,7 +121,12 @@ func (r *rulesetUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse,
func (r *rulesetUi) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) { func (r *rulesetUi) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
jsonreq, err := json.Marshal(request) jsonreq, err := json.Marshal(request)
if err = r.checkApproval("ApproveTx", jsonreq, err); err == nil { approved, err := r.checkApproval("ApproveSignData", jsonreq, err)
if err != nil {
log.Info("Rule-based approval error, going to manual", "error", "err")
return r.next.ApproveSignData(request)
}
if approved {
return core.SignDataResponse{Approved: true, Password: ""}, nil return core.SignDataResponse{Approved: true, Password: ""}, nil
} }
return core.SignDataResponse{Approved: false, Password: ""}, err return core.SignDataResponse{Approved: false, Password: ""}, err
@ -122,7 +134,12 @@ func (r *rulesetUi) ApproveSignData(request *core.SignDataRequest) (core.SignDat
func (r *rulesetUi) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) { func (r *rulesetUi) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
jsonreq, err := json.Marshal(request) jsonreq, err := json.Marshal(request)
if err = r.checkApproval("ApproveTx", jsonreq, err); err == nil { approved, err := r.checkApproval("ApproveExport", jsonreq, err)
if err != nil {
log.Info("Rule-based approval error, going to manual", "error", "err")
return r.next.ApproveExport(request)
}
if approved {
return core.ExportResponse{Approved: true}, nil return core.ExportResponse{Approved: true}, nil
} }
return core.ExportResponse{Approved: false}, err return core.ExportResponse{Approved: false}, err
@ -136,7 +153,12 @@ func (r *rulesetUi) ApproveImport(request *core.ImportRequest) (core.ImportRespo
func (r *rulesetUi) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { func (r *rulesetUi) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
jsonreq, err := json.Marshal(request) jsonreq, err := json.Marshal(request)
if err = r.checkApproval("ApproveListing", jsonreq, err); err == nil { approved, err := r.checkApproval("ApproveListing", jsonreq, err)
if err != nil {
log.Info("Rule-based approval error, going to manual", "error", "err")
return r.next.ApproveListing(request)
}
if approved {
return core.ListResponse{Accounts: request.Accounts}, nil return core.ListResponse{Accounts: request.Accounts}, nil
} }
return core.ListResponse{}, err return core.ListResponse{}, err
@ -157,8 +179,8 @@ func (r *rulesetUi) ShowInfo(message string) {
log.Info(message) log.Info(message)
r.next.ShowInfo(message) r.next.ShowInfo(message)
} }
func (r *rulesetUi) OnApprovedTx(tx ethapi.SignTransactionResult) {
func (r *rulesetUi) OnApprovedTx(tx ethapi.SignTransactionResult) {
jsonTx, err := json.Marshal(tx) jsonTx, err := json.Marshal(tx)
if err != nil { if err != nil {
log.Warn("failed marshalling transaction", "tx", tx) log.Warn("failed marshalling transaction", "tx", tx)
@ -169,5 +191,4 @@ func (r *rulesetUi) OnApprovedTx(tx ethapi.SignTransactionResult) {
fmt.Printf("Error in onapprove %v", err) fmt.Printf("Error in onapprove %v", err)
log.Warn("error occurred during execution", "error", err) log.Warn("error occurred during execution", "error", err)
} }
} }

View file

@ -53,9 +53,46 @@ func hexAddr(a string) common.Address { return common.BytesToAddress(common.Hex2
func mixAddr(a string) (*common.MixedcaseAddress, error) { func mixAddr(a string) (*common.MixedcaseAddress, error) {
return common.NewMixedcaseAddressFromString(a) return common.NewMixedcaseAddressFromString(a)
} }
type alwaysDenyUi struct{}
func (alwaysDenyUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
return core.SignTxResponse{request.Transaction, false, ""}, nil
}
func (alwaysDenyUi) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
return core.SignDataResponse{false, ""}, nil
}
func (alwaysDenyUi) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
return core.ExportResponse{false}, nil
}
func (alwaysDenyUi) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) {
return core.ImportResponse{false, "", ""}, nil
}
func (alwaysDenyUi) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
return core.ListResponse{nil}, nil
}
func (alwaysDenyUi) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) {
return core.NewAccountResponse{false, ""}, nil
}
func (alwaysDenyUi) ShowError(message string) {
panic("implement me")
}
func (alwaysDenyUi) ShowInfo(message string) {
panic("implement me")
}
func (alwaysDenyUi) OnApprovedTx(tx ethapi.SignTransactionResult) {
panic("implement me")
}
func initRuleEngine(js string) (*rulesetUi, error) { func initRuleEngine(js string) (*rulesetUi, error) {
r, err := NewRuleEvaluator() r, err := NewRuleEvaluator(&alwaysDenyUi{})
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to create js engine: %v", err) return nil, fmt.Errorf("Failed to create js engine: %v", err)
} }
@ -154,10 +191,13 @@ func TestMissingFunc(t *testing.T) {
t.Error("Expected error") t.Error("Expected error")
} }
if r.checkApproval("MissingMethod", nil, nil) == nil { approved, err := r.checkApproval("MissingMethod", nil, nil);
t.Errorf("Expected error to resolve to 'Reject'") if err == nil {
t.Errorf("Expected missing method to yield error'")
}
if approved{
t.Errorf("Expected missing method to cause non-approval")
} }
fmt.Printf("Err %v", err) fmt.Printf("Err %v", err)
} }