mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-28 18:02:38 +02:00
All dangerzone-container subprocesses get called from global_commons, and if the user cancels or fails the authentication dialog, handle gracefully
This commit is contained in:
parent
171fda8017
commit
3a1b6d457f
6 changed files with 87 additions and 49 deletions
|
@ -11,6 +11,10 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||
from .container import container_runtime
|
||||
|
||||
|
||||
class AuthorizationFailed(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def is_docker_installed(global_common):
|
||||
if platform.system() == "Darwin":
|
||||
# Does the docker binary exist?
|
||||
|
@ -29,15 +33,18 @@ def is_docker_installed(global_common):
|
|||
|
||||
def is_docker_ready(global_common):
|
||||
# Run `docker image ls` without an error
|
||||
try:
|
||||
print(global_common.get_dangerzone_container_args())
|
||||
subprocess.run(
|
||||
global_common.get_dangerzone_container_args() + ["image-ls"],
|
||||
startupinfo=global_common.get_subprocess_startupinfo(),
|
||||
)
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
with global_common.exec_dangerzone_container(["image-ls"]) as p:
|
||||
p.communicate()
|
||||
|
||||
# The user canceled, or permission denied
|
||||
if p.returncode == 126 or p.returncode == 127:
|
||||
raise AuthorizationFailed
|
||||
|
||||
# Return true if it succeeds
|
||||
if p.returncode == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def launch_docker_windows(global_common):
|
||||
|
|
|
@ -6,6 +6,7 @@ import appdirs
|
|||
import platform
|
||||
import subprocess
|
||||
import shlex
|
||||
import pipes
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
if platform.system() == "Darwin":
|
||||
|
@ -284,14 +285,25 @@ class GlobalCommon(object):
|
|||
else:
|
||||
return "/usr/bin/dangerzone-container"
|
||||
|
||||
def get_dangerzone_container_args(self):
|
||||
def exec_dangerzone_container(self, args):
|
||||
# Prefix the args with the retainer runtime, and in the case linux when the user isn't in the docker group, pkexec
|
||||
if platform.system() == "Linux":
|
||||
if self.settings.get("linux_prefers_typing_password"):
|
||||
return ["/usr/bin/pkexec", self.dz_container_path]
|
||||
args = ["/usr/bin/pkexec", self.dz_container_path] + args
|
||||
else:
|
||||
return [self.dz_container_path]
|
||||
args = [self.dz_container_path] + args
|
||||
else:
|
||||
return [self.dz_container_path]
|
||||
args = [self.dz_container_path] + args
|
||||
|
||||
# Execute dangerzone-container
|
||||
args_str = " ".join(pipes.quote(s) for s in args)
|
||||
print(f"Executing: {args_str}")
|
||||
return subprocess.Popen(
|
||||
args,
|
||||
startupinfo=self.get_subprocess_startupinfo(),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
|
||||
def get_window_icon(self):
|
||||
if platform.system() == "Windows":
|
||||
|
|
|
@ -15,6 +15,7 @@ from .docker_installer import (
|
|||
is_docker_ready,
|
||||
launch_docker_windows,
|
||||
DockerInstaller,
|
||||
AuthorizationFailed,
|
||||
)
|
||||
from .container import container_runtime
|
||||
|
||||
|
@ -51,14 +52,23 @@ def gui_main(custom_container, filename):
|
|||
|
||||
if custom_container:
|
||||
# Do we have this container?
|
||||
output = subprocess.check_output(
|
||||
global_common.get_dangerzone_container_args()
|
||||
+ ["image-ls", custom_container],
|
||||
startupinfo=global_common.get_subprocess_startupinfo(),
|
||||
)
|
||||
if custom_container.encode() not in output:
|
||||
click.echo(f"Container '{container}' not found")
|
||||
return
|
||||
with global_common.exec_dangerzone_container(
|
||||
["image-ls", "--container-name", custom_container]
|
||||
) as p:
|
||||
stdout_data, stderr_data = p.communicate()
|
||||
|
||||
# The user canceled, or permission denied
|
||||
if p.returncode == 126 or p.returncode == 127:
|
||||
click.echo("Authorization failed")
|
||||
return
|
||||
elif p.returncode != 0:
|
||||
click.echo("Container error")
|
||||
return
|
||||
|
||||
# Check the output
|
||||
if custom_container.encode() not in stdout_data:
|
||||
click.echo(f"Container '{container}' not found")
|
||||
return
|
||||
|
||||
global_common.custom_container = custom_container
|
||||
|
||||
|
@ -69,8 +79,12 @@ def gui_main(custom_container, filename):
|
|||
if platform.system() == "Linux" and container_runtime == "/usr/bin/docker":
|
||||
if not global_common.ensure_docker_group_preference():
|
||||
return
|
||||
if not global_common.ensure_docker_service_is_started():
|
||||
click.echo("Failed to start docker service")
|
||||
try:
|
||||
if not global_common.ensure_docker_service_is_started():
|
||||
click.echo("Failed to start docker service")
|
||||
return
|
||||
except AuthorizationFailed:
|
||||
click.echo("Authorization failed")
|
||||
return
|
||||
|
||||
# See if we need to install Docker...
|
||||
|
|
|
@ -52,7 +52,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||
self.settings_widget.document_selected
|
||||
)
|
||||
self.settings_widget.start_clicked.connect(self.start_clicked)
|
||||
self.settings_widget.close_window.connect(self.close)
|
||||
self.settings_widget.hide()
|
||||
QtCore.QTimer.singleShot(
|
||||
1, self.settings_widget.check_update_container_default_state
|
||||
)
|
||||
|
||||
# Tasks
|
||||
self.tasks_widget = TasksWidget(self.global_common, self.common)
|
||||
|
|
|
@ -6,6 +6,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||
|
||||
class SettingsWidget(QtWidgets.QWidget):
|
||||
start_clicked = QtCore.pyqtSignal()
|
||||
close_window = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, global_common, common):
|
||||
super(SettingsWidget, self).__init__()
|
||||
|
@ -134,24 +135,31 @@ class SettingsWidget(QtWidgets.QWidget):
|
|||
else:
|
||||
self.update_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
def check_update_container_default_state(self):
|
||||
# Is update containers required?
|
||||
if self.global_common.custom_container:
|
||||
self.update_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
self.update_checkbox.setEnabled(False)
|
||||
self.update_checkbox.hide()
|
||||
else:
|
||||
output = subprocess.check_output(
|
||||
self.global_common.get_dangerzone_container_args()
|
||||
+ [
|
||||
with self.global_common.exec_dangerzone_container(
|
||||
[
|
||||
"image-ls",
|
||||
"--container-name",
|
||||
self.global_common.get_container_name(),
|
||||
],
|
||||
startupinfo=self.global_common.get_subprocess_startupinfo(),
|
||||
)
|
||||
if b"dangerzone" not in output:
|
||||
self.update_checkbox.setCheckState(QtCore.Qt.Checked)
|
||||
self.update_checkbox.setEnabled(False)
|
||||
]
|
||||
) as p:
|
||||
stdout_data, stderror_data = p.communicate()
|
||||
|
||||
# The user canceled, or permission denied
|
||||
if p.returncode == 126 or p.returncode == 127:
|
||||
self.close_window.emit()
|
||||
return
|
||||
|
||||
# Check the output
|
||||
if b"dangerzone" not in stdout_data:
|
||||
self.update_checkbox.setCheckState(QtCore.Qt.Checked)
|
||||
self.update_checkbox.setEnabled(False)
|
||||
|
||||
def update_ui(self):
|
||||
if platform.system() == "Windows":
|
||||
|
|
|
@ -16,29 +16,25 @@ class TaskBase(QtCore.QThread):
|
|||
super(TaskBase, self).__init__()
|
||||
|
||||
def exec_container(self, args):
|
||||
args = self.global_common.get_dangerzone_container_args() + args
|
||||
output = ""
|
||||
self.update_details.emit(output)
|
||||
|
||||
with subprocess.Popen(
|
||||
args,
|
||||
stdin=None,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
bufsize=1,
|
||||
universal_newlines=True,
|
||||
startupinfo=self.global_common.get_subprocess_startupinfo(),
|
||||
) as p:
|
||||
with self.global_common.exec_dangerzone_container(args) as p:
|
||||
for line in p.stdout:
|
||||
output += line
|
||||
print(line, end="")
|
||||
output += line.decode()
|
||||
print(line.decode(), end="")
|
||||
self.update_details.emit(output)
|
||||
|
||||
stderr = p.stderr.read()
|
||||
output += stderr
|
||||
print(stderr)
|
||||
output += stderr.decode()
|
||||
print(stderr.decode())
|
||||
self.update_details.emit(output)
|
||||
|
||||
if p.returncode == 126 or p.returncode == 127:
|
||||
self.task_failed.emit(f"Authorization failed")
|
||||
elif p.returncode == 0:
|
||||
self.task_failed.emit(f"Return code: {p.returncode}")
|
||||
|
||||
print("")
|
||||
return p.returncode, output
|
||||
|
||||
|
@ -58,7 +54,6 @@ class PullImageTask(TaskBase):
|
|||
returncode, _ = self.exec_container(args)
|
||||
|
||||
if returncode != 0:
|
||||
self.task_failed.emit(f"Return code: {returncode}")
|
||||
return
|
||||
|
||||
self.task_finished.emit()
|
||||
|
@ -88,7 +83,6 @@ class ConvertToPixels(TaskBase):
|
|||
returncode, output = self.exec_container(args)
|
||||
|
||||
if returncode != 0:
|
||||
self.task_failed.emit(f"Return code: {returncode}")
|
||||
return
|
||||
|
||||
# Did we hit an error?
|
||||
|
@ -194,7 +188,6 @@ class ConvertToPDF(TaskBase):
|
|||
returncode, output = self.exec_container(args)
|
||||
|
||||
if returncode != 0:
|
||||
self.task_failed.emit(f"Return code: {returncode}")
|
||||
return
|
||||
|
||||
self.task_finished.emit()
|
||||
|
|
Loading…
Reference in a new issue