fix: object URL leak, CDP before goto, limit raw secrets in extract
- AuthCaptureDialog: revokeObjectURL on each frame to prevent memory leak - CDP Network capture starts before initial page.goto, not after - /extract defaults to candidates-only; pass ?include_raw=true for full data
This commit is contained in:
@@ -89,12 +89,13 @@ async def create_capture_session(
|
||||
@router.get("/sessions/{session_id}/extract", response_model=CaptureExtractResponse)
|
||||
async def extract_credentials(
|
||||
session_id: str,
|
||||
include_raw: bool = Query(default=False, description="Include full cookies/storage/headers in response"),
|
||||
_=Depends(get_current_user),
|
||||
):
|
||||
"""Extract all auth credentials from the browser session.
|
||||
"""Extract auth credentials from the browser session.
|
||||
|
||||
Returns cookies, localStorage, sessionStorage, and curated candidates.
|
||||
Candidate values are masked in logs.
|
||||
By default only returns curated candidates (typed, scored, with masked preview).
|
||||
Pass include_raw=true to also get full cookies, localStorage, and headers.
|
||||
"""
|
||||
try:
|
||||
session = browser_sessions.get_session(session_id)
|
||||
@@ -106,6 +107,9 @@ async def extract_credentials(
|
||||
except Exception as exc:
|
||||
raise _browser_error(exc)
|
||||
|
||||
if not include_raw:
|
||||
# Strip raw data — only keep curated candidates
|
||||
return CaptureExtractResponse(candidates=result.get("candidates", []))
|
||||
return CaptureExtractResponse(**result)
|
||||
|
||||
|
||||
|
||||
@@ -387,10 +387,11 @@ class BrowserSessionService:
|
||||
captured_headers=[],
|
||||
)
|
||||
self._sessions[session.id] = session
|
||||
# Start CDP network capture BEFORE the initial page load,
|
||||
# so we capture login redirects and auth headers from the start.
|
||||
await self._start_cdp_capture(session)
|
||||
try:
|
||||
await page.goto(url, wait_until="domcontentloaded", timeout=45000)
|
||||
# Start CDP network capture immediately — so we don't miss login requests
|
||||
await self._start_cdp_capture(session)
|
||||
except Exception:
|
||||
await self.close(session.id)
|
||||
raise
|
||||
|
||||
@@ -180,6 +180,7 @@ const frameRef = ref<HTMLElement | null>(null)
|
||||
let ws: WebSocket | null = null
|
||||
let pointerDown = false
|
||||
let frameW = 1; let frameH = 1 // natural dimensions of the frame
|
||||
let prevFrameUrl = '' // previous blob URL to revoke
|
||||
|
||||
// ——— Launch ———
|
||||
|
||||
@@ -212,11 +213,11 @@ function connectWs() {
|
||||
|
||||
ws.onmessage = (evt) => {
|
||||
if (evt.data instanceof ArrayBuffer) {
|
||||
// Binary JPEG frame
|
||||
// Binary JPEG frame — revoke previous to avoid memory leak
|
||||
if (prevFrameUrl) URL.revokeObjectURL(prevFrameUrl)
|
||||
const blob = new Blob([evt.data], { type: 'image/jpeg' })
|
||||
frameUrl.value = URL.createObjectURL(blob)
|
||||
// Revoke previous URL after a tick to free memory
|
||||
setTimeout(() => { /* old URL auto-revoked */ }, 100)
|
||||
prevFrameUrl = URL.createObjectURL(blob)
|
||||
frameUrl.value = prevFrameUrl
|
||||
} else {
|
||||
// JSON message (init, error, etc.)
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user