Compare commits
1 Commits
step35/595
...
step35/541
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0763a20d74 |
@@ -37,6 +37,12 @@ from glitch_patterns import (
|
||||
)
|
||||
|
||||
|
||||
|
||||
try:
|
||||
from playwright.sync_api import sync_playwright
|
||||
_PLAYWRIGHT_AVAILABLE = True
|
||||
except ImportError:
|
||||
_PLAYWRIGHT_AVAILABLE = False
|
||||
@dataclass
|
||||
class DetectedGlitch:
|
||||
"""A single detected glitch with metadata."""
|
||||
@@ -97,7 +103,7 @@ def generate_scan_angles(num_angles: int) -> list[dict]:
|
||||
]
|
||||
|
||||
|
||||
def capture_screenshots(url: str, angles: list[dict], output_dir: Path) -> list[Path]:
|
||||
def capture_screenshots(url: str, angles: list[dict], output_dir: Path, live: bool = False) -> list[Path]:
|
||||
"""Capture screenshots of a 3D web world from multiple angles.
|
||||
|
||||
Uses browser_vision tool when available; falls back to placeholder generation
|
||||
@@ -111,7 +117,7 @@ def capture_screenshots(url: str, angles: list[dict], output_dir: Path) -> list[
|
||||
|
||||
# Attempt browser-based capture via browser_vision
|
||||
try:
|
||||
result = _browser_capture(url, angle, filename)
|
||||
result = _browser_capture(url, angle, filename, live=live)
|
||||
if result:
|
||||
screenshots.append(filename)
|
||||
continue
|
||||
@@ -125,26 +131,83 @@ def capture_screenshots(url: str, angles: list[dict], output_dir: Path) -> list[
|
||||
return screenshots
|
||||
|
||||
|
||||
def _browser_capture(url: str, angle: dict, output_path: Path) -> bool:
|
||||
def _browser_capture(url: str, angle: dict, output_path: Path, live: bool = False) -> bool:
|
||||
"""Capture a screenshot via browser automation.
|
||||
|
||||
This is a stub that delegates to the browser_vision tool when run
|
||||
in an environment that provides it. In CI or offline mode, returns False.
|
||||
Uses Playwright to navigate to the URL and capture a screenshot.
|
||||
In live mode, this is required; otherwise, falls back to placeholder.
|
||||
|
||||
Args:
|
||||
url: Target URL to scan
|
||||
angle: Camera angle dict with yaw/pitch/label
|
||||
output_path: Where to save the screenshot
|
||||
live: If True, hard-fail when browser unavailable
|
||||
|
||||
Returns:
|
||||
True on success, False otherwise
|
||||
"""
|
||||
# Check if browser_vision is available via environment
|
||||
bv_script = os.environ.get("BROWSER_VISION_SCRIPT")
|
||||
if bv_script and Path(bv_script).exists():
|
||||
import subprocess
|
||||
cmd = [
|
||||
sys.executable, bv_script,
|
||||
"--url", url,
|
||||
"--screenshot", str(output_path),
|
||||
"--rotate-yaw", str(angle["yaw"]),
|
||||
"--rotate-pitch", str(angle["pitch"]),
|
||||
]
|
||||
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
return proc.returncode == 0 and output_path.exists()
|
||||
return False
|
||||
# Import check
|
||||
if not _PLAYWRIGHT_AVAILABLE:
|
||||
if live:
|
||||
raise ImportError(
|
||||
"browser automation requires playwright. Install with: pip install playwright && playwright install chromium"
|
||||
)
|
||||
return False
|
||||
|
||||
try:
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
page = browser.new_page(viewport={"width": 1280, "height": 720})
|
||||
page.goto(url, wait_until="networkidle", timeout=30000)
|
||||
page.wait_for_timeout(2000)
|
||||
|
||||
# Rotate camera if using custom angles (yaw/pitch in degrees)
|
||||
yaw = angle.get("yaw", 0)
|
||||
pitch = angle.get("pitch", 0)
|
||||
if yaw != 0 or pitch != 0:
|
||||
yaw_rad = yaw * (3.14159 / 180)
|
||||
pitch_rad = pitch * (3.14159 / 180)
|
||||
js = f"""
|
||||
(function() {{
|
||||
// Try common Three.js camera locations
|
||||
let cam = null;
|
||||
if (window.renderer && window.renderer.camera) cam = window.renderer.camera;
|
||||
else if (window.scene && window.scene.camera) cam = window.scene.camera;
|
||||
else if (window.camera) cam = window.camera;
|
||||
// Check for Three.js r125+ camera in renderer.info
|
||||
const canvases = document.querySelectorAll('canvas');
|
||||
for (const c of canvases) {{
|
||||
if (c.__three__ && c.__three__.camera) {{ cam = c.__three__.camera; break; }}
|
||||
}}
|
||||
if (cam) {{
|
||||
cam.rotation.set({pitch_rad}, {yaw_rad}, 0, 'YXZ');
|
||||
if (cam.updateMatrixWorld) cam.updateMatrixWorld();
|
||||
}}
|
||||
}})();
|
||||
"""
|
||||
page.evaluate(js)
|
||||
page.wait_for_timeout(500)
|
||||
|
||||
page.screenshot(path=str(output_path))
|
||||
browser.close()
|
||||
return output_path.exists()
|
||||
except Exception as e:
|
||||
if live:
|
||||
raise
|
||||
# Silent fail for automatic fallback
|
||||
return False
|
||||
|
||||
|
||||
def _generate_placeholder_screenshot(path: Path, angle: dict):
|
||||
"""Generate a minimal 1x1 PNG as a placeholder for testing."""
|
||||
png_data = (
|
||||
b"\x89PNG\r\n\x1a\n"
|
||||
b"\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01"
|
||||
b"\x08\x06\x00\x00\x00\x1f\x15\xc4\x89"
|
||||
b"\x00\x00\x00\nIDATx\x9cc\x00\x01\x00\x00\x05\x00\x01"
|
||||
b"\r\n\xb4\x00\x00\x00\x00IEND\xaeB`\x82"
|
||||
)
|
||||
path.write_bytes(png_data)
|
||||
|
||||
|
||||
def _generate_placeholder_screenshot(path: Path, angle: dict):
|
||||
@@ -524,6 +587,11 @@ Examples:
|
||||
help="Minimum severity to include in report",
|
||||
)
|
||||
parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
|
||||
parser.add_argument(
|
||||
"--live",
|
||||
action="store_true",
|
||||
help="Use live browser automation (requires playwright); falls back to placeholders if unavailable",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--threejs",
|
||||
action="store_true",
|
||||
@@ -555,7 +623,7 @@ Examples:
|
||||
|
||||
# Capture screenshots
|
||||
screenshots_dir = Path(f"/tmp/matrix_glitch_{scan_id}")
|
||||
screenshots = capture_screenshots(args.url, angles, screenshots_dir)
|
||||
screenshots = capture_screenshots(args.url, angles, screenshots_dir, live=args.live)
|
||||
print(f"[*] Captured {len(screenshots)} screenshots")
|
||||
|
||||
# Filter patterns by severity and type
|
||||
|
||||
Reference in New Issue
Block a user