mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-28 18:02:38 +02:00
Add Qubes-specific code for disposable VMs
The "document to pixels" code assumes that the client has called it with some mount points in which it can write files. This is true for the container isolation provider, but not for Qubes, who can communicate with the client only via stdin/stdout. Add a Qubes wrapper for this code that reads the suspicious document from stdin and writes the pages to stdout. The on-wire format is the same as the one that TrustedPDF uses.
This commit is contained in:
parent
cfdaec23c5
commit
a83f5dfc7a
1 changed files with 89 additions and 0 deletions
89
dangerzone/conversion/doc_to_pixels_qubes_wrapper.py
Normal file
89
dangerzone/conversion/doc_to_pixels_qubes_wrapper.py
Normal file
|
@ -0,0 +1,89 @@
|
|||
import asyncio
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Optional, TextIO
|
||||
|
||||
from .doc_to_pixels import DocumentToPixels
|
||||
|
||||
|
||||
def _read_bytes() -> bytes:
|
||||
"""Read bytes from the stdin."""
|
||||
data = sys.stdin.buffer.read()
|
||||
if data is None:
|
||||
raise EOFError
|
||||
return data
|
||||
|
||||
|
||||
def _write_bytes(data: bytes, file: TextIO = sys.stdout) -> None:
|
||||
file.buffer.write(data)
|
||||
|
||||
|
||||
def _write_text(text: str, file: TextIO = sys.stdout) -> None:
|
||||
_write_bytes(text.encode(), file=file)
|
||||
|
||||
|
||||
def _write_int(num: int, file: TextIO = sys.stdout) -> None:
|
||||
_write_bytes(num.to_bytes(2, signed=False), file=file)
|
||||
|
||||
|
||||
# ==== ASYNC METHODS ====
|
||||
# We run sync methods in async wrappers, because pure async methods are more difficult:
|
||||
# https://stackoverflow.com/a/52702646
|
||||
#
|
||||
# In practice, because they are I/O bound and we don't have many running concurrently,
|
||||
# they shouldn't cause a problem.
|
||||
|
||||
|
||||
async def read_bytes() -> bytes:
|
||||
return await asyncio.to_thread(_read_bytes)
|
||||
|
||||
|
||||
async def write_bytes(data: bytes, file: TextIO = sys.stdout) -> None:
|
||||
return await asyncio.to_thread(_write_bytes, data, file=file)
|
||||
|
||||
|
||||
async def write_text(text: str, file: TextIO = sys.stdout) -> None:
|
||||
return await asyncio.to_thread(_write_text, text, file=file)
|
||||
|
||||
|
||||
async def write_int(num: int, file: TextIO = sys.stdout) -> None:
|
||||
return await asyncio.to_thread(_write_int, num, file=file)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
out_dir = Path("/tmp/dangerzone")
|
||||
if out_dir.exists():
|
||||
shutil.rmtree(out_dir)
|
||||
out_dir.mkdir()
|
||||
|
||||
try:
|
||||
data = await read_bytes()
|
||||
except EOFError:
|
||||
sys.exit(1)
|
||||
|
||||
with open("/tmp/input_file", "wb") as f:
|
||||
f.write(data)
|
||||
|
||||
converter = DocumentToPixels()
|
||||
await converter.convert()
|
||||
|
||||
num_pages = len(list(out_dir.glob("*.rgb")))
|
||||
await write_int(num_pages)
|
||||
for num_page in range(1, num_pages + 1):
|
||||
page_base = out_dir / f"page-{num_page}"
|
||||
with open(f"{page_base}.width", "r") as width_file:
|
||||
width = int(width_file.read())
|
||||
with open(f"{page_base}.height", "r") as height_file:
|
||||
height = int(height_file.read())
|
||||
await write_int(width)
|
||||
await write_int(height)
|
||||
with open(f"{page_base}.rgb", "rb") as rgb_file:
|
||||
rgb_data = rgb_file.read()
|
||||
await write_bytes(rgb_data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(asyncio.run(main()))
|
Loading…
Reference in a new issue