From c00249fc17600315ca0025164c5d8bf469e49b79 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sat, 2 Jul 2022 09:38:28 -0400 Subject: [PATCH 01/14] Island: Change FileNotFoundError import in LocalStorageFileRepository --- .../cc/repository/local_storage_file_repository.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/repository/local_storage_file_repository.py b/monkey/monkey_island/cc/repository/local_storage_file_repository.py index 4c7662b0c..cf0444abe 100644 --- a/monkey/monkey_island/cc/repository/local_storage_file_repository.py +++ b/monkey/monkey_island/cc/repository/local_storage_file_repository.py @@ -4,10 +4,11 @@ from pathlib import Path from typing import BinaryIO from common.utils.file_utils import get_all_regular_files_in_directory +from monkey_island.cc import repository from monkey_island.cc.repository import RemovalError, RetrievalError, StorageError from monkey_island.cc.server_utils.file_utils import create_secure_directory -from . import IFileRepository, i_file_repository +from . import IFileRepository logger = logging.getLogger(__name__) @@ -49,7 +50,7 @@ class LocalStorageFileRepository(IFileRepository): return open(safe_file_path, "rb") except FileNotFoundError as err: # Wrap Python's FileNotFound error, which is-an OSError, in repository.FileNotFoundError - raise i_file_repository.FileNotFoundError( + raise repository.FileNotFoundError( f'The requested file "{unsafe_file_name}" does not exist: {err}' ) except Exception as err: From bc0c4a1c8e697b1e27dee331fd72a4302f87b633 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sat, 2 Jul 2022 09:49:12 -0400 Subject: [PATCH 02/14] Island: Add FileRepositoryLoggingDecorator --- .../monkey_island/cc/repository/__init__.py | 1 + .../file_repository_logging_decorator.py | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 monkey/monkey_island/cc/repository/file_repository_logging_decorator.py diff --git a/monkey/monkey_island/cc/repository/__init__.py b/monkey/monkey_island/cc/repository/__init__.py index 153d57e27..3b18883c2 100644 --- a/monkey/monkey_island/cc/repository/__init__.py +++ b/monkey/monkey_island/cc/repository/__init__.py @@ -1,6 +1,7 @@ from .errors import RemovalError, RetrievalError, StorageError from .i_file_repository import FileNotFoundError, IFileRepository from .local_storage_file_repository import LocalStorageFileRepository +from .file_repository_logging_decorator import FileRepositoryLoggingDecorator from .i_agent_binary_repository import IAgentBinaryRepository from .agent_binary_repository import AgentBinaryRepository from .i_agent_configuration_repository import IAgentConfigurationRepository diff --git a/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py b/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py new file mode 100644 index 000000000..47ba16ca1 --- /dev/null +++ b/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py @@ -0,0 +1,31 @@ +import logging +from typing import BinaryIO + +from . import IFileRepository + +logger = logging.getLogger(__name__) + + +class FileRepositoryLoggingDecorator(IFileRepository): + def __init__(self, file_repository: IFileRepository): + self._file_repository = file_repository + + def save_file(self, unsafe_file_name: str, file_contents: BinaryIO): + logger.info(f"Saving file {unsafe_file_name}") + + return self._file_repository.save_file(unsafe_file_name, file_contents) + + def open_file(self, unsafe_file_name: str) -> BinaryIO: + logger.info(f"Opening file {unsafe_file_name}") + + return self._file_repository.open_file(unsafe_file_name) + + def delete_file(self, unsafe_file_name: str): + logger.info(f"Deleting file {unsafe_file_name}") + + return self._file_repository.delete_file(unsafe_file_name) + + def delete_all_files(self): + logger.info("Deleting all files in the repository") + + return self._file_repository.delete_all_files() From e3b5e0c01aebe68493253a9988d8b0b97b5ee07f Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sat, 2 Jul 2022 09:53:18 -0400 Subject: [PATCH 03/14] Island: Add FileRepositoryLockingDecorator --- .../monkey_island/cc/repository/__init__.py | 1 + .../file_repository_locking_decorator.py | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 monkey/monkey_island/cc/repository/file_repository_locking_decorator.py diff --git a/monkey/monkey_island/cc/repository/__init__.py b/monkey/monkey_island/cc/repository/__init__.py index 3b18883c2..6f683cc1a 100644 --- a/monkey/monkey_island/cc/repository/__init__.py +++ b/monkey/monkey_island/cc/repository/__init__.py @@ -1,6 +1,7 @@ from .errors import RemovalError, RetrievalError, StorageError from .i_file_repository import FileNotFoundError, IFileRepository from .local_storage_file_repository import LocalStorageFileRepository +from .file_repository_locking_decorator import FileRepositoryLockingDecorator from .file_repository_logging_decorator import FileRepositoryLoggingDecorator from .i_agent_binary_repository import IAgentBinaryRepository from .agent_binary_repository import AgentBinaryRepository diff --git a/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py b/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py new file mode 100644 index 000000000..7539d4fc1 --- /dev/null +++ b/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py @@ -0,0 +1,26 @@ +from multiprocessing import Lock +from typing import BinaryIO + +from . import IFileRepository + + +class FileRepositoryLockingDecorator(IFileRepository): + def __init__(self, file_repository: IFileRepository): + self._file_repository = file_repository + self._lock = Lock() + + def save_file(self, unsafe_file_name: str, file_contents: BinaryIO): + with self._lock: + return self._file_repository.save_file(unsafe_file_name, file_contents) + + def open_file(self, unsafe_file_name: str) -> BinaryIO: + with self._lock: + return self._file_repository.open_file(unsafe_file_name) + + def delete_file(self, unsafe_file_name: str): + with self._lock: + return self._file_repository.delete_file(unsafe_file_name) + + def delete_all_files(self): + with self._lock: + return self._file_repository.delete_all_files() From d4883c6e4420c86abc43a8109498773e8e303c48 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sat, 2 Jul 2022 10:32:12 -0400 Subject: [PATCH 04/14] Island: Specify "read-only" in IFileRepository.open_file() docstring --- monkey/monkey_island/cc/repository/i_file_repository.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/repository/i_file_repository.py b/monkey/monkey_island/cc/repository/i_file_repository.py index baa52fdda..bedc9cfdb 100644 --- a/monkey/monkey_island/cc/repository/i_file_repository.py +++ b/monkey/monkey_island/cc/repository/i_file_repository.py @@ -27,7 +27,7 @@ class IFileRepository(metaclass=abc.ABCMeta): @abc.abstractmethod def open_file(self, unsafe_file_name: str) -> BinaryIO: """ - Open a file and return a file-like object + Open a file and return a read-only file-like object :param unsafe_file_name: An unsanitized file name that identifies the file to be opened :return: A file-like object providing access to the file's contents From 9affe10f67c4b15c48703d2dfd83e2f05763a80e Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sat, 2 Jul 2022 10:33:06 -0400 Subject: [PATCH 05/14] Island: Add FileRepositoryCachingDecorator --- .../monkey_island/cc/repository/__init__.py | 1 + .../file_repository_caching_decorator.py | 37 +++++++++++++ .../test_file_repository_caching_decorator.py | 55 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 monkey/monkey_island/cc/repository/file_repository_caching_decorator.py create mode 100644 monkey/tests/unit_tests/monkey_island/cc/repository/test_file_repository_caching_decorator.py diff --git a/monkey/monkey_island/cc/repository/__init__.py b/monkey/monkey_island/cc/repository/__init__.py index 6f683cc1a..d90f6aac6 100644 --- a/monkey/monkey_island/cc/repository/__init__.py +++ b/monkey/monkey_island/cc/repository/__init__.py @@ -1,6 +1,7 @@ from .errors import RemovalError, RetrievalError, StorageError from .i_file_repository import FileNotFoundError, IFileRepository from .local_storage_file_repository import LocalStorageFileRepository +from .file_repository_caching_decorator import FileRepositoryCachingDecorator from .file_repository_locking_decorator import FileRepositoryLockingDecorator from .file_repository_logging_decorator import FileRepositoryLoggingDecorator from .i_agent_binary_repository import IAgentBinaryRepository diff --git a/monkey/monkey_island/cc/repository/file_repository_caching_decorator.py b/monkey/monkey_island/cc/repository/file_repository_caching_decorator.py new file mode 100644 index 000000000..76739716f --- /dev/null +++ b/monkey/monkey_island/cc/repository/file_repository_caching_decorator.py @@ -0,0 +1,37 @@ +import io +import shutil +from functools import lru_cache +from typing import BinaryIO + +from . import IFileRepository + + +class FileRepositoryCachingDecorator(IFileRepository): + def __init__(self, file_repository: IFileRepository): + self._file_repository = file_repository + + def save_file(self, unsafe_file_name: str, file_contents: BinaryIO): + self._open_file.cache_clear() + return self._file_repository.save_file(unsafe_file_name, file_contents) + + def open_file(self, unsafe_file_name: str) -> BinaryIO: + original_file = self._open_file(unsafe_file_name) + file_copy = io.BytesIO() + + shutil.copyfileobj(original_file, file_copy) + original_file.seek(0) + file_copy.seek(0) + + return file_copy + + @lru_cache(maxsize=16) + def _open_file(self, unsafe_file_name: str) -> BinaryIO: + return self._file_repository.open_file(unsafe_file_name) + + def delete_file(self, unsafe_file_name: str): + self._open_file.cache_clear() + return self._file_repository.delete_file(unsafe_file_name) + + def delete_all_files(self): + self._open_file.cache_clear() + return self._file_repository.delete_all_files() diff --git a/monkey/tests/unit_tests/monkey_island/cc/repository/test_file_repository_caching_decorator.py b/monkey/tests/unit_tests/monkey_island/cc/repository/test_file_repository_caching_decorator.py new file mode 100644 index 000000000..14fdf8c27 --- /dev/null +++ b/monkey/tests/unit_tests/monkey_island/cc/repository/test_file_repository_caching_decorator.py @@ -0,0 +1,55 @@ +import io + +import pytest +from tests.monkey_island import SingleFileRepository + +from monkey_island.cc import repository +from monkey_island.cc.repository import FileRepositoryCachingDecorator + + +@pytest.fixture +def file_repository(): + return FileRepositoryCachingDecorator(SingleFileRepository()) + + +def test_open_cache_file(file_repository): + file_name = "test.txt" + file_contents = b"Hello World!" + + file_repository.save_file(file_name, io.BytesIO(file_contents)) + assert file_repository.open_file(file_name).read() == file_contents + assert file_repository.open_file(file_name).read() == file_contents + + +def test_overwrite_file(file_repository): + file_name = "test.txt" + file_contents_1 = b"Hello World!" + file_contents_2 = b"Goodbye World!" + + file_repository.save_file(file_name, io.BytesIO(file_contents_1)) + assert file_repository.open_file(file_name).read() == file_contents_1 + + file_repository.save_file(file_name, io.BytesIO(file_contents_2)) + assert file_repository.open_file(file_name).read() == file_contents_2 + + +def test_delete_file(file_repository): + file_name = "test.txt" + file_contents = b"Hello World!" + + file_repository.save_file(file_name, io.BytesIO(file_contents)) + file_repository.delete_file(file_name) + + with pytest.raises(repository.FileNotFoundError): + file_repository.open_file(file_name) + + +def test_delete_all_files(file_repository): + file_name = "test.txt" + file_contents = b"Hello World!" + + file_repository.save_file(file_name, io.BytesIO(file_contents)) + file_repository.delete_all_files() + + with pytest.raises(repository.FileNotFoundError): + file_repository.open_file(file_name) From a329177b499fc32980bf4c13a9ca8bcf5550ec4e Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sat, 2 Jul 2022 19:59:50 -0400 Subject: [PATCH 06/14] Island: Decorate LocalStorageFileRepository --- monkey/monkey_island/cc/services/initialize.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py index 28a88558c..dad5b92c7 100644 --- a/monkey/monkey_island/cc/services/initialize.py +++ b/monkey/monkey_island/cc/services/initialize.py @@ -12,6 +12,9 @@ from common.utils.file_utils import get_binary_io_sha256_hash from monkey_island.cc.repository import ( AgentBinaryRepository, FileAgentConfigurationRepository, + FileRepositoryCachingDecorator, + FileRepositoryLockingDecorator, + FileRepositoryLoggingDecorator, FileSimulationRepository, IAgentBinaryRepository, IAgentConfigurationRepository, @@ -62,7 +65,8 @@ def _register_conventions(container: DIContainer, data_dir: Path): def _register_repositories(container: DIContainer, data_dir: Path): container.register_instance( - IFileRepository, LocalStorageFileRepository(data_dir / "runtime_data") + IFileRepository, + _decorate_file_repository(LocalStorageFileRepository(data_dir / "runtime_data")), ) container.register_instance(IAgentBinaryRepository, _build_agent_binary_repository()) container.register_instance( @@ -71,6 +75,12 @@ def _register_repositories(container: DIContainer, data_dir: Path): container.register_instance(ISimulationRepository, container.resolve(FileSimulationRepository)) +def _decorate_file_repository(file_repository: IFileRepository) -> IFileRepository: + return FileRepositoryLockingDecorator( + FileRepositoryCachingDecorator(FileRepositoryLoggingDecorator(file_repository)) + ) + + def _build_agent_binary_repository(): file_repository = LocalStorageFileRepository(AGENT_BINARIES_PATH) agent_binary_repository = AgentBinaryRepository(file_repository) From 6cc3689ab4ec4342b37297f39f7a3b6498aef771 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sat, 2 Jul 2022 20:02:53 -0400 Subject: [PATCH 07/14] Island: Remove unnecesary logging from LocalStorageFileRepository Most logging is now handled by FileRepositoryLoggingDecorator, which makes the logging reusable across different implementations of `IFileRepository`. --- .../cc/repository/local_storage_file_repository.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/monkey/monkey_island/cc/repository/local_storage_file_repository.py b/monkey/monkey_island/cc/repository/local_storage_file_repository.py index cf0444abe..58fd20bdb 100644 --- a/monkey/monkey_island/cc/repository/local_storage_file_repository.py +++ b/monkey/monkey_island/cc/repository/local_storage_file_repository.py @@ -36,7 +36,6 @@ class LocalStorageFileRepository(IFileRepository): try: safe_file_path = self._get_safe_file_path(unsafe_file_name) - logger.debug(f"Saving file contents to {safe_file_path}") with open(safe_file_path, "wb") as dest: shutil.copyfileobj(file_contents, dest) except Exception as err: @@ -45,8 +44,6 @@ class LocalStorageFileRepository(IFileRepository): def open_file(self, unsafe_file_name: str) -> BinaryIO: try: safe_file_path = self._get_safe_file_path(unsafe_file_name) - - logger.debug(f"Opening {safe_file_path}") return open(safe_file_path, "rb") except FileNotFoundError as err: # Wrap Python's FileNotFound error, which is-an OSError, in repository.FileNotFoundError @@ -61,8 +58,6 @@ class LocalStorageFileRepository(IFileRepository): def delete_file(self, unsafe_file_name: str): try: safe_file_path = self._get_safe_file_path(unsafe_file_name) - - logger.debug(f"Deleting {safe_file_path}") safe_file_path.unlink() except FileNotFoundError: # This method is idempotent. From 3c85a897027152774b55469dde3a5c6e15ae66b8 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sat, 2 Jul 2022 20:04:10 -0400 Subject: [PATCH 08/14] Island: Change log level in FileRepositoryLoggingDecorator to debug Most log statements in repositories should probably be at debug. Services and resources could potentially log at info. --- .../repository/file_repository_logging_decorator.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py b/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py index 47ba16ca1..5365faf4b 100644 --- a/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py +++ b/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py @@ -11,21 +11,17 @@ class FileRepositoryLoggingDecorator(IFileRepository): self._file_repository = file_repository def save_file(self, unsafe_file_name: str, file_contents: BinaryIO): - logger.info(f"Saving file {unsafe_file_name}") - + logger.debug(f"Saving file {unsafe_file_name}") return self._file_repository.save_file(unsafe_file_name, file_contents) def open_file(self, unsafe_file_name: str) -> BinaryIO: - logger.info(f"Opening file {unsafe_file_name}") - + logger.debug(f"Opening file {unsafe_file_name}") return self._file_repository.open_file(unsafe_file_name) def delete_file(self, unsafe_file_name: str): - logger.info(f"Deleting file {unsafe_file_name}") - + logger.debug(f"Deleting file {unsafe_file_name}") return self._file_repository.delete_file(unsafe_file_name) def delete_all_files(self): - logger.info("Deleting all files in the repository") - + logger.debug("Deleting all files in the repository") return self._file_repository.delete_all_files() From 9cb79c119ce55a043a5faacfbcfe1b1f20480420 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sun, 3 Jul 2022 09:35:19 -0400 Subject: [PATCH 09/14] Island: Decorate the FileRepository for AgentBinaryRepository --- monkey/monkey_island/cc/services/initialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py index dad5b92c7..7616a191e 100644 --- a/monkey/monkey_island/cc/services/initialize.py +++ b/monkey/monkey_island/cc/services/initialize.py @@ -82,7 +82,7 @@ def _decorate_file_repository(file_repository: IFileRepository) -> IFileReposito def _build_agent_binary_repository(): - file_repository = LocalStorageFileRepository(AGENT_BINARIES_PATH) + file_repository = _decorate_file_repository(LocalStorageFileRepository(AGENT_BINARIES_PATH)) agent_binary_repository = AgentBinaryRepository(file_repository) _log_agent_binary_hashes(agent_binary_repository) From 18f995919d04a2f599f2139fbd8adbe763be2d54 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Sun, 3 Jul 2022 09:38:31 -0400 Subject: [PATCH 10/14] Island: Add TODO about read/write lock --- .../cc/repository/file_repository_locking_decorator.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py b/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py index 7539d4fc1..18a559f78 100644 --- a/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py +++ b/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py @@ -3,6 +3,10 @@ from typing import BinaryIO from . import IFileRepository +# TODO: Use a read-write lock. See: +# - https://pypi.org/project/readerwriterlock/ +# - https://www.oreilly.com/library/view/python-cookbook/0596001673/ch06s04.html + class FileRepositoryLockingDecorator(IFileRepository): def __init__(self, file_repository: IFileRepository): From df8132c86c348db2696e640dbb324af54d875f48 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Mon, 4 Jul 2022 07:14:11 -0400 Subject: [PATCH 11/14] Island: Change the order of FileRepository decorators The caching decorator was suppressing debug log messages. Reversing their order resolves the issue. --- monkey/monkey_island/cc/services/initialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py index 7616a191e..b5a16ec9f 100644 --- a/monkey/monkey_island/cc/services/initialize.py +++ b/monkey/monkey_island/cc/services/initialize.py @@ -77,7 +77,7 @@ def _register_repositories(container: DIContainer, data_dir: Path): def _decorate_file_repository(file_repository: IFileRepository) -> IFileRepository: return FileRepositoryLockingDecorator( - FileRepositoryCachingDecorator(FileRepositoryLoggingDecorator(file_repository)) + FileRepositoryLoggingDecorator(FileRepositoryCachingDecorator(file_repository)) ) From 48cc6d6dd2defc5f39d22e825b925a407a82a280 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 5 Jul 2022 10:42:06 -0400 Subject: [PATCH 12/14] Island: Add readerwriterlock as a dependency --- monkey/monkey_island/Pipfile | 1 + monkey/monkey_island/Pipfile.lock | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/Pipfile b/monkey/monkey_island/Pipfile index fbc8b16ae..052a46039 100644 --- a/monkey/monkey_island/Pipfile +++ b/monkey/monkey_island/Pipfile @@ -30,6 +30,7 @@ pywin32 = {version = "*", sys_platform = "== 'win32'"} # Lock file is not create pefile = {version = "*", sys_platform = "== 'win32'"} # Pyinstaller requirement on windows marshmallow = "*" marshmallow-enum = "*" +readerwriterlock = "*" [dev-packages] virtualenv = ">=20.0.26" diff --git a/monkey/monkey_island/Pipfile.lock b/monkey/monkey_island/Pipfile.lock index c3e59c1d5..67647710a 100644 --- a/monkey/monkey_island/Pipfile.lock +++ b/monkey/monkey_island/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "04efa1f593acdfcdc48b7089108921a46421acbacec80d8a664ec674b221dd4b" + "sha256": "91b8cfcf1408b3709300f47d420c550fe355df76ad396e455049fef1cceca3ad" }, "pipfile-spec": 6, "requires": { @@ -338,7 +338,7 @@ "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" ], - "markers": "python_full_version >= '3.5.0'", + "markers": "python_version >= '3.5'", "version": "==3.3" }, "importlib-metadata": { @@ -792,6 +792,14 @@ "markers": "sys_platform == 'win32'", "version": "==0.2.0" }, + "readerwriterlock": { + "hashes": [ + "sha256:8c4b704e60d15991462081a27ef46762fea49b478aa4426644f2146754759ca7", + "sha256:b7c4cc003435d7a8ff15b312b0a62a88d9800ba6164af88991f87f8b748f9bea" + ], + "index": "pypi", + "version": "==1.0.9" + }, "requests": { "hashes": [ "sha256:bc7861137fbce630f17b03d3ad02ad0bf978c844f3536d0edda6499dafce2b6f", @@ -1117,7 +1125,7 @@ "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" ], - "markers": "python_full_version >= '3.5.0'", + "markers": "python_version >= '3.5'", "version": "==3.3" }, "imagesize": { From a8b54f69f9771d8ba111a34e9cb57b500397202b Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 5 Jul 2022 11:17:03 -0400 Subject: [PATCH 13/14] Island: Use read/write lock in FileRepositoryLockingDecorator --- .../file_repository_locking_decorator.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py b/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py index 18a559f78..0e7ee8a50 100644 --- a/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py +++ b/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py @@ -1,30 +1,27 @@ -from multiprocessing import Lock from typing import BinaryIO -from . import IFileRepository +from readerwriterlock import rwlock -# TODO: Use a read-write lock. See: -# - https://pypi.org/project/readerwriterlock/ -# - https://www.oreilly.com/library/view/python-cookbook/0596001673/ch06s04.html +from . import IFileRepository class FileRepositoryLockingDecorator(IFileRepository): def __init__(self, file_repository: IFileRepository): self._file_repository = file_repository - self._lock = Lock() + self._rwlock = rwlock.RWLockFair() def save_file(self, unsafe_file_name: str, file_contents: BinaryIO): - with self._lock: + with self._rwlock.gen_wlock(): return self._file_repository.save_file(unsafe_file_name, file_contents) def open_file(self, unsafe_file_name: str) -> BinaryIO: - with self._lock: + with self._rwlock.gen_rlock(): return self._file_repository.open_file(unsafe_file_name) def delete_file(self, unsafe_file_name: str): - with self._lock: + with self._rwlock.gen_wlock(): return self._file_repository.delete_file(unsafe_file_name) def delete_all_files(self): - with self._lock: + with self._rwlock.gen_wlock(): return self._file_repository.delete_all_files() From 545f35710f9c1fc716df01eda83a4fffabac0d70 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 5 Jul 2022 11:24:34 -0400 Subject: [PATCH 14/14] Island: Add class docstrings for IFileRepository decorators --- .../cc/repository/file_repository_caching_decorator.py | 4 ++++ .../cc/repository/file_repository_locking_decorator.py | 4 ++++ .../cc/repository/file_repository_logging_decorator.py | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/monkey/monkey_island/cc/repository/file_repository_caching_decorator.py b/monkey/monkey_island/cc/repository/file_repository_caching_decorator.py index 76739716f..0e026d035 100644 --- a/monkey/monkey_island/cc/repository/file_repository_caching_decorator.py +++ b/monkey/monkey_island/cc/repository/file_repository_caching_decorator.py @@ -7,6 +7,10 @@ from . import IFileRepository class FileRepositoryCachingDecorator(IFileRepository): + """ + An IFileRepository decorator that provides caching for other IFileRepositories. + """ + def __init__(self, file_repository: IFileRepository): self._file_repository = file_repository diff --git a/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py b/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py index 0e7ee8a50..1bd76b4dd 100644 --- a/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py +++ b/monkey/monkey_island/cc/repository/file_repository_locking_decorator.py @@ -6,6 +6,10 @@ from . import IFileRepository class FileRepositoryLockingDecorator(IFileRepository): + """ + An IFileRepository decorator that makes other IFileRepositories thread-safe. + """ + def __init__(self, file_repository: IFileRepository): self._file_repository = file_repository self._rwlock = rwlock.RWLockFair() diff --git a/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py b/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py index 5365faf4b..2bf8bfe6e 100644 --- a/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py +++ b/monkey/monkey_island/cc/repository/file_repository_logging_decorator.py @@ -7,6 +7,10 @@ logger = logging.getLogger(__name__) class FileRepositoryLoggingDecorator(IFileRepository): + """ + An IFileRepository decorator that provides debug logging for other IFileRepositories. + """ + def __init__(self, file_repository: IFileRepository): self._file_repository = file_repository