mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-29 10:12:38 +02:00

Due to a bump in our Python dependencies, we now install Mypy 1.1.1 instead of 0.982. This change triggered the following errors: * Incompatible default for argument <a> (default has type None, argument has type <t>): Mypy further explains here that PEP 484 prohibits implicit Optional, so we need to make these types explicit Optional. * Unused "type: ignore" comment, use narrower [method-assign] instead of [assignment]: Mypy has specialized some of its lints, meaning that we should switch to the newer variants. Also, it detected several other small inconsistencies. We fix all of these errors in this commit.
108 lines
3.5 KiB
Python
108 lines
3.5 KiB
Python
import functools
|
|
import os
|
|
from typing import List, Optional, Tuple
|
|
|
|
import click
|
|
|
|
from . import errors
|
|
from .document import Document
|
|
|
|
|
|
@errors.handle_document_errors
|
|
def _validate_input_filename(
|
|
ctx: click.Context, param: str, value: Optional[str]
|
|
) -> Optional[str]:
|
|
if value is None:
|
|
return None
|
|
filename = Document.normalize_filename(value)
|
|
Document.validate_input_filename(filename)
|
|
return filename
|
|
|
|
|
|
@errors.handle_document_errors
|
|
def _validate_input_filenames(
|
|
ctx: click.Context, param: List[str], value: Tuple[str]
|
|
) -> List[str]:
|
|
normalized_filenames = []
|
|
for filename in value:
|
|
filename = Document.normalize_filename(filename)
|
|
Document.validate_input_filename(filename)
|
|
normalized_filenames.append(filename)
|
|
return normalized_filenames
|
|
|
|
|
|
@errors.handle_document_errors
|
|
def _validate_output_filename(
|
|
ctx: click.Context, param: str, value: Optional[str]
|
|
) -> Optional[str]:
|
|
if value is None:
|
|
return None
|
|
filename = Document.normalize_filename(value)
|
|
Document.validate_output_filename(filename)
|
|
return filename
|
|
|
|
|
|
# XXX: Click versions 7.x and below inspect the number of arguments that the
|
|
# callback handler supports. Unfortunately, common Python decorators (such as
|
|
# `handle_document_errors()`) mask this number, so we need to reinstate it
|
|
# somehow [1]. The simplest way to do so is using a wrapper function.
|
|
#
|
|
# Once we stop supporting Click 7.x, we can remove the wrappers below.
|
|
#
|
|
# [1]: https://github.com/freedomofpress/dangerzone/issues/206#issuecomment-1297336863
|
|
def validate_input_filename(
|
|
ctx: click.Context, param: str, value: Optional[str]
|
|
) -> Optional[str]:
|
|
return _validate_input_filename(ctx, param, value)
|
|
|
|
|
|
def validate_input_filenames(
|
|
ctx: click.Context, param: List[str], value: Tuple[str]
|
|
) -> List[str]:
|
|
return _validate_input_filenames(ctx, param, value)
|
|
|
|
|
|
def validate_output_filename(
|
|
ctx: click.Context, param: str, value: Optional[str]
|
|
) -> Optional[str]:
|
|
return _validate_output_filename(ctx, param, value)
|
|
|
|
|
|
def check_suspicious_options(args: List[str]) -> None:
|
|
options = set([arg for arg in args if arg.startswith("-")])
|
|
try:
|
|
files = set(os.listdir())
|
|
except Exception:
|
|
# If we can list files in the current working directory, this means that
|
|
# we're probably in an unlinked directory. Dangerzone should still work in
|
|
# this case, so we should return here.
|
|
return
|
|
|
|
intersection = options & files
|
|
if intersection:
|
|
filenames_str = ", ".join(intersection)
|
|
msg = (
|
|
f"Security: Detected CLI options that are also present as files in the"
|
|
f" current working directory: {filenames_str}"
|
|
)
|
|
click.echo(msg)
|
|
exit(1)
|
|
|
|
|
|
def override_parser_and_check_suspicious_options(click_main: click.Command) -> None:
|
|
"""Override the argument parsing logic of Click.
|
|
|
|
Click does not allow us to have access to the raw arguments that it receives (either
|
|
from sys.argv or from its testing module). To circumvent this, we can override its
|
|
`Command.parse_args()` method, which is public and should be safe to do so.
|
|
|
|
We can use it to check for any suspicious options prior to arg parsing.
|
|
"""
|
|
orig_parse_fn = click_main.parse_args
|
|
|
|
@functools.wraps(orig_parse_fn)
|
|
def custom_parse_fn(ctx: click.Context, args: List[str]) -> List[str]:
|
|
check_suspicious_options(args)
|
|
return orig_parse_fn(ctx, args)
|
|
|
|
click_main.parse_args = custom_parse_fn # type: ignore [method-assign]
|