From 97c9d986d465dab0c7dac2222bba6b0bfc75b9ab Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Thu, 14 Aug 2014 14:23:47 -0500 Subject: [PATCH] Log an unexpected error that was encountered. The stack trace did not make it evidant which request had caused this issue, so add extra logging for the request that caused it. Sanitize this request if it may contain any secrets. Additionally, in this situation, begin shutting down the wallet rather than simply dropping the response. This will help to catch the issue since it's easier to notice all requests failing, rather than just one that was dropped. If shutdown takes an unreasonably long time, panic. --- rpcserver.go | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/rpcserver.go b/rpcserver.go index 3509bb6..bd5e806 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -658,6 +658,27 @@ type rawRequest struct { Params []json.RawMessage `json:"params"` } +// String returns a sanitized string for the request which may be safely +// logged. It is intended to strip private keys, passphrases, and any other +// secrets from request parameters before they may be saved to a log file. +// +// This intentionally implements the fmt.Stringer interface to prevent +// accidental leaking of secrets. +func (r *rawRequest) String() string { + // These are considered unsafe to log, so sanitize parameters. + switch r.Method { + case "encryptwallet", "importprivkey", "importwallet", + "signrawtransaction", "walletpassphrase", + "walletpassphrasechange": + + return fmt.Sprintf(`{"id":%v,"method":"%s","params":SANITIZED %d parameters}`, + r.ID, r.Method, len(r.Params)) + } + + return fmt.Sprintf(`{"id":%v,"method":"%s","params":%v}`, r.ID, + r.Method, r.Params) +} + // idPointer returns a pointer to the passed ID, or nil if the interface is nil. // Interface pointers are usually a red flag of doing something incorrectly, // but this is only implemented here to work around an oddity with btcjson, @@ -796,7 +817,22 @@ out: resp := f(request, raw) mresp, err := json.Marshal(resp) if err != nil { - panic(err) + // Completely unexpected error, but have seen + // it happen regardless. Log the sanitized + // request and begin clean shutdown, panicing + // if shutdown takes too long. + log.Criticalf("Unexpected error marshaling "+ + "response for request '%s': %v", + raw, err) + wsc.wg.Done() + + s.Stop() + go func() { + time.Sleep(30 * time.Second) + panic("shutdown took too long") + }() + + return } _ = wsc.send(mresp)