mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
[eric] browser: login-wall guard so the scripted send never fills an auth page
This commit is contained in:
@@ -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} "
|
||||
|
||||
@@ -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"]
|
||||
|
||||
Reference in New Issue
Block a user