5f94f8c7e7
This PR will will break existing UIs, since it changes all calls like ApproveSignTransaction to be on the form ui_approveSignTransaction. This is to make it possible for the UI to reuse the json-rpc library from go-ethereum, which uses this convention. Also, this PR removes some unused structs, after import/export were removed from the external api (so no longer needs internal methods for approval) One more breaking change is introduced, removing passwords from the ApproveSignTxResponse and the likes. This makes the manual interface more like the rulebased interface, and integrates nicely with the credential storage. Thus, the way it worked before, it would be tempting for the UI to implement 'remember password' functionality. The way it is now, it will be easy instead to tell clef to store passwords and use them. If a pw is not found in the credential store, the user is prompted to provide the password.
124 lines
3.7 KiB
Go
124 lines
3.7 KiB
Go
// Copyright 2018 The go-ethereum Authors
|
|
// This file is part of go-ethereum.
|
|
//
|
|
// go-ethereum is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// go-ethereum is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
package core
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
|
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
)
|
|
|
|
type StdIOUI struct {
|
|
client rpc.Client
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func NewStdIOUI() *StdIOUI {
|
|
client, err := rpc.DialContext(context.Background(), "stdio://")
|
|
if err != nil {
|
|
log.Crit("Could not create stdio client", "err", err)
|
|
}
|
|
ui := &StdIOUI{client: *client}
|
|
return ui
|
|
}
|
|
|
|
func (ui *StdIOUI) RegisterUIServer(api *UIServerAPI) {
|
|
ui.client.RegisterName("clef", api)
|
|
}
|
|
|
|
// dispatch sends a request over the stdio
|
|
func (ui *StdIOUI) dispatch(serviceMethod string, args interface{}, reply interface{}) error {
|
|
err := ui.client.Call(&reply, serviceMethod, args)
|
|
if err != nil {
|
|
log.Info("Error", "exc", err.Error())
|
|
}
|
|
return err
|
|
}
|
|
|
|
// notify sends a request over the stdio, and does not listen for a response
|
|
func (ui *StdIOUI) notify(serviceMethod string, args interface{}) error {
|
|
ctx := context.Background()
|
|
err := ui.client.Notify(ctx, serviceMethod, args)
|
|
if err != nil {
|
|
log.Info("Error", "exc", err.Error())
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (ui *StdIOUI) ApproveTx(request *SignTxRequest) (SignTxResponse, error) {
|
|
var result SignTxResponse
|
|
err := ui.dispatch("ui_approveTx", request, &result)
|
|
return result, err
|
|
}
|
|
|
|
func (ui *StdIOUI) ApproveSignData(request *SignDataRequest) (SignDataResponse, error) {
|
|
var result SignDataResponse
|
|
err := ui.dispatch("ui_approveSignData", request, &result)
|
|
return result, err
|
|
}
|
|
|
|
func (ui *StdIOUI) ApproveListing(request *ListRequest) (ListResponse, error) {
|
|
var result ListResponse
|
|
err := ui.dispatch("ui_approveListing", request, &result)
|
|
return result, err
|
|
}
|
|
|
|
func (ui *StdIOUI) ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) {
|
|
var result NewAccountResponse
|
|
err := ui.dispatch("ui_approveNewAccount", request, &result)
|
|
return result, err
|
|
}
|
|
|
|
func (ui *StdIOUI) ShowError(message string) {
|
|
err := ui.notify("ui_showError", &Message{message})
|
|
if err != nil {
|
|
log.Info("Error calling 'ui_showError'", "exc", err.Error(), "msg", message)
|
|
}
|
|
}
|
|
|
|
func (ui *StdIOUI) ShowInfo(message string) {
|
|
err := ui.notify("ui_showInfo", Message{message})
|
|
if err != nil {
|
|
log.Info("Error calling 'ui_showInfo'", "exc", err.Error(), "msg", message)
|
|
}
|
|
}
|
|
func (ui *StdIOUI) OnApprovedTx(tx ethapi.SignTransactionResult) {
|
|
err := ui.notify("ui_onApprovedTx", tx)
|
|
if err != nil {
|
|
log.Info("Error calling 'ui_onApprovedTx'", "exc", err.Error(), "tx", tx)
|
|
}
|
|
}
|
|
|
|
func (ui *StdIOUI) OnSignerStartup(info StartupInfo) {
|
|
err := ui.notify("ui_onSignerStartup", info)
|
|
if err != nil {
|
|
log.Info("Error calling 'ui_onSignerStartup'", "exc", err.Error(), "info", info)
|
|
}
|
|
}
|
|
func (ui *StdIOUI) OnInputRequired(info UserInputRequest) (UserInputResponse, error) {
|
|
var result UserInputResponse
|
|
err := ui.dispatch("ui_onInputRequired", info, &result)
|
|
if err != nil {
|
|
log.Info("Error calling 'ui_onInputRequired'", "exc", err.Error(), "info", info)
|
|
}
|
|
return result, err
|
|
}
|