diff --git a/BUILD.md b/BUILD.md index b1f7ae6..d8fc97e 100644 --- a/BUILD.md +++ b/BUILD.md @@ -31,7 +31,13 @@ Create a .deb: Install dependencies: ```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: @@ -62,7 +68,9 @@ If you don't have it already, install poetry (`pip3 install --user poetry`). The 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 ./install/macos/make-vm.sh @@ -97,8 +105,6 @@ The output is in the `dist` folder. ## 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. 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,31 @@ Change to the `dangerzone` folder, and install the poetry dependencies: 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) +- [Chocolatey](https://chocolatey.org/install) + +Open an administrator PowerShell and run: + +``` +choco install vcbuildtools +``` + +Build OpenSSH: + +``` +powershell.exe -executionpolicy remotesigned -File .\install\windows\make-openssh.ps1 +``` + +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: ``` diff --git a/dangerzone/gui/vm.py b/dangerzone/gui/vm.py index 6680678..5517527 100644 --- a/dangerzone/gui/vm.py +++ b/dangerzone/gui/vm.py @@ -1,5 +1,4 @@ import os -import sys import subprocess import uuid import pipes @@ -10,6 +9,7 @@ import getpass import json import psutil import time +import platform from PySide2 import QtCore @@ -32,24 +32,8 @@ class Vm(QtCore.QObject): self.sshd_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 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_pubkey_path = os.path.join( self.state_dir.name, "host_ed25519.pub" @@ -63,11 +47,33 @@ class Vm(QtCore.QObject): 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 - self.vm_uuid = str(uuid.uuid4()) - self.vm_cmdline = ( - "earlyprintk=serial console=ttyS0 modules=loop,squashfs,sd-mod" - ) + if platform.system() == "Darwin": + # 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" + ) + + # 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": + pass # Threads self.wait_t = None @@ -78,9 +84,6 @@ class Vm(QtCore.QObject): def start(self): print("Starting VM\n") - self.state = self.STATE_STARTING - self.vm_state_change.emit(self.state) - # Delete keys if they already exist for filename in [ self.ssh_host_key_path, @@ -91,6 +94,10 @@ class Vm(QtCore.QObject): if os.path.exists(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 subprocess.run( [ @@ -127,10 +134,6 @@ class Vm(QtCore.QObject): with open(self.ssh_client_pubkey_path) as f: 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 args = [ "/usr/sbin/sshd", @@ -162,6 +165,13 @@ class Vm(QtCore.QObject): print("> " + args_str) subprocess.run(args, stdout=self.devnull, stderr=self.devnull) + if platform.system() == "Darwin": + self.start_macos() + + 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 # This is a 512kb file that starts with a JSON object, followed by null bytes guest_vm_info = { @@ -257,6 +267,10 @@ class Vm(QtCore.QObject): self.vm_state_change.emit(self.state) def stop(self): + if platform.system() == "Darwin": + self.stop_macos() + + def stop_macos(self): # Kill existing processes self.kill_sshd() if self.vpnkit_p is not None: diff --git a/dev_scripts/dangerzone-container.bat b/dev_scripts/dangerzone-container.bat deleted file mode 100644 index 07b3fc3..0000000 --- a/dev_scripts/dangerzone-container.bat +++ /dev/null @@ -1,2 +0,0 @@ -set DANGERZONE_MODE=container -poetry run python .\dev_scripts\dangerzone %* \ No newline at end of file diff --git a/install/vm-builder/windows.sh b/install/vm-builder/windows.sh new file mode 100644 index 0000000..1bfaa1d --- /dev/null +++ b/install/vm-builder/windows.sh @@ -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 diff --git a/install/windows/get-openssh.py b/install/windows/get-openssh.py new file mode 100644 index 0000000..ce24f1c --- /dev/null +++ b/install/windows/get-openssh.py @@ -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() diff --git a/install/windows/make-vm.bat b/install/windows/make-vm.bat new file mode 100644 index 0000000..25c9142 --- /dev/null +++ b/install/windows/make-vm.bat @@ -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 +if not exists share\vm mkdir share\vm +cp install\vm-builder\vm\* share\vm