Files
gravity_control/tools/deep_iframe_inspector.js

368 lines
15 KiB
JavaScript

// ═══════════════════════════════════════════════════════════════════
// 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 = `<iframe#${i}> 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}│ ── <webview#${i}> ──`);
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, `<webview#${i}> 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;
})();