diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 2781be656f..045c8854ef 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -45,9 +45,10 @@ type Account struct { } type Manager struct { - keyStore crypto.KeyStore - unlocked map[common.Address]*unlocked - mutex sync.RWMutex + keyStore crypto.KeyStore + unlocked map[common.Address]*unlocked + mutex sync.RWMutex + dangerZone bool } type unlocked struct { @@ -62,6 +63,17 @@ func NewManager(keyStore crypto.KeyStore) *Manager { } } +func (am *Manager) SetDangerZone(toggle bool) { + if toggle { + fmt.Println("WARNING: Accounts unlocking enabled even if RPC running!") + } + am.dangerZone = toggle +} + +func (am *Manager) DangerZone() bool { + return am.dangerZone +} + func (am *Manager) HasAccount(addr common.Address) bool { accounts, _ := am.Accounts() for _, acct := range accounts { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index ba753a4936..862c23b113 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -278,6 +278,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.IdentityFlag, utils.UnlockedAccountFlag, utils.PasswordFileFlag, + utils.DangerZoneFlag, utils.GenesisFileFlag, utils.BootnodesFlag, utils.DataDirFlag, @@ -548,7 +549,12 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) { utils.StartEthereum(eth) am := eth.AccountManager() + dangerZone := ctx.GlobalBool(utils.DangerZoneFlag.Name) + am.SetDangerZone(dangerZone) account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) + if ctx.GlobalBool(utils.RPCEnabledFlag.Name) && account != "" && !dangerZone { + utils.Fatalf("Accounts cannot be unlocked if RPC is enabled. To force this combination, run with --dangerzone") + } accounts := strings.Split(account, " ") for i, account := range accounts { if len(account) > 0 { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 95fb649e63..126fd7c598 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -183,6 +183,10 @@ var ( Usage: "Path to password file to use with options and subcommands needing a password", Value: "", } + DangerZoneFlag = cli.BoolFlag{ + Name: "dangerzone", + Usage: "Enables unlocking of accounts when RPC is enabled.", + } // vm flags VMDebugFlag = cli.BoolFlag{ @@ -585,8 +589,12 @@ func StartIPC(eth *eth.Ethereum, ctx *cli.Context) error { } func StartRPC(eth *eth.Ethereum, ctx *cli.Context) error { + listenAddr := ctx.GlobalString(RPCListenAddrFlag.Name) + if listenAddr == "0.0.0.0" { + glog.V(logger.Info).Infoln("WARNING: RPC reachable from any IP!") + } config := comms.HttpConfig{ - ListenAddress: ctx.GlobalString(RPCListenAddrFlag.Name), + ListenAddress: listenAddr, ListenPort: uint(ctx.GlobalInt(RPCPortFlag.Name)), CorsDomain: ctx.GlobalString(RPCCORSDomainFlag.Name), } diff --git a/rpc/api/personal.go b/rpc/api/personal.go index 1fb412612b..b9611f696b 100644 --- a/rpc/api/personal.go +++ b/rpc/api/personal.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/rpc/codec" + "github.com/ethereum/go-ethereum/rpc/comms" "github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/xeth" ) @@ -105,6 +106,9 @@ func (self *personalApi) NewAccount(req *shared.Request) (interface{}, error) { } func (self *personalApi) UnlockAccount(req *shared.Request) (interface{}, error) { + if comms.IsRPCRunning() && !self.ethereum.AccountManager().DangerZone() { + return false, fmt.Errorf("Cannot unlock accounts while RPC is running. Run with --dangerzone to enable.") + } args := new(UnlockAccountArgs) if err := self.codec.Decode(req.Params, &args); err != nil { return nil, shared.NewDecodeParamError(err.Error()) diff --git a/rpc/comms/http.go b/rpc/comms/http.go index f4a930d0ef..706ca78de9 100644 --- a/rpc/comms/http.go +++ b/rpc/comms/http.go @@ -100,6 +100,12 @@ func StartHttp(cfg HttpConfig, codec codec.Codec, api shared.EthereumApi) error return nil } +func IsRPCRunning() bool { + httpServerMu.Lock() + defer httpServerMu.Unlock() + return httpServer != nil +} + func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.Header().Set("Content-Type", "application/json")