I am currently rewriting a firefox extension to be used only internally at my company. I started out by moving most of the logic into an external js file loaded via a script tag within the xul overlay. (We've found it hard to get our employees to consistently upgrade so I thought I could get around that). It worked fine like this:
<overlay id="my-overlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<script type="application/x-javascript" src="https://my.company.com/path/to/jquery.min.js/>
<script type="application/x-javascript" src="https://my.company.com/path/to/toolbar/main.js"/>
<toolbox id="navigator-toolbox">
<!-- some stuff here -->
</toolbox>
But then I had the crazy idea of loading the script file dynamically so that I could use preferences to determine whether it would load from the production servers or alpha/beta servers. And that's when I failed miserably.
I've tried the following unsuccessfully:
$.ajax({ dataType: 'script', ... }) // appears to do absolutely nothing
$('overlay').appendChild('', { src: ... }) // script tag is added but not executed
document.createElementNS, etc // script tag is is added but not executed
Components.utils.import // does not accept http protocol
mozIJSSubScriptLoader // does not accept http protocol
I haven't attempted Components.utils.evalInSandbox but given its restrictions, I'm afraid it would require significant other code changes that would not be worth the slight simplification of the development cycle.
From reading thru much more mozilla documentation and bugs it appears that basically what I'm attempting to do is breaking various security concerns (I understand in principle but of course in my case, I have full control of both ends).
The thing that bothers me is that it appears to work fine as long as I hard code the script tag but only fails once I try to dynamically generate it. Should I just toss in the towel or does someone know a way to make this work?
Have you tried the brute-force approach of reading in the file using XMLHttpRequest and then just calling eval() to run it? On the face of it this seems scary from a security perspective but, as you say, using a script tag with an HTTP source URL is basically the same thing.
Related
For seven years I have been programming small websites for offline and private use. Each of these projects consists of an html file, linking to a css file, and a javascript file. The latter uses AJAX to load content from a .txt file and displays it flexibly on the html site. The files (.html, .css, .js, .txt) are in the same folder on my local hard disk and I open the html file locally in my browser. I have been using this setting successfully for writing own small encyclopedias, vocabulary trainers, games etc.
However, it does not work any longer. AJAX does not load the text file contents. (I know that because I inserted the Javascript/AJAX code directly in the html file and it still didn't work.) Moreover, HTML does not connect with the .js file. (I know that because I inserted the text contents directly as variable in the Javascript file and it still didn't work.) Only if I combine both steps (i.e. inserting Javascript code in the html file and inserting the text contents as variable), it works. Then, all but CSS is in one html file. This is however not feasible as the file gets very confusing and editing the text contents is hardly possible.
The problem started about half a year ago when I updated my Firefox. First, I thought the browser has changed some security settings in order not to allow an html file to link to a javascript. But I didn't find respective settings. Then, I tried with other browsers. Chrome, Edge and the old IE reacted the same way. I confess that I didn't try Opera, Safari and other browsers, however, the ones I tried already represent a certain variety. I tried different computers, but my once succesfull web sites failed. It felt like as the setting had never worked, but it has worked perfectly for many years. As such code is taught in popular courses such as W3 Schools, it should work. I had not changed anything of the code. So, I wondered whether this feature had been removed globally for any security reasons. But if so, the most simple processes of the world wide web would not work any longer. This is obviously not the case. A simple html file linked to a javascript code using AJAX is one of the most basic features of web programming, isn't it? Thus, there seems to be an error or cause which I cannot find.
I have been waiting and trying all solutions I could think of, but it seems there is only one way to get out of this dead end: Asking you, dear programmers. I think many of you have much more experience than me, as I know only very basic issues of web design. I would be thankful if you can let me know in case you can think of any cause and/or solution for my problem.
For easier understanding, I give here the basic sample code which is almost the same in all my projects:
This is the address (please look at the last two characters):
file:///C:/MyProgrammes/SampleProgramme/Site.html?1
This is the Site.html file:
<!DOCTYPE html>
<html>
<head>
<link href="Design.css" rel="stylesheet"/>
<script src="Programme.js"></script>
</head>
<body>
<div id="ShowResult"></div>
</body>
</html>
This is the Programme.js file:
var List; // this variable is defined globally here
var GetContent = new XMLHttpRequest(); // start of AJAX, receivinig contents of the txt file
GetContent.open('GET','Contents.txt',true);
GetContent.send();
GetContent.onreadystatechange = function () {
if (GetContent.readyState == 4) {
List = GetContent.responseText.split("\n");
}
} // end of AJAX
document.getElementById('ShowResult').innerHTML = List[1];
This is a sample of the Contents.txt file:
Grass is green.
The sky is blue.
Clouds are white.
Furthermore, there is a Design.css file which still works the usual way.
Now, I expect the screen to display "The sky is blue.". It worked perfectly, but now it doesn't. Please help me if you know a solution!
Best regards,
Johannes
This looks like it is probably a result of security fix referenced at the below:
https://www.mozilla.org/en-US/security/advisories/mfsa2019-21/#CVE-2019-11730
A disussion on the subject at:
https://bugzilla.mozilla.org/show_bug.cgi?id=1566051
suggests you now need to explictly enable reading of local files by setting:
privacy.file_unique_origin preference
I'm working on small .js which is going to be embedded on multiple websites, it will be loaded in a classic way - via script tag: <script src="myscript.js"></script> in sites body tag. I cannot add any more scripts to those sites.
I would like to track errors with error tracker such as Sentry, Rollup or HoneyBadger. However, all of them require being loaded with another script tag, most preferred before everything else.
Note: Those services need to load before everything else to catch errors property.
As I cannot add another script tag in the site's code, I need to execute their code inside my script, but before my actual script code.
I tried taking the content of HoneyBadger javascript library and putting it directly inside my file - it worked, however, I feel like it's terrible practice, as their code is written with modern browsers in mind, and mine supports older ones.
Is there any good way in my situation to load their .js externally?
I don't think that would work because of the way honeybadger.js v0.5 parses the script tag to get those attributes--it looks for the script tag in the dom when it's loaded.
Also, we've moved away from using the data- attributes in honeybadger.js v1.0, which was just released. In that version, you must use Honeybadger.configure to set your API key. Take a look at the new docs here:
https://docs.honeybadger.io/lib/javascript/integration/browser.html
I'd recommend going with v1.0, and using Honeybadger.configure for the configuration.
Website that use JS tracking usually use this kind of code :
<script>
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:9999,hjsv:5};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'//static.hotjar.com/c/hotjar-','.js?sv=');
</script>
In the end, those scripts just add a <script> tag to the <head> of the page, so surely there must be a reason why they're doing it this way.
Is it for ad-blocking bypass reasons ? Wouldn't the generated request be the same as if it was hardcoded in the <head> ?
I'm the chief architect at Hotjar so I'll explain the reasons why we did it in this particular way.
We need to do things before the main script is loaded.
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
That particular line allows us to store actions to execute once the main script is loaded. It allows for things like hj('trackVirtualPageView', '/url') to be called before our script is loaded.
We can store things like settings as part of the snippet.
h._hjSettings={hjid:9999,hjsv:5};
That could absolutely be added as part of the query string when loading the script. The downside of using that approach is that we would get less optimal caching since it would be impossible for a browser to know that script.js?hjid=1 and script.js?hjid=2 actually loads the same JS file.
What we're doing in the last part is actually just creating a <script async=1> tag and adding it to the <head> which works really well. The reason we're doing it through JS is that we like to make it as easy as possible for our users by only asking them to put code in one place.
There might be an even better to do what we're doing which I'm blissfully unaware of, and in case there is, please reach out and tell me about it! :)
At least part of the answer is that vendors want to load their libraries in a way that does not block page rendering.
If the browser hits a script element it tries to get the script source, and might prevent the page from rendering until the complete script is downloaded. In the bad old days it used to happen that website would show up blank, because the (then synchronous) Google Analytics script could not be downloaded in a timely fashion and stopped the page from rendering. Script injection became an accepted method to make scripts non-blocking.
There are other ways (defer, asynch, etc - for historical interest here is a link to an 2009 article that discusses the issue, because the problem is that old), but script injection is a convenient way to set up a few variables along the way (plus if Google does it it must be the best way, or so seems to be the though process with some companies).
I'm not a full-time Javascript developer. We have a web app and one piece is to write out a small informational widget onto another domain. This literally is just a html table with some values written out into it. I have had to do this a couple of times over the past 8 years and I always end up doing it via a script that just document.write's out the table.
For example:
document.write('<table border="1"><tr><td>here is some content</td></tr></table>');
on theirdomain.com
<body>
....
<script src='http://ourdomain.com/arc/v1/api/inventory/1' type='text/javascript'></script>
.....
</body>
I always think this is a bit ugly but it works fine and we always have control over the content (or a trusted representative has control such as like your current inventory or something). So another project like this came up and I coded it up in like 5 minutes using document.write. Somebody else thinks this is just too ugly but I don't see what the problem is. Re the widget aspect, I have also done iframe and jsonp implementations but iframe tends not to play well with other site's css and jsonp tends to just be too much. Is there a some security element I'm missing? Or is what I'm doing ok? What would be the strongest argument against using this technique? Is there a best practice I don't get?
To be honest, I don't really see a problem. Yes, document.write is very old-school, but it is simple and universally supported; you can depend on it working the same in every browser.
For your application (writing out a HTML table with some data), I don't think a more complex solution is necessary if you're willing to assume a few small risks. Dealing with DOM mutation that works correctly across browsers is not an easy thing to get right if you're not using jQuery (et al).
The risks of document.write:
Your script must be loaded synchronously. This means a normal inline script tag (like you're already using). However, if someone gets clever and adds the async or defer attributes to your script tag (or does something fancy like appending a dynamically created script element to the head), your script will be loaded asynchronously.
This means that when your script eventually loads and calls write, the main document may have already finished loading and the document is "closed". Calling write on a closed document implicitly calls open, which completely clears the DOM – it's esentially the same as wiping the page clean and starting from scratch. You don't want that.
Because your script is loaded synchronously, you put third-party pages at the mercy of your server. If your server goes down or gets overloaded and responds slowly, every page that contain your script tag cannot finish loading until your server does respond or the browser times out the request.
The people who put your widget on their website will not be happy.
If you're confident in your uptime, then there's really no reason to change what you're doing.
The alternative is to load your script asynchronously and insert your table into the correct spot in the DOM. This means third parties would have to both insert a script snippet (either <script async src="..."> or use the dynamic script tag insertion trick. They would also need to carve out a special <div id="tablegoeshere"> for you to put your table into.
Using document.write() after loading the entire DOM do not allow you to access DOM any further.
See Why do I need to use document.write instead of DOM manipulation methods?.
You are in that case putting away a very powerfull functionnality of in web page...
Is there a some security element I'm missing?
The security risk is for them in that theirdomain.com trusting your domain's script code to not do anthing malicous. Your client script will run in the context of their domain and can do what it likes such as stealing cookies or embedding a key logger (not that you would do that of course). As long as they trust you, that is fine.
I have problem to get .load() function working in Wordpress. Initially I was using 3.0.5 version of WP, wanted to get some content from external page (same domain), so I used this code
jQuery.noConflict();
jQuery(document).ready(function(){
jQuery(".someclass").load("http://www.mydomain.com #someid");
});
...and it worked. However, after update of Wordpress to latest version (and installation of plugins /some use jquery or mootools/, this piece of code isnt pulling any content anymore. I tried to write different code for noConflict mode but also without success (but JS is working if I change line to some alert func). I also deactivated all plugins, removed other js (like for menu), but still no content was displayed. If I use same code in a separate file (in the same directory where WP theme is) - it works.
I would be thankful if someone have advice what to try next or where to look for potential problem. Or maybe to suggest some other approach how to get content from external page (and specific div). If I put that separate file into iframe and call it within sidebar, it's working but then there's a problem of iframe links opening within iframe box.
Your problem is the same origin policy, which in lamens terms means you can't do ajax requests to different domains (even subdomains) as it is security risk, you browser simply won't let you do it. Specifically in your case you are attempting to load www.infostar.rs from inforstar.rs.
You will need to come up with another idea, personally I would just do it in PHP with:
echo file_get_contents('http://domain.com');
Alternatively would could look into forcing non-www in htaccess.