diff --git a/dangerzone/container.py b/dangerzone/container.py index 98da8ac..5977ba2 100644 --- a/dangerzone/container.py +++ b/dangerzone/container.py @@ -4,12 +4,12 @@ import subprocess import sys import pipes import shutil -import os +import json # What is the container runtime for this platform? if platform.system() == "Darwin": - container_tech = "docker" - container_runtime = "/usr/local/bin/docker" + container_tech = "dangerzone-vm" + container_runtime = shutil.which("docker") elif platform.system() == "Windows": container_tech = "docker" container_runtime = shutil.which("docker.exe") @@ -29,24 +29,11 @@ else: startupinfo = None -def exec_container(args): - args = [container_runtime] + args - +def exec(args): args_str = " ".join(pipes.quote(s) for s in args) print("> " + args_str) sys.stdout.flush() - # In Tails, tell the container runtime to download over Tor - if ( - platform.system() == "Linux" - and os.getlogin() == "amnesia" - and os.getuid() == 1000 - ): - env = os.environ.copy() - env["HTTP_PROXY"] = "socks5://127.0.0.1:9050" - else: - env = None - with subprocess.Popen( args, stdin=None, @@ -55,12 +42,51 @@ def exec_container(args): bufsize=1, universal_newlines=True, startupinfo=startupinfo, - env=env, ) as p: p.communicate() return p.returncode +def exec_vm(args, vm_info): + if container_tech == "dangerzone-vm" and vm_info is None: + print("--vm-info-path required on this platform") + return + + args = [ + "/usr/bin/ssh", + "-q", + "-i", + vm_info["client_key_path"], + "-p", + vm_info["tunnel_port"], + "-o", + "StrictHostKeyChecking=no", + "user@127.0.0.1", + ] + args + return exec(args) + + +def exec_container(args, vm_info): + if container_tech == "dangerzone-vm" and vm_info is None: + print("--vm-info-path required on this platform") + return + + if container_tech == "dangerzone-vm": + args = ["podman"] + args + return exec_vm(args, vm_info) + + args = [container_runtime] + args + return exec(args) + + +def load_vm_info(vm_info_path): + if not vm_info_path: + return None + + with open(vm_info_path) as f: + return json.loads(f.read()) + + @click.group() def container_main(): """ @@ -71,23 +97,21 @@ def container_main(): @container_main.command() +@click.option("--vm-info-path", default=None) @click.option("--container-name", default="docker.io/flmcode/dangerzone") -def ls(container_name): +def ls(vm_info_path, container_name): """docker image ls [container_name]""" - sys.exit(exec_container(["image", "ls", container_name])) - - -@container_main.command() -def pull(): - """docker pull flmcode/dangerzone""" - sys.exit(exec_container(["pull", "docker.io/flmcode/dangerzone"])) + sys.exit( + exec_container(["image", "ls", container_name]), load_vm_info(vm_info_path) + ) @container_main.command() +@click.option("--vm-info-path", default=None) @click.option("--document-filename", required=True) @click.option("--pixel-dir", required=True) @click.option("--container-name", default="docker.io/flmcode/dangerzone") -def documenttopixels(document_filename, pixel_dir, container_name): +def documenttopixels(vm_info_path, document_filename, pixel_dir, container_name): """docker run --network none -v [document_filename]:/tmp/input_file -v [pixel_dir]:/dangerzone [container_name] document-to-pixels""" args = ["run", "--network", "none"] @@ -103,16 +127,17 @@ def documenttopixels(document_filename, pixel_dir, container_name): container_name, "document-to-pixels", ] - sys.exit(exec_container(args)) + sys.exit(exec_container(args, load_vm_info(vm_info_path))) @container_main.command() +@click.option("--vm-info-path", default=None) @click.option("--pixel-dir", required=True) @click.option("--safe-dir", required=True) @click.option("--container-name", default="docker.io/flmcode/dangerzone") @click.option("--ocr", required=True) @click.option("--ocr-lang", required=True) -def pixelstopdf(pixel_dir, safe_dir, container_name, ocr, ocr_lang): +def pixelstopdf(vm_info_path, pixel_dir, safe_dir, container_name, ocr, ocr_lang): """docker run --network none -v [pixel_dir]:/dangerzone -v [safe_dir]:/safezone [container_name] -e OCR=[ocr] -e OCR_LANGUAGE=[ocr_lang] pixels-to-pdf""" sys.exit( exec_container( @@ -130,6 +155,7 @@ def pixelstopdf(pixel_dir, safe_dir, container_name, ocr, ocr_lang): f"OCR_LANGUAGE={ocr_lang}", container_name, "pixels-to-pdf", - ] + ], + load_vm_info(vm_info_path), ) ) diff --git a/dangerzone/global_common.py b/dangerzone/global_common.py index 53f259f..f089753 100644 --- a/dangerzone/global_common.py +++ b/dangerzone/global_common.py @@ -443,6 +443,8 @@ class GlobalCommon(object): def exec_dangerzone_container(self, args): args = [self.dz_container_path] + args + if self.vm: + args += ["--vm-info-path", self.vm.vm_info_path] args_str = " ".join(pipes.quote(s) for s in args) print(Style.DIM + "> " + Style.NORMAL + Fore.CYAN + args_str) diff --git a/dangerzone/gui/main_window.py b/dangerzone/gui/main_window.py index b82ef50..4829e1c 100644 --- a/dangerzone/gui/main_window.py +++ b/dangerzone/gui/main_window.py @@ -1,9 +1,11 @@ -from dangerzone import global_common import shutil import os import platform +import tempfile +import subprocess from PySide2 import QtCore, QtGui, QtWidgets +from .tasks import ConvertToPixels, ConvertToPDF from ..common import Common diff --git a/dangerzone/gui/vm.py b/dangerzone/gui/vm.py index 8ef2f57..7cdcde2 100644 --- a/dangerzone/gui/vm.py +++ b/dangerzone/gui/vm.py @@ -60,6 +60,7 @@ class Vm(QtCore.QObject): ) self.sshd_pid_path = os.path.join(self.state_dir.name, "sshd.pid") self.sshd_log_path = os.path.join(self.state_dir.name, "sshd.log") + self.vm_info_path = os.path.join(self.state_dir.name, "info.json") self.vm_disk_img_path = os.path.join(self.state_dir.name, "disk.img") # UDID for VM @@ -145,8 +146,6 @@ class Vm(QtCore.QObject): "-o", "Compression=yes", "-o", - "ForceCommand=/usr/bin/whoami", - "-o", "UseDNS=no", "-o", f"AuthorizedKeysFile={self.ssh_client_pubkey_path}", @@ -157,7 +156,7 @@ class Vm(QtCore.QObject): # Create a JSON object to pass into the VM # This is a 512kb file that starts with a JSON object, followed by null bytes - vm_info = { + guest_vm_info = { "id_ed25519": ssh_client_key, "id_ed25519.pub": ssh_client_pubkey, "user": getpass.getuser(), @@ -166,9 +165,17 @@ class Vm(QtCore.QObject): "tunnel_port": self.sshd_tunnel_port, } with open(self.vm_disk_img_path, "wb") as f: - vm_info_bytes = json.dumps(vm_info).encode() - f.write(vm_info_bytes) - f.write(b"\x00" * (512 * 1024 - len(vm_info_bytes))) + guest_vm_info_bytes = json.dumps(guest_vm_info).encode() + f.write(guest_vm_info_bytes) + f.write(b"\x00" * (512 * 1024 - len(guest_vm_info_bytes))) + + # Create a JSON object for the container process to read + vm_info = { + "client_key_path": self.ssh_client_key_path, + "tunnel_port": self.sshd_tunnel_port, + } + with open(self.vm_info_path, "w") as f: + f.write(json.dumps(vm_info)) # Run VPNKit args = [ diff --git a/install/vm-builder/etc/ssh-to-host.py b/install/vm-builder/etc/ssh-to-host.py index 05fb829..920beb5 100755 --- a/install/vm-builder/etc/ssh-to-host.py +++ b/install/vm-builder/etc/ssh-to-host.py @@ -31,15 +31,25 @@ def main(): f.write(info["id_ed25519.pub"]) f.write("\n") + with open("/home/user/.ssh/config", "w") as f: + f.write("Host hostbox\n") + f.write(f" Hostname {info['ip']}\n") + f.write(f" Port {info['port']}\n") + f.write(f" User {info['user']}\n") + f.write(" IdentityFile /home/user/.ssh/id_ed25519\n") + f.write("\n") + os.chmod("/home/user/.ssh", 0o700) os.chmod("/home/user/.ssh/id_ed25519", 0o600) os.chmod("/home/user/.ssh/id_ed25519.pub", 0o644) os.chmod("/home/user/.ssh/authorized_keys", 0o600) + os.chmod("/home/user/.ssh/config", 0o600) shutil.chown("/home/user/.ssh", "user", "user") shutil.chown("/home/user/.ssh/id_ed25519", "user", "user") shutil.chown("/home/user/.ssh/id_ed25519.pub", "user", "user") shutil.chown("/home/user/.ssh/authorized_keys", "user", "user") + shutil.chown("/home/user/.ssh/config", "user", "user") # Start SSH reverse port forward subprocess.run( @@ -50,14 +60,10 @@ def main(): "/usr/bin/ssh", "-o", "StrictHostKeyChecking=no", - "-i", - "/home/user/.ssh/id_ed25519", "-N", "-R", f"{info['tunnel_port']}:127.0.0.1:22", - "-p", - str(info["port"]), - f"{info['user']}@{info['ip']}", + "hostbox", ] )