feat(cred): harden client onboarding with Instagram linking portal, age verification bypass, and fleet runbook

This commit is contained in:
operator
2026-10-04 21:43:32 +00:00
parent 7902622852
commit 178ddc5dbf
10 changed files with 898 additions and 41 deletions
+77 -37
View File
@@ -95,50 +95,71 @@ def main():
page = get_page(port)
ws = websocket.create_connection(page['webSocketDebuggerUrl'], timeout=15)
# Step 1: Check if already logged in
# Step 1: Check if already logged in or blocked at verification gate
title = ev(ws, "document.title")
body = ev(ws, "document.body.innerText.slice(0,200)")
if "Connected" in body or "Chats" in body:
body = ev(ws, "document.body.innerText.slice(0,500)")
url = ev(ws, "location.href") or ""
if "access/verification" in url or "confirm your age" in body.lower():
ig_link = ev(ws, """(async()=>{
try {
const r = await fetch('/api/hatch/age-confirmation/linking-web-auth?account_type=instagram', {
headers: {'Accept': 'application/json'}
});
const j = await r.json();
return j && j.url ? j.url : null;
} catch(e) { return null; }
})()""", True)
if ig_link:
print(f"LINK_INSTAGRAM_URL: {ig_link}")
print(f"NEEDS_HUMAN: Age verification required for {args.email} at {url}. Client intervention required to confirm age or link Instagram/Facebook.", file=sys.stderr)
ws.close()
sys.exit(3)
if ("Connected" in body or "Chats" in body) and "Enter your code" not in body and "access/verification" not in url:
print(f"Already logged in (title: {title})")
ws.close()
return 0
# Step 2: Click Log in (if on landing page)
if "Log in" in body:
print("Clicking Log in...")
already_on_otp = ("Enter your code" in body or "code we sent" in body) and args.email in body
if not already_on_otp:
# Step 2: Click Log in (if on landing page)
if "Log in" in body:
print("Clicking Log in...")
ev(ws, """(async()=>{
const b=[...document.querySelectorAll('button')].find(x=>x.innerText.includes('Log in'));
if(b) b.click(); return !!b;
})()""", True)
time.sleep(3)
# Step 3: Enter email
print("Entering email: [redacted]")
result = ev(ws, f"""(async()=>{{
const inp=[...document.querySelectorAll('input')].find(i=>
(i.placeholder&&i.placeholder.toLowerCase().includes('email'))||
(i.getAttribute('aria-label')&&i.getAttribute('aria-label').toLowerCase().includes('email'))
);
if(!inp) return 'NOINPUT';
inp.focus();
document.execCommand('insertText',false,'{args.email}');
await new Promise(r=>setTimeout(r,500));
return 'entered:'+inp.value;
}})()""", True)
print("Email: [redacted]")
if result == 'NOINPUT':
print("ERROR: Email input not found", file=sys.stderr)
ws.close()
sys.exit(1)
time.sleep(1)
# Step 4: Click Continue
print("Clicking Continue...")
ev(ws, """(async()=>{
const b=[...document.querySelectorAll('button')].find(x=>x.innerText.includes('Log in'));
const b=[...document.querySelectorAll('button')].find(x=>x.innerText.includes('Continue'));
if(b) b.click(); return !!b;
})()""", True)
time.sleep(3)
# Step 3: Enter email
print("Entering email: [redacted]")
result = ev(ws, f"""(async()=>{{
const inp=[...document.querySelectorAll('input')].find(i=>
(i.placeholder&&i.placeholder.toLowerCase().includes('email'))||
(i.getAttribute('aria-label')&&i.getAttribute('aria-label').toLowerCase().includes('email'))
);
if(!inp) return 'NOINPUT';
inp.focus();
document.execCommand('insertText',false,'{args.email}');
await new Promise(r=>setTimeout(r,500));
return 'entered:'+inp.value;
}})()""", True)
print("Email: [redacted]")
if result == 'NOINPUT':
print("ERROR: Email input not found", file=sys.stderr)
ws.close()
sys.exit(1)
time.sleep(1)
# Step 4: Click Continue
print("Clicking Continue...")
ev(ws, """(async()=>{
const b=[...document.querySelectorAll('button')].find(x=>x.innerText.includes('Continue'));
if(b) b.click(); return !!b;
})()""", True)
time.sleep(4)
time.sleep(4)
else:
print("Page is already on OTP prompt for this email, skipping email entry.")
# Step 5: Check for OTP prompt
body = ev(ws, "document.body.innerText.slice(0,500)")
@@ -176,7 +197,26 @@ def main():
# Verify login
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:
url = ev(ws, "location.href") or ""
# Check for post-login gates requiring human/client intervention
if "access/verification" in url or "confirm your age" in body.lower():
ig_link = ev(ws, """(async()=>{
try {
const r = await fetch('/api/hatch/age-confirmation/linking-web-auth?account_type=instagram', {
headers: {'Accept': 'application/json'}
});
const j = await r.json();
return j && j.url ? j.url : null;
} catch(e) { return null; }
})()""", True)
if ig_link:
print(f"LINK_INSTAGRAM_URL: {ig_link}")
print(f"NEEDS_HUMAN: Age verification required for {args.email} at {url}. Client intervention required to confirm age or link Instagram/Facebook.", file=sys.stderr)
ws.close()
sys.exit(3)
if "Connected" in body or "Chats" in body or (("Muse" in title or "Chat" in title) and "access/verification" not in url):
print(f"SUCCESS: Logged in as [redacted] (title: {title})")
ws.close()
return 0