Skip to content

Instantly share code, notes, and snippets.

@imaman
Last active June 24, 2024 05:41
Show Gist options
  • Save imaman/cd7c943e0831a447b1d2b073ede347e2 to your computer and use it in GitHub Desktop.
Save imaman/cd7c943e0831a447b1d2b073ede347e2 to your computer and use it in GitHub Desktop.
iframe inspection w/o getFlattenedDocument()
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));
}
@trovdimi
Copy link

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!

@imaman
Copy link
Author

imaman commented Jan 31, 2022

IIUC, you can always iterate over all nodes in a document of an iframe and map them (via map.set()) to the frameId.

@Rabbitzzc
Copy link

great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment