Evaluate javascript on every dynamically loaded nested iFrames using Puppeteer - puppeteer

Before I start describing my problem I just want to give a heads-up that all the pages, iFrames etc. are hosted locally on my PC. And that I have used page.setBypassCSP(true) to temporarily disable any origin based restrictions.
Here we go, I have a webpage which embeds an iFrame and that iFrame may embed another one (and the list can go on...). Some of the deeper iFrames may be appended to the body of it's parent via Javascript e.g. document.body.appendChild inside a setTimeout(..., 3000) which kind of simulates a dynamic iframe load. I want to know what is the best way to evaluate a script source on all of these iFrames. I tried using page.on('framenavigated', ...) but this only works for the page's immediate child frame(s).
I tried recursively iterating through all the frames in the page using page.frames() but that only works for iFrames that are available at the time when the DOMContentLoaded event is fired.
I'm looking for a way to listen to all the framenavigated events fired by all the nested iFrames even for the ones that loaded dynamically at any point of time, after the page is loaded. Any pointers would be greatly appreciated.
UPDATE:
I have tried listening to events using page.on('frameattached', ...) and page.on('framedetached', ...) but that also doesn't let me list all iFrames.

Related

How do we get iframes to allow state changes to reflect in our components?

I'm building a component that uses an <iframe> to display another component. This component connects to an NGXS state which needs to reflect changes made to the state. After a lot of failures and testing I discovered the component will always only load the default settings of the state. I created a <button> to toggle a boolean and added an *ngIf to the <iframe> so I can force it to reload manually after trying things like this.Frame.(contentDocument || contentWindow).location.reload(true); didn't make any difference.
I created a stablitz app to demonstrate this issue however I think stackblitz blocks the use of <iframe>s in their platform so you might need to copy it into a local project to tinker with it. It's a simple app that shows the state outside of the <iframe> as well as inside with a button that toggles the <iframe> on and off so you can see how only the default values load after you update the value I have available for demonstration purposes. I'm not getting any type of errors and the issue isn't a matter of something being wrong with the code so I don't know what more to show that isn't in the stackblitz.
Does anybody know why and how <iframe>s do this and if there's a way around it? The only thing I can think to try is make a NestJS app to see if putting the data outside the app and making an API request from the component inside the <iframe> will be allowed, however I don't know why this issue is occurring to in turn know if that too won't be rejected for that same reason. How this can be handled?
The document running in an iframe is isolated from its host. They do not share memory- Angular does not provide a way to synchronize state between a host and an iframe on the page out of the box. The example is actually booting two Angular apps (one inside the frame and one outside). If you are using an iframe for security and isolation purposes, you'll need to devise a way to pass state between the host and the child via postMessage (and be aware that you are running two copies of your application). If this isn't for security/isolation, simply do not use an iframe to contain the child component.

Detect Javascript being disabled *after* page load

I have come across several posts about how to handle Javascript being disabled while/before the page is being loaded. However, is there any way to detect Javascript being disabled by the user after the page has loaded in order to hide content at the last minute?
Use a dead man switch on setInterval. If it doesn't trip the trigger, then you need to hide that content before the no javascript gremlins destroys it. How can you hide it without javascript? Have a competitive process going between CSS animations, and Javascript. Such that if javascript is not present the CSS animations (to hide the content), win out. And lo, the content waseth hiddeneth.
Attempt to an send an HTTP request to your server? If that ping doesn't arrive, javascript could be disabled.
Use a noscript tag to inform the user of various things in the event that javascript is disabled, such as the fact that the user has javascript disabled
Put a form in a noscript tag to ask a user to tell you that javascript is disabled, or otherwise to send feedback about their browsing experience to your site without javascript
Check if the UserAgent header contains Lynx?
You can find out if a particular user had disabled JS on his browser by using cookies. You can assume that your JS sets a cookie with some key-value pair like js-enabled=true
When the page gets loaded next time, if cookie does not contain js-enabled key then you know that JS is disabled on the page and server returns the content accordingly.
Now, your question:
After the page has loaded in order to hide content at the last minute?
Say even if you know JS is disabled on the browser, how will you hide the content. You again need JS to be executed to manipulate the DOM which is not possible I think when JS is disabled. So one of the solutions can be when your server knows that JS is disabled then return the page which does not have that content which you want to hide
There is a way to show a warning when javascript is disabled before loading: Write a div element with a warning that jscript is disabled and hide it with jscript while loading the webpage. It is not possible to show a warning when javascript is disabled, because javascript is needed to change any part of a webpage.
if your app can stand the hit of doing log checks - I would, say every minute or so, use ajax to call
the backend - which will then log a time. if the backend checks and the last log time is substantially off - then shut down the app.

Any way to read elements from another website in an iframe?

I'm playing around with some stuff and trying to discern if when using a cross-domain iframe(post_message) if I can read the elements: div-tag p-tag etc of site within the iframe? I haven't seen any other posts on this, so hopefully someone can provide some insight.
postMessage allows you to communicate with a cooperating iframe. To use it, one window must send a message with postMessage and the other window must have an event listener listening for the message and it must process that message and do whatever you want done with it.
So, it is possible to use postMessage to retrieve content from an iframe, even a cross-origin iframe, but it requires that there be code in the iframe that can receive the message, understand what is being asked of it and do postMessage back to the original frame with the information that was requested.
So, this means that if you control both the window and iframe javascript, you can do what you ask, but if you don't control one of the two and they don't already have the right javascript code in them to fetch the data you want, then you can't get the job done with postMessage. All it does is deliver messages. The code to process those messages must be put there by the owner of that particular web page.

Communication between two iframes from the same domain with postMessage

I have two iframes from the same domain, which are hosted in document from another domain. The problem is these iframes cannot communicate with each other through postMessage. I cant even access the DOM of iframe1 from iframe2 even though they belong to same domain. Is there any solution ????
I used following options to refer the required iframe.
parent.frame[x]
I tried following lines to access DOM of iframes
parent.frame[x].contentWindow returns null,
parent.frame[x].document.getElementsByTagName("body") returns null
Update:
I guess my question is not clear enough. There is no problem with postMessage api, the actual problem is browser creates a custom frameset around the iframe document, in my case!
So parent.frame[x] won't point to the iframe window, instead it points to the custom frameset inside the iframe window.
Following question explains the problem well.
Prevent browser from loading a custom frameset in an iframe's document
If you want cross-window same-domain communication, you can set it up via localStorage. When you add an item to localStorage, you get window "storage" event in all other windows / iframes / tabs of the same domain.
So, you basically localStorage.setItem('name', 'value') in one iframe while you listen to window.addEventListener('storage', (event) => {/* handle message */}) and you get the message.
Take a look at the following description of the postMessage function and how it could be used. So in frame1 you call the postMessage method and in frame2 you subscribe for notifications. Obviously the browser you are using must support this API.
There's also a very nice jQuery plugin which wraps this API and simplifies its usage. It also works in browsers that do not support the postMessage method by using the hash portion of the url.

Continuous playing swf on Static Website

I have a music player swf embedded on an html page. Is there any way to have the music continuously play, even when the different html pages are loaded? When a link is clicked, the page is refreshed, also restarting the swf(music).
If the site was AJAX driven, this wouldn't be a problem, but all my pages are static. I suppose I could put the entire body in an iframe, but there has to be a better option. I am certainly open to the idea of using ajax here, but I do not have much ajax experience. Any ideas?
Ajax is really not that hard to learn, use it.
If you reload another page or the same page with a normal link, you will lose your current status in your embedded player. So you either have to use a non-standard link-mechanism, separate your player from the page or save your current status on change of the page. Your options basically are:
Use Ajax and never actually load a new page, but only new content (<- best solution, imho)
Use the standard link mechanism, but do it in an iframe, the player runs in a parent page (I agree with you, that wouldn't be nice)
Load the player in a new Window, put it in the background or something. This might be better than the iframe-solution, but you might get some difficulties with popup-blockers. Remember to close your popup when the user leaves your page.
Save the status of the player in a cookie whenever a link is clicked. On pageload check for the cookie and continue playing at the saved position. This will result in small breaks during playback and you need to be able to interact with the music player.