diff --git a/slack_sdk/socket_mode/builtin/client.py b/slack_sdk/socket_mode/builtin/client.py index 79f875d52..15e93af02 100644 --- a/slack_sdk/socket_mode/builtin/client.py +++ b/slack_sdk/socket_mode/builtin/client.py @@ -20,6 +20,7 @@ from slack_sdk.web import WebClient from .connection import Connection, ConnectionState from ..interval_runner import IntervalRunner +from ..logger.messages import debug_redacted_message_string from ...errors import SlackClientConfigurationError, SlackClientNotConnectedError from ...proxy_env_variable_loader import load_http_proxy_from_env @@ -231,7 +232,7 @@ def close(self): def _on_message(self, message: str): if self.logger.level <= logging.DEBUG: - self.logger.debug(f"on_message invoked: (message: {message})") + self.logger.debug(f"on_message invoked: (message: {debug_redacted_message_string(message)})") self.enqueue_message(message) for listener in self.on_message_listeners: listener(message) diff --git a/slack_sdk/socket_mode/logger/__init__.py b/slack_sdk/socket_mode/logger/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/slack_sdk/socket_mode/logger/messages.py b/slack_sdk/socket_mode/logger/messages.py new file mode 100644 index 000000000..d10f7ee20 --- /dev/null +++ b/slack_sdk/socket_mode/logger/messages.py @@ -0,0 +1,6 @@ +import re + + +def debug_redacted_message_string(message: str) -> str: + xwfp_token_pattern = re.compile(r"\"xwfp-[A-Za-z0-9\-]+\"") # ex: "xwfp-abc-ABC-1234" + return re.sub(xwfp_token_pattern, "[[REDACTED]]", message) diff --git a/slack_sdk/socket_mode/websocket_client/__init__.py b/slack_sdk/socket_mode/websocket_client/__init__.py index faa7fdd6f..c6d1b9b41 100644 --- a/slack_sdk/socket_mode/websocket_client/__init__.py +++ b/slack_sdk/socket_mode/websocket_client/__init__.py @@ -24,6 +24,8 @@ from slack_sdk.socket_mode.request import SocketModeRequest from slack_sdk.web import WebClient +from ..logger.messages import debug_redacted_message_string + class SocketModeClient(BaseSocketModeClient): logger: Logger @@ -147,7 +149,7 @@ def on_open(ws: WebSocketApp): def on_message(ws: WebSocketApp, message: str): if self.logger.level <= logging.DEBUG: - self.logger.debug(f"on_message invoked: (message: {message})") + self.logger.debug(f"on_message invoked: (message: {debug_redacted_message_string(message)})") self.enqueue_message(message) for listener in self.on_message_listeners: listener(ws, message) diff --git a/slack_sdk/socket_mode/websockets/__init__.py b/slack_sdk/socket_mode/websockets/__init__.py index 39ed6b33f..dd8d9fd9c 100644 --- a/slack_sdk/socket_mode/websockets/__init__.py +++ b/slack_sdk/socket_mode/websockets/__init__.py @@ -26,6 +26,8 @@ from slack_sdk.socket_mode.request import SocketModeRequest from slack_sdk.web.async_client import AsyncWebClient +from ..logger.messages import debug_redacted_message_string + class SocketModeClient(AsyncBaseSocketModeClient): logger: Logger @@ -149,7 +151,9 @@ async def receive_messages(self) -> None: if isinstance(message, bytes): message = message.decode("utf-8") if self.logger.level <= logging.DEBUG: - self.logger.debug(f"Received message: {message}, session: {session_id}") + self.logger.debug( + f"Received message: {debug_redacted_message_string(message)}, session: {session_id}" + ) await self.enqueue_message(message) consecutive_error_count = 0 except Exception as e: diff --git a/tests/slack_sdk/socket_mode/logger/__init__.py b/tests/slack_sdk/socket_mode/logger/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slack_sdk/socket_mode/logger/test_messages.py b/tests/slack_sdk/socket_mode/logger/test_messages.py new file mode 100644 index 000000000..e241f9b77 --- /dev/null +++ b/tests/slack_sdk/socket_mode/logger/test_messages.py @@ -0,0 +1,26 @@ +import unittest + +from slack_sdk.socket_mode.logger.messages import debug_redacted_message_string + + +class TestRequest(unittest.TestCase): + def setUp(self): + pass + + def tearDown(self): + pass + + def test_debug_redacted_message_string(self): + message = """{"envelope_id":"abc-123","payload":{"token":"xxx","team_id":"T123","api_app_id":"A123","event":{"type":"function_executed","function":{"id":"Fn123","callback_id":"sample_function","title":"Sample function","description":"","type":"app","input_parameters":[],"output_parameters":[],"app_id":"A123","date_created":1719416102,"date_released":0,"date_updated":1719426759,"date_deleted":0,"form_enabled":false},"inputs":{"user_id":"U123"},"function_execution_id":"Fx123","workflow_execution_id":"Wx079QN9CT8E","event_ts":"1719427571.129426","bot_access_token":"xwfp-123-abc"},"type":"event_callback","event_id":"Ev123","event_time":1719427571},"type":"events_api","accepts_response_payload":false,"retry_attempt":0,"retry_reason":""}""" + redacted_message = debug_redacted_message_string(message) + self.assertEqual(redacted_message.count('"bot_access_token":[[REDACTED]]'), 1) + + def test_debug_redacted_message_string_no_changes(self): + message = """{"envelope_id":"abc-123","payload":{"token":"xxx","team_id":"T123","api_app_id":"A123","event":{"type":"function_executed","function":{"id":"Fn123","callback_id":"sample_function","title":"Sample function","description":"","type":"app","input_parameters":[],"output_parameters":[],"app_id":"A123","date_created":1719416102,"date_released":0,"date_updated":1719426759,"date_deleted":0,"form_enabled":false},"inputs":{"user_id":"U123"},"function_execution_id":"Fx123","workflow_execution_id":"Wx079QN9CT8E","event_ts":"1719427571.129426"},"type":"event_callback","event_id":"Ev123","event_time":1719427571},"type":"events_api","accepts_response_payload":false,"retry_attempt":0,"retry_reason":""}""" + redacted_message = debug_redacted_message_string(message) + self.assertEqual(redacted_message.count('"bot_access_token":[[REDACTED]]'), 0) + + def test_debug_redacted_message_string_simple(self): + message = '"bot_access_token": "xwfp-123-abc"' + redacted_message = debug_redacted_message_string(message) + self.assertEqual(redacted_message.count('"bot_access_token": [[REDACTED]]'), 1)