Browse Source

crash reporter: hardcode gui text. do not trust the server with it

paranoia.
master
SomberNight 3 years ago
parent
commit
ff2da7ceb9
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 30
      electrum/base_crash_reporter.py
  2. 14
      electrum/gui/kivy/uix/dialogs/crash_reporter.py
  3. 6
      electrum/gui/qml/qeapp.py
  4. 11
      electrum/gui/qt/exception_window.py

30
electrum/base_crash_reporter.py

@ -25,6 +25,7 @@ import locale
import traceback
import sys
import queue
from typing import NamedTuple, Optional
from .version import ELECTRUM_VERSION
from . import constants
@ -33,6 +34,12 @@ from .util import make_aiohttp_session
from .logging import describe_os_version, Logger, get_git_version
class CrashReportResponse(NamedTuple):
status: Optional[str]
text: str
url: Optional[str]
class BaseCrashReporter(Logger):
report_server = "https://crashhub.electrum.org"
config_key = "show_crash_reporter"
@ -63,16 +70,33 @@ class BaseCrashReporter(Logger):
Logger.__init__(self)
self.exc_args = (exctype, value, tb)
def send_report(self, asyncio_loop, proxy, endpoint="/crash", *, timeout=None):
def send_report(self, asyncio_loop, proxy, *, timeout=None) -> CrashReportResponse:
# FIXME the caller needs to catch generic "Exception", as this method does not have a well-defined API...
if constants.net.GENESIS[-4:] not in ["4943", "e26f"] and ".electrum.org" in BaseCrashReporter.report_server:
# Gah! Some kind of altcoin wants to send us crash reports.
raise Exception(_("Missing report URL."))
report = self.get_traceback_info()
report.update(self.get_additional_info())
report = json.dumps(report)
coro = self.do_post(proxy, BaseCrashReporter.report_server + endpoint, data=report)
coro = self.do_post(proxy, BaseCrashReporter.report_server + "/crash.json", data=report)
response = asyncio.run_coroutine_threadsafe(coro, asyncio_loop).result(timeout)
return response
self.logger.info(f"Crash report sent. Got response [DO NOT TRUST THIS MESSAGE]: {response!r}")
response = json.loads(response)
assert isinstance(response, dict), type(response)
# sanitize URL
if location := response.get("location"):
assert isinstance(location, str)
base_issues_url = constants.GIT_REPO_ISSUES_URL
if not base_issues_url.endswith("/"):
base_issues_url = base_issues_url + "/"
if not location.startswith(base_issues_url):
location = None
ret = CrashReportResponse(
status=response.get("status"),
url=location,
text=_("Thanks for reporting this issue!"),
)
return ret
async def do_post(self, proxy, url, data):
async with make_aiohttp_session(proxy) as session:

14
electrum/gui/kivy/uix/dialogs/crash_reporter.py

@ -121,16 +121,16 @@ class CrashReporter(BaseCrashReporter, Factory.Popup):
loop = self.main_window.network.asyncio_loop
proxy = self.main_window.network.proxy
# FIXME network request in GUI thread...
response = json.loads(BaseCrashReporter.send_report(self, loop, proxy,
"/crash.json", timeout=10))
except (ValueError, ClientError) as e:
response = BaseCrashReporter.send_report(self, loop, proxy, timeout=10)
except Exception as e:
self.logger.warning(f"Error sending crash report. exc={e!r}")
self.show_popup(_('Unable to send report'), _("Please check your network connection."))
else:
self.show_popup(_('Report sent'), response["text"])
location = response["location"]
if location:
self.logger.info(f"Crash report sent. location={location!r}")
text = response.text
if response.url:
text += f" You can track further progress on GitHub."
self.show_popup(_('Report sent'), text)
if location := response.url:
self.open_url(location)
self.dismiss()

6
electrum/gui/qml/qeapp.py

@ -247,13 +247,17 @@ class QEAppController(BaseCrashReporter, QObject):
def report_task():
try:
response = BaseCrashReporter.send_report(self, network.asyncio_loop, proxy)
self.sendingBugreportSuccess.emit(response)
except Exception as e:
self.logger.error('There was a problem with the automatic reporting', exc_info=e)
self.sendingBugreportFailure.emit(_('There was a problem with the automatic reporting:') + '<br/>' +
repr(e)[:120] + '<br/><br/>' +
_("Please report this issue manually") +
f' <a href="{constants.GIT_REPO_ISSUES_URL}">on GitHub</a>.')
else:
text = response.text
if response.url:
text += f" You can track further progress on <a href='{response.url}'>GitHub</a>."
self.sendingBugreportSuccess.emit(text)
self.sendingBugreport.emit()
threading.Thread(target=report_task).start()

11
electrum/gui/qt/exception_window.py

@ -31,7 +31,7 @@ from PyQt5.QtWidgets import (QWidget, QLabel, QPushButton, QTextEdit,
QMessageBox, QHBoxLayout, QVBoxLayout)
from electrum.i18n import _
from electrum.base_crash_reporter import BaseCrashReporter, EarlyExceptionsQueue
from electrum.base_crash_reporter import BaseCrashReporter, EarlyExceptionsQueue, CrashReportResponse
from electrum.logging import Logger
from electrum import constants
from electrum.network import Network
@ -103,12 +103,13 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
self.show()
def send_report(self):
def on_success(response):
# note: 'response' coming from (remote) crash reporter server.
# It contains a URL to the GitHub issue, so we allow rich text.
def on_success(response: CrashReportResponse):
text = response.text
if response.url:
text += f" You can track further progress on <a href='{response.url}'>GitHub</a>."
self.show_message(parent=self,
title=_("Crash report"),
msg=response,
msg=text,
rich_text=True)
self.close()
def on_failure(exc_info):

Loading…
Cancel
Save