import json from pathlib import Path from typing import Any START_MARKER = "/*WellFargoProprietary%" END_MARKER = "%WellFargoProprietary*/" class WellsFargoPayloadExtractor: """Extract wrapped WellFargo payloads from HAR entries and parse them as JSON.""" def __init__(self) -> None: self.objects: list[Any] = [] self.errors: list[str] = [] def _normalize_text(self, raw_text: Any) -> str | None: """Return a normalized text payload or None when input is not a string.""" if not isinstance(raw_text, str): return None text = raw_text.strip() # Some HAR exports store content.text as an escaped JSON string literal. if len(text) >= 2 and text[0] == '"' and text[-1] == '"': try: decoded = json.loads(text) if isinstance(decoded, str): text = decoded except json.JSONDecodeError: self.errors.append("Could not decode an escaped text wrapper") return text def _parse_wrapped_text(self, text: str, context: str) -> Any | None: """Parse a marker-wrapped WellFargo payload text into JSON.""" if not text.startswith(START_MARKER): return None end_idx = text.find(END_MARKER, len(START_MARKER)) if end_idx == -1: self.errors.append(f"{context}: missing end marker") return None payload = text[len(START_MARKER) : end_idx] if not payload: self.errors.append(f"{context}: payload between markers is empty") return None try: return json.loads(payload) except json.JSONDecodeError as ex: self.errors.append(f"{context}: invalid payload JSON ({ex.msg})") return None def extract_from_data( self, har_data: dict[str, Any], entry0_only: bool = False ) -> list[Any]: """Parse payload objects from log.entries response/content/text fields.""" self.objects = [] self.errors = [] entries = har_data.get("log", {}).get("entries", []) if not isinstance(entries, list): self.errors.append("Expected log.entries to be a list") return self.objects indexed_entries = list(enumerate(entries[:1] if entry0_only else entries)) for index, entry in indexed_entries: text_value = ( entry.get("response", {}) .get("content", {}) .get("text") if isinstance(entry, dict) else None ) text = self._normalize_text(text_value) if not text: continue parsed = self._parse_wrapped_text(text, f"Entry {index}") if parsed is not None: self.objects.append(parsed) return self.objects def extract_from_file( self, input_path: str | Path, entry0_only: bool = False ) -> list[Any]: """Load HAR JSON from a file path and extract payload objects.""" path = Path(input_path) with path.open("r", encoding="utf-8") as f: har_data = json.load(f) return self.extract_from_data(har_data, entry0_only=entry0_only) def get_objects(self) -> list[Any]: """Return the latest parsed objects.""" return self.objects def extract_wf_objects(har_data: dict[str, Any]) -> list[Any]: """Backward-compatible functional API.""" return WellsFargoPayloadExtractor().extract_from_data(har_data)