forked from p15670423/monkey
Merge pull request #2037 from guardicore/repository-errors
Repository errors
This commit is contained in:
commit
05abc22ac0
|
@ -1,4 +1,4 @@
|
||||||
from .errors import RetrievalError
|
from .errors import RemovalError, RetrievalError, StorageError
|
||||||
from .file_storage import FileNotFoundError, IFileRepository, LocalStorageFileRepository
|
from .file_storage import FileNotFoundError, IFileRepository, LocalStorageFileRepository
|
||||||
from .i_agent_binary_repository import IAgentBinaryRepository
|
from .i_agent_binary_repository import IAgentBinaryRepository
|
||||||
from .agent_binary_repository import AgentBinaryRepository
|
from .agent_binary_repository import AgentBinaryRepository
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
class RemovalError(RuntimeError):
|
||||||
|
"""
|
||||||
|
Raised when a repository encounters an error while attempting to remove data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RetrievalError(RuntimeError):
|
class RetrievalError(RuntimeError):
|
||||||
"""
|
"""
|
||||||
Raised when a repository encounters an error while attempting to retrieve data.
|
Raised when a repository encounters an error while attempting to retrieve data.
|
||||||
|
|
|
@ -20,6 +20,7 @@ class IFileRepository(metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
:param unsafe_file_name: An unsanitized file name that will identify the file
|
:param unsafe_file_name: An unsanitized file name that will identify the file
|
||||||
:param file_contents: The data to be stored in the file
|
:param file_contents: The data to be stored in the file
|
||||||
|
:raises StorageError: If an error was encountered while attempting to store the file
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ class IFileRepository(metaclass=abc.ABCMeta):
|
||||||
idempotent and will succeed if the file to be deleted does not exist.
|
idempotent and will succeed if the file to be deleted does not exist.
|
||||||
|
|
||||||
:param unsafe_file_name: An unsanitized file name that identifies the file to be deleted
|
:param unsafe_file_name: An unsanitized file name that identifies the file to be deleted
|
||||||
|
:raises RemovalError: If an error was encountered while attempting to remove a file
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -51,5 +53,7 @@ class IFileRepository(metaclass=abc.ABCMeta):
|
||||||
def delete_all_files(self):
|
def delete_all_files(self):
|
||||||
"""
|
"""
|
||||||
Delete all files that have been stored using this service.
|
Delete all files that have been stored using this service.
|
||||||
|
|
||||||
|
:raises RemovalError: If an error was encountered while attempting to remove a file
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -4,7 +4,7 @@ from pathlib import Path
|
||||||
from typing import BinaryIO
|
from typing import BinaryIO
|
||||||
|
|
||||||
from common.utils.file_utils import get_all_regular_files_in_directory
|
from common.utils.file_utils import get_all_regular_files_in_directory
|
||||||
from monkey_island.cc.repository import RetrievalError
|
from monkey_island.cc.repository import RemovalError, RetrievalError, StorageError
|
||||||
from monkey_island.cc.server_utils.file_utils import create_secure_directory
|
from monkey_island.cc.server_utils.file_utils import create_secure_directory
|
||||||
|
|
||||||
from . import IFileRepository, i_file_repository
|
from . import IFileRepository, i_file_repository
|
||||||
|
@ -32,16 +32,19 @@ class LocalStorageFileRepository(IFileRepository):
|
||||||
self._storage_directory = storage_directory
|
self._storage_directory = storage_directory
|
||||||
|
|
||||||
def save_file(self, unsafe_file_name: str, file_contents: BinaryIO):
|
def save_file(self, unsafe_file_name: str, file_contents: BinaryIO):
|
||||||
safe_file_path = self._get_safe_file_path(unsafe_file_name)
|
try:
|
||||||
|
safe_file_path = self._get_safe_file_path(unsafe_file_name)
|
||||||
|
|
||||||
logger.debug(f"Saving file contents to {safe_file_path}")
|
logger.debug(f"Saving file contents to {safe_file_path}")
|
||||||
with open(safe_file_path, "wb") as dest:
|
with open(safe_file_path, "wb") as dest:
|
||||||
shutil.copyfileobj(file_contents, dest)
|
shutil.copyfileobj(file_contents, dest)
|
||||||
|
except Exception as err:
|
||||||
|
raise StorageError(f"Error while attempting to store {unsafe_file_name}: {err}")
|
||||||
|
|
||||||
def open_file(self, unsafe_file_name: str) -> BinaryIO:
|
def open_file(self, unsafe_file_name: str) -> BinaryIO:
|
||||||
safe_file_path = self._get_safe_file_path(unsafe_file_name)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
safe_file_path = self._get_safe_file_path(unsafe_file_name)
|
||||||
|
|
||||||
logger.debug(f"Opening {safe_file_path}")
|
logger.debug(f"Opening {safe_file_path}")
|
||||||
return open(safe_file_path, "rb")
|
return open(safe_file_path, "rb")
|
||||||
except FileNotFoundError as err:
|
except FileNotFoundError as err:
|
||||||
|
@ -55,14 +58,16 @@ class LocalStorageFileRepository(IFileRepository):
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete_file(self, unsafe_file_name: str):
|
def delete_file(self, unsafe_file_name: str):
|
||||||
safe_file_path = self._get_safe_file_path(unsafe_file_name)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
safe_file_path = self._get_safe_file_path(unsafe_file_name)
|
||||||
|
|
||||||
logger.debug(f"Deleting {safe_file_path}")
|
logger.debug(f"Deleting {safe_file_path}")
|
||||||
safe_file_path.unlink()
|
safe_file_path.unlink()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
# This method is idempotent.
|
# This method is idempotent.
|
||||||
pass
|
pass
|
||||||
|
except Exception as err:
|
||||||
|
raise RemovalError(f"Error while attempting to remove {unsafe_file_name}: {err}")
|
||||||
|
|
||||||
def _get_safe_file_path(self, unsafe_file_name: str):
|
def _get_safe_file_path(self, unsafe_file_name: str):
|
||||||
# Remove any path information from the file name.
|
# Remove any path information from the file name.
|
||||||
|
@ -71,12 +76,17 @@ class LocalStorageFileRepository(IFileRepository):
|
||||||
|
|
||||||
# This is a paranoid check to avoid directory traversal attacks.
|
# This is a paranoid check to avoid directory traversal attacks.
|
||||||
if self._storage_directory.resolve() not in safe_file_path.parents:
|
if self._storage_directory.resolve() not in safe_file_path.parents:
|
||||||
raise ValueError(f"The file named {unsafe_file_name} can not be safely retrieved")
|
raise ValueError(
|
||||||
|
f'The file named "{unsafe_file_name}" cannot be safely retrieved or written'
|
||||||
|
)
|
||||||
|
|
||||||
logger.debug(f"Untrusted file name {unsafe_file_name} sanitized: {safe_file_path}")
|
logger.debug(f"Untrusted file name {unsafe_file_name} sanitized: {safe_file_path}")
|
||||||
return safe_file_path
|
return safe_file_path
|
||||||
|
|
||||||
def delete_all_files(self):
|
def delete_all_files(self):
|
||||||
for file in get_all_regular_files_in_directory(self._storage_directory):
|
try:
|
||||||
logger.debug(f"Deleting {file}")
|
for file in get_all_regular_files_in_directory(self._storage_directory):
|
||||||
file.unlink()
|
logger.debug(f"Deleting {file}")
|
||||||
|
file.unlink()
|
||||||
|
except Exception as err:
|
||||||
|
raise RemovalError(f"Error while attempting to clear the repository: {err}")
|
||||||
|
|
Loading…
Reference in New Issue