I'm looking for a Javascript obfuscation tool that will be able to obfuscate specific string literals.
I have a class function like this:
function Mapper() {
var map = {};
this.put = function(name, val) {
map[name] = val;
};
this.get = function(name) {
return map[name];
};
}
And it's used like this throughout my code:
var mapper = new Mapper();
mapper.put("first", 123);
mapper.put("second", 999);
var value = mapper.get("first");
// etc...
I want to obfuscate the key names - "first", "second" - since they are only relevant during development.
I obviously need these strings to be obfuscated only where they are used in context with the mapper put() or get() methods, but this is not an issue because the keys I use are not used anywhere else in my application.
However, I don't want ALL the string literals in my app to be obfuscated. Not all string literals are used as object property keys.
I wouldn't mind manually defining a list of keys that should be obfuscated if the tool requires me to do so.
How can this be done?
Is there a way to do this with one of the commonly used obfuscation tools like Closure Compiler, YUI, unglifyjs, or anything similar?
The Closure Compiler has both a "ReplaceStrings" and support for replacing "id generators". Without more details, I would assume the id generator replacement is what you want.
Related
Example use case:
I have an object with an attribute "myProperty", having getter and setter ("Property Getters and Setters" are supported since EcmaScript 5: https://www.w3schools.com/js/js_es5.asp):
var obj = {
myProperty:'myPropertyValue',
get myProperty(){
return this.property;
},
set myProperty(value){
this.property=value;
}
};
I would like to bind that attribute to a view, which is the task of a custom function that is called bindProperty.
In order to pass the property myProperty to the function, I could do something like
bindProperty(obj, 'myProperty');
However, I would like to avoid to pass the property name as a hard coded String. Strings have the disadvantage, that they are not updated when the attribute name changes during refactoring.
If I would use
bindProperty(obj, obj.myProperty);
the function would only know the property value 'myPropertyValue' and not where the value comes from.
=>How can I pass/identify the property itself, without using a String?
A. Using reflection?
I could imagine something like
bindProperty(obj, ()=>obj.myProperty);
The function bindProperty would then have to do some reflection magic to find out the name of the attribute in the body of the lambda expression (pseudo code):
let attributeName = getNameofArgumentFromBodyOfLambdaExpression(lambda);
obj[attributeName] = 'newValue';
=>Is it possible in JavaScript to evaluate the body of the lambda expression using reflection to get the name of the property?
(I know that this can be done in .NET languages, e.g.
Private Sub BindProperty(Of T)(propertyExpression As Expression(Of Func(Of T)))
Dim propertyName As String = GetPropertyName(propertyExpression)
'...
)
B. Using complex attributes
An alternative whould be that I use wrapping property objects, having their own getters and setters. Howerver, then I would have to use the property like
obj.myProperty.set('newValue')
or
obj.myProperty('newValue') //similar to knockout observables
I still want to be able to use the great Getter/Setter feature. With other words: I want to use my properties like plain attributes:
obj.myProperty = 'newValue'
Therefore, this is not an option for me and I would prefer to use Strings instead of B.
C. Any other alternatives?
An object in javascript is more or less just a mapping of strings or symbols to values. There is no real reflection that you can call upon in the runtime environment that would enable you to move backward from the value to the property name.
If all you need is refactoring, the one way to do this would be to just configure your IDE to recognize string accessors by providing some sort of type information either via Flow or Typescript or something of that sort (the type information is likely what allows reflection to work in languages like .NET). Or you could just settle for a unique prefix like "viewable_propName" and just do simple find and replace if you need to rename.
If you are really focused on getting this to work without type information and in current ES6 syntax, you could do the following:
function getNameofPropFromVal(obj, val){
for(let prop in obj){
if(obj[prop] === val) return prop;
}
}
obj[getNameofPropFromVal(obj, obj.myProp)] = 'newVal';
Though this has shortcomings:
(1) There is no guarantee that two properties won't share the same value.
(2) It introduces unnecessary runtime overhead.
Finally, if you're willing to be cutting edge and use a transformer like babel you could use decorators for your bindProperty method. That way you can just do the binding in the object definition itself. Here is an article explaining the gist and here is the more formal ECMAScript proposal.
I just found following simple work around that might fullfill my needs:
function bindProperty(obj, lambdaExpression){
let expression = lambdaExpression.toString(); // "()=> obj.myProperty"
let subStrings = expression.split(".");
let propertyName = subStrings[1];
console.info(propertyName );
//...
}
To my knowledge, the Symbol primitive in JavaScript ES6 is particularly useful for two things:
Create unique keys for Object properties
Override standard built-in JavaScript Object methods, properties and operators
For example: Symbol.hasInstance is called when (before) instanceof runs
Thus, if we create a custom version of Symbol.hasInstance, we could override the behavior of instanceof
My somewhat basic question is: Why use a Symbol to override these functions? Can't we just override them directly?
For example: Override String.prototype.match() instead of Symbol.match
Edit: Agree with the commenter that overriding instanceof directly would not work, thus using match() as an example instead.
You didn't quite elaborate enough in your question, but from a bit of inference and the comments, it seems like you are be misunderstanding how well-known symbols are used to interact with existing types. That is causing you to misunderstand how they improve over possible ES5 global overwriting solutions.
It's important to understand that the value of String.match is a symbol, not a function for matching. It is almost as if someone had done
Symbol.match = Symbol("match");
at the top of your program to create a new Symbol, and set it as a global property so anyone can access it from anywhere.
This is in contrast with the value of String.prototype.match which is the actual function that is used when developers call "foo".match(...).
You seem to be envisioning String.prototype.match like
String.prototype.match = function(obj) {
return Symbol.match(obj);
};
which is not the case. Looking at a simplified example of the actual implementation may help you understand:
String.prototype.match = function(obj) {
// Any object that has a `Symbol.match` property
// will just call that property. This includes every
// existing RegExp object.
if (obj != null && obj[Symbol.match] !== undefined) {
return obj[Symbol.match](this);
}
// Otherwise create a new regex to match against
// match match using that. This is to handle strings, e.g
// "foo".match("f")
const reg = new RegExp(obj);
return reg[Symbol.match](this);
};
and remember, obj[Symbol.match](this); is not calling Symbol.match(), it is reading a property from obj with the name Symbol.match, and then calling the resulting function.
Why use a Symbol to override these functions?
Hopefully that example makes the reasoning behind this clearer.
var regexp = new RegExp("little");
var result = "a little pattern".match(regexp);
is essentially identical to doing
var regexp = new RegExp("little");
var result = regexp[Symbol.match]("a little pattern");
So why does this matter? Because now when you're designing an API to process text, you aren't limited to doing so with regular expressions. I could make my own whole library as
class MyOwnMatcher {
constructor(word) {
this.word = word;
}
[Symbol.match](haystack) {
return haystack.indexOf(this.word);
}
}
var index = "a little pattern".match(new MyOwnMatcher("little"));
// index === 2
and most importantly, I'm able to do this without having to change any globals. In JS code generally it's considered bad practice to modify globals unless you're polyfilling an officially specced and adopted API. You could implement the above like
var original = String.prototype.match;
String.prototype.match = function(arg) {
if (arg instanceof MyOwnMatcher) return this.indexOf(arg);
return original.apply(this, arguments);
};
but it's extremely ugly, easy to get wrong, and modifies a global object that isn't one that you've defined in your own code.
You can essentially think of well-known symbols as a way to implement an interface defined by a separate piece of code.
I had some legacy JS code that creates a giant nested object structure with [].
The code goes some like this
var data = [];
data ["first"] = [];
data ["first"]["second"] = [];
data ["first"]["second2"] = "hello";
It is about 250+ KB of javascript, which is fairly large. When I try to wrap it around with requirejs to load into another requirejs module, it throws Out Of Memory error.
The error goes away if I use {} where I was using [].
I did some homework on [] vs. {} over the weekend and the cause seems to be that using associated arrays as nested dictionaries may be leaky in Javascript since array extends a JS Object and may have more update stuff going on when appending new objects into it. But does it explain the memory consumption issue? Or it is related to how Requirejs parse a module's object?
I don't have enough knowledge about doing JS memory instrumentation and make comparisons between using {} or [] in browser engines, so it is hard to reach conclusions. Any hint or suggestion on how to instrument {} vs. [] would be welcome.
Update: I tried some sizeOf() via node yesterday. I used all of the existing ones: "js-sizeof", "object-sizeof", "sizeof"
Code:
var sizeof = require('object-sizeof');
var obj = [];
obj['ball'] = 'hello';
obj['air'] = 'hello';
obj['ball']['fire'] = 'world';
obj['ball']['ice'] = [];
console.log(sizeof(obj));
var obj2 = {};
obj2['ball'] = 'hello';
obj2['air'] = 'hello';
obj2['ball']['fire'] = 'world';
obj2['ball']['ice'] = [];
console.log(sizeof(obj2));
The results is
[]: 34
{}: 34
The sizeOf is actually the same., but maybe something else happened with [] that could trigger out of memory issue. I am not sure if it is the requirejs parsing it that trigger it or some V8 optimization path. I don't think the Lint tools even suggest against this practice so it is rather ambiguous which way is the "right" way in practice
There is no such thing as an "associated array" in JavaScript. [ 1, 2, 3 ] is array literal syntax; it initializes an Array. { foo: "bar" } is object literal syntax; it initializes an Object. A quirk of JavaScript, however, is that Arrays also happen to be Objects, which is why this code "works":
var data = [];
data["first"] = [];
data["first"]["second"] = [];
...but you shouldn't do it, because it doesn't make any sense. You're initializing an empty Array ([]), but then you're not using it like an Array—you're using it like an Object. If you're using property names (data["first"], which is equivalent to data.first) instead of integer keys (data[0]), then you want to use an Object. There is no scenario in which you should initialize an Array when you're going to use it like an Object.
As a rule of thumb, if you need each item to have a name, or need to be able to access them quickly by a name, use an Object ({}) and use strings for keys. If you need to be able to iterate over the items in order, use an Array with integers for keys.
I don't know the exact cause of your out-of-memory error—especially not without seeing your actual code—but it is definitely the case that you should be using an Object ({}), not an Array ([]) when you're not using integer keys. JavaScript engines optimize everything they can, and Arrays and Objects are no exception, so it's not surprising that when you use an Array in a way that the engine doesn't expect it might cause performance or memory problems.
P.S. As a matter of style, consider using property notation (or "dot notation," i.e. foo.bar) instead of subscript notation (i.e. foo["bar"]) when dealing with Objects:
var data = {};
data.first = {};
data.first.second = {};
data.first.second2 = "hello";
This is exactly equivalent to the code you posted, but it's easier to read and might help you remember that Objects and Arrays have different uses. You could also just express this as a single object literal:
var data = {
first: {
second: {},
second2: "hello"
}
};
This is also exactly equivalent and helps you see the "structure" of your object (as long as you're disciplined about indentation).
Most JavaScript style guides say that you should always use "dot notation" unless you have keys that would cause a syntax error. For example, if you have a property named "foo/bar", you obviously can't do this:
var obj.foo/bar = 1;
...because it's a syntax error. So you have to do this:
var obj["foo/bar"] = 1;
...which is perfectly valid. These cases tend to be the exception, so I would encourage to always use dot notation unless you have to use subscript notation.
I'm writing a library that I hope to be compatible with Closure Compiler in Advanced mode. Most objects in the library maintain an internal object of attributes that are frequently part of the API, which leads to my source files being filled with lots and lots of functions like this.
/*
* Get name.
*/
Layer.prototype.getName = function() {
return this.attrs.name;
}
/*
* Set name.
*/
Layer.prototype.setName = function(name) {
this.attrs.name = name;
}
I can think of a billion ways to optimize this to declutter my code a bit. One example: KineticJS, as per this related question, does something a bit like this:
Global.addGettersSetters = function(obj, property) {
obj['get'+property] = function() { return this.attrs[property] }
obj['set'+property] = function(val) { this.attrs[property] = val }
}
// Later that day, in our original object, we have:
Global.addGettersSetters(Layer, 'name');
My understanding is that this is a no-no with Closure Compiler--the names won't be shortened and the functions won't be optimized because I'm specifying the properties of Layer as strings.
So, is there a way for me to fully and properly define the interface without cluttering up my code? Something in the Closure Library I've overlooked, perhaps?
An alternative solution: is there a way to do C#-style properties in modern JS? In a way Closure Compiler finds permissible? I have the luxury of targeting Webkit and only Webkit with this library, so stuff that's not yet fully implemented is fine.
If the getters/setters are public anyway, then you need them to not be renamed in the minified js. That means having them use strings for names is fine - they won't be minified but that's what you wanted.
Yes, modern JS has getters/setters.
You cannot dynamically add a function which could then be compiled (and minified/obfuscated) by the Closure Compiler because that dynamic "addGettersSetters" function would only be used at runtime, so the compiler has no knowledge of what it could be creating. The downside of using the compiler is a lot of duplicate pre-compiled code, but the benefit is that the majority of the places where your getters and setters are used will either be minified or just changed to inline references to the variables.
Also, by putting in explicit getters/setters and properly annotating them with JsDoc annotations:
/*
* Set name.
* #param {string} name
*/
Layer.prototype.setName = function(name) {
this.attrs.name = name;
}
you can add some level of type safety to your code to ensure you get a warning during compilation if someone calls "setName(5)".
Otherwise I would follow Chris's suggestion and look into JS getters / setters (other reference here). I have not used these with the closure compiler though so I cannot vouch for them.
Sorry, I don't get the ne8il answer and why it was marked as the correct one.
You can do what you want by just adding .prototype between obj and [ like this:
function addGettersSetters(obj, property) {
// You can also add this if you don't want to declare attrs = {} each time
// if (!("attrs" in obj.prototype)) obj.prototype.attrs = {};
obj.prototype['get'+property] = function() { return this.attrs[property] }
obj.prototype['set'+property] = function(val) { this.attrs[property] = val }
}
And also writing the property name with capital letter. Then you can use it like this:
var Layer = function() { this.attrs = {}; };
// Or just: 'var Layer = function(){};' if you use the line commented above
addGettersSetters(Layer, 'Name');
var layer = new Layer();
layer.setName("John");
alert(layer.getName()); // "John"
Not a complete answer of the original question, just adding some info.
You can see how various JavaScript OOP frameworks handle getters/setters e.g. here: jsPerf.com - JavaScript Object Oriented Libraries Benchmark with getters and setters
is there a way for me to fully and properly define the interface without cluttering up my code?
Tan Nhu (original author of the benchmark) created his own OOP library jsface which is available at: https://github.com/tnhu/jsface
I like it, I use it for exactly this reason
EDIT: how are the getters/setters generator solved in TypeScript is mentioned e.g. in SO article get and set in TypeScript
For more complete list of other frameworks and their way of encoding getters/setters you can check List of languages that compile to JS · jashkenas/coffeescript Wiki · GitHub
I'm trying to use the unobtrusive date picker in an old liferay project (3.6) which I believe is running prototype.js.
I have a call like this:
datePickerController.createDatePicker({formElements:{"elementId":"%d/%m/%Y"}});
made to this:
createDatePicker: function(options) { addDatePicker(options); },
I've not been able to use a variable in place of a hard-coded elementId. I've tried array indexing, dot indexing, string variable, etc. but can't get it to work.
It looks to me like the called function only wants a generally unspecified object, yet if I do one of the above (array, dot, etc.) the browser complains about the bracket (array indexed), the dot (dot indexing), parens or anything other than the expected format.
The underlying called module (addDatePicker) expects formElements so I can't change that.
I don't understand how the browser knows enough to complain about the format of the function's parameter...obviously I'm seriously lacking here!
Pointers greatly appreciated.
e.g.
obj[tag] = 'elementId';
datePickerController.createDatePicker({formElements:{obj[tag]:"%d/%m/%Y"}});
// SCRIPT1003: Expected ':'
You can't put a variable key in an object literal - the syntax requires that the keys be constant values.
You'll need to create the object and fill it, and then pass it:
var obj = {};
var tag = 'elementId';
obj[tag] = "%d/%m/%Y";
// you now have obj = { elementId: "%d/%m/%Y" }
...createDatePicker({ formElements: obj });