github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/signer/rules/rules.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:42</date> 10 //</624450110876553216> 11 12 13 package rules 14 15 import ( 16 "encoding/json" 17 "fmt" 18 "os" 19 "strings" 20 21 "github.com/ethereum/go-ethereum/common" 22 "github.com/ethereum/go-ethereum/internal/ethapi" 23 "github.com/ethereum/go-ethereum/log" 24 "github.com/ethereum/go-ethereum/signer/core" 25 "github.com/ethereum/go-ethereum/signer/rules/deps" 26 "github.com/ethereum/go-ethereum/signer/storage" 27 "github.com/robertkrimen/otto" 28 ) 29 30 var ( 31 BigNumber_JS = deps.MustAsset("bignumber.js") 32 ) 33 34 //consoleoutput是console.log和console.error方法的重写,用于 35 //将输出流传输到配置的输出流,而不是stdout。 36 func consoleOutput(call otto.FunctionCall) otto.Value { 37 output := []string{"JS:> "} 38 for _, argument := range call.ArgumentList { 39 output = append(output, fmt.Sprintf("%v", argument)) 40 } 41 fmt.Fprintln(os.Stdout, strings.Join(output, " ")) 42 return otto.Value{} 43 } 44 45 //rulesetui提供了一个signerui的实现,它评估一个javascript 46 //每个定义的UI方法的文件 47 type rulesetUI struct { 48 next core.SignerUI //下一个处理程序,用于手动处理 49 storage storage.Storage 50 credentials storage.Storage 51 jsRules string //使用的规则 52 } 53 54 func NewRuleEvaluator(next core.SignerUI, jsbackend, credentialsBackend storage.Storage) (*rulesetUI, error) { 55 c := &rulesetUI{ 56 next: next, 57 storage: jsbackend, 58 credentials: credentialsBackend, 59 jsRules: "", 60 } 61 62 return c, nil 63 } 64 65 func (r *rulesetUI) Init(javascriptRules string) error { 66 r.jsRules = javascriptRules 67 return nil 68 } 69 func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (otto.Value, error) { 70 71 //每次实例化一个新的VM引擎 72 vm := otto.New() 73 //设置本机回调 74 consoleObj, _ := vm.Get("console") 75 consoleObj.Object().Set("log", consoleOutput) 76 consoleObj.Object().Set("error", consoleOutput) 77 vm.Set("storage", r.storage) 78 79 //加载引导程序库 80 script, err := vm.Compile("bignumber.js", BigNumber_JS) 81 if err != nil { 82 log.Warn("Failed loading libraries", "err", err) 83 return otto.UndefinedValue(), err 84 } 85 vm.Run(script) 86 87 //运行实际规则实现 88 _, err = vm.Run(r.jsRules) 89 if err != nil { 90 log.Warn("Execution failed", "err", err) 91 return otto.UndefinedValue(), err 92 } 93 94 //和实际通话 95 //所有调用都是对象,其中参数是该对象中的键。 96 //为了在JS和Go之间提供额外的隔离,我们在Go端将其序列化为JSON, 97 //并在JS端对其进行反序列化。 98 99 jsonbytes, err := json.Marshal(jsarg) 100 if err != nil { 101 log.Warn("failed marshalling data", "data", jsarg) 102 return otto.UndefinedValue(), err 103 } 104 //现在,我们称之为foobar(json.parse(<jsondata>)。 105 var call string 106 if len(jsonbytes) > 0 { 107 call = fmt.Sprintf("%v(JSON.parse(%v))", jsfunc, string(jsonbytes)) 108 } else { 109 call = fmt.Sprintf("%v()", jsfunc) 110 } 111 return vm.Run(call) 112 } 113 114 func (r *rulesetUI) checkApproval(jsfunc string, jsarg []byte, err error) (bool, error) { 115 if err != nil { 116 return false, err 117 } 118 v, err := r.execute(jsfunc, string(jsarg)) 119 if err != nil { 120 log.Info("error occurred during execution", "error", err) 121 return false, err 122 } 123 result, err := v.ToString() 124 if err != nil { 125 log.Info("error occurred during response unmarshalling", "error", err) 126 return false, err 127 } 128 if result == "Approve" { 129 log.Info("Op approved") 130 return true, nil 131 } else if result == "Reject" { 132 log.Info("Op rejected") 133 return false, nil 134 } 135 return false, fmt.Errorf("Unknown response") 136 } 137 138 func (r *rulesetUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { 139 jsonreq, err := json.Marshal(request) 140 approved, err := r.checkApproval("ApproveTx", jsonreq, err) 141 if err != nil { 142 log.Info("Rule-based approval error, going to manual", "error", err) 143 return r.next.ApproveTx(request) 144 } 145 146 if approved { 147 return core.SignTxResponse{ 148 Transaction: request.Transaction, 149 Approved: true, 150 Password: r.lookupPassword(request.Transaction.From.Address()), 151 }, 152 nil 153 } 154 return core.SignTxResponse{Approved: false}, err 155 } 156 157 func (r *rulesetUI) lookupPassword(address common.Address) string { 158 return r.credentials.Get(strings.ToLower(address.String())) 159 } 160 161 func (r *rulesetUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) { 162 jsonreq, err := json.Marshal(request) 163 approved, err := r.checkApproval("ApproveSignData", jsonreq, err) 164 if err != nil { 165 log.Info("Rule-based approval error, going to manual", "error", err) 166 return r.next.ApproveSignData(request) 167 } 168 if approved { 169 return core.SignDataResponse{Approved: true, Password: r.lookupPassword(request.Address.Address())}, nil 170 } 171 return core.SignDataResponse{Approved: false, Password: ""}, err 172 } 173 174 func (r *rulesetUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) { 175 jsonreq, err := json.Marshal(request) 176 approved, err := r.checkApproval("ApproveExport", jsonreq, err) 177 if err != nil { 178 log.Info("Rule-based approval error, going to manual", "error", err) 179 return r.next.ApproveExport(request) 180 } 181 if approved { 182 return core.ExportResponse{Approved: true}, nil 183 } 184 return core.ExportResponse{Approved: false}, err 185 } 186 187 func (r *rulesetUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) { 188 //这不能由规则处理,需要设置密码 189 //发送到下一个 190 return r.next.ApproveImport(request) 191 } 192 193 //规则未处理OnInputRequired 194 func (r *rulesetUI) OnInputRequired(info core.UserInputRequest) (core.UserInputResponse, error) { 195 return r.next.OnInputRequired(info) 196 } 197 198 func (r *rulesetUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { 199 jsonreq, err := json.Marshal(request) 200 approved, err := r.checkApproval("ApproveListing", jsonreq, err) 201 if err != nil { 202 log.Info("Rule-based approval error, going to manual", "error", err) 203 return r.next.ApproveListing(request) 204 } 205 if approved { 206 return core.ListResponse{Accounts: request.Accounts}, nil 207 } 208 return core.ListResponse{}, err 209 } 210 211 func (r *rulesetUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) { 212 //这不能由规则处理,需要设置密码 213 //发送到下一个 214 return r.next.ApproveNewAccount(request) 215 } 216 217 func (r *rulesetUI) ShowError(message string) { 218 log.Error(message) 219 r.next.ShowError(message) 220 } 221 222 func (r *rulesetUI) ShowInfo(message string) { 223 log.Info(message) 224 r.next.ShowInfo(message) 225 } 226 227 func (r *rulesetUI) OnSignerStartup(info core.StartupInfo) { 228 jsonInfo, err := json.Marshal(info) 229 if err != nil { 230 log.Warn("failed marshalling data", "data", info) 231 return 232 } 233 r.next.OnSignerStartup(info) 234 _, err = r.execute("OnSignerStartup", string(jsonInfo)) 235 if err != nil { 236 log.Info("error occurred during execution", "error", err) 237 } 238 } 239 240 func (r *rulesetUI) OnApprovedTx(tx ethapi.SignTransactionResult) { 241 jsonTx, err := json.Marshal(tx) 242 if err != nil { 243 log.Warn("failed marshalling transaction", "tx", tx) 244 return 245 } 246 _, err = r.execute("OnApprovedTx", string(jsonTx)) 247 if err != nil { 248 log.Info("error occurred during execution", "error", err) 249 } 250 } 251