From 0169c81b73e4b67d51e8315efbbe42a5f8b307ec Mon Sep 17 00:00:00 2001 From: Abolfazl Date: Tue, 5 May 2026 08:04:11 +0330 Subject: [PATCH] feat: enhance logging by masking Apps Script deployment IDs for security --- config.example.json | 5 +++++ main.py | 8 ++++++-- src/relay/domain_fronter.py | 19 +++++++++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/config.example.json b/config.example.json index 3a201dd..6e47f32 100644 --- a/config.example.json +++ b/config.example.json @@ -1,6 +1,11 @@ { "google_ip": "216.239.38.120", "front_domain": "www.google.com", + "front_domains": [ + "www.google.com", + "mail.google.com", + "accounts.google.com" + ], "script_id": "YOUR_APPS_SCRIPT_DEPLOYMENT_ID", "auth_key": "CHANGE_ME_TO_A_STRONG_SECRET", "listen_host": "127.0.0.1", diff --git a/main.py b/main.py index 85c6232..a8d67e1 100644 --- a/main.py +++ b/main.py @@ -245,9 +245,13 @@ def main(): if isinstance(script_ids, list): log.info("Script IDs : %d scripts (sticky per-host)", len(script_ids)) for i, sid in enumerate(script_ids): - log.info(" [%d] %s", i + 1, sid) + _s = str(sid) + masked = f"{_s[:6]}…{_s[-4:]}" if len(_s) > 12 else _s + log.info(" [%d] %s", i + 1, masked) else: - log.info("Script ID : %s", script_ids) + _s = str(script_ids) if script_ids else "(none)" + masked = f"{_s[:6]}…{_s[-4:]}" if len(_s) > 12 else _s + log.info("Script ID : %s", masked) # Ensure CA file exists before checking / installing it. # MITMCertManager generates ca/ca.crt on first instantiation. diff --git a/src/relay/domain_fronter.py b/src/relay/domain_fronter.py index d48c37c..91628e3 100644 --- a/src/relay/domain_fronter.py +++ b/src/relay/domain_fronter.py @@ -73,6 +73,21 @@ from .http_reader import read_http_response log = logging.getLogger("Fronter") +def _mask_sid(sid: str) -> str: + """Return a safe display form of an Apps Script deployment ID. + + Full deployment IDs look like ``AKfycbwLd8Ca2BIsMWs5uN3x7...`` + and should never appear in log files or screenshots that users might + share in issue reports. Show only the first 6 and last 4 characters + so it's identifiable but not usable to hijack the deployment: + + AKfycb…5dGE + """ + if not sid or len(sid) <= 12: + return sid or "(none)" + return f"{sid[:6]}\u2026{sid[-4:]}" + + class DomainFronter: _STATIC_EXTS = STATIC_EXTS _H2_FAILURE_COOLDOWN = 60.0 @@ -576,7 +591,7 @@ class DomainFronter: return # Nothing to fall back to — blacklist would be pointless. self._sid_blacklist[sid] = time.time() + self._blacklist_ttl log.warning("Blacklisted script %s for %ds%s", - sid[-8:] if len(sid) > 8 else sid, + _mask_sid(sid), int(self._blacklist_ttl), f" ({reason})" if reason else "") @@ -763,7 +778,7 @@ class DomainFronter: ) if snap["blacklisted_scripts"]: log.debug(" blacklisted scripts: %s", - ", ".join(f"{b['sid']} ({b['expires_in_s']}s)" + ", ".join(f"{_mask_sid(b['sid'])} ({b['expires_in_s']}s)" for b in snap["blacklisted_scripts"])) except asyncio.CancelledError: break