From c070eaa526482ce22f28d4ec97b043e77840622c Mon Sep 17 00:00:00 2001 From: deeplow Date: Fri, 13 Dec 2024 21:28:03 +0000 Subject: [PATCH] Initial support for IPP / driverless printing Changes export logic (in sd-devices) to be able to detect IPP printers without breaking compatibility with the old system. To achive this, ipp-usb is used in combination with Avahi. The former detects IPP-compatible printers and creates a local IPP server. Avahi allows for the discovery of these printing servers such that print dialogs can display print information. Contrary to the legacy printer support, for driverless printing, no print queue is setup with `lpadmin`. Printers are automatically discovered. --- debian/control | 3 +- debian/securedrop-export.install | 1 + export/files/60-securedrop-export.preset | 4 ++ export/securedrop_export/print/service.py | 58 +++++++++++++++++------ 4 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 export/files/60-securedrop-export.preset diff --git a/debian/control b/debian/control index 3a5f69fc8..03ecfff7c 100644 --- a/debian/control +++ b/debian/control @@ -14,7 +14,8 @@ Description: securedrop client for qubes workstation Package: securedrop-export Architecture: all -Depends: ${misc:Depends}, python3, udisks2, cups, printer-driver-brlaser, printer-driver-hpcups, system-config-printer, xpp, libcups2, gnome-disk-utility, libreoffice, +Depends: ${misc:Depends}, python3, udisks2, cups, cups-ipp-utils, printer-driver-brlaser, printer-driver-hpcups, + avahi-daemon, system-config-printer, xpp, libcups2, gnome-disk-utility, libreoffice, desktop-file-utils, shared-mime-info, libfile-mimeinfo-perl Description: Submission export scripts for SecureDrop Workstation This package provides scripts used by the SecureDrop Qubes Workstation to diff --git a/debian/securedrop-export.install b/debian/securedrop-export.install index b095f316f..1c2df926e 100644 --- a/debian/securedrop-export.install +++ b/debian/securedrop-export.install @@ -2,3 +2,4 @@ export/files/application-x-sd-export.xml usr/share/mime/packages export/files/send-to-usb.desktop usr/share/applications export/files/sd-logo.png usr/share/securedrop/icons export/files/tcrypt.conf etc/udisks2 +export/files/60-securedrop-export.preset usr/lib/systemd/system-preset diff --git a/export/files/60-securedrop-export.preset b/export/files/60-securedrop-export.preset new file mode 100644 index 000000000..7535e5b04 --- /dev/null +++ b/export/files/60-securedrop-export.preset @@ -0,0 +1,4 @@ +# avahi-daemon so that driverless printers are detected when +# plugged in via USB, overriding 75-qubes-vm.preset + +enable avahi-daemon.service \ No newline at end of file diff --git a/export/securedrop_export/print/service.py b/export/securedrop_export/print/service.py index 830820349..bab59e623 100644 --- a/export/securedrop_export/print/service.py +++ b/export/securedrop_export/print/service.py @@ -143,32 +143,59 @@ def _check_printer_setup(self) -> None: Check printer setup. Raise ExportException if supported setup is not found. """ + legacy_printers=False try: logger.info("Searching for printer") - output = subprocess.check_output(["sudo", "lpinfo", "-v"]) - printers = [x for x in output.decode("utf-8").split() if "usb://" in x] + + printers = self._get_printers_ipp() if not printers: - logger.info("No usb printers connected") - raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_FOUND) + # look for legacy printers after no IPP ones are detected + printers = self._get_printers_legacy() + legacy_printers=True - supported_printers = [ - p for p in printers if any(sub in p for sub in self.SUPPORTED_PRINTERS) - ] - if not supported_printers: - logger.info(f"{printers} are unsupported printers") - raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_SUPPORTED) + if not printers: + logger.info("No supported printers connected") + raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_FOUND) - if len(supported_printers) > 1: - logger.info("Too many usb printers connected") + if len(printers) > 1: + logger.info("Too many printers connected") raise ExportException(sdstatus=Status.ERROR_MULTIPLE_PRINTERS_FOUND) printer_uri = printers[0] - printer_ppd = self._install_printer_ppd(printer_uri) - self._setup_printer(printer_uri, printer_ppd) + if legacy_printers: # IPP printers are auto-detected by the print dialog + self._setup_printer(printer_uri) except subprocess.CalledProcessError as e: logger.error(e) raise ExportException(sdstatus=Status.ERROR_UNKNOWN) + def _get_printers_legacy(self) -> list[str]: + logger.info("Searching for legacy printers") + output = subprocess.check_output(["sudo", "lpinfo", "-v"]) + discovered_printers = [x for x in output.decode("utf-8").split() if "usb://" in x] + + supported_printers = [ + p for p in discovered_printers if any(sub in p for sub in self.SUPPORTED_PRINTERS) + ] + if not supported_printers: + logger.info(f"{discovered_printers} are unsupported printers") + raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_SUPPORTED) + + return supported_printers + + def _get_printers_ipp(self) -> list[str]: + logger.info("Searching for IPP printers (driverless)") + discovered_printers = subprocess.check_output( + ["ippfind"], + universal_newlines=True + ).split() + + if discovered_printers: + logger.debug(f"Found IPP printers: {', '.join(discovered_printers)}") + else: + logger.debug(f"No IPP were found") + + return discovered_printers + def _get_printer_uri(self) -> str: """ Get the URI via lpinfo. Only accept URIs of supported printers. @@ -202,6 +229,9 @@ def _get_printer_uri(self) -> str: return printer_uri def _install_printer_ppd(self, uri): + """ + Discovery and installation of PPD driver (for legacy printers) + """ if not any(x in uri for x in self.SUPPORTED_PRINTERS): logger.error(f"Cannot install printer ppd for unsupported printer: {uri}") raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_SUPPORTED)