How to escape initial json data in jade? - javascript

I use nodeJS/express as the backend and jade as a template engine. My Javascript part required some variables from the server. Generally, this can be done like this:
script(type='text/javascript').
var user = !{JSON.stringify(userObject)};
All works fine except the case when userObject has <script>[some text]</script> block. Please don't ask why this block appears in userObject because this is an internal thing and I just want to handle this case.
Because of the fact that the Javascript parser executes earlier than the HTML parser my embedding gets broken with the error:
<script>
var user = {
name: 'Erik',
about: '<script>about me</script>'
};
</script>
Uncaught SyntaxError: Invalid or unexpected token
The error happens due to the about me</script> line because it closes the main <script> tag.
So my question is: what is proper way to handle this error?

If you don't want to add an endpoint and do a GET request to it for the data, there are two more crude solutions. Note that these are kludgey hacks. I still think the best way to solve this is with an AJAX request to an API endpoint with the required data within the <script> tag.
1) Have functions that strip out the < and > characters and apply them before and after.
E.g. In the Express endpoint:
function replaceTags(aboutSection) {
aboutSection = aboutSection.replace(/</g, '%StartBracket%');
aboutSection = aboutSection.replace(/>/g, '%CloseBracket%');
return aboutSection;
}
In the client side code:
function undoReplace(aboutSection) {
aboutSection = aboutSection.replace(/%StartBracket%/g, '<');
aboutSection = aboutSection.replace(/%CloseBracket%/g, '>');
return aboutSection;
}
I'm using regex with the g tag to make sure everything, not just the first instance, is replaced.
2) If you don't need the about section, you could delete it before passing it to the endpoint.

Related

How do I get a JS script to parse raw JSON from a file?

I have a really simple JSON data file with no kind of wrapping, e.g.:
[{"name:","fakename"}, {"lang:", "javascript"}]
I'm trying to use this data in a js script in the same directory. I'm reading in both files in the document <head>, like such:
<script id="myJSON" src="data.json"></script>
<script src="myScript.js"></script>
and then the part I'm stuck on is how to get myScript to SEE that JSON data. In the script I can do:
d = document.getElementById("myJSON");
console.log(d);
The script returns the DOM element "myJSON" but I don't know how to access its JSON contents. I figured it would be a property like 'text' or 'value' or 'innerHTML' but I don't see it anywhere. I've tried various combinations of the type attribute in the tag but none of that makes any difference.
I know I could use an API like fetch but that's more complexity than I want. My best idea so far is to edit the json file to put an identifier at the beginning of the json file, like var myJSON = '[{"json"}]'; so then myScript would have a clear handle to JSON.parse(myJSON). But that's an extra step in an automated process which I don't want (or think I need).
How do I get my JS to see this "anonymous" JSON?
If you don't want to use fetch, you could use the server side code (PHP, ASP, etc) to write the text of the JSON into a hidden div in the page, and then you could use getElementByID to get the text, followed by parse to get an object that represents the JSON data.
This was not that much extra code but it was kind of a pain to wrap my head around. I had to wrap everything in a .then clause of fetch, or of an async function which called fetch. Here's what my code ended up looking like.
readJSONFile().then(jq => {
for (i = 0; i < jq.length; ++i) {
console.log( jq[i].myJSONKey )
});
async function readJSONFile() {
const response = await fetch('data.json');
const jq = await response.json();
return jq;
}

403 Forbidden while sending data from JavaScript

It is neither issue of file permission nor existence of file.
While sending formData through jquery data is passing successfully, but when I try with pure javascript then it returns error POST 403(Forbidden).
It is sure that problem is generated from ckeditor content. because if I pass following parameters
var heading = document.getElementById('heading').value;
var date = document.getElementById('date').value;
And pass as follow
http.send('heading='+heading+'&date='+date);
It returns no error, works fine.
But if I add following parameters
var content = CKEDITOR.instances.editor.getData();
And pass as follow
http.send('heading='+heading+'&date='+date+'&content='+encodeURIComponent(content));
It returns error.
POST 403(Forbidden)
I think special characters that are inserted in textarea are the cause of problem. Because if variable content is empty there would no error. Jquery is passing data, but why forbidden issue while using javascript ? I need to pass special characters without escaping. Because I can't control ckeditor output, becuase it is user input.

Accessing a Javascript variable inside an HTML file

I'm doing a little bit of reverse engineering on the Rapportive API in Gmail.
I make this request
import requests
url ='https://api.linkedin.com/uas/js/xdrpc.html'
r = requests.get(url)
print r.text
The response is an empty HTML file that has a lot of Javascript in it. On line 3661, it sets the RequestHeader for the subsequent call to Rapportive:
ak.setRequestHeader("oauth_token", ae);
Is there a way I can request that page and then return ae?
I think you can try:
Get the page as you already does;
Remove all non-javascript elements from the response page;
Prepend a javascript (described below) in the page's javascript to override some code;
Execute it with eval('<code>');
Check if the token has been set correctly;
I'm proposing the following code to override the XMLHttpRequest.setRequestHeader functionality to be able to get the token:
// this will keep the token
var headerToken;
// create a backup method
XMLHttpRequest.prototype.setRequestHeaderBkp =
XMLHttpRequest.prototype.setRequestHeader;
// override the "setRequestHeader" method
XMLHttpRequest.prototype.setRequestHeader = function(key, val)
{
if ('oauth_token' === key)
headerToken = val;
this.setRequestHeaderBkp(key, val);
}
If you are just interested in retrieving the token can't you just do a regex match:
var str = '<script>var a = 1;...ak.setRequestHeader("oauth_token", ae);...</script>';
var token = str.match(/setRequestHeader\("oauth_token",\s*([^)]+)/)[1];
Although this assumes ae is the actual string value. If it's a variable this approach wouldn't work as easily.
Edit: If it's a variable you could do something like:
str.replace(/\w+\.setRequestHeader\([^,]+,\s*([^)]+)\s*\);/, 'oauthToken = \1';
Before running the JavaScript returned from the page, then the global oauthToken (notice the missing 'var') will contain the value of the token, assuming the the evaluation of the code is run in the same scope as the caller.

Cannot set property of undefined -- inserting text with javascript

I am currently trying to insert some text in a specific spot at a website, http://kawowii.com , however, I keep getting error messages. These error messages seem to originate from the section I am trying to select using javascript (variables txtClasses and styleClasses). The error messages are
Uncaught TypeError: Cannot set property 'textContent' of undefined
So, the variables seem to be undefined but I don't understand why. I have looked at the other answers and still cannot determine what is wrong.
Right now, I have
window.onload = function() {
var txtClasses = document.querySelectorAll("div.coord-control.leaflet-control");
txtClasses[0].textContent = "Server: UP Location:"
}
and I tried this
window.onload = function() {
var styleClasses = document.querySelectorAll(".coord-control leaflet-control");
function insertAfter1(referenceNode, newNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
var brk = document.createElement("br");
insertAfter1(styleClasses[0], brk);
var div = document.createElement("div");
var textNode = document.createTextNode("Server: UP")
div.appendChild(textNode);
insertAfter1(brk, div);
}
My end goal is to change the website, kawowii.com , such that before Location :, it reads Server: UP using javascript.
I executed document.querySelectorAll("div.coord-control.leaflet-control"); on the website you provided, and it does in fact show an array with that element.
I think div.coord-control.leaflet-control is being inserted dynamically (perhaps after an AJAX request completes).
Therefore, you need to put your controlling logic inside the callback of the request:
whateverRequestIsInsertingThatElement.then(function() {
var txtClasses = document.querySelectorAll("div.coord-control.leaflet-control");
txtClasses[0].textContent = "Server: UP Location:"
});
I don't know if you're using promises or if the async method you're using provides a callback, but onload will happen in parallel with your async request, so you need to query for the dynamic element in the callback of the async request.
Not sure which API you're using to generate the map on your website, but usually any calls for location data will happen asynchronously (like the Google Maps API, for example). You can only manipulate dynamically generated DOM elements once the data has arrived.
Edit
You can see that the client is initially getting the configuration data from the route up/configuration. I would suggest looking for where that async call is being made in your source code, and then call querySelectorAll in its success handler.
I also see that in some of your sources, $.ajax is being called, so I assume somewhere in there, $.ajax is being called to the up/configuration route on your server.
So what I imagine happening is this:
You are querying your page for a your leaflet control but its returning an array of nothing. So when you try and access txtClasses[0] its undefined (since txtClasses.length == 0).
// this illustrates your problem
try {
// I am manually creating an empty array (your results)
var txtClasses = []
// this throws the error
txtClasses[0].bad = "throws an error";
} catch (e) {
// this just displays the error for you to see
document.getElementById("log").innerHTML += e.toString()
}
<div id="log"></div>
If you are expecting something back, you should check your selector is actually working (what I like to do is open up a web console and type my code right in there).
I noticed your selector changed in the first and second example too so make sure you read more about css selectors here.

Javascript - Sanitize Malicious code from file (string)

I have a data javascript file, which is being dynamically added to website via some custom code.
This file comes from a third party vendor, who could potentially add malicious code in the file
Before this file is added to the website, I would like to parse through it, and look for malicious code, such as redirects or alerts, that inherently get executed upon a files inclusion in the project/website.
For example, my js file could look like this :
alert ('i am malicious');
var IAmGoodData =
[
{ Name :'test', Type:'Test2 },
{ Name :'test1', Type:'Test21' },
{ Name :'test2', Type:'Test22' }
]
I load this file into a object via a XMLHttpRequest call, and when this call returns, I can use the variable (which is my file text) and search it for words:
var client = new XMLHttpRequest();
client.open('GET', 'folder/fileName.js');
client.onreadystatechange = function()
{
ScanText(client.responseText);
}
client.send();
function ScanText(text)
{
alert(text);
var index = text.search('alert'); //Here i can search for keywords
}
The last line would return index of 0, as the word alert is found at index 0 in the file.
Questions:
Is there a more efficient way to search for keywords in the file?
What specific keywords should i be searching for to prevent malicious code being run? ie redirects, popups, sounds etc.....
Instead of having them include var IAmGoodData =, make them simply provide JSON (which is basically what the rest of the file is, or seems to be). Then you parse it as JSON, using JSON.parse(). If it fails, they either didn't follow the JSON format well, or have external code, and in either case you would ignore the response.
For example, you'd expect data from the external file like:
[
{ Name :'test', Type:'Test2' },
{ Name :'test1', Type:'Test21' },
{ Name :'test2', Type:'Test22' }
]
which needs to be properly serialized as JSON (double quotes instead of single quotes, and double quotes around the keys). In your code, you'd use:
var json;
try {
json = JSON.parse(client.responseText);
catch (ex) {
// Invalid JSON
}
if (json) {
// Do something with the response
}
Then you could loop over json and access the Name and Type properties of each.
Random Note:
In your client.onreadystatechange callback, make sure you check client.readyState === 4 && client.status === 200, to know that the request was successful and is done.
This is extremely difficult to do. There are no intrinsically malicious keywords or functions in JavaScript, there are malicious applications. You could be getting false positives for "malicious" activity and prevent a legitimate code with a real purpose from being executed. And at the same time, anyone with a little bit of imagination could bypass any "preventive" method you may implement.
I'd suggest you look for a different approach. This is one of those problems (like CAPTCHA) in which it's trivial for a human to solve while for a machine is practically impossible to do so. You could try having a moderator or some human evaluator to interpret the code and accept it.
You should have them provide valid JSON rather than arbitrary Javascript.
You can then call JSON.parse() to read their data without any risk of code execution.
In short, data is not code, and should not be able to contain code.
You shouldn't. The user should be allowed to type whatever they want, and it's your job to display it.
It all depends on where it is being put, of course:
Database: mysql_real_escape_string or equivalent for whatever engine you're using.
HTML: htmlspecialchars in PHP, createTextNode or .replace(/</g,"<") in JavaScript
JavaScript: json_encode in PHP, JSON.stringify in JavaScript.
At the end of the day, just don't be Yahoo

Categories

Resources