dangerzone/dangerzone/errors.py

146 lines
4.3 KiB
Python

import functools
import logging
import sys
from typing import Any, Callable, TypeVar, cast
import click
F = TypeVar("F", bound=Callable[..., Any])
log = logging.getLogger(__name__)
class DocumentFilenameException(Exception):
"""Exception for document-related filename errors."""
class AddedDuplicateDocumentException(DocumentFilenameException):
"""Exception for a document is added twice."""
def __init__(self) -> None:
super().__init__("A document was added twice")
class InputFileNotFoundException(DocumentFilenameException):
"""Exception for when an input file does not exist."""
def __init__(self) -> None:
super().__init__("Input file not found: make sure you typed it correctly.")
class InputFileNotReadableException(DocumentFilenameException):
"""Exception for when an input file exists but is not readable."""
def __init__(self) -> None:
super().__init__("You don't have permission to open the input file.")
class NonPDFOutputFileException(DocumentFilenameException):
"""Exception for when the output file is not a PDF."""
def __init__(self) -> None:
super().__init__("Safe PDF filename must end in '.pdf'")
class IllegalOutputFilenameException(DocumentFilenameException):
"""Exception for when the output file contains illegal characters."""
def __init__(self, char: str) -> None:
super().__init__(f"Illegal character: {char}")
class UnwriteableOutputDirException(DocumentFilenameException):
"""Exception for when the output file is not writeable."""
def __init__(self) -> None:
super().__init__("Safe PDF filename is not writable")
class NotSetInputFilenameException(DocumentFilenameException):
"""Exception for when the output filename is set before having an
associated input file."""
def __init__(self) -> None:
super().__init__("Input filename has not been set yet.")
class NotSetOutputFilenameException(DocumentFilenameException):
"""Exception for when the output filename is read before it has been set."""
def __init__(self) -> None:
super().__init__("Output filename has not been set yet.")
class NonExistantOutputDirException(DocumentFilenameException):
"""Exception for when the output dir does not exist."""
def __init__(self) -> None:
super().__init__("Output directory does not exist")
class OutputDirIsNotDirException(DocumentFilenameException):
"""Exception for when the specified output dir is not actually a dir."""
def __init__(self) -> None:
super().__init__("Specified output directory is actually not a directory")
class UnwriteableArchiveDirException(DocumentFilenameException):
"""Exception for when the archive directory cannot be created."""
def __init__(self) -> None:
super().__init__(
"Archive directory for storing unsafe documents cannot be created."
)
class SuffixNotApplicableException(DocumentFilenameException):
"""Exception for when the suffix cannot be applied to the output filename."""
def __init__(self) -> None:
super().__init__("Cannot set a suffix after setting an output filename")
def handle_document_errors(func: F) -> F:
"""Decorator to log document-related errors and exit gracefully."""
@functools.wraps(func)
def wrapper(*args, **kwargs): # type: ignore
try:
return func(*args, **kwargs)
except DocumentFilenameException as e:
if getattr(sys, "dangerzone_dev", False):
# Show the full traceback only on dev environments.
msg = "An exception occured while validating a document"
log.exception(msg)
click.echo(str(e))
sys.exit(1)
return cast(F, wrapper)
#### Container-related errors
class ImageNotPresentException(Exception):
pass
class ImageInstallationException(Exception):
pass
class NoContainerTechException(Exception):
def __init__(self, container_tech: str) -> None:
super().__init__(f"{container_tech} is not installed")
class NotAvailableContainerTechException(Exception):
def __init__(self, container_tech: str, error: str) -> None:
self.error = error
self.container_tech = container_tech
super().__init__(f"{container_tech} is not available")
class UnsupportedContainerRuntime(Exception):
pass