workstation-config/securedrop-mime-handling.py (51 lines of code) (raw):
#!/usr/bin/python3
##
# securedrop-mime-handling
# =====================
#
# Overrides mimetype handling for certain VMs. Instead of relying on the
# /usr/share/applications (system volume), we instead use /home/user/.local/share/
# to be provisioned on boot by systemd.
##
import logging
import logging.handlers
import sys
from pathlib import Path
from qubesdb import QubesDB
# Configure logging
syslog_handler = logging.handlers.SysLogHandler(address="/dev/log")
stdout_handler = logging.StreamHandler(sys.stdout)
logging.basicConfig(level=logging.INFO, handlers=[syslog_handler, stdout_handler])
logger = logging.getLogger()
def create_symlink_strict(source_path_str, target_path_str, overwrite_expected=False):
"""
Creates a symlink, but warning when idempotence is required and failing if
link source already exsits.
"""
source_path = Path(source_path_str)
target_path = Path(target_path_str)
target_path.resolve(strict=True) # raise exception if does not exist
try:
source_path.symlink_to(target_path)
except FileExistsError as e:
if source_path.is_symlink():
if source_path.readlink() == target_path:
if not overwrite_expected:
# Harmless situation, yet not ideal (idempotency required)
logger.warning(f"'{source_path}' existed already (unexpected)")
else:
logger.error(f"'{source_path}' existed already and is linked to the wrong file")
raise e
else:
logger.error(f"'{source_path}' existed already")
raise e
def get_mime_handling():
mime_handling = QubesDB().read("/vm-config/SD_MIME_HANDLING")
if mime_handling is None or len(mime_handling) == 0:
raise RuntimeError("'SD_MIME_HANDLING' qubesdb vm-config is not set")
return mime_handling.decode()
def main():
# Should fail on DVM templates to avoid tainting the disposables' home.
# In practice we cannot detect this from within, so we have to hard-code
# sd-app as the only valid non-disposable.
persistent_home = QubesDB().read("/qubes-vm-persistence").decode() != "none"
vm_name = QubesDB().read("/name").decode()
if persistent_home and vm_name != "sd-app":
sys.exit(1)
# Ensure applications open with the correct tool (or disposable qube)
mime_handling = get_mime_handling()
mimeapps_override_path = Path(f"/opt/sdw/mimeapps.list.{mime_handling}")
mimeapps_override_path.resolve(strict=True)
user_apps_dir_path = Path("/home/user/.local/share/applications")
user_apps_dir_path.mkdir(mode=0o755, parents=True, exist_ok=True)
create_symlink_strict(
user_apps_dir_path / "mimeapps.list",
mimeapps_override_path,
overwrite_expected=persistent_home,
)
# Fallback mechanism if MIME type lookup fails in tools like xdg-open
create_symlink_strict(
"/home/user/.mailcap", "/opt/sdw/mailcap.default", overwrite_expected=persistent_home
)
if __name__ == "__main__":
main()