Created
September 5, 2016 22:09
-
-
Save balbuf/81a77a754c0c03319452a8e5d68abf48 to your computer and use it in GitHub Desktop.
Demonstrates a method of managing protected data within objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(){ | |
// an object is used as a "key" since this object cannot be referenced outside of this scope (unless deliberately exposed) | |
// this exploits the strict equivalence of objects, requiring them to be the exact same instance to be considered equal | |
var secret = {}; | |
/** | |
* A simple contrived object to demonstrate privileged getters/setters. | |
*/ | |
function Person(name, age) { | |
this._ = new ProtectedData(secret); | |
this.setName(name); | |
this.setAge(age); | |
} | |
Person.prototype = { | |
constructor: Person, | |
getName: function() { | |
return this._.access(secret).name; | |
}, | |
setName: function(value) { | |
this._.access(secret).name = value; | |
}, | |
getAge: function() { | |
return this._.access(secret).age; | |
}, | |
setAge: function(value) { | |
this._.access(secret).age = value; | |
}, | |
}; | |
})(); | |
// create a new Person object with name and age | |
var me = new Person('Steve', 26); | |
// name is readily available via its getter | |
console.log(me.getName()); // "Steve" | |
// name can easily be set to another value | |
me.setName('Stephen'); | |
console.log(me.getName('Stephen')); // "Stephen" | |
// the ProtectedData object is exposed and accessible | |
console.log(typeof me._); // "object" | |
// ...but its underlying data object is not | |
console.log(me._.access(secret).name); // Uncaught ReferenceError: secret is not defined | |
/** | |
* The object "secret" is completely inaccessible from this scope and thus | |
* it is not possible to get at the data object within the ProtectedData object. | |
* That being said, WeakMaps (if available) present a more elegant solution: | |
* http://fitzgeraldnick.com/2014/01/13/hiding-implementation-details-with-e6-weakmaps.html | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Protected setter/getter which uses an arbitrary object as a "key". | |
* The safety comes from the object "key" existing only within the protected scope of the consuming objects. | |
* @param {object} key object used to | |
* @param {bool} silent silently fails with incorrect key instead of | |
*/ | |
function ProtectedData(key, silent) { | |
// key must be an object for it to be secure | |
if (Object(key) !== key) throw new Error('Invalid key type.'); | |
// property mapping | |
var props = Object.create(null); | |
props.__silent__ = silent; | |
// authenticate the key | |
function auth(lock) { | |
if (lock !== key) { | |
if (props.__silent__) return false; | |
throw new Error('Access denied.'); | |
} | |
return true; | |
} | |
return { | |
access: function(key) { | |
if (auth(key)) return props; | |
}, | |
setKey: function(oldKey, newKey) { | |
if (auth(oldKey)) key = newKey; | |
}, | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment