[eric] browser: login-wall guard so the scripted send never fills an auth page

This commit is contained in:
ciregenz
2026-07-17 16:43:54 -07:00
parent 19734e1eac
commit 1dd4d5ef78
2 changed files with 64 additions and 1 deletions
@@ -37,6 +37,31 @@ P_COMPOSER_NAME_RE = re.compile(
re.I,
)
# Login/auth walls: a logged-out card lands here, and the structural reveal-finder would
# otherwise fill a login field and arm the page's own submit as a "send" (measured live on
# instagram/threads). A real composer never lives on one of these, so decline outright.
P_LOGIN_WALL_URL_RE = re.compile(
r"accounts\.google\.com|/i/flow/login|/accounts/login|/uas/login|/users/sign_in|"
r"/sessions/new|/checkpoint|force_authentication|"
r"/(?:log[_-]?in|sign[_-]?in|signin|logon)(?:[/?#]|$)",
re.I,
)
P_LOGIN_WALL_STATE_RE = re.compile(
r'<\s*textbox\s+"[^"]*(?:password|passwd)|(?:log|sign)\s?in to |'
r"continue with (?:google|apple|facebook)",
re.I,
)
def looks_like_login_wall(current_url: str, state_text: str) -> bool:
"""A login/auth page (by URL) or an auth form in the perception (a password field, a
'Log in to X' heading, an OAuth 'Continue with ...'). The scripted send declines here:
a real composer never shares a page with these, and filling here types a login field."""
if current_url and P_LOGIN_WALL_URL_RE.search(current_url):
return True
return bool(state_text and P_LOGIN_WALL_STATE_RE.search(state_text))
ToolRunner = Callable[[str, dict, str, str], Awaitable[dict]]
@@ -187,6 +212,9 @@ async def run_send_script(
if P_READONLY_RE.search(task) or P_READONLY_RE.search(payload_source or ""):
logger.info("[browser-sendscript] decline: read-only directive in task")
return None
if looks_like_login_wall(current_url, state_text):
logger.info(f"[browser-sendscript] decline: login/auth wall ({(current_url or '')[:60]!r})")
return None
payload = quoted_payload(payload_source or task)
if not payload:
logger.info("[browser-sendscript] decline: no unambiguous quoted payload")
@@ -255,7 +283,13 @@ async def run_send_script(
break
logger.info("[browser-sendscript] reveal navigated (open-first); re-perceiving the destination")
await asyncio.sleep(1.5)
await fresh_list()
dest = await fresh_list()
# open-first can land on a login redirect (a logged-out feed's first item);
# stop before the NEXT fill so we never type into the auth form we just opened.
if looks_like_login_wall("", dest):
logger.info("[browser-sendscript] decline: reveal landed on a login/auth wall")
fc = {}
break
if isinstance(fc, dict) and fc.get("found") and fc.get("filled"):
p_struct_selector = str(fc.get("selector") or "")
logger.info(f"[browser-sendscript] structural composer role={fc.get('role')!r} "
+29
View File
@@ -224,3 +224,32 @@ async def test_readonly_probe_never_fires():
payload_source=TASK, current_url=THREAD_URL)
assert r is None
assert not calls["clicks"]
def test_looks_like_login_wall_hits_and_false_positives():
# login/auth URLs (the live instagram/threads mis-fire was one of these)
assert ss.looks_like_login_wall("https://www.instagram.com/accounts/login/?force_authentication", "")
assert ss.looks_like_login_wall("https://accounts.google.com/v3/signin/identifier", "")
assert ss.looks_like_login_wall("https://www.reddit.com/login/", "")
assert ss.looks_like_login_wall("https://x.com/i/flow/login", "")
# auth-form perception signals with an innocuous url
assert ss.looks_like_login_wall("https://site.com/x", '[3]<textbox "Password">')
assert ss.looks_like_login_wall("https://site.com/x", "Log in to X to continue")
# false positives: a real composer page, a blog path, gmail inbox, a /author/ path
assert not ss.looks_like_login_wall("https://x.com/home", X_COMPOSER)
assert not ss.looks_like_login_wall("https://example.com/blog/login-tips", "")
assert not ss.looks_like_login_wall("https://mail.google.com/mail/u/0/#inbox?compose=new", "")
assert not ss.looks_like_login_wall("https://site.com/author/jane", "")
@pytest.mark.asyncio
async def test_login_wall_url_declines_before_any_fill():
"""A login URL declines even when the perception carries a composer and the task quotes a
payload: a real send surface never shares a page with a login wall, and filling here types
into the auth form (the live instagram/threads mis-fire under the reveal finder)."""
ex, calls = make_exec([X_COMPOSER])
r = await ss.run_send_script('post this exactly: "hello from the test x9"', "b1", "", X_COMPOSER, ex,
send_submit_index_in_state, payload_in_textbox,
current_url="https://x.com/i/flow/login")
assert r is None
assert not calls["clicks"]