Securing eval function - javascript

I have written two applications:
JS script attached on different websites
Management panel for me
Each script will create different DOM structure using JS, I can create javascript code doing this for each website from management panel.
Thus I have to keep this part of code in the database, and use eval in each script to run it.
The sample eval looks like this:
var container = document.createElement('div');
container.innerHTML = "Fjkdfjdf";
html = {
container: container
};
doAction();
So first I create DOM elements, then I attach some of them to the attribute in my script, then I call some function in my script - attaching these elements to body. The script looks like this:
(function() {
var module = (function() {
var html = ();
var fire = function() {
Api.getStyles(function(response) {
eval(response.script);
};
};
var doAction = function() {
document.getElementsByTagName('body')[0].appendChild(html.container);
};
return {
fire: fire,
doAction: doAction
};
});
module.fire();
)();
Is this safe enoough? Can someone override doAction() method and do whatever he wants?

Related

I am not able to get any of my JSLink working. What am I doing wrong

We have SharePoint 2013 on Prem and I am trying to do some customizations using JS Link. Even the most simple exercises are not working. I don't understand what I'm doing wrong.
New page - List added and jS Link = ~site/SiteAssets/js-test/OverRideCustomHeader.js
(function () {
var overrideContext = {};
overrideContext.Templates = {};
overrideContext.Templates.Header = overrideCustomHeader;
overrideContext.Templates.Footer = overrideCustomFooter;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideContext);
})();
function overrideCustomHeader() {
return “<h3>Our Custom Header</h3>”;
}
function overrideCustomFooter() {
return “<h3>Our Custom Footer</h3>”;
}
I expect to see a header and a footer display and they are not.
Insert script editor webpart into the page and insert the script into script editor webpart(use correct 【"】).
(function () {
var overrideContext = {};
overrideContext.Templates = {};
overrideContext.Templates.Header = overrideCustomHeader;
overrideContext.Templates.Footer = overrideCustomFooter;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideContext);
})();
function overrideCustomHeader() {
return "<h3>Our Custom Header</h3>";
}
function overrideCustomFooter() {
return "<h3>Our Custom Footer</h3>";
}
Update:
Have you enabled Minimal Download Strategy?
JSLink won't work if url like /_layouts/15/start.aspx# , you could disable the feature.

VueJS: How to dynamically execute Javascript from string?

I'm writing a website using VueJS which allows (selected) users to add scripts that are automatically executed upon page load. Here's a sample text that a user might upload:
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.0.5/howler.js"></script>
<script>
var sound = new howler.Howl({
src: ['./sample.mp3']
)}.play();
</script>
This text is stored into a string after retrieving from API backend. The problem now is: I couldn't get it to execute however I try. Is there an option in VueJS that can automatically execute javascripts in strings?
As a reference, here's my code:
var temp_arr = utils.preprocess(vm.chapterInfo.Content)
vm.display = temp_arr[0]
vm.control_script = console.log(temp_arr[1])
// None of below worked
eval(vm.control_script)
document.getElementsByTagName("head")[0].appendChild(control_script)
The problem isn't a Vue one, but a JavaScript one.
I assume that you already understand the security implications of allowing users to run JavaScript; it's rarely a good idea. Sites like JSFiddle do it successfully, however it will take a lot of work and understanding to make it safe, so if you're not 100% sure with what you are doing, then as #WaldemarIce said, you shouldn't do it!
Right, with the warning out the way, you need to do a few things to get this to work:
1) Load the external scripts:
loadScripts() {
return new Promise(resolve => {
let scriptEl = document.createElement("script");
scriptEl.src = "https://cdnjs.cloudflare.com/ajax/libs/howler/2.0.5/howler.js";
scriptEl.type = "text/javascript";
// Attach script to head
document.getElementsByTagName("head")[0].appendChild(scriptEl);
// Wait for tag to load before promise is resolved
scriptEl.addEventListener('load',() => {
resolve();
});
});
}
Here I'm simply attaching the external script to the head of the document and attaching a load event, which resolves the Promise when loaded.
2) Now we have loaded the external script we can execute the remainder of the script. You will need to strip out the script tags, so you can do something like this:
executeScript() {
// remove script tags from string (this has been declared globally)
let script = string.replace(/<\/?script>/g,"")
eval(script)
}
Form the Vue perspective, you can then execute this inside the created hook:
created() {
this.loadScripts().then(() => {
this.executeScript();
});
},
I'll leave it to you to extract the external scripts you want to load from your user input, but here's a JSFiddle: https://jsfiddle.net/49dq563d/
I recently came across this problem and had to extend on the answer from #craig_h. The example below allows full embed code to be sent through as string (HTML elements as well as scripts and inline JS). This is using DOMParser.
<div ref="htmlDump"></div>
<script>
import Vue from "vue";
export default {
...
methods: {
cloneAttributes(element, sourceNode) {
let attr;
let attributes = Array.prototype.slice.call(sourceNode.attributes);
while(attr = attributes.pop()) {
element.setAttribute(attr.nodeName, attr.nodeValue);
}
}
},
mounted(){
if(this.embedString && this.embedString.length > 0)
{
//Parse the code given from the API into a new DOM so we can easily manipulate it
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(this.embedString, 'text/html');
//Get the contents of the new DOM body and loop through.
//We want to add all HTML elements to the page and run / load all JS
var kids = [...htmlDoc.body.children];
let len = kids.length;
for (var i = 0; i < len; i++) {
var item = kids[i];
if(item.tagName == "SCRIPT")
{
//If we have a 'src' attribute then we're loading in a script
if(item.hasAttribute('src'))
{
//Create a new element within the current doc to trigger the script load
let scriptEl = document.createElement("script");
//Copy all attributes from the source element to the new one
this.cloneAttributes(scriptEl, item);
//Attach script to the DOM to trigger it to load
this.$refs.htmlDump.appendChild(scriptEl);
} else {
//if we don't have a 'src' attribute then we have some code to run
eval(item.innerText);
}
} else{
this.$refs.htmlDump.appendChild(item);
}
}
}
}
...
}
</script>

How to select fragments of an existing SVG using Snap.svg

I'm trying to run Snap.svg locally, but the Snap.load() function makes an AJAX request, which isn't allowed locally (in Chrome, anyways). Below is my code:
window.onload = function () {
var s = Snap("#headDiv");
Snap.load("emotions.svg", function(f) {
eyes = f.select("#eyes");
lids = f.select("#lids");
head = f.select("#head");
s.append(f);
});
};
So while this works fine from a server, I'd like to get this to run locally. What would be my best option to include my emotions.svg file without making an AJAX request?
I know it's easy to just throw the SVG in the DIV, but I wasn't able to access the fragments that way with my current script. Any ideas?
Changing:
window.onload = function () {
var s = Snap("#headDiv");
Snap.load("emotions.svg", function(f) {
eyes = f.select("#eyes");
lids = f.select("#lids");
head = f.select("#head");
s.append(f);
});
};
To simply:
window.onload = function () {
eyes = Snap.select("#eyes");
lids = Snap.select("#lids");
head = Snap.select("#head");
};
And then placing the actual SVG script in the target DIV worked great.

Using script variables in html body

I want to call the variable from the script to body.
Here is my script code. I want to take the rightanswers and wronganswers values to use in html body.
GetFeedback = function (a) {
if (a == CorrectAnswer) {
rightanswers++;
} else {
wronganswers++;
}
lock = true;
}
You need to use the Document Object Modle. You have different methods with JavaScript to create and insert elements into the DOM. As for example:
var element = document.createElement('p');
var body = document.body;
body.appendChild(element);
With that code you are creating an element, then appendig it into the body. And that is pure JavaScript. You could use Mootools or jQuery, and It is goign to be simpler. But JavaScript doesn't work like PHP for example, where you can use the variables mixed up with the HTML.
And if you want to trigger the function from the HTML you need to bind thtat function to an event. For example clicking on a link would be.
HTML
Click Here
JS
var b = document.getElementById('button');
b.click = function(){
GetFeedback();
}
Make sure you're declaring the variable (we can't see that in the code provided) by using var:
<script>
var GetFeedback = function (a) {
if (a == CorrectAnswer) {
rightanswers++;
} else {
wronganswers++;
}
lock = true;
</script>
Then in your HTML, you can use feedback like this (although, it's not good practice to use the below, it's merely for demonstration purposes):
Hello
you can use jquery to change the html on the page.
GetFeedback = function(a){
if(a==CorrectAnswer){
rightanswers++;
}else{
wronganswers++;
}
lock=true;
$('p:first').html('Right Answers: '+rightanswers+' <br> Wrong Answers: '+wronganswers);
};
and have this as your html
<body>
<p></p>
Get Feedback
</body>

ReferenceError: Can't find variable: $

Hi All i'm developping a game when i run it on chrome it works but when i try it on the emulator i'm getting an error in my javascript code that i can't understand the source or the cause
here's the error:
05-13 11:53:11.726: E/Web Console(790): ReferenceError: Can't find variable: $ at file:///android_asset/www/js/html5games.matchgame6.js:5
the error is in line 5: here's my javascript file content:
var matchingGame = {};
***var uiPlay1 = $("#gamePlay1");*** //////line 5
var uiPlay2 = $("#gamePlay2");
var uiIntro = $("#popup");
var uiExit = $("#gameExit");
var uiNextLevel = $("#gameNextLevel");
var uigameQuit =$("#gameQuit");
var uiPlay3 = $("#gamePlay3");
matchingGame.savingObject = {};
matchingGame.savingObject.deck = [];
matchingGame.savingObject.removedCards = [];
// store the counting elapsed time.
matchingGame.savingObject.currentElapsedTime = 0;
//store the last-elapsed-time
//matchingGame.savingObject.LastElapsedTime = 0;//now
// store the player name
matchingGame.savingObject.palyerName=$("#player-name").html();
matchingGame.savingObject.currentLevel="game6.html";
// all possible values for each card in deck
matchingGame.deck = [
'cardAK', 'cardAK',
'cardAQ', 'cardAQ',
'cardAJ', 'cardAJ',
];
$( function(){init();} );
//initialise game
function init() {
$("#game").addClass("hide");
$("#cards").addClass("hide");
uiPlay1.click(function(e) {
e.preventDefault();
$("#popup").addClass("hide");
startNewGame();
});
uiPlay2.click(function(e) {
e.preventDefault();
$("#popup").addClass("hide");
var savedObject = savedSavingObject();
// location.href =savedObject.currentLevel ;
if (savedObject.currentLevel=="game6.html")
rejouer();
else
location.href =savedObject.currentLevel ;
//ResumeLastGame();
//alert ("level :"+savedObject.currentLevel );
});
uiExit.click(function(e) {e.preventDefault();
//alert("u clicked me ");
}
);
uiPlay3.click(function(e) {
e.preventDefault();
$("#popupHelp").fadeIn(500, function() {
$(this).delay(10000).fadeOut(500)}); });
}
Any idea please thank u in advance
You probably didn't include jQuery.
Presumably you haven't defined the $ function anywhere.
Perhaps you a working from documentation that assumes you have loaded Prototype.js, Mootools, jQuery or one of the many other libraries that set up a variable of that (very poor) name.
make sure you have loaded jquery, mootools, other javascript libraries etc before you use the $.
Have you included your library at the end of your document and you have your script written before the library is downloaded.
make sure you have a script tag that refers to your library and then have your script content.
Also one more thing to note is that your document may not have been loaded when your scriot is executed and some of the controls might not exist on the page, thus make sure you wrap them in an API that will run the function once the document is loaded completely. In jquery you use $(document).ready(function(){});
I am developing a JS app in Ejecta. jQuery was included but the DOM ready doesn't work with Ejecta. Instead on site/app initialization I do something like this:
function func() {
init();
animate();
}
setTimeout(func, 1000);
This gives jQuery time to be loaded and parsed.

Categories