Compare commits

..

No commits in common. "02602b072aee619cda7cda647f0be44263f959d9" and "1298e9c3981d160d63a5992ba97521c644b1cbd5" have entirely different histories.

6 changed files with 22 additions and 72 deletions

View file

@ -53,13 +53,8 @@ jobs:
gpg --keyserver hkps://keys.openpgp.org \ gpg --keyserver hkps://keys.openpgp.org \
--no-default-keyring --keyring ./fpf-apt-tools-archive-keyring.gpg \ --no-default-keyring --keyring ./fpf-apt-tools-archive-keyring.gpg \
--recv-keys "DE28 AB24 1FA4 8260 FAC9 B8BA A7C9 B385 2260 4281" --recv-keys "DE28 AB24 1FA4 8260 FAC9 B8BA A7C9 B385 2260 4281"
# Export the GPG key in armor mode because sequoia needs it this way
# (sqv is used on debian trixie by default to check the keys)
mkdir -p /etc/apt/keyrings/ mkdir -p /etc/apt/keyrings/
gpg --no-default-keyring --keyring ./fpf-apt-tools-archive-keyring.gpg \ mv fpf-apt-tools-archive-keyring.gpg /etc/apt/keyrings
--armor --export "DE28 AB24 1FA4 8260 FAC9 B8BA A7C9 B385 2260 4281" \
> /etc/apt/keyrings/fpf-apt-tools-archive-keyring.gpg
- name: Add packages.freedom.press to our APT sources - name: Add packages.freedom.press to our APT sources
run: | run: |

View file

@ -94,9 +94,7 @@ gpg --keyserver hkps://keys.openpgp.org \
--no-default-keyring --keyring ./fpf-apt-tools-archive-keyring.gpg \ --no-default-keyring --keyring ./fpf-apt-tools-archive-keyring.gpg \
--recv-keys "DE28 AB24 1FA4 8260 FAC9 B8BA A7C9 B385 2260 4281" --recv-keys "DE28 AB24 1FA4 8260 FAC9 B8BA A7C9 B385 2260 4281"
sudo mkdir -p /etc/apt/keyrings/ sudo mkdir -p /etc/apt/keyrings/
sudo gpg --no-default-keyring --keyring ./fpf-apt-tools-archive-keyring.gpg \ sudo mv fpf-apt-tools-archive-keyring.gpg /etc/apt/keyrings
--armor --export "DE28 AB24 1FA4 8260 FAC9 B8BA A7C9 B385 2260 4281" \
> /etc/apt/keyrings/fpf-apt-tools-archive-keyring.gpg
``` ```
Add the URL of the repo in your APT sources: Add the URL of the repo in your APT sources:

View file

@ -42,12 +42,6 @@ def print_header(s: str) -> None:
type=click.UNPROCESSED, type=click.UNPROCESSED,
callback=args.validate_input_filenames, callback=args.validate_input_filenames,
) )
@click.option(
"--debug",
"debug",
flag_value=True,
help="Run Dangerzone in debug mode, to get logs from gVisor.",
)
@click.version_option(version=get_version(), message="%(version)s") @click.version_option(version=get_version(), message="%(version)s")
@errors.handle_document_errors @errors.handle_document_errors
def cli_main( def cli_main(
@ -56,7 +50,6 @@ def cli_main(
filenames: List[str], filenames: List[str],
archive: bool, archive: bool,
dummy_conversion: bool, dummy_conversion: bool,
debug: bool,
) -> None: ) -> None:
setup_logging() setup_logging()
@ -65,7 +58,7 @@ def cli_main(
elif is_qubes_native_conversion(): elif is_qubes_native_conversion():
dangerzone = DangerzoneCore(Qubes()) dangerzone = DangerzoneCore(Qubes())
else: else:
dangerzone = DangerzoneCore(Container(debug=debug)) dangerzone = DangerzoneCore(Container())
display_banner() display_banner()
if len(filenames) == 1 and output_filename: if len(filenames) == 1 and output_filename:

View file

@ -5,9 +5,7 @@ import platform
import signal import signal
import subprocess import subprocess
import sys import sys
import threading
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from io import BytesIO
from typing import IO, Callable, Iterator, Optional from typing import IO, Callable, Iterator, Optional
import fitz import fitz
@ -20,6 +18,10 @@ from ..util import get_tessdata_dir, replace_control_chars
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
MAX_CONVERSION_LOG_CHARS = 150 * 50 # up to ~150 lines of 50 characters
DOC_TO_PIXELS_LOG_START = "----- DOC TO PIXELS LOG START -----"
DOC_TO_PIXELS_LOG_END = "----- DOC TO PIXELS LOG END -----"
TIMEOUT_EXCEPTION = 15 TIMEOUT_EXCEPTION = 15
TIMEOUT_GRACE = 15 TIMEOUT_GRACE = 15
TIMEOUT_FORCE = 5 TIMEOUT_FORCE = 5
@ -73,9 +75,9 @@ def read_int(f: IO[bytes]) -> int:
return int.from_bytes(untrusted_int, "big", signed=False) return int.from_bytes(untrusted_int, "big", signed=False)
def sanitize_debug_text(text: bytes) -> str: def read_debug_text(f: IO[bytes], size: int) -> str:
"""Read all the buffer and return a sanitized version""" """Read arbitrarily long text (for debug purposes), and sanitize it."""
untrusted_text = text.decode("ascii", errors="replace") untrusted_text = f.read(size).decode("ascii", errors="replace")
return replace_control_chars(untrusted_text, keep_newlines=True) return replace_control_chars(untrusted_text, keep_newlines=True)
@ -84,16 +86,12 @@ class IsolationProvider(ABC):
Abstracts an isolation provider Abstracts an isolation provider
""" """
def __init__(self, debug: bool = False) -> None: def __init__(self) -> None:
self.debug = debug if getattr(sys, "dangerzone_dev", False) is True:
if self.should_capture_stderr():
self.proc_stderr = subprocess.PIPE self.proc_stderr = subprocess.PIPE
else: else:
self.proc_stderr = subprocess.DEVNULL self.proc_stderr = subprocess.DEVNULL
def should_capture_stderr(self) -> bool:
return self.debug or getattr(sys, "dangerzone_dev", False)
@abstractmethod @abstractmethod
def install(self) -> bool: def install(self) -> bool:
pass pass
@ -329,11 +327,7 @@ class IsolationProvider(ABC):
timeout_force: int = TIMEOUT_FORCE, timeout_force: int = TIMEOUT_FORCE,
) -> Iterator[subprocess.Popen]: ) -> Iterator[subprocess.Popen]:
"""Start a conversion process, pass it to the caller, and then clean it up.""" """Start a conversion process, pass it to the caller, and then clean it up."""
# Store the proc stderr in memory
stderr = BytesIO()
p = self.start_doc_to_pixels_proc(document) p = self.start_doc_to_pixels_proc(document)
stderr_thread = self.start_stderr_thread(p, stderr)
if platform.system() != "Windows": if platform.system() != "Windows":
assert os.getpgid(p.pid) != os.getpgid( assert os.getpgid(p.pid) != os.getpgid(
os.getpid() os.getpid()
@ -349,40 +343,15 @@ class IsolationProvider(ABC):
document, p, timeout_grace=timeout_grace, timeout_force=timeout_force document, p, timeout_grace=timeout_grace, timeout_force=timeout_force
) )
if stderr_thread: # Read the stderr of the process only if:
# Wait for the thread to complete. If it's still alive, mention it in the debug log. # * Dev mode is enabled.
stderr_thread.join(timeout=1) # * The process has exited (else we risk hanging).
if getattr(sys, "dangerzone_dev", False) and p.poll() is not None:
debug_bytes = stderr.getvalue() assert p.stderr
debug_log = sanitize_debug_text(debug_bytes) debug_log = read_debug_text(p.stderr, MAX_CONVERSION_LOG_CHARS)
incomplete = "(incomplete) " if stderr_thread.is_alive() else ""
log.info( log.info(
"Conversion output (doc to pixels)\n" "Conversion output (doc to pixels)\n"
f"----- DOC TO PIXELS LOG START {incomplete}-----\n" f"{DOC_TO_PIXELS_LOG_START}\n"
f"{debug_log}" # no need for an extra newline here f"{debug_log}" # no need for an extra newline here
"----- DOC TO PIXELS LOG END -----" f"{DOC_TO_PIXELS_LOG_END}"
) )
def start_stderr_thread(
self, process: subprocess.Popen, stderr: IO[bytes]
) -> Optional[threading.Thread]:
"""Start a thread to read stderr from the process"""
def _stream_stderr(process_stderr: IO[bytes]) -> None:
try:
for line in process_stderr:
stderr.write(line)
except (ValueError, IOError) as e:
log.debug(f"Stderr stream closed: {e}")
if process.stderr:
stderr_thread = threading.Thread(
target=_stream_stderr,
args=(process.stderr,),
daemon=True,
)
stderr_thread.start()
return stderr_thread
return None

View file

@ -168,10 +168,6 @@ class Container(IsolationProvider):
) -> subprocess.Popen: ) -> subprocess.Popen:
container_runtime = container_utils.get_runtime() container_runtime = container_utils.get_runtime()
security_args = self.get_runtime_security_args() security_args = self.get_runtime_security_args()
debug_args = []
if self.debug:
debug_args += ["-e", "RUNSC_DEBUG=1"]
enable_stdin = ["-i"] enable_stdin = ["-i"]
set_name = ["--name", name] set_name = ["--name", name]
prevent_leakage_args = ["--rm"] prevent_leakage_args = ["--rm"]
@ -181,14 +177,14 @@ class Container(IsolationProvider):
args = ( args = (
["run"] ["run"]
+ security_args + security_args
+ debug_args
+ prevent_leakage_args + prevent_leakage_args
+ enable_stdin + enable_stdin
+ set_name + set_name
+ image_name + image_name
+ command + command
) )
return self.exec([container_runtime] + args) args = [container_runtime] + args
return self.exec(args)
def kill_container(self, name: str) -> None: def kill_container(self, name: str) -> None:
"""Terminate a spawned container. """Terminate a spawned container.

View file

@ -71,7 +71,6 @@ class DangerzoneCore(object):
ocr_lang, ocr_lang,
stdout_callback, stdout_callback,
) )
except Exception: except Exception:
log.exception( log.exception(
f"Unexpected error occurred while converting '{document}'" f"Unexpected error occurred while converting '{document}'"