mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-29 10:12:38 +02:00
Merge branch 'vm' of github.com:firstlookmedia/dangerzone into vm
This commit is contained in:
commit
db674a184e
10 changed files with 314 additions and 55 deletions
26
BUILD.md
26
BUILD.md
|
@ -31,7 +31,13 @@ Create a .deb:
|
||||||
Install dependencies:
|
Install dependencies:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo dnf install -y rpm-build podman python3 python3-setuptools python3-pyside2 python3-appdirs python3-click python3-pyxdg python3-requests python3-colorama
|
sudo dnf install -y rpm-build podman python3 python3-setuptools python3-pyside2 python3-appdirs python3-click python3-pyxdg python3-requests python3-colorama python3-psutil
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the latest container:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./install/linux/build-container.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Run from source tree:
|
Run from source tree:
|
||||||
|
@ -62,7 +68,9 @@ If you don't have it already, install poetry (`pip3 install --user poetry`). The
|
||||||
poetry install
|
poetry install
|
||||||
```
|
```
|
||||||
|
|
||||||
Make sure [Docker Desktop](https://www.docker.com/products/docker-desktop) and vagrant (`brew install vagrant`) are installed and run this to collect the binaries from Docker Desktop and then build a custom Alpine Linux ISO for Dangerzone, and copy them into the `share` folder:
|
Make sure [Docker Desktop](https://www.docker.com/products/docker-desktop) and vagrant (`brew install vagrant`) are installed.
|
||||||
|
|
||||||
|
Run this to build a custom Alpine Linux ISO for Dangerzone, and copy it into the `share` folder:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./install/macos/make-vm.sh
|
./install/macos/make-vm.sh
|
||||||
|
@ -97,8 +105,6 @@ The output is in the `dist` folder.
|
||||||
|
|
||||||
## Windows
|
## Windows
|
||||||
|
|
||||||
Install [Docker Desktop](https://www.docker.com/products/docker-desktop).
|
|
||||||
|
|
||||||
These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH.
|
These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH.
|
||||||
|
|
||||||
Download Python 3.9.0, 32-bit (x86) from https://www.python.org/downloads/release/python-390/. I downloaded python-3.9.0.exe. When installing it, make sure to check the "Add Python 3.9 to PATH" checkbox on the first page of the installer.
|
Download Python 3.9.0, 32-bit (x86) from https://www.python.org/downloads/release/python-390/. I downloaded python-3.9.0.exe. When installing it, make sure to check the "Add Python 3.9 to PATH" checkbox on the first page of the installer.
|
||||||
|
@ -115,6 +121,18 @@ Change to the `dangerzone` folder, and install the poetry dependencies:
|
||||||
poetry install
|
poetry install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Make sure these are installed:
|
||||||
|
|
||||||
|
- [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||||
|
- [Vagrant](https://www.vagrantup.com/downloads)
|
||||||
|
- [VirtualBox](https://www.virtualbox.org/wiki/Downloads)
|
||||||
|
|
||||||
|
Run this to build a custom Alpine Linux ISO for Dangerzone, and copy it (and some binaries from Docker) into the `share` folder:
|
||||||
|
|
||||||
|
```
|
||||||
|
.\install\windows\make-vm.bat
|
||||||
|
```
|
||||||
|
|
||||||
After that you can launch dangerzone during development with:
|
After that you can launch dangerzone during development with:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -88,10 +88,13 @@ def vm_exec(args, vm_info, stdout_callback=None):
|
||||||
return exec(args, stdout_callback)
|
return exec(args, stdout_callback)
|
||||||
|
|
||||||
|
|
||||||
def vm_mkdir(vm_info):
|
def vm_mkdirs(vm_info):
|
||||||
guest_path = os.path.join("/home/user/", str(uuid.uuid4()))
|
guest_path = os.path.join("/home/user/", str(uuid.uuid4()))
|
||||||
vm_exec(["/bin/mkdir", guest_path], vm_info)
|
input_dir = os.path.join(guest_path, "input")
|
||||||
return guest_path
|
pixel_dir = os.path.join(guest_path, "pixel")
|
||||||
|
safe_dir = os.path.join(guest_path, "safe")
|
||||||
|
vm_exec(["/bin/mkdir", guest_path, input_dir, pixel_dir, safe_dir], vm_info)
|
||||||
|
return guest_path, input_dir, pixel_dir, safe_dir
|
||||||
|
|
||||||
|
|
||||||
def vm_rmdir(guest_path, vm_info):
|
def vm_rmdir(guest_path, vm_info):
|
||||||
|
@ -154,13 +157,9 @@ def convert(global_common, input_filename, output_filename, ocr_lang, stdout_cal
|
||||||
# Otherwise, create temp dirs
|
# Otherwise, create temp dirs
|
||||||
if vm_info:
|
if vm_info:
|
||||||
ssh_args_str = " ".join(pipes.quote(s) for s in vm_ssh_args(vm_info))
|
ssh_args_str = " ".join(pipes.quote(s) for s in vm_ssh_args(vm_info))
|
||||||
print("If you want to SSH to the VM: " + ssh_args_str)
|
print("\nIf you want to SSH to the VM:\n" + ssh_args_str + "\n")
|
||||||
|
|
||||||
guest_tmpdir = vm_mkdir(vm_info)
|
|
||||||
input_dir = os.path.join(guest_tmpdir, "input")
|
|
||||||
pixel_dir = os.path.join(guest_tmpdir, "pixel")
|
|
||||||
safe_dir = os.path.join(guest_tmpdir, "safe")
|
|
||||||
|
|
||||||
|
guest_tmpdir, input_dir, pixel_dir, safe_dir = vm_mkdirs(vm_info)
|
||||||
guest_input_filename = os.path.join(input_dir, "input_file")
|
guest_input_filename = os.path.join(input_dir, "input_file")
|
||||||
container_output_filename = os.path.join(safe_dir, "safe-output-compressed.pdf")
|
container_output_filename = os.path.join(safe_dir, "safe-output-compressed.pdf")
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ 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)
|
||||||
|
self.is_waiting_finished = False
|
||||||
|
|
||||||
def get_window_icon(self):
|
def get_window_icon(self):
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
path = self.global_common.get_resource_path("dangerzone.ico")
|
path = self.global_common.get_resource_path("dangerzone.ico")
|
||||||
|
|
|
@ -54,8 +54,12 @@ 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 we have a VM
|
||||||
self.waiting_widget.show()
|
if self.gui_common.is_waiting_finished:
|
||||||
self.content_widget.hide()
|
self.waiting_widget.hide()
|
||||||
|
self.content_widget.show()
|
||||||
|
else:
|
||||||
|
self.waiting_widget.show()
|
||||||
|
self.content_widget.hide()
|
||||||
|
|
||||||
# Layout
|
# Layout
|
||||||
layout = QtWidgets.QVBoxLayout()
|
layout = QtWidgets.QVBoxLayout()
|
||||||
|
@ -70,6 +74,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def waiting_finished(self):
|
def waiting_finished(self):
|
||||||
|
self.gui_common.is_waiting_finished = True
|
||||||
self.waiting_widget.hide()
|
self.waiting_widget.hide()
|
||||||
self.content_widget.show()
|
self.content_widget.show()
|
||||||
|
|
||||||
|
@ -423,13 +428,14 @@ class SettingsWidget(QtWidgets.QWidget):
|
||||||
|
|
||||||
|
|
||||||
class ConvertThread(QtCore.QThread):
|
class ConvertThread(QtCore.QThread):
|
||||||
finished = QtCore.Signal()
|
finished = QtCore.Signal(bool)
|
||||||
update = QtCore.Signal(bool, str, int)
|
update = QtCore.Signal(bool, str, int)
|
||||||
|
|
||||||
def __init__(self, global_common, common):
|
def __init__(self, global_common, common):
|
||||||
super(ConvertThread, self).__init__()
|
super(ConvertThread, self).__init__()
|
||||||
self.global_common = global_common
|
self.global_common = global_common
|
||||||
self.common = common
|
self.common = common
|
||||||
|
self.error = False
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
ocr_lang = self.global_common.ocr_languages[
|
ocr_lang = self.global_common.ocr_languages[
|
||||||
|
@ -443,19 +449,20 @@ class ConvertThread(QtCore.QThread):
|
||||||
ocr_lang,
|
ocr_lang,
|
||||||
self.stdout_callback,
|
self.stdout_callback,
|
||||||
):
|
):
|
||||||
self.finished.emit()
|
self.finished.emit(self.error)
|
||||||
|
|
||||||
def stdout_callback(self, line):
|
def stdout_callback(self, line):
|
||||||
try:
|
try:
|
||||||
status = json.loads(line)
|
status = json.loads(line)
|
||||||
except:
|
except:
|
||||||
print(f"Invalid JSON returned from container: {line}")
|
print(f"Invalid JSON returned from container: {line}")
|
||||||
|
self.error = True
|
||||||
self.update.emit(True, "Invalid JSON returned from container", 0)
|
self.update.emit(True, "Invalid JSON returned from container", 0)
|
||||||
return
|
return
|
||||||
|
|
||||||
s = Style.BRIGHT + Fore.CYAN + f"{status['percentage']}% "
|
s = Style.BRIGHT + Fore.CYAN + f"{status['percentage']}% "
|
||||||
if status["error"]:
|
if status["error"]:
|
||||||
|
self.error = True
|
||||||
s += Style.RESET_ALL + Fore.RED + status["text"]
|
s += Style.RESET_ALL + Fore.RED + status["text"]
|
||||||
else:
|
else:
|
||||||
s += Style.RESET_ALL + status["text"]
|
s += Style.RESET_ALL + status["text"]
|
||||||
|
@ -473,6 +480,8 @@ class ConvertWidget(QtWidgets.QWidget):
|
||||||
self.gui_common = gui_common
|
self.gui_common = gui_common
|
||||||
self.common = common
|
self.common = common
|
||||||
|
|
||||||
|
self.error = False
|
||||||
|
|
||||||
# Dangerous document label
|
# Dangerous document label
|
||||||
self.dangerous_doc_label = QtWidgets.QLabel()
|
self.dangerous_doc_label = QtWidgets.QLabel()
|
||||||
self.dangerous_doc_label.setAlignment(QtCore.Qt.AlignCenter)
|
self.dangerous_doc_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
@ -480,11 +489,25 @@ class ConvertWidget(QtWidgets.QWidget):
|
||||||
"QLabel { font-size: 16px; font-weight: bold; }"
|
"QLabel { font-size: 16px; font-weight: bold; }"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Label
|
||||||
|
self.error_image = QtWidgets.QLabel()
|
||||||
|
self.error_image.setPixmap(
|
||||||
|
QtGui.QPixmap.fromImage(
|
||||||
|
QtGui.QImage(self.global_common.get_resource_path("error.png"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.error_image.hide()
|
||||||
|
|
||||||
self.label = QtWidgets.QLabel()
|
self.label = QtWidgets.QLabel()
|
||||||
self.label.setAlignment(QtCore.Qt.AlignCenter)
|
self.label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
self.label.setWordWrap(True)
|
self.label.setWordWrap(True)
|
||||||
self.label.setStyleSheet("QLabel { font-size: 18px; }")
|
self.label.setStyleSheet("QLabel { font-size: 18px; }")
|
||||||
|
|
||||||
|
label_layout = QtWidgets.QHBoxLayout()
|
||||||
|
label_layout.addWidget(self.error_image)
|
||||||
|
label_layout.addWidget(self.label, stretch=1)
|
||||||
|
|
||||||
|
# Progress bar
|
||||||
self.progress = QtWidgets.QProgressBar()
|
self.progress = QtWidgets.QProgressBar()
|
||||||
self.progress.setRange(0, 100)
|
self.progress.setRange(0, 100)
|
||||||
self.progress.setValue(0)
|
self.progress.setValue(0)
|
||||||
|
@ -493,7 +516,7 @@ class ConvertWidget(QtWidgets.QWidget):
|
||||||
layout = QtWidgets.QVBoxLayout()
|
layout = QtWidgets.QVBoxLayout()
|
||||||
layout.addWidget(self.dangerous_doc_label)
|
layout.addWidget(self.dangerous_doc_label)
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
layout.addWidget(self.label)
|
layout.addLayout(label_layout)
|
||||||
layout.addWidget(self.progress)
|
layout.addWidget(self.progress)
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
@ -512,13 +535,17 @@ class ConvertWidget(QtWidgets.QWidget):
|
||||||
|
|
||||||
def update(self, error, text, percentage):
|
def update(self, error, text, percentage):
|
||||||
if error:
|
if error:
|
||||||
# TODO: add error image or something
|
self.error = True
|
||||||
pass
|
self.error_image.show()
|
||||||
|
self.progress.hide()
|
||||||
|
|
||||||
self.label.setText(text)
|
self.label.setText(text)
|
||||||
self.progress.setValue(percentage)
|
self.progress.setValue(percentage)
|
||||||
|
|
||||||
def all_done(self):
|
def all_done(self):
|
||||||
|
if self.error:
|
||||||
|
return
|
||||||
|
|
||||||
# In Windows, open Explorer with the safe PDF in focus
|
# In Windows, open Explorer with the safe PDF in focus
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
dest_filename_windows = self.common.output_filename.replace("/", "\\")
|
dest_filename_windows = self.common.output_filename.replace("/", "\\")
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import uuid
|
import uuid
|
||||||
import pipes
|
import pipes
|
||||||
|
@ -10,6 +9,8 @@ import getpass
|
||||||
import json
|
import json
|
||||||
import psutil
|
import psutil
|
||||||
import time
|
import time
|
||||||
|
import platform
|
||||||
|
import shutil
|
||||||
from PySide2 import QtCore
|
from PySide2 import QtCore
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,24 +33,8 @@ class Vm(QtCore.QObject):
|
||||||
self.sshd_port = None
|
self.sshd_port = None
|
||||||
self.sshd_tunnel_port = None
|
self.sshd_tunnel_port = None
|
||||||
|
|
||||||
# Processes
|
|
||||||
self.vpnkit_p = None
|
|
||||||
self.hyperkit_p = None
|
|
||||||
self.devnull = open(os.devnull, "w")
|
|
||||||
|
|
||||||
# Relevant paths
|
|
||||||
self.vpnkit_path = self.global_common.get_resource_path("bin/vpnkit")
|
|
||||||
self.hyperkit_path = self.global_common.get_resource_path("bin/hyperkit")
|
|
||||||
self.vm_iso_path = self.global_common.get_resource_path("vm/dangerzone.iso")
|
|
||||||
self.vm_kernel_path = self.global_common.get_resource_path("vm/kernel")
|
|
||||||
self.vm_initramfs_path = self.global_common.get_resource_path(
|
|
||||||
"vm/initramfs.img"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Folder to hold temporary files related to the VM
|
# Folder to hold temporary files related to the VM
|
||||||
self.state_dir = tempfile.TemporaryDirectory()
|
self.state_dir = tempfile.TemporaryDirectory()
|
||||||
self.vpnkit_sock_path = os.path.join(self.state_dir.name, "vpnkit.eth.sock")
|
|
||||||
self.hyperkit_pid_path = os.path.join(self.state_dir.name, "hyperkit.pid")
|
|
||||||
self.ssh_host_key_path = os.path.join(self.state_dir.name, "host_ed25519")
|
self.ssh_host_key_path = os.path.join(self.state_dir.name, "host_ed25519")
|
||||||
self.ssh_host_pubkey_path = os.path.join(
|
self.ssh_host_pubkey_path = os.path.join(
|
||||||
self.state_dir.name, "host_ed25519.pub"
|
self.state_dir.name, "host_ed25519.pub"
|
||||||
|
@ -63,11 +48,46 @@ class Vm(QtCore.QObject):
|
||||||
self.vm_info_path = os.path.join(self.state_dir.name, "info.json")
|
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
|
self.vm_iso_path = self.global_common.get_resource_path("vm/dangerzone.iso")
|
||||||
self.vm_uuid = str(uuid.uuid4())
|
|
||||||
self.vm_cmdline = (
|
if platform.system() == "Darwin":
|
||||||
"earlyprintk=serial console=ttyS0 modules=loop,squashfs,sd-mod"
|
self.ssh_keygen_path = shutil.which("ssh-keygen")
|
||||||
)
|
self.sshd_path = shutil.which("sshd")
|
||||||
|
|
||||||
|
# Processes
|
||||||
|
self.vpnkit_p = None
|
||||||
|
self.hyperkit_p = None
|
||||||
|
self.devnull = open(os.devnull, "w")
|
||||||
|
|
||||||
|
# Relevant paths
|
||||||
|
self.vpnkit_path = self.global_common.get_resource_path("bin/vpnkit")
|
||||||
|
self.hyperkit_path = self.global_common.get_resource_path("bin/hyperkit")
|
||||||
|
self.vm_kernel_path = self.global_common.get_resource_path("vm/kernel")
|
||||||
|
self.vm_initramfs_path = self.global_common.get_resource_path(
|
||||||
|
"vm/initramfs.img"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Temporary files related to the VM
|
||||||
|
self.vpnkit_sock_path = os.path.join(self.state_dir.name, "vpnkit.eth.sock")
|
||||||
|
self.hyperkit_pid_path = os.path.join(self.state_dir.name, "hyperkit.pid")
|
||||||
|
|
||||||
|
# UDID for VM
|
||||||
|
self.vm_uuid = str(uuid.uuid4())
|
||||||
|
self.vm_cmdline = (
|
||||||
|
"earlyprintk=serial console=ttyS0 modules=loop,squashfs,sd-mod"
|
||||||
|
)
|
||||||
|
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
self.vboxmanage_path = (
|
||||||
|
"C:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.ssh_keygen_path = os.path.join(
|
||||||
|
self.global_common.get_resource_path("bin"), "ssh-keygen.exe"
|
||||||
|
)
|
||||||
|
self.sshd_path = os.path.join(
|
||||||
|
self.global_common.get_resource_path("bin"), "sshd.exe"
|
||||||
|
)
|
||||||
|
|
||||||
# Threads
|
# Threads
|
||||||
self.wait_t = None
|
self.wait_t = None
|
||||||
|
@ -76,8 +96,7 @@ class Vm(QtCore.QObject):
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.state = self.STATE_STARTING
|
print("Starting VM\n")
|
||||||
self.vm_state_change.emit(self.state)
|
|
||||||
|
|
||||||
# Delete keys if they already exist
|
# Delete keys if they already exist
|
||||||
for filename in [
|
for filename in [
|
||||||
|
@ -89,10 +108,14 @@ class Vm(QtCore.QObject):
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
|
|
||||||
|
# Find an open port
|
||||||
|
self.sshd_port = self.find_open_port()
|
||||||
|
self.sshd_tunnel_port = self.find_open_port()
|
||||||
|
|
||||||
# Generate new keys
|
# Generate new keys
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
[
|
[
|
||||||
"/usr/bin/ssh-keygen",
|
self.ssh_keygen_path,
|
||||||
"-t",
|
"-t",
|
||||||
"ed25519",
|
"ed25519",
|
||||||
"-C",
|
"-C",
|
||||||
|
@ -107,7 +130,7 @@ class Vm(QtCore.QObject):
|
||||||
)
|
)
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
[
|
[
|
||||||
"/usr/bin/ssh-keygen",
|
self.ssh_keygen_path,
|
||||||
"-t",
|
"-t",
|
||||||
"ed25519",
|
"ed25519",
|
||||||
"-C",
|
"-C",
|
||||||
|
@ -125,13 +148,9 @@ class Vm(QtCore.QObject):
|
||||||
with open(self.ssh_client_pubkey_path) as f:
|
with open(self.ssh_client_pubkey_path) as f:
|
||||||
ssh_client_pubkey = f.read()
|
ssh_client_pubkey = f.read()
|
||||||
|
|
||||||
# Find an open port
|
|
||||||
self.sshd_port = self.find_open_port()
|
|
||||||
self.sshd_tunnel_port = self.find_open_port()
|
|
||||||
|
|
||||||
# Start an sshd service on this port
|
# Start an sshd service on this port
|
||||||
args = [
|
args = [
|
||||||
"/usr/sbin/sshd",
|
self.sshd_path,
|
||||||
"-4",
|
"-4",
|
||||||
"-E",
|
"-E",
|
||||||
self.sshd_log_path,
|
self.sshd_log_path,
|
||||||
|
@ -160,6 +179,16 @@ class Vm(QtCore.QObject):
|
||||||
print("> " + args_str)
|
print("> " + args_str)
|
||||||
subprocess.run(args, stdout=self.devnull, stderr=self.devnull)
|
subprocess.run(args, stdout=self.devnull, stderr=self.devnull)
|
||||||
|
|
||||||
|
if platform.system() == "Darwin":
|
||||||
|
self.start_macos()
|
||||||
|
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
self.start_windows()
|
||||||
|
|
||||||
|
def start_macos(self):
|
||||||
|
self.state = self.STATE_STARTING
|
||||||
|
self.vm_state_change.emit(self.state)
|
||||||
|
|
||||||
# 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
|
||||||
guest_vm_info = {
|
guest_vm_info = {
|
||||||
|
@ -246,6 +275,84 @@ class Vm(QtCore.QObject):
|
||||||
self.wait_t.timeout.connect(self.vm_timeout)
|
self.wait_t.timeout.connect(self.vm_timeout)
|
||||||
self.wait_t.start()
|
self.wait_t.start()
|
||||||
|
|
||||||
|
def start_windows(self):
|
||||||
|
vm_name = "dangezone-podman"
|
||||||
|
basefolder_path = os.path.join(
|
||||||
|
self.global_common.appdata_path, "virtualbox-basefolder"
|
||||||
|
)
|
||||||
|
|
||||||
|
# See if we already have a VM
|
||||||
|
exists = False
|
||||||
|
for line in subprocess.check_output([self.vboxmanage_path, "list", "vms"]):
|
||||||
|
name = line.split()[0].lstrip('"').rstrip('"')
|
||||||
|
if name == vm_name:
|
||||||
|
exists = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# Create the VM
|
||||||
|
if not exists:
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
self.vboxmanage_path,
|
||||||
|
"createvm",
|
||||||
|
"--name",
|
||||||
|
vm_name,
|
||||||
|
"--basefolder",
|
||||||
|
basefolder_path,
|
||||||
|
"--ostype",
|
||||||
|
"Linux_x64",
|
||||||
|
"--register",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Configure the VM
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
self.vboxmanage_path,
|
||||||
|
"modifyvm",
|
||||||
|
vm_name,
|
||||||
|
"--memory",
|
||||||
|
"4096",
|
||||||
|
"--nic1",
|
||||||
|
"nat",
|
||||||
|
"--cableconnected1",
|
||||||
|
"on",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
self.vboxmanage_path,
|
||||||
|
"storagectl",
|
||||||
|
vm_name,
|
||||||
|
"--name",
|
||||||
|
"DangerzoneBoot",
|
||||||
|
"--add",
|
||||||
|
"ide",
|
||||||
|
"--bootable",
|
||||||
|
"on",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
self.vboxmanage_path,
|
||||||
|
"storageattach",
|
||||||
|
vm_name,
|
||||||
|
"--storagectl",
|
||||||
|
"DangerzoneBoot",
|
||||||
|
"--port",
|
||||||
|
"1",
|
||||||
|
"--device",
|
||||||
|
"1",
|
||||||
|
"--type",
|
||||||
|
"dvddrive",
|
||||||
|
"--medium",
|
||||||
|
self.vm_iso_path,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Start the VM
|
||||||
|
subprocess.run([self.vboxmanage_path, "startvm", "--type", "headless"])
|
||||||
|
|
||||||
def vm_connected(self):
|
def vm_connected(self):
|
||||||
self.state = self.STATE_ON
|
self.state = self.STATE_ON
|
||||||
self.vm_state_change.emit(self.state)
|
self.vm_state_change.emit(self.state)
|
||||||
|
@ -255,8 +362,16 @@ class Vm(QtCore.QObject):
|
||||||
self.vm_state_change.emit(self.state)
|
self.vm_state_change.emit(self.state)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
# Kill existing processes
|
|
||||||
self.kill_sshd()
|
self.kill_sshd()
|
||||||
|
|
||||||
|
if platform.system() == "Darwin":
|
||||||
|
self.stop_macos()
|
||||||
|
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
self.stop_windows()
|
||||||
|
|
||||||
|
def stop_macos(self):
|
||||||
|
# Kill existing processes
|
||||||
if self.vpnkit_p is not None:
|
if self.vpnkit_p is not None:
|
||||||
self.vpnkit_p.terminate()
|
self.vpnkit_p.terminate()
|
||||||
self.vpnkit_p = None
|
self.vpnkit_p = None
|
||||||
|
@ -267,6 +382,17 @@ class Vm(QtCore.QObject):
|
||||||
# Just to be extra sure
|
# Just to be extra sure
|
||||||
self.kill_hyperkit()
|
self.kill_hyperkit()
|
||||||
|
|
||||||
|
def stop_windows(self):
|
||||||
|
vm_name = "dangezone-podman"
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
self.vboxmanage_path,
|
||||||
|
"controlvm",
|
||||||
|
vm_name,
|
||||||
|
"poweroff",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
def find_open_port(self):
|
def find_open_port(self):
|
||||||
with socket.socket() as tmpsock:
|
with socket.socket() as tmpsock:
|
||||||
while True:
|
while True:
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
set DANGERZONE_MODE=container
|
|
||||||
poetry run python .\dev_scripts\dangerzone %*
|
|
12
install/vm-builder/windows.sh
Normal file
12
install/vm-builder/windows.sh
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
VAGRANT_FILES=$(find /vagrant -type f | grep -v /vagrant/.vagrant | grep -v /vagrant/vm)
|
||||||
|
DANGERZONE_CONVERTER_FILES=$(find /opt/dangerzone-converter -type f)
|
||||||
|
|
||||||
|
for FILE in $VAGRANT_FILES; do dos2unix $FILE; done
|
||||||
|
for FILE in $DANGERZONE_CONVERTER_FILES; do dos2unix $FILE; done
|
||||||
|
|
||||||
|
/vagrant/build-iso.sh
|
||||||
|
|
||||||
|
for FILE in $VAGRANT_FILES; do unix2dos $FILE; done
|
||||||
|
for FILE in $DANGERZONE_CONVERTER_FILES; do unix2dos $FILE; done
|
65
install/windows/get-openssh.py
Normal file
65
install/windows/get-openssh.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import inspect
|
||||||
|
import requests
|
||||||
|
import hashlib
|
||||||
|
import zipfile
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
zip_url = "https://github.com/PowerShell/Win32-OpenSSH/releases/download/V8.6.0.0p1-Beta/OpenSSH-Win32.zip"
|
||||||
|
expected_zip_sha256 = (
|
||||||
|
"0221324212413a6caf260f95e308d22f8c141fc37727b622a6ad50998c46d226"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Figure out the paths
|
||||||
|
root_path = os.path.dirname(
|
||||||
|
os.path.dirname(
|
||||||
|
os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
zip_path = os.path.join(root_path, "build", "OpenSSH-Win32.zip")
|
||||||
|
extracted_path = os.path.join(root_path, "build", "OpenSSH-Win32")
|
||||||
|
bin_path = os.path.join(root_path, "share", "bin")
|
||||||
|
|
||||||
|
os.makedirs(os.path.join(root_path, "build"), exist_ok=True)
|
||||||
|
os.makedirs(os.path.join(bin_path), exist_ok=True)
|
||||||
|
|
||||||
|
# Make sure openssh is downloaded
|
||||||
|
if not os.path.exists(zip_path):
|
||||||
|
print(f"Downloading {zip_url}")
|
||||||
|
r = requests.get(zip_url)
|
||||||
|
open(zip_path, "wb").write(r.content)
|
||||||
|
zip_sha256 = hashlib.sha256(r.content).hexdigest()
|
||||||
|
else:
|
||||||
|
zip_data = open(zip_path, "rb").read()
|
||||||
|
zip_sha256 = hashlib.sha256(zip_data).hexdigest()
|
||||||
|
|
||||||
|
# Compare the hash
|
||||||
|
if zip_sha256 != expected_zip_sha256:
|
||||||
|
print("ERROR! The sha256 doesn't match:")
|
||||||
|
print("expected: {}".format(expected_zip_sha256))
|
||||||
|
print(" actual: {}".format(zip_sha256))
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
# Extract the zip
|
||||||
|
with zipfile.ZipFile(zip_path, "r") as z:
|
||||||
|
z.extractall(os.path.join(root_path, "build"))
|
||||||
|
|
||||||
|
# Copy binaries to share
|
||||||
|
shutil.copy(os.path.join(extracted_path, "libcrypto.dll"), bin_path)
|
||||||
|
shutil.copy(os.path.join(extracted_path, "moduli"), bin_path)
|
||||||
|
shutil.copy(os.path.join(extracted_path, "scp.exe"), bin_path)
|
||||||
|
shutil.copy(os.path.join(extracted_path, "ssh-agent.exe"), bin_path)
|
||||||
|
shutil.copy(os.path.join(extracted_path, "ssh-keygen.exe"), bin_path)
|
||||||
|
shutil.copy(os.path.join(extracted_path, "ssh.exe"), bin_path)
|
||||||
|
shutil.copy(os.path.join(extracted_path, "sshd.exe"), bin_path)
|
||||||
|
shutil.copyfile(
|
||||||
|
os.path.join(extracted_path, "LICENSE.txt"),
|
||||||
|
os.path.join(bin_path, "LICENSE-OpenSSH.txt"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
11
install/windows/make-vm.bat
Normal file
11
install/windows/make-vm.bat
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
REM Build ISO
|
||||||
|
cd install\vm-builder
|
||||||
|
vagrant up
|
||||||
|
vagrant ssh -- dos2unix /vagrant/windows.sh
|
||||||
|
vagrant ssh -- /vagrant/windows.sh
|
||||||
|
vagrant halt
|
||||||
|
cd ..\..
|
||||||
|
|
||||||
|
REM Copy the ISO to resources
|
||||||
|
mkdir share\vm
|
||||||
|
cp install\vm-builder\vm\dangerzone.iso share\vm
|
BIN
share/error.png
Normal file
BIN
share/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Loading…
Reference in a new issue