// ═══════════════════════════════════════════════════════════════════ // Deep Iframe Inspector for Antigravity // ═══════════════════════════════════════════════════════════════════ // Usage: Paste this entire script into the AG Renderer DevTools console // (Ctrl+Shift+I → Console tab in the main workbench window) // // This script recursively inspects ALL iframes, webview elements, // and shadow DOMs to map the complete DOM tree including: // - iframe nesting depth and origin info // - webview elements and their executeJavaScript availability // - shadow DOM roots // - button inventory at each level // - Content Security Policy headers // - Cross-origin accessibility status // ═══════════════════════════════════════════════════════════════════ (function deepIframeInspector() { 'use strict'; const SEP = '─'.repeat(70); const results = []; let nodeCount = 0; function log(msg) { console.log('[DEEP-INSPECT] ' + msg); results.push(msg); } function indent(depth) { return ' '.repeat(depth); } // ── Inspect a single document context ── function inspectDocument(doc, depth, label) { nodeCount++; const id = `node_${nodeCount}`; const pfx = indent(depth); log(`${pfx}┌─ ${label} (depth=${depth})`); if (!doc) { log(`${pfx}│ ⛔ document is null/undefined`); log(`${pfx}└─ END ${label}`); return; } // Basic doc info try { log(`${pfx}│ URL: ${(doc.URL || doc.documentURI || 'unknown').substring(0, 120)}`); log(`${pfx}│ title: "${(doc.title || '').substring(0, 80)}"`); log(`${pfx}│ readyState: ${doc.readyState}`); log(`${pfx}│ domain: ${doc.domain || 'N/A'}`); } catch (e) { log(`${pfx}│ ⛔ Cannot read doc properties: ${e.message}`); } // CSP meta tags try { const cspMetas = doc.querySelectorAll('meta[http-equiv="Content-Security-Policy"]'); if (cspMetas.length > 0) { for (let i = 0; i < cspMetas.length; i++) { log(`${pfx}│ CSP[${i}]: ${(cspMetas[i].content || '').substring(0, 150)}`); } } } catch (e) {} // Count key elements try { const allEls = doc.querySelectorAll('*'); const buttons = doc.querySelectorAll('button'); const inputs = doc.querySelectorAll('input[type="button"],input[type="submit"]'); const anchors = doc.querySelectorAll('a[role="button"]'); const iframes = doc.querySelectorAll('iframe'); const webviews = doc.querySelectorAll('webview'); const divWithRole = doc.querySelectorAll('[role="button"]'); log(`${pfx}│ Elements: total=${allEls.length} buttons=${buttons.length} roleBtn=${divWithRole.length} iframes=${iframes.length} webviews=${webviews.length}`); // Dump ALL buttons (not just first 10) if (buttons.length > 0) { log(`${pfx}│ ── Buttons ──`); const maxShow = Math.min(30, buttons.length); for (let i = 0; i < maxShow; i++) { const b = buttons[i]; const txt = (b.textContent || '').trim().substring(0, 60); const cls = (b.className || '').substring(0, 50); const disabled = b.disabled ? ' [DISABLED]' : ''; const hidden = (b.hidden || !b.offsetParent) ? ' [HIDDEN]' : ''; const ariaLabel = b.getAttribute('aria-label') || ''; const title = b.getAttribute('title') || ''; log(`${pfx}│ btn[${i}]: "${txt}"${disabled}${hidden} class="${cls}" aria="${ariaLabel}" title="${title}"`); } if (buttons.length > maxShow) { log(`${pfx}│ ... +${buttons.length - maxShow} more buttons`); } } // Dump role="button" elements that aren't actual buttons if (divWithRole.length > 0) { log(`${pfx}│ ── role="button" elements ──`); const maxShow = Math.min(15, divWithRole.length); for (let i = 0; i < maxShow; i++) { const el = divWithRole[i]; if (el.tagName === 'BUTTON') continue; // skip actual buttons const txt = (el.textContent || '').trim().substring(0, 60); const tag = el.tagName.toLowerCase(); log(`${pfx}│ roleBtn[${i}]: <${tag}> "${txt}"`); } } // Recurse into shadow DOMs let shadowCount = 0; for (let i = 0; i < allEls.length; i++) { const sr = allEls[i].shadowRoot; if (sr) { shadowCount++; const tag = allEls[i].tagName.toLowerCase(); const cls = (allEls[i].className || '').substring(0, 40); inspectDocument(sr, depth + 1, `ShadowRoot of <${tag} class="${cls}">`); } } if (shadowCount === 0) { log(`${pfx}│ (no shadow DOMs found)`); } // Recurse into iframes for (let i = 0; i < iframes.length; i++) { const f = iframes[i]; const src = (f.src || '').substring(0, 120); const cls = (f.className || '').substring(0, 50); const id = f.id || ''; const sandbox = f.getAttribute('sandbox') || 'none'; const allow = f.getAttribute('allow') || ''; let fLabel = ` id="${id}" class="${cls}" src="${src}" sandbox="${sandbox}"`; try { const idoc = f.contentDocument || (f.contentWindow && f.contentWindow.document); if (idoc) { inspectDocument(idoc, depth + 1, fLabel + ' [ACCESSIBLE]'); } else { log(`${pfx}│ ${fLabel} → contentDocument=null`); // Try contentWindow info try { const cw = f.contentWindow; log(`${pfx}│ contentWindow exists: ${!!cw}`); if (cw) { log(`${pfx}│ contentWindow.length (sub-frames): ${cw.length}`); try { log(`${pfx}│ contentWindow.location: ${cw.location.href}`); } catch (e2) { log(`${pfx}│ contentWindow.location: ⛔ ${e2.message.substring(0, 60)}`); } } } catch (e2) {} } } catch (e) { log(`${pfx}│ ${fLabel} → ⛔ BLOCKED: ${e.message.substring(0, 80)}`); // Still try to get some info about the blocked iframe try { const cw = f.contentWindow; log(`${pfx}│ contentWindow exists: ${!!cw}`); if (cw) { log(`${pfx}│ contentWindow.length (sub-frames): ${cw.length}`); } } catch (e2) { log(`${pfx}│ contentWindow also blocked: ${e2.message.substring(0, 60)}`); } } } // Recurse into webview elements for (let i = 0; i < webviews.length; i++) { const wv = webviews[i]; const src = (wv.src || '').substring(0, 120); const cls = (wv.className || '').substring(0, 50); const partition = wv.getAttribute('partition') || ''; const preload = wv.getAttribute('preload') || ''; const nodeInteg = wv.getAttribute('nodeintegration') || ''; const nodeIntegSub = wv.getAttribute('nodeintegrationinsubframes') || ''; const webpref = wv.getAttribute('webpreferences') || ''; log(`${pfx}│ ── ──`); log(`${pfx}│ src: ${src}`); log(`${pfx}│ class: ${cls}`); log(`${pfx}│ partition: ${partition}`); log(`${pfx}│ preload: ${preload}`); log(`${pfx}│ nodeintegration: ${nodeInteg}`); log(`${pfx}│ webpreferences: ${webpref}`); // Try contentDocument try { const wdoc = wv.contentDocument; if (wdoc) { inspectDocument(wdoc, depth + 1, ` contentDocument [ACCESSIBLE]`); } else { log(`${pfx}│ contentDocument: null`); } } catch (e) { log(`${pfx}│ contentDocument: ⛔ ${e.message.substring(0, 60)}`); } // Check executeJavaScript availability log(`${pfx}│ executeJavaScript: ${typeof wv.executeJavaScript}`); if (typeof wv.executeJavaScript === 'function') { log(`${pfx}│ 🔑 executeJavaScript IS AVAILABLE — attempting probe...`); try { wv.executeJavaScript(` (function() { var btns = document.querySelectorAll('button'); var allEls = document.querySelectorAll('*'); var iframes = document.querySelectorAll('iframe'); var webviews = document.querySelectorAll('webview'); var btnTexts = []; for (var i = 0; i < btns.length; i++) { var txt = (btns[i].textContent || '').trim(); var disabled = btns[i].disabled ? ' [DISABLED]' : ''; var hidden = (btns[i].hidden || !btns[i].offsetParent) ? ' [HIDDEN]' : ''; var cls = (btns[i].className || '').substring(0, 40); btnTexts.push('"' + txt.substring(0, 50) + '"' + disabled + hidden + ' cls=' + cls); } // Also check for role=button var roleBtns = document.querySelectorAll('[role="button"]'); var roleBtnTexts = []; for (var j = 0; j < roleBtns.length; j++) { if (roleBtns[j].tagName !== 'BUTTON') { roleBtnTexts.push('<' + roleBtns[j].tagName.toLowerCase() + '> "' + (roleBtns[j].textContent || '').trim().substring(0, 40) + '"'); } } // Check for shadow DOMs var shadowCount = 0; for (var k = 0; k < allEls.length; k++) { if (allEls[k].shadowRoot) shadowCount++; } return JSON.stringify({ url: document.URL, title: document.title, totalElements: allEls.length, buttons: btns.length, buttonTexts: btnTexts.slice(0, 30), roleBtns: roleBtnTexts.slice(0, 15), iframes: iframes.length, webviews: webviews.length, shadowDOMs: shadowCount }); })() `).then(function(result) { try { const data = JSON.parse(result); console.log('[DEEP-INSPECT] 📦 webview#' + i + ' INTERNAL PROBE:'); console.log('[DEEP-INSPECT] URL: ' + data.url); console.log('[DEEP-INSPECT] title: ' + data.title); console.log('[DEEP-INSPECT] Elements: total=' + data.totalElements + ' buttons=' + data.buttons + ' iframes=' + data.iframes + ' webviews=' + data.webviews + ' shadowDOMs=' + data.shadowDOMs); if (data.buttonTexts.length > 0) { console.log('[DEEP-INSPECT] ── Buttons inside webview ──'); data.buttonTexts.forEach(function(t, idx) { console.log('[DEEP-INSPECT] btn[' + idx + ']: ' + t); }); } if (data.roleBtns.length > 0) { console.log('[DEEP-INSPECT] ── role="button" inside webview ──'); data.roleBtns.forEach(function(t, idx) { console.log('[DEEP-INSPECT] roleBtn[' + idx + ']: ' + t); }); } } catch (e) { console.log('[DEEP-INSPECT] raw result: ' + result); } }).catch(function(e) { console.log('[DEEP-INSPECT] ⛔ executeJavaScript FAILED: ' + e.message); }); } catch (e) { log(`${pfx}│ ⛔ executeJavaScript call threw: ${e.message}`); } } // Try getWebContentsId (Electron-specific) try { if (typeof wv.getWebContentsId === 'function') { log(`${pfx}│ webContentsId: ${wv.getWebContentsId()}`); } } catch (e) {} } } catch (e) { log(`${pfx}│ ⛔ Error during inspection: ${e.message}`); } log(`${pfx}└─ END ${label}`); } // ── Window hierarchy ── function inspectWindowHierarchy() { log(SEP); log('📐 Window Hierarchy'); log(SEP); log(`window.location.href: ${window.location.href}`); log(`window.location.origin: ${window.location.origin}`); log(`window.location.protocol: ${window.location.protocol}`); log(`window.frames.length: ${window.frames.length}`); log(`window === window.top: ${window === window.top}`); log(`window === window.parent: ${window === window.parent}`); log(`navigator.userAgent: ${navigator.userAgent.substring(0, 120)}`); // Check if we're in Electron try { log(`process.type: ${typeof process !== 'undefined' ? process.type : 'N/A'}`); log(`process.versions.electron: ${typeof process !== 'undefined' && process.versions ? process.versions.electron : 'N/A'}`); } catch (e) { log(`process info: N/A (${e.message.substring(0, 40)})`); } // Check webFrame (Electron renderer API) try { if (typeof require === 'function') { const { webFrame } = require('electron'); log(`webFrame available: ${!!webFrame}`); if (webFrame) { log(`webFrame.routingId: ${webFrame.routingId}`); } } } catch (e) { log(`electron.webFrame: N/A (${e.message.substring(0, 40)})`); } // Check webContents access via remote/electron try { if (typeof require === 'function') { const electron = require('electron'); const ipcRenderer = electron.ipcRenderer; log(`ipcRenderer available: ${!!ipcRenderer}`); } } catch (e) { log(`electron.ipcRenderer: N/A (${e.message.substring(0, 40)})`); } } // ── Main ── log(''); log('═'.repeat(70)); log(' DEEP IFRAME INSPECTOR — Antigravity DOM Analysis'); log(' Timestamp: ' + new Date().toISOString()); log('═'.repeat(70)); log(''); inspectWindowHierarchy(); log(''); log(SEP); log('📄 Document Tree (recursive)'); log(SEP); inspectDocument(document, 0, 'Main Document'); log(''); log(SEP); log(`✅ Inspection complete. ${nodeCount} document contexts inspected.`); log(SEP); // Summary log(''); log('📋 SUMMARY:'); log(' Copy all [DEEP-INSPECT] lines from this console'); log(' Webview executeJavaScript probe results will appear AFTER this summary (async)'); return results; })();