From 06f344784bc0d20abb6eafc0ee5abc6e14902057 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Tue, 31 Oct 2023 14:16:28 -0500 Subject: [PATCH 1/5] fix: hide secrets --- src/ape/logging.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ape/logging.py b/src/ape/logging.py index 04c31f4f5a..e01f871a54 100644 --- a/src/ape/logging.py +++ b/src/ape/logging.py @@ -7,6 +7,7 @@ from typing import IO, Any, Dict, Optional, Union import click +from yarl import URL class LogLevel(IntEnum): @@ -93,6 +94,19 @@ def __init__(self, echo_kwargs): def emit(self, record): try: msg = self.format(record) + + # Sanitize URLs + if "http" in msg: + parts = msg.split("http") + rest = parts[1].split(' ') + url = f"http{rest[0].rstrip()}" + sanitized_url = URL(url).with_user(None).with_password(None) + + # If there is a path, hide it but show that you are hiding it. + # Use string interpolation to prevent URL-character encoding. + sanitized_url_str = f"{sanitized_url.with_path('')}/[hidden]" if sanitized_url.path else f"{url}" + msg = f"{parts[0]}{sanitized_url_str}{' '.join(rest[1:])}" + level = record.levelname.lower() if self.echo_kwargs.get(level): click.echo(msg, **self.echo_kwargs[level]) From 8cda3f1f4a0633ec11da48465984fa4397cf115d Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Tue, 31 Oct 2023 14:18:21 -0500 Subject: [PATCH 2/5] fix: space --- src/ape/logging.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ape/logging.py b/src/ape/logging.py index e01f871a54..adea46fdb1 100644 --- a/src/ape/logging.py +++ b/src/ape/logging.py @@ -105,7 +105,7 @@ def emit(self, record): # If there is a path, hide it but show that you are hiding it. # Use string interpolation to prevent URL-character encoding. sanitized_url_str = f"{sanitized_url.with_path('')}/[hidden]" if sanitized_url.path else f"{url}" - msg = f"{parts[0]}{sanitized_url_str}{' '.join(rest[1:])}" + msg = f"{parts[0]}{sanitized_url_str} {' '.join(rest[1:])}".strip() level = record.levelname.lower() if self.echo_kwargs.get(level): From d405f0293c66a5ac0d6af628e023cf62e3747e76 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Tue, 31 Oct 2023 14:23:18 -0500 Subject: [PATCH 3/5] fix: check --- src/ape/logging.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ape/logging.py b/src/ape/logging.py index adea46fdb1..166db4125b 100644 --- a/src/ape/logging.py +++ b/src/ape/logging.py @@ -96,10 +96,10 @@ def emit(self, record): msg = self.format(record) # Sanitize URLs - if "http" in msg: - parts = msg.split("http") + if "http://" in msg or "https://" in msg or "ws://" in msg or "wss://" in msg: + parts = msg.split(" http") if "http" in msg else msg.split(" ws") rest = parts[1].split(' ') - url = f"http{rest[0].rstrip()}" + url = f"http{rest[0].strip()}" sanitized_url = URL(url).with_user(None).with_password(None) # If there is a path, hide it but show that you are hiding it. From 328f51bbcdb72d19c61e8ea3984afbe2840f6446 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Tue, 31 Oct 2023 14:40:42 -0500 Subject: [PATCH 4/5] refactor: a better way --- src/ape/api/providers.py | 17 ++++++++++++--- src/ape/logging.py | 47 +++++++++++++++++++++++----------------- src/ape_geth/provider.py | 7 ++---- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/ape/api/providers.py b/src/ape/api/providers.py index b93ad5d440..f2760972d3 100644 --- a/src/ape/api/providers.py +++ b/src/ape/api/providers.py @@ -46,7 +46,7 @@ TransactionNotFoundError, VirtualMachineError, ) -from ape.logging import LogLevel, logger +from ape.logging import LogLevel, logger, sanitize_url from ape.types import ( AddressType, AutoGasLimit, @@ -745,6 +745,17 @@ def _increment_call_func_coverage_hit_count(self, txn: TransactionAPI): self._test_runner.coverage_tracker.hit_function(contract_src, method) +def _sanitize_web3_url(msg: str) -> str: + if "URI: " not in msg: + return msg + + parts = msg.split("URI: ") + prefix = parts[0] + rest = parts[1].split(" ") + sanitized_url = sanitize_url(rest[0]) + return f"{prefix} URI: {sanitized_url} {' '.join(rest[1:])}" + + class Web3Provider(ProviderAPI, ABC): """ A base provider mixin class that uses the @@ -755,8 +766,8 @@ class Web3Provider(ProviderAPI, ABC): _client_version: Optional[str] = None def __init__(self, *args, **kwargs): - logger.create_logger("web3.RequestManager") - logger.create_logger("web3.providers.HTTPProvider") + logger.create_logger("web3.RequestManager", handlers=(_sanitize_web3_url,)) + logger.create_logger("web3.providers.HTTPProvider", handlers=(_sanitize_web3_url,)) super().__init__(*args, **kwargs) @property diff --git a/src/ape/logging.py b/src/ape/logging.py index 166db4125b..c95fc73b02 100644 --- a/src/ape/logging.py +++ b/src/ape/logging.py @@ -4,7 +4,7 @@ import traceback from enum import IntEnum from pathlib import Path -from typing import IO, Any, Dict, Optional, Union +from typing import IO, Any, Callable, Dict, Optional, Sequence, Union import click from yarl import URL @@ -87,25 +87,18 @@ def format(self, record): class ClickHandler(logging.Handler): - def __init__(self, echo_kwargs): + def __init__( + self, echo_kwargs: Dict, handlers: Optional[Sequence[Callable[[str], str]]] = None + ): super().__init__() self.echo_kwargs = echo_kwargs + self.handlers = handlers or [] def emit(self, record): try: msg = self.format(record) - - # Sanitize URLs - if "http://" in msg or "https://" in msg or "ws://" in msg or "wss://" in msg: - parts = msg.split(" http") if "http" in msg else msg.split(" ws") - rest = parts[1].split(' ') - url = f"http{rest[0].strip()}" - sanitized_url = URL(url).with_user(None).with_password(None) - - # If there is a path, hide it but show that you are hiding it. - # Use string interpolation to prevent URL-character encoding. - sanitized_url_str = f"{sanitized_url.with_path('')}/[hidden]" if sanitized_url.path else f"{url}" - msg = f"{parts[0]}{sanitized_url_str} {' '.join(rest[1:])}".strip() + for handler in self.handlers: + msg = handler(msg) level = record.levelname.lower() if self.echo_kwargs.get(level): @@ -226,15 +219,19 @@ def log_debug_stack_trace(self): stack_trace = traceback.format_exc() self._logger.debug(stack_trace) - def create_logger(self, new_name: str) -> logging.Logger: - _logger = get_logger(new_name, self.fmt) + def create_logger( + self, new_name: str, handlers: Optional[Sequence[Callable[[str], str]]] = None + ) -> logging.Logger: + _logger = get_logger(new_name, fmt=self.fmt, handlers=handlers) _logger.setLevel(self.level) self._extra_loggers[new_name] = _logger return _logger -def _format_logger(_logger: logging.Logger, fmt: str): - handler = ClickHandler(echo_kwargs=CLICK_ECHO_KWARGS) +def _format_logger( + _logger: logging.Logger, fmt: str, handlers: Optional[Sequence[Callable[[str], str]]] = None +): + handler = ClickHandler(echo_kwargs=CLICK_ECHO_KWARGS, handlers=handlers) formatter = ApeColorFormatter(fmt=fmt) handler.setFormatter(formatter) @@ -246,7 +243,9 @@ def _format_logger(_logger: logging.Logger, fmt: str): _logger.addHandler(handler) -def get_logger(name: str, fmt: Optional[str] = None) -> logging.Logger: +def get_logger( + name: str, fmt: Optional[str] = None, handlers: Optional[Sequence[Callable[[str], str]]] = None +) -> logging.Logger: """ Get a logger with the given ``name`` and configure it for usage with Ape. @@ -259,7 +258,7 @@ def get_logger(name: str, fmt: Optional[str] = None) -> logging.Logger: ``logging.Logger`` """ _logger = logging.getLogger(name) - _format_logger(_logger, fmt=fmt or DEFAULT_LOG_FORMAT) + _format_logger(_logger, fmt=fmt or DEFAULT_LOG_FORMAT, handlers=handlers) return _logger @@ -272,6 +271,14 @@ def _get_level(level: Optional[Union[str, int]] = None) -> str: return level +def sanitize_url(url: str) -> str: + url_obj = URL(url).with_user(None).with_password(None) + + # If there is a path, hide it but show that you are hiding it. + # Use string interpolation to prevent URL-character encoding. + return f"{url_obj.with_path('')}/[hidden]" if url_obj.path else f"{url}" + + logger = ApeLogger.create() # TODO: Can remove this type alias after 0.7 diff --git a/src/ape_geth/provider.py b/src/ape_geth/provider.py index 8c371ac59d..27dde32017 100644 --- a/src/ape_geth/provider.py +++ b/src/ape_geth/provider.py @@ -52,7 +52,7 @@ ContractNotFoundError, ProviderError, ) -from ape.logging import LogLevel, logger +from ape.logging import LogLevel, logger, sanitize_url from ape.types import AddressType, CallTreeNode, SnapshotID, SourceTraceback, TraceFrame from ape.utils import ( DEFAULT_NUMBER_OF_TEST_ACCOUNTS, @@ -277,10 +277,7 @@ def uri(self) -> str: @property def _clean_uri(self) -> str: - url = URL(self.uri).with_user(None).with_password(None) - # If there is a path, hide it but show that you are hiding it. - # Use string interpolation to prevent URL-character encoding. - return f"{url.with_path('')}/[hidden]" if url.path else f"{url}" + return sanitize_url(self.uri) @property def ipc_path(self) -> Path: From d382d897d569fc4ba7d03ef0f8fa97ead68f61bb Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Tue, 31 Oct 2023 14:42:31 -0500 Subject: [PATCH 5/5] fix: extra space --- src/ape/api/providers.py | 2 +- src/ape/logging.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ape/api/providers.py b/src/ape/api/providers.py index f2760972d3..8ab58adb86 100644 --- a/src/ape/api/providers.py +++ b/src/ape/api/providers.py @@ -750,7 +750,7 @@ def _sanitize_web3_url(msg: str) -> str: return msg parts = msg.split("URI: ") - prefix = parts[0] + prefix = parts[0].strip() rest = parts[1].split(" ") sanitized_url = sanitize_url(rest[0]) return f"{prefix} URI: {sanitized_url} {' '.join(rest[1:])}" diff --git a/src/ape/logging.py b/src/ape/logging.py index c95fc73b02..30fb00da6d 100644 --- a/src/ape/logging.py +++ b/src/ape/logging.py @@ -253,6 +253,7 @@ def get_logger( name (str): The name of the logger. fmt (Optional[str]): The format of the logger. Defaults to the Ape logger's default format: ``"%(levelname)s%(plugin)s: %(message)s"``. + handlers (Optional[Sequence[Callable[[str], str]]]): Additional log message handlers. Returns: ``logging.Logger``