There is a situation to run code inside javascript string. But there is two possibilities that the string can contain a javascript or not. So I want to check first is there any javascript code before executing the string.
let code = "alert('Run Run')";
let runFunction = new Function(code);
runFunction();
I tried regex apporach, but it would not work.
let exists = code.match(/[!##$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/) ? "YES" : "NO";
Is there any way to check this.
You can check the syntax of the string to see if it can be parsed properly before running it for real, though this essentially just involves attempting to execute the string as Javascript anyway.
const stringIsJS = (str) => new Promise((resolve) => {
window.addEventListener('unhandledrejection', (errorEvent) => {
// Don't pollute the console with additional info:
errorEvent.preventDefault();
resolve(errorEvent.reason.message === 'No syntax problems');
}, { once: true });
Promise.resolve().then(() => {
eval('throw new Error("No syntax problems");' + str);
});
});
(async () => {
console.log(
await stringIsJS('hello hello'),
await stringIsJS('const foo = "bar";'),
);
})();
throw new Error is inserted at the top of the code to be evaluated to ensure that the stringIsJS only checks the syntax of the string, rather than actually running any substantive code.
Or, using Acorn:
const stringIsJS = (str) => {
try {
acorn.Parser.parse(str);
return true;
} catch(e){
return false;
}
};
console.log(
stringIsJS('hello hello'),
stringIsJS('const foo = "bar";'),
);
<script src="https://cdn.jsdelivr.net/npm/acorn#6.1.1/dist/acorn.min.js"></script>
(still, this is a very weird thing to have to determine programmatically - it would be much better to, for example, save an additional flag in a database to indicate whether a particular string is Javascript or not)
Related
I can't believe that I'm asking an obvious question, but I still get the wrong in console log.
Console shows crawl like "[]" in the site, but I've checked at least 10 times for typos. Anyways, here's the javascript code.
I want to crawl in the site.
This is the kangnam.js file :
const axios = require('axios');
const cheerio = require('cheerio');
const log = console.log;
const getHTML = async () => {
try {
return await axios.get('https://web.kangnam.ac.kr', {
headers: {
Accept: 'text/html'
}
});
} catch (error) {
console.log(error);
}
};
getHTML()
.then(html => {
let ulList = [];
const $ = cheerio.load(html.data);
const $allNotices = $("ul.tab_listl div.list_txt");
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : $(this).find("list_txt title").text(),
url : $(this).find("list_txt a").attr('href')
};
});
const data = ulList.filter(n => n.title);
return data;
}). then(res => log(res));
I've checked and revised at least 10 times
Yet, Js still throws this result :
root#goorm:/workspace/web_platform_test/myapp/kangnamCrawling(master)# node kangnam.js
[]
Mate, I think the issue is you're parsing it incorrectly.
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : $(this).find("list_txt title").text(),
url : $(this).find("list_txt a").attr('href')
};
});
The data that you're trying to parse for is located within the first index of the $(this) array, which is really just storing a DOM Node. As to why the DOM stores Nodes this way, it's most likely due to efficiency and effectiveness. But all the data that you're looking for is contained within this Node object. However, the find() is superficial and only checks the indexes of an array for the conditions you supplied, which is a string search. The $(this) array only contains a Node, not a string, so when you you call .find() for a string, it will always return undefined.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
You need to first access the initial index and do property accessors on the Node. You also don't need to use $(this) since you're already given the same exact data with the element parameter. It's also more efficient to just use element since you've already been given the data you need to work with.
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : element.children[0].attribs.title,
url : element.children[0].attribs.href
};
});
This should now populate your data array correctly. You should always analyze the data structures you're parsing for since that's the only way you can correctly parse them.
Anyways, I hope I solved your problem!
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.
This one has a ton of moving parts that I've tried to simplify down as much as possible, and I still learning about async/await processing, so bear with me -
So I'm trying to write chat commands for a Discord chatbot with discord.js. The command that I'm having trouble with, triggered by a message beginning in !aut, is supposed to take in a string of user input (that follows the command itself) and return another string; if the user does not provide a string, I want it to grab the content of the message immediately above the message containing the command (i.e. 2nd most recent) and use that as the input string.
However, testing this latter case, it keeps throwing this error:
(node:17896) UnhandledPromiseRejectionWarning: DiscordAPIError: Cannot send an empty message
I've structured the bot with an event listener that listens for commands and calls the wrapper function execute(string, channel) if it detects one; the wrapper then calls the appropriate utility function for that command to get a string that in then passes back to the listener, which then sends the string out to the channel.
The utility function com_aut(array) is working perfectly fine; the problem is that the default empty string sComResult defined within the wrapper is being returned to the listener before it can be overwritten by com_aut:
client.on('message', pMessage => {
if (executable(pMessage.content) == true) {
let sResult = execute(pMessage.content, pMessage.channel);
pMessage.channel.send(sResult);
}
});
function execute(sMessage, pChannel = null) {
// strip off the initial ! that marks the message as a command; whatever comes immediately afterwards is the command
let args = sMessage.substring(1).trim().split(/ +/g);
let cmd = args[0];
// don't include the command itself among the rest of the arguments passed to it
args = args.splice(1);
let sComResult = "";
switch(cmd){
...
case "aut":
if (args.length < 1) {
// input string that should be in args actually isn't, so grab the content of the 2nd most recent message instead
pChannel.fetchMessages({ limit: 2 }).then(pMessages => {
sComResult = com_aut([pMessages.last().content]);
});
} else {
// input string is present in args, so just use that
sComResult = com_aut(args);
}
break;
}
return sComResult;
}
TextChannel.fetchMessages is asynchronous - or returns a Promise, at least - so I tried making the wrapper asynchronous as well so I could force it to await. Plus the necessary changes in the listener, I found that this worked:
client.on('message', pMessage => {
if (executable(pMessage.content) == true) {
execute(pMessage.content, pMessage.channel).then(sResult => { pMessage.channel.send(sResult) });
}
});
async function execute(sMessage, pChannel = null) {
// strip off the initial ! that marks the message as a command; whatever comes immediately afterwards is the command
let args = sMessage.substring(1).trim().split(/ +/g);
let cmd = args[0];
// don't include the command itself among the rest of the arguments passed to it
args = args.splice(1);
let sComResult = "";
switch(cmd){
...
case "aut":
if (args.length < 1) {
// input string that should be in args actually isn't, so grab the content of the 2nd most recent message instead
pMessages = await pChannel.fetchMessages({ limit: 2 });
sComResult = com_aut([pMessages.last().content]);
});
} else {
// input string is present in args, so just use that
sComResult = com_aut(args);
}
break;
}
return sComResult;
}
However, NOW the problem is that I can't call execute(string, channel) recursively, which I do when piping the output of one string-output command into another, string-input command. (Which is also why the wrapper exists in the first place instead of the listener just being linked directly to the utility functions) This involves an execute call within execute itself. I'll just link to pastebin at this point, but it's throwing a type error since it's not able to get a value back from the nested execute and so it ends up trying to call null.then:
(node:6796) UnhandledPromiseRejectionWarning: TypeError: pInnerPromise.then is not a function
How can I structure my code so that it properly awaits the fetchMessages query before moving on, but still allowing recursive calling of the wrapper function (or some other way to pipe)?
Your code
if (executable(sInnerCom) == true) {
// here you are using await so promise is already resolved.
let pInnerPromise = await execute(sInnerCom, pChannel);
// no need to use then, you can return result direct
pInnerPromise.then(result => { sInnerComResult = result });
}
It should be like this
if (executable(sInnerCom) == true) {
let result = await execute(sInnerCom, pChannel);
sInnerComResult = result ;
}
or like this
if (executable(sInnerCom) == true) {
sInnerComResult = await execute(sInnerCom, pChannel);
}
var checking_location = "none"
const getentitiesByType = (arr, type) => {
for (let i in arr) {
if (arr[i].type === type) {
checking_location = "exists"
return arr[i].entity
}
}
return null;
}
if (!meeting.location) {
if (checking_location != 'exists') {
rl.question('where is the location ', function(answer) {
// session.send("The location you gave:" answer);
rl.close();
session.send(answer)
// console.log(tryagain(answer, 'Calendar.Location'));
session.send(tryagain(answer, 'Calendar.Location'));
});
}
} else {
next();
}
What i'm trying to do here is to have a loop in the if (!meeting.location) if checking_location stays equal to none. Basically i want to check if a certain Json field exists, if it doesn't i want to keep asking the question in rl.question.My issues is that the code is only working the first time, then even if i give another input not containing the required field i don't get that question.Also note that this is not the entire code but it's more than enough to understand the possible issue spots in my implementation.
getentitiesByType needs to be called somewhere, simply assigning it to a variable will not make the function run: getentitiesByType(youArr, yourType).
Also, as a side note, instead of using string values for checking_location just rename the variable and use a boolean value. Ex: var hasLocation = false.
My JavaScript sometimes crashes on this line:
var json = eval('(' + this.responseText + ')');
Crashes are caused when the argument of eval() is not JSON. Is there any way to check if the string is JSON before making this call?
I don't want to use a framework - is there any way to make this work using just eval()? (There's a good reason, I promise.)
If you include the JSON parser from json.org, you can use its parse() function and just wrap it in a try/catch, like so:
try
{
var json = JSON.parse(this.responseText);
}
catch(e)
{
alert('invalid json');
}
Something like that would probably do what you want.
Hers's the jQuery alternative...
try
{
var jsonObject = jQuery.parseJSON(yourJsonString);
}
catch(e)
{
// handle error
}
I highly recommend you use a javascript JSON library for serializing to and from JSON. eval() is a security risk which should never be used unless you are absolutely certain that its input is sanitized and safe.
With a JSON library in place, just wrap the call to its parse() equivalent in a try/catch-block to handle non-JSON input:
try
{
var jsonObject = JSON.parse(yourJsonString);
}
catch(e)
{
// handle error
}
Maybe this helps:
With this code, you can get directly your data…
<!DOCTYPE html>
<html>
<body>
<h3>Open console, please, to view result!</h3>
<p id="demo"></p>
<script>
var tryJSON = function (test) {
try {
JSON.parse(test);
}
catch(err) {
// maybe you need to escape this… (or not)
test = '"'+test.replace(/\\?"/g,'\\"')+'"';
}
eval('test = '+test);
console.debug('Try json:', test);
};
// test with string…
var test = 'bonjour "mister"';
tryJSON(test);
// test with JSON…
var test = '{"fr-FR": "<p>Ceci est un texte en français !</p>","en-GB": "<p>And here, a text in english!</p>","nl-NL": "","es-ES": ""}';
tryJSON(test);
</script>
</body>
</html>
The problem with depending on the try-catch approach is that JSON.parse('123') = 123 and it will not throw an exception. Therefore, In addition to the try-catch, we need to check the type as follows:
function isJsonStr(str) {
var parsedStr = str;
try {
parsedStr = JSON.parse(str);
} catch (e) {
return false;
}
return typeof parsedStr == 'object'
}
Why you can't just check what is the response? It is more more efficient.
var result;
if (response.headers['Content-Type'] === 'application/json')
result = JSON.parse(this.responseText);
else
result = this.responseText;
screen1
jQuery $.ajax() will add the responseJSON property to the response object, and to test if the response is JSON, you can use:
if (xhr.hasOwnProperty('responseJSON')) {}
There is a tiny library that checks JavaScript types: is.js
is.json({foo: 'bar'});
=> true
// functions are returning as false
is.json(toString);
=> false
is.not.json([]);
=> true
is.all.json({}, 1);
=> false
is.any.json({}, 2);
=> true
// 'all' and 'any' interfaces can also take array parameter
is.all.json([{}, {foo: 'bar'}]);
=> true
Actually is.js is much more then this, some honorable mentions:
var obj = document.createElement('div');
is.domNode(obj);
=> true
is.error(new Error());
=> true
is.function(toString);
=> true
is.chrome();
=> true if current browser is chrome