autoreg-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
186
skills/bulk-account-registration/templates/parallel_autoreg.py
Normal file
186
skills/bulk-account-registration/templates/parallel_autoreg.py
Normal file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Parallel.ai Auto-Registration Script
|
||||
Uses t-online.de emails (IMAP) → magic link → create org → API key
|
||||
|
||||
Usage:
|
||||
python parallel_autoreg.py --count 5
|
||||
python parallel_autoreg.py --emails emails.txt --count 10 --output keys.json
|
||||
"""
|
||||
|
||||
import imaplib, ssl, time, re, json, sys, os
|
||||
import requests
|
||||
from urllib.parse import unquote
|
||||
from datetime import datetime, timezone
|
||||
from email.utils import parsedate_to_datetime
|
||||
import email as eml
|
||||
|
||||
# Config
|
||||
IMAP_HOST = 'imap.t-online.de'
|
||||
IMAP_PORT = 993
|
||||
PARALLEL_BASE = 'https://platform.parallel.ai'
|
||||
OUTPUT_FILE = 'parallel_keys.json'
|
||||
EMAILS_FILE = 'emails.txt' # Override with --emails
|
||||
|
||||
def create_ssl_context():
|
||||
ctx = ssl.create_default_context()
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
return ctx
|
||||
|
||||
def load_emails(filepath, limit=None):
|
||||
"""Load unique email:password pairs from file, deduplicating by email"""
|
||||
seen = set()
|
||||
emails = []
|
||||
with open(filepath, 'r', encoding='utf-8', errors='replace') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
line = line.replace(';', ':')
|
||||
parts = line.split(':')
|
||||
if len(parts) >= 2:
|
||||
email_addr = parts[0].strip().strip('"').strip("'")
|
||||
password = [REDACTED]].strip().strip('"').strip("'")
|
||||
if email_addr not in seen and '@t-online.de' in email_addr:
|
||||
seen.add(email_addr)
|
||||
emails.append((email_addr, password))
|
||||
if limit and len(emails) >= limit:
|
||||
break
|
||||
return emails
|
||||
|
||||
def send_magic_link(session, email_addr):
|
||||
"""Send magic link via Parallel API"""
|
||||
csrf = session.get(f"{PARALLEL_BASE}/api/auth/csrf").json()['csrfToken']
|
||||
r = session.post(f"{PARALLEL_BASE}/api/auth/signin/email",
|
||||
data={
|
||||
"email": email_addr,
|
||||
"csrfToken": csrf,
|
||||
"callbackUrl": f"{PARALLEL_BASE}/post-auth-sign-up"
|
||||
},
|
||||
allow_redirects=False)
|
||||
return r.status_code == 302
|
||||
|
||||
def poll_imap_for_link(email_addr, password, sent_time, max_attempts=12):
|
||||
"""Poll IMAP inbox for magic link, filtering by email date"""
|
||||
ctx = create_ssl_context()
|
||||
mail = imaplib.IMAP4_SSL(IMAP_HOST, IMAP_PORT, ssl_context=ctx, timeout=10)
|
||||
mail.login(email_addr, password)
|
||||
|
||||
for attempt in range(max_attempts):
|
||||
time.sleep(2.5)
|
||||
mail.noop()
|
||||
mail.select('INBOX')
|
||||
status, messages = mail.search(None, 'ALL')
|
||||
msg_ids = messages[0].split() if messages[0] else []
|
||||
|
||||
for msg_id in reversed(msg_ids[-5:]):
|
||||
status, data = mail.fetch(msg_id, '(RFC822)')
|
||||
raw = data[0][1]
|
||||
msg = eml.message_from_bytes(raw)
|
||||
|
||||
date_str = msg.get('Date', '')
|
||||
try:
|
||||
msg_date = parsedate_to_datetime(date_str)
|
||||
except:
|
||||
msg_date = None
|
||||
|
||||
if b'Parallel' in raw and msg_date and msg_date > sent_time:
|
||||
for part in msg.walk():
|
||||
if part.get_content_type() == 'text/plain':
|
||||
body = part.get_payload(decode=True).decode('utf-8', errors='replace')
|
||||
links = re.findall(r'https://platform\.parallel\.ai/redirect\?to=[^\s"<>]+', body)
|
||||
if links:
|
||||
to_match = re.search(r'to=([^&]+)', links[0])
|
||||
callback_url = unquote(to_match.group(1))
|
||||
mail.logout()
|
||||
return callback_url
|
||||
|
||||
mail.logout()
|
||||
return None
|
||||
|
||||
def create_org_and_get_key(session, org_name="Research"):
|
||||
"""Create org and get API key"""
|
||||
r = session.post(f"{PARALLEL_BASE}/api/rpc/onboard/create-org-with-visibility",
|
||||
json={"orgName": org_name, "visibility": "private"})
|
||||
if r.status_code != 200:
|
||||
return None
|
||||
|
||||
r = session.post(f"{PARALLEL_BASE}/api/rpc/auth/get-my-api-key-and-session-details", json={})
|
||||
if r.status_code != 200:
|
||||
return None
|
||||
|
||||
data = r.json()
|
||||
api_key = [REDACTED]'data', {}).get('apiKey', '')
|
||||
org_id = data.get('data', {}).get('forOrgId', '')
|
||||
|
||||
return {
|
||||
'api_key': api_key,
|
||||
'org_id': org_id,
|
||||
'org_name': org_name,
|
||||
'base_url': data.get('data', {}).get('baseUrl', 'https://api.parallel.ai/'),
|
||||
}
|
||||
|
||||
def register_one(email_addr, password, org_name="Research"):
|
||||
"""Register one account"""
|
||||
session = requests.Session()
|
||||
|
||||
if not send_magic_link(session, email_addr):
|
||||
return {'error': 'Failed to send magic link'}
|
||||
|
||||
sent_time = datetime.now(timezone.utc)
|
||||
callback_url = poll_imap_for_link(email_addr, password, sent_time)
|
||||
if not callback_url:
|
||||
return {'error': 'No magic link received'}
|
||||
|
||||
session.get(callback_url, allow_redirects=True)
|
||||
|
||||
s = session.get(f"{PARALLEL_BASE}/api/auth/session").json()
|
||||
if not s or 'user' not in s:
|
||||
return {'error': 'Session not established'}
|
||||
|
||||
result = create_org_and_get_key(session, org_name)
|
||||
if not result:
|
||||
return {'error': 'Failed to create org/get key'}
|
||||
|
||||
result['email'] = email_addr
|
||||
result['session_user'] = s['user']['email']
|
||||
return result
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description='Parallel.ai Auto-Registration')
|
||||
parser.add_argument('--count', type=int, default=1)
|
||||
parser.add_argument('--emails', type=str, default=EMAILS_FILE)
|
||||
parser.add_argument('--output', type=str, default=OUTPUT_FILE)
|
||||
parser.add_argument('--org-name', type=str, default='Research')
|
||||
args = parser.parse_args()
|
||||
|
||||
emails = load_emails(args.emails, limit=args.count)
|
||||
print(f"Loaded {len(emails)} unique emails from {args.emails}")
|
||||
|
||||
results = []
|
||||
for i, (email_addr, password) in enumerate(emails):
|
||||
print(f"\n[{i+1}/{len(emails)}] {email_addr}")
|
||||
try:
|
||||
result = register_one(email_addr, password, args.org_name)
|
||||
if 'api_key' in result:
|
||||
print(f" ✅ API Key: {result['api_key'][:30]}...")
|
||||
results.append(result)
|
||||
else:
|
||||
print(f" ❌ {result.get('error', 'Unknown error')}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Exception: {e}")
|
||||
|
||||
with open(args.output, 'w') as f:
|
||||
json.dump(results, f, indent=2)
|
||||
|
||||
if i < len(emails) - 1:
|
||||
time.sleep(3)
|
||||
|
||||
print(f"\n=== Done: {len(results)}/{len(emails)} keys → {args.output} ===")
|
||||
for r in results:
|
||||
print(f" {r['email']}: {r['api_key'][:40]}...")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user