github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/rpc/useragent/remote_frontend.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package useragent 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "net" 23 24 "github.com/ethereum/go-ethereum/accounts" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/logger" 27 "github.com/ethereum/go-ethereum/logger/glog" 28 "github.com/ethereum/go-ethereum/rpc/shared" 29 ) 30 31 // remoteFrontend implements xeth.Frontend and will communicate with an external 32 // user agent over a connection 33 type RemoteFrontend struct { 34 enabled bool 35 mgr *accounts.Manager 36 d *json.Decoder 37 e *json.Encoder 38 n int 39 } 40 41 // NewRemoteFrontend creates a new frontend which will interact with an user agent 42 // over the given connection 43 func NewRemoteFrontend(conn net.Conn, mgr *accounts.Manager) *RemoteFrontend { 44 return &RemoteFrontend{false, mgr, json.NewDecoder(conn), json.NewEncoder(conn), 0} 45 } 46 47 // Enable will enable user interaction 48 func (fe *RemoteFrontend) Enable() { 49 fe.enabled = true 50 } 51 52 // UnlockAccount asks the user agent for the user password and tries to unlock the account. 53 // It will try 3 attempts before giving up. 54 func (fe *RemoteFrontend) UnlockAccount(address []byte) bool { 55 if !fe.enabled { 56 return false 57 } 58 59 err := fe.send(AskPasswordMethod, common.Bytes2Hex(address)) 60 if err != nil { 61 glog.V(logger.Error).Infof("Unable to send password request to agent - %v\n", err) 62 return false 63 } 64 65 passwdRes, err := fe.recv() 66 if err != nil { 67 glog.V(logger.Error).Infof("Unable to recv password response from agent - %v\n", err) 68 return false 69 } 70 71 if passwd, ok := passwdRes.Result.(string); ok { 72 err = fe.mgr.Unlock(common.BytesToAddress(address), passwd) 73 } 74 75 if err == nil { 76 return true 77 } 78 79 glog.V(logger.Debug).Infoln("3 invalid account unlock attempts") 80 return false 81 } 82 83 // ConfirmTransaction asks the user for approval 84 func (fe *RemoteFrontend) ConfirmTransaction(tx string) bool { 85 if !fe.enabled { 86 return true // backwards compatibility 87 } 88 89 err := fe.send(ConfirmTransactionMethod, tx) 90 if err != nil { 91 glog.V(logger.Error).Infof("Unable to send tx confirmation request to agent - %v\n", err) 92 return false 93 } 94 95 confirmResponse, err := fe.recv() 96 if err != nil { 97 glog.V(logger.Error).Infof("Unable to recv tx confirmation response from agent - %v\n", err) 98 return false 99 } 100 101 if confirmed, ok := confirmResponse.Result.(bool); ok { 102 return confirmed 103 } 104 105 return false 106 } 107 108 // send request to the agent 109 func (fe *RemoteFrontend) send(method string, params ...interface{}) error { 110 fe.n += 1 111 112 p, err := json.Marshal(params) 113 if err != nil { 114 glog.V(logger.Info).Infof("Unable to send agent request %v\n", err) 115 return err 116 } 117 118 req := shared.Request{ 119 Method: method, 120 Jsonrpc: shared.JsonRpcVersion, 121 Id: fe.n, 122 Params: p, 123 } 124 125 return fe.e.Encode(&req) 126 } 127 128 // recv user response from agent 129 func (fe *RemoteFrontend) recv() (*shared.SuccessResponse, error) { 130 var res json.RawMessage 131 if err := fe.d.Decode(&res); err != nil { 132 return nil, err 133 } 134 135 var response shared.SuccessResponse 136 if err := json.Unmarshal(res, &response); err == nil { 137 return &response, nil 138 } 139 140 return nil, fmt.Errorf("Invalid user agent response") 141 }