Overriding external object's function using JavaScript in Internet Explorer - javascript

I am currently working on an IE-only project which makes use of an external object model provided by the host application. Internet Explorer allows access to this external object through browser components:
http://msdn.microsoft.com/en-us/library/ie/ms535246(v=vs.85).aspx
Access to the object takes the form of JavaScript function invocations, similar to:
external.MethodName(arg1, arg2);
One of the recent changes to the application flow will introduce hundreds, if not thousands of if-statement conditionals around these JavaScript invocations, e.g.:
if (X) {
external.MethodName(arg1, arg2);
} else {
// do something else
}
Rather than modify potentially thousands of HTML files, it would seem to make sense if we could override or rewrite the external object's functions so that the if condition only appears in one place. Normally, this could be accomplished in JavaScript with:
external.OldMethodName = external.MethodName;
external.MethodName = function(arg1, arg2) {
if (X) {
external.OldMethodName(arg1, arg2);
} else {
// do something else
}
};
However, this results in an "Invalid procedure call or argument" script error, because you cannot reference the external host method this way.
I do not have access to the host application proprietary code to change the external method directly.
Is there any way I can use JavaScript to override the external object's functions, or will I need to wrap the (potential) thousands of invocations with if-statements (a very bad practice)?
UPDATE: After much back-and-forth with the client, we have managed to reach out to the third-party vendor to update the external host method, which is vastly preferable to our method of wrapping the method on the front end. I have accepted Paul's answer in the meantime.

Use toString() and eval:
var foo = external.MethodName.toString().replace("OldMethodName", "MethodName").replace("bar","baz");
eval(foo);
if(x)
{
external.OldMethodName(arg1,arg2);
}
else
{
MethodName(arg1,arg2)
}

Related

Postman:how to set up library of (semi-)complicated reusable scripts for collection

Update
I've completely rewritten this question based on subsequent investigation. Hopefully this will generate some answers.
I'm new to Postman, and trying to figure out how to most efficiently build a collection of tests for a REST application. There are a bunch of utility functions that I'd like to have accessible in each of my test scripts, but cut-and-paste-ing them in to each test script seems like a horrible solution.
In looking at the various "scopes" that Postman allows you to squirrel away data (e.g. globals, environment, collection), it seems that all of these are merely string/number stores. In other words, it properly stores them if you can/do stringify the results. But it doesn't actually allow you to store proper objects or functions. This makes sense, since each script seems to be run as a separate execution, so the idea of sharing pointers to things between different scripts doesn't make sense.
It seems like the accepted way to share utility functions is to toString() the function in the defining script (e.g. the Collection Pre-Req script), and then eval() that stringified version in the test script. For instance:
Collection Pre-Req Script
const utilFunc = () => { console.log("I am a utility function"); };
pm.environment.set("utilFunc",utilFunc.toString() );
Test Script
const utilFunc = eval(pm.environment.get("utilFunc"));
utilFunc();
The test script will successfully print to console "I am a utility function".
I've seen people do more complicated things where, if they have more than one utility function, put them in to an object like utils.func1 and utils.func2, and have the overall function return the utils object, so the test script still only has to have a single line at the top importing the whole thing.
The problem I'm running in to is scoping - since the literal text of the function is executed in the Test Script, everything thing that the utility function has to have must be in that code, or otherwise exist at eval() time in the Test Script. For instance, if I do:
Collection Pre-Req Script
const baseUtilFunc = (foo) => { console.log(foo); };
const utilFunc1 = (param) => { baseUtilFunc("One: " + param); };
const utilFunc2 = (param) => { baseUtilFunc("Two: " + param); };
pm.environment.set("utilFunc1",utilFunc1.toString() );
pm.environment.set("utilFunc2",utilFunc2.toString() );
Test Script
const utilFunc1 = eval(pm.environment.get("utilFunc1"));
const utilFunc2 = eval(pm.environment.get("utilFunc2"));
utilFunc1("Test");
This fails because, in the Test Script, baseUtilFunc does not exist. Obviously, in this example, it'd be easy to fix. But in a more complicated world where the utility functions I expect to use in my Test Scripts are themselves built on top of underlying helper functions, it gets more difficult.
So what is the right way to handle this issue? Do people just cram all the relevant logic in to one big function that they then call toString() on? Do they embed an extraction-from-environment-and-then-eval in each util function within its definition, so that it works in the Test Script context? Do they export each individual method?
There are different ways to do it. The way I did recently for one of the projects is creating a project in Git and then using raw url to fetch the data. I have a sample created at below repo
https://github.com/tarunlalwani/postman-utils
To load the file you will need to associate the below code at collection level
if (typeof pmutil == "undefined") {
var url = "https://raw.githubusercontent.com/tarunlalwani/postman-utils/master/pmutils.js";
if (pm.globals.has("pmutiljs"))
eval(pm.globals.get("pmutiljs"))
else {
console.log("pmutil not found. loading from " + url);
pm.sendRequest(url, function (err, res) {
eval(res.text());
pm.globals.set('pmutiljs', res.text())
});
}
}
As shown in below screenshot
And the later in the tests or Pre-Requests you will run the below line of code to load it
eval(pm.globals.get("pmutiljs"))
And then you can use the functions easily in test.

js - How to decorate/proxy/spy on all functions? For creating a runtime profiler

So I have this decorate function that takes an object and a method-name and wraps it with external logic.
function decorate(object, methodName) {
var originalMethod = object[methodName];
object[methodName] = function () {
// pre-logic
var retVal = originalMethod.apply(this, arguments);
// post-logic
return retVal;
};
}
Now I want to wrap ALL of the functions in my application, i.e.
All the recursive public functions of the object
All private scope functions
All anonymous functions
Anything else I might have forgotten.
My purpose in doing this is to implement a "JS Profiler" that will run alongside my application during automated testing, and output performance data to logs.
I need this for testing purposes, so the solution must have minimal changes to the actual code of my application.
Possible solutions I've considered:
Public methods can be easily traversed and replaced using a recursive object traversal function.
Some hack using eval() to be able to access private methods.
Ideally, to handle all cases, I could use a proxy HTTP server (Node.js for example) that will transform each javascript file before sending it to the browser. This way my codebase will remain clean, but my tests will have the necessary changes.
The first 2 are only partial solutions, and the last one seems like an overkill and also a potential "bug factory"...
Does anyone have any other ideas on how to achieve what I need?

Dojo module loading in general

Coming from Java/C# I struggle to understand what that actually means for me as a developer (I'm thinking too much object-oriented).
Suppose there are two html files that use the same Dojo module via require() in a script tag like so:
<script type="text/javascript">
require(["some/module"],
function(someModule) {
...
}
);
</script>
I understand that require() loads all the given modules before calling the callback method. But, is the module loaded for each and every require() where it is defined? So in the sample above is some/module loaded once and then shared between the two HTMLs or is it loaded twice (i.e. loaded for every require where it is listed in the requirements list)?
If the module is loaded only once, can I share information between the two callbacks then? In case it is loaded twice, how can I share information between those two callbacks then?
The official documentation says "The global function define allows you to register a module with the loader. ". Does that mean that defines are something like static classes/methods?
If you load the module twice in the same window, it will only load the module once and return the same object when you request it a second time.
So, if you're having two seperate pages, then it will have two windows which will mean that it will load the module two times. If you want to share information, you will have to store it somewhere (the web is stateless), you could use a back-end service + database, or you could use the HTML5 localStorage API or the IndexedDB (for example).
If you don't want that, you can always use single page applications. This means that you will load multiple pages in one window using JavaScript (asynchronous pages).
About your last question... with define() you define modules. A module can be a simple object (which would be similar to static classes since you don't have to instantiate), but a module can also be a prototype, which means you will be able to create instances, for example:
define([], function() {
return {
"foo": function() {
console.log("bar");
}
};
});
This will return the same single object every time you need it. You can see it as a static class or a singleton. If you require it twice, then it will return the same object.
However, you could also write something like this:
define([], function() {
return function() {
this.foo = function() {
console.log("bar");
};
};
});
Which means that you're returning a prototype. Using it requires you to instantiate it, for example:
require(["my/Module"], function(Module) {
new Module().foo();
});
Prototyping is a basic feature of JavaScript, but in Dojo there's a module that does that for you, called dojo/_base/declare. You will often see things like this:
define(["dojo/_base/declare"], function(declare) {
return declare([], {
foo: function() {
console.log("bar");
}
});
});
In this case, you will have to load it similarly to a prototype (using the new keyword).
You can find a demo of all this on Plunker.
You might ask, how can you tell the difference between a singleton/static class module, and a prototypal module... well, there's a common naming convention to it. When your module starts with a capital letter (for example dijit/layout/ContentPane, dojo/dnd/Moveable, ...) then it usually means the module requires instances. When the module starts with a lowercase letter, it's a static class/singleton (for example dojo/_base/declare, dijit/registry)
1) dojo require, loads the module once and then if you called it again require() will simply return if the package is already loaded. so the request will be called once and it will also call any dependencies once.
but all that if you are in the same HTML page if you leave the page and call the same module in a different page then it will be called from the server. you can also use cache in your config settings so things will be cached in the browser and the file will or not by setting the cacheBust to true if you want a fresh copy or false if you want things to be cached.
2) if you are in the same html page and domain, the module didn't change the module will be the same and you can share values and any change you make you can get it from anywhere unless you call a new instance. but that is not possible between different html pages.
3) not it is not like a static classes or methods from what I understand static methods A static class can be used as a convenient container for sets of methods that just operate on input parameters and do not have to get or set any internal instance fields..
dojo work differently it is a reference for an object if you did it in that way :
define(function(){
var privateValue = 0;
return {
increment: function(){
privateValue++;
},
decrement: function(){
privateValue--;
},
getValue: function(){
return privateValue;
}
};
});
This means every bit of code loads that module will reference the same object in memory so the value will be the same through out the use of that module.
of course that is my understanding please feel free to tell me where I am wrong.

how to unit-test private methods in jquery plugins?

Perhaps this is a bit of a novice JQuery question but:
proper jquery plugins are written inside a closure
thus only methods defining the plugin interface are accessible from the outside
sometimes (or many times) one may need helper methods that it doesn't make sense to expose as part of plugin interface (for example because they alter internal state).
how do those get unit-tested?
For example, looking at blockUI plugin, how can methods install, remove, reset get unit-tested?
To draw a parallel, in Java I would:
create a BlockUI interface containing public methods only (by definition)
create a BlockUIImpl class implementing the above interface. This class would contain install(), remove(), reset() methods that could be public, or (package) protected
So, I would unit-test the Impl but client programmers would interact with the plugin via BlockUI interface.
The same applies here as with any other language and testing privates: To test private methods, you should exercise them via the public interface. In other words, by calling your public methods, the private methods get tested in the process because the public methods rely on the privates.
Generally private methods are not tested separately from the public interface - the entire point is that they are implementation details, and tests should generally not know too much about the specifics of the implementation.
Code written inside a function in JavaScript, or closure as you called it, is not necessarily isolated from the outside of that function.
It is useful to know that functions have visibility of the scope in which they are defined. Any closure you create carries the scope, and therefore functions, of the code that contains it.
This simple example with a jQuery plugin and an artificial "namespace" might serve to prove this assumption:
// Initialise this only when running tests
my_public_test_namespace = function(){};
jQuery.fn.makeItBlue = function() {
makeItBlue(this);
function makeItBlue(object) {
object.css('color','blue');
}
if(typeof my_public_test_namespace != "undefined") {
my_public_test_namespace.testHarness = function() {
return {
_makeItBluePrivateFn: makeItBlue
}
};
}
};
$("#myElement").makeItBlue(); // make something blue, initialise plugin
console.debug(my_public_test_namespace.testHarness()._makeItBluePrivateFn);
But don't forget you shouldn't really test privates. ;)
I came up with the same question and after navigating and finding answers that not really apply, here's what I ended up to solve a similar problem.
Problem: "I have a widget that has a behavior I want to test to ensure it's working as expected, some of the methods are called internally because they have to solve internal behavior, exposing them as public does not make sense because they wont be called from outside, testing the public methods means you wont test the internals of the widget, so finally what can I do?"
Solution: "Creata a test widget that exposes the methods you are interested in testing and use them in the qunit, here is the example:"
// Namespaces to avoid having conflicts with other things defined similarly
var formeditortest = formeditortest || {};
// widget that inherits from the container I want to test
$.widget( "app.testcontainer", $.app.container, {
executeDrop: function(drop, helper) {
var self = this;
self._executeDrop(drop, helper);
}
});
// Test cases
formeditortest.testDropSimple = function(assert) {
var container = $("<div />");
container.testcontainer();
container.testcontainer("drop", 0, 3);
assert.equal(true, $(innerDiv.children()[0]).hasClass("droparea"));
});
QUnit.test(name, function( assert ) {
formeditortest.testDropSimple(assert);
formeditortest.testDropBottom(assert);
});
Using this method the inherited testcontainer could have the preparation required to test elements and then the qunit will handle the test, this solves my problem, hope this works for someone else that is having troubles to approach these kind of tests.
Critics? welcome to comment, I want to improve this if I'm doing something silly!!!

Is it possible to sandbox JavaScript running in the browser?

I'm wondering if it's possible to sandbox JavaScript running in the browser to prevent access to features that are normally available to JavaScript code running in an HTML page.
For example, let's say I want to provide a JavaScript API for end users to let them define event handlers to be run when "interesting events" happen, but I don't want those users to access the properties and functions of the window object. Am I able to do this?
In the simplest case, let's say I want to prevent users calling alert. A couple of approaches I can think of are:
Redefine window.alert globally. I don't think this would be a valid approach because other code running in the page (i.e., stuff not authored by users in their event handlers) might want to use alert.
Send the event handler code to the server to process. I'm not sure that sending the code to the server to process is the right approach, because the event handlers need to run in the context of the page.
Perhaps a solution where the server processes the user defined function and then generates a callback to be executed on the client would work? Even if that approach works, are there better ways to solve this problem?
Google Caja is a source-to-source translator that "allows you to put untrusted third-party HTML and JavaScript inline in your page and still be secure."
Have a look at Douglas Crockford's ADsafe:
ADsafe makes it safe to put guest code (such as third party scripted advertising or widgets) on any web page. ADsafe defines a subset of JavaScript that is powerful enough to allow guest code to perform valuable interactions, while at the same time preventing malicious or accidental damage or intrusion. The ADsafe subset can be verified mechanically by tools like JSLint so that no human inspection is necessary to review guest code for safety. The ADsafe subset also enforces good coding practices, increasing the likelihood that guest code will run correctly.
You can see an example of how to use ADsafe by looking at the template.html and template.js files in the project's GitHub repository.
I created a sandboxing library called jsandbox that uses web workers to sandbox evaluated code. It also has an input method for explicitly giving sandboxed code data it wouldn't otherwise be able to get.
The following is an example of the API:
jsandbox
.eval({
code : "x=1;Math.round(Math.pow(input, ++x))",
input : 36.565010597564445,
callback: function(n) {
console.log("number: ", n); // number: 1337
}
}).eval({
code : "][];.]\\ (*# ($(! ~",
onerror: function(ex) {
console.log("syntax error: ", ex); // syntax error: [error object]
}
}).eval({
code : '"foo"+input',
input : "bar",
callback: function(str) {
console.log("string: ", str); // string: foobar
}
}).eval({
code : "({q:1, w:2})",
callback: function(obj) {
console.log("object: ", obj); // object: object q=1 w=2
}
}).eval({
code : "[1, 2, 3].concat(input)",
input : [4, 5, 6],
callback: function(arr) {
console.log("array: ", arr); // array: [1, 2, 3, 4, 5, 6]
}
}).eval({
code : "function x(z){this.y=z;};new x(input)",
input : 4,
callback: function(x) {
console.log("new x: ", x); // new x: object y=4
}
});
An improved version of RyanOHara's web workers sandbox code, in a single file (no extra eval.js file is necessary).
function safeEval(untrustedCode)
{
return new Promise(function (resolve, reject)
{
var blobURL = URL.createObjectURL(new Blob([
"(",
function ()
{
var _postMessage = postMessage;
var _addEventListener = addEventListener;
(function (obj)
{
"use strict";
var current = obj;
var keepProperties =
[
// Required
'Object', 'Function', 'Infinity', 'NaN', 'undefined', 'caches', 'TEMPORARY', 'PERSISTENT',
// Optional, but trivial to get back
'Array', 'Boolean', 'Number', 'String', 'Symbol',
// Optional
'Map', 'Math', 'Set',
];
do
{
Object.getOwnPropertyNames(current).forEach(function (name)
{
if (keepProperties.indexOf(name) === -1)
{
delete current[name];
}
});
current = Object.getPrototypeOf(current);
}
while (current !== Object.prototype)
;
})(this);
_addEventListener("message", function (e)
{
var f = new Function("", "return (" + e.data + "\n);");
_postMessage(f());
});
}.toString(),
")()"],
{type: "application/javascript"}));
var worker = new Worker(blobURL);
URL.revokeObjectURL(blobURL);
worker.onmessage = function (evt)
{
worker.terminate();
resolve(evt.data);
};
worker.onerror = function (evt)
{
reject(new Error(evt.message));
};
worker.postMessage(untrustedCode);
setTimeout(function ()
{
worker.terminate();
reject(new Error('The worker timed out.'));
}, 1000);
});
}
Test it:
https://jsfiddle.net/kp0cq6yw/
var promise = safeEval("1+2+3");
promise.then(function (result) {
alert(result);
});
It should output 6 (tested in Chrome and Firefox).
As mentioned in other responces, it's enough to jail the code in a sandboxed iframe (without sending it to the server-side) and communicate with messages.
I would suggest to take a look at a small library I created mostly because of the need to providing some API to the untrusted code, just like as described in the question: there's an opportunity to export the particular set of functions right into the sandbox where the untrusted code runs. And there's also a demo which executes the code submitted by a user in a sandbox:
http://asvd.github.io/jailed/demos/web/console/
I think that js.js is worth mentioning here. It's a JavaScript interpreter written in JavaScript.
It's about 200 times slower than native JavaScript, but its nature makes it a perfect sandbox environment. Another drawback is its size – almost 600 KB, which may be acceptable for desktops in some cases, but not for mobile devices.
All the browser vendors and the HTML5 specification are working towards an actual sandbox property to allow sandboxed iframes -- but it's still limited to iframe granularity.
In general, no degree of regular expressions, etc. can safely sanitise arbitrary user provided JavaScript as it degenerates to the halting problem :-/
An ugly way, but maybe this works for you:
I took all the globals and redefined them in the sandbox scope, as well I added the strict mode so they can't get the global object using an anonymous function.
function construct(constructor, args) {
function F() {
return constructor.apply(this, args);
}
F.prototype = constructor.prototype;
return new F();
}
// Sanboxer
function sandboxcode(string, inject) {
"use strict";
var globals = [];
for (var i in window) {
// <--REMOVE THIS CONDITION
if (i != "console")
// REMOVE THIS CONDITION -->
globals.push(i);
}
globals.push('"use strict";\n'+string);
return construct(Function, globals).apply(inject ? inject : {});
}
sandboxcode('console.log( this, window, top , self, parent, this["jQuery"], (function(){return this;}()));');
// => Object {} undefined undefined undefined undefined undefined undefined
console.log("return of this", sandboxcode('return this;', {window:"sanboxed code"}));
// => Object {window: "sanboxed code"}
https://gist.github.com/alejandrolechuga/9381781
An independent JavaScript interpreter is more likely to yield a robust sandbox than a caged version of the built-in browser implementation.
Ryan has already mentioned js.js, but a more up-to-date project is JS-Interpreter. The documentation covers how to expose various functions to the interpreter, but its scope is otherwise very limited.
As of 2019, vm2 looks like the most popular and most regularly-updated solution to running JavaScript in Node.js. I'm not aware of a front-end solution.
With NISP you'll be able to do sandboxed evaluation.
Though the expression you write is not exactly JavaScript code, instead you'll write S-expressions. It is ideal for simple DSLs that doesn't demand extensive programming.
Suppose you have code to execute:
var sCode = "alert(document)";
Now, suppose you want to execute it in a sandbox:
new Function("window", "with(window){" + sCode + "}")({});
These two lines when executed will fail, because "alert" function is not available from the "sandbox"
And now you want to expose a member of window object with your functionality:
new Function("window", "with(window){" + sCode + "}")({
'alert':function(sString){document.title = sString}
});
Indeed you can add quotes escaping and make other polishing, but I guess the idea is clear.
Where is this user JavaScript code coming from?
There is not much you can do about a user embedding code into your page and then calling it from their browser (see Greasemonkey). It's just something browsers do.
However, if you store the script in a database, then retrieve it and eval() it, then you can clean up the script before it is run.
Examples of code that removes all window. and document. references:
eval(
unsafeUserScript
.replace(/\/\/.+\n|\/\*.*\*\/, '') // Clear all comments
.replace(/\s(window|document)\s*[\;\)\.]/, '') // Removes window. Or window; or window)
)
This tries to prevent the following from being executed (not tested):
window.location = 'http://example.com';
var w = window;
There are a lot of limitations you would have to apply to the unsafe user script. Unfortunately, there isn't any 'sandbox container' available for JavaScript.
I've been working on a simplistic JavaScript sandbox for letting users build applets for my site. Although I still face some challenges with allowing DOM access (parentNode just won't let me keep things secure =/), my approach was just to redefine the window object with some of its useful/harmless members, and then eval() the user code with this redefined window as the default scope.
My "core" code goes like this... (I'm not showing it entirely ;)
function Sandbox(parent){
this.scope = {
window: {
alert: function(str){
alert("Overriden Alert: " + str);
},
prompt: function(message, defaultValue){
return prompt("Overriden Prompt:" + message, defaultValue);
},
document: null,
.
.
.
.
}
};
this.execute = function(codestring){
// Here some code sanitizing, please
with (this.scope) {
with (window) {
eval(codestring);
}
}
};
}
So, I can instantiate a Sandbox and use its execute() function to get code running. Also, all new declared variables within eval'd code will ultimately bound to the execute() scope, so there will not be clashing names or messing with existing code.
Although global objects will still be accessible, those which should remain unknown to the sandboxed code must be defined as proxies in the Sandbox::scope object.
You can wrap the user's code in a function that redefines forbidden objects as parameters -- these would then be undefined when called:
(function (alert) {
alert ("uh oh!"); // User code
}) ();
Of course, clever attackers can get around this by inspecting the JavaScript DOM and finding a non-overridden object that contains a reference to the window.
Another idea is scanning the user's code using a tool like JSLint. Make sure it's set to have no preset variables (or: only variables you want), and then if any globals are set or accessed do not let the user's script be used. Again, it might be vulnerable to walking the DOM -- objects that the user can construct using literals might have implicit references to the window object that could be accessed to escape the sandbox.

Categories

Resources