Convert string expression into JS object (not JSON) - javascript

I have an expression like this inside a contenteditable div:
{
name : "Jeff",
job : "rat whacker"
}
How can I get this into a JS object?
If I grab the string from the div:
$("div").text();
...I get this:
"{\n name: \"Jeff\",\n job: \"rat whacker\"\n}"
Obviously JSON.parse won't work since this isn't valid JSON. How can I grab this as text but then assign it to a regular JSON object:
{
name : "Jeff",
job : "rat whacker"
}

Note that the last thing you want to do is trust people. Someone is going to abuse your site if you allow arbitrary code execution, so make that impossible: write code that validates user input before it's allowed to even make it to the next step.
Either take the textContent from your div, rewrite it so that it's valid JSON, and then parse that JSON (bonus: JSON.parse automatically throws an error if the input can't be parsed, so you can write a pretty simply string replacement that works for the kind of input you want, while yielding bad JSON for anything else, and the JSON.parse function will just reject bad input), or literally parse the text string as JS, using a JS parser that is set to throw away any active content (function, fat arrow notation, exercution operators, etc). If you only want to allow simple input like what you're showing, then writing your own simple-and-limited-JS parser is a little bit of work, but might be more than enough.

Related

How can I remove empty strings in template literals?

I'm creating a script that loops through an array of objects and creates .edn file that we're using to migrate some of our client's data.
As we have to use .edn file which uses Clojure, I generate a template literal string and populate the data in the format that we need.
In the generated string I have many conditional operations, where I check if some data exist before returning some string. If the data doesn't exist I cannot use null, so I use an empty string. Now when my file gets created, those empty strings create an extra line that I want to remove. Investigating it more, the string adds /n which actually creates those extra lines from an empty string.
What is the best way to do it?
This is an example of what I'm doing:
arrayOfObjects.map(a => {
return `
; ...other code that doesn't depend on data
; Code that depends on data, if it's false I want to remove it completely and
; and avoid passing empty string as it creates extra space in the generated file
${a.stripe_connected_account
? `[[:im.stripeAccount/id]
#:im.stripeAccount{:stripeAccountId "${a.stripe_connected_account}"
:user #im/ref :user/${a.user}}]`
: ""}
`;
});
Appreciate any help, thanks!
An empty string doesn't do that. T${''}h${''}i${''}s is no different from This. The "extra space" is the whitespace that you (unconditionally) include in your template string around the ${ } part:
If you'd start the ${ } expression earlier and end it later and put the whitespace (if you even want it) as part of your if-true expression of the ternary, you will get what you want.
For example:
arrayOfObjects.map(a => {
return `
; ...other code that doesn't depend on data
; Code that depends on data, if it's false I want to remove it completely and
; and avoid passing empty string as it creates extra space in the generated file${
a.stripe_connected_account ? `
[[:im.stripeAccount/id]
#:im.stripeAccount{:stripeAccountId "${a.stripe_connected_account}"
:user #im/ref :user/${a.user}}]`
: ""
}`;
});
(Yes, the strange indentation is a result of merging two different indentation levels, the code's and the output's, and preventing line breaks in the output unless desired. I tried several ways to format it but none of them looked good - there are only ugly ways, no way to indent it nicely and have the result you want, unless you were to write a tagged template function that would smartly detect when a ${ } expression would need surrounding whitespace stripped and when it wouldn't.)

Javascript crashes on special characters from query string

To use this value in my TypeScript I am getting it from my query string like this:
var UserName = #Request.QueryString["UserName"];
But I get a Unexpeted Identifier error on it because if in DevTool if I go to where it breaks that query string has a value like this:
var UserName = ANT -- ANT 37690 / THIRD PARTY
So is there a way to do some kind of sanitation on it so it wouldn't crash? I guess there are illegal characters in that value for JS?
The error has nothing to do with "special" characters, but with the fact that the right side of the assignment - unwrapped in quotes - contains what js engine views as unknown identifier[s].
One way to properly format data that becomes part of javascript code is to use JavaScriptSerializer class from System.Web.Script.Serialization namespace.
var UserName = #new System.Web.Script.Serialization.JavaScriptSerializer().Seria‌​lize(Request.Query‌​St‌​ring["UserName"]);
The shorter version of this for a string is:
var UserName = "#System.Web.HttpUtility.JavaScriptStringEncode(Request.Query‌​St‌​ring["UserName"])";
or overloaded version that wraps the result in double quotes:
var UserName = #System.Web.HttpUtility.JavaScriptStringEncode(Request.Query‌​St‌​ring["UserName"], true);
You need to include quotes for the value.
var UserName = "#(Request.QueryString["UserName"])";
Otherwise the name will come through verbatim in your code and cause the problems you are seeing.
There is no need to protect against an attack vector here as the user can alter the page as they see fit at any time with a user script, and the QueryString is entered by them and only seen as a result by them in this scenario.
If there was a need to scrub the user input, it should be done prior to it actually reaching the view on server side. However, if still concerned about scrubbing output into a view in this type of scenario in general, it would be prudent to include an encode from razor's library.
var sanitizedJsVariable = "#System.Web.HttpUtility.JavaScriptStringEncode(model.VariableFromServer)";

UTF-8 symbol is converted when inserted to dom

I have a following problem, i am building app that uses data stream from ajax calls, the data that is coming is therefore escaped inside json string.
example: 1°Set
When i insert that data to DOM it is being converted like this: 1°Set
I dont use any libraries like jQuery, pure Javascript.
I tried to store converted name also in another place but i cannot seem to convert it manually, i tried following functions:
var test = function(str) {
console.log(unescape(encodeURIComponent(str)) );
console.log(decodeURIComponent(escape(str)) );
};
test('1°Set');
It stays the same, does anyone have an idea how to convert it to a DOM like version?
I have a following problem, i am building app that uses data stream from ajax calls, the data that is coming is therefore escaped inside json string.
example: 1°Set
Sounds like you're having a problem because your backend serves a JSON that looks like:
{
"something": "1°Set"
}
Instead of a string "1°Set", you're serving HTML source code that amounts to "1°Set". This looks very unnecessary. I cannot see a good reason of using HTML escaping inside JSON, unless you actually want your JSON to actually contain a part of HTML source (with formatting and everything), rather than just a string.
My suggestion: Let's keep it simple and instead serve something like:
{
"something": "1°Set"
}
or equivalently escape it properly using JSON syntax:
{
"something": "1\u00b0Set"
}
Now you'll JavaScript will receive a plain string that can be easily displayed, for example inside element.textContent or element.value or anywhere else. You won't even need any conversions.

"Fixing" JSON coming out of MySQL

I'm fetching JSON code stored in MySQL and it has extra slashes, which I have to remove in order to parse it in JavaScript, after I print it on the page. Right now I'm doing the following:
$save = str_replace("\n", "<br>", $save); // Replace new line characters with <br>
$save = str_replace('\\"', '"', $save); // top-level JSON
$save = str_replace('\\\\"', '\"', $save); // HTML inside top level JSON
$save = str_replace('\\\\\\\\\\"', '\\\\\"', $save); // HTML inside second level JSON
Here is an example JSON code, as it comes out from MySQL:
{\"id\":2335,\"editor\":{\"selected_shape\":\"spot-7488\"},\"general\":{\"name\":\"HTML Test\",\"shortcode\":\"html-test\",\"width\":1280,\"height\":776},\"spots\":[{\"id\":\"spot-7488\",\"x\":9.9,\"y\":22.6,\"default_style\":{\"use_icon\":1},\"tooltip_content\":{\"content_type\":\"content-builder\",\"plain_text\":\"<p class=\\\"test\\\">Test</p>\",\"squares_json\":\"{\\\"containers\\\":[{\\\"id\\\":\\\"sq-container-293021\\\",\\\"settings\\\":{\\\"elements\\\":[{\\\"settings\\\":{\\\"name\\\":\\\"Paragraph\\\",\\\"iconClass\\\":\\\"fa fa-paragraph\\\"},\\\"options\\\":{\\\"text\\\":{\\\"text\\\":\\\"<p class=\\\\\\\"test\\\\\\\">Test</p>\\\"}}}]}}]}\"}}]}
And here is how it's supposed to look in order to get parsed correctly (using jsonlint.com to test):
{"id":2335,"editor":{"selected_shape":"spot-7488"},"general":{"name":"HTML Test","shortcode":"html-test","width":1280,"height":776},"spots":[{"id":"spot-7488","x":9.9,"y":22.6,"default_style":{"use_icon":1},"tooltip_content":{"content_type":"content-builder","plain_text":"<p class=\"test\">Test</p>","squares_json":"{\"containers\":[{\"id\":\"sq-container-293021\",\"settings\":{\"elements\":[{\"settings\":{\"name\":\"Paragraph\",\"iconClass\":\"fa fa-paragraph\"},\"options\":{\"text\":{\"text\":\"<p class=\\\"test\\\">Test</p>\"}}}]}}]}"}}]}
Please note that I have HTML code inside JSON, which is inside another JSON and this is where it gets a bit messy.
My question - is there a function or library for PHP (for JS will work too) which covers all those corner cases, because I'm sure someone will find a way to break the script.
Thanks!
The short answer, which is woefully inadequate, is for you to use stripslashes. The reason this answer is not adequate is that your JSON string might have been escaped or had addslashes called on it multiple times and you would have to call stripslashes precisely once for each time this had happened.
The proper solution is to find out where the slashes are being added and either a) avoid adding the slashes or b) understand why the slashes are there and respond accordingly. I strongly believe that the process that creates that broken JSON is where the problem lies.
Slashes are typically added in PHP in a few cases:
magic_quotes are turned on. This is an old PHP feature which has been removed. The basic idea is that PHP used to auto-escape quotes in incoming requests to let you just cram incoming strings into a db. Guess what? NOT SAFE.
add_slashes has been called. Why call this? Some folks use it as an incorrect means of escaping data before sticking stuff in a db. Others use it to keep HTML from breaking when echoing variables out (htmlspecialchars should probably be used instead). It can also come in handy in a variety of other meta situations when you are defining code in a string.
When escaping data input. The most common escaping function is mysqli_real_escape_string. It's very important to escape values before inserting them in a db to prevent sql injection and other exploits but you should never escape things twice.
So there's a possibility that your code is double-escaping things or that addslashes is getting called or something like magic_quotes is causing the problem, but I suspect it is another problem: some JS code might be supplying this JSON not as a proper JSON string, but one that has been escaped so to define a string within javascript.
If you take your example JSON string above, and slap some quotes around it:
var myJSON = "<put your string here>";
then SURPRISE your javascript is not broken and the var myJSON contains a string that is actually valid JSON and can be parsed into an a valid JSON object:
var myJSON = "{\"id\":2335,\"editor\":{\"selected_shape\":\"spot-7488\"},\"general\":{\"name\":\"HTML Test\",\"shortcode\":\"html-test\",\"width\":1280,\"height\":776},\"spots\":[{\"id\":\"spot-7488\",\"x\":9.9,\"y\":22.6,\"default_style\":{\"use_icon\":1},\"tooltip_content\":{\"content_type\":\"content-builder\",\"plain_text\":\"<p class=\\\"test\\\">Test</p>\",\"squares_json\":\"{\\\"containers\\\":[{\\\"id\\\":\\\"sq-container-293021\\\",\\\"settings\\\":{\\\"elements\\\":[{\\\"settings\\\":{\\\"name\\\":\\\"Paragraph\\\",\\\"iconClass\\\":\\\"fa fa-paragraph\\\"},\\\"options\\\":{\\\"text\\\":{\\\"text\\\":\\\"<p class=\\\\\\\"test\\\\\\\">Test</p>\\\"}}}]}}]}\"}}]}";
console.log(JSON.parse(myJSON)); // this is an actual object
The key here is to examine the point of entry where this JSON arrives in your system. I suspect some AJAX request has created some object and rather than sending valid JSON Of that object, it is sending instead an escaped string of a JSON object.
EDIT:
Here's a simple example of what happens when you have too many encodings. Try running this JS in your browser and observe the console output:
var myObj = {"key":"here is my value"};
console.log(myObj);
var myJSON = JSON.stringify(myObj);
console.log(myJSON);
var doubleEncoded = JSON.stringify(myJSON);
console.log(doubleEncoded);

Regex replacement with prompting/callback UI

I'm trying to write a function that takes a long string of text, identifies place holders within the text, and prompts the user to supply a value that should take the place of the placeholder. The markup for the placeholders looks similar to markdown used for images or links:
some text, some more text, ?[name][description] more text, not just commas
Where name and description are arbitrary runs of text. When I've found these placeholders, I want to pop up a nicely formatted dialog, using the names and descriptions, and have the user supply a replacement value.
I already have a nice function (called htmlPrompt) available where you hand it a piece of HTML (for the main part of the prompt), has a text box, and then calls a callback function you've supplied with the result (or null if Cancel is pressed), with the following signature:
function (htmlText, inputStartValue, callback)
Before plugging in this function, I wrote the rough and ready:
myText = myText.replace(/(\?\[(.+)\][ ]?(?:\n[ ]*)?\[(.+)\])/g,
function (wholematch, m1, m2, m3) {
var repValue = prompt(m2);
if (repValue == null)
{
return m1;
}
return repValue;
});
Which uses the DOM built-in prompt method - which doesn't really do an adequate job for me, when it comes to formatting.
However, I can't think of a way of plugging in htmlPrompt - it only simulates a modal dialog and provides the final result by calling callback.
I did think of trying to manually do the replacements, using the results from match rather than replace - but so far as I can see, the values returned by match are just strings - they don't give you anything useful (such as the location of the match within the overall text).
Or do you think I'm going about this completely wrong? The overall flow I want is:
Find each placeholder in the text
Prompt the user for a replacement, using both the name and description values
Replace the placeholder expressions in the text with the user supplied value.
For each of the name and description tupples:
First use match to read name and desription.
Prompt user.
Then use replace to replace those.

Categories

Resources