Skip to content

Instantly share code, notes, and snippets.

@BonsaiDen
Created September 2, 2011 22:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BonsaiDen/1190086 to your computer and use it in GitHub Desktop.
Save BonsaiDen/1190086 to your computer and use it in GitHub Desktop.
Perverted JavaScript... checking for access violations based on member prefixing!
/**
* Copyright (c) 2011 Ivo Wetzel.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
(function(exports) {
var protectId = 0;
function guard(clas, raise) {
var e = function() {};
e.prototype = clas.prototype;
e.prototype.constructor = clas;
return function() {
var instance = new e();
clas.apply(instance, arguments);
shield(instance, clas, raise);
return instance;
};
}
function shield(obj, clas, raise) {
var proto = clas.prototype;
function accessViolation(key, f, type, value) {
var detail = value ? key + ' (' + value + ')' : key,
msg = 'Access violation [' + type + ': ' + detail + '] on ';
f = f ? f.caller || window : window;
var error = new AccessError(f, msg, type, obj, f, value);
if (raise) {
throw error;
}
}
function protectProperty(key, read) {
var stored = obj[key];
Object.defineProperty(obj, key, {
configurable: false,
enumerable: !read,
set: function sf(value) {
if (clas.___protectId !== sf.caller.___protectId) {
accessViolation(key, sf, 'write', value);
}
stored = value;
},
get: function gf() {
if (read && clas.___protectId !== gf.caller.___protectId) {
accessViolation(key, gf, 'read', stored);
}
return stored;
}
});
}
function protectMethod(proto, method) {
var func = proto[method];
Object.defineProperty(obj, method, {
configurable: false,
enumerable: false,
get: function f(value) {
if (clas.___protectId !== f.caller.___protectId) {
accessViolation(method, f, 'call');
}
return func;
}
});
}
// Protect properties
for(var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var sub = prop.match(/^_+/),
level = sub && sub[0].length;
if (level >= 1) {
protectProperty(prop, level === 2);
}
}
}
// Patch the prototype once for each clas
if (clas.___protectId === undefined) {
clas.___protectId = protectId++;
for(var method in proto) {
if (proto.hasOwnProperty(method)) {
proto[method].___protectId = protectId;
if (/^__/.test(method)) {
protectMethod(proto, method);
}
}
}
}
}
function AccessError(func, msg, type, object, caller, value) {
this.name = 'AccessError';
this.message = '';
this.object = object;
this.type = type;
this.caller = caller;
this.value = value;
console.error(msg, 'on', object, 'by', caller);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, func);
}
}
AccessError.prototype = new Error();
exports.guard = guard;
})(typeof window !== 'undefined' ? window : global);
function Kitten() {
this.__foo = 2;
this.__private = 16;
}
function Foo() {
this.Public = 2;
this.__private = 32;
this._protected = 'blue';
Kitten.call(this);
// Valid
this.__private = 64;
this._protected = 'red';
this.__privateMethod(this.__private);
}
Foo.prototype = {
// Valid access from within the object
test: function() {
console.log('test');
this.__setStuff(15, 'yellow');
return this.__private + this._protected;
},
__setStuff: function(a, b) {
this.__private = a;
this._protected = b;
},
__privateMethod: function(num) {
console.log('Private random number ', num);
},
_protectedMethod: function() {
}
};
function test() {
var e = new Foo(),
b = new Foo();
e.test();
var test = {
l: e
};
// Valid read
console.log(e._protected);
// Invalid writes
console.log('------- Invalid ----------');
e.__private = 128;
e._protected = 'green';
// Invalid read
console.log(e.__private);
console.log(test.l._protected);
console.log(test.l.__private);
e.__privateMethod(4);
}
Foo = guard(Foo);
test();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment