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  }