Blame view

node_modules/private/README.md 7.87 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  # private [![Build Status](https://travis-ci.org/benjamn/private.png?branch=master)](https://travis-ci.org/benjamn/private) [![Greenkeeper badge](https://badges.greenkeeper.io/benjamn/private.svg)](https://greenkeeper.io/)
  
  A general-purpose utility for associating truly private state with any JavaScript object.
  
  Installation
  ---
  
  From NPM:
  
      npm install private
  
  From GitHub:
  
      cd path/to/node_modules
      git clone git://github.com/benjamn/private.git
      cd private
      npm install .
  
  Usage
  ---
  **Get or create a secret object associated with any (non-frozen) object:**
  ```js
  var getSecret = require("private").makeAccessor();
  var obj = Object.create(null); // any kind of object works
  getSecret(obj).totallySafeProperty = "p455w0rd";
  
  console.log(Object.keys(obj)); // []
  console.log(Object.getOwnPropertyNames(obj)); // []
  console.log(getSecret(obj)); // { totallySafeProperty: "p455w0rd" }
  ```
  Now, only code that has a reference to both `getSecret` and `obj` can possibly access `.totallySafeProperty`.
  
  *Importantly, no global references to the secret object are retained by the `private` package, so as soon as `obj` gets garbage collected, the secret will be reclaimed as well. In other words, you don't have to worry about memory leaks.*
  
  **Create a unique property name that cannot be enumerated or guessed:**
  ```js
  var secretKey = require("private").makeUniqueKey();
  var obj = Object.create(null); // any kind of object works
  
  Object.defineProperty(obj, secretKey, {
    value: { totallySafeProperty: "p455w0rd" },
    enumerable: false // optional; non-enumerability is the default
  });
  
  Object.defineProperty(obj, "nonEnumerableProperty", {
    value: "anyone can guess my name",
    enumerable: false
  });
  
  console.log(obj[secretKey].totallySafeProperty); // p455w0rd
  console.log(obj.nonEnumerableProperty); // "anyone can guess my name"
  console.log(Object.keys(obj)); // []
  console.log(Object.getOwnPropertyNames(obj)); // ["nonEnumerableProperty"]
  
  for (var key in obj) {
    console.log(key); // never called
  }
  ```
  Because these keys are non-enumerable, you can't discover them using a `for`-`in` loop. Because `secretKey` is a long string of random characters, you would have a lot of trouble guessing it. And because the `private` module wraps `Object.getOwnPropertyNames` to exclude the keys it generates, you can't even use that interface to discover it.
  
  Unless you have access to the value of the `secretKey` property name, there is no way to access the value associated with it. So your only responsibility as secret-keeper is to avoid handing out the value of `secretKey` to untrusted code.
  
  Think of this style as a home-grown version of the first style. Note, however, that it requires a full implementation of ES5's `Object.defineProperty` method in order to make any safety guarantees, whereas the first example will provide safety even in environments that do not support `Object.defineProperty`.
  
  Rationale
  ---
  
  In JavaScript, the only data that are truly private are local variables
  whose values do not *leak* from the scope in which they were defined.
  
  This notion of *closure privacy* is powerful, and it readily provides some
  of the benefits of traditional data privacy, a la Java or C++:
  ```js
  function MyClass(secret) {
      this.increment = function() {
          return ++secret;
      };
  }
  
  var mc = new MyClass(3);
  console.log(mc.increment()); // 4
  ```
  You can learn something about `secret` by calling `.increment()`, and you
  can increase its value by one as many times as you like, but you can never
  decrease its value, because it is completely inaccessible except through
  the `.increment` method. And if the `.increment` method were not
  available, it would be as if no `secret` variable had ever been declared,
  as far as you could tell.
  
  This style breaks down as soon as you want to inherit methods from the
  prototype of a class:
  ```js
  function MyClass(secret) {
      this.secret = secret;
  }
  
  MyClass.prototype.increment = function() {
      return ++this.secret;
  };
  ```
  The only way to communicate between the `MyClass` constructor and the
  `.increment` method in this example is to manipulate shared properties of
  `this`. Unfortunately `this.secret` is now exposed to unlicensed
  modification:
  ```js
  var mc = new MyClass(6);
  console.log(mc.increment()); // 7
  mc.secret -= Infinity;
  console.log(mc.increment()); // -Infinity
  mc.secret = "Go home JavaScript, you're drunk.";
  mc.increment(); // NaN
  ```
  Another problem with closure privacy is that it only lends itself to
  per-instance privacy, whereas the `private` keyword in most
  object-oriented languages indicates that the data member in question is
  visible to all instances of the same class.
  
  Suppose you have a `Node` class with a notion of parents and children:
  ```js
  function Node() {
      var parent;
      var children = [];
  
      this.getParent = function() {
          return parent;
      };
  
      this.appendChild = function(child) {
          children.push(child);
          child.parent = this; // Can this be made to work?
      };
  }
  ```
  The desire here is to allow other `Node` objects to manipulate the value
  returned by `.getParent()`, but otherwise disallow any modification of the
  `parent` variable. You could expose a `.setParent` function, but then
  anyone could call it, and you might as well give up on the getter/setter
  pattern.
  
  This module solves both of these problems.
  
  Usage
  ---
  
  Let's revisit the `Node` example from above:
  ```js
  var p = require("private").makeAccessor();
  
  function Node() {
      var privates = p(this);
      var children = [];
  
      this.getParent = function() {
          return privates.parent;
      };
  
      this.appendChild = function(child) {
          children.push(child);
          var cp = p(child);
          if (cp.parent)
              cp.parent.removeChild(child);
          cp.parent = this;
          return child;
      };
  }
  ```
  Now, in order to access the private data of a `Node` object, you need to
  have access to the unique `p` function that is being used here.  This is
  already an improvement over the previous example, because it allows
  restricted access by other `Node` instances, but can it help with the
  `Node.prototype` problem too?
  
  Yes it can!
  ```js
  var p = require("private").makeAccessor();
  
  function Node() {
      p(this).children = [];
  }
  
  var Np = Node.prototype;
  
  Np.getParent = function() {
      return p(this).parent;
  };
  
  Np.appendChild = function(child) {
      p(this).children.push(child);
      var cp = p(child);
      if (cp.parent)
          cp.parent.removeChild(child);
      cp.parent = this;
      return child;
  };
  ```
  Because `p` is in scope not only within the `Node` constructor but also
  within `Node` methods, we can finally avoid redefining methods every time
  the `Node` constructor is called.
  
  Now, you might be wondering how you can restrict access to `p` so that no
  untrusted code is able to call it. The answer is to use your favorite
  module pattern, be it CommonJS, AMD `define`, or even the old
  Immediately-Invoked Function Expression:
  ```js
  var Node = (function() {
      var p = require("private").makeAccessor();
  
      function Node() {
          p(this).children = [];
      }
  
      var Np = Node.prototype;
  
      Np.getParent = function() {
          return p(this).parent;
      };
  
      Np.appendChild = function(child) {
          p(this).children.push(child);
          var cp = p(child);
          if (cp.parent)
              cp.parent.removeChild(child);
          cp.parent = this;
          return child;
      };
  
      return Node;
  }());
  
  var parent = new Node;
  var child = new Node;
  parent.appendChild(child);
  assert.strictEqual(child.getParent(), parent);
  ```
  Because this version of `p` never leaks from the enclosing function scope,
  only `Node` objects have access to it.
  
  So, you see, the claim I made at the beginning of this README remains
  true:
  
  > In JavaScript, the only data that are truly private are local variables
  > whose values do not *leak* from the scope in which they were defined.
  
  It just so happens that closure privacy is sufficient to implement a
  privacy model similar to that provided by other languages.