Merge pull request #120 from firstlookmedia/podman

Switch back to Podman in Linux
This commit is contained in:
Micah Lee 2021-06-22 13:57:33 -04:00 committed by GitHub
commit 9df7c4095a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 67 additions and 253 deletions

View file

@ -81,37 +81,6 @@ jobs:
package_cloud push firstlookmedia/code/ubuntu/groovy deb_dist/dangerzone_${VERSION}-1_all.deb package_cloud push firstlookmedia/code/ubuntu/groovy deb_dist/dangerzone_${VERSION}-1_all.deb
package_cloud push firstlookmedia/code/ubuntu/groovy deb_dist/dangerzone_${VERSION}-1.dsc package_cloud push firstlookmedia/code/ubuntu/groovy deb_dist/dangerzone_${VERSION}-1.dsc
build-ubuntu-focal:
docker:
- image: ubuntu:20.04
steps:
- run:
name: Install dependencies
command: |
export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true
apt-get update
apt-get install -y git ssh ruby-dev rubygems python-all dh-python python3 python3-stdeb python3-pyside2.qtcore python3-pyside2.qtgui python3-pyside2.qtwidgets python3-appdirs python3-click python3-xdg python3-requests python3-colorama
gem install -N rake
gem install -N package_cloud
- checkout
- run:
name: Create the .deb package
command: |
./install/linux/build_deb.py
dpkg -i deb_dist/dangerzone_*-1_all.deb
- run:
name: Deploy to packagecloud.io
# Linux Mint 20 (ulyana) and 20.1 (ulyssa) are based on Ubuntu 20.04 LTS
# https://en.wikipedia.org/wiki/Linux_Mint_version_history
command: |
VERSION=$(cat share/version.txt)
package_cloud push firstlookmedia/code/ubuntu/focal deb_dist/dangerzone_${VERSION}-1_all.deb
package_cloud push firstlookmedia/code/ubuntu/focal deb_dist/dangerzone_${VERSION}-1.dsc
package_cloud push firstlookmedia/code/linuxmint/ulyana deb_dist/dangerzone_${VERSION}-1_all.deb
package_cloud push firstlookmedia/code/linuxmint/ulyana deb_dist/dangerzone_${VERSION}-1.dsc
package_cloud push firstlookmedia/code/linuxmint/ulyssa deb_dist/dangerzone_${VERSION}-1_all.deb
package_cloud push firstlookmedia/code/linuxmint/ulyssa deb_dist/dangerzone_${VERSION}-1.dsc
build-debian-bullseye: build-debian-bullseye:
docker: docker:
- image: debian:bullseye - image: debian:bullseye
@ -136,30 +105,6 @@ jobs:
package_cloud push firstlookmedia/code/debian/bullseye deb_dist/dangerzone_${VERSION}-1_all.deb package_cloud push firstlookmedia/code/debian/bullseye deb_dist/dangerzone_${VERSION}-1_all.deb
package_cloud push firstlookmedia/code/debian/bullseye deb_dist/dangerzone_${VERSION}-1.dsc package_cloud push firstlookmedia/code/debian/bullseye deb_dist/dangerzone_${VERSION}-1.dsc
build-debian-buster:
docker:
- image: debian:buster
steps:
- run:
name: Install dependencies
command: |
apt-get update
apt-get install -y git ssh ruby-dev rubygems python-all dh-python python3 python3-stdeb python3-pyside2.qtcore python3-pyside2.qtgui python3-pyside2.qtwidgets python3-appdirs python3-click python3-xdg python3-requests python3-colorama
gem install --no-ri --no-rdoc rake
gem install --no-ri --no-rdoc package_cloud
- checkout
- run:
name: Create the .deb package
command: |
./install/linux/build_deb.py
dpkg -i deb_dist/dangerzone_*-1_all.deb
- run:
name: Deploy to packagecloud.io
command: |
VERSION=$(cat share/version.txt)
package_cloud push firstlookmedia/code/debian/buster deb_dist/dangerzone_${VERSION}-1_all.deb
package_cloud push firstlookmedia/code/debian/buster deb_dist/dangerzone_${VERSION}-1.dsc
build-fedora-34: build-fedora-34:
docker: docker:
# The package_cloud ruby gem doesn't work properly when installed in fedora 34, # The package_cloud ruby gem doesn't work properly when installed in fedora 34,
@ -252,24 +197,12 @@ workflows:
only: /^v.*/ only: /^v.*/
branches: branches:
ignore: /.*/ ignore: /.*/
- build-ubuntu-focal:
filters:
tags:
only: /^v.*/
branches:
ignore: /.*/
- build-debian-bullseye: - build-debian-bullseye:
filters: filters:
tags: tags:
only: /^v.*/ only: /^v.*/
branches: branches:
ignore: /.*/ ignore: /.*/
- build-debian-buster:
filters:
tags:
only: /^v.*/
branches:
ignore: /.*/
- build-fedora-34: - build-fedora-34:
filters: filters:
tags: tags:

View file

@ -5,11 +5,9 @@
Install dependencies: Install dependencies:
```sh ```sh
sudo apt install -y dh-python python3 python3-stdeb python3-pyside2.qtcore python3-pyside2.qtgui python3-pyside2.qtwidgets python3-appdirs python3-click python3-xdg python3-requests python3-colorama sudo apt install -y podman dh-python python3 python3-stdeb python3-pyside2.qtcore python3-pyside2.qtgui python3-pyside2.qtwidgets python3-appdirs python3-click python3-xdg python3-requests python3-colorama
``` ```
You also need docker, either by installing the [Docker snap package](https://snapcraft.io/docker), installing the `docker.io` package, or by installing `docker-ce` by following [these instructions for Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/) or [for Debian](https://docs.docker.com/install/linux/docker-ce/debian/).
Run from source tree: Run from source tree:
```sh ```sh
@ -27,11 +25,9 @@ Create a .deb:
Install dependencies: Install dependencies:
```sh ```sh
sudo dnf install -y rpm-build 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
``` ```
You also need docker, either by installing the `docker` package, or by installing `docker-ce` by following [these instructions](https://docs.docker.com/install/linux/docker-ce/fedora/).
Run from source tree: Run from source tree:
```sh ```sh
@ -46,6 +42,8 @@ Create a .rpm:
## macOS ## macOS
Install [Docker Desktop](https://www.docker.com/products/docker-desktop).
Install python@3.9 from Homebrew: Install python@3.9 from Homebrew:
``` ```
@ -87,6 +85,8 @@ 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.

View file

@ -9,7 +9,7 @@ from .common import Common
def print_header(s): def print_header(s):
click.echo("") click.echo("")
click.echo(Style.BRIGHT + Fore.LIGHTWHITE_EX + s) click.echo(Style.BRIGHT + s)
def exec_container(global_common, args): def exec_container(global_common, args):
@ -22,7 +22,7 @@ def exec_container(global_common, args):
# Hack to add colors to the command executing # Hack to add colors to the command executing
if line.startswith(b"> "): if line.startswith(b"> "):
print( print(
Fore.YELLOW + "> " + Fore.LIGHTCYAN_EX + line.decode()[2:], Style.DIM + "> " + Style.NORMAL + Fore.CYAN + line.decode()[2:],
end="", end="",
) )
else: else:

View file

@ -2,6 +2,7 @@ import os
import stat import stat
import platform import platform
import tempfile import tempfile
import appdirs
class Common(object): class Common(object):
@ -11,18 +12,7 @@ class Common(object):
def __init__(self): def __init__(self):
# Temporary directory to store pixel data and safe PDFs # Temporary directory to store pixel data and safe PDFs
if platform.system() == "Windows": cache_dir = appdirs.user_cache_dir("dangerzone")
self.pixel_dir = tempfile.TemporaryDirectory(prefix="dangerzone-pixel-")
self.safe_dir = tempfile.TemporaryDirectory(prefix="dangerzone-safe-")
elif platform.system() == "Darwin":
# In macOS, temp dirs must be in /tmp (or a few other paths) for Docker to mount them
self.pixel_dir = tempfile.TemporaryDirectory(
prefix="/tmp/dangerzone-pixel-"
)
self.safe_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-safe-")
else:
# In Linux, temp dirs must be in the homedir for the snap package version of Docker to mount them
cache_dir = os.path.expanduser("~/.cache/dangerzone")
os.makedirs(cache_dir, exist_ok=True) os.makedirs(cache_dir, exist_ok=True)
self.pixel_dir = tempfile.TemporaryDirectory( self.pixel_dir = tempfile.TemporaryDirectory(
prefix=os.path.join(cache_dir, "pixel-") prefix=os.path.join(cache_dir, "pixel-")
@ -31,6 +21,7 @@ class Common(object):
prefix=os.path.join(cache_dir, "safe-") prefix=os.path.join(cache_dir, "safe-")
) )
try:
# Make the folders world-readable to ensure that the container has permission # Make the folders world-readable to ensure that the container has permission
# to access it even if it's owned by root or someone else # to access it even if it's owned by root or someone else
permissions = ( permissions = (
@ -44,6 +35,8 @@ class Common(object):
) )
os.chmod(self.pixel_dir.name, permissions) os.chmod(self.pixel_dir.name, permissions)
os.chmod(self.safe_dir.name, permissions) os.chmod(self.safe_dir.name, permissions)
except:
pass
# Name of input and out files # Name of input and out files
self.document_filename = None self.document_filename = None

View file

@ -4,13 +4,21 @@ import subprocess
import sys import sys
import pipes import pipes
import shutil import shutil
import os
# 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_runtime = "/usr/local/bin/docker" container_tech = "docker"
container_runtime = shutil.which("docker")
elif platform.system() == "Windows": elif platform.system() == "Windows":
container_tech = "docker"
container_runtime = shutil.which("docker.exe") container_runtime = shutil.which("docker.exe")
elif platform.system() == "Linux":
container_tech = "podman"
container_runtime = shutil.which("podman")
else: else:
print("Unknown operating system, defaulting to Docker")
container_tech = "docker"
container_runtime = shutil.which("docker") container_runtime = shutil.which("docker")
# Define startupinfo for subprocesses # Define startupinfo for subprocesses
@ -28,6 +36,17 @@ def exec_container(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,
@ -36,6 +55,7 @@ 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
@ -51,7 +71,7 @@ def container_main():
@container_main.command() @container_main.command()
@click.option("--container-name", default="flmcode/dangerzone") @click.option("--container-name", default="docker.io/flmcode/dangerzone")
def ls(container_name): def ls(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]))
@ -60,22 +80,22 @@ def ls(container_name):
@container_main.command() @container_main.command()
def pull(): def pull():
"""docker pull flmcode/dangerzone""" """docker pull flmcode/dangerzone"""
sys.exit(exec_container(["pull", "flmcode/dangerzone"])) sys.exit(exec_container(["pull", "docker.io/flmcode/dangerzone"]))
@container_main.command() @container_main.command()
@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="flmcode/dangerzone") @click.option("--container-name", default="docker.io/flmcode/dangerzone")
def documenttopixels(document_filename, pixel_dir, container_name): def documenttopixels(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"""
sys.exit( args = ["run", "--network", "none"]
exec_container(
[ # docker uses --security-opt, podman doesn't
"run", if container_tech == "docker":
"--network", args += ["--security-opt=no-new-privileges:true"]
"none",
"--security-opt=no-new-privileges:true", args += [
"-v", "-v",
f"{document_filename}:/tmp/input_file", f"{document_filename}:/tmp/input_file",
"-v", "-v",
@ -83,14 +103,13 @@ def documenttopixels(document_filename, pixel_dir, container_name):
container_name, container_name,
"document-to-pixels", "document-to-pixels",
] ]
) sys.exit(exec_container(args))
)
@container_main.command() @container_main.command()
@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="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(pixel_dir, safe_dir, container_name, ocr, ocr_lang):

View file

@ -384,7 +384,7 @@ class GlobalCommon(object):
if self.custom_container: if self.custom_container:
return self.custom_container return self.custom_container
else: else:
return "flmcode/dangerzone" 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):
@ -439,18 +439,11 @@ class GlobalCommon(object):
return "/usr/bin/dangerzone-container" return "/usr/bin/dangerzone-container"
def exec_dangerzone_container(self, args): def exec_dangerzone_container(self, args):
# Prefix the args with the retainer runtime, and in the case linux when the user isn't in the docker group, pkexec
if platform.system() == "Linux":
if self.settings.get("linux_prefers_typing_password"):
args = ["/usr/bin/pkexec", self.dz_container_path] + args
else:
args = [self.dz_container_path] + args
else:
args = [self.dz_container_path] + args args = [self.dz_container_path] + args
args_str = " ".join(pipes.quote(s) for s in args)
print(Style.DIM + "> " + Style.NORMAL + Fore.CYAN + args_str)
# Execute dangerzone-container # Execute dangerzone-container
args_str = " ".join(pipes.quote(s) for s in args)
print(Fore.YELLOW + "> " + Fore.CYAN + args_str)
return subprocess.Popen( return subprocess.Popen(
args, args,
startupinfo=self.get_subprocess_startupinfo(), startupinfo=self.get_subprocess_startupinfo(),

View file

@ -71,18 +71,6 @@ def gui_main(custom_container, 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)
# If we're using Linux and docker, see if we need to add the user to the docker group or if the user prefers typing their password
if platform.system() == "Linux":
if not gui_common.ensure_docker_group_preference():
return
try:
if not gui_common.ensure_docker_service_is_started():
click.echo("Failed to start docker service")
return
except AuthorizationFailed:
click.echo("Authorization failed")
return
# See if we need to install Docker... # See if we need to install Docker...
if (platform.system() == "Darwin" or platform.system() == "Windows") and ( if (platform.system() == "Darwin" or platform.system() == "Windows") and (
not is_docker_installed() or not is_docker_ready(global_common) not is_docker_installed() or not is_docker_ready(global_common)

View file

@ -142,95 +142,6 @@ class GuiCommon(object):
return pdf_viewers return pdf_viewers
def ensure_docker_group_preference(self):
# If the user prefers typing their password
if self.global_common.settings.get("linux_prefers_typing_password") == True:
return True
# Get the docker group
try:
groupinfo = grp.getgrnam("docker")
except:
# Ignore if group is not found
return True
# See if the user is in the group
username = getpass.getuser()
if username not in groupinfo.gr_mem:
# User is not in the docker group, ask if they prefer typing their password
message = "<b>Dangerzone requires Docker</b><br><br>In order to use Docker, your user must be in the 'docker' group or you'll need to type your password each time you run dangerzone.<br><br><b>Adding your user to the 'docker' group is more convenient but less secure</b>, and will require just typing your password once. Which do you prefer?"
return_code = Alert(
self,
self.global_common,
message,
ok_text="I'll type my password each time",
extra_button_text="Add my user to the 'docker' group",
).launch()
if return_code == QtWidgets.QDialog.Accepted:
# Prefers typing password
self.global_common.settings.set("linux_prefers_typing_password", True)
self.global_common.settings.save()
return True
elif return_code == 2:
# Prefers being in the docker group
self.global_common.settings.set("linux_prefers_typing_password", False)
self.global_common.settings.save()
# Add user to the docker group
p = subprocess.run(
[
"/usr/bin/pkexec",
"/usr/sbin/usermod",
"-a",
"-G",
"docker",
username,
]
)
if p.returncode == 0:
message = "Great! Now you must log out of your computer and log back in, and then you can use Dangerzone."
Alert(self, self.global_common, message).launch()
else:
message = "Failed to add your user to the 'docker' group, quitting."
Alert(self, self.global_common, message).launch()
return False
else:
# Cancel
return False
return True
def ensure_docker_service_is_started(self):
if not is_docker_ready(self.global_common):
message = "<b>Dangerzone requires Docker</b><br><br>Docker should be installed, but it looks like it's not running in the background.<br><br>Click Ok to try starting the docker service. You will have to type your login password."
if (
Alert(self, self.global_common, message).launch()
== QtWidgets.QDialog.Accepted
):
p = subprocess.run(
[
"/usr/bin/pkexec",
self.global_common.get_resource_path(
"enable_docker_service.sh"
),
]
)
if p.returncode == 0:
# Make sure docker is now ready
if is_docker_ready(self.global_common):
return True
else:
message = "Restarting docker appeared to work, but the service still isn't responding, quitting."
Alert(self, self.global_common, message).launch()
else:
message = "Failed to start the docker service, quitting."
Alert(self, self.global_common, message).launch()
return False
return True
class Alert(QtWidgets.QDialog): class Alert(QtWidgets.QDialog):
def __init__( def __init__(

View file

@ -21,7 +21,7 @@ class TaskBase(QtCore.QThread):
if line.startswith(b"> "): if line.startswith(b"> "):
print( print(
Fore.YELLOW + "> " + Fore.LIGHTCYAN_EX + line.decode()[2:], Style.DIM + "> " + Style.NORMAL + Fore.CYAN + line.decode()[2:],
end="", end="",
) )
else: else:

View file

@ -29,7 +29,7 @@ def main():
print("* Building RPM package") print("* Building RPM package")
subprocess.run( subprocess.run(
"python3 setup.py bdist_rpm --requires='python3-pyside2,python3-appdirs,python3-click,python3-pyxdg,python3-requests,python3-colorama,(docker or docker-ce)'", "python3 setup.py bdist_rpm --requires='podman,python3-pyside2,python3-appdirs,python3-click,python3-pyxdg,python3-requests,python3-colorama'",
shell=True, shell=True,
cwd=root, cwd=root,
check=True, check=True,

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
<policyconfig>
<action id="org.freedesktop.policykit.pkexec.dangerzone">
<description>Run Dangerzone Container</description>
<message>Dangerzone needs you to authenticate to run containers</message>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/dangerzone-container</annotate>
</action>
</policyconfig>

View file

@ -34,10 +34,6 @@ setuptools.setup(
["install/linux/media.firstlook.dangerzone.png"], ["install/linux/media.firstlook.dangerzone.png"],
), ),
("share/dangerzone", file_list("share")), ("share/dangerzone", file_list("share")),
(
"share/polkit-1/actions",
["install/linux/media.firstlook.dangerzone-container.policy"],
),
], ],
classifiers=[ classifiers=[
"Programming Language :: Python", "Programming Language :: Python",

View file

@ -1,3 +0,0 @@
#!/bin/sh
/bin/systemctl restart docker.service
/bin/systemctl enable docker.service

View file

@ -1,6 +1,6 @@
[DEFAULT] [DEFAULT]
Package3: dangerzone Package3: dangerzone
Depends3: python3, python3-pyside2.qtcore, python3-pyside2.qtgui, python3-pyside2.qtwidgets, python3-appdirs, python3-click, python3-xdg, python3-requests, python3-colorama Depends3: podman, python3, python3-pyside2.qtcore, python3-pyside2.qtgui, python3-pyside2.qtwidgets, python3-appdirs, python3-click, python3-xdg, python3-requests, python3-colorama
Build-Depends: dh-python, python3, python3-all Build-Depends: dh-python, python3, python3-all
Suite: bionic Suite: bionic
X-Python3-Version: >= 3.6 X-Python3-Version: >= 3.6