crash reporter: hardcode gui text. do not trust the server with it
paranoia.
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user