From 02a1663336c2f450ef4d0ab1cedaa0e80f675dd2 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sun, 17 May 2026 20:08:28 +0200 Subject: [PATCH] scripts(mitm): parametrise account-id/device-id redaction convert_mitm_script.py was the last tracked file carrying a real Bose account ID (9569497) and the maintainer's test-speaker MAC (A81B6A536A98), hardcoded as the values to redact from MITM captures. Replaced with mitmproxy `--set` options (`account_id`, `device_id`), defaulting to empty strings (no-op) so the tracked source no longer contains either real value. Callers configure their own at runtime: mitmdump -s convert_mitm_script.py \ --set out_dir=_/mitm \ --set account_id=1234567 \ --set device_id=AABBCCDDEEFF Added a module docstring documenting the flags so the usage isn't folded only into the loader help text. After this commit, the tree is clean for every personal-data pattern the audit at _/RFC-5737-cleanup/assessment.md identified. The only remaining 192.168.1.x references live in docs/analysis/ANONYMIZATION-SUMMARY.md as intentional doc-context discussion of why we moved off that range. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/convert_mitm_script.py | 45 ++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/scripts/convert_mitm_script.py b/scripts/convert_mitm_script.py index e49f6cb..87096d7 100644 --- a/scripts/convert_mitm_script.py +++ b/scripts/convert_mitm_script.py @@ -1,3 +1,20 @@ +"""mitmproxy add-on: dump request/response pairs to disk for analysis. + +Optionally redact a real Bose account ID and device ID from paths and +WebSocket text payloads, replacing them with `{accountId}` / +`{device_id}` so captures can be shared without leaking personal data. + +Usage: + + mitmdump -s convert_mitm_script.py \ + --set out_dir=_/mitm \ + --set account_id=1234567 \ + --set device_id=AABBCCDDEEFF + +`account_id` and `device_id` default to empty strings, in which case +no redaction is performed. +""" + from mitmproxy import http import os from datetime import datetime @@ -9,6 +26,18 @@ def load(loader): default="_/mitm", help="Output directory", ) + loader.add_option( + name="account_id", + typespec=str, + default="", + help="Real Bose account ID to redact from paths and WS payloads (replaced with {accountId}). Empty = no redaction.", + ) + loader.add_option( + name="device_id", + typespec=str, + default="", + help="Real device ID/MAC to redact from paths and WS payloads (replaced with {device_id}). Empty = no redaction.", + ) def request(flow: http.HTTPFlow): # This is called when a request is received, but in replay mode we process it in 'response' or 'done' @@ -41,9 +70,13 @@ def process_flow(flow: http.HTTPFlow): path = path.split('?')[0] dir_path = path - # Apply replacements as seen in other scripts - dir_path = dir_path.replace("9569497", "{accountId}") - dir_path = dir_path.replace("A81B6A536A98", "{device_id}") + # Optional redaction — see module docstring for --set flags. + account_id = ctx.options.account_id + device_id = ctx.options.device_id + if account_id: + dir_path = dir_path.replace(account_id, "{accountId}") + if device_id: + dir_path = dir_path.replace(device_id, "{device_id}") # Ensure dir_path doesn't have double slashes and is relative dir_path = dir_path.lstrip('/') @@ -103,8 +136,10 @@ def process_flow(flow: http.HTTPFlow): # Apply replacements to content as well if it's text if msg.type == 1: # Text content_str = content.decode('utf-8', errors='ignore') - content_str = content_str.replace("9569497", "{accountId}") - content_str = content_str.replace("A81B6A536A98", "{device_id}") + if account_id: + content_str = content_str.replace(account_id, "{accountId}") + if device_id: + content_str = content_str.replace(device_id, "{device_id}") content = content_str.encode('utf-8') msg_filename = f"{i:04d}-{direction}.{'bin' if msg.type == 2 else 'txt'}"