mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-28 18:02:38 +02:00
Work on changing the WaitingWidget to check for Docker
This commit is contained in:
parent
d1c33bfcf5
commit
42ce884419
8 changed files with 83 additions and 158 deletions
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -1,6 +0,0 @@
|
||||||
[submodule "vendor/hyperkit"]
|
|
||||||
path = vendor/hyperkit
|
|
||||||
url = https://github.com/moby/hyperkit.git
|
|
||||||
[submodule "vendor/vpnkit"]
|
|
||||||
path = vendor/vpnkit
|
|
||||||
url = https://github.com/moby/vpnkit.git
|
|
|
@ -35,8 +35,8 @@ class GlobalCommon(object):
|
||||||
# App data folder
|
# App data folder
|
||||||
self.appdata_path = appdirs.user_config_dir("dangerzone")
|
self.appdata_path = appdirs.user_config_dir("dangerzone")
|
||||||
|
|
||||||
# In case we have a custom container
|
# Container name
|
||||||
self.custom_container = None
|
self.container_name = "dangerzone.rocks/dangerzone"
|
||||||
|
|
||||||
# Languages supported by tesseract
|
# Languages supported by tesseract
|
||||||
self.ocr_languages = {
|
self.ocr_languages = {
|
||||||
|
@ -380,12 +380,6 @@ class GlobalCommon(object):
|
||||||
)
|
)
|
||||||
print(Back.BLACK + Fore.YELLOW + Style.DIM + "╰──────────────────────────╯")
|
print(Back.BLACK + Fore.YELLOW + Style.DIM + "╰──────────────────────────╯")
|
||||||
|
|
||||||
def get_container_name(self):
|
|
||||||
if self.custom_container:
|
|
||||||
return self.custom_container
|
|
||||||
else:
|
|
||||||
return "docker.io/flmcode/dangerzone"
|
|
||||||
|
|
||||||
def get_resource_path(self, filename):
|
def get_resource_path(self, filename):
|
||||||
if getattr(sys, "dangerzone_dev", False):
|
if getattr(sys, "dangerzone_dev", False):
|
||||||
# Look for resources directory relative to python file
|
# Look for resources directory relative to python file
|
||||||
|
@ -414,17 +408,17 @@ class GlobalCommon(object):
|
||||||
def exec_dangerzone_container(self, input_filename, output_filename, ocr_lang):
|
def exec_dangerzone_container(self, input_filename, output_filename, ocr_lang):
|
||||||
convert(self, input_filename, output_filename, ocr_lang)
|
convert(self, input_filename, output_filename, ocr_lang)
|
||||||
|
|
||||||
args = [self.dz_container_path] + args
|
# args = [self.dz_container_path] + args
|
||||||
args_str = " ".join(pipes.quote(s) for s in args)
|
# args_str = " ".join(pipes.quote(s) for s in args)
|
||||||
print(Style.DIM + "> " + Style.NORMAL + Fore.CYAN + args_str)
|
# print(Style.DIM + "> " + Style.NORMAL + Fore.CYAN + args_str)
|
||||||
|
|
||||||
# Execute dangerzone-container
|
# # Execute dangerzone-container
|
||||||
return subprocess.Popen(
|
# return subprocess.Popen(
|
||||||
args,
|
# args,
|
||||||
startupinfo=self.get_subprocess_startupinfo(),
|
# startupinfo=self.get_subprocess_startupinfo(),
|
||||||
stdout=subprocess.PIPE,
|
# stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
# stderr=subprocess.PIPE,
|
||||||
)
|
# )
|
||||||
|
|
||||||
def get_subprocess_startupinfo(self):
|
def get_subprocess_startupinfo(self):
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
|
|
|
@ -9,12 +9,6 @@ from PySide2 import QtCore, QtWidgets
|
||||||
from .common import GuiCommon
|
from .common import GuiCommon
|
||||||
from .main_window import MainWindow
|
from .main_window import MainWindow
|
||||||
from .systray import SysTray
|
from .systray import SysTray
|
||||||
from .docker_installer import (
|
|
||||||
is_docker_installed,
|
|
||||||
is_docker_ready,
|
|
||||||
DockerInstaller,
|
|
||||||
AuthorizationFailed,
|
|
||||||
)
|
|
||||||
from ..global_common import GlobalCommon
|
from ..global_common import GlobalCommon
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,15 +80,6 @@ def gui_main(filename):
|
||||||
# Allow Ctrl-C to smoothly quit the program instead of throwing an exception
|
# Allow Ctrl-C to smoothly quit the program instead of throwing an exception
|
||||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
|
||||||
# See if we need to install Docker (Windows-only)
|
|
||||||
if (platform.system() == "Windows" or platform.system() == "Darwin") and (
|
|
||||||
not is_docker_installed() or not is_docker_ready(global_common)
|
|
||||||
):
|
|
||||||
click.echo("Docker is either not installed or not running")
|
|
||||||
docker_installer = DockerInstaller(gui_common)
|
|
||||||
docker_installer.start()
|
|
||||||
return
|
|
||||||
|
|
||||||
# Create the system tray
|
# Create the system tray
|
||||||
systray = SysTray(global_common, gui_common, app, app_wrapper)
|
systray = SysTray(global_common, gui_common, app, app_wrapper)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ elif platform.system() == "Linux":
|
||||||
import getpass
|
import getpass
|
||||||
from xdg.DesktopEntry import DesktopEntry
|
from xdg.DesktopEntry import DesktopEntry
|
||||||
|
|
||||||
from .docker_installer import is_docker_ready
|
|
||||||
from ..settings import Settings
|
from ..settings import Settings
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ class GuiCommon(object):
|
||||||
# Preload list of PDF viewers on computer
|
# Preload list of PDF viewers on computer
|
||||||
self.pdf_viewers = self._find_pdf_viewers()
|
self.pdf_viewers = self._find_pdf_viewers()
|
||||||
|
|
||||||
# Are we done waiting (for VM to start, or container to install)
|
# Are we done waiting (for Docker Desktop to be installed, or for container to install)
|
||||||
self.is_waiting_finished = False
|
self.is_waiting_finished = False
|
||||||
|
|
||||||
def get_window_icon(self):
|
def get_window_icon(self):
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import shutil
|
|
||||||
import platform
|
|
||||||
from PySide2 import QtCore, QtWidgets
|
|
||||||
|
|
||||||
|
|
||||||
class AuthorizationFailed(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
container_runtime = shutil.which("docker")
|
|
||||||
|
|
||||||
|
|
||||||
def is_docker_installed():
|
|
||||||
return container_runtime is not None
|
|
||||||
|
|
||||||
|
|
||||||
def is_docker_ready(global_common):
|
|
||||||
# Run `docker image ls` without an error
|
|
||||||
with subprocess.Popen([container_runtime, "image", "ls"]) as p:
|
|
||||||
outs, errs = 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:
|
|
||||||
print(outs)
|
|
||||||
print(errs)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def launch_docker_windows(global_common):
|
|
||||||
docker_desktop_path = "C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe"
|
|
||||||
subprocess.Popen(
|
|
||||||
[docker_desktop_path], startupinfo=global_common.get_subprocess_startupinfo()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class DockerInstaller(QtWidgets.QDialog):
|
|
||||||
def __init__(self, gui_common):
|
|
||||||
super(DockerInstaller, self).__init__()
|
|
||||||
|
|
||||||
self.setWindowTitle("Dangerzone")
|
|
||||||
self.setWindowIcon(gui_common.get_window_icon())
|
|
||||||
# self.setMinimumHeight(170)
|
|
||||||
|
|
||||||
label = QtWidgets.QLabel()
|
|
||||||
if platform.system() == "Darwin":
|
|
||||||
label.setText("Dangerzone for macOS requires Docker")
|
|
||||||
elif platform.system() == "Windows":
|
|
||||||
label.setText("Dangerzone for Windows requires Docker")
|
|
||||||
label.setStyleSheet("QLabel { font-weight: bold; }")
|
|
||||||
label.setAlignment(QtCore.Qt.AlignCenter)
|
|
||||||
|
|
||||||
self.task_label = QtWidgets.QLabel()
|
|
||||||
self.task_label.setAlignment(QtCore.Qt.AlignCenter)
|
|
||||||
self.task_label.setWordWrap(True)
|
|
||||||
self.task_label.setOpenExternalLinks(True)
|
|
||||||
|
|
||||||
self.ok_button = QtWidgets.QPushButton("OK")
|
|
||||||
self.ok_button.clicked.connect(self.ok_clicked)
|
|
||||||
|
|
||||||
buttons_layout = QtWidgets.QHBoxLayout()
|
|
||||||
buttons_layout.addStretch()
|
|
||||||
buttons_layout.addWidget(self.ok_button)
|
|
||||||
buttons_layout.addStretch()
|
|
||||||
|
|
||||||
layout = QtWidgets.QVBoxLayout()
|
|
||||||
layout.addWidget(label)
|
|
||||||
layout.addWidget(self.task_label)
|
|
||||||
layout.addLayout(buttons_layout)
|
|
||||||
layout.addStretch()
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
if platform.system() == "Darwin":
|
|
||||||
self.docker_path = "/Applications/Docker.app/Contents/Resources/bin/docker"
|
|
||||||
elif platform.system() == "Windows":
|
|
||||||
self.docker_path = shutil.which("docker.exe")
|
|
||||||
|
|
||||||
def ok_clicked(self):
|
|
||||||
self.accept()
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
if not os.path.exists(self.docker_path):
|
|
||||||
self.task_label.setText(
|
|
||||||
"<a href='https://www.docker.com/products/docker-desktop'>Download Docker Desktop</a>, install it, and then run Dangerzone again."
|
|
||||||
)
|
|
||||||
self.task_label.setTextFormat(QtCore.Qt.RichText)
|
|
||||||
else:
|
|
||||||
self.task_label.setText(
|
|
||||||
"Docker Desktop is installed, but you must launch it first. Open Docker, make sure it's running, and then open Dangerzone again."
|
|
||||||
)
|
|
||||||
|
|
||||||
return self.exec_() == QtWidgets.QDialog.Accepted
|
|
|
@ -3,6 +3,7 @@ import platform
|
||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
|
import shutil
|
||||||
from PySide2 import QtCore, QtGui, QtWidgets
|
from PySide2 import QtCore, QtGui, QtWidgets
|
||||||
from colorama import Style, Fore
|
from colorama import Style, Fore
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
header_layout.addWidget(header_label)
|
header_layout.addWidget(header_label)
|
||||||
header_layout.addStretch()
|
header_layout.addStretch()
|
||||||
|
|
||||||
# Waiting widget, replaces content widget while VM is booting
|
# Waiting widget, replaces content widget while container runtime isn't available
|
||||||
self.waiting_widget = WaitingWidget(self.global_common, self.gui_common)
|
self.waiting_widget = WaitingWidget(self.global_common, self.gui_common)
|
||||||
self.waiting_widget.finished.connect(self.waiting_finished)
|
self.waiting_widget.finished.connect(self.waiting_finished)
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
)
|
)
|
||||||
self.content_widget.close_window.connect(self.close)
|
self.content_widget.close_window.connect(self.close)
|
||||||
|
|
||||||
# Only use the waiting widget if we have a VM
|
# Only use the waiting widget if container runtime isn't available
|
||||||
if self.gui_common.is_waiting_finished:
|
if self.gui_common.is_waiting_finished:
|
||||||
self.waiting_widget.hide()
|
self.waiting_widget.hide()
|
||||||
self.content_widget.show()
|
self.content_widget.show()
|
||||||
|
@ -101,6 +102,15 @@ class InstallContainerThread(QtCore.QThread):
|
||||||
|
|
||||||
|
|
||||||
class WaitingWidget(QtWidgets.QWidget):
|
class WaitingWidget(QtWidgets.QWidget):
|
||||||
|
# These are the possible states that the WaitingWidget can show.
|
||||||
|
#
|
||||||
|
# Windows and macOS states:
|
||||||
|
# - "not_installed"
|
||||||
|
# - "not_running"
|
||||||
|
# - "install_container"
|
||||||
|
#
|
||||||
|
# Linux states
|
||||||
|
# - "install_container"
|
||||||
finished = QtCore.Signal()
|
finished = QtCore.Signal()
|
||||||
|
|
||||||
def __init__(self, global_common, gui_common):
|
def __init__(self, global_common, gui_common):
|
||||||
|
@ -110,34 +120,78 @@ class WaitingWidget(QtWidgets.QWidget):
|
||||||
|
|
||||||
self.label = QtWidgets.QLabel()
|
self.label = QtWidgets.QLabel()
|
||||||
self.label.setAlignment(QtCore.Qt.AlignCenter)
|
self.label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.label.setTextFormat(QtCore.Qt.RichText)
|
||||||
self.label.setStyleSheet("QLabel { font-size: 20px; }")
|
self.label.setStyleSheet("QLabel { font-size: 20px; }")
|
||||||
|
|
||||||
|
# Buttons
|
||||||
|
check_button = QtWidgets.QPushButton("Check Again")
|
||||||
|
check_button.clicked.connect(self.check_state)
|
||||||
|
buttons_layout = QtWidgets.QHBoxLayout()
|
||||||
|
buttons_layout.addStretch()
|
||||||
|
buttons_layout.addWidget(check_button)
|
||||||
|
buttons_layout.addStretch()
|
||||||
|
self.buttons = QtWidgets.QWidget()
|
||||||
|
self.buttons.setLayout(buttons_layout)
|
||||||
|
|
||||||
# Layout
|
# Layout
|
||||||
layout = QtWidgets.QVBoxLayout()
|
layout = QtWidgets.QVBoxLayout()
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
layout.addWidget(self.label)
|
layout.addWidget(self.label)
|
||||||
|
layout.addWidget(self.buttons)
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
if platform.system() == "Darwin":
|
# Check the state
|
||||||
self.label.setText("Waiting for the Dangerzone virtual machine to start...")
|
self.check_state()
|
||||||
self.global_common.vm.vm_state_change.connect(self.vm_state_change)
|
|
||||||
|
|
||||||
elif platform.system() == "Linux":
|
def check_state(self):
|
||||||
self.label.setText("Installing the Dangerzone container...")
|
state = None
|
||||||
|
|
||||||
|
# Can we find the container runtime binary binary
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
container_runtime = shutil.which("podman")
|
||||||
|
else:
|
||||||
|
container_runtime = shutil.which("docker")
|
||||||
|
|
||||||
|
if container_runtime is None:
|
||||||
|
print("Docker is not installed")
|
||||||
|
state = "not_installed"
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Can we run `docker image ls` without an error
|
||||||
|
with subprocess.Popen([container_runtime, "image", "ls"]) as p:
|
||||||
|
p.communicate()
|
||||||
|
if p.returncode != 0:
|
||||||
|
print("Docker is not running")
|
||||||
|
state = "not_running"
|
||||||
|
else:
|
||||||
|
# Always try installing the container
|
||||||
|
print("Ensuring the container is installed")
|
||||||
|
state = "install_container"
|
||||||
|
|
||||||
|
# Update the state
|
||||||
|
self.state_change(state)
|
||||||
|
|
||||||
|
def state_change(self, state):
|
||||||
|
if state == "not_installed":
|
||||||
|
self.label.setText(
|
||||||
|
"<strong>Dangerzone requires Docker</strong><br><br><a href='https://www.docker.com/products/docker-desktop'>Download Docker Desktop</a> and install it."
|
||||||
|
)
|
||||||
|
self.buttons.show()
|
||||||
|
elif state == "not_running":
|
||||||
|
self.label.setText(
|
||||||
|
"Docker Desktop is installed, but you must launch it first. Open Docker and make sure it's running in the background."
|
||||||
|
)
|
||||||
|
self.buttons.show()
|
||||||
|
else:
|
||||||
|
self.label.setText(
|
||||||
|
"Installing the Dangerzone container..."
|
||||||
|
)
|
||||||
|
self.buttons.hide()
|
||||||
self.install_container_t = InstallContainerThread(self.global_common)
|
self.install_container_t = InstallContainerThread(self.global_common)
|
||||||
self.install_container_t.finished.connect(self.finished)
|
self.install_container_t.finished.connect(self.finished)
|
||||||
self.install_container_t.start()
|
self.install_container_t.start()
|
||||||
|
|
||||||
else:
|
|
||||||
self.label.setText("Platform not implemented yet")
|
|
||||||
|
|
||||||
def vm_state_change(self, state):
|
|
||||||
if state == self.global_common.vm.STATE_ON:
|
|
||||||
self.finished.emit()
|
|
||||||
elif state == self.global_common.vm.STATE_FAIL:
|
|
||||||
self.label.setText("Dangerzone virtual machine failed to start :(")
|
|
||||||
|
|
||||||
|
|
||||||
class ContentWidget(QtWidgets.QWidget):
|
class ContentWidget(QtWidgets.QWidget):
|
||||||
close_window = QtCore.Signal()
|
close_window = QtCore.Signal()
|
||||||
|
|
1
vendor/hyperkit
vendored
1
vendor/hyperkit
vendored
|
@ -1 +0,0 @@
|
||||||
Subproject commit 09fe9202a29a56a532d07505fd91831989b9afeb
|
|
1
vendor/vpnkit
vendored
1
vendor/vpnkit
vendored
|
@ -1 +0,0 @@
|
||||||
Subproject commit 16ed722e6dc24307e99aee931ffd0eb80a9487d0
|
|
Loading…
Reference in a new issue