Parsing a JavaScript function string - javascript

Starting off, I am aware of the security risks storing JavaScript functions in JSON strings, however that is not what is happening here.
Now I am working on a JS multi-threading model using web workers and blob strings. However as I'm sure you are aware you cannot use custom objects or prototypes from said custom objects in web workers so I developed a system for serializing a custom object with functions into an anonymous object that can be used in the web worker however I am getting a syntax error when calling JSON.parse over the serialized object.
Serialize function:
AjaxHandler.prototype.getEmbedded = function(stringify) {
"use strict";
let embMembers = this.metaData.embeddedMembers; // an array of function names to add
let embeddedObj = {};
let stringifyArray = stringify ? new Array(embMembers.length) : [];
if (stringify) {
for (let i = 0; i < embMembers.length; i++) {
stringifyArray[i] = ('"' + embMembers[i] + '":"' + AjaxHandler.prototype[embMembers[i]].toString().replace(/[\n\r]+/gi, '').replace(/[\t]+/gi, '')).replace(/\/\*\*\/this.\/\*\*\//gi, '') + '"';
}
} else {
for (let mem of embMembers) {
embeddedObj[mem] = AjaxHandler.prototype[mem];
}
}
if (stringify) {
return ("{" + stringifyArray.join(",") + "}");
} else {
return embeddedObj;
}
};
All functions being embedded are syntactically correct however when I try to parse it:
!function TestAction() {
"use strict";
let tHandler = new AjaxHandler();
let eme = tHandler.getEmbedded();
let stf = tHandler.getEmbedded(true);
let ptf = JSON.parse(stf); // Throws syntax error
debugger;
}();
It throws an error (Uncaught SyntaxError: Unexpected string) as noted in the code.
Is there a way to parse out the object containing functions?
Notes:
No JSON data is being sent to or from the client so I don't think it's a security risk to store and send a function in JSON.
I have researched previous questions on the matter and none of the leads I found produced any valid solution aside from "don't do it, it's a security risk".

Related

Deserialize DeepObject Querystring Keys in Azure Functions / Javascript

We are constructing an API with Azure Functions, and the spec calls for DeepObject references in the GET request's querystring. So, the structure looks like https://example.com/api/persons?name[first]=Todd. The expectation is that some of the query keys may be DeepObject references, others will be flat.
This is a pattern that apparently Express can handle, but Azure Functions uses an ASP.NET router. The expectation is that the reference above should deserialize into req.params: { name: { first: "Todd" } }. However, instead the output looks like req.params: { "name[first]": "Todd" }.
I would really love to not have to regex/search each key, so does anyone know if:
There's a config/flag in ASP.NET to support this structure?
There's a good pattern in Javascript to deserialize this in some functional -- or at least non-idiosyncratic -- way?
Note: Anyone who suggest some use of the eval() method will not be selected. But for playing you will take home a comment with a Nineties reference, because that was the last decade the use of the that method was considered acceptable. :stuck_out_tongue_winking_eye:
For this problem, I don't think we can change some configuration to support this structure. What we can do is to implement in code by ourselves.
Here is my function code:
module.exports = async function (context, req) {
console.log("======query url is:" + req.url);
const result = queryStringToJSON(req.url);
console.log(result);
context.res = {
body: "success"
};
}
function queryStringToJSON(queryUrl) {
if(queryUrl.indexOf('?') > -1){
var queryString = queryUrl.split('?')[1];
}
var pairs = queryString.split('&');
var result = {};
pairs.forEach(function(pair) {
if (pair.indexOf('[') > -1) {
var nameObj = {};
var firstObj = {};
var nameStr = pair.substring(0, pair.indexOf('['));
var firstStr = pair.substring(pair.indexOf('[')+1, pair.indexOf(']'));
firstObj[firstStr] = pair.split('=')[1];
nameObj[nameStr] = firstObj;
Object.assign(result, nameObj);
}else {
pair = pair.split('=');
result[pair[0]] = decodeURIComponent(pair[1] || '');
}
});
return result;
}
Start the function project, I request it with http://localhost:7071/api/HttpTrigger1?name[first]=Todd&email=test#mail.com. The result shows:
After much searching, I wasn't able to find any way to natively implement this in the ASP.NET router. Though there is a great deal of suggestions on how to deserialize this structure directly in your ASP.NET controller functions, I am working in Javascript.
What was helpful was the qs library, available in NPM, which supports a number of nuances related to this query string structure.
const { query } = req;
// => { "name[first]": "Todd" };
const deserializedQuery = qs.parse(query);
// => { name: { first: "Todd" }
Equally helpful to me is that I need a way to restructure my outbound query string in this same format. Qs works with the paramsSerializer attribute in Axios.
const params = { name: { first: "Todd" };
const paramsSerializer = (params) => { return Qs.stringify(params); };
const reqOptions = { params, paramsSerializer };
axios.get("https://example.com/api/persons", reqOptions);
// => GET https://example.com/api/persons?name[first]=Todd
Thanks to #hury-shen for a completely workable solution. It just wasn't turnkey solution I was looking for.

What is the correct equivalent of Java of this JS line of code?

I am trying to lessen the line of codes using the Lambda expression in Java after seeing the same code written in 1 line in JS somewhere. But i am getting this below error:
Incompatible types.
Required:
org.openqa.selenium.logging.LogEntries
Found:
void
This is what i have now.
List e =driver.manage().logs().get(LogType.BROWSER).getAll();
String s="",t ="";
if (!e.isEmpty()){
for (Object l : e)
{
t=l.toString();
if(t.contains("SyntaxError")){
s = s + t+"<BR/>";
}
else if(t.contains("EvalError")){
s = s + t+"<BR/>";
}
else if(t.contains("ReferenceError")){
s = s + t+"<BR/>";
}
else if(t.contains("RangeError")){
s = s + t+"<BR/>";
}
else if(t.contains("TypeError")){
s = s + t+"<BR/>";
}
else if(t.contains("URIError")){
s = s + t+"<BR/>";
}
}
And this is what i am trying to get to:
List<String > errorStrings = new ArrayList<>();
errorStrings.add("SyntaxError");
errorStrings.add("EvalError");
errorStrings.add("ReferenceError");
errorStrings.add("RangeError");
errorStrings.add("TypeError");
errorStrings.add("URIError");
LogEntries l = driver.manage().logs().get(LogType.BROWSER).forEach(le -> errorStrings.stream().anyMatch(er -> le.getMessage().contains(er)));
By following this line of code written is JS:
var jsErrors = Driver.Manage().Logs.GetLog(LogType.Browser).Where(x => errorStrings.Any(e => x.Message.Contains(e)));
Please help me to understand what am i doing wrong.
-TIA
Your code is
LogEntries l = driver.manage().logs().get(LogType.BROWSER)
.forEach(le -> errorStrings.stream()
.anyMatch(er -> le.getMessage().contains(er)));
And your error message is
Incompatible types. Required: org.openqa.selenium.logging.LogEntries Found: void
The error message is telling you that your assignment statement is expecting you to return a LogEntries but it is getting a void. It is getting a void because that is the return type of the Stream.forEach method. The forEach method is used to consume all elements of the stream and return nothing.
I think what you are trying to do is filter a set of log entries and turn them into a LogEntries object right? If that's the case I suspect you want filter rather than forEach.
I'm not a selenium expert so I can't advise you on how to turn a Stream<LogEntry> into aLogEntries`. I'm assuming you can use a reduce or collect operation but might be best to pose that as a separate question.

How do you prevent a NodeJS server from potentially exposing function code?

Let's imagine you're building a banking app backend. You want to respond to a user with a string that returns the balance but you forgot to add ().
class User {
constructor() {console.log("ctor")}
balance() { console.log("secret balance code")}
}
Then when referencing the user, instead of writing this:
const userA = new User();
return `Your balance is $${userA.balance()}`;
I accidentally write this:
const userA = new User();
return `Your balance is $${userA.balance}`;
Which sadly outputs:
'Your balance is balance() { console.log("secret balance code")}'
Which leaks the source code.
You do not need to worry about it, if you forget something, then testing will help to find it. Nobody deploy in production without testing when he has a serious project. It is better to write tests than to try to correct language behavior.
One workaround is to override all functions' toString like so:
> Function.prototype.toString = () => {return "bla"}
[Function]
> '' + new User().balance
'bla'
When responding to a request, you're undoubtedly going to be running the response through some sort of serializer. JSON, CBOR, etc. Handle it on that layer.
Fortunately for you, if you're returning JSON data, it's already handled:
JSON.stringify(someFunction);
// undefined
If you really are returning plain text strings, you can still have such a layer that ensures you're not putting out functions.
I've a solution which is definitely slower than raw templates, but here it goes.
So basically I just send a context object which has all the string I want to resolve. And before the actual string replacement, I just check for the types of arguments.
function resolveTemplates(str, args){
if(args && Array.isArray(args) && args.length){
args.forEach((argument) => {
// check here for any unwanted types
if(typeof arg === 'function'){
throw new Error('Cannot send function to create raw Strings')
}
})
}
const rx = /\{([^{}]*)\}/g;
let match = {};
let matches = [];
while(match = rx.exec(str)){
matches.push(match)
}
matches.reverse();
matches.forEach(function(match){
const key = match[1];
const index = match.index;
str = str.slice(0, index) + args[key] + str.slice(index + 2 + key.length)
})
return str;
}
resolveTemplates('Hello! My name is {firstName} {lastName}', {firstName: 'Shobhit', lastName: 'Chittora'})
PS: Instead of throwing errors for functions as arguments, you can call the functions. But binding the functions to the correct context can be a overhead to think about and generally not suggested.

javascript functions wait for data availability or variable not capable of handling huge data

forgive the trivial question but I am more used to C++ and Python code than javascript.
I have the following code from the THREE JS PLY loader:
var geometry;
var scope = this;
if (data instanceof ArrayBuffer) {
geometry = isASCII(data) ? parseASCII(bin2str(data)) : parseBinary(data);
} else {
geometry = parseASCII(data);
}
parse: function (data) {
function isASCII(data) {
var header = parseHeader(bin2str(data));
return header.format === 'ascii';
}
function bin2str(buf) {
var array_buffer = new Uint8Array(buf);
var str = '';
for (var i = 0; i < buf.byteLength; i++) {
str += String.fromCharCode(array_buffer[i]); // implicitly assumes little-endian
}
return str;
}
It works fine if I load a small ply file but browser crashes on very large one. I believe there are two "possible" issues:
1) on a large file the string str returned by the function bin2str(buf) might not be able to handle the parsing process
2) in the function isASCII(data) the line
parseHeader(bin2str(data));
crashes the browser as the bin2str(data) cannot return a proper value in time as the process is very memory consuming
I am using the conditional as i am not totally sure of what the problem is. Any suggestion and/or possible solution?
Thank you,
Dino
In the end the solution I have adopted was to decimate my file using the free software MeshLab.
Hope this helps.
Dino

How to expose object in node module

I've a module which is using parsing ( a parsing functionality), other modules should query this parser values.
my question is
how should I build it (design aspects ) ?
which method should init the parser (the first method that call it
to get specific value)
This is sample code which return two object from the parser but I dont think that this is the right way to do that since maybe I'll need to provide additional properties
the is the module parse
parse = function (data) {
var ymlObj = ymlParser.parse(data);
return {
web: ymlObj.process_types.web,
con: ymlObj.con
}
};
If I understood you right you can just make simple module with getters and setter.
(parse.js)
var ymlObj = {};
function Parse() {}
Parse.prototype.setData = function (data) {
ymlObj = data;
}
Parse.prototype.getWeb = function () {
return ymlObj.process_types.web;
}
Parse.prototype.getCon = function () {
return ymlObj.con;
}
module.exports = new Parse();
(parseUser.js)
var parse = require('./parse.js');
function ParseUser() { }
ParseUser.prototype.useParse = function () {
console.log(parse.getCon());
}
module.exports = new ParseUser();
(app.js)
var parse = require('./parse.js');
var parseUser = require('parseUser.js');
parse.setData({ ... });
parseUser.useParse();
You still have to do basics like handle exceptions but hope this helps you understand the basic structure.
What comes to init it really depends when you want to initialize (fetch?) your data and where does that data come from. You can set timestamp to indicate how old your data is and make decision if you still rely on it or fetch newer data. Or you can register callbacks from your user modules to deal with new data every time its fetched.
So its up to you how you design your module. ;)

Categories