From 5bb4271d36d888b0c34f0d5934380ac8ecd196e1 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sat, 4 Jul 2026 08:47:34 +0900 Subject: [PATCH] feat: log-level redaction filter --- dzgui/app_init.py | 10 ++++++++- dzgui/model/model_factory.py | 5 +---- dzgui/util/redact.py | 41 ++++++++++++++++++++++-------------- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/dzgui/app_init.py b/dzgui/app_init.py index 3ed89d2..4644531 100644 --- a/dzgui/app_init.py +++ b/dzgui/app_init.py @@ -4,7 +4,7 @@ import shutil from typing import TYPE_CHECKING -from dzgui.const.constants import APP_NAME, APP_NAME_LOWER +from dzgui.const.constants import APP_NAME from dzgui.const.enum import Preferences from dzgui.config.query import lookup from dzgui.config.userprefs import UserPrefs @@ -21,6 +21,7 @@ from dzgui.strings import boot # from dzgui.util.map_count import get_map_count from dzgui.util.deck import is_steam_deck, is_game_mode from dzgui.util.localize import set_locale +from dzgui.util.redact import RedactionFilter, REDACTION_PATTERNS from dzgui.util.strings import init from dzgui.views.base import App @@ -40,13 +41,19 @@ def make_parents(path: "Path") -> None: def setup_logger(log_path: "Path") -> None: + # TODO: put in consts? _format = ( "%(asctime)s␞%(levelname)s␞%(filename)s::%(funcName)s::%(lineno)s␞%(message)s" ) + fh = logging.FileHandler(log_path) formatter = logging.Formatter(_format) fh.setFormatter(formatter) fh.setLevel(logging.DEBUG) + + _filter = RedactionFilter(patterns=REDACTION_PATTERNS) + fh.addFilter(_filter) + logger.setLevel(logging.DEBUG) logger.addHandler(fh) @@ -66,6 +73,7 @@ def copy_bare_configs(config: "Path", resolution: "Path") -> tuple[bool, bool]: ] config_changed = False state_changed = False + if config.parent.exists() is False: new_file = config old_file = config.parent.parent / conf diff --git a/dzgui/model/model_factory.py b/dzgui/model/model_factory.py index daefeb3..7dfffbf 100644 --- a/dzgui/model/model_factory.py +++ b/dzgui/model/model_factory.py @@ -2,7 +2,6 @@ from dataclasses import dataclass from typing import Any, Sequence, TYPE_CHECKING from dzgui.const.enum import HELP_MENU_ROWS -from dzgui.util.redact import redact_log from dzgui.util.strings import delimiter import gi @@ -134,9 +133,7 @@ class ModelFactory: with open(path, "r") as f: lines = [line.split(delimiter) for line in f.read().splitlines()] for record in lines: - # NOTE: strips PII and API keys - clean = redact_log(record) - store.append(clean) + store.append(record) return store def new_model_from_class(self, cls: type) -> FastInsertListStore: diff --git a/dzgui/util/redact.py b/dzgui/util/redact.py index 94d4bfb..75c2dc9 100644 --- a/dzgui/util/redact.py +++ b/dzgui/util/redact.py @@ -1,20 +1,29 @@ +import logging import re +from typing import Literal -def redact(text: str) -> str: - r = r"(/home/)([^/])*" - cleaned = re.sub(r, r"/home/REDACTED", text) +api_filter = r"(.*&key=)([^&]*)(.*)" +home_filter = r"(/home/)([^/]*)(.*)" +REDACTED = r"\1REDACTED\3" +REDACTION_PATTERNS = [api_filter, home_filter] + + +def redact_home(text: str) -> str: + pat = re.compile(home_filter) + cleaned = pat.sub(REDACTED, text) return cleaned -def redact_log(record: list) -> list[str]: - """ - requests library includes Steam API key in URL params - """ - clean = [] - for item in record: - if "&key=" in item: - pat = r"(.*&key=)(\S+)(.*)" - scrubbed = re.sub(pat, r"\1REDACTED\3", item) - clean.append(scrubbed) - else: - clean.append(item) - return clean + +class RedactionFilter(logging.Filter): + def __init__(self, patterns: list[str] | None = None) -> None: + super().__init__() + self._patterns = [re.compile(pat) for pat in (patterns or [])] + + def filter(self, record: logging.LogRecord) -> Literal[True]: + for pattern in self._patterns: + try: + record.msg = pattern.sub(REDACTED, record.msg) + except TypeError: + exception_text = f"{type(record.msg).__name__}: {record.msg}" + record.msg = pattern.sub(REDACTED, exception_text) + return True