diff --git a/dangerzone/gui/main_window.py b/dangerzone/gui/main_window.py
index 27ca0bc..6d9fb1d 100644
--- a/dangerzone/gui/main_window.py
+++ b/dangerzone/gui/main_window.py
@@ -3,6 +3,7 @@ import os
import platform
import subprocess
import tempfile
+import traceback
import typing
from multiprocessing.pool import ThreadPool
from typing import List, Optional
@@ -388,15 +389,25 @@ class MainWindow(QtWidgets.QMainWindow):
class InstallContainerThread(QtCore.QThread):
- finished = QtCore.Signal()
+ finished = QtCore.Signal(str)
def __init__(self, dangerzone: DangerzoneGui) -> None:
super(InstallContainerThread, self).__init__()
self.dangerzone = dangerzone
def run(self) -> None:
- self.dangerzone.isolation_provider.install()
- self.finished.emit()
+ error = None
+ try:
+ installed = self.dangerzone.isolation_provider.install()
+ except Exception as e:
+ log.error("Installation problemo")
+ error = "".join(traceback.format_exception(e))
+ self.finished.emit(error)
+ else:
+ if not installed:
+ # FIXME: Improve this.
+ self.finished.emit("Failed to install the container image")
+ self.finished.emit(None)
class WaitingWidget(QtWidgets.QWidget):
@@ -416,7 +427,6 @@ class WaitingWidgetContainer(WaitingWidget):
#
# Linux states
# - "install_container"
- finished = QtCore.Signal()
def __init__(self, dangerzone: DangerzoneGui) -> None:
super(WaitingWidgetContainer, self).__init__()
@@ -441,17 +451,7 @@ class WaitingWidgetContainer(WaitingWidget):
# Error
self.error_text = QTextEdit()
self.error_text.setReadOnly(True)
- self.error_text.setStyleSheet(
- """
- QTextEdit {
- font-family: Consolas, Monospace;
- font-size: 12px;
- background-color: #fff;
- color: #000;
- padding: 10px;
- }
- """
- )
+ self.error_text.setProperty("style", "container_error")
self.error_text.setVisible(False)
# Enable copying
self.error_text.setTextInteractionFlags(Qt.TextSelectableByMouse)
@@ -503,56 +503,66 @@ class WaitingWidgetContainer(WaitingWidget):
# Update the state
self.state_change(state, error)
+ def show_error(self, msg: str, details: str | None = None) -> None:
+ self.label.setText(msg)
+ if details is not None:
+ self.error_text.setPlainText(details)
+ self.error_text.setVisible(True)
+ else:
+ self.error_text.setVisible(False)
+ self.buttons.show()
+
+ def show_message(self, msg: str) -> None:
+ self.label.setText(msg)
+ self.error_text.setVisible(False)
+ self.buttons.hide()
+
+ def installation_finished(self, error: str | None = None) -> None:
+ if error:
+ msg = (
+ "Installing the Dangerzone container image.
"
+ "An unexpected error occurred:"
+ )
+ self.show_error(msg, error)
+ else:
+ self.finished.emit()
+
def state_change(self, state: str, error: str | None = None) -> None:
if state == "not_installed":
if platform.system() == "Linux":
- self.label.setText(
- (
- "Dangerzone requires Podman
"
- "Install it and retry."
- )
+ self.show_error(
+ "Dangerzone requires Podman
"
+ "Install it and retry."
)
else:
- self.label.setText(
- (
- "Dangerzone requires Docker Desktop
"
- "Download Docker Desktop"
- ", install it, and open it."
- )
+ self.show_error(
+ "Dangerzone requires Docker Desktop
"
+ "Download Docker Desktop"
+ ", install it, and open it."
)
- self.buttons.show()
elif state == "not_running":
if platform.system() == "Linux":
# "not_running" here means that the `podman image ls` command failed.
- message = (
+ self.show_error(
"Dangerzone requires Podman
"
- "Podman is installed but cannot run properly. See errors below"
+ "Podman is installed but cannot run properly.
"
+ "See errors below:",
+ error,
)
- if error:
- self.error_text.setPlainText(error)
- self.error_text.setVisible(True)
-
- self.label.setText(message)
-
else:
- self.label.setText(
- (
- "Dangerzone requires Docker Desktop
"
- "Docker is installed but isn't running.
"
- "Open Docker and make sure it's running in the background."
- )
+ self.show_error(
+ "Dangerzone requires Docker Desktop
"
+ "Docker is installed but isn't running.
"
+ "Open Docker and make sure it's running in the background."
)
- self.buttons.show()
else:
- self.label.setText(
- (
- "Installing the Dangerzone container image.
"
- "This might take a few minutes..."
- )
+ self.show_message(
+ "Installing the Dangerzone container image.
"
+ "This might take a few minutes...",
)
- self.buttons.hide()
+
self.install_container_t = InstallContainerThread(self.dangerzone)
- self.install_container_t.finished.connect(self.finished)
+ self.install_container_t.finished.connect(self.installation_finished)
self.install_container_t.start()
diff --git a/dangerzone/isolation_provider/container.py b/dangerzone/isolation_provider/container.py
index 7137d57..0589fc3 100644
--- a/dangerzone/isolation_provider/container.py
+++ b/dangerzone/isolation_provider/container.py
@@ -168,7 +168,7 @@ class Container(IsolationProvider):
startupinfo=get_subprocess_startupinfo(),
)
- chunk_size = 10240
+ chunk_size = 4 << 20
compressed_container_path = get_resource_path("container.tar.gz")
with gzip.open(compressed_container_path) as f:
while True:
@@ -178,7 +178,11 @@ class Container(IsolationProvider):
p.stdin.write(chunk)
else:
break
- p.communicate()
+ _, err = p.communicate()
+ if p.returncode < 0:
+ raise RuntimeError(f"Could not install container image: {err}")
+
+ log.info("Container image installation finished successfully")
if not Container.is_container_installed():
log.error("Failed to install the container image")
@@ -192,7 +196,6 @@ class Container(IsolationProvider):
"""
See if the podman container is installed. Linux only.
"""
- # Get the image id
with open(get_resource_path("image-id.txt")) as f:
expected_image_id = f.read().strip()
diff --git a/share/dangerzone.css b/share/dangerzone.css
index 45fdc2b..23f3bab 100644
--- a/share/dangerzone.css
+++ b/share/dangerzone.css
@@ -48,3 +48,11 @@ QLabel.version {
font-size: 20px;
padding-bottom: 5px; /* align with 'dangerzone' font */
}
+
+QTextEdit[style="container_error"] {
+ font-family: Consolas, Monospace;
+ font-size: 12px;
+ background-color: #ffffff;
+ color: #000000;
+ padding: 10px;
+}