remote_frontend.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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. package useragent
  17. import (
  18. "encoding/json"
  19. "fmt"
  20. "net"
  21. "github.com/ethereum/go-ethereum/accounts"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/logger"
  24. "github.com/ethereum/go-ethereum/logger/glog"
  25. "github.com/ethereum/go-ethereum/rpc/shared"
  26. )
  27. // remoteFrontend implements xeth.Frontend and will communicate with an external
  28. // user agent over a connection
  29. type RemoteFrontend struct {
  30. enabled bool
  31. mgr *accounts.Manager
  32. d *json.Decoder
  33. e *json.Encoder
  34. n int
  35. }
  36. // NewRemoteFrontend creates a new frontend which will interact with an user agent
  37. // over the given connection
  38. func NewRemoteFrontend(conn net.Conn, mgr *accounts.Manager) *RemoteFrontend {
  39. return &RemoteFrontend{false, mgr, json.NewDecoder(conn), json.NewEncoder(conn), 0}
  40. }
  41. // Enable will enable user interaction
  42. func (fe *RemoteFrontend) Enable() {
  43. fe.enabled = true
  44. }
  45. func (fe *RemoteFrontend) AskPassword() (string, bool) {
  46. if !fe.enabled {
  47. return "", false
  48. }
  49. err := fe.send(AskPasswordMethod)
  50. if err != nil {
  51. glog.V(logger.Error).Infof("Unable to send password request to agent - %v\n", err)
  52. return "", false
  53. }
  54. passwdRes, err := fe.recv()
  55. if err != nil {
  56. glog.V(logger.Error).Infof("Unable to recv password response from agent - %v\n", err)
  57. return "", false
  58. }
  59. if passwd, ok := passwdRes.Result.(string); ok {
  60. return passwd, true
  61. }
  62. return "", false
  63. }
  64. // UnlockAccount asks the user agent for the user password and tries to unlock the account.
  65. // It will try 3 attempts before giving up.
  66. func (fe *RemoteFrontend) UnlockAccount(address []byte) bool {
  67. if !fe.enabled {
  68. return false
  69. }
  70. err := fe.send(AskPasswordMethod, common.Bytes2Hex(address))
  71. if err != nil {
  72. glog.V(logger.Error).Infof("Unable to send password request to agent - %v\n", err)
  73. return false
  74. }
  75. passwdRes, err := fe.recv()
  76. if err != nil {
  77. glog.V(logger.Error).Infof("Unable to recv password response from agent - %v\n", err)
  78. return false
  79. }
  80. if passwd, ok := passwdRes.Result.(string); ok {
  81. err = fe.mgr.Unlock(common.BytesToAddress(address), passwd)
  82. }
  83. if err == nil {
  84. return true
  85. }
  86. glog.V(logger.Debug).Infoln("3 invalid account unlock attempts")
  87. return false
  88. }
  89. // ConfirmTransaction asks the user for approval
  90. func (fe *RemoteFrontend) ConfirmTransaction(tx string) bool {
  91. if !fe.enabled {
  92. return true // backwards compatibility
  93. }
  94. err := fe.send(ConfirmTransactionMethod, tx)
  95. if err != nil {
  96. glog.V(logger.Error).Infof("Unable to send tx confirmation request to agent - %v\n", err)
  97. return false
  98. }
  99. confirmResponse, err := fe.recv()
  100. if err != nil {
  101. glog.V(logger.Error).Infof("Unable to recv tx confirmation response from agent - %v\n", err)
  102. return false
  103. }
  104. if confirmed, ok := confirmResponse.Result.(bool); ok {
  105. return confirmed
  106. }
  107. return false
  108. }
  109. // send request to the agent
  110. func (fe *RemoteFrontend) send(method string, params ...interface{}) error {
  111. fe.n += 1
  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. req := shared.Request{
  118. Method: method,
  119. Jsonrpc: shared.JsonRpcVersion,
  120. Id: fe.n,
  121. Params: p,
  122. }
  123. return fe.e.Encode(&req)
  124. }
  125. // recv user response from agent
  126. func (fe *RemoteFrontend) recv() (*shared.SuccessResponse, error) {
  127. var res json.RawMessage
  128. if err := fe.d.Decode(&res); err != nil {
  129. return nil, err
  130. }
  131. var response shared.SuccessResponse
  132. if err := json.Unmarshal(res, &response); err == nil {
  133. return &response, nil
  134. }
  135. return nil, fmt.Errorf("Invalid user agent response")
  136. }