Last active
June 24, 2024 05:41
-
-
Save imaman/cd7c943e0831a447b1d2b073ede347e2 to your computer and use it in GitHub Desktop.
iframe inspection w/o getFlattenedDocument()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const CDP = require('chrome-remote-interface'); | |
const chromeLauncher = require('chrome-launcher'); | |
const util = require('util'); | |
// cdp.js: a playground for using chrome-devtools-protocol. | |
// Plug-in your own code at the run() function, below. | |
// | |
// Usage: | |
// $ node scripts/cdp.js | |
// | |
// This program requires node version >= 8. | |
async function launch(action) { | |
let chrome; | |
try { | |
chrome = await chromeLauncher.launch({}); | |
console.log(`Chrome debugging port running on ${chrome.port}`); | |
return await action(chrome.port); | |
} finally { | |
if (chrome) { | |
await chrome.kill(); | |
} | |
} | |
} | |
async function onLaunched(port) { | |
let client; | |
try { | |
client = await CDP({port}); | |
return await run(client, port); | |
} finally { | |
if (client) { | |
await client.close(); | |
} | |
} | |
} | |
async function main() { | |
return await launch(onLaunched); | |
} | |
async function show(x) { | |
console.log(JSON.stringify(x, null, 2)); | |
return x; | |
} | |
/** | |
* Your custom business logic goes in here. | |
* @returns {*} whatever is returned from this method will be console.log()-ed by the caller. | |
*/ | |
async function run(client, port) { | |
const { Page, DOM, Target } = client; | |
await DOM.enable(); | |
await Page.enable(); | |
await Page.navigate({ url: 'http://jsbin.testim.io/wem' }); | |
await Page.loadEventFired(); | |
const nodeA = await findElementInIframe(DOM, 'iframe[src="http://jsbin.testim.io/gev"]', 'input[type="file"]'); | |
console.log(JSON.stringify(nodeA, null, 2)); | |
const nodeB = await findElementInCrossDomainIframe(port, DOM, Target, 'iframe[src="https://imaman.github.io/upload.html"]', 'input[type="file"]') | |
console.log(JSON.stringify(nodeB, null, 2)); | |
} | |
async function findElementInIframe(DOM, iframeSelector, elementSelector) { | |
const doc = await DOM.getDocument({depth: 0}); | |
const iframeQueryResult = await DOM.querySelector({nodeId: doc.root.nodeId, selector: iframeSelector}); | |
const iframeDescription = await DOM.describeNode({nodeId: iframeQueryResult.nodeId}); | |
const contentDocRemoteObject = await DOM.resolveNode({backendNodeId: iframeDescription.node.contentDocument.backendNodeId}); | |
const contentDocNode = await DOM.requestNode({objectId: contentDocRemoteObject.object.objectId}); | |
const elementQueryResult = await DOM.querySelector({nodeId: contentDocNode.nodeId, selector: elementSelector}); | |
return await DOM.describeNode({nodeId: elementQueryResult.nodeId}); | |
} | |
async function findElementInCrossDomainIframe(port, DOM, Target, iframeSelector, elementSelector) { | |
const doc = await DOM.getDocument({depth: 1}); | |
const iframeQueryResult = await DOM.querySelector({nodeId: doc.root.nodeId, selector: iframeSelector}); | |
const iframeDescription = await DOM.describeNode({nodeId: iframeQueryResult.nodeId}); | |
if (iframeDescription.node.contentDocument) { | |
throw new Error('oops. probably same domain'); | |
} | |
// This call is important. Without it, the creation of a new CDP which attached to the iframe | |
// (as its target) will fail. | |
await Target.getTargets(); | |
let client2; | |
try { | |
client2 = await CDP({port, target: iframeDescription.node.frameId}); | |
const DOM2 = client2.DOM; | |
const doc2 = await DOM2.getDocument({depth: 1}); | |
const elementQueryResult = await DOM2.querySelector({nodeId: doc2.root.nodeId, selector: elementSelector}); | |
return await DOM2.describeNode({nodeId: elementQueryResult.nodeId}); | |
} finally { | |
if (client2) { | |
client2.close(); | |
} | |
} | |
} | |
if (require.main === module) { | |
main() | |
.then(x => console.log('Output:\n' + x)) | |
.catch(e => console.error('Error: ', e)); | |
} |
IIUC, you can always iterate over all nodes in a document of an iframe and map them (via map.set()
) to the frameId.
great!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
This is a great gist!
I was wondering if there is a way to map a Dom.NodeId to a Page.FrameId. My goal would be to, later on, intercept all requests made by an iframe using Network.requestWillBeSent. I tried using Page.getFrameTree, but somehow it is not returning all iframes found in the DOM.
Thanks in advance!