muse-signin: mask secrets in progress output at the source

Identifier, OTP code, and account-name values replaced with [redacted] in all progress prints. Line structure and markers preserved (APPROVAL_NEEDED/NEEDS_HUMAN/SUCCESS prefixes intact); exit codes 0/2/3/4 unchanged, no consumer parses stdout. Defense in depth: onboard-driver already scrubs its passthrough; this covers manual operator flows too.
This commit is contained in:
cred-driver
2026-10-04 18:07:48 +00:00
parent 86da8b5539
commit 7b5271a69a
+13 -13
View File
@@ -7,7 +7,7 @@ Usage:
If --otp is not provided, the script will:
1. Navigate through login flow up to OTP prompt
2. Print "APPROVAL_NEEDED: OTP required for <email>"
2. Print "APPROVAL_NEEDED: OTP required for [redacted]"
3. Exit with code 2
The operator then obtains the OTP (via chat with user) and re-runs:
@@ -83,7 +83,7 @@ def main():
args = p.parse_args()
if is_registered_in_accounts(args.email):
print(f"Registry check: {args.email} is registered in ACCOUNTS.md")
print("Registry check: [redacted] is registered in ACCOUNTS.md")
if args.cdp_port:
port = args.cdp_port
@@ -113,7 +113,7 @@ def main():
time.sleep(3)
# Step 3: Enter email
print(f"Entering email: {args.email}")
print("Entering email: [redacted]")
result = ev(ws, f"""(async()=>{{
const inp=[...document.querySelectorAll('input')].find(i=>
(i.placeholder&&i.placeholder.toLowerCase().includes('email'))||
@@ -125,7 +125,7 @@ def main():
await new Promise(r=>setTimeout(r,500));
return 'entered:'+inp.value;
}})()""", True)
print(f"Email: {result}")
print("Email: [redacted]")
if result == 'NOINPUT':
print("ERROR: Email input not found", file=sys.stderr)
ws.close()
@@ -143,10 +143,10 @@ def main():
# Step 5: Check for OTP prompt
body = ev(ws, "document.body.innerText.slice(0,500)")
if "Enter your code" in body or "code we sent" in body or "To log in" in body or "To confirm your account" in body:
print(f"OTP prompt detected for {args.email}")
print("OTP prompt detected for [redacted]")
if not args.otp:
print(f"APPROVAL_NEEDED: OTP required for {args.email}")
print("Re-run with: signin.py --email {} --otp <code>".format(args.email))
print("APPROVAL_NEEDED: OTP required for [redacted]")
print("Re-run with: signin.py --email [redacted] --otp <code>")
ws.close()
sys.exit(2) # Approval needed
@@ -160,7 +160,7 @@ def main():
await new Promise(r=>setTimeout(r,500));
return 'entered:'+inp.value;
}})()""", True)
print(f"OTP: {result}")
print("OTP: [redacted]")
time.sleep(1)
# Click Next/Verify/Confirm
@@ -177,7 +177,7 @@ def main():
body = ev(ws, "document.body.innerText.slice(0,500)")
title = ev(ws, "document.title") or ""
if "Connected" in body or "Chats" in body or "Muse" in title or "Chat" in title:
print(f"SUCCESS: Logged in as {args.email} (title: {title})")
print(f"SUCCESS: Logged in as [redacted] (title: {title})")
ws.close()
return 0
# Multi-account selection: Meta shows one button per matching
@@ -200,16 +200,16 @@ def main():
})()""" % json.dumps(args.account_name), True)
if not picked:
print(f"NEEDS_HUMAN: no account button matched "
f"'{args.account_name}'", file=sys.stderr)
f"'[redacted]'", file=sys.stderr)
ws.close()
sys.exit(3)
print(f"Selected account '{args.account_name}', waiting...")
print(f"Selected account '[redacted]', waiting...")
time.sleep(5)
body = ev(ws, "document.body.innerText.slice(0,500)")
title = ev(ws, "document.title") or ""
if "Connected" in body or "Chats" in body or "Muse" in title or "Chat" in title:
print(f"SUCCESS: Logged in as {args.email} "
f"(account: {args.account_name})")
print("SUCCESS: Logged in as [redacted] "
"(account: [redacted])")
ws.close()
return 0
print("WARNING: account selection did not land in chat",