Let's say I call window.alert('my message') in dart code. But what if (exactly my case) there is a script which did override alert function before my script. Now if I try to call window.alert('message') It executes overridden alert function instead of initial one.
Is there a mechanism to ensure that all functions are not overridden in described way? Or should I always make sure that dart script is the first to execute on page to ensure that no undesirable overrides are done and behavior is stable and it's the only way to go?
Here is basic github repo if you would like to see the issue live.
EDIT 1:
main.dart
import 'dart:html';
void main() {
window.alert('alert');
}
index.html
<html>
<head>
<title>test</title>
<script>
alert = (variable) => confirm("hehe it's jinxed");
</script>
<script defer src="main.dart.js"></script>
</head>
</html>
That does not sound possible.
If something "overrides" the JavaScript alert function, it actually overwrites the alert property of the window object. The old value is completely lost at that point, and it's not (easily) possible to even detect that this has happened.
If your code doesn't run first in a web browser, you can't protect yourself from this. If your code does run first, you can use Object.freeze or similar functionality to lock down the original properties, or take copies of them into your own variables. Simply running first is not a guarantee, if your code just uses window.alert directly later. You have to make an effort to prevent later code from overwriting it too.
This is really a JavaScript issue, there is nothing special about dart:html or Dart compiled code in this, it affects any JavaScript code which doesn't run first in a browser.
Related
I'm trying to mock the date on a CefSharp browser by injecting MockDate and setting it to some fixed date before every other script runs. Every window object, on any frame, at any time, should only have access to the mocked date, so the ideal would be to internally redefine the JavaScript Date object, but I don't think CefSharp or probably even Chromium has this option. I'm also going to mock some other functions like setTimeout and Math.rand, to prevent the browser from having any side effects (this is part of a larger project whose aim is to be able to record/replay browsing activity), so messing with OS's time wouldn't solve it.
I considered using RegisterJsObject since it can actually overwrite existing globals, but I don't think there is a way to pass a JavaScript constructor.
What I've tried so far is to handle the FrameLoadStart event:
private static string Inject = File.ReadAllText("Inject.js");
private void ChromeBrowser_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
{
e.Frame.ExecuteJavaScriptAsync(Inject);
}
Where "Inject.js" contains the mock date code. But I've noticed that, randomly, sometimes it'll work and sometimes it won't. I guess because the function is async and the javascript context sometimes haven't been created, since according to the documentations you shouldn't run scripts here. The documentation recommends handling OnContextCreated instead, but it only runs for the main frame, which wouldn't let me inject the code on any iframe. So I wonder if I have any alternative.
In case anyone else need this, the solution was to modify the actual C++ CefSharp code by adding a line to the end of CefAppUnmanagedWrapper::OnContextCreated:
frame->ExecuteJavaScript(CodeToInject, "something://something", 1);
This won't work if injected on the C# side, I believe because these calls are async so you may be injecting it too late, after scripts on the page have already run.
If you can edit HTML entry points then you can just add window.Date = MockDate before any other scripts. For example:
<html>
<body>
<script src="mockdate.js"></script>
<script>
window.Date = MockDate
</script>
<script src="myscript.js"></script>
</body>
</html>
So the idea is you can tune script loading order in your HTML. It can be done in any browser.
If you can not or do not want to edit HTML then it's much trickier. You could use CefLoadHandler in CEF C++ or its alternative in CefSharp.
UPD
Actually i'm not sure about CefLoadHandler. The reliable way would be to implement your own CefRenderProcessHandler But you already mentioned it. If it doesn't work then it's a bug in CefSharp or CEF C++ itself. In that case it would be better to write about it on http://magpcss.org/ceforum/
I'm wondering if it is possible to, in Java, detect whether or not an HTML file would open an alert dialog if opened in the browser. Preferably headlessly. For example, a file with the below contents were parsed, it would return true.
<html><script>alert("hey")</script></html>
and the below would return true also
<html><iframe src="javascript:alert(1)" onload="alert(2)"></iframe></html>
but the below would return false because it would not open an alert dialog if it were opened in the browser (because none of the code is syntactically correct, and the part that is isn't in a tag).
<html><script>alert;,(123w)</script>alert(1)</html>
I have thought of a way to approach this problem, but it is flawed. Basically, you see if the stringalert(1) is in the file, etc.
The problem with this is that it wouldn't work in cases where that code isn't inside of script tags or tags that make it execute. An example of where it wouldn't work is: The following would return true, even though it wouldn't actually open a popup <html>alert(1)</html>.
This isn't Android by the way. Appreciate your help!
You will need to not only verify if the Alert function is there but check if the JavaScript function would even run. An example of this is if there is a script with an Alert function inside a function that never runs. The Alert function would be there but it would never run. This would give a false positive. So the in the best case you should run the JavaScript in some way to validate the code and to see if the function would ever run.
As Louis pointed out in the comments Option 2 is better in this case as you will need to account for both the DOM and JavaScript's behaviour as both can change if the Alert function runs and how it runs.
Option 1 : Run the JavaScript with Script Engine
You would need some way of separating the HTML from the JavaScript but once you have that you can do this method.
You can run the JavaScript in Java using ScriptEngine. https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/api.html
If you read the API there is a way to create variables and communicate between your Java Program and the JavaScript you are Running.
To capture the context of the Alert you can create a custom JavaScript function that overwrites the Alert function. Inside this custom function you can send the arguments of the function back to your Java Program.
Option 2 : Headless Browser
You can also try to use a headless browser like JBrowserDriver and as you can see you have an Alert interface with getText as a function. For async issue the headless browser has a default amount of time for waiting for the script to complete. If this default amount is not enough you can use the setScriptTimeout to handle it.
http://machinepublishers.github.io/jBrowserDriver/
I stumbled upon this today and since I'm no browser guru or a web developer, it's possible I missed something rather obvious. Observe the simple HTML below:
<html>
<head>
<script>
function ping() {
console.log('pong');
}
</script>
</head>
<body>
Call ping
</body>
</html>
What I expected when clicking on the link is to have pong printed in the console. However, what I get in both Chrome and Firefox is "TypeError: ping is not a function". If I call the function directly from the console, it works. If I rename the ping function to anything else, it works. If I replace the "a" tag with, say, "button" tag, whilst leaving the function called ping, it works!
It seems that somehow, only in this specific combination: onClick of tag "a" with function called ping() results in the above error. Am I crazy or did I just discover the most insignificant bug in the world? If it is a bug, I find it very strange that it happens in both Chrome and Firefox, since they have different JavaScript engine implementation, different layout engine implementation etc.
Some tests I did show that inline event handlers have access to the element's attributes directly by name. So this happens if your function matches any valid attribute name (and ping seems to be a valid attribute in HTML5).
So your code is being interpreted as an attempt to issue a function call on "" (the value of ping), and fails. That only happens with inline event handlers, not if you use element.onclick=function(){... or addEventListener, so the problem can be avoided if you use one of those methods (they are recommended anyway, as inline handlers violate the principle of separation of concerns).
Added Attribute Ping
New ping attribute can be specified on a and area elements.
Issue: There are various methods for tracking clickthroughs on a link
for advertising or QA purposes. Many of which involve executing a
script (client-side or server-side) to perform tracking before
following a link. This obscures the destination of the link to the end
user, forces the UA to follow HTTP redirects before reaching the
destination, and/or requires Javascript to follow a hyperlink.
Read more at w3.org
so i guess that has something to do with.. ping being a string..
Call ping alerts string... :/
Please try following, onclick should be all small.
Call ping
Cheers !!
I am using the Prototype javascript framework. I have included it in a javascript code snippet that I allow people to copy and paste onto their websites. There is a possibility that their website already includes Prototype or they wanted to include the snippet multiple times. In both cases, Prototype will be defined twice and, as a result, IE7 will not function. It will say "Object does not support this property or method" on nearly any Prototype library function call. I tried this:
if (typeof(Prototype) === 'undefined') {
alert('including Prototype');
// minified Prototype code here
}
alert('running my code');
// all my code here
When I ran this, only "including Prototype" was alerted, but "running my code" never got alerted. Why?
only "including Prototype" was alerted, but "running my code" never got alerted. Why?
I don't know without seeing the code—do you get anything in the JavaScript error console?—but one possibility is that something in the code relied on being in an unadorned global scope. For example the function statement may not be used inside an if in standard ECMAScript. What actually happens if you try is browser-dependent, but typically it may override a previously-declared version of the function even if the if clause does not evaluate true.
This problem could be solved by putting Prototype in its own <script> block that's inserted into the page via DOM methods or document.write before the main script executes. However:
I have included it in a javascript code snippet that I allow people to copy and paste onto their websites.
Yeah, I really wouldn't do that. Using more than one wide-ranging, intrusive framework like Prototype or jQuery on a single page is a recipe for conflict and potentially hard-to-debug problems. (Same with two copies/versions of the same framework.)
When you are a pastable snippet you are a guest in another webmaster's house need to have as low a footprint as possible. IMO that means you should not use any framework.
I ask because I'm running an application in which I load an external script file in the HEAD section of the page, and then attempt to call a function from it in the onLoad section of the BODY tag.
external.js
function someFunction()
{
alert("Some message");
}
myPage.html
<html>
<head>
<script type="text/javascript" language="javascript" src="external.js"></script>
</head>
<body onLoad="someFunction();">
</body>
</html>
Using the developer tools in IE8, I get an exception thrown at the onLoad statement because, apparently, the external javascript file hasn't been loaded yet.
I haven't had this problem come up in IE7 before, thus my question.
Did they change the load order between IE7 and IE8? If so, is there a better way to do this? (the real function references many other functions and constants, which look much better in an external file)
Thanks,
B.J.
Well, I feel pretty stupid actually.
Turns out the problem wasn't with the load order. The problem was that the external javascript file had a syntax error in one of its functions, and apparently when the exception was thrown it completely invalidated the whole file, thus making the rest of the functions unavailable to the main page.
I'm not sure if this behavior is different in IE8 compared to IE7, but anyway, that was the real problem.
Thanks for your reply.
B.J.
I doubt very much that his has changed it would break a considerable number of websites.
Try this (without using the developer tools):-
<body onload="alert(somefunction)">
this shouldn't break and will tell you whether at the point onload executes whether the identifier somefunction can be seen.
Assuming that what you think is happening is what is happening, you should try to attach the body.onLoad later on.
To simplify things, you can do it with Prototype (including prototype, of course) with
Event.observe(window, 'load', function() { myFunction.init() });
or JQuery (including JQuery) with
$(document).ready(function(){
// Your code here...
});
I think there is a pure Javascript way to do this, but the problem is that the body element won't exist yet, so it's rough...
That said, I have had no problems running body onload in Javascript with IE8, and putting it right into the body tag, using external files. I'm going to test that right now out of curiosity, and I'll report back.
Edit: There's no problem doing the onload from an external file. However, while we're at it, you might want to get to know JQuery, Prototype or Scriptaculous :)