mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-28 18:02:38 +02:00
Start making it possible to execute podman inside the VM
This commit is contained in:
parent
c7bd8a317a
commit
2904d44aad
5 changed files with 85 additions and 42 deletions
|
@ -4,12 +4,12 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
import pipes
|
import pipes
|
||||||
import shutil
|
import shutil
|
||||||
import os
|
import json
|
||||||
|
|
||||||
# What is the container runtime for this platform?
|
# What is the container runtime for this platform?
|
||||||
if platform.system() == "Darwin":
|
if platform.system() == "Darwin":
|
||||||
container_tech = "docker"
|
container_tech = "dangerzone-vm"
|
||||||
container_runtime = "/usr/local/bin/docker"
|
container_runtime = shutil.which("docker")
|
||||||
elif platform.system() == "Windows":
|
elif platform.system() == "Windows":
|
||||||
container_tech = "docker"
|
container_tech = "docker"
|
||||||
container_runtime = shutil.which("docker.exe")
|
container_runtime = shutil.which("docker.exe")
|
||||||
|
@ -29,24 +29,11 @@ else:
|
||||||
startupinfo = None
|
startupinfo = None
|
||||||
|
|
||||||
|
|
||||||
def exec_container(args):
|
def exec(args):
|
||||||
args = [container_runtime] + args
|
|
||||||
|
|
||||||
args_str = " ".join(pipes.quote(s) for s in args)
|
args_str = " ".join(pipes.quote(s) for s in args)
|
||||||
print("> " + args_str)
|
print("> " + args_str)
|
||||||
sys.stdout.flush()
|
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(
|
with subprocess.Popen(
|
||||||
args,
|
args,
|
||||||
stdin=None,
|
stdin=None,
|
||||||
|
@ -55,12 +42,51 @@ def exec_container(args):
|
||||||
bufsize=1,
|
bufsize=1,
|
||||||
universal_newlines=True,
|
universal_newlines=True,
|
||||||
startupinfo=startupinfo,
|
startupinfo=startupinfo,
|
||||||
env=env,
|
|
||||||
) as p:
|
) as p:
|
||||||
p.communicate()
|
p.communicate()
|
||||||
return p.returncode
|
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()
|
@click.group()
|
||||||
def container_main():
|
def container_main():
|
||||||
"""
|
"""
|
||||||
|
@ -71,23 +97,21 @@ def container_main():
|
||||||
|
|
||||||
|
|
||||||
@container_main.command()
|
@container_main.command()
|
||||||
|
@click.option("--vm-info-path", default=None)
|
||||||
@click.option("--container-name", default="docker.io/flmcode/dangerzone")
|
@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]"""
|
"""docker image ls [container_name]"""
|
||||||
sys.exit(exec_container(["image", "ls", container_name]))
|
sys.exit(
|
||||||
|
exec_container(["image", "ls", container_name]), load_vm_info(vm_info_path)
|
||||||
|
)
|
||||||
@container_main.command()
|
|
||||||
def pull():
|
|
||||||
"""docker pull flmcode/dangerzone"""
|
|
||||||
sys.exit(exec_container(["pull", "docker.io/flmcode/dangerzone"]))
|
|
||||||
|
|
||||||
|
|
||||||
@container_main.command()
|
@container_main.command()
|
||||||
|
@click.option("--vm-info-path", default=None)
|
||||||
@click.option("--document-filename", required=True)
|
@click.option("--document-filename", required=True)
|
||||||
@click.option("--pixel-dir", required=True)
|
@click.option("--pixel-dir", required=True)
|
||||||
@click.option("--container-name", default="docker.io/flmcode/dangerzone")
|
@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"""
|
"""docker run --network none -v [document_filename]:/tmp/input_file -v [pixel_dir]:/dangerzone [container_name] document-to-pixels"""
|
||||||
args = ["run", "--network", "none"]
|
args = ["run", "--network", "none"]
|
||||||
|
|
||||||
|
@ -103,16 +127,17 @@ def documenttopixels(document_filename, pixel_dir, container_name):
|
||||||
container_name,
|
container_name,
|
||||||
"document-to-pixels",
|
"document-to-pixels",
|
||||||
]
|
]
|
||||||
sys.exit(exec_container(args))
|
sys.exit(exec_container(args, load_vm_info(vm_info_path)))
|
||||||
|
|
||||||
|
|
||||||
@container_main.command()
|
@container_main.command()
|
||||||
|
@click.option("--vm-info-path", default=None)
|
||||||
@click.option("--pixel-dir", required=True)
|
@click.option("--pixel-dir", required=True)
|
||||||
@click.option("--safe-dir", required=True)
|
@click.option("--safe-dir", required=True)
|
||||||
@click.option("--container-name", default="docker.io/flmcode/dangerzone")
|
@click.option("--container-name", default="docker.io/flmcode/dangerzone")
|
||||||
@click.option("--ocr", required=True)
|
@click.option("--ocr", required=True)
|
||||||
@click.option("--ocr-lang", 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"""
|
"""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(
|
sys.exit(
|
||||||
exec_container(
|
exec_container(
|
||||||
|
@ -130,6 +155,7 @@ def pixelstopdf(pixel_dir, safe_dir, container_name, ocr, ocr_lang):
|
||||||
f"OCR_LANGUAGE={ocr_lang}",
|
f"OCR_LANGUAGE={ocr_lang}",
|
||||||
container_name,
|
container_name,
|
||||||
"pixels-to-pdf",
|
"pixels-to-pdf",
|
||||||
]
|
],
|
||||||
|
load_vm_info(vm_info_path),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -443,6 +443,8 @@ class GlobalCommon(object):
|
||||||
|
|
||||||
def exec_dangerzone_container(self, args):
|
def exec_dangerzone_container(self, args):
|
||||||
args = [self.dz_container_path] + 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)
|
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)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
from dangerzone import global_common
|
|
||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
import tempfile
|
||||||
|
import subprocess
|
||||||
from PySide2 import QtCore, QtGui, QtWidgets
|
from PySide2 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
from .tasks import ConvertToPixels, ConvertToPDF
|
||||||
from ..common import Common
|
from ..common import Common
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ class Vm(QtCore.QObject):
|
||||||
)
|
)
|
||||||
self.sshd_pid_path = os.path.join(self.state_dir.name, "sshd.pid")
|
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.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")
|
self.vm_disk_img_path = os.path.join(self.state_dir.name, "disk.img")
|
||||||
|
|
||||||
# UDID for VM
|
# UDID for VM
|
||||||
|
@ -145,8 +146,6 @@ class Vm(QtCore.QObject):
|
||||||
"-o",
|
"-o",
|
||||||
"Compression=yes",
|
"Compression=yes",
|
||||||
"-o",
|
"-o",
|
||||||
"ForceCommand=/usr/bin/whoami",
|
|
||||||
"-o",
|
|
||||||
"UseDNS=no",
|
"UseDNS=no",
|
||||||
"-o",
|
"-o",
|
||||||
f"AuthorizedKeysFile={self.ssh_client_pubkey_path}",
|
f"AuthorizedKeysFile={self.ssh_client_pubkey_path}",
|
||||||
|
@ -157,7 +156,7 @@ class Vm(QtCore.QObject):
|
||||||
|
|
||||||
# Create a JSON object to pass into the VM
|
# Create a JSON object to pass into the VM
|
||||||
# This is a 512kb file that starts with a JSON object, followed by null bytes
|
# 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": ssh_client_key,
|
||||||
"id_ed25519.pub": ssh_client_pubkey,
|
"id_ed25519.pub": ssh_client_pubkey,
|
||||||
"user": getpass.getuser(),
|
"user": getpass.getuser(),
|
||||||
|
@ -166,9 +165,17 @@ class Vm(QtCore.QObject):
|
||||||
"tunnel_port": self.sshd_tunnel_port,
|
"tunnel_port": self.sshd_tunnel_port,
|
||||||
}
|
}
|
||||||
with open(self.vm_disk_img_path, "wb") as f:
|
with open(self.vm_disk_img_path, "wb") as f:
|
||||||
vm_info_bytes = json.dumps(vm_info).encode()
|
guest_vm_info_bytes = json.dumps(guest_vm_info).encode()
|
||||||
f.write(vm_info_bytes)
|
f.write(guest_vm_info_bytes)
|
||||||
f.write(b"\x00" * (512 * 1024 - len(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
|
# Run VPNKit
|
||||||
args = [
|
args = [
|
||||||
|
|
|
@ -31,15 +31,25 @@ def main():
|
||||||
f.write(info["id_ed25519.pub"])
|
f.write(info["id_ed25519.pub"])
|
||||||
f.write("\n")
|
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", 0o700)
|
||||||
os.chmod("/home/user/.ssh/id_ed25519", 0o600)
|
os.chmod("/home/user/.ssh/id_ed25519", 0o600)
|
||||||
os.chmod("/home/user/.ssh/id_ed25519.pub", 0o644)
|
os.chmod("/home/user/.ssh/id_ed25519.pub", 0o644)
|
||||||
os.chmod("/home/user/.ssh/authorized_keys", 0o600)
|
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", "user", "user")
|
||||||
shutil.chown("/home/user/.ssh/id_ed25519", "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/id_ed25519.pub", "user", "user")
|
||||||
shutil.chown("/home/user/.ssh/authorized_keys", "user", "user")
|
shutil.chown("/home/user/.ssh/authorized_keys", "user", "user")
|
||||||
|
shutil.chown("/home/user/.ssh/config", "user", "user")
|
||||||
|
|
||||||
# Start SSH reverse port forward
|
# Start SSH reverse port forward
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
|
@ -50,14 +60,10 @@ def main():
|
||||||
"/usr/bin/ssh",
|
"/usr/bin/ssh",
|
||||||
"-o",
|
"-o",
|
||||||
"StrictHostKeyChecking=no",
|
"StrictHostKeyChecking=no",
|
||||||
"-i",
|
|
||||||
"/home/user/.ssh/id_ed25519",
|
|
||||||
"-N",
|
"-N",
|
||||||
"-R",
|
"-R",
|
||||||
f"{info['tunnel_port']}:127.0.0.1:22",
|
f"{info['tunnel_port']}:127.0.0.1:22",
|
||||||
"-p",
|
"hostbox",
|
||||||
str(info["port"]),
|
|
||||||
f"{info['user']}@{info['ip']}",
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue