Showing
39 changed files
with
5737 additions
and
2 deletions
.gitignore.txt
0 → 100644
1 | +node_modules | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -4,13 +4,53 @@ const bodyParser = require('body-parser'); | ... | @@ -4,13 +4,53 @@ const bodyParser = require('body-parser'); |
4 | const app = express(); | 4 | const app = express(); |
5 | 5 | ||
6 | app.use(bodyParser.json()); | 6 | app.use(bodyParser.json()); |
7 | -//Home | ||
8 | -app.get('/', (req,res) => res.send('Hello world!')); | ||
9 | 7 | ||
8 | +app.use(session({ | ||
9 | + secret: 'keyboard cat', | ||
10 | + cookie: { maxAge: 60000 }, | ||
11 | + resave: false, | ||
12 | + saveUninitialized: false, | ||
13 | + })); | ||
14 | + | ||
15 | +//Home | ||
16 | +app.get('/', function(req,res){ | ||
17 | + res.send("Home page"); | ||
18 | +}) | ||
10 | //login | 19 | //login |
20 | +app.put('/login',function(req,res){ | ||
21 | + res.send("Login page"); | ||
22 | +}) | ||
11 | //logout | 23 | //logout |
24 | +app.put('/logout',function(req,res){ | ||
25 | + res.send("Logout page"); | ||
26 | +}) | ||
12 | //register | 27 | //register |
28 | +app.post('/register',function(req,res){ | ||
29 | + res.send('register page'); | ||
30 | +}) | ||
13 | //Mapmain | 31 | //Mapmain |
32 | +app.get('/Mapmain',function(req,res){ | ||
33 | + res.send('Mapmain page'); | ||
34 | +}) | ||
35 | +//Read post | ||
36 | +app.get('/Mapmain/posts/:postId',function(req,res){ | ||
37 | + var postId = req.params.postId; | ||
38 | + res.send("Mapmain post page", postId); | ||
39 | +}) | ||
40 | +//Create post | ||
41 | +app.post('/Mapmain/posts',function(req,res){ | ||
42 | + res.send("Mapmain create page"); | ||
43 | +}) | ||
44 | +//Update post | ||
45 | +app.put('/Mapmain/posts/:postId',function(req,res){ | ||
46 | + var postId = req.params.postId; | ||
47 | + res.send("Mapmain update page"); | ||
48 | +}) | ||
49 | +//Delete post | ||
50 | +app.delete('/Mapmain/posts/:postId',function(req,res){ | ||
51 | + var postId = req.params.postId; | ||
52 | + res.send("Mapmain update page"); | ||
53 | +}) | ||
14 | //Mapmain/category/:_category | 54 | //Mapmain/category/:_category |
15 | //Mapmain/post/:_pk | 55 | //Mapmain/post/:_pk |
16 | 56 | ... | ... |
1 | +1.17.1 / 2020-04-16 | ||
2 | +=================== | ||
3 | + | ||
4 | + * Fix internal method wrapping error on failed reloads | ||
5 | + | ||
6 | +1.17.0 / 2019-10-10 | ||
7 | +=================== | ||
8 | + | ||
9 | + * deps: cookie@0.4.0 | ||
10 | + - Add `SameSite=None` support | ||
11 | + * deps: safe-buffer@5.2.0 | ||
12 | + | ||
13 | +1.16.2 / 2019-06-12 | ||
14 | +=================== | ||
15 | + | ||
16 | + * Fix restoring `cookie.originalMaxAge` when store returns `Date` | ||
17 | + * deps: parseurl@~1.3.3 | ||
18 | + | ||
19 | +1.16.1 / 2019-04-11 | ||
20 | +=================== | ||
21 | + | ||
22 | + * Fix error passing `data` option to `Cookie` constructor | ||
23 | + * Fix uncaught error from bad session data | ||
24 | + | ||
25 | +1.16.0 / 2019-04-10 | ||
26 | +=================== | ||
27 | + | ||
28 | + * Catch invalid `cookie.maxAge` value earlier | ||
29 | + * Deprecate setting `cookie.maxAge` to a `Date` object | ||
30 | + * Fix issue where `resave: false` may not save altered sessions | ||
31 | + * Remove `utils-merge` dependency | ||
32 | + * Use `safe-buffer` for improved Buffer API | ||
33 | + * Use `Set-Cookie` as cookie header name for compatibility | ||
34 | + * deps: depd@~2.0.0 | ||
35 | + - Replace internal `eval` usage with `Function` constructor | ||
36 | + - Use instance methods on `process` to check for listeners | ||
37 | + - perf: remove argument reassignment | ||
38 | + * deps: on-headers@~1.0.2 | ||
39 | + - Fix `res.writeHead` patch missing return value | ||
40 | + | ||
41 | +1.15.6 / 2017-09-26 | ||
42 | +=================== | ||
43 | + | ||
44 | + * deps: debug@2.6.9 | ||
45 | + * deps: parseurl@~1.3.2 | ||
46 | + - perf: reduce overhead for full URLs | ||
47 | + - perf: unroll the "fast-path" `RegExp` | ||
48 | + * deps: uid-safe@~2.1.5 | ||
49 | + - perf: remove only trailing `=` | ||
50 | + * deps: utils-merge@1.0.1 | ||
51 | + | ||
52 | +1.15.5 / 2017-08-02 | ||
53 | +=================== | ||
54 | + | ||
55 | + * Fix `TypeError` when `req.url` is an empty string | ||
56 | + * deps: depd@~1.1.1 | ||
57 | + - Remove unnecessary `Buffer` loading | ||
58 | + | ||
59 | +1.15.4 / 2017-07-18 | ||
60 | +=================== | ||
61 | + | ||
62 | + * deps: debug@2.6.8 | ||
63 | + | ||
64 | +1.15.3 / 2017-05-17 | ||
65 | +=================== | ||
66 | + | ||
67 | + * deps: debug@2.6.7 | ||
68 | + - deps: ms@2.0.0 | ||
69 | + | ||
70 | +1.15.2 / 2017-03-26 | ||
71 | +=================== | ||
72 | + | ||
73 | + * deps: debug@2.6.3 | ||
74 | + - Fix `DEBUG_MAX_ARRAY_LENGTH` | ||
75 | + * deps: uid-safe@~2.1.4 | ||
76 | + - Remove `base64-url` dependency | ||
77 | + | ||
78 | +1.15.1 / 2017-02-10 | ||
79 | +=================== | ||
80 | + | ||
81 | + * deps: debug@2.6.1 | ||
82 | + - Fix deprecation messages in WebStorm and other editors | ||
83 | + - Undeprecate `DEBUG_FD` set to `1` or `2` | ||
84 | + | ||
85 | +1.15.0 / 2017-01-22 | ||
86 | +=================== | ||
87 | + | ||
88 | + * Fix detecting modified session when session contains "cookie" property | ||
89 | + * Fix resaving already-saved reloaded session at end of request | ||
90 | + * deps: crc@3.4.4 | ||
91 | + - perf: use `Buffer.from` when available | ||
92 | + * deps: debug@2.6.0 | ||
93 | + - Allow colors in workers | ||
94 | + - Deprecated `DEBUG_FD` environment variable | ||
95 | + - Use same color for same namespace | ||
96 | + - Fix error when running under React Native | ||
97 | + - deps: ms@0.7.2 | ||
98 | + * perf: remove unreachable branch in set-cookie method | ||
99 | + | ||
100 | +1.14.2 / 2016-10-30 | ||
101 | +=================== | ||
102 | + | ||
103 | + * deps: crc@3.4.1 | ||
104 | + - Fix deprecation warning in Node.js 7.x | ||
105 | + * deps: uid-safe@~2.1.3 | ||
106 | + - deps: base64-url@1.3.3 | ||
107 | + | ||
108 | +1.14.1 / 2016-08-24 | ||
109 | +=================== | ||
110 | + | ||
111 | + * Fix not always resetting session max age before session save | ||
112 | + * Fix the cookie `sameSite` option to actually alter the `Set-Cookie` | ||
113 | + * deps: uid-safe@~2.1.2 | ||
114 | + - deps: base64-url@1.3.2 | ||
115 | + | ||
116 | +1.14.0 / 2016-07-01 | ||
117 | +=================== | ||
118 | + | ||
119 | + * Correctly inherit from `EventEmitter` class in `Store` base class | ||
120 | + * Fix issue where `Set-Cookie` `Expires` was not always updated | ||
121 | + * Methods are no longer enumerable on `req.session` object | ||
122 | + * deps: cookie@0.3.1 | ||
123 | + - Add `sameSite` option | ||
124 | + - Improve error message when `encode` is not a function | ||
125 | + - Improve error message when `expires` is not a `Date` | ||
126 | + - perf: enable strict mode | ||
127 | + - perf: use for loop in parse | ||
128 | + - perf: use string concatination for serialization | ||
129 | + * deps: parseurl@~1.3.1 | ||
130 | + - perf: enable strict mode | ||
131 | + * deps: uid-safe@~2.1.1 | ||
132 | + - Use `random-bytes` for byte source | ||
133 | + - deps: base64-url@1.2.2 | ||
134 | + * perf: enable strict mode | ||
135 | + * perf: remove argument reassignment | ||
136 | + | ||
137 | +1.13.0 / 2016-01-10 | ||
138 | +=================== | ||
139 | + | ||
140 | + * Fix `rolling: true` to not set cookie when no session exists | ||
141 | + - Better `saveUninitialized: false` + `rolling: true` behavior | ||
142 | + * deps: crc@3.4.0 | ||
143 | + | ||
144 | +1.12.1 / 2015-10-29 | ||
145 | +=================== | ||
146 | + | ||
147 | + * deps: cookie@0.2.3 | ||
148 | + - Fix cookie `Max-Age` to never be a floating point number | ||
149 | + | ||
150 | +1.12.0 / 2015-10-25 | ||
151 | +=================== | ||
152 | + | ||
153 | + * Support the value `'auto'` in the `cookie.secure` option | ||
154 | + * deps: cookie@0.2.2 | ||
155 | + - Throw on invalid values provided to `serialize` | ||
156 | + * deps: depd@~1.1.0 | ||
157 | + - Enable strict mode in more places | ||
158 | + - Support web browser loading | ||
159 | + * deps: on-headers@~1.0.1 | ||
160 | + - perf: enable strict mode | ||
161 | + | ||
162 | +1.11.3 / 2015-05-22 | ||
163 | +=================== | ||
164 | + | ||
165 | + * deps: cookie@0.1.3 | ||
166 | + - Slight optimizations | ||
167 | + * deps: crc@3.3.0 | ||
168 | + | ||
169 | +1.11.2 / 2015-05-10 | ||
170 | +=================== | ||
171 | + | ||
172 | + * deps: debug@~2.2.0 | ||
173 | + - deps: ms@0.7.1 | ||
174 | + * deps: uid-safe@~2.0.0 | ||
175 | + | ||
176 | +1.11.1 / 2015-04-08 | ||
177 | +=================== | ||
178 | + | ||
179 | + * Fix mutating `options.secret` value | ||
180 | + | ||
181 | +1.11.0 / 2015-04-07 | ||
182 | +=================== | ||
183 | + | ||
184 | + * Support an array in `secret` option for key rotation | ||
185 | + * deps: depd@~1.0.1 | ||
186 | + | ||
187 | +1.10.4 / 2015-03-15 | ||
188 | +=================== | ||
189 | + | ||
190 | + * deps: debug@~2.1.3 | ||
191 | + - Fix high intensity foreground color for bold | ||
192 | + - deps: ms@0.7.0 | ||
193 | + | ||
194 | +1.10.3 / 2015-02-16 | ||
195 | +=================== | ||
196 | + | ||
197 | + * deps: cookie-signature@1.0.6 | ||
198 | + * deps: uid-safe@1.1.0 | ||
199 | + - Use `crypto.randomBytes`, if available | ||
200 | + - deps: base64-url@1.2.1 | ||
201 | + | ||
202 | +1.10.2 / 2015-01-31 | ||
203 | +=================== | ||
204 | + | ||
205 | + * deps: uid-safe@1.0.3 | ||
206 | + - Fix error branch that would throw | ||
207 | + - deps: base64-url@1.2.0 | ||
208 | + | ||
209 | +1.10.1 / 2015-01-08 | ||
210 | +=================== | ||
211 | + | ||
212 | + * deps: uid-safe@1.0.2 | ||
213 | + - Remove dependency on `mz` | ||
214 | + | ||
215 | +1.10.0 / 2015-01-05 | ||
216 | +=================== | ||
217 | + | ||
218 | + * Add `store.touch` interface for session stores | ||
219 | + * Fix `MemoryStore` expiration with `resave: false` | ||
220 | + * deps: debug@~2.1.1 | ||
221 | + | ||
222 | +1.9.3 / 2014-12-02 | ||
223 | +================== | ||
224 | + | ||
225 | + * Fix error when `req.sessionID` contains a non-string value | ||
226 | + | ||
227 | +1.9.2 / 2014-11-22 | ||
228 | +================== | ||
229 | + | ||
230 | + * deps: crc@3.2.1 | ||
231 | + - Minor fixes | ||
232 | + | ||
233 | +1.9.1 / 2014-10-22 | ||
234 | +================== | ||
235 | + | ||
236 | + * Remove unnecessary empty write call | ||
237 | + - Fixes Node.js 0.11.14 behavior change | ||
238 | + - Helps work-around Node.js 0.10.1 zlib bug | ||
239 | + | ||
240 | +1.9.0 / 2014-09-16 | ||
241 | +================== | ||
242 | + | ||
243 | + * deps: debug@~2.1.0 | ||
244 | + - Implement `DEBUG_FD` env variable support | ||
245 | + * deps: depd@~1.0.0 | ||
246 | + | ||
247 | +1.8.2 / 2014-09-15 | ||
248 | +================== | ||
249 | + | ||
250 | + * Use `crc` instead of `buffer-crc32` for speed | ||
251 | + * deps: depd@0.4.5 | ||
252 | + | ||
253 | +1.8.1 / 2014-09-08 | ||
254 | +================== | ||
255 | + | ||
256 | + * Keep `req.session.save` non-enumerable | ||
257 | + * Prevent session prototype methods from being overwritten | ||
258 | + | ||
259 | +1.8.0 / 2014-09-07 | ||
260 | +================== | ||
261 | + | ||
262 | + * Do not resave already-saved session at end of request | ||
263 | + * deps: cookie-signature@1.0.5 | ||
264 | + * deps: debug@~2.0.0 | ||
265 | + | ||
266 | +1.7.6 / 2014-08-18 | ||
267 | +================== | ||
268 | + | ||
269 | + * Fix exception on `res.end(null)` calls | ||
270 | + | ||
271 | +1.7.5 / 2014-08-10 | ||
272 | +================== | ||
273 | + | ||
274 | + * Fix parsing original URL | ||
275 | + * deps: on-headers@~1.0.0 | ||
276 | + * deps: parseurl@~1.3.0 | ||
277 | + | ||
278 | +1.7.4 / 2014-08-05 | ||
279 | +================== | ||
280 | + | ||
281 | + * Fix response end delay for non-chunked responses | ||
282 | + | ||
283 | +1.7.3 / 2014-08-05 | ||
284 | +================== | ||
285 | + | ||
286 | + * Fix `res.end` patch to call correct upstream `res.write` | ||
287 | + | ||
288 | +1.7.2 / 2014-07-27 | ||
289 | +================== | ||
290 | + | ||
291 | + * deps: depd@0.4.4 | ||
292 | + - Work-around v8 generating empty stack traces | ||
293 | + | ||
294 | +1.7.1 / 2014-07-26 | ||
295 | +================== | ||
296 | + | ||
297 | + * deps: depd@0.4.3 | ||
298 | + - Fix exception when global `Error.stackTraceLimit` is too low | ||
299 | + | ||
300 | +1.7.0 / 2014-07-22 | ||
301 | +================== | ||
302 | + | ||
303 | + * Improve session-ending error handling | ||
304 | + - Errors are passed to `next(err)` instead of `console.error` | ||
305 | + * deps: debug@1.0.4 | ||
306 | + * deps: depd@0.4.2 | ||
307 | + - Add `TRACE_DEPRECATION` environment variable | ||
308 | + - Remove non-standard grey color from color output | ||
309 | + - Support `--no-deprecation` argument | ||
310 | + - Support `--trace-deprecation` argument | ||
311 | + | ||
312 | +1.6.5 / 2014-07-11 | ||
313 | +================== | ||
314 | + | ||
315 | + * Do not require `req.originalUrl` | ||
316 | + * deps: debug@1.0.3 | ||
317 | + - Add support for multiple wildcards in namespaces | ||
318 | + | ||
319 | +1.6.4 / 2014-07-07 | ||
320 | +================== | ||
321 | + | ||
322 | + * Fix blank responses for stores with synchronous operations | ||
323 | + | ||
324 | +1.6.3 / 2014-07-04 | ||
325 | +================== | ||
326 | + | ||
327 | + * Fix resave deprecation message | ||
328 | + | ||
329 | +1.6.2 / 2014-07-04 | ||
330 | +================== | ||
331 | + | ||
332 | + * Fix confusing option deprecation messages | ||
333 | + | ||
334 | +1.6.1 / 2014-06-28 | ||
335 | +================== | ||
336 | + | ||
337 | + * Fix saveUninitialized deprecation message | ||
338 | + | ||
339 | +1.6.0 / 2014-06-28 | ||
340 | +================== | ||
341 | + | ||
342 | + * Add deprecation message to undefined `resave` option | ||
343 | + * Add deprecation message to undefined `saveUninitialized` option | ||
344 | + * Fix `res.end` patch to return correct value | ||
345 | + * Fix `res.end` patch to handle multiple `res.end` calls | ||
346 | + * Reject cookies with missing signatures | ||
347 | + | ||
348 | +1.5.2 / 2014-06-26 | ||
349 | +================== | ||
350 | + | ||
351 | + * deps: cookie-signature@1.0.4 | ||
352 | + - fix for timing attacks | ||
353 | + | ||
354 | +1.5.1 / 2014-06-21 | ||
355 | +================== | ||
356 | + | ||
357 | + * Move hard-to-track-down `req.secret` deprecation message | ||
358 | + | ||
359 | +1.5.0 / 2014-06-19 | ||
360 | +================== | ||
361 | + | ||
362 | + * Debug name is now "express-session" | ||
363 | + * Deprecate integration with `cookie-parser` middleware | ||
364 | + * Deprecate looking for secret in `req.secret` | ||
365 | + * Directly read cookies; `cookie-parser` no longer required | ||
366 | + * Directly set cookies; `res.cookie` no longer required | ||
367 | + * Generate session IDs with `uid-safe`, faster and even less collisions | ||
368 | + | ||
369 | +1.4.0 / 2014-06-17 | ||
370 | +================== | ||
371 | + | ||
372 | + * Add `genid` option to generate custom session IDs | ||
373 | + * Add `saveUninitialized` option to control saving uninitialized sessions | ||
374 | + * Add `unset` option to control unsetting `req.session` | ||
375 | + * Generate session IDs with `rand-token` by default; reduce collisions | ||
376 | + * deps: buffer-crc32@0.2.3 | ||
377 | + | ||
378 | +1.3.1 / 2014-06-14 | ||
379 | +================== | ||
380 | + | ||
381 | + * Add description in package for npmjs.org listing | ||
382 | + | ||
383 | +1.3.0 / 2014-06-14 | ||
384 | +================== | ||
385 | + | ||
386 | + * Integrate with express "trust proxy" by default | ||
387 | + * deps: debug@1.0.2 | ||
388 | + | ||
389 | +1.2.1 / 2014-05-27 | ||
390 | +================== | ||
391 | + | ||
392 | + * Fix `resave` such that `resave: true` works | ||
393 | + | ||
394 | +1.2.0 / 2014-05-19 | ||
395 | +================== | ||
396 | + | ||
397 | + * Add `resave` option to control saving unmodified sessions | ||
398 | + | ||
399 | +1.1.0 / 2014-05-12 | ||
400 | +================== | ||
401 | + | ||
402 | + * Add `name` option; replacement for `key` option | ||
403 | + * Use `setImmediate` in MemoryStore for node.js >= 0.10 | ||
404 | + | ||
405 | +1.0.4 / 2014-04-27 | ||
406 | +================== | ||
407 | + | ||
408 | + * deps: debug@0.8.1 | ||
409 | + | ||
410 | +1.0.3 / 2014-04-19 | ||
411 | +================== | ||
412 | + | ||
413 | + * Use `res.cookie()` instead of `res.setHeader()` | ||
414 | + * deps: cookie@0.1.2 | ||
415 | + | ||
416 | +1.0.2 / 2014-02-23 | ||
417 | +================== | ||
418 | + | ||
419 | + * Add missing dependency to `package.json` | ||
420 | + | ||
421 | +1.0.1 / 2014-02-15 | ||
422 | +================== | ||
423 | + | ||
424 | + * Add missing dependencies to `package.json` | ||
425 | + | ||
426 | +1.0.0 / 2014-02-15 | ||
427 | +================== | ||
428 | + | ||
429 | + * Genesis from `connect` |
Mapmory/node_modules/express-session/LICENSE
0 → 100644
1 | +(The MIT License) | ||
2 | + | ||
3 | +Copyright (c) 2010 Sencha Inc. | ||
4 | +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> | ||
5 | +Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com> | ||
6 | + | ||
7 | +Permission is hereby granted, free of charge, to any person obtaining | ||
8 | +a copy of this software and associated documentation files (the | ||
9 | +'Software'), to deal in the Software without restriction, including | ||
10 | +without limitation the rights to use, copy, modify, merge, publish, | ||
11 | +distribute, sublicense, and/or sell copies of the Software, and to | ||
12 | +permit persons to whom the Software is furnished to do so, subject to | ||
13 | +the following conditions: | ||
14 | + | ||
15 | +The above copyright notice and this permission notice shall be | ||
16 | +included in all copies or substantial portions of the Software. | ||
17 | + | ||
18 | +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, | ||
19 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
20 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
21 | +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
22 | +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
23 | +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
24 | +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
1 | +# express-session | ||
2 | + | ||
3 | +[![NPM Version][npm-version-image]][npm-url] | ||
4 | +[![NPM Downloads][npm-downloads-image]][node-url] | ||
5 | +[![Build Status][travis-image]][travis-url] | ||
6 | +[![Test Coverage][coveralls-image]][coveralls-url] | ||
7 | + | ||
8 | +## Installation | ||
9 | + | ||
10 | +This is a [Node.js](https://nodejs.org/en/) module available through the | ||
11 | +[npm registry](https://www.npmjs.com/). Installation is done using the | ||
12 | +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): | ||
13 | + | ||
14 | +```sh | ||
15 | +$ npm install express-session | ||
16 | +``` | ||
17 | + | ||
18 | +## API | ||
19 | + | ||
20 | +```js | ||
21 | +var session = require('express-session') | ||
22 | +``` | ||
23 | + | ||
24 | +### session(options) | ||
25 | + | ||
26 | +Create a session middleware with the given `options`. | ||
27 | + | ||
28 | +**Note** Session data is _not_ saved in the cookie itself, just the session ID. | ||
29 | +Session data is stored server-side. | ||
30 | + | ||
31 | +**Note** Since version 1.5.0, the [`cookie-parser` middleware](https://www.npmjs.com/package/cookie-parser) | ||
32 | +no longer needs to be used for this module to work. This module now directly reads | ||
33 | +and writes cookies on `req`/`res`. Using `cookie-parser` may result in issues | ||
34 | +if the `secret` is not the same between this module and `cookie-parser`. | ||
35 | + | ||
36 | +**Warning** The default server-side session storage, `MemoryStore`, is _purposely_ | ||
37 | +not designed for a production environment. It will leak memory under most | ||
38 | +conditions, does not scale past a single process, and is meant for debugging and | ||
39 | +developing. | ||
40 | + | ||
41 | +For a list of stores, see [compatible session stores](#compatible-session-stores). | ||
42 | + | ||
43 | +#### Options | ||
44 | + | ||
45 | +`express-session` accepts these properties in the options object. | ||
46 | + | ||
47 | +##### cookie | ||
48 | + | ||
49 | +Settings object for the session ID cookie. The default value is | ||
50 | +`{ path: '/', httpOnly: true, secure: false, maxAge: null }`. | ||
51 | + | ||
52 | +The following are options that can be set in this object. | ||
53 | + | ||
54 | +##### cookie.domain | ||
55 | + | ||
56 | +Specifies the value for the `Domain` `Set-Cookie` attribute. By default, no domain | ||
57 | +is set, and most clients will consider the cookie to apply to only the current | ||
58 | +domain. | ||
59 | + | ||
60 | +##### cookie.expires | ||
61 | + | ||
62 | +Specifies the `Date` object to be the value for the `Expires` `Set-Cookie` attribute. | ||
63 | +By default, no expiration is set, and most clients will consider this a | ||
64 | +"non-persistent cookie" and will delete it on a condition like exiting a web browser | ||
65 | +application. | ||
66 | + | ||
67 | +**Note** If both `expires` and `maxAge` are set in the options, then the last one | ||
68 | +defined in the object is what is used. | ||
69 | + | ||
70 | +**Note** The `expires` option should not be set directly; instead only use the `maxAge` | ||
71 | +option. | ||
72 | + | ||
73 | +##### cookie.httpOnly | ||
74 | + | ||
75 | +Specifies the `boolean` value for the `HttpOnly` `Set-Cookie` attribute. When truthy, | ||
76 | +the `HttpOnly` attribute is set, otherwise it is not. By default, the `HttpOnly` | ||
77 | +attribute is set. | ||
78 | + | ||
79 | +**Note** be careful when setting this to `true`, as compliant clients will not allow | ||
80 | +client-side JavaScript to see the cookie in `document.cookie`. | ||
81 | + | ||
82 | +##### cookie.maxAge | ||
83 | + | ||
84 | +Specifies the `number` (in milliseconds) to use when calculating the `Expires` | ||
85 | +`Set-Cookie` attribute. This is done by taking the current server time and adding | ||
86 | +`maxAge` milliseconds to the value to calculate an `Expires` datetime. By default, | ||
87 | +no maximum age is set. | ||
88 | + | ||
89 | +**Note** If both `expires` and `maxAge` are set in the options, then the last one | ||
90 | +defined in the object is what is used. | ||
91 | + | ||
92 | +##### cookie.path | ||
93 | + | ||
94 | +Specifies the value for the `Path` `Set-Cookie`. By default, this is set to `'/'`, which | ||
95 | +is the root path of the domain. | ||
96 | + | ||
97 | +##### cookie.sameSite | ||
98 | + | ||
99 | +Specifies the `boolean` or `string` to be the value for the `SameSite` `Set-Cookie` attribute. | ||
100 | + | ||
101 | + - `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement. | ||
102 | + - `false` will not set the `SameSite` attribute. | ||
103 | + - `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement. | ||
104 | + - `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie. | ||
105 | + - `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement. | ||
106 | + | ||
107 | +More information about the different enforcement levels can be found in | ||
108 | +[the specification][rfc-6265bis-03-4.1.2.7]. | ||
109 | + | ||
110 | +**Note** This is an attribute that has not yet been fully standardized, and may change in | ||
111 | +the future. This also means many clients may ignore this attribute until they understand it. | ||
112 | + | ||
113 | +##### cookie.secure | ||
114 | + | ||
115 | +Specifies the `boolean` value for the `Secure` `Set-Cookie` attribute. When truthy, | ||
116 | +the `Secure` attribute is set, otherwise it is not. By default, the `Secure` | ||
117 | +attribute is not set. | ||
118 | + | ||
119 | +**Note** be careful when setting this to `true`, as compliant clients will not send | ||
120 | +the cookie back to the server in the future if the browser does not have an HTTPS | ||
121 | +connection. | ||
122 | + | ||
123 | +Please note that `secure: true` is a **recommended** option. However, it requires | ||
124 | +an https-enabled website, i.e., HTTPS is necessary for secure cookies. If `secure` | ||
125 | +is set, and you access your site over HTTP, the cookie will not be set. If you | ||
126 | +have your node.js behind a proxy and are using `secure: true`, you need to set | ||
127 | +"trust proxy" in express: | ||
128 | + | ||
129 | +```js | ||
130 | +var app = express() | ||
131 | +app.set('trust proxy', 1) // trust first proxy | ||
132 | +app.use(session({ | ||
133 | + secret: 'keyboard cat', | ||
134 | + resave: false, | ||
135 | + saveUninitialized: true, | ||
136 | + cookie: { secure: true } | ||
137 | +})) | ||
138 | +``` | ||
139 | + | ||
140 | +For using secure cookies in production, but allowing for testing in development, | ||
141 | +the following is an example of enabling this setup based on `NODE_ENV` in express: | ||
142 | + | ||
143 | +```js | ||
144 | +var app = express() | ||
145 | +var sess = { | ||
146 | + secret: 'keyboard cat', | ||
147 | + cookie: {} | ||
148 | +} | ||
149 | + | ||
150 | +if (app.get('env') === 'production') { | ||
151 | + app.set('trust proxy', 1) // trust first proxy | ||
152 | + sess.cookie.secure = true // serve secure cookies | ||
153 | +} | ||
154 | + | ||
155 | +app.use(session(sess)) | ||
156 | +``` | ||
157 | + | ||
158 | +The `cookie.secure` option can also be set to the special value `'auto'` to have | ||
159 | +this setting automatically match the determined security of the connection. Be | ||
160 | +careful when using this setting if the site is available both as HTTP and HTTPS, | ||
161 | +as once the cookie is set on HTTPS, it will no longer be visible over HTTP. This | ||
162 | +is useful when the Express `"trust proxy"` setting is properly setup to simplify | ||
163 | +development vs production configuration. | ||
164 | + | ||
165 | +##### genid | ||
166 | + | ||
167 | +Function to call to generate a new session ID. Provide a function that returns | ||
168 | +a string that will be used as a session ID. The function is given `req` as the | ||
169 | +first argument if you want to use some value attached to `req` when generating | ||
170 | +the ID. | ||
171 | + | ||
172 | +The default value is a function which uses the `uid-safe` library to generate IDs. | ||
173 | + | ||
174 | +**NOTE** be careful to generate unique IDs so your sessions do not conflict. | ||
175 | + | ||
176 | +```js | ||
177 | +app.use(session({ | ||
178 | + genid: function(req) { | ||
179 | + return genuuid() // use UUIDs for session IDs | ||
180 | + }, | ||
181 | + secret: 'keyboard cat' | ||
182 | +})) | ||
183 | +``` | ||
184 | + | ||
185 | +##### name | ||
186 | + | ||
187 | +The name of the session ID cookie to set in the response (and read from in the | ||
188 | +request). | ||
189 | + | ||
190 | +The default value is `'connect.sid'`. | ||
191 | + | ||
192 | +**Note** if you have multiple apps running on the same hostname (this is just | ||
193 | +the name, i.e. `localhost` or `127.0.0.1`; different schemes and ports do not | ||
194 | +name a different hostname), then you need to separate the session cookies from | ||
195 | +each other. The simplest method is to simply set different `name`s per app. | ||
196 | + | ||
197 | +##### proxy | ||
198 | + | ||
199 | +Trust the reverse proxy when setting secure cookies (via the "X-Forwarded-Proto" | ||
200 | +header). | ||
201 | + | ||
202 | +The default value is `undefined`. | ||
203 | + | ||
204 | + - `true` The "X-Forwarded-Proto" header will be used. | ||
205 | + - `false` All headers are ignored and the connection is considered secure only | ||
206 | + if there is a direct TLS/SSL connection. | ||
207 | + - `undefined` Uses the "trust proxy" setting from express | ||
208 | + | ||
209 | +##### resave | ||
210 | + | ||
211 | +Forces the session to be saved back to the session store, even if the session | ||
212 | +was never modified during the request. Depending on your store this may be | ||
213 | +necessary, but it can also create race conditions where a client makes two | ||
214 | +parallel requests to your server and changes made to the session in one | ||
215 | +request may get overwritten when the other request ends, even if it made no | ||
216 | +changes (this behavior also depends on what store you're using). | ||
217 | + | ||
218 | +The default value is `true`, but using the default has been deprecated, | ||
219 | +as the default will change in the future. Please research into this setting | ||
220 | +and choose what is appropriate to your use-case. Typically, you'll want | ||
221 | +`false`. | ||
222 | + | ||
223 | +How do I know if this is necessary for my store? The best way to know is to | ||
224 | +check with your store if it implements the `touch` method. If it does, then | ||
225 | +you can safely set `resave: false`. If it does not implement the `touch` | ||
226 | +method and your store sets an expiration date on stored sessions, then you | ||
227 | +likely need `resave: true`. | ||
228 | + | ||
229 | +##### rolling | ||
230 | + | ||
231 | +Force the session identifier cookie to be set on every response. The expiration | ||
232 | +is reset to the original [`maxAge`](#cookiemaxage), resetting the expiration | ||
233 | +countdown. | ||
234 | + | ||
235 | +The default value is `false`. | ||
236 | + | ||
237 | +With this enabled, the session identifier cookie will expire in | ||
238 | +[`maxAge`](#cookiemaxage) since the last response was sent instead of in | ||
239 | +[`maxAge`](#cookiemaxage) since the session was last modified by the server. | ||
240 | + | ||
241 | +This is typically used in conjuction with short, non-session-length | ||
242 | +[`maxAge`](#cookiemaxage) values to provide a quick timeout of the session data | ||
243 | +with reduced potentional of it occurring during on going server interactions. | ||
244 | + | ||
245 | +**Note** When this option is set to `true` but the `saveUninitialized` option is | ||
246 | +set to `false`, the cookie will not be set on a response with an uninitialized | ||
247 | +session. This option only modifies the behavior when an existing session was | ||
248 | +loaded for the request. | ||
249 | + | ||
250 | +##### saveUninitialized | ||
251 | + | ||
252 | +Forces a session that is "uninitialized" to be saved to the store. A session is | ||
253 | +uninitialized when it is new but not modified. Choosing `false` is useful for | ||
254 | +implementing login sessions, reducing server storage usage, or complying with | ||
255 | +laws that require permission before setting a cookie. Choosing `false` will also | ||
256 | +help with race conditions where a client makes multiple parallel requests | ||
257 | +without a session. | ||
258 | + | ||
259 | +The default value is `true`, but using the default has been deprecated, as the | ||
260 | +default will change in the future. Please research into this setting and | ||
261 | +choose what is appropriate to your use-case. | ||
262 | + | ||
263 | +**Note** if you are using Session in conjunction with PassportJS, Passport | ||
264 | +will add an empty Passport object to the session for use after a user is | ||
265 | +authenticated, which will be treated as a modification to the session, causing | ||
266 | +it to be saved. *This has been fixed in PassportJS 0.3.0* | ||
267 | + | ||
268 | +##### secret | ||
269 | + | ||
270 | +**Required option** | ||
271 | + | ||
272 | +This is the secret used to sign the session ID cookie. This can be either a string | ||
273 | +for a single secret, or an array of multiple secrets. If an array of secrets is | ||
274 | +provided, only the first element will be used to sign the session ID cookie, while | ||
275 | +all the elements will be considered when verifying the signature in requests. | ||
276 | + | ||
277 | +##### store | ||
278 | + | ||
279 | +The session store instance, defaults to a new `MemoryStore` instance. | ||
280 | + | ||
281 | +##### unset | ||
282 | + | ||
283 | +Control the result of unsetting `req.session` (through `delete`, setting to `null`, | ||
284 | +etc.). | ||
285 | + | ||
286 | +The default value is `'keep'`. | ||
287 | + | ||
288 | + - `'destroy'` The session will be destroyed (deleted) when the response ends. | ||
289 | + - `'keep'` The session in the store will be kept, but modifications made during | ||
290 | + the request are ignored and not saved. | ||
291 | + | ||
292 | +### req.session | ||
293 | + | ||
294 | +To store or access session data, simply use the request property `req.session`, | ||
295 | +which is (generally) serialized as JSON by the store, so nested objects | ||
296 | +are typically fine. For example below is a user-specific view counter: | ||
297 | + | ||
298 | +```js | ||
299 | +// Use the session middleware | ||
300 | +app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }})) | ||
301 | + | ||
302 | +// Access the session as req.session | ||
303 | +app.get('/', function(req, res, next) { | ||
304 | + if (req.session.views) { | ||
305 | + req.session.views++ | ||
306 | + res.setHeader('Content-Type', 'text/html') | ||
307 | + res.write('<p>views: ' + req.session.views + '</p>') | ||
308 | + res.write('<p>expires in: ' + (req.session.cookie.maxAge / 1000) + 's</p>') | ||
309 | + res.end() | ||
310 | + } else { | ||
311 | + req.session.views = 1 | ||
312 | + res.end('welcome to the session demo. refresh!') | ||
313 | + } | ||
314 | +}) | ||
315 | +``` | ||
316 | + | ||
317 | +#### Session.regenerate(callback) | ||
318 | + | ||
319 | +To regenerate the session simply invoke the method. Once complete, | ||
320 | +a new SID and `Session` instance will be initialized at `req.session` | ||
321 | +and the `callback` will be invoked. | ||
322 | + | ||
323 | +```js | ||
324 | +req.session.regenerate(function(err) { | ||
325 | + // will have a new session here | ||
326 | +}) | ||
327 | +``` | ||
328 | + | ||
329 | +#### Session.destroy(callback) | ||
330 | + | ||
331 | +Destroys the session and will unset the `req.session` property. | ||
332 | +Once complete, the `callback` will be invoked. | ||
333 | + | ||
334 | +```js | ||
335 | +req.session.destroy(function(err) { | ||
336 | + // cannot access session here | ||
337 | +}) | ||
338 | +``` | ||
339 | + | ||
340 | +#### Session.reload(callback) | ||
341 | + | ||
342 | +Reloads the session data from the store and re-populates the | ||
343 | +`req.session` object. Once complete, the `callback` will be invoked. | ||
344 | + | ||
345 | +```js | ||
346 | +req.session.reload(function(err) { | ||
347 | + // session updated | ||
348 | +}) | ||
349 | +``` | ||
350 | + | ||
351 | +#### Session.save(callback) | ||
352 | + | ||
353 | +Save the session back to the store, replacing the contents on the store with the | ||
354 | +contents in memory (though a store may do something else--consult the store's | ||
355 | +documentation for exact behavior). | ||
356 | + | ||
357 | +This method is automatically called at the end of the HTTP response if the | ||
358 | +session data has been altered (though this behavior can be altered with various | ||
359 | +options in the middleware constructor). Because of this, typically this method | ||
360 | +does not need to be called. | ||
361 | + | ||
362 | +There are some cases where it is useful to call this method, for example, | ||
363 | +redirects, long-lived requests or in WebSockets. | ||
364 | + | ||
365 | +```js | ||
366 | +req.session.save(function(err) { | ||
367 | + // session saved | ||
368 | +}) | ||
369 | +``` | ||
370 | + | ||
371 | +#### Session.touch() | ||
372 | + | ||
373 | +Updates the `.maxAge` property. Typically this is | ||
374 | +not necessary to call, as the session middleware does this for you. | ||
375 | + | ||
376 | +### req.session.id | ||
377 | + | ||
378 | +Each session has a unique ID associated with it. This property is an | ||
379 | +alias of [`req.sessionID`](#reqsessionid-1) and cannot be modified. | ||
380 | +It has been added to make the session ID accessible from the `session` | ||
381 | +object. | ||
382 | + | ||
383 | +### req.session.cookie | ||
384 | + | ||
385 | +Each session has a unique cookie object accompany it. This allows | ||
386 | +you to alter the session cookie per visitor. For example we can | ||
387 | +set `req.session.cookie.expires` to `false` to enable the cookie | ||
388 | +to remain for only the duration of the user-agent. | ||
389 | + | ||
390 | +#### Cookie.maxAge | ||
391 | + | ||
392 | +Alternatively `req.session.cookie.maxAge` will return the time | ||
393 | +remaining in milliseconds, which we may also re-assign a new value | ||
394 | +to adjust the `.expires` property appropriately. The following | ||
395 | +are essentially equivalent | ||
396 | + | ||
397 | +```js | ||
398 | +var hour = 3600000 | ||
399 | +req.session.cookie.expires = new Date(Date.now() + hour) | ||
400 | +req.session.cookie.maxAge = hour | ||
401 | +``` | ||
402 | + | ||
403 | +For example when `maxAge` is set to `60000` (one minute), and 30 seconds | ||
404 | +has elapsed it will return `30000` until the current request has completed, | ||
405 | +at which time `req.session.touch()` is called to reset | ||
406 | +`req.session.cookie.maxAge` to its original value. | ||
407 | + | ||
408 | +```js | ||
409 | +req.session.cookie.maxAge // => 30000 | ||
410 | +``` | ||
411 | + | ||
412 | +#### Cookie.originalMaxAge | ||
413 | + | ||
414 | +The `req.session.cookie.originalMaxAge` property returns the original | ||
415 | +`maxAge` (time-to-live), in milliseconds, of the session cookie. | ||
416 | + | ||
417 | +### req.sessionID | ||
418 | + | ||
419 | +To get the ID of the loaded session, access the request property | ||
420 | +`req.sessionID`. This is simply a read-only value set when a session | ||
421 | +is loaded/created. | ||
422 | + | ||
423 | +## Session Store Implementation | ||
424 | + | ||
425 | +Every session store _must_ be an `EventEmitter` and implement specific | ||
426 | +methods. The following methods are the list of **required**, **recommended**, | ||
427 | +and **optional**. | ||
428 | + | ||
429 | + * Required methods are ones that this module will always call on the store. | ||
430 | + * Recommended methods are ones that this module will call on the store if | ||
431 | + available. | ||
432 | + * Optional methods are ones this module does not call at all, but helps | ||
433 | + present uniform stores to users. | ||
434 | + | ||
435 | +For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo. | ||
436 | + | ||
437 | +### store.all(callback) | ||
438 | + | ||
439 | +**Optional** | ||
440 | + | ||
441 | +This optional method is used to get all sessions in the store as an array. The | ||
442 | +`callback` should be called as `callback(error, sessions)`. | ||
443 | + | ||
444 | +### store.destroy(sid, callback) | ||
445 | + | ||
446 | +**Required** | ||
447 | + | ||
448 | +This required method is used to destroy/delete a session from the store given | ||
449 | +a session ID (`sid`). The `callback` should be called as `callback(error)` once | ||
450 | +the session is destroyed. | ||
451 | + | ||
452 | +### store.clear(callback) | ||
453 | + | ||
454 | +**Optional** | ||
455 | + | ||
456 | +This optional method is used to delete all sessions from the store. The | ||
457 | +`callback` should be called as `callback(error)` once the store is cleared. | ||
458 | + | ||
459 | +### store.length(callback) | ||
460 | + | ||
461 | +**Optional** | ||
462 | + | ||
463 | +This optional method is used to get the count of all sessions in the store. | ||
464 | +The `callback` should be called as `callback(error, len)`. | ||
465 | + | ||
466 | +### store.get(sid, callback) | ||
467 | + | ||
468 | +**Required** | ||
469 | + | ||
470 | +This required method is used to get a session from the store given a session | ||
471 | +ID (`sid`). The `callback` should be called as `callback(error, session)`. | ||
472 | + | ||
473 | +The `session` argument should be a session if found, otherwise `null` or | ||
474 | +`undefined` if the session was not found (and there was no error). A special | ||
475 | +case is made when `error.code === 'ENOENT'` to act like `callback(null, null)`. | ||
476 | + | ||
477 | +### store.set(sid, session, callback) | ||
478 | + | ||
479 | +**Required** | ||
480 | + | ||
481 | +This required method is used to upsert a session into the store given a | ||
482 | +session ID (`sid`) and session (`session`) object. The callback should be | ||
483 | +called as `callback(error)` once the session has been set in the store. | ||
484 | + | ||
485 | +### store.touch(sid, session, callback) | ||
486 | + | ||
487 | +**Recommended** | ||
488 | + | ||
489 | +This recommended method is used to "touch" a given session given a | ||
490 | +session ID (`sid`) and session (`session`) object. The `callback` should be | ||
491 | +called as `callback(error)` once the session has been touched. | ||
492 | + | ||
493 | +This is primarily used when the store will automatically delete idle sessions | ||
494 | +and this method is used to signal to the store the given session is active, | ||
495 | +potentially resetting the idle timer. | ||
496 | + | ||
497 | +## Compatible Session Stores | ||
498 | + | ||
499 | +The following modules implement a session store that is compatible with this | ||
500 | +module. Please make a PR to add additional modules :) | ||
501 | + | ||
502 | +[![★][aerospike-session-store-image] aerospike-session-store][aerospike-session-store-url] A session store using [Aerospike](http://www.aerospike.com/). | ||
503 | + | ||
504 | +[aerospike-session-store-url]: https://www.npmjs.com/package/aerospike-session-store | ||
505 | +[aerospike-session-store-image]: https://badgen.net/github/stars/aerospike/aerospike-session-store-expressjs?label=%E2%98%85 | ||
506 | + | ||
507 | +[![★][cassandra-store-image] cassandra-store][cassandra-store-url] An Apache Cassandra-based session store. | ||
508 | + | ||
509 | +[cassandra-store-url]: https://www.npmjs.com/package/cassandra-store | ||
510 | +[cassandra-store-image]: https://badgen.net/github/stars/webcc/cassandra-store?label=%E2%98%85 | ||
511 | + | ||
512 | +[![★][cluster-store-image] cluster-store][cluster-store-url] A wrapper for using in-process / embedded | ||
513 | +stores - such as SQLite (via knex), leveldb, files, or memory - with node cluster (desirable for Raspberry Pi 2 | ||
514 | +and other multi-core embedded devices). | ||
515 | + | ||
516 | +[cluster-store-url]: https://www.npmjs.com/package/cluster-store | ||
517 | +[cluster-store-image]: https://badgen.net/github/stars/coolaj86/cluster-store?label=%E2%98%85 | ||
518 | + | ||
519 | +[![★][connect-arango-image] connect-arango][connect-arango-url] An ArangoDB-based session store. | ||
520 | + | ||
521 | +[connect-arango-url]: https://www.npmjs.com/package/connect-arango | ||
522 | +[connect-arango-image]: https://badgen.net/github/stars/AlexanderArvidsson/connect-arango?label=%E2%98%85 | ||
523 | + | ||
524 | +[![★][connect-azuretables-image] connect-azuretables][connect-azuretables-url] An [Azure Table Storage](https://azure.microsoft.com/en-gb/services/storage/tables/)-based session store. | ||
525 | + | ||
526 | +[connect-azuretables-url]: https://www.npmjs.com/package/connect-azuretables | ||
527 | +[connect-azuretables-image]: https://badgen.net/github/stars/mike-goodwin/connect-azuretables?label=%E2%98%85 | ||
528 | + | ||
529 | +[![★][connect-cloudant-store-image] connect-cloudant-store][connect-cloudant-store-url] An [IBM Cloudant](https://cloudant.com/)-based session store. | ||
530 | + | ||
531 | +[connect-cloudant-store-url]: https://www.npmjs.com/package/connect-cloudant-store | ||
532 | +[connect-cloudant-store-image]: https://badgen.net/github/stars/adriantanasa/connect-cloudant-store?label=%E2%98%85 | ||
533 | + | ||
534 | +[![★][connect-couchbase-image] connect-couchbase][connect-couchbase-url] A [couchbase](http://www.couchbase.com/)-based session store. | ||
535 | + | ||
536 | +[connect-couchbase-url]: https://www.npmjs.com/package/connect-couchbase | ||
537 | +[connect-couchbase-image]: https://badgen.net/github/stars/christophermina/connect-couchbase?label=%E2%98%85 | ||
538 | + | ||
539 | +[![★][connect-datacache-image] connect-datacache][connect-datacache-url] An [IBM Bluemix Data Cache](http://www.ibm.com/cloud-computing/bluemix/)-based session store. | ||
540 | + | ||
541 | +[connect-datacache-url]: https://www.npmjs.com/package/connect-datacache | ||
542 | +[connect-datacache-image]: https://badgen.net/github/stars/adriantanasa/connect-datacache?label=%E2%98%85 | ||
543 | + | ||
544 | +[![★][@google-cloud/connect-datastore-image] @google-cloud/connect-datastore][@google-cloud/connect-datastore-url] A [Google Cloud Datastore](https://cloud.google.com/datastore/docs/concepts/overview)-based session store. | ||
545 | + | ||
546 | +[@google-cloud/connect-datastore-url]: https://www.npmjs.com/package/@google-cloud/connect-datastore | ||
547 | +[@google-cloud/connect-datastore-image]: https://badgen.net/github/stars/GoogleCloudPlatform/cloud-datastore-session-node?label=%E2%98%85 | ||
548 | + | ||
549 | +[![★][connect-db2-image] connect-db2][connect-db2-url] An IBM DB2-based session store built using [ibm_db](https://www.npmjs.com/package/ibm_db) module. | ||
550 | + | ||
551 | +[connect-db2-url]: https://www.npmjs.com/package/connect-db2 | ||
552 | +[connect-db2-image]: https://badgen.net/github/stars/wallali/connect-db2?label=%E2%98%85 | ||
553 | + | ||
554 | +[![★][connect-dynamodb-image] connect-dynamodb][connect-dynamodb-url] A DynamoDB-based session store. | ||
555 | + | ||
556 | +[connect-dynamodb-url]: https://www.npmjs.com/package/connect-dynamodb | ||
557 | +[connect-dynamodb-image]: https://badgen.net/github/stars/ca98am79/connect-dynamodb?label=%E2%98%85 | ||
558 | + | ||
559 | +[![★][@google-cloud/connect-firestore-image] @google-cloud/connect-firestore][@google-cloud/connect-firestore-url] A [Google Cloud Firestore](https://cloud.google.com/firestore/docs/overview)-based session store. | ||
560 | + | ||
561 | +[@google-cloud/connect-firestore-url]: https://www.npmjs.com/package/@google-cloud/connect-firestore | ||
562 | +[@google-cloud/connect-firestore-image]: https://badgen.net/github/stars/googleapis/nodejs-firestore-session?label=%E2%98%85 | ||
563 | + | ||
564 | +[![★][connect-hazelcast-image] connect-hazelcast][connect-hazelcast-url] Hazelcast session store for Connect and Express. | ||
565 | + | ||
566 | +[connect-hazelcast-url]: https://www.npmjs.com/package/connect-hazelcast | ||
567 | +[connect-hazelcast-image]: https://badgen.net/github/stars/huseyinbabal/connect-hazelcast?label=%E2%98%85 | ||
568 | + | ||
569 | +[![★][connect-loki-image] connect-loki][connect-loki-url] A Loki.js-based session store. | ||
570 | + | ||
571 | +[connect-loki-url]: https://www.npmjs.com/package/connect-loki | ||
572 | +[connect-loki-image]: https://badgen.net/github/stars/Requarks/connect-loki?label=%E2%98%85 | ||
573 | + | ||
574 | +[![★][connect-memcached-image] connect-memcached][connect-memcached-url] A memcached-based session store. | ||
575 | + | ||
576 | +[connect-memcached-url]: https://www.npmjs.com/package/connect-memcached | ||
577 | +[connect-memcached-image]: https://badgen.net/github/stars/balor/connect-memcached?label=%E2%98%85 | ||
578 | + | ||
579 | +[![★][connect-memjs-image] connect-memjs][connect-memjs-url] A memcached-based session store using | ||
580 | +[memjs](https://www.npmjs.com/package/memjs) as the memcached client. | ||
581 | + | ||
582 | +[connect-memjs-url]: https://www.npmjs.com/package/connect-memjs | ||
583 | +[connect-memjs-image]: https://badgen.net/github/stars/liamdon/connect-memjs?label=%E2%98%85 | ||
584 | + | ||
585 | +[![★][connect-ml-image] connect-ml][connect-ml-url] A MarkLogic Server-based session store. | ||
586 | + | ||
587 | +[connect-ml-url]: https://www.npmjs.com/package/connect-ml | ||
588 | +[connect-ml-image]: https://badgen.net/github/stars/bluetorch/connect-ml?label=%E2%98%85 | ||
589 | + | ||
590 | +[![★][connect-monetdb-image] connect-monetdb][connect-monetdb-url] A MonetDB-based session store. | ||
591 | + | ||
592 | +[connect-monetdb-url]: https://www.npmjs.com/package/connect-monetdb | ||
593 | +[connect-monetdb-image]: https://badgen.net/github/stars/MonetDB/npm-connect-monetdb?label=%E2%98%85 | ||
594 | + | ||
595 | +[![★][connect-mongo-image] connect-mongo][connect-mongo-url] A MongoDB-based session store. | ||
596 | + | ||
597 | +[connect-mongo-url]: https://www.npmjs.com/package/connect-mongo | ||
598 | +[connect-mongo-image]: https://badgen.net/github/stars/kcbanner/connect-mongo?label=%E2%98%85 | ||
599 | + | ||
600 | +[![★][connect-mongodb-session-image] connect-mongodb-session][connect-mongodb-session-url] Lightweight MongoDB-based session store built and maintained by MongoDB. | ||
601 | + | ||
602 | +[connect-mongodb-session-url]: https://www.npmjs.com/package/connect-mongodb-session | ||
603 | +[connect-mongodb-session-image]: https://badgen.net/github/stars/mongodb-js/connect-mongodb-session?label=%E2%98%85 | ||
604 | + | ||
605 | +[![★][connect-mssql-image] connect-mssql][connect-mssql-url] A SQL Server-based session store. | ||
606 | + | ||
607 | +[connect-mssql-url]: https://www.npmjs.com/package/connect-mssql | ||
608 | +[connect-mssql-image]: https://badgen.net/github/stars/patriksimek/connect-mssql?label=%E2%98%85 | ||
609 | + | ||
610 | +[![★][connect-pg-simple-image] connect-pg-simple][connect-pg-simple-url] A PostgreSQL-based session store. | ||
611 | + | ||
612 | +[connect-pg-simple-url]: https://www.npmjs.com/package/connect-pg-simple | ||
613 | +[connect-pg-simple-image]: https://badgen.net/github/stars/voxpelli/node-connect-pg-simple?label=%E2%98%85 | ||
614 | + | ||
615 | +[![★][connect-redis-image] connect-redis][connect-redis-url] A Redis-based session store. | ||
616 | + | ||
617 | +[connect-redis-url]: https://www.npmjs.com/package/connect-redis | ||
618 | +[connect-redis-image]: https://badgen.net/github/stars/tj/connect-redis?label=%E2%98%85 | ||
619 | + | ||
620 | +[![★][connect-session-firebase-image] connect-session-firebase][connect-session-firebase-url] A session store based on the [Firebase Realtime Database](https://firebase.google.com/docs/database/) | ||
621 | + | ||
622 | +[connect-session-firebase-url]: https://www.npmjs.com/package/connect-session-firebase | ||
623 | +[connect-session-firebase-image]: https://badgen.net/github/stars/benweier/connect-session-firebase?label=%E2%98%85 | ||
624 | + | ||
625 | +[![★][connect-session-knex-image] connect-session-knex][connect-session-knex-url] A session store using | ||
626 | +[Knex.js](http://knexjs.org/), which is a SQL query builder for PostgreSQL, MySQL, MariaDB, SQLite3, and Oracle. | ||
627 | + | ||
628 | +[connect-session-knex-url]: https://www.npmjs.com/package/connect-session-knex | ||
629 | +[connect-session-knex-image]: https://badgen.net/github/stars/llambda/connect-session-knex?label=%E2%98%85 | ||
630 | + | ||
631 | +[![★][connect-session-sequelize-image] connect-session-sequelize][connect-session-sequelize-url] A session store using | ||
632 | +[Sequelize.js](http://sequelizejs.com/), which is a Node.js / io.js ORM for PostgreSQL, MySQL, SQLite and MSSQL. | ||
633 | + | ||
634 | +[connect-session-sequelize-url]: https://www.npmjs.com/package/connect-session-sequelize | ||
635 | +[connect-session-sequelize-image]: https://badgen.net/github/stars/mweibel/connect-session-sequelize?label=%E2%98%85 | ||
636 | + | ||
637 | +[![★][connect-sqlite3-image] connect-sqlite3][connect-sqlite3-url] A [SQLite3](https://github.com/mapbox/node-sqlite3) session store modeled after the TJ's `connect-redis` store. | ||
638 | + | ||
639 | +[connect-sqlite3-url]: https://www.npmjs.com/package/connect-sqlite3 | ||
640 | +[connect-sqlite3-image]: https://badgen.net/github/stars/rawberg/connect-sqlite3?label=%E2%98%85 | ||
641 | + | ||
642 | +[![★][connect-typeorm-image] connect-typeorm][connect-typeorm-url] A [TypeORM](https://github.com/typeorm/typeorm)-based session store. | ||
643 | + | ||
644 | +[connect-typeorm-url]: https://www.npmjs.com/package/connect-typeorm | ||
645 | +[connect-typeorm-image]: https://badgen.net/github/stars/makepost/connect-typeorm?label=%E2%98%85 | ||
646 | + | ||
647 | +[![★][couchdb-expression-image] couchdb-expression][couchdb-expression-url] A [CouchDB](https://couchdb.apache.org/)-based session store. | ||
648 | + | ||
649 | +[couchdb-expression-url]: https://www.npmjs.com/package/couchdb-expression | ||
650 | +[couchdb-expression-image]: https://badgen.net/github/stars/tkshnwesper/couchdb-expression?label=%E2%98%85 | ||
651 | + | ||
652 | +[![★][documentdb-session-image] documentdb-session][documentdb-session-url] A session store for Microsoft Azure's [DocumentDB](https://azure.microsoft.com/en-us/services/documentdb/) NoSQL database service. | ||
653 | + | ||
654 | +[documentdb-session-url]: https://www.npmjs.com/package/documentdb-session | ||
655 | +[documentdb-session-image]: https://badgen.net/github/stars/dwhieb/documentdb-session?label=%E2%98%85 | ||
656 | + | ||
657 | +[![★][dynamodb-store-image] dynamodb-store][dynamodb-store-url] A DynamoDB-based session store. | ||
658 | + | ||
659 | +[dynamodb-store-url]: https://www.npmjs.com/package/dynamodb-store | ||
660 | +[dynamodb-store-image]: https://badgen.net/github/stars/rafaelrpinto/dynamodb-store?label=%E2%98%85 | ||
661 | + | ||
662 | +[![★][express-etcd-image] express-etcd][express-etcd-url] An [etcd](https://github.com/stianeikeland/node-etcd) based session store. | ||
663 | + | ||
664 | +[express-etcd-url]: https://www.npmjs.com/package/express-etcd | ||
665 | +[express-etcd-image]: https://badgen.net/github/stars/gildean/express-etcd?label=%E2%98%85 | ||
666 | + | ||
667 | +[![★][express-mysql-session-image] express-mysql-session][express-mysql-session-url] A session store using native | ||
668 | +[MySQL](https://www.mysql.com/) via the [node-mysql](https://github.com/felixge/node-mysql) module. | ||
669 | + | ||
670 | +[express-mysql-session-url]: https://www.npmjs.com/package/express-mysql-session | ||
671 | +[express-mysql-session-image]: https://badgen.net/github/stars/chill117/express-mysql-session?label=%E2%98%85 | ||
672 | + | ||
673 | +[![★][express-nedb-session-image] express-nedb-session][express-nedb-session-url] A NeDB-based session store. | ||
674 | + | ||
675 | +[express-nedb-session-url]: https://www.npmjs.com/package/express-nedb-session | ||
676 | +[express-nedb-session-image]: https://badgen.net/github/stars/louischatriot/express-nedb-session?label=%E2%98%85 | ||
677 | + | ||
678 | +[![★][express-oracle-session-image] express-oracle-session][express-oracle-session-url] A session store using native | ||
679 | +[oracle](https://www.oracle.com/) via the [node-oracledb](https://www.npmjs.com/package/oracledb) module. | ||
680 | + | ||
681 | +[express-oracle-session-url]: https://www.npmjs.com/package/express-oracle-session | ||
682 | +[express-oracle-session-image]: https://badgen.net/github/stars/slumber86/express-oracle-session?label=%E2%98%85 | ||
683 | + | ||
684 | +[![★][express-session-cache-manager-image] express-session-cache-manager][express-session-cache-manager-url] | ||
685 | +A store that implements [cache-manager](https://www.npmjs.com/package/cache-manager), which supports | ||
686 | +a [variety of storage types](https://www.npmjs.com/package/cache-manager#store-engines). | ||
687 | + | ||
688 | +[express-session-cache-manager-url]: https://www.npmjs.com/package/express-session-cache-manager | ||
689 | +[express-session-cache-manager-image]: https://badgen.net/github/stars/theogravity/express-session-cache-manager?label=%E2%98%85 | ||
690 | + | ||
691 | +[![★][express-session-etcd3-image] express-session-etcd3][express-session-etcd3-url] An [etcd3](https://github.com/mixer/etcd3) based session store. | ||
692 | + | ||
693 | +[express-session-etcd3-url]: https://www.npmjs.com/package/express-session-etcd3 | ||
694 | +[express-session-etcd3-image]: https://badgen.net/github/stars/willgm/express-session-etcd3?label=%E2%98%85 | ||
695 | + | ||
696 | +[![★][express-session-level-image] express-session-level][express-session-level-url] A [LevelDB](https://github.com/Level/levelup) based session store. | ||
697 | + | ||
698 | +[express-session-level-url]: https://www.npmjs.com/package/express-session-level | ||
699 | +[express-session-level-image]: https://badgen.net/github/stars/tgohn/express-session-level?label=%E2%98%85 | ||
700 | + | ||
701 | +[![★][express-session-rsdb-image] express-session-rsdb][express-session-rsdb-url] Session store based on Rocket-Store: A very simple, super fast and yet powerfull, flat file database. | ||
702 | + | ||
703 | +[express-session-rsdb-url]: https://www.npmjs.com/package/express-session-rsdb | ||
704 | +[express-session-rsdb-image]: https://badgen.net/github/stars/paragi/express-session-rsdb?label=%E2%98%85 | ||
705 | + | ||
706 | +[![★][express-sessions-image] express-sessions][express-sessions-url] A session store supporting both MongoDB and Redis. | ||
707 | + | ||
708 | +[express-sessions-url]: https://www.npmjs.com/package/express-sessions | ||
709 | +[express-sessions-image]: https://badgen.net/github/stars/konteck/express-sessions?label=%E2%98%85 | ||
710 | + | ||
711 | +[![★][firestore-store-image] firestore-store][firestore-store-url] A [Firestore](https://github.com/hendrysadrak/firestore-store)-based session store. | ||
712 | + | ||
713 | +[firestore-store-url]: https://www.npmjs.com/package/firestore-store | ||
714 | +[firestore-store-image]: https://badgen.net/github/stars/hendrysadrak/firestore-store?label=%E2%98%85 | ||
715 | + | ||
716 | +[![★][fortune-session-image] fortune-session][fortune-session-url] A [Fortune.js](https://github.com/fortunejs/fortune) | ||
717 | +based session store. Supports all backends supported by Fortune (MongoDB, Redis, Postgres, NeDB). | ||
718 | + | ||
719 | +[fortune-session-url]: https://www.npmjs.com/package/fortune-session | ||
720 | +[fortune-session-image]: https://badgen.net/github/stars/aliceklipper/fortune-session?label=%E2%98%85 | ||
721 | + | ||
722 | +[![★][hazelcast-store-image] hazelcast-store][hazelcast-store-url] A Hazelcast-based session store built on the [Hazelcast Node Client](https://www.npmjs.com/package/hazelcast-client). | ||
723 | + | ||
724 | +[hazelcast-store-url]: https://www.npmjs.com/package/hazelcast-store | ||
725 | +[hazelcast-store-image]: https://badgen.net/github/stars/jackspaniel/hazelcast-store?label=%E2%98%85 | ||
726 | + | ||
727 | +[![★][level-session-store-image] level-session-store][level-session-store-url] A LevelDB-based session store. | ||
728 | + | ||
729 | +[level-session-store-url]: https://www.npmjs.com/package/level-session-store | ||
730 | +[level-session-store-image]: https://badgen.net/github/stars/toddself/level-session-store?label=%E2%98%85 | ||
731 | + | ||
732 | +[![★][lowdb-session-store-image] lowdb-session-store][lowdb-session-store-url] A [lowdb](https://www.npmjs.com/package/lowdb)-based session store. | ||
733 | + | ||
734 | +[lowdb-session-store-url]: https://www.npmjs.com/package/lowdb-session-store | ||
735 | +[lowdb-session-store-image]: https://badgen.net/github/stars/fhellwig/lowdb-session-store?label=%E2%98%85 | ||
736 | + | ||
737 | +[![★][medea-session-store-image] medea-session-store][medea-session-store-url] A Medea-based session store. | ||
738 | + | ||
739 | +[medea-session-store-url]: https://www.npmjs.com/package/medea-session-store | ||
740 | +[medea-session-store-image]: https://badgen.net/github/stars/BenjaminVadant/medea-session-store?label=%E2%98%85 | ||
741 | + | ||
742 | +[![★][memorystore-image] memorystore][memorystore-url] A memory session store made for production. | ||
743 | + | ||
744 | +[memorystore-url]: https://www.npmjs.com/package/memorystore | ||
745 | +[memorystore-image]: https://badgen.net/github/stars/roccomuso/memorystore?label=%E2%98%85 | ||
746 | + | ||
747 | +[![★][mssql-session-store-image] mssql-session-store][mssql-session-store-url] A SQL Server-based session store. | ||
748 | + | ||
749 | +[mssql-session-store-url]: https://www.npmjs.com/package/mssql-session-store | ||
750 | +[mssql-session-store-image]: https://badgen.net/github/stars/jwathen/mssql-session-store?label=%E2%98%85 | ||
751 | + | ||
752 | +[![★][nedb-session-store-image] nedb-session-store][nedb-session-store-url] An alternate NeDB-based (either in-memory or file-persisted) session store. | ||
753 | + | ||
754 | +[nedb-session-store-url]: https://www.npmjs.com/package/nedb-session-store | ||
755 | +[nedb-session-store-image]: https://badgen.net/github/stars/JamesMGreene/nedb-session-store?label=%E2%98%85 | ||
756 | + | ||
757 | +[![★][restsession-image] restsession][restsession-url] Store sessions utilizing a RESTful API | ||
758 | + | ||
759 | +[restsession-url]: https://www.npmjs.com/package/restsession | ||
760 | +[restsession-image]: https://badgen.net/github/stars/jankal/restsession?label=%E2%98%85 | ||
761 | + | ||
762 | +[![★][sequelstore-connect-image] sequelstore-connect][sequelstore-connect-url] A session store using [Sequelize.js](http://sequelizejs.com/). | ||
763 | + | ||
764 | +[sequelstore-connect-url]: https://www.npmjs.com/package/sequelstore-connect | ||
765 | +[sequelstore-connect-image]: https://badgen.net/github/stars/MattMcFarland/sequelstore-connect?label=%E2%98%85 | ||
766 | + | ||
767 | +[![★][session-file-store-image] session-file-store][session-file-store-url] A file system-based session store. | ||
768 | + | ||
769 | +[session-file-store-url]: https://www.npmjs.com/package/session-file-store | ||
770 | +[session-file-store-image]: https://badgen.net/github/stars/valery-barysok/session-file-store?label=%E2%98%85 | ||
771 | + | ||
772 | +[![★][session-pouchdb-store-image] session-pouchdb-store][session-pouchdb-store-url] Session store for PouchDB / CouchDB. Accepts embedded, custom, or remote PouchDB instance and realtime synchronization. | ||
773 | + | ||
774 | +[session-pouchdb-store-url]: https://www.npmjs.com/package/session-pouchdb-store | ||
775 | +[session-pouchdb-store-image]: https://badgen.net/github/stars/solzimer/session-pouchdb-store?label=%E2%98%85 | ||
776 | + | ||
777 | +[![★][session-rethinkdb-image] session-rethinkdb][session-rethinkdb-url] A [RethinkDB](http://rethinkdb.com/)-based session store. | ||
778 | + | ||
779 | +[session-rethinkdb-url]: https://www.npmjs.com/package/session-rethinkdb | ||
780 | +[session-rethinkdb-image]: https://badgen.net/github/stars/llambda/session-rethinkdb?label=%E2%98%85 | ||
781 | + | ||
782 | +[![★][sessionstore-image] sessionstore][sessionstore-url] A session store that works with various databases. | ||
783 | + | ||
784 | +[sessionstore-url]: https://www.npmjs.com/package/sessionstore | ||
785 | +[sessionstore-image]: https://badgen.net/github/stars/adrai/sessionstore?label=%E2%98%85 | ||
786 | + | ||
787 | +[![★][tch-nedb-session-image] tch-nedb-session][tch-nedb-session-url] A file system session store based on NeDB. | ||
788 | + | ||
789 | +[tch-nedb-session-url]: https://www.npmjs.com/package/tch-nedb-session | ||
790 | +[tch-nedb-session-image]: https://badgen.net/github/stars/tomaschyly/NeDBSession?label=%E2%98%85 | ||
791 | + | ||
792 | +## Example | ||
793 | + | ||
794 | +A simple example using `express-session` to store page views for a user. | ||
795 | + | ||
796 | +```js | ||
797 | +var express = require('express') | ||
798 | +var parseurl = require('parseurl') | ||
799 | +var session = require('express-session') | ||
800 | + | ||
801 | +var app = express() | ||
802 | + | ||
803 | +app.use(session({ | ||
804 | + secret: 'keyboard cat', | ||
805 | + resave: false, | ||
806 | + saveUninitialized: true | ||
807 | +})) | ||
808 | + | ||
809 | +app.use(function (req, res, next) { | ||
810 | + if (!req.session.views) { | ||
811 | + req.session.views = {} | ||
812 | + } | ||
813 | + | ||
814 | + // get the url pathname | ||
815 | + var pathname = parseurl(req).pathname | ||
816 | + | ||
817 | + // count the views | ||
818 | + req.session.views[pathname] = (req.session.views[pathname] || 0) + 1 | ||
819 | + | ||
820 | + next() | ||
821 | +}) | ||
822 | + | ||
823 | +app.get('/foo', function (req, res, next) { | ||
824 | + res.send('you viewed this page ' + req.session.views['/foo'] + ' times') | ||
825 | +}) | ||
826 | + | ||
827 | +app.get('/bar', function (req, res, next) { | ||
828 | + res.send('you viewed this page ' + req.session.views['/bar'] + ' times') | ||
829 | +}) | ||
830 | +``` | ||
831 | + | ||
832 | +## Debugging | ||
833 | + | ||
834 | +This module uses the [debug](https://www.npmjs.com/package/debug) module | ||
835 | +internally to log information about session operations. | ||
836 | + | ||
837 | +To see all the internal logs, set the `DEBUG` environment variable to | ||
838 | +`express-session` when launching your app (`npm start`, in this example): | ||
839 | + | ||
840 | +```sh | ||
841 | +$ DEBUG=express-session npm start | ||
842 | +``` | ||
843 | + | ||
844 | +On Windows, use the corresponding command; | ||
845 | + | ||
846 | +```sh | ||
847 | +> set DEBUG=express-session & npm start | ||
848 | +``` | ||
849 | + | ||
850 | +## License | ||
851 | + | ||
852 | +[MIT](LICENSE) | ||
853 | + | ||
854 | +[rfc-6265bis-03-4.1.2.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7 | ||
855 | +[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/session/master | ||
856 | +[coveralls-url]: https://coveralls.io/r/expressjs/session?branch=master | ||
857 | +[node-url]: https://nodejs.org/en/download | ||
858 | +[npm-downloads-image]: https://badgen.net/npm/dm/express-session | ||
859 | +[npm-url]: https://npmjs.org/package/express-session | ||
860 | +[npm-version-image]: https://badgen.net/npm/v/express-session | ||
861 | +[travis-image]: https://badgen.net/travis/expressjs/session/master | ||
862 | +[travis-url]: https://travis-ci.org/expressjs/session |
1 | +/*! | ||
2 | + * express-session | ||
3 | + * Copyright(c) 2010 Sencha Inc. | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * Copyright(c) 2014-2015 Douglas Christopher Wilson | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +'use strict'; | ||
10 | + | ||
11 | +/** | ||
12 | + * Module dependencies. | ||
13 | + * @private | ||
14 | + */ | ||
15 | + | ||
16 | +var Buffer = require('safe-buffer').Buffer | ||
17 | +var cookie = require('cookie'); | ||
18 | +var crypto = require('crypto') | ||
19 | +var debug = require('debug')('express-session'); | ||
20 | +var deprecate = require('depd')('express-session'); | ||
21 | +var onHeaders = require('on-headers') | ||
22 | +var parseUrl = require('parseurl'); | ||
23 | +var signature = require('cookie-signature') | ||
24 | +var uid = require('uid-safe').sync | ||
25 | + | ||
26 | +var Cookie = require('./session/cookie') | ||
27 | +var MemoryStore = require('./session/memory') | ||
28 | +var Session = require('./session/session') | ||
29 | +var Store = require('./session/store') | ||
30 | + | ||
31 | +// environment | ||
32 | + | ||
33 | +var env = process.env.NODE_ENV; | ||
34 | + | ||
35 | +/** | ||
36 | + * Expose the middleware. | ||
37 | + */ | ||
38 | + | ||
39 | +exports = module.exports = session; | ||
40 | + | ||
41 | +/** | ||
42 | + * Expose constructors. | ||
43 | + */ | ||
44 | + | ||
45 | +exports.Store = Store; | ||
46 | +exports.Cookie = Cookie; | ||
47 | +exports.Session = Session; | ||
48 | +exports.MemoryStore = MemoryStore; | ||
49 | + | ||
50 | +/** | ||
51 | + * Warning message for `MemoryStore` usage in production. | ||
52 | + * @private | ||
53 | + */ | ||
54 | + | ||
55 | +var warning = 'Warning: connect.session() MemoryStore is not\n' | ||
56 | + + 'designed for a production environment, as it will leak\n' | ||
57 | + + 'memory, and will not scale past a single process.'; | ||
58 | + | ||
59 | +/** | ||
60 | + * Node.js 0.8+ async implementation. | ||
61 | + * @private | ||
62 | + */ | ||
63 | + | ||
64 | +/* istanbul ignore next */ | ||
65 | +var defer = typeof setImmediate === 'function' | ||
66 | + ? setImmediate | ||
67 | + : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) } | ||
68 | + | ||
69 | +/** | ||
70 | + * Setup session store with the given `options`. | ||
71 | + * | ||
72 | + * @param {Object} [options] | ||
73 | + * @param {Object} [options.cookie] Options for cookie | ||
74 | + * @param {Function} [options.genid] | ||
75 | + * @param {String} [options.name=connect.sid] Session ID cookie name | ||
76 | + * @param {Boolean} [options.proxy] | ||
77 | + * @param {Boolean} [options.resave] Resave unmodified sessions back to the store | ||
78 | + * @param {Boolean} [options.rolling] Enable/disable rolling session expiration | ||
79 | + * @param {Boolean} [options.saveUninitialized] Save uninitialized sessions to the store | ||
80 | + * @param {String|Array} [options.secret] Secret for signing session ID | ||
81 | + * @param {Object} [options.store=MemoryStore] Session store | ||
82 | + * @param {String} [options.unset] | ||
83 | + * @return {Function} middleware | ||
84 | + * @public | ||
85 | + */ | ||
86 | + | ||
87 | +function session(options) { | ||
88 | + var opts = options || {} | ||
89 | + | ||
90 | + // get the cookie options | ||
91 | + var cookieOptions = opts.cookie || {} | ||
92 | + | ||
93 | + // get the session id generate function | ||
94 | + var generateId = opts.genid || generateSessionId | ||
95 | + | ||
96 | + // get the session cookie name | ||
97 | + var name = opts.name || opts.key || 'connect.sid' | ||
98 | + | ||
99 | + // get the session store | ||
100 | + var store = opts.store || new MemoryStore() | ||
101 | + | ||
102 | + // get the trust proxy setting | ||
103 | + var trustProxy = opts.proxy | ||
104 | + | ||
105 | + // get the resave session option | ||
106 | + var resaveSession = opts.resave; | ||
107 | + | ||
108 | + // get the rolling session option | ||
109 | + var rollingSessions = Boolean(opts.rolling) | ||
110 | + | ||
111 | + // get the save uninitialized session option | ||
112 | + var saveUninitializedSession = opts.saveUninitialized | ||
113 | + | ||
114 | + // get the cookie signing secret | ||
115 | + var secret = opts.secret | ||
116 | + | ||
117 | + if (typeof generateId !== 'function') { | ||
118 | + throw new TypeError('genid option must be a function'); | ||
119 | + } | ||
120 | + | ||
121 | + if (resaveSession === undefined) { | ||
122 | + deprecate('undefined resave option; provide resave option'); | ||
123 | + resaveSession = true; | ||
124 | + } | ||
125 | + | ||
126 | + if (saveUninitializedSession === undefined) { | ||
127 | + deprecate('undefined saveUninitialized option; provide saveUninitialized option'); | ||
128 | + saveUninitializedSession = true; | ||
129 | + } | ||
130 | + | ||
131 | + if (opts.unset && opts.unset !== 'destroy' && opts.unset !== 'keep') { | ||
132 | + throw new TypeError('unset option must be "destroy" or "keep"'); | ||
133 | + } | ||
134 | + | ||
135 | + // TODO: switch to "destroy" on next major | ||
136 | + var unsetDestroy = opts.unset === 'destroy' | ||
137 | + | ||
138 | + if (Array.isArray(secret) && secret.length === 0) { | ||
139 | + throw new TypeError('secret option array must contain one or more strings'); | ||
140 | + } | ||
141 | + | ||
142 | + if (secret && !Array.isArray(secret)) { | ||
143 | + secret = [secret]; | ||
144 | + } | ||
145 | + | ||
146 | + if (!secret) { | ||
147 | + deprecate('req.secret; provide secret option'); | ||
148 | + } | ||
149 | + | ||
150 | + // notify user that this store is not | ||
151 | + // meant for a production environment | ||
152 | + /* istanbul ignore next: not tested */ | ||
153 | + if (env === 'production' && store instanceof MemoryStore) { | ||
154 | + console.warn(warning); | ||
155 | + } | ||
156 | + | ||
157 | + // generates the new session | ||
158 | + store.generate = function(req){ | ||
159 | + req.sessionID = generateId(req); | ||
160 | + req.session = new Session(req); | ||
161 | + req.session.cookie = new Cookie(cookieOptions); | ||
162 | + | ||
163 | + if (cookieOptions.secure === 'auto') { | ||
164 | + req.session.cookie.secure = issecure(req, trustProxy); | ||
165 | + } | ||
166 | + }; | ||
167 | + | ||
168 | + var storeImplementsTouch = typeof store.touch === 'function'; | ||
169 | + | ||
170 | + // register event listeners for the store to track readiness | ||
171 | + var storeReady = true | ||
172 | + store.on('disconnect', function ondisconnect() { | ||
173 | + storeReady = false | ||
174 | + }) | ||
175 | + store.on('connect', function onconnect() { | ||
176 | + storeReady = true | ||
177 | + }) | ||
178 | + | ||
179 | + return function session(req, res, next) { | ||
180 | + // self-awareness | ||
181 | + if (req.session) { | ||
182 | + next() | ||
183 | + return | ||
184 | + } | ||
185 | + | ||
186 | + // Handle connection as if there is no session if | ||
187 | + // the store has temporarily disconnected etc | ||
188 | + if (!storeReady) { | ||
189 | + debug('store is disconnected') | ||
190 | + next() | ||
191 | + return | ||
192 | + } | ||
193 | + | ||
194 | + // pathname mismatch | ||
195 | + var originalPath = parseUrl.original(req).pathname || '/' | ||
196 | + if (originalPath.indexOf(cookieOptions.path || '/') !== 0) return next(); | ||
197 | + | ||
198 | + // ensure a secret is available or bail | ||
199 | + if (!secret && !req.secret) { | ||
200 | + next(new Error('secret option required for sessions')); | ||
201 | + return; | ||
202 | + } | ||
203 | + | ||
204 | + // backwards compatibility for signed cookies | ||
205 | + // req.secret is passed from the cookie parser middleware | ||
206 | + var secrets = secret || [req.secret]; | ||
207 | + | ||
208 | + var originalHash; | ||
209 | + var originalId; | ||
210 | + var savedHash; | ||
211 | + var touched = false | ||
212 | + | ||
213 | + // expose store | ||
214 | + req.sessionStore = store; | ||
215 | + | ||
216 | + // get the session ID from the cookie | ||
217 | + var cookieId = req.sessionID = getcookie(req, name, secrets); | ||
218 | + | ||
219 | + // set-cookie | ||
220 | + onHeaders(res, function(){ | ||
221 | + if (!req.session) { | ||
222 | + debug('no session'); | ||
223 | + return; | ||
224 | + } | ||
225 | + | ||
226 | + if (!shouldSetCookie(req)) { | ||
227 | + return; | ||
228 | + } | ||
229 | + | ||
230 | + // only send secure cookies via https | ||
231 | + if (req.session.cookie.secure && !issecure(req, trustProxy)) { | ||
232 | + debug('not secured'); | ||
233 | + return; | ||
234 | + } | ||
235 | + | ||
236 | + if (!touched) { | ||
237 | + // touch session | ||
238 | + req.session.touch() | ||
239 | + touched = true | ||
240 | + } | ||
241 | + | ||
242 | + // set cookie | ||
243 | + setcookie(res, name, req.sessionID, secrets[0], req.session.cookie.data); | ||
244 | + }); | ||
245 | + | ||
246 | + // proxy end() to commit the session | ||
247 | + var _end = res.end; | ||
248 | + var _write = res.write; | ||
249 | + var ended = false; | ||
250 | + res.end = function end(chunk, encoding) { | ||
251 | + if (ended) { | ||
252 | + return false; | ||
253 | + } | ||
254 | + | ||
255 | + ended = true; | ||
256 | + | ||
257 | + var ret; | ||
258 | + var sync = true; | ||
259 | + | ||
260 | + function writeend() { | ||
261 | + if (sync) { | ||
262 | + ret = _end.call(res, chunk, encoding); | ||
263 | + sync = false; | ||
264 | + return; | ||
265 | + } | ||
266 | + | ||
267 | + _end.call(res); | ||
268 | + } | ||
269 | + | ||
270 | + function writetop() { | ||
271 | + if (!sync) { | ||
272 | + return ret; | ||
273 | + } | ||
274 | + | ||
275 | + if (chunk == null) { | ||
276 | + ret = true; | ||
277 | + return ret; | ||
278 | + } | ||
279 | + | ||
280 | + var contentLength = Number(res.getHeader('Content-Length')); | ||
281 | + | ||
282 | + if (!isNaN(contentLength) && contentLength > 0) { | ||
283 | + // measure chunk | ||
284 | + chunk = !Buffer.isBuffer(chunk) | ||
285 | + ? Buffer.from(chunk, encoding) | ||
286 | + : chunk; | ||
287 | + encoding = undefined; | ||
288 | + | ||
289 | + if (chunk.length !== 0) { | ||
290 | + debug('split response'); | ||
291 | + ret = _write.call(res, chunk.slice(0, chunk.length - 1)); | ||
292 | + chunk = chunk.slice(chunk.length - 1, chunk.length); | ||
293 | + return ret; | ||
294 | + } | ||
295 | + } | ||
296 | + | ||
297 | + ret = _write.call(res, chunk, encoding); | ||
298 | + sync = false; | ||
299 | + | ||
300 | + return ret; | ||
301 | + } | ||
302 | + | ||
303 | + if (shouldDestroy(req)) { | ||
304 | + // destroy session | ||
305 | + debug('destroying'); | ||
306 | + store.destroy(req.sessionID, function ondestroy(err) { | ||
307 | + if (err) { | ||
308 | + defer(next, err); | ||
309 | + } | ||
310 | + | ||
311 | + debug('destroyed'); | ||
312 | + writeend(); | ||
313 | + }); | ||
314 | + | ||
315 | + return writetop(); | ||
316 | + } | ||
317 | + | ||
318 | + // no session to save | ||
319 | + if (!req.session) { | ||
320 | + debug('no session'); | ||
321 | + return _end.call(res, chunk, encoding); | ||
322 | + } | ||
323 | + | ||
324 | + if (!touched) { | ||
325 | + // touch session | ||
326 | + req.session.touch() | ||
327 | + touched = true | ||
328 | + } | ||
329 | + | ||
330 | + if (shouldSave(req)) { | ||
331 | + req.session.save(function onsave(err) { | ||
332 | + if (err) { | ||
333 | + defer(next, err); | ||
334 | + } | ||
335 | + | ||
336 | + writeend(); | ||
337 | + }); | ||
338 | + | ||
339 | + return writetop(); | ||
340 | + } else if (storeImplementsTouch && shouldTouch(req)) { | ||
341 | + // store implements touch method | ||
342 | + debug('touching'); | ||
343 | + store.touch(req.sessionID, req.session, function ontouch(err) { | ||
344 | + if (err) { | ||
345 | + defer(next, err); | ||
346 | + } | ||
347 | + | ||
348 | + debug('touched'); | ||
349 | + writeend(); | ||
350 | + }); | ||
351 | + | ||
352 | + return writetop(); | ||
353 | + } | ||
354 | + | ||
355 | + return _end.call(res, chunk, encoding); | ||
356 | + }; | ||
357 | + | ||
358 | + // generate the session | ||
359 | + function generate() { | ||
360 | + store.generate(req); | ||
361 | + originalId = req.sessionID; | ||
362 | + originalHash = hash(req.session); | ||
363 | + wrapmethods(req.session); | ||
364 | + } | ||
365 | + | ||
366 | + // inflate the session | ||
367 | + function inflate (req, sess) { | ||
368 | + store.createSession(req, sess) | ||
369 | + originalId = req.sessionID | ||
370 | + originalHash = hash(sess) | ||
371 | + | ||
372 | + if (!resaveSession) { | ||
373 | + savedHash = originalHash | ||
374 | + } | ||
375 | + | ||
376 | + wrapmethods(req.session) | ||
377 | + } | ||
378 | + | ||
379 | + function rewrapmethods (sess, callback) { | ||
380 | + return function () { | ||
381 | + if (req.session !== sess) { | ||
382 | + wrapmethods(req.session) | ||
383 | + } | ||
384 | + | ||
385 | + callback.apply(this, arguments) | ||
386 | + } | ||
387 | + } | ||
388 | + | ||
389 | + // wrap session methods | ||
390 | + function wrapmethods(sess) { | ||
391 | + var _reload = sess.reload | ||
392 | + var _save = sess.save; | ||
393 | + | ||
394 | + function reload(callback) { | ||
395 | + debug('reloading %s', this.id) | ||
396 | + _reload.call(this, rewrapmethods(this, callback)) | ||
397 | + } | ||
398 | + | ||
399 | + function save() { | ||
400 | + debug('saving %s', this.id); | ||
401 | + savedHash = hash(this); | ||
402 | + _save.apply(this, arguments); | ||
403 | + } | ||
404 | + | ||
405 | + Object.defineProperty(sess, 'reload', { | ||
406 | + configurable: true, | ||
407 | + enumerable: false, | ||
408 | + value: reload, | ||
409 | + writable: true | ||
410 | + }) | ||
411 | + | ||
412 | + Object.defineProperty(sess, 'save', { | ||
413 | + configurable: true, | ||
414 | + enumerable: false, | ||
415 | + value: save, | ||
416 | + writable: true | ||
417 | + }); | ||
418 | + } | ||
419 | + | ||
420 | + // check if session has been modified | ||
421 | + function isModified(sess) { | ||
422 | + return originalId !== sess.id || originalHash !== hash(sess); | ||
423 | + } | ||
424 | + | ||
425 | + // check if session has been saved | ||
426 | + function isSaved(sess) { | ||
427 | + return originalId === sess.id && savedHash === hash(sess); | ||
428 | + } | ||
429 | + | ||
430 | + // determine if session should be destroyed | ||
431 | + function shouldDestroy(req) { | ||
432 | + return req.sessionID && unsetDestroy && req.session == null; | ||
433 | + } | ||
434 | + | ||
435 | + // determine if session should be saved to store | ||
436 | + function shouldSave(req) { | ||
437 | + // cannot set cookie without a session ID | ||
438 | + if (typeof req.sessionID !== 'string') { | ||
439 | + debug('session ignored because of bogus req.sessionID %o', req.sessionID); | ||
440 | + return false; | ||
441 | + } | ||
442 | + | ||
443 | + return !saveUninitializedSession && cookieId !== req.sessionID | ||
444 | + ? isModified(req.session) | ||
445 | + : !isSaved(req.session) | ||
446 | + } | ||
447 | + | ||
448 | + // determine if session should be touched | ||
449 | + function shouldTouch(req) { | ||
450 | + // cannot set cookie without a session ID | ||
451 | + if (typeof req.sessionID !== 'string') { | ||
452 | + debug('session ignored because of bogus req.sessionID %o', req.sessionID); | ||
453 | + return false; | ||
454 | + } | ||
455 | + | ||
456 | + return cookieId === req.sessionID && !shouldSave(req); | ||
457 | + } | ||
458 | + | ||
459 | + // determine if cookie should be set on response | ||
460 | + function shouldSetCookie(req) { | ||
461 | + // cannot set cookie without a session ID | ||
462 | + if (typeof req.sessionID !== 'string') { | ||
463 | + return false; | ||
464 | + } | ||
465 | + | ||
466 | + return cookieId !== req.sessionID | ||
467 | + ? saveUninitializedSession || isModified(req.session) | ||
468 | + : rollingSessions || req.session.cookie.expires != null && isModified(req.session); | ||
469 | + } | ||
470 | + | ||
471 | + // generate a session if the browser doesn't send a sessionID | ||
472 | + if (!req.sessionID) { | ||
473 | + debug('no SID sent, generating session'); | ||
474 | + generate(); | ||
475 | + next(); | ||
476 | + return; | ||
477 | + } | ||
478 | + | ||
479 | + // generate the session object | ||
480 | + debug('fetching %s', req.sessionID); | ||
481 | + store.get(req.sessionID, function(err, sess){ | ||
482 | + // error handling | ||
483 | + if (err && err.code !== 'ENOENT') { | ||
484 | + debug('error %j', err); | ||
485 | + next(err) | ||
486 | + return | ||
487 | + } | ||
488 | + | ||
489 | + try { | ||
490 | + if (err || !sess) { | ||
491 | + debug('no session found') | ||
492 | + generate() | ||
493 | + } else { | ||
494 | + debug('session found') | ||
495 | + inflate(req, sess) | ||
496 | + } | ||
497 | + } catch (e) { | ||
498 | + next(e) | ||
499 | + return | ||
500 | + } | ||
501 | + | ||
502 | + next() | ||
503 | + }); | ||
504 | + }; | ||
505 | +}; | ||
506 | + | ||
507 | +/** | ||
508 | + * Generate a session ID for a new session. | ||
509 | + * | ||
510 | + * @return {String} | ||
511 | + * @private | ||
512 | + */ | ||
513 | + | ||
514 | +function generateSessionId(sess) { | ||
515 | + return uid(24); | ||
516 | +} | ||
517 | + | ||
518 | +/** | ||
519 | + * Get the session ID cookie from request. | ||
520 | + * | ||
521 | + * @return {string} | ||
522 | + * @private | ||
523 | + */ | ||
524 | + | ||
525 | +function getcookie(req, name, secrets) { | ||
526 | + var header = req.headers.cookie; | ||
527 | + var raw; | ||
528 | + var val; | ||
529 | + | ||
530 | + // read from cookie header | ||
531 | + if (header) { | ||
532 | + var cookies = cookie.parse(header); | ||
533 | + | ||
534 | + raw = cookies[name]; | ||
535 | + | ||
536 | + if (raw) { | ||
537 | + if (raw.substr(0, 2) === 's:') { | ||
538 | + val = unsigncookie(raw.slice(2), secrets); | ||
539 | + | ||
540 | + if (val === false) { | ||
541 | + debug('cookie signature invalid'); | ||
542 | + val = undefined; | ||
543 | + } | ||
544 | + } else { | ||
545 | + debug('cookie unsigned') | ||
546 | + } | ||
547 | + } | ||
548 | + } | ||
549 | + | ||
550 | + // back-compat read from cookieParser() signedCookies data | ||
551 | + if (!val && req.signedCookies) { | ||
552 | + val = req.signedCookies[name]; | ||
553 | + | ||
554 | + if (val) { | ||
555 | + deprecate('cookie should be available in req.headers.cookie'); | ||
556 | + } | ||
557 | + } | ||
558 | + | ||
559 | + // back-compat read from cookieParser() cookies data | ||
560 | + if (!val && req.cookies) { | ||
561 | + raw = req.cookies[name]; | ||
562 | + | ||
563 | + if (raw) { | ||
564 | + if (raw.substr(0, 2) === 's:') { | ||
565 | + val = unsigncookie(raw.slice(2), secrets); | ||
566 | + | ||
567 | + if (val) { | ||
568 | + deprecate('cookie should be available in req.headers.cookie'); | ||
569 | + } | ||
570 | + | ||
571 | + if (val === false) { | ||
572 | + debug('cookie signature invalid'); | ||
573 | + val = undefined; | ||
574 | + } | ||
575 | + } else { | ||
576 | + debug('cookie unsigned') | ||
577 | + } | ||
578 | + } | ||
579 | + } | ||
580 | + | ||
581 | + return val; | ||
582 | +} | ||
583 | + | ||
584 | +/** | ||
585 | + * Hash the given `sess` object omitting changes to `.cookie`. | ||
586 | + * | ||
587 | + * @param {Object} sess | ||
588 | + * @return {String} | ||
589 | + * @private | ||
590 | + */ | ||
591 | + | ||
592 | +function hash(sess) { | ||
593 | + // serialize | ||
594 | + var str = JSON.stringify(sess, function (key, val) { | ||
595 | + // ignore sess.cookie property | ||
596 | + if (this === sess && key === 'cookie') { | ||
597 | + return | ||
598 | + } | ||
599 | + | ||
600 | + return val | ||
601 | + }) | ||
602 | + | ||
603 | + // hash | ||
604 | + return crypto | ||
605 | + .createHash('sha1') | ||
606 | + .update(str, 'utf8') | ||
607 | + .digest('hex') | ||
608 | +} | ||
609 | + | ||
610 | +/** | ||
611 | + * Determine if request is secure. | ||
612 | + * | ||
613 | + * @param {Object} req | ||
614 | + * @param {Boolean} [trustProxy] | ||
615 | + * @return {Boolean} | ||
616 | + * @private | ||
617 | + */ | ||
618 | + | ||
619 | +function issecure(req, trustProxy) { | ||
620 | + // socket is https server | ||
621 | + if (req.connection && req.connection.encrypted) { | ||
622 | + return true; | ||
623 | + } | ||
624 | + | ||
625 | + // do not trust proxy | ||
626 | + if (trustProxy === false) { | ||
627 | + return false; | ||
628 | + } | ||
629 | + | ||
630 | + // no explicit trust; try req.secure from express | ||
631 | + if (trustProxy !== true) { | ||
632 | + return req.secure === true | ||
633 | + } | ||
634 | + | ||
635 | + // read the proto from x-forwarded-proto header | ||
636 | + var header = req.headers['x-forwarded-proto'] || ''; | ||
637 | + var index = header.indexOf(','); | ||
638 | + var proto = index !== -1 | ||
639 | + ? header.substr(0, index).toLowerCase().trim() | ||
640 | + : header.toLowerCase().trim() | ||
641 | + | ||
642 | + return proto === 'https'; | ||
643 | +} | ||
644 | + | ||
645 | +/** | ||
646 | + * Set cookie on response. | ||
647 | + * | ||
648 | + * @private | ||
649 | + */ | ||
650 | + | ||
651 | +function setcookie(res, name, val, secret, options) { | ||
652 | + var signed = 's:' + signature.sign(val, secret); | ||
653 | + var data = cookie.serialize(name, signed, options); | ||
654 | + | ||
655 | + debug('set-cookie %s', data); | ||
656 | + | ||
657 | + var prev = res.getHeader('Set-Cookie') || [] | ||
658 | + var header = Array.isArray(prev) ? prev.concat(data) : [prev, data]; | ||
659 | + | ||
660 | + res.setHeader('Set-Cookie', header) | ||
661 | +} | ||
662 | + | ||
663 | +/** | ||
664 | + * Verify and decode the given `val` with `secrets`. | ||
665 | + * | ||
666 | + * @param {String} val | ||
667 | + * @param {Array} secrets | ||
668 | + * @returns {String|Boolean} | ||
669 | + * @private | ||
670 | + */ | ||
671 | +function unsigncookie(val, secrets) { | ||
672 | + for (var i = 0; i < secrets.length; i++) { | ||
673 | + var result = signature.unsign(val, secrets[i]); | ||
674 | + | ||
675 | + if (result !== false) { | ||
676 | + return result; | ||
677 | + } | ||
678 | + } | ||
679 | + | ||
680 | + return false; | ||
681 | +} |
1 | +2.0.0 / 2018-10-26 | ||
2 | +================== | ||
3 | + | ||
4 | + * Drop support for Node.js 0.6 | ||
5 | + * Replace internal `eval` usage with `Function` constructor | ||
6 | + * Use instance methods on `process` to check for listeners | ||
7 | + | ||
8 | +1.1.2 / 2018-01-11 | ||
9 | +================== | ||
10 | + | ||
11 | + * perf: remove argument reassignment | ||
12 | + * Support Node.js 0.6 to 9.x | ||
13 | + | ||
14 | +1.1.1 / 2017-07-27 | ||
15 | +================== | ||
16 | + | ||
17 | + * Remove unnecessary `Buffer` loading | ||
18 | + * Support Node.js 0.6 to 8.x | ||
19 | + | ||
20 | +1.1.0 / 2015-09-14 | ||
21 | +================== | ||
22 | + | ||
23 | + * Enable strict mode in more places | ||
24 | + * Support io.js 3.x | ||
25 | + * Support io.js 2.x | ||
26 | + * Support web browser loading | ||
27 | + - Requires bundler like Browserify or webpack | ||
28 | + | ||
29 | +1.0.1 / 2015-04-07 | ||
30 | +================== | ||
31 | + | ||
32 | + * Fix `TypeError`s when under `'use strict'` code | ||
33 | + * Fix useless type name on auto-generated messages | ||
34 | + * Support io.js 1.x | ||
35 | + * Support Node.js 0.12 | ||
36 | + | ||
37 | +1.0.0 / 2014-09-17 | ||
38 | +================== | ||
39 | + | ||
40 | + * No changes | ||
41 | + | ||
42 | +0.4.5 / 2014-09-09 | ||
43 | +================== | ||
44 | + | ||
45 | + * Improve call speed to functions using the function wrapper | ||
46 | + * Support Node.js 0.6 | ||
47 | + | ||
48 | +0.4.4 / 2014-07-27 | ||
49 | +================== | ||
50 | + | ||
51 | + * Work-around v8 generating empty stack traces | ||
52 | + | ||
53 | +0.4.3 / 2014-07-26 | ||
54 | +================== | ||
55 | + | ||
56 | + * Fix exception when global `Error.stackTraceLimit` is too low | ||
57 | + | ||
58 | +0.4.2 / 2014-07-19 | ||
59 | +================== | ||
60 | + | ||
61 | + * Correct call site for wrapped functions and properties | ||
62 | + | ||
63 | +0.4.1 / 2014-07-19 | ||
64 | +================== | ||
65 | + | ||
66 | + * Improve automatic message generation for function properties | ||
67 | + | ||
68 | +0.4.0 / 2014-07-19 | ||
69 | +================== | ||
70 | + | ||
71 | + * Add `TRACE_DEPRECATION` environment variable | ||
72 | + * Remove non-standard grey color from color output | ||
73 | + * Support `--no-deprecation` argument | ||
74 | + * Support `--trace-deprecation` argument | ||
75 | + * Support `deprecate.property(fn, prop, message)` | ||
76 | + | ||
77 | +0.3.0 / 2014-06-16 | ||
78 | +================== | ||
79 | + | ||
80 | + * Add `NO_DEPRECATION` environment variable | ||
81 | + | ||
82 | +0.2.0 / 2014-06-15 | ||
83 | +================== | ||
84 | + | ||
85 | + * Add `deprecate.property(obj, prop, message)` | ||
86 | + * Remove `supports-color` dependency for node.js 0.8 | ||
87 | + | ||
88 | +0.1.0 / 2014-06-15 | ||
89 | +================== | ||
90 | + | ||
91 | + * Add `deprecate.function(fn, message)` | ||
92 | + * Add `process.on('deprecation', fn)` emitter | ||
93 | + * Automatically generate message when omitted from `deprecate()` | ||
94 | + | ||
95 | +0.0.1 / 2014-06-15 | ||
96 | +================== | ||
97 | + | ||
98 | + * Fix warning for dynamic calls at singe call site | ||
99 | + | ||
100 | +0.0.0 / 2014-06-15 | ||
101 | +================== | ||
102 | + | ||
103 | + * Initial implementation |
1 | +(The MIT License) | ||
2 | + | ||
3 | +Copyright (c) 2014-2018 Douglas Christopher Wilson | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining | ||
6 | +a copy of this software and associated documentation files (the | ||
7 | +'Software'), to deal in the Software without restriction, including | ||
8 | +without limitation the rights to use, copy, modify, merge, publish, | ||
9 | +distribute, sublicense, and/or sell copies of the Software, and to | ||
10 | +permit persons to whom the Software is furnished to do so, subject to | ||
11 | +the following conditions: | ||
12 | + | ||
13 | +The above copyright notice and this permission notice shall be | ||
14 | +included in all copies or substantial portions of the Software. | ||
15 | + | ||
16 | +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, | ||
17 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
18 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
19 | +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
20 | +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
21 | +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
22 | +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
1 | +# depd | ||
2 | + | ||
3 | +[![NPM Version][npm-version-image]][npm-url] | ||
4 | +[![NPM Downloads][npm-downloads-image]][npm-url] | ||
5 | +[![Node.js Version][node-image]][node-url] | ||
6 | +[![Linux Build][travis-image]][travis-url] | ||
7 | +[![Windows Build][appveyor-image]][appveyor-url] | ||
8 | +[![Coverage Status][coveralls-image]][coveralls-url] | ||
9 | + | ||
10 | +Deprecate all the things | ||
11 | + | ||
12 | +> With great modules comes great responsibility; mark things deprecated! | ||
13 | + | ||
14 | +## Install | ||
15 | + | ||
16 | +This module is installed directly using `npm`: | ||
17 | + | ||
18 | +```sh | ||
19 | +$ npm install depd | ||
20 | +``` | ||
21 | + | ||
22 | +This module can also be bundled with systems like | ||
23 | +[Browserify](http://browserify.org/) or [webpack](https://webpack.github.io/), | ||
24 | +though by default this module will alter it's API to no longer display or | ||
25 | +track deprecations. | ||
26 | + | ||
27 | +## API | ||
28 | + | ||
29 | +<!-- eslint-disable no-unused-vars --> | ||
30 | + | ||
31 | +```js | ||
32 | +var deprecate = require('depd')('my-module') | ||
33 | +``` | ||
34 | + | ||
35 | +This library allows you to display deprecation messages to your users. | ||
36 | +This library goes above and beyond with deprecation warnings by | ||
37 | +introspection of the call stack (but only the bits that it is interested | ||
38 | +in). | ||
39 | + | ||
40 | +Instead of just warning on the first invocation of a deprecated | ||
41 | +function and never again, this module will warn on the first invocation | ||
42 | +of a deprecated function per unique call site, making it ideal to alert | ||
43 | +users of all deprecated uses across the code base, rather than just | ||
44 | +whatever happens to execute first. | ||
45 | + | ||
46 | +The deprecation warnings from this module also include the file and line | ||
47 | +information for the call into the module that the deprecated function was | ||
48 | +in. | ||
49 | + | ||
50 | +**NOTE** this library has a similar interface to the `debug` module, and | ||
51 | +this module uses the calling file to get the boundary for the call stacks, | ||
52 | +so you should always create a new `deprecate` object in each file and not | ||
53 | +within some central file. | ||
54 | + | ||
55 | +### depd(namespace) | ||
56 | + | ||
57 | +Create a new deprecate function that uses the given namespace name in the | ||
58 | +messages and will display the call site prior to the stack entering the | ||
59 | +file this function was called from. It is highly suggested you use the | ||
60 | +name of your module as the namespace. | ||
61 | + | ||
62 | +### deprecate(message) | ||
63 | + | ||
64 | +Call this function from deprecated code to display a deprecation message. | ||
65 | +This message will appear once per unique caller site. Caller site is the | ||
66 | +first call site in the stack in a different file from the caller of this | ||
67 | +function. | ||
68 | + | ||
69 | +If the message is omitted, a message is generated for you based on the site | ||
70 | +of the `deprecate()` call and will display the name of the function called, | ||
71 | +similar to the name displayed in a stack trace. | ||
72 | + | ||
73 | +### deprecate.function(fn, message) | ||
74 | + | ||
75 | +Call this function to wrap a given function in a deprecation message on any | ||
76 | +call to the function. An optional message can be supplied to provide a custom | ||
77 | +message. | ||
78 | + | ||
79 | +### deprecate.property(obj, prop, message) | ||
80 | + | ||
81 | +Call this function to wrap a given property on object in a deprecation message | ||
82 | +on any accessing or setting of the property. An optional message can be supplied | ||
83 | +to provide a custom message. | ||
84 | + | ||
85 | +The method must be called on the object where the property belongs (not | ||
86 | +inherited from the prototype). | ||
87 | + | ||
88 | +If the property is a data descriptor, it will be converted to an accessor | ||
89 | +descriptor in order to display the deprecation message. | ||
90 | + | ||
91 | +### process.on('deprecation', fn) | ||
92 | + | ||
93 | +This module will allow easy capturing of deprecation errors by emitting the | ||
94 | +errors as the type "deprecation" on the global `process`. If there are no | ||
95 | +listeners for this type, the errors are written to STDERR as normal, but if | ||
96 | +there are any listeners, nothing will be written to STDERR and instead only | ||
97 | +emitted. From there, you can write the errors in a different format or to a | ||
98 | +logging source. | ||
99 | + | ||
100 | +The error represents the deprecation and is emitted only once with the same | ||
101 | +rules as writing to STDERR. The error has the following properties: | ||
102 | + | ||
103 | + - `message` - This is the message given by the library | ||
104 | + - `name` - This is always `'DeprecationError'` | ||
105 | + - `namespace` - This is the namespace the deprecation came from | ||
106 | + - `stack` - This is the stack of the call to the deprecated thing | ||
107 | + | ||
108 | +Example `error.stack` output: | ||
109 | + | ||
110 | +``` | ||
111 | +DeprecationError: my-cool-module deprecated oldfunction | ||
112 | + at Object.<anonymous> ([eval]-wrapper:6:22) | ||
113 | + at Module._compile (module.js:456:26) | ||
114 | + at evalScript (node.js:532:25) | ||
115 | + at startup (node.js:80:7) | ||
116 | + at node.js:902:3 | ||
117 | +``` | ||
118 | + | ||
119 | +### process.env.NO_DEPRECATION | ||
120 | + | ||
121 | +As a user of modules that are deprecated, the environment variable `NO_DEPRECATION` | ||
122 | +is provided as a quick solution to silencing deprecation warnings from being | ||
123 | +output. The format of this is similar to that of `DEBUG`: | ||
124 | + | ||
125 | +```sh | ||
126 | +$ NO_DEPRECATION=my-module,othermod node app.js | ||
127 | +``` | ||
128 | + | ||
129 | +This will suppress deprecations from being output for "my-module" and "othermod". | ||
130 | +The value is a list of comma-separated namespaces. To suppress every warning | ||
131 | +across all namespaces, use the value `*` for a namespace. | ||
132 | + | ||
133 | +Providing the argument `--no-deprecation` to the `node` executable will suppress | ||
134 | +all deprecations (only available in Node.js 0.8 or higher). | ||
135 | + | ||
136 | +**NOTE** This will not suppress the deperecations given to any "deprecation" | ||
137 | +event listeners, just the output to STDERR. | ||
138 | + | ||
139 | +### process.env.TRACE_DEPRECATION | ||
140 | + | ||
141 | +As a user of modules that are deprecated, the environment variable `TRACE_DEPRECATION` | ||
142 | +is provided as a solution to getting more detailed location information in deprecation | ||
143 | +warnings by including the entire stack trace. The format of this is the same as | ||
144 | +`NO_DEPRECATION`: | ||
145 | + | ||
146 | +```sh | ||
147 | +$ TRACE_DEPRECATION=my-module,othermod node app.js | ||
148 | +``` | ||
149 | + | ||
150 | +This will include stack traces for deprecations being output for "my-module" and | ||
151 | +"othermod". The value is a list of comma-separated namespaces. To trace every | ||
152 | +warning across all namespaces, use the value `*` for a namespace. | ||
153 | + | ||
154 | +Providing the argument `--trace-deprecation` to the `node` executable will trace | ||
155 | +all deprecations (only available in Node.js 0.8 or higher). | ||
156 | + | ||
157 | +**NOTE** This will not trace the deperecations silenced by `NO_DEPRECATION`. | ||
158 | + | ||
159 | +## Display | ||
160 | + | ||
161 | +![message](files/message.png) | ||
162 | + | ||
163 | +When a user calls a function in your library that you mark deprecated, they | ||
164 | +will see the following written to STDERR (in the given colors, similar colors | ||
165 | +and layout to the `debug` module): | ||
166 | + | ||
167 | +``` | ||
168 | +bright cyan bright yellow | ||
169 | +| | reset cyan | ||
170 | +| | | | | ||
171 | +▼ ▼ ▼ ▼ | ||
172 | +my-cool-module deprecated oldfunction [eval]-wrapper:6:22 | ||
173 | +▲ ▲ ▲ ▲ | ||
174 | +| | | | | ||
175 | +namespace | | location of mycoolmod.oldfunction() call | ||
176 | + | deprecation message | ||
177 | + the word "deprecated" | ||
178 | +``` | ||
179 | + | ||
180 | +If the user redirects their STDERR to a file or somewhere that does not support | ||
181 | +colors, they see (similar layout to the `debug` module): | ||
182 | + | ||
183 | +``` | ||
184 | +Sun, 15 Jun 2014 05:21:37 GMT my-cool-module deprecated oldfunction at [eval]-wrapper:6:22 | ||
185 | +▲ ▲ ▲ ▲ ▲ | ||
186 | +| | | | | | ||
187 | +timestamp of message namespace | | location of mycoolmod.oldfunction() call | ||
188 | + | deprecation message | ||
189 | + the word "deprecated" | ||
190 | +``` | ||
191 | + | ||
192 | +## Examples | ||
193 | + | ||
194 | +### Deprecating all calls to a function | ||
195 | + | ||
196 | +This will display a deprecated message about "oldfunction" being deprecated | ||
197 | +from "my-module" on STDERR. | ||
198 | + | ||
199 | +```js | ||
200 | +var deprecate = require('depd')('my-cool-module') | ||
201 | + | ||
202 | +// message automatically derived from function name | ||
203 | +// Object.oldfunction | ||
204 | +exports.oldfunction = deprecate.function(function oldfunction () { | ||
205 | + // all calls to function are deprecated | ||
206 | +}) | ||
207 | + | ||
208 | +// specific message | ||
209 | +exports.oldfunction = deprecate.function(function () { | ||
210 | + // all calls to function are deprecated | ||
211 | +}, 'oldfunction') | ||
212 | +``` | ||
213 | + | ||
214 | +### Conditionally deprecating a function call | ||
215 | + | ||
216 | +This will display a deprecated message about "weirdfunction" being deprecated | ||
217 | +from "my-module" on STDERR when called with less than 2 arguments. | ||
218 | + | ||
219 | +```js | ||
220 | +var deprecate = require('depd')('my-cool-module') | ||
221 | + | ||
222 | +exports.weirdfunction = function () { | ||
223 | + if (arguments.length < 2) { | ||
224 | + // calls with 0 or 1 args are deprecated | ||
225 | + deprecate('weirdfunction args < 2') | ||
226 | + } | ||
227 | +} | ||
228 | +``` | ||
229 | + | ||
230 | +When calling `deprecate` as a function, the warning is counted per call site | ||
231 | +within your own module, so you can display different deprecations depending | ||
232 | +on different situations and the users will still get all the warnings: | ||
233 | + | ||
234 | +```js | ||
235 | +var deprecate = require('depd')('my-cool-module') | ||
236 | + | ||
237 | +exports.weirdfunction = function () { | ||
238 | + if (arguments.length < 2) { | ||
239 | + // calls with 0 or 1 args are deprecated | ||
240 | + deprecate('weirdfunction args < 2') | ||
241 | + } else if (typeof arguments[0] !== 'string') { | ||
242 | + // calls with non-string first argument are deprecated | ||
243 | + deprecate('weirdfunction non-string first arg') | ||
244 | + } | ||
245 | +} | ||
246 | +``` | ||
247 | + | ||
248 | +### Deprecating property access | ||
249 | + | ||
250 | +This will display a deprecated message about "oldprop" being deprecated | ||
251 | +from "my-module" on STDERR when accessed. A deprecation will be displayed | ||
252 | +when setting the value and when getting the value. | ||
253 | + | ||
254 | +```js | ||
255 | +var deprecate = require('depd')('my-cool-module') | ||
256 | + | ||
257 | +exports.oldprop = 'something' | ||
258 | + | ||
259 | +// message automatically derives from property name | ||
260 | +deprecate.property(exports, 'oldprop') | ||
261 | + | ||
262 | +// explicit message | ||
263 | +deprecate.property(exports, 'oldprop', 'oldprop >= 0.10') | ||
264 | +``` | ||
265 | + | ||
266 | +## License | ||
267 | + | ||
268 | +[MIT](LICENSE) | ||
269 | + | ||
270 | +[appveyor-image]: https://badgen.net/appveyor/ci/dougwilson/nodejs-depd/master?label=windows | ||
271 | +[appveyor-url]: https://ci.appveyor.com/project/dougwilson/nodejs-depd | ||
272 | +[coveralls-image]: https://badgen.net/coveralls/c/github/dougwilson/nodejs-depd/master | ||
273 | +[coveralls-url]: https://coveralls.io/r/dougwilson/nodejs-depd?branch=master | ||
274 | +[node-image]: https://badgen.net/npm/node/depd | ||
275 | +[node-url]: https://nodejs.org/en/download/ | ||
276 | +[npm-downloads-image]: https://badgen.net/npm/dm/depd | ||
277 | +[npm-url]: https://npmjs.org/package/depd | ||
278 | +[npm-version-image]: https://badgen.net/npm/v/depd | ||
279 | +[travis-image]: https://badgen.net/travis/dougwilson/nodejs-depd/master?label=linux | ||
280 | +[travis-url]: https://travis-ci.org/dougwilson/nodejs-depd |
1 | +/*! | ||
2 | + * depd | ||
3 | + * Copyright(c) 2014-2018 Douglas Christopher Wilson | ||
4 | + * MIT Licensed | ||
5 | + */ | ||
6 | + | ||
7 | +/** | ||
8 | + * Module dependencies. | ||
9 | + */ | ||
10 | + | ||
11 | +var relative = require('path').relative | ||
12 | + | ||
13 | +/** | ||
14 | + * Module exports. | ||
15 | + */ | ||
16 | + | ||
17 | +module.exports = depd | ||
18 | + | ||
19 | +/** | ||
20 | + * Get the path to base files on. | ||
21 | + */ | ||
22 | + | ||
23 | +var basePath = process.cwd() | ||
24 | + | ||
25 | +/** | ||
26 | + * Determine if namespace is contained in the string. | ||
27 | + */ | ||
28 | + | ||
29 | +function containsNamespace (str, namespace) { | ||
30 | + var vals = str.split(/[ ,]+/) | ||
31 | + var ns = String(namespace).toLowerCase() | ||
32 | + | ||
33 | + for (var i = 0; i < vals.length; i++) { | ||
34 | + var val = vals[i] | ||
35 | + | ||
36 | + // namespace contained | ||
37 | + if (val && (val === '*' || val.toLowerCase() === ns)) { | ||
38 | + return true | ||
39 | + } | ||
40 | + } | ||
41 | + | ||
42 | + return false | ||
43 | +} | ||
44 | + | ||
45 | +/** | ||
46 | + * Convert a data descriptor to accessor descriptor. | ||
47 | + */ | ||
48 | + | ||
49 | +function convertDataDescriptorToAccessor (obj, prop, message) { | ||
50 | + var descriptor = Object.getOwnPropertyDescriptor(obj, prop) | ||
51 | + var value = descriptor.value | ||
52 | + | ||
53 | + descriptor.get = function getter () { return value } | ||
54 | + | ||
55 | + if (descriptor.writable) { | ||
56 | + descriptor.set = function setter (val) { return (value = val) } | ||
57 | + } | ||
58 | + | ||
59 | + delete descriptor.value | ||
60 | + delete descriptor.writable | ||
61 | + | ||
62 | + Object.defineProperty(obj, prop, descriptor) | ||
63 | + | ||
64 | + return descriptor | ||
65 | +} | ||
66 | + | ||
67 | +/** | ||
68 | + * Create arguments string to keep arity. | ||
69 | + */ | ||
70 | + | ||
71 | +function createArgumentsString (arity) { | ||
72 | + var str = '' | ||
73 | + | ||
74 | + for (var i = 0; i < arity; i++) { | ||
75 | + str += ', arg' + i | ||
76 | + } | ||
77 | + | ||
78 | + return str.substr(2) | ||
79 | +} | ||
80 | + | ||
81 | +/** | ||
82 | + * Create stack string from stack. | ||
83 | + */ | ||
84 | + | ||
85 | +function createStackString (stack) { | ||
86 | + var str = this.name + ': ' + this.namespace | ||
87 | + | ||
88 | + if (this.message) { | ||
89 | + str += ' deprecated ' + this.message | ||
90 | + } | ||
91 | + | ||
92 | + for (var i = 0; i < stack.length; i++) { | ||
93 | + str += '\n at ' + stack[i].toString() | ||
94 | + } | ||
95 | + | ||
96 | + return str | ||
97 | +} | ||
98 | + | ||
99 | +/** | ||
100 | + * Create deprecate for namespace in caller. | ||
101 | + */ | ||
102 | + | ||
103 | +function depd (namespace) { | ||
104 | + if (!namespace) { | ||
105 | + throw new TypeError('argument namespace is required') | ||
106 | + } | ||
107 | + | ||
108 | + var stack = getStack() | ||
109 | + var site = callSiteLocation(stack[1]) | ||
110 | + var file = site[0] | ||
111 | + | ||
112 | + function deprecate (message) { | ||
113 | + // call to self as log | ||
114 | + log.call(deprecate, message) | ||
115 | + } | ||
116 | + | ||
117 | + deprecate._file = file | ||
118 | + deprecate._ignored = isignored(namespace) | ||
119 | + deprecate._namespace = namespace | ||
120 | + deprecate._traced = istraced(namespace) | ||
121 | + deprecate._warned = Object.create(null) | ||
122 | + | ||
123 | + deprecate.function = wrapfunction | ||
124 | + deprecate.property = wrapproperty | ||
125 | + | ||
126 | + return deprecate | ||
127 | +} | ||
128 | + | ||
129 | +/** | ||
130 | + * Determine if event emitter has listeners of a given type. | ||
131 | + * | ||
132 | + * The way to do this check is done three different ways in Node.js >= 0.8 | ||
133 | + * so this consolidates them into a minimal set using instance methods. | ||
134 | + * | ||
135 | + * @param {EventEmitter} emitter | ||
136 | + * @param {string} type | ||
137 | + * @returns {boolean} | ||
138 | + * @private | ||
139 | + */ | ||
140 | + | ||
141 | +function eehaslisteners (emitter, type) { | ||
142 | + var count = typeof emitter.listenerCount !== 'function' | ||
143 | + ? emitter.listeners(type).length | ||
144 | + : emitter.listenerCount(type) | ||
145 | + | ||
146 | + return count > 0 | ||
147 | +} | ||
148 | + | ||
149 | +/** | ||
150 | + * Determine if namespace is ignored. | ||
151 | + */ | ||
152 | + | ||
153 | +function isignored (namespace) { | ||
154 | + if (process.noDeprecation) { | ||
155 | + // --no-deprecation support | ||
156 | + return true | ||
157 | + } | ||
158 | + | ||
159 | + var str = process.env.NO_DEPRECATION || '' | ||
160 | + | ||
161 | + // namespace ignored | ||
162 | + return containsNamespace(str, namespace) | ||
163 | +} | ||
164 | + | ||
165 | +/** | ||
166 | + * Determine if namespace is traced. | ||
167 | + */ | ||
168 | + | ||
169 | +function istraced (namespace) { | ||
170 | + if (process.traceDeprecation) { | ||
171 | + // --trace-deprecation support | ||
172 | + return true | ||
173 | + } | ||
174 | + | ||
175 | + var str = process.env.TRACE_DEPRECATION || '' | ||
176 | + | ||
177 | + // namespace traced | ||
178 | + return containsNamespace(str, namespace) | ||
179 | +} | ||
180 | + | ||
181 | +/** | ||
182 | + * Display deprecation message. | ||
183 | + */ | ||
184 | + | ||
185 | +function log (message, site) { | ||
186 | + var haslisteners = eehaslisteners(process, 'deprecation') | ||
187 | + | ||
188 | + // abort early if no destination | ||
189 | + if (!haslisteners && this._ignored) { | ||
190 | + return | ||
191 | + } | ||
192 | + | ||
193 | + var caller | ||
194 | + var callFile | ||
195 | + var callSite | ||
196 | + var depSite | ||
197 | + var i = 0 | ||
198 | + var seen = false | ||
199 | + var stack = getStack() | ||
200 | + var file = this._file | ||
201 | + | ||
202 | + if (site) { | ||
203 | + // provided site | ||
204 | + depSite = site | ||
205 | + callSite = callSiteLocation(stack[1]) | ||
206 | + callSite.name = depSite.name | ||
207 | + file = callSite[0] | ||
208 | + } else { | ||
209 | + // get call site | ||
210 | + i = 2 | ||
211 | + depSite = callSiteLocation(stack[i]) | ||
212 | + callSite = depSite | ||
213 | + } | ||
214 | + | ||
215 | + // get caller of deprecated thing in relation to file | ||
216 | + for (; i < stack.length; i++) { | ||
217 | + caller = callSiteLocation(stack[i]) | ||
218 | + callFile = caller[0] | ||
219 | + | ||
220 | + if (callFile === file) { | ||
221 | + seen = true | ||
222 | + } else if (callFile === this._file) { | ||
223 | + file = this._file | ||
224 | + } else if (seen) { | ||
225 | + break | ||
226 | + } | ||
227 | + } | ||
228 | + | ||
229 | + var key = caller | ||
230 | + ? depSite.join(':') + '__' + caller.join(':') | ||
231 | + : undefined | ||
232 | + | ||
233 | + if (key !== undefined && key in this._warned) { | ||
234 | + // already warned | ||
235 | + return | ||
236 | + } | ||
237 | + | ||
238 | + this._warned[key] = true | ||
239 | + | ||
240 | + // generate automatic message from call site | ||
241 | + var msg = message | ||
242 | + if (!msg) { | ||
243 | + msg = callSite === depSite || !callSite.name | ||
244 | + ? defaultMessage(depSite) | ||
245 | + : defaultMessage(callSite) | ||
246 | + } | ||
247 | + | ||
248 | + // emit deprecation if listeners exist | ||
249 | + if (haslisteners) { | ||
250 | + var err = DeprecationError(this._namespace, msg, stack.slice(i)) | ||
251 | + process.emit('deprecation', err) | ||
252 | + return | ||
253 | + } | ||
254 | + | ||
255 | + // format and write message | ||
256 | + var format = process.stderr.isTTY | ||
257 | + ? formatColor | ||
258 | + : formatPlain | ||
259 | + var output = format.call(this, msg, caller, stack.slice(i)) | ||
260 | + process.stderr.write(output + '\n', 'utf8') | ||
261 | +} | ||
262 | + | ||
263 | +/** | ||
264 | + * Get call site location as array. | ||
265 | + */ | ||
266 | + | ||
267 | +function callSiteLocation (callSite) { | ||
268 | + var file = callSite.getFileName() || '<anonymous>' | ||
269 | + var line = callSite.getLineNumber() | ||
270 | + var colm = callSite.getColumnNumber() | ||
271 | + | ||
272 | + if (callSite.isEval()) { | ||
273 | + file = callSite.getEvalOrigin() + ', ' + file | ||
274 | + } | ||
275 | + | ||
276 | + var site = [file, line, colm] | ||
277 | + | ||
278 | + site.callSite = callSite | ||
279 | + site.name = callSite.getFunctionName() | ||
280 | + | ||
281 | + return site | ||
282 | +} | ||
283 | + | ||
284 | +/** | ||
285 | + * Generate a default message from the site. | ||
286 | + */ | ||
287 | + | ||
288 | +function defaultMessage (site) { | ||
289 | + var callSite = site.callSite | ||
290 | + var funcName = site.name | ||
291 | + | ||
292 | + // make useful anonymous name | ||
293 | + if (!funcName) { | ||
294 | + funcName = '<anonymous@' + formatLocation(site) + '>' | ||
295 | + } | ||
296 | + | ||
297 | + var context = callSite.getThis() | ||
298 | + var typeName = context && callSite.getTypeName() | ||
299 | + | ||
300 | + // ignore useless type name | ||
301 | + if (typeName === 'Object') { | ||
302 | + typeName = undefined | ||
303 | + } | ||
304 | + | ||
305 | + // make useful type name | ||
306 | + if (typeName === 'Function') { | ||
307 | + typeName = context.name || typeName | ||
308 | + } | ||
309 | + | ||
310 | + return typeName && callSite.getMethodName() | ||
311 | + ? typeName + '.' + funcName | ||
312 | + : funcName | ||
313 | +} | ||
314 | + | ||
315 | +/** | ||
316 | + * Format deprecation message without color. | ||
317 | + */ | ||
318 | + | ||
319 | +function formatPlain (msg, caller, stack) { | ||
320 | + var timestamp = new Date().toUTCString() | ||
321 | + | ||
322 | + var formatted = timestamp + | ||
323 | + ' ' + this._namespace + | ||
324 | + ' deprecated ' + msg | ||
325 | + | ||
326 | + // add stack trace | ||
327 | + if (this._traced) { | ||
328 | + for (var i = 0; i < stack.length; i++) { | ||
329 | + formatted += '\n at ' + stack[i].toString() | ||
330 | + } | ||
331 | + | ||
332 | + return formatted | ||
333 | + } | ||
334 | + | ||
335 | + if (caller) { | ||
336 | + formatted += ' at ' + formatLocation(caller) | ||
337 | + } | ||
338 | + | ||
339 | + return formatted | ||
340 | +} | ||
341 | + | ||
342 | +/** | ||
343 | + * Format deprecation message with color. | ||
344 | + */ | ||
345 | + | ||
346 | +function formatColor (msg, caller, stack) { | ||
347 | + var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' + // bold cyan | ||
348 | + ' \x1b[33;1mdeprecated\x1b[22;39m' + // bold yellow | ||
349 | + ' \x1b[0m' + msg + '\x1b[39m' // reset | ||
350 | + | ||
351 | + // add stack trace | ||
352 | + if (this._traced) { | ||
353 | + for (var i = 0; i < stack.length; i++) { | ||
354 | + formatted += '\n \x1b[36mat ' + stack[i].toString() + '\x1b[39m' // cyan | ||
355 | + } | ||
356 | + | ||
357 | + return formatted | ||
358 | + } | ||
359 | + | ||
360 | + if (caller) { | ||
361 | + formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m' // cyan | ||
362 | + } | ||
363 | + | ||
364 | + return formatted | ||
365 | +} | ||
366 | + | ||
367 | +/** | ||
368 | + * Format call site location. | ||
369 | + */ | ||
370 | + | ||
371 | +function formatLocation (callSite) { | ||
372 | + return relative(basePath, callSite[0]) + | ||
373 | + ':' + callSite[1] + | ||
374 | + ':' + callSite[2] | ||
375 | +} | ||
376 | + | ||
377 | +/** | ||
378 | + * Get the stack as array of call sites. | ||
379 | + */ | ||
380 | + | ||
381 | +function getStack () { | ||
382 | + var limit = Error.stackTraceLimit | ||
383 | + var obj = {} | ||
384 | + var prep = Error.prepareStackTrace | ||
385 | + | ||
386 | + Error.prepareStackTrace = prepareObjectStackTrace | ||
387 | + Error.stackTraceLimit = Math.max(10, limit) | ||
388 | + | ||
389 | + // capture the stack | ||
390 | + Error.captureStackTrace(obj) | ||
391 | + | ||
392 | + // slice this function off the top | ||
393 | + var stack = obj.stack.slice(1) | ||
394 | + | ||
395 | + Error.prepareStackTrace = prep | ||
396 | + Error.stackTraceLimit = limit | ||
397 | + | ||
398 | + return stack | ||
399 | +} | ||
400 | + | ||
401 | +/** | ||
402 | + * Capture call site stack from v8. | ||
403 | + */ | ||
404 | + | ||
405 | +function prepareObjectStackTrace (obj, stack) { | ||
406 | + return stack | ||
407 | +} | ||
408 | + | ||
409 | +/** | ||
410 | + * Return a wrapped function in a deprecation message. | ||
411 | + */ | ||
412 | + | ||
413 | +function wrapfunction (fn, message) { | ||
414 | + if (typeof fn !== 'function') { | ||
415 | + throw new TypeError('argument fn must be a function') | ||
416 | + } | ||
417 | + | ||
418 | + var args = createArgumentsString(fn.length) | ||
419 | + var stack = getStack() | ||
420 | + var site = callSiteLocation(stack[1]) | ||
421 | + | ||
422 | + site.name = fn.name | ||
423 | + | ||
424 | + // eslint-disable-next-line no-new-func | ||
425 | + var deprecatedfn = new Function('fn', 'log', 'deprecate', 'message', 'site', | ||
426 | + '"use strict"\n' + | ||
427 | + 'return function (' + args + ') {' + | ||
428 | + 'log.call(deprecate, message, site)\n' + | ||
429 | + 'return fn.apply(this, arguments)\n' + | ||
430 | + '}')(fn, log, this, message, site) | ||
431 | + | ||
432 | + return deprecatedfn | ||
433 | +} | ||
434 | + | ||
435 | +/** | ||
436 | + * Wrap property in a deprecation message. | ||
437 | + */ | ||
438 | + | ||
439 | +function wrapproperty (obj, prop, message) { | ||
440 | + if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) { | ||
441 | + throw new TypeError('argument obj must be object') | ||
442 | + } | ||
443 | + | ||
444 | + var descriptor = Object.getOwnPropertyDescriptor(obj, prop) | ||
445 | + | ||
446 | + if (!descriptor) { | ||
447 | + throw new TypeError('must call property on owner object') | ||
448 | + } | ||
449 | + | ||
450 | + if (!descriptor.configurable) { | ||
451 | + throw new TypeError('property must be configurable') | ||
452 | + } | ||
453 | + | ||
454 | + var deprecate = this | ||
455 | + var stack = getStack() | ||
456 | + var site = callSiteLocation(stack[1]) | ||
457 | + | ||
458 | + // set site name | ||
459 | + site.name = prop | ||
460 | + | ||
461 | + // convert data descriptor | ||
462 | + if ('value' in descriptor) { | ||
463 | + descriptor = convertDataDescriptorToAccessor(obj, prop, message) | ||
464 | + } | ||
465 | + | ||
466 | + var get = descriptor.get | ||
467 | + var set = descriptor.set | ||
468 | + | ||
469 | + // wrap getter | ||
470 | + if (typeof get === 'function') { | ||
471 | + descriptor.get = function getter () { | ||
472 | + log.call(deprecate, message, site) | ||
473 | + return get.apply(this, arguments) | ||
474 | + } | ||
475 | + } | ||
476 | + | ||
477 | + // wrap setter | ||
478 | + if (typeof set === 'function') { | ||
479 | + descriptor.set = function setter () { | ||
480 | + log.call(deprecate, message, site) | ||
481 | + return set.apply(this, arguments) | ||
482 | + } | ||
483 | + } | ||
484 | + | ||
485 | + Object.defineProperty(obj, prop, descriptor) | ||
486 | +} | ||
487 | + | ||
488 | +/** | ||
489 | + * Create DeprecationError for deprecation | ||
490 | + */ | ||
491 | + | ||
492 | +function DeprecationError (namespace, message, stack) { | ||
493 | + var error = new Error() | ||
494 | + var stackString | ||
495 | + | ||
496 | + Object.defineProperty(error, 'constructor', { | ||
497 | + value: DeprecationError | ||
498 | + }) | ||
499 | + | ||
500 | + Object.defineProperty(error, 'message', { | ||
501 | + configurable: true, | ||
502 | + enumerable: false, | ||
503 | + value: message, | ||
504 | + writable: true | ||
505 | + }) | ||
506 | + | ||
507 | + Object.defineProperty(error, 'name', { | ||
508 | + enumerable: false, | ||
509 | + configurable: true, | ||
510 | + value: 'DeprecationError', | ||
511 | + writable: true | ||
512 | + }) | ||
513 | + | ||
514 | + Object.defineProperty(error, 'namespace', { | ||
515 | + configurable: true, | ||
516 | + enumerable: false, | ||
517 | + value: namespace, | ||
518 | + writable: true | ||
519 | + }) | ||
520 | + | ||
521 | + Object.defineProperty(error, 'stack', { | ||
522 | + configurable: true, | ||
523 | + enumerable: false, | ||
524 | + get: function () { | ||
525 | + if (stackString !== undefined) { | ||
526 | + return stackString | ||
527 | + } | ||
528 | + | ||
529 | + // prepare stack trace | ||
530 | + return (stackString = createStackString.call(this, stack)) | ||
531 | + }, | ||
532 | + set: function setter (val) { | ||
533 | + stackString = val | ||
534 | + } | ||
535 | + }) | ||
536 | + | ||
537 | + return error | ||
538 | +} |
1 | +/*! | ||
2 | + * depd | ||
3 | + * Copyright(c) 2015 Douglas Christopher Wilson | ||
4 | + * MIT Licensed | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict' | ||
8 | + | ||
9 | +/** | ||
10 | + * Module exports. | ||
11 | + * @public | ||
12 | + */ | ||
13 | + | ||
14 | +module.exports = depd | ||
15 | + | ||
16 | +/** | ||
17 | + * Create deprecate for namespace in caller. | ||
18 | + */ | ||
19 | + | ||
20 | +function depd (namespace) { | ||
21 | + if (!namespace) { | ||
22 | + throw new TypeError('argument namespace is required') | ||
23 | + } | ||
24 | + | ||
25 | + function deprecate (message) { | ||
26 | + // no-op in browser | ||
27 | + } | ||
28 | + | ||
29 | + deprecate._file = undefined | ||
30 | + deprecate._ignored = true | ||
31 | + deprecate._namespace = namespace | ||
32 | + deprecate._traced = false | ||
33 | + deprecate._warned = Object.create(null) | ||
34 | + | ||
35 | + deprecate.function = wrapfunction | ||
36 | + deprecate.property = wrapproperty | ||
37 | + | ||
38 | + return deprecate | ||
39 | +} | ||
40 | + | ||
41 | +/** | ||
42 | + * Return a wrapped function in a deprecation message. | ||
43 | + * | ||
44 | + * This is a no-op version of the wrapper, which does nothing but call | ||
45 | + * validation. | ||
46 | + */ | ||
47 | + | ||
48 | +function wrapfunction (fn, message) { | ||
49 | + if (typeof fn !== 'function') { | ||
50 | + throw new TypeError('argument fn must be a function') | ||
51 | + } | ||
52 | + | ||
53 | + return fn | ||
54 | +} | ||
55 | + | ||
56 | +/** | ||
57 | + * Wrap property in a deprecation message. | ||
58 | + * | ||
59 | + * This is a no-op version of the wrapper, which does nothing but call | ||
60 | + * validation. | ||
61 | + */ | ||
62 | + | ||
63 | +function wrapproperty (obj, prop, message) { | ||
64 | + if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) { | ||
65 | + throw new TypeError('argument obj must be object') | ||
66 | + } | ||
67 | + | ||
68 | + var descriptor = Object.getOwnPropertyDescriptor(obj, prop) | ||
69 | + | ||
70 | + if (!descriptor) { | ||
71 | + throw new TypeError('must call property on owner object') | ||
72 | + } | ||
73 | + | ||
74 | + if (!descriptor.configurable) { | ||
75 | + throw new TypeError('property must be configurable') | ||
76 | + } | ||
77 | +} |
1 | +{ | ||
2 | + "_from": "depd@~2.0.0", | ||
3 | + "_id": "depd@2.0.0", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", | ||
6 | + "_location": "/express-session/depd", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "range", | ||
10 | + "registry": true, | ||
11 | + "raw": "depd@~2.0.0", | ||
12 | + "name": "depd", | ||
13 | + "escapedName": "depd", | ||
14 | + "rawSpec": "~2.0.0", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "~2.0.0" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/express-session" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", | ||
22 | + "_shasum": "b696163cc757560d09cf22cc8fad1571b79e76df", | ||
23 | + "_spec": "depd@~2.0.0", | ||
24 | + "_where": "C:\\Users\\fheld\\Desktop\\khuhub\\mapmory\\Mapmory\\node_modules\\express-session", | ||
25 | + "author": { | ||
26 | + "name": "Douglas Christopher Wilson", | ||
27 | + "email": "doug@somethingdoug.com" | ||
28 | + }, | ||
29 | + "browser": "lib/browser/index.js", | ||
30 | + "bugs": { | ||
31 | + "url": "https://github.com/dougwilson/nodejs-depd/issues" | ||
32 | + }, | ||
33 | + "bundleDependencies": false, | ||
34 | + "deprecated": false, | ||
35 | + "description": "Deprecate all the things", | ||
36 | + "devDependencies": { | ||
37 | + "beautify-benchmark": "0.2.4", | ||
38 | + "benchmark": "2.1.4", | ||
39 | + "eslint": "5.7.0", | ||
40 | + "eslint-config-standard": "12.0.0", | ||
41 | + "eslint-plugin-import": "2.14.0", | ||
42 | + "eslint-plugin-markdown": "1.0.0-beta.7", | ||
43 | + "eslint-plugin-node": "7.0.1", | ||
44 | + "eslint-plugin-promise": "4.0.1", | ||
45 | + "eslint-plugin-standard": "4.0.0", | ||
46 | + "istanbul": "0.4.5", | ||
47 | + "mocha": "5.2.0", | ||
48 | + "safe-buffer": "5.1.2", | ||
49 | + "uid-safe": "2.1.5" | ||
50 | + }, | ||
51 | + "engines": { | ||
52 | + "node": ">= 0.8" | ||
53 | + }, | ||
54 | + "files": [ | ||
55 | + "lib/", | ||
56 | + "History.md", | ||
57 | + "LICENSE", | ||
58 | + "index.js", | ||
59 | + "Readme.md" | ||
60 | + ], | ||
61 | + "homepage": "https://github.com/dougwilson/nodejs-depd#readme", | ||
62 | + "keywords": [ | ||
63 | + "deprecate", | ||
64 | + "deprecated" | ||
65 | + ], | ||
66 | + "license": "MIT", | ||
67 | + "name": "depd", | ||
68 | + "repository": { | ||
69 | + "type": "git", | ||
70 | + "url": "git+https://github.com/dougwilson/nodejs-depd.git" | ||
71 | + }, | ||
72 | + "scripts": { | ||
73 | + "bench": "node benchmark/index.js", | ||
74 | + "lint": "eslint --plugin markdown --ext js,md .", | ||
75 | + "test": "mocha --reporter spec --bail test/", | ||
76 | + "test-ci": "istanbul cover --print=none node_modules/mocha/bin/_mocha -- --reporter spec test/ && istanbul report lcovonly text-summary", | ||
77 | + "test-cov": "istanbul cover --print=none node_modules/mocha/bin/_mocha -- --reporter dot test/ && istanbul report lcov text-summary" | ||
78 | + }, | ||
79 | + "version": "2.0.0" | ||
80 | +} |
1 | +The MIT License (MIT) | ||
2 | + | ||
3 | +Copyright (c) Feross Aboukhadijeh | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | +of this software and associated documentation files (the "Software"), to deal | ||
7 | +in the Software without restriction, including without limitation the rights | ||
8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | +copies of the Software, and to permit persons to whom the Software is | ||
10 | +furnished to do so, subject to the following conditions: | ||
11 | + | ||
12 | +The above copyright notice and this permission notice shall be included in | ||
13 | +all copies or substantial portions of the Software. | ||
14 | + | ||
15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | +THE SOFTWARE. |
1 | +# safe-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url] | ||
2 | + | ||
3 | +[travis-image]: https://img.shields.io/travis/feross/safe-buffer/master.svg | ||
4 | +[travis-url]: https://travis-ci.org/feross/safe-buffer | ||
5 | +[npm-image]: https://img.shields.io/npm/v/safe-buffer.svg | ||
6 | +[npm-url]: https://npmjs.org/package/safe-buffer | ||
7 | +[downloads-image]: https://img.shields.io/npm/dm/safe-buffer.svg | ||
8 | +[downloads-url]: https://npmjs.org/package/safe-buffer | ||
9 | +[standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg | ||
10 | +[standard-url]: https://standardjs.com | ||
11 | + | ||
12 | +#### Safer Node.js Buffer API | ||
13 | + | ||
14 | +**Use the new Node.js Buffer APIs (`Buffer.from`, `Buffer.alloc`, | ||
15 | +`Buffer.allocUnsafe`, `Buffer.allocUnsafeSlow`) in all versions of Node.js.** | ||
16 | + | ||
17 | +**Uses the built-in implementation when available.** | ||
18 | + | ||
19 | +## install | ||
20 | + | ||
21 | +``` | ||
22 | +npm install safe-buffer | ||
23 | +``` | ||
24 | + | ||
25 | +[Get supported safe-buffer with the Tidelift Subscription](https://tidelift.com/subscription/pkg/npm-safe-buffer?utm_source=npm-safe-buffer&utm_medium=referral&utm_campaign=readme) | ||
26 | + | ||
27 | +## usage | ||
28 | + | ||
29 | +The goal of this package is to provide a safe replacement for the node.js `Buffer`. | ||
30 | + | ||
31 | +It's a drop-in replacement for `Buffer`. You can use it by adding one `require` line to | ||
32 | +the top of your node.js modules: | ||
33 | + | ||
34 | +```js | ||
35 | +var Buffer = require('safe-buffer').Buffer | ||
36 | + | ||
37 | +// Existing buffer code will continue to work without issues: | ||
38 | + | ||
39 | +new Buffer('hey', 'utf8') | ||
40 | +new Buffer([1, 2, 3], 'utf8') | ||
41 | +new Buffer(obj) | ||
42 | +new Buffer(16) // create an uninitialized buffer (potentially unsafe) | ||
43 | + | ||
44 | +// But you can use these new explicit APIs to make clear what you want: | ||
45 | + | ||
46 | +Buffer.from('hey', 'utf8') // convert from many types to a Buffer | ||
47 | +Buffer.alloc(16) // create a zero-filled buffer (safe) | ||
48 | +Buffer.allocUnsafe(16) // create an uninitialized buffer (potentially unsafe) | ||
49 | +``` | ||
50 | + | ||
51 | +## api | ||
52 | + | ||
53 | +### Class Method: Buffer.from(array) | ||
54 | +<!-- YAML | ||
55 | +added: v3.0.0 | ||
56 | +--> | ||
57 | + | ||
58 | +* `array` {Array} | ||
59 | + | ||
60 | +Allocates a new `Buffer` using an `array` of octets. | ||
61 | + | ||
62 | +```js | ||
63 | +const buf = Buffer.from([0x62,0x75,0x66,0x66,0x65,0x72]); | ||
64 | + // creates a new Buffer containing ASCII bytes | ||
65 | + // ['b','u','f','f','e','r'] | ||
66 | +``` | ||
67 | + | ||
68 | +A `TypeError` will be thrown if `array` is not an `Array`. | ||
69 | + | ||
70 | +### Class Method: Buffer.from(arrayBuffer[, byteOffset[, length]]) | ||
71 | +<!-- YAML | ||
72 | +added: v5.10.0 | ||
73 | +--> | ||
74 | + | ||
75 | +* `arrayBuffer` {ArrayBuffer} The `.buffer` property of a `TypedArray` or | ||
76 | + a `new ArrayBuffer()` | ||
77 | +* `byteOffset` {Number} Default: `0` | ||
78 | +* `length` {Number} Default: `arrayBuffer.length - byteOffset` | ||
79 | + | ||
80 | +When passed a reference to the `.buffer` property of a `TypedArray` instance, | ||
81 | +the newly created `Buffer` will share the same allocated memory as the | ||
82 | +TypedArray. | ||
83 | + | ||
84 | +```js | ||
85 | +const arr = new Uint16Array(2); | ||
86 | +arr[0] = 5000; | ||
87 | +arr[1] = 4000; | ||
88 | + | ||
89 | +const buf = Buffer.from(arr.buffer); // shares the memory with arr; | ||
90 | + | ||
91 | +console.log(buf); | ||
92 | + // Prints: <Buffer 88 13 a0 0f> | ||
93 | + | ||
94 | +// changing the TypedArray changes the Buffer also | ||
95 | +arr[1] = 6000; | ||
96 | + | ||
97 | +console.log(buf); | ||
98 | + // Prints: <Buffer 88 13 70 17> | ||
99 | +``` | ||
100 | + | ||
101 | +The optional `byteOffset` and `length` arguments specify a memory range within | ||
102 | +the `arrayBuffer` that will be shared by the `Buffer`. | ||
103 | + | ||
104 | +```js | ||
105 | +const ab = new ArrayBuffer(10); | ||
106 | +const buf = Buffer.from(ab, 0, 2); | ||
107 | +console.log(buf.length); | ||
108 | + // Prints: 2 | ||
109 | +``` | ||
110 | + | ||
111 | +A `TypeError` will be thrown if `arrayBuffer` is not an `ArrayBuffer`. | ||
112 | + | ||
113 | +### Class Method: Buffer.from(buffer) | ||
114 | +<!-- YAML | ||
115 | +added: v3.0.0 | ||
116 | +--> | ||
117 | + | ||
118 | +* `buffer` {Buffer} | ||
119 | + | ||
120 | +Copies the passed `buffer` data onto a new `Buffer` instance. | ||
121 | + | ||
122 | +```js | ||
123 | +const buf1 = Buffer.from('buffer'); | ||
124 | +const buf2 = Buffer.from(buf1); | ||
125 | + | ||
126 | +buf1[0] = 0x61; | ||
127 | +console.log(buf1.toString()); | ||
128 | + // 'auffer' | ||
129 | +console.log(buf2.toString()); | ||
130 | + // 'buffer' (copy is not changed) | ||
131 | +``` | ||
132 | + | ||
133 | +A `TypeError` will be thrown if `buffer` is not a `Buffer`. | ||
134 | + | ||
135 | +### Class Method: Buffer.from(str[, encoding]) | ||
136 | +<!-- YAML | ||
137 | +added: v5.10.0 | ||
138 | +--> | ||
139 | + | ||
140 | +* `str` {String} String to encode. | ||
141 | +* `encoding` {String} Encoding to use, Default: `'utf8'` | ||
142 | + | ||
143 | +Creates a new `Buffer` containing the given JavaScript string `str`. If | ||
144 | +provided, the `encoding` parameter identifies the character encoding. | ||
145 | +If not provided, `encoding` defaults to `'utf8'`. | ||
146 | + | ||
147 | +```js | ||
148 | +const buf1 = Buffer.from('this is a tést'); | ||
149 | +console.log(buf1.toString()); | ||
150 | + // prints: this is a tést | ||
151 | +console.log(buf1.toString('ascii')); | ||
152 | + // prints: this is a tC)st | ||
153 | + | ||
154 | +const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex'); | ||
155 | +console.log(buf2.toString()); | ||
156 | + // prints: this is a tést | ||
157 | +``` | ||
158 | + | ||
159 | +A `TypeError` will be thrown if `str` is not a string. | ||
160 | + | ||
161 | +### Class Method: Buffer.alloc(size[, fill[, encoding]]) | ||
162 | +<!-- YAML | ||
163 | +added: v5.10.0 | ||
164 | +--> | ||
165 | + | ||
166 | +* `size` {Number} | ||
167 | +* `fill` {Value} Default: `undefined` | ||
168 | +* `encoding` {String} Default: `utf8` | ||
169 | + | ||
170 | +Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the | ||
171 | +`Buffer` will be *zero-filled*. | ||
172 | + | ||
173 | +```js | ||
174 | +const buf = Buffer.alloc(5); | ||
175 | +console.log(buf); | ||
176 | + // <Buffer 00 00 00 00 00> | ||
177 | +``` | ||
178 | + | ||
179 | +The `size` must be less than or equal to the value of | ||
180 | +`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is | ||
181 | +`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will | ||
182 | +be created if a `size` less than or equal to 0 is specified. | ||
183 | + | ||
184 | +If `fill` is specified, the allocated `Buffer` will be initialized by calling | ||
185 | +`buf.fill(fill)`. See [`buf.fill()`][] for more information. | ||
186 | + | ||
187 | +```js | ||
188 | +const buf = Buffer.alloc(5, 'a'); | ||
189 | +console.log(buf); | ||
190 | + // <Buffer 61 61 61 61 61> | ||
191 | +``` | ||
192 | + | ||
193 | +If both `fill` and `encoding` are specified, the allocated `Buffer` will be | ||
194 | +initialized by calling `buf.fill(fill, encoding)`. For example: | ||
195 | + | ||
196 | +```js | ||
197 | +const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64'); | ||
198 | +console.log(buf); | ||
199 | + // <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64> | ||
200 | +``` | ||
201 | + | ||
202 | +Calling `Buffer.alloc(size)` can be significantly slower than the alternative | ||
203 | +`Buffer.allocUnsafe(size)` but ensures that the newly created `Buffer` instance | ||
204 | +contents will *never contain sensitive data*. | ||
205 | + | ||
206 | +A `TypeError` will be thrown if `size` is not a number. | ||
207 | + | ||
208 | +### Class Method: Buffer.allocUnsafe(size) | ||
209 | +<!-- YAML | ||
210 | +added: v5.10.0 | ||
211 | +--> | ||
212 | + | ||
213 | +* `size` {Number} | ||
214 | + | ||
215 | +Allocates a new *non-zero-filled* `Buffer` of `size` bytes. The `size` must | ||
216 | +be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit | ||
217 | +architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is | ||
218 | +thrown. A zero-length Buffer will be created if a `size` less than or equal to | ||
219 | +0 is specified. | ||
220 | + | ||
221 | +The underlying memory for `Buffer` instances created in this way is *not | ||
222 | +initialized*. The contents of the newly created `Buffer` are unknown and | ||
223 | +*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such | ||
224 | +`Buffer` instances to zeroes. | ||
225 | + | ||
226 | +```js | ||
227 | +const buf = Buffer.allocUnsafe(5); | ||
228 | +console.log(buf); | ||
229 | + // <Buffer 78 e0 82 02 01> | ||
230 | + // (octets will be different, every time) | ||
231 | +buf.fill(0); | ||
232 | +console.log(buf); | ||
233 | + // <Buffer 00 00 00 00 00> | ||
234 | +``` | ||
235 | + | ||
236 | +A `TypeError` will be thrown if `size` is not a number. | ||
237 | + | ||
238 | +Note that the `Buffer` module pre-allocates an internal `Buffer` instance of | ||
239 | +size `Buffer.poolSize` that is used as a pool for the fast allocation of new | ||
240 | +`Buffer` instances created using `Buffer.allocUnsafe(size)` (and the deprecated | ||
241 | +`new Buffer(size)` constructor) only when `size` is less than or equal to | ||
242 | +`Buffer.poolSize >> 1` (floor of `Buffer.poolSize` divided by two). The default | ||
243 | +value of `Buffer.poolSize` is `8192` but can be modified. | ||
244 | + | ||
245 | +Use of this pre-allocated internal memory pool is a key difference between | ||
246 | +calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`. | ||
247 | +Specifically, `Buffer.alloc(size, fill)` will *never* use the internal Buffer | ||
248 | +pool, while `Buffer.allocUnsafe(size).fill(fill)` *will* use the internal | ||
249 | +Buffer pool if `size` is less than or equal to half `Buffer.poolSize`. The | ||
250 | +difference is subtle but can be important when an application requires the | ||
251 | +additional performance that `Buffer.allocUnsafe(size)` provides. | ||
252 | + | ||
253 | +### Class Method: Buffer.allocUnsafeSlow(size) | ||
254 | +<!-- YAML | ||
255 | +added: v5.10.0 | ||
256 | +--> | ||
257 | + | ||
258 | +* `size` {Number} | ||
259 | + | ||
260 | +Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes. The | ||
261 | +`size` must be less than or equal to the value of | ||
262 | +`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is | ||
263 | +`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will | ||
264 | +be created if a `size` less than or equal to 0 is specified. | ||
265 | + | ||
266 | +The underlying memory for `Buffer` instances created in this way is *not | ||
267 | +initialized*. The contents of the newly created `Buffer` are unknown and | ||
268 | +*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such | ||
269 | +`Buffer` instances to zeroes. | ||
270 | + | ||
271 | +When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances, | ||
272 | +allocations under 4KB are, by default, sliced from a single pre-allocated | ||
273 | +`Buffer`. This allows applications to avoid the garbage collection overhead of | ||
274 | +creating many individually allocated Buffers. This approach improves both | ||
275 | +performance and memory usage by eliminating the need to track and cleanup as | ||
276 | +many `Persistent` objects. | ||
277 | + | ||
278 | +However, in the case where a developer may need to retain a small chunk of | ||
279 | +memory from a pool for an indeterminate amount of time, it may be appropriate | ||
280 | +to create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then | ||
281 | +copy out the relevant bits. | ||
282 | + | ||
283 | +```js | ||
284 | +// need to keep around a few small chunks of memory | ||
285 | +const store = []; | ||
286 | + | ||
287 | +socket.on('readable', () => { | ||
288 | + const data = socket.read(); | ||
289 | + // allocate for retained data | ||
290 | + const sb = Buffer.allocUnsafeSlow(10); | ||
291 | + // copy the data into the new allocation | ||
292 | + data.copy(sb, 0, 0, 10); | ||
293 | + store.push(sb); | ||
294 | +}); | ||
295 | +``` | ||
296 | + | ||
297 | +Use of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after* | ||
298 | +a developer has observed undue memory retention in their applications. | ||
299 | + | ||
300 | +A `TypeError` will be thrown if `size` is not a number. | ||
301 | + | ||
302 | +### All the Rest | ||
303 | + | ||
304 | +The rest of the `Buffer` API is exactly the same as in node.js. | ||
305 | +[See the docs](https://nodejs.org/api/buffer.html). | ||
306 | + | ||
307 | + | ||
308 | +## Related links | ||
309 | + | ||
310 | +- [Node.js issue: Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660) | ||
311 | +- [Node.js Enhancement Proposal: Buffer.from/Buffer.alloc/Buffer.zalloc/Buffer() soft-deprecate](https://github.com/nodejs/node-eps/pull/4) | ||
312 | + | ||
313 | +## Why is `Buffer` unsafe? | ||
314 | + | ||
315 | +Today, the node.js `Buffer` constructor is overloaded to handle many different argument | ||
316 | +types like `String`, `Array`, `Object`, `TypedArrayView` (`Uint8Array`, etc.), | ||
317 | +`ArrayBuffer`, and also `Number`. | ||
318 | + | ||
319 | +The API is optimized for convenience: you can throw any type at it, and it will try to do | ||
320 | +what you want. | ||
321 | + | ||
322 | +Because the Buffer constructor is so powerful, you often see code like this: | ||
323 | + | ||
324 | +```js | ||
325 | +// Convert UTF-8 strings to hex | ||
326 | +function toHex (str) { | ||
327 | + return new Buffer(str).toString('hex') | ||
328 | +} | ||
329 | +``` | ||
330 | + | ||
331 | +***But what happens if `toHex` is called with a `Number` argument?*** | ||
332 | + | ||
333 | +### Remote Memory Disclosure | ||
334 | + | ||
335 | +If an attacker can make your program call the `Buffer` constructor with a `Number` | ||
336 | +argument, then they can make it allocate uninitialized memory from the node.js process. | ||
337 | +This could potentially disclose TLS private keys, user data, or database passwords. | ||
338 | + | ||
339 | +When the `Buffer` constructor is passed a `Number` argument, it returns an | ||
340 | +**UNINITIALIZED** block of memory of the specified `size`. When you create a `Buffer` like | ||
341 | +this, you **MUST** overwrite the contents before returning it to the user. | ||
342 | + | ||
343 | +From the [node.js docs](https://nodejs.org/api/buffer.html#buffer_new_buffer_size): | ||
344 | + | ||
345 | +> `new Buffer(size)` | ||
346 | +> | ||
347 | +> - `size` Number | ||
348 | +> | ||
349 | +> The underlying memory for `Buffer` instances created in this way is not initialized. | ||
350 | +> **The contents of a newly created `Buffer` are unknown and could contain sensitive | ||
351 | +> data.** Use `buf.fill(0)` to initialize a Buffer to zeroes. | ||
352 | + | ||
353 | +(Emphasis our own.) | ||
354 | + | ||
355 | +Whenever the programmer intended to create an uninitialized `Buffer` you often see code | ||
356 | +like this: | ||
357 | + | ||
358 | +```js | ||
359 | +var buf = new Buffer(16) | ||
360 | + | ||
361 | +// Immediately overwrite the uninitialized buffer with data from another buffer | ||
362 | +for (var i = 0; i < buf.length; i++) { | ||
363 | + buf[i] = otherBuf[i] | ||
364 | +} | ||
365 | +``` | ||
366 | + | ||
367 | + | ||
368 | +### Would this ever be a problem in real code? | ||
369 | + | ||
370 | +Yes. It's surprisingly common to forget to check the type of your variables in a | ||
371 | +dynamically-typed language like JavaScript. | ||
372 | + | ||
373 | +Usually the consequences of assuming the wrong type is that your program crashes with an | ||
374 | +uncaught exception. But the failure mode for forgetting to check the type of arguments to | ||
375 | +the `Buffer` constructor is more catastrophic. | ||
376 | + | ||
377 | +Here's an example of a vulnerable service that takes a JSON payload and converts it to | ||
378 | +hex: | ||
379 | + | ||
380 | +```js | ||
381 | +// Take a JSON payload {str: "some string"} and convert it to hex | ||
382 | +var server = http.createServer(function (req, res) { | ||
383 | + var data = '' | ||
384 | + req.setEncoding('utf8') | ||
385 | + req.on('data', function (chunk) { | ||
386 | + data += chunk | ||
387 | + }) | ||
388 | + req.on('end', function () { | ||
389 | + var body = JSON.parse(data) | ||
390 | + res.end(new Buffer(body.str).toString('hex')) | ||
391 | + }) | ||
392 | +}) | ||
393 | + | ||
394 | +server.listen(8080) | ||
395 | +``` | ||
396 | + | ||
397 | +In this example, an http client just has to send: | ||
398 | + | ||
399 | +```json | ||
400 | +{ | ||
401 | + "str": 1000 | ||
402 | +} | ||
403 | +``` | ||
404 | + | ||
405 | +and it will get back 1,000 bytes of uninitialized memory from the server. | ||
406 | + | ||
407 | +This is a very serious bug. It's similar in severity to the | ||
408 | +[the Heartbleed bug](http://heartbleed.com/) that allowed disclosure of OpenSSL process | ||
409 | +memory by remote attackers. | ||
410 | + | ||
411 | + | ||
412 | +### Which real-world packages were vulnerable? | ||
413 | + | ||
414 | +#### [`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht) | ||
415 | + | ||
416 | +[Mathias Buus](https://github.com/mafintosh) and I | ||
417 | +([Feross Aboukhadijeh](http://feross.org/)) found this issue in one of our own packages, | ||
418 | +[`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht). The bug would allow | ||
419 | +anyone on the internet to send a series of messages to a user of `bittorrent-dht` and get | ||
420 | +them to reveal 20 bytes at a time of uninitialized memory from the node.js process. | ||
421 | + | ||
422 | +Here's | ||
423 | +[the commit](https://github.com/feross/bittorrent-dht/commit/6c7da04025d5633699800a99ec3fbadf70ad35b8) | ||
424 | +that fixed it. We released a new fixed version, created a | ||
425 | +[Node Security Project disclosure](https://nodesecurity.io/advisories/68), and deprecated all | ||
426 | +vulnerable versions on npm so users will get a warning to upgrade to a newer version. | ||
427 | + | ||
428 | +#### [`ws`](https://www.npmjs.com/package/ws) | ||
429 | + | ||
430 | +That got us wondering if there were other vulnerable packages. Sure enough, within a short | ||
431 | +period of time, we found the same issue in [`ws`](https://www.npmjs.com/package/ws), the | ||
432 | +most popular WebSocket implementation in node.js. | ||
433 | + | ||
434 | +If certain APIs were called with `Number` parameters instead of `String` or `Buffer` as | ||
435 | +expected, then uninitialized server memory would be disclosed to the remote peer. | ||
436 | + | ||
437 | +These were the vulnerable methods: | ||
438 | + | ||
439 | +```js | ||
440 | +socket.send(number) | ||
441 | +socket.ping(number) | ||
442 | +socket.pong(number) | ||
443 | +``` | ||
444 | + | ||
445 | +Here's a vulnerable socket server with some echo functionality: | ||
446 | + | ||
447 | +```js | ||
448 | +server.on('connection', function (socket) { | ||
449 | + socket.on('message', function (message) { | ||
450 | + message = JSON.parse(message) | ||
451 | + if (message.type === 'echo') { | ||
452 | + socket.send(message.data) // send back the user's message | ||
453 | + } | ||
454 | + }) | ||
455 | +}) | ||
456 | +``` | ||
457 | + | ||
458 | +`socket.send(number)` called on the server, will disclose server memory. | ||
459 | + | ||
460 | +Here's [the release](https://github.com/websockets/ws/releases/tag/1.0.1) where the issue | ||
461 | +was fixed, with a more detailed explanation. Props to | ||
462 | +[Arnout Kazemier](https://github.com/3rd-Eden) for the quick fix. Here's the | ||
463 | +[Node Security Project disclosure](https://nodesecurity.io/advisories/67). | ||
464 | + | ||
465 | + | ||
466 | +### What's the solution? | ||
467 | + | ||
468 | +It's important that node.js offers a fast way to get memory otherwise performance-critical | ||
469 | +applications would needlessly get a lot slower. | ||
470 | + | ||
471 | +But we need a better way to *signal our intent* as programmers. **When we want | ||
472 | +uninitialized memory, we should request it explicitly.** | ||
473 | + | ||
474 | +Sensitive functionality should not be packed into a developer-friendly API that loosely | ||
475 | +accepts many different types. This type of API encourages the lazy practice of passing | ||
476 | +variables in without checking the type very carefully. | ||
477 | + | ||
478 | +#### A new API: `Buffer.allocUnsafe(number)` | ||
479 | + | ||
480 | +The functionality of creating buffers with uninitialized memory should be part of another | ||
481 | +API. We propose `Buffer.allocUnsafe(number)`. This way, it's not part of an API that | ||
482 | +frequently gets user input of all sorts of different types passed into it. | ||
483 | + | ||
484 | +```js | ||
485 | +var buf = Buffer.allocUnsafe(16) // careful, uninitialized memory! | ||
486 | + | ||
487 | +// Immediately overwrite the uninitialized buffer with data from another buffer | ||
488 | +for (var i = 0; i < buf.length; i++) { | ||
489 | + buf[i] = otherBuf[i] | ||
490 | +} | ||
491 | +``` | ||
492 | + | ||
493 | + | ||
494 | +### How do we fix node.js core? | ||
495 | + | ||
496 | +We sent [a PR to node.js core](https://github.com/nodejs/node/pull/4514) (merged as | ||
497 | +`semver-major`) which defends against one case: | ||
498 | + | ||
499 | +```js | ||
500 | +var str = 16 | ||
501 | +new Buffer(str, 'utf8') | ||
502 | +``` | ||
503 | + | ||
504 | +In this situation, it's implied that the programmer intended the first argument to be a | ||
505 | +string, since they passed an encoding as a second argument. Today, node.js will allocate | ||
506 | +uninitialized memory in the case of `new Buffer(number, encoding)`, which is probably not | ||
507 | +what the programmer intended. | ||
508 | + | ||
509 | +But this is only a partial solution, since if the programmer does `new Buffer(variable)` | ||
510 | +(without an `encoding` parameter) there's no way to know what they intended. If `variable` | ||
511 | +is sometimes a number, then uninitialized memory will sometimes be returned. | ||
512 | + | ||
513 | +### What's the real long-term fix? | ||
514 | + | ||
515 | +We could deprecate and remove `new Buffer(number)` and use `Buffer.allocUnsafe(number)` when | ||
516 | +we need uninitialized memory. But that would break 1000s of packages. | ||
517 | + | ||
518 | +~~We believe the best solution is to:~~ | ||
519 | + | ||
520 | +~~1. Change `new Buffer(number)` to return safe, zeroed-out memory~~ | ||
521 | + | ||
522 | +~~2. Create a new API for creating uninitialized Buffers. We propose: `Buffer.allocUnsafe(number)`~~ | ||
523 | + | ||
524 | +#### Update | ||
525 | + | ||
526 | +We now support adding three new APIs: | ||
527 | + | ||
528 | +- `Buffer.from(value)` - convert from any type to a buffer | ||
529 | +- `Buffer.alloc(size)` - create a zero-filled buffer | ||
530 | +- `Buffer.allocUnsafe(size)` - create an uninitialized buffer with given size | ||
531 | + | ||
532 | +This solves the core problem that affected `ws` and `bittorrent-dht` which is | ||
533 | +`Buffer(variable)` getting tricked into taking a number argument. | ||
534 | + | ||
535 | +This way, existing code continues working and the impact on the npm ecosystem will be | ||
536 | +minimal. Over time, npm maintainers can migrate performance-critical code to use | ||
537 | +`Buffer.allocUnsafe(number)` instead of `new Buffer(number)`. | ||
538 | + | ||
539 | + | ||
540 | +### Conclusion | ||
541 | + | ||
542 | +We think there's a serious design issue with the `Buffer` API as it exists today. It | ||
543 | +promotes insecure software by putting high-risk functionality into a convenient API | ||
544 | +with friendly "developer ergonomics". | ||
545 | + | ||
546 | +This wasn't merely a theoretical exercise because we found the issue in some of the | ||
547 | +most popular npm packages. | ||
548 | + | ||
549 | +Fortunately, there's an easy fix that can be applied today. Use `safe-buffer` in place of | ||
550 | +`buffer`. | ||
551 | + | ||
552 | +```js | ||
553 | +var Buffer = require('safe-buffer').Buffer | ||
554 | +``` | ||
555 | + | ||
556 | +Eventually, we hope that node.js core can switch to this new, safer behavior. We believe | ||
557 | +the impact on the ecosystem would be minimal since it's not a breaking change. | ||
558 | +Well-maintained, popular packages would be updated to use `Buffer.alloc` quickly, while | ||
559 | +older, insecure packages would magically become safe from this attack vector. | ||
560 | + | ||
561 | + | ||
562 | +## links | ||
563 | + | ||
564 | +- [Node.js PR: buffer: throw if both length and enc are passed](https://github.com/nodejs/node/pull/4514) | ||
565 | +- [Node Security Project disclosure for `ws`](https://nodesecurity.io/advisories/67) | ||
566 | +- [Node Security Project disclosure for`bittorrent-dht`](https://nodesecurity.io/advisories/68) | ||
567 | + | ||
568 | + | ||
569 | +## credit | ||
570 | + | ||
571 | +The original issues in `bittorrent-dht` | ||
572 | +([disclosure](https://nodesecurity.io/advisories/68)) and | ||
573 | +`ws` ([disclosure](https://nodesecurity.io/advisories/67)) were discovered by | ||
574 | +[Mathias Buus](https://github.com/mafintosh) and | ||
575 | +[Feross Aboukhadijeh](http://feross.org/). | ||
576 | + | ||
577 | +Thanks to [Adam Baldwin](https://github.com/evilpacket) for helping disclose these issues | ||
578 | +and for his work running the [Node Security Project](https://nodesecurity.io/). | ||
579 | + | ||
580 | +Thanks to [John Hiesey](https://github.com/jhiesey) for proofreading this README and | ||
581 | +auditing the code. | ||
582 | + | ||
583 | + | ||
584 | +## license | ||
585 | + | ||
586 | +MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org) |
1 | +declare module "safe-buffer" { | ||
2 | + export class Buffer { | ||
3 | + length: number | ||
4 | + write(string: string, offset?: number, length?: number, encoding?: string): number; | ||
5 | + toString(encoding?: string, start?: number, end?: number): string; | ||
6 | + toJSON(): { type: 'Buffer', data: any[] }; | ||
7 | + equals(otherBuffer: Buffer): boolean; | ||
8 | + compare(otherBuffer: Buffer, targetStart?: number, targetEnd?: number, sourceStart?: number, sourceEnd?: number): number; | ||
9 | + copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; | ||
10 | + slice(start?: number, end?: number): Buffer; | ||
11 | + writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; | ||
12 | + writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; | ||
13 | + writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; | ||
14 | + writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; | ||
15 | + readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number; | ||
16 | + readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number; | ||
17 | + readIntLE(offset: number, byteLength: number, noAssert?: boolean): number; | ||
18 | + readIntBE(offset: number, byteLength: number, noAssert?: boolean): number; | ||
19 | + readUInt8(offset: number, noAssert?: boolean): number; | ||
20 | + readUInt16LE(offset: number, noAssert?: boolean): number; | ||
21 | + readUInt16BE(offset: number, noAssert?: boolean): number; | ||
22 | + readUInt32LE(offset: number, noAssert?: boolean): number; | ||
23 | + readUInt32BE(offset: number, noAssert?: boolean): number; | ||
24 | + readInt8(offset: number, noAssert?: boolean): number; | ||
25 | + readInt16LE(offset: number, noAssert?: boolean): number; | ||
26 | + readInt16BE(offset: number, noAssert?: boolean): number; | ||
27 | + readInt32LE(offset: number, noAssert?: boolean): number; | ||
28 | + readInt32BE(offset: number, noAssert?: boolean): number; | ||
29 | + readFloatLE(offset: number, noAssert?: boolean): number; | ||
30 | + readFloatBE(offset: number, noAssert?: boolean): number; | ||
31 | + readDoubleLE(offset: number, noAssert?: boolean): number; | ||
32 | + readDoubleBE(offset: number, noAssert?: boolean): number; | ||
33 | + swap16(): Buffer; | ||
34 | + swap32(): Buffer; | ||
35 | + swap64(): Buffer; | ||
36 | + writeUInt8(value: number, offset: number, noAssert?: boolean): number; | ||
37 | + writeUInt16LE(value: number, offset: number, noAssert?: boolean): number; | ||
38 | + writeUInt16BE(value: number, offset: number, noAssert?: boolean): number; | ||
39 | + writeUInt32LE(value: number, offset: number, noAssert?: boolean): number; | ||
40 | + writeUInt32BE(value: number, offset: number, noAssert?: boolean): number; | ||
41 | + writeInt8(value: number, offset: number, noAssert?: boolean): number; | ||
42 | + writeInt16LE(value: number, offset: number, noAssert?: boolean): number; | ||
43 | + writeInt16BE(value: number, offset: number, noAssert?: boolean): number; | ||
44 | + writeInt32LE(value: number, offset: number, noAssert?: boolean): number; | ||
45 | + writeInt32BE(value: number, offset: number, noAssert?: boolean): number; | ||
46 | + writeFloatLE(value: number, offset: number, noAssert?: boolean): number; | ||
47 | + writeFloatBE(value: number, offset: number, noAssert?: boolean): number; | ||
48 | + writeDoubleLE(value: number, offset: number, noAssert?: boolean): number; | ||
49 | + writeDoubleBE(value: number, offset: number, noAssert?: boolean): number; | ||
50 | + fill(value: any, offset?: number, end?: number): this; | ||
51 | + indexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; | ||
52 | + lastIndexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; | ||
53 | + includes(value: string | number | Buffer, byteOffset?: number, encoding?: string): boolean; | ||
54 | + | ||
55 | + /** | ||
56 | + * Allocates a new buffer containing the given {str}. | ||
57 | + * | ||
58 | + * @param str String to store in buffer. | ||
59 | + * @param encoding encoding to use, optional. Default is 'utf8' | ||
60 | + */ | ||
61 | + constructor (str: string, encoding?: string); | ||
62 | + /** | ||
63 | + * Allocates a new buffer of {size} octets. | ||
64 | + * | ||
65 | + * @param size count of octets to allocate. | ||
66 | + */ | ||
67 | + constructor (size: number); | ||
68 | + /** | ||
69 | + * Allocates a new buffer containing the given {array} of octets. | ||
70 | + * | ||
71 | + * @param array The octets to store. | ||
72 | + */ | ||
73 | + constructor (array: Uint8Array); | ||
74 | + /** | ||
75 | + * Produces a Buffer backed by the same allocated memory as | ||
76 | + * the given {ArrayBuffer}. | ||
77 | + * | ||
78 | + * | ||
79 | + * @param arrayBuffer The ArrayBuffer with which to share memory. | ||
80 | + */ | ||
81 | + constructor (arrayBuffer: ArrayBuffer); | ||
82 | + /** | ||
83 | + * Allocates a new buffer containing the given {array} of octets. | ||
84 | + * | ||
85 | + * @param array The octets to store. | ||
86 | + */ | ||
87 | + constructor (array: any[]); | ||
88 | + /** | ||
89 | + * Copies the passed {buffer} data onto a new {Buffer} instance. | ||
90 | + * | ||
91 | + * @param buffer The buffer to copy. | ||
92 | + */ | ||
93 | + constructor (buffer: Buffer); | ||
94 | + prototype: Buffer; | ||
95 | + /** | ||
96 | + * Allocates a new Buffer using an {array} of octets. | ||
97 | + * | ||
98 | + * @param array | ||
99 | + */ | ||
100 | + static from(array: any[]): Buffer; | ||
101 | + /** | ||
102 | + * When passed a reference to the .buffer property of a TypedArray instance, | ||
103 | + * the newly created Buffer will share the same allocated memory as the TypedArray. | ||
104 | + * The optional {byteOffset} and {length} arguments specify a memory range | ||
105 | + * within the {arrayBuffer} that will be shared by the Buffer. | ||
106 | + * | ||
107 | + * @param arrayBuffer The .buffer property of a TypedArray or a new ArrayBuffer() | ||
108 | + * @param byteOffset | ||
109 | + * @param length | ||
110 | + */ | ||
111 | + static from(arrayBuffer: ArrayBuffer, byteOffset?: number, length?: number): Buffer; | ||
112 | + /** | ||
113 | + * Copies the passed {buffer} data onto a new Buffer instance. | ||
114 | + * | ||
115 | + * @param buffer | ||
116 | + */ | ||
117 | + static from(buffer: Buffer): Buffer; | ||
118 | + /** | ||
119 | + * Creates a new Buffer containing the given JavaScript string {str}. | ||
120 | + * If provided, the {encoding} parameter identifies the character encoding. | ||
121 | + * If not provided, {encoding} defaults to 'utf8'. | ||
122 | + * | ||
123 | + * @param str | ||
124 | + */ | ||
125 | + static from(str: string, encoding?: string): Buffer; | ||
126 | + /** | ||
127 | + * Returns true if {obj} is a Buffer | ||
128 | + * | ||
129 | + * @param obj object to test. | ||
130 | + */ | ||
131 | + static isBuffer(obj: any): obj is Buffer; | ||
132 | + /** | ||
133 | + * Returns true if {encoding} is a valid encoding argument. | ||
134 | + * Valid string encodings in Node 0.12: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex' | ||
135 | + * | ||
136 | + * @param encoding string to test. | ||
137 | + */ | ||
138 | + static isEncoding(encoding: string): boolean; | ||
139 | + /** | ||
140 | + * Gives the actual byte length of a string. encoding defaults to 'utf8'. | ||
141 | + * This is not the same as String.prototype.length since that returns the number of characters in a string. | ||
142 | + * | ||
143 | + * @param string string to test. | ||
144 | + * @param encoding encoding used to evaluate (defaults to 'utf8') | ||
145 | + */ | ||
146 | + static byteLength(string: string, encoding?: string): number; | ||
147 | + /** | ||
148 | + * Returns a buffer which is the result of concatenating all the buffers in the list together. | ||
149 | + * | ||
150 | + * If the list has no items, or if the totalLength is 0, then it returns a zero-length buffer. | ||
151 | + * If the list has exactly one item, then the first item of the list is returned. | ||
152 | + * If the list has more than one item, then a new Buffer is created. | ||
153 | + * | ||
154 | + * @param list An array of Buffer objects to concatenate | ||
155 | + * @param totalLength Total length of the buffers when concatenated. | ||
156 | + * If totalLength is not provided, it is read from the buffers in the list. However, this adds an additional loop to the function, so it is faster to provide the length explicitly. | ||
157 | + */ | ||
158 | + static concat(list: Buffer[], totalLength?: number): Buffer; | ||
159 | + /** | ||
160 | + * The same as buf1.compare(buf2). | ||
161 | + */ | ||
162 | + static compare(buf1: Buffer, buf2: Buffer): number; | ||
163 | + /** | ||
164 | + * Allocates a new buffer of {size} octets. | ||
165 | + * | ||
166 | + * @param size count of octets to allocate. | ||
167 | + * @param fill if specified, buffer will be initialized by calling buf.fill(fill). | ||
168 | + * If parameter is omitted, buffer will be filled with zeros. | ||
169 | + * @param encoding encoding used for call to buf.fill while initalizing | ||
170 | + */ | ||
171 | + static alloc(size: number, fill?: string | Buffer | number, encoding?: string): Buffer; | ||
172 | + /** | ||
173 | + * Allocates a new buffer of {size} octets, leaving memory not initialized, so the contents | ||
174 | + * of the newly created Buffer are unknown and may contain sensitive data. | ||
175 | + * | ||
176 | + * @param size count of octets to allocate | ||
177 | + */ | ||
178 | + static allocUnsafe(size: number): Buffer; | ||
179 | + /** | ||
180 | + * Allocates a new non-pooled buffer of {size} octets, leaving memory not initialized, so the contents | ||
181 | + * of the newly created Buffer are unknown and may contain sensitive data. | ||
182 | + * | ||
183 | + * @param size count of octets to allocate | ||
184 | + */ | ||
185 | + static allocUnsafeSlow(size: number): Buffer; | ||
186 | + } | ||
187 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* eslint-disable node/no-deprecated-api */ | ||
2 | +var buffer = require('buffer') | ||
3 | +var Buffer = buffer.Buffer | ||
4 | + | ||
5 | +// alternative to using Object.keys for old browsers | ||
6 | +function copyProps (src, dst) { | ||
7 | + for (var key in src) { | ||
8 | + dst[key] = src[key] | ||
9 | + } | ||
10 | +} | ||
11 | +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { | ||
12 | + module.exports = buffer | ||
13 | +} else { | ||
14 | + // Copy properties from require('buffer') | ||
15 | + copyProps(buffer, exports) | ||
16 | + exports.Buffer = SafeBuffer | ||
17 | +} | ||
18 | + | ||
19 | +function SafeBuffer (arg, encodingOrOffset, length) { | ||
20 | + return Buffer(arg, encodingOrOffset, length) | ||
21 | +} | ||
22 | + | ||
23 | +SafeBuffer.prototype = Object.create(Buffer.prototype) | ||
24 | + | ||
25 | +// Copy static methods from Buffer | ||
26 | +copyProps(Buffer, SafeBuffer) | ||
27 | + | ||
28 | +SafeBuffer.from = function (arg, encodingOrOffset, length) { | ||
29 | + if (typeof arg === 'number') { | ||
30 | + throw new TypeError('Argument must not be a number') | ||
31 | + } | ||
32 | + return Buffer(arg, encodingOrOffset, length) | ||
33 | +} | ||
34 | + | ||
35 | +SafeBuffer.alloc = function (size, fill, encoding) { | ||
36 | + if (typeof size !== 'number') { | ||
37 | + throw new TypeError('Argument must be a number') | ||
38 | + } | ||
39 | + var buf = Buffer(size) | ||
40 | + if (fill !== undefined) { | ||
41 | + if (typeof encoding === 'string') { | ||
42 | + buf.fill(fill, encoding) | ||
43 | + } else { | ||
44 | + buf.fill(fill) | ||
45 | + } | ||
46 | + } else { | ||
47 | + buf.fill(0) | ||
48 | + } | ||
49 | + return buf | ||
50 | +} | ||
51 | + | ||
52 | +SafeBuffer.allocUnsafe = function (size) { | ||
53 | + if (typeof size !== 'number') { | ||
54 | + throw new TypeError('Argument must be a number') | ||
55 | + } | ||
56 | + return Buffer(size) | ||
57 | +} | ||
58 | + | ||
59 | +SafeBuffer.allocUnsafeSlow = function (size) { | ||
60 | + if (typeof size !== 'number') { | ||
61 | + throw new TypeError('Argument must be a number') | ||
62 | + } | ||
63 | + return buffer.SlowBuffer(size) | ||
64 | +} |
1 | +{ | ||
2 | + "_from": "safe-buffer@5.2.0", | ||
3 | + "_id": "safe-buffer@5.2.0", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", | ||
6 | + "_location": "/express-session/safe-buffer", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "version", | ||
10 | + "registry": true, | ||
11 | + "raw": "safe-buffer@5.2.0", | ||
12 | + "name": "safe-buffer", | ||
13 | + "escapedName": "safe-buffer", | ||
14 | + "rawSpec": "5.2.0", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "5.2.0" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/express-session" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", | ||
22 | + "_shasum": "b74daec49b1148f88c64b68d49b1e815c1f2f519", | ||
23 | + "_spec": "safe-buffer@5.2.0", | ||
24 | + "_where": "C:\\Users\\fheld\\Desktop\\khuhub\\mapmory\\Mapmory\\node_modules\\express-session", | ||
25 | + "author": { | ||
26 | + "name": "Feross Aboukhadijeh", | ||
27 | + "email": "feross@feross.org", | ||
28 | + "url": "http://feross.org" | ||
29 | + }, | ||
30 | + "bugs": { | ||
31 | + "url": "https://github.com/feross/safe-buffer/issues" | ||
32 | + }, | ||
33 | + "bundleDependencies": false, | ||
34 | + "deprecated": false, | ||
35 | + "description": "Safer Node.js Buffer API", | ||
36 | + "devDependencies": { | ||
37 | + "standard": "*", | ||
38 | + "tape": "^4.0.0" | ||
39 | + }, | ||
40 | + "homepage": "https://github.com/feross/safe-buffer", | ||
41 | + "keywords": [ | ||
42 | + "buffer", | ||
43 | + "buffer allocate", | ||
44 | + "node security", | ||
45 | + "safe", | ||
46 | + "safe-buffer", | ||
47 | + "security", | ||
48 | + "uninitialized" | ||
49 | + ], | ||
50 | + "license": "MIT", | ||
51 | + "main": "index.js", | ||
52 | + "name": "safe-buffer", | ||
53 | + "repository": { | ||
54 | + "type": "git", | ||
55 | + "url": "git://github.com/feross/safe-buffer.git" | ||
56 | + }, | ||
57 | + "scripts": { | ||
58 | + "test": "standard && tape test/*.js" | ||
59 | + }, | ||
60 | + "types": "index.d.ts", | ||
61 | + "version": "5.2.0" | ||
62 | +} |
1 | +{ | ||
2 | + "_from": "express-session", | ||
3 | + "_id": "express-session@1.17.1", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q==", | ||
6 | + "_location": "/express-session", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "tag", | ||
10 | + "registry": true, | ||
11 | + "raw": "express-session", | ||
12 | + "name": "express-session", | ||
13 | + "escapedName": "express-session", | ||
14 | + "rawSpec": "", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "latest" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "#USER", | ||
20 | + "/" | ||
21 | + ], | ||
22 | + "_resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.1.tgz", | ||
23 | + "_shasum": "36ecbc7034566d38c8509885c044d461c11bf357", | ||
24 | + "_spec": "express-session", | ||
25 | + "_where": "C:\\Users\\fheld\\Desktop\\khuhub\\mapmory\\Mapmory", | ||
26 | + "author": { | ||
27 | + "name": "TJ Holowaychuk", | ||
28 | + "email": "tj@vision-media.ca", | ||
29 | + "url": "http://tjholowaychuk.com" | ||
30 | + }, | ||
31 | + "bugs": { | ||
32 | + "url": "https://github.com/expressjs/session/issues" | ||
33 | + }, | ||
34 | + "bundleDependencies": false, | ||
35 | + "contributors": [ | ||
36 | + { | ||
37 | + "name": "Douglas Christopher Wilson", | ||
38 | + "email": "doug@somethingdoug.com" | ||
39 | + }, | ||
40 | + { | ||
41 | + "name": "Joe Wagner", | ||
42 | + "email": "njwjs722@gmail.com" | ||
43 | + } | ||
44 | + ], | ||
45 | + "dependencies": { | ||
46 | + "cookie": "0.4.0", | ||
47 | + "cookie-signature": "1.0.6", | ||
48 | + "debug": "2.6.9", | ||
49 | + "depd": "~2.0.0", | ||
50 | + "on-headers": "~1.0.2", | ||
51 | + "parseurl": "~1.3.3", | ||
52 | + "safe-buffer": "5.2.0", | ||
53 | + "uid-safe": "~2.1.5" | ||
54 | + }, | ||
55 | + "deprecated": false, | ||
56 | + "description": "Simple session middleware for Express", | ||
57 | + "devDependencies": { | ||
58 | + "after": "0.8.2", | ||
59 | + "cookie-parser": "1.4.5", | ||
60 | + "eslint": "3.19.0", | ||
61 | + "eslint-plugin-markdown": "1.0.2", | ||
62 | + "express": "4.17.1", | ||
63 | + "mocha": "7.1.1", | ||
64 | + "nyc": "15.0.1", | ||
65 | + "supertest": "4.0.2" | ||
66 | + }, | ||
67 | + "engines": { | ||
68 | + "node": ">= 0.8.0" | ||
69 | + }, | ||
70 | + "files": [ | ||
71 | + "session/", | ||
72 | + "HISTORY.md", | ||
73 | + "LICENSE", | ||
74 | + "index.js" | ||
75 | + ], | ||
76 | + "homepage": "https://github.com/expressjs/session#readme", | ||
77 | + "license": "MIT", | ||
78 | + "name": "express-session", | ||
79 | + "repository": { | ||
80 | + "type": "git", | ||
81 | + "url": "git+https://github.com/expressjs/session.git" | ||
82 | + }, | ||
83 | + "scripts": { | ||
84 | + "lint": "eslint --plugin markdown --ext js,md . && node ./scripts/lint-readme.js", | ||
85 | + "test": "mocha --require test/support/env --check-leaks --bail --no-exit --reporter spec test/", | ||
86 | + "test-cov": "nyc npm test", | ||
87 | + "test-travis": "nyc npm test -- --no-exit", | ||
88 | + "version": "node scripts/version-history.js && git add HISTORY.md" | ||
89 | + }, | ||
90 | + "version": "1.17.1" | ||
91 | +} |
1 | +/*! | ||
2 | + * Connect - session - Cookie | ||
3 | + * Copyright(c) 2010 Sencha Inc. | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +'use strict'; | ||
9 | + | ||
10 | +/** | ||
11 | + * Module dependencies. | ||
12 | + */ | ||
13 | + | ||
14 | +var cookie = require('cookie') | ||
15 | +var deprecate = require('depd')('express-session') | ||
16 | + | ||
17 | +/** | ||
18 | + * Initialize a new `Cookie` with the given `options`. | ||
19 | + * | ||
20 | + * @param {IncomingMessage} req | ||
21 | + * @param {Object} options | ||
22 | + * @api private | ||
23 | + */ | ||
24 | + | ||
25 | +var Cookie = module.exports = function Cookie(options) { | ||
26 | + this.path = '/'; | ||
27 | + this.maxAge = null; | ||
28 | + this.httpOnly = true; | ||
29 | + | ||
30 | + if (options) { | ||
31 | + if (typeof options !== 'object') { | ||
32 | + throw new TypeError('argument options must be a object') | ||
33 | + } | ||
34 | + | ||
35 | + for (var key in options) { | ||
36 | + if (key !== 'data') { | ||
37 | + this[key] = options[key] | ||
38 | + } | ||
39 | + } | ||
40 | + } | ||
41 | + | ||
42 | + if (this.originalMaxAge === undefined || this.originalMaxAge === null) { | ||
43 | + this.originalMaxAge = this.maxAge | ||
44 | + } | ||
45 | +}; | ||
46 | + | ||
47 | +/*! | ||
48 | + * Prototype. | ||
49 | + */ | ||
50 | + | ||
51 | +Cookie.prototype = { | ||
52 | + | ||
53 | + /** | ||
54 | + * Set expires `date`. | ||
55 | + * | ||
56 | + * @param {Date} date | ||
57 | + * @api public | ||
58 | + */ | ||
59 | + | ||
60 | + set expires(date) { | ||
61 | + this._expires = date; | ||
62 | + this.originalMaxAge = this.maxAge; | ||
63 | + }, | ||
64 | + | ||
65 | + /** | ||
66 | + * Get expires `date`. | ||
67 | + * | ||
68 | + * @return {Date} | ||
69 | + * @api public | ||
70 | + */ | ||
71 | + | ||
72 | + get expires() { | ||
73 | + return this._expires; | ||
74 | + }, | ||
75 | + | ||
76 | + /** | ||
77 | + * Set expires via max-age in `ms`. | ||
78 | + * | ||
79 | + * @param {Number} ms | ||
80 | + * @api public | ||
81 | + */ | ||
82 | + | ||
83 | + set maxAge(ms) { | ||
84 | + if (ms && typeof ms !== 'number' && !(ms instanceof Date)) { | ||
85 | + throw new TypeError('maxAge must be a number or Date') | ||
86 | + } | ||
87 | + | ||
88 | + if (ms instanceof Date) { | ||
89 | + deprecate('maxAge as Date; pass number of milliseconds instead') | ||
90 | + } | ||
91 | + | ||
92 | + this.expires = typeof ms === 'number' | ||
93 | + ? new Date(Date.now() + ms) | ||
94 | + : ms; | ||
95 | + }, | ||
96 | + | ||
97 | + /** | ||
98 | + * Get expires max-age in `ms`. | ||
99 | + * | ||
100 | + * @return {Number} | ||
101 | + * @api public | ||
102 | + */ | ||
103 | + | ||
104 | + get maxAge() { | ||
105 | + return this.expires instanceof Date | ||
106 | + ? this.expires.valueOf() - Date.now() | ||
107 | + : this.expires; | ||
108 | + }, | ||
109 | + | ||
110 | + /** | ||
111 | + * Return cookie data object. | ||
112 | + * | ||
113 | + * @return {Object} | ||
114 | + * @api private | ||
115 | + */ | ||
116 | + | ||
117 | + get data() { | ||
118 | + return { | ||
119 | + originalMaxAge: this.originalMaxAge | ||
120 | + , expires: this._expires | ||
121 | + , secure: this.secure | ||
122 | + , httpOnly: this.httpOnly | ||
123 | + , domain: this.domain | ||
124 | + , path: this.path | ||
125 | + , sameSite: this.sameSite | ||
126 | + } | ||
127 | + }, | ||
128 | + | ||
129 | + /** | ||
130 | + * Return a serialized cookie string. | ||
131 | + * | ||
132 | + * @return {String} | ||
133 | + * @api public | ||
134 | + */ | ||
135 | + | ||
136 | + serialize: function(name, val){ | ||
137 | + return cookie.serialize(name, val, this.data); | ||
138 | + }, | ||
139 | + | ||
140 | + /** | ||
141 | + * Return JSON representation of this cookie. | ||
142 | + * | ||
143 | + * @return {Object} | ||
144 | + * @api private | ||
145 | + */ | ||
146 | + | ||
147 | + toJSON: function(){ | ||
148 | + return this.data; | ||
149 | + } | ||
150 | +}; |
1 | +/*! | ||
2 | + * express-session | ||
3 | + * Copyright(c) 2010 Sencha Inc. | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * Copyright(c) 2015 Douglas Christopher Wilson | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +'use strict'; | ||
10 | + | ||
11 | +/** | ||
12 | + * Module dependencies. | ||
13 | + * @private | ||
14 | + */ | ||
15 | + | ||
16 | +var Store = require('./store') | ||
17 | +var util = require('util') | ||
18 | + | ||
19 | +/** | ||
20 | + * Shim setImmediate for node.js < 0.10 | ||
21 | + * @private | ||
22 | + */ | ||
23 | + | ||
24 | +/* istanbul ignore next */ | ||
25 | +var defer = typeof setImmediate === 'function' | ||
26 | + ? setImmediate | ||
27 | + : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) } | ||
28 | + | ||
29 | +/** | ||
30 | + * Module exports. | ||
31 | + */ | ||
32 | + | ||
33 | +module.exports = MemoryStore | ||
34 | + | ||
35 | +/** | ||
36 | + * A session store in memory. | ||
37 | + * @public | ||
38 | + */ | ||
39 | + | ||
40 | +function MemoryStore() { | ||
41 | + Store.call(this) | ||
42 | + this.sessions = Object.create(null) | ||
43 | +} | ||
44 | + | ||
45 | +/** | ||
46 | + * Inherit from Store. | ||
47 | + */ | ||
48 | + | ||
49 | +util.inherits(MemoryStore, Store) | ||
50 | + | ||
51 | +/** | ||
52 | + * Get all active sessions. | ||
53 | + * | ||
54 | + * @param {function} callback | ||
55 | + * @public | ||
56 | + */ | ||
57 | + | ||
58 | +MemoryStore.prototype.all = function all(callback) { | ||
59 | + var sessionIds = Object.keys(this.sessions) | ||
60 | + var sessions = Object.create(null) | ||
61 | + | ||
62 | + for (var i = 0; i < sessionIds.length; i++) { | ||
63 | + var sessionId = sessionIds[i] | ||
64 | + var session = getSession.call(this, sessionId) | ||
65 | + | ||
66 | + if (session) { | ||
67 | + sessions[sessionId] = session; | ||
68 | + } | ||
69 | + } | ||
70 | + | ||
71 | + callback && defer(callback, null, sessions) | ||
72 | +} | ||
73 | + | ||
74 | +/** | ||
75 | + * Clear all sessions. | ||
76 | + * | ||
77 | + * @param {function} callback | ||
78 | + * @public | ||
79 | + */ | ||
80 | + | ||
81 | +MemoryStore.prototype.clear = function clear(callback) { | ||
82 | + this.sessions = Object.create(null) | ||
83 | + callback && defer(callback) | ||
84 | +} | ||
85 | + | ||
86 | +/** | ||
87 | + * Destroy the session associated with the given session ID. | ||
88 | + * | ||
89 | + * @param {string} sessionId | ||
90 | + * @public | ||
91 | + */ | ||
92 | + | ||
93 | +MemoryStore.prototype.destroy = function destroy(sessionId, callback) { | ||
94 | + delete this.sessions[sessionId] | ||
95 | + callback && defer(callback) | ||
96 | +} | ||
97 | + | ||
98 | +/** | ||
99 | + * Fetch session by the given session ID. | ||
100 | + * | ||
101 | + * @param {string} sessionId | ||
102 | + * @param {function} callback | ||
103 | + * @public | ||
104 | + */ | ||
105 | + | ||
106 | +MemoryStore.prototype.get = function get(sessionId, callback) { | ||
107 | + defer(callback, null, getSession.call(this, sessionId)) | ||
108 | +} | ||
109 | + | ||
110 | +/** | ||
111 | + * Commit the given session associated with the given sessionId to the store. | ||
112 | + * | ||
113 | + * @param {string} sessionId | ||
114 | + * @param {object} session | ||
115 | + * @param {function} callback | ||
116 | + * @public | ||
117 | + */ | ||
118 | + | ||
119 | +MemoryStore.prototype.set = function set(sessionId, session, callback) { | ||
120 | + this.sessions[sessionId] = JSON.stringify(session) | ||
121 | + callback && defer(callback) | ||
122 | +} | ||
123 | + | ||
124 | +/** | ||
125 | + * Get number of active sessions. | ||
126 | + * | ||
127 | + * @param {function} callback | ||
128 | + * @public | ||
129 | + */ | ||
130 | + | ||
131 | +MemoryStore.prototype.length = function length(callback) { | ||
132 | + this.all(function (err, sessions) { | ||
133 | + if (err) return callback(err) | ||
134 | + callback(null, Object.keys(sessions).length) | ||
135 | + }) | ||
136 | +} | ||
137 | + | ||
138 | +/** | ||
139 | + * Touch the given session object associated with the given session ID. | ||
140 | + * | ||
141 | + * @param {string} sessionId | ||
142 | + * @param {object} session | ||
143 | + * @param {function} callback | ||
144 | + * @public | ||
145 | + */ | ||
146 | + | ||
147 | +MemoryStore.prototype.touch = function touch(sessionId, session, callback) { | ||
148 | + var currentSession = getSession.call(this, sessionId) | ||
149 | + | ||
150 | + if (currentSession) { | ||
151 | + // update expiration | ||
152 | + currentSession.cookie = session.cookie | ||
153 | + this.sessions[sessionId] = JSON.stringify(currentSession) | ||
154 | + } | ||
155 | + | ||
156 | + callback && defer(callback) | ||
157 | +} | ||
158 | + | ||
159 | +/** | ||
160 | + * Get session from the store. | ||
161 | + * @private | ||
162 | + */ | ||
163 | + | ||
164 | +function getSession(sessionId) { | ||
165 | + var sess = this.sessions[sessionId] | ||
166 | + | ||
167 | + if (!sess) { | ||
168 | + return | ||
169 | + } | ||
170 | + | ||
171 | + // parse | ||
172 | + sess = JSON.parse(sess) | ||
173 | + | ||
174 | + if (sess.cookie) { | ||
175 | + var expires = typeof sess.cookie.expires === 'string' | ||
176 | + ? new Date(sess.cookie.expires) | ||
177 | + : sess.cookie.expires | ||
178 | + | ||
179 | + // destroy expired session | ||
180 | + if (expires && expires <= Date.now()) { | ||
181 | + delete this.sessions[sessionId] | ||
182 | + return | ||
183 | + } | ||
184 | + } | ||
185 | + | ||
186 | + return sess | ||
187 | +} |
1 | +/*! | ||
2 | + * Connect - session - Session | ||
3 | + * Copyright(c) 2010 Sencha Inc. | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +'use strict'; | ||
9 | + | ||
10 | +/** | ||
11 | + * Expose Session. | ||
12 | + */ | ||
13 | + | ||
14 | +module.exports = Session; | ||
15 | + | ||
16 | +/** | ||
17 | + * Create a new `Session` with the given request and `data`. | ||
18 | + * | ||
19 | + * @param {IncomingRequest} req | ||
20 | + * @param {Object} data | ||
21 | + * @api private | ||
22 | + */ | ||
23 | + | ||
24 | +function Session(req, data) { | ||
25 | + Object.defineProperty(this, 'req', { value: req }); | ||
26 | + Object.defineProperty(this, 'id', { value: req.sessionID }); | ||
27 | + | ||
28 | + if (typeof data === 'object' && data !== null) { | ||
29 | + // merge data into this, ignoring prototype properties | ||
30 | + for (var prop in data) { | ||
31 | + if (!(prop in this)) { | ||
32 | + this[prop] = data[prop] | ||
33 | + } | ||
34 | + } | ||
35 | + } | ||
36 | +} | ||
37 | + | ||
38 | +/** | ||
39 | + * Update reset `.cookie.maxAge` to prevent | ||
40 | + * the cookie from expiring when the | ||
41 | + * session is still active. | ||
42 | + * | ||
43 | + * @return {Session} for chaining | ||
44 | + * @api public | ||
45 | + */ | ||
46 | + | ||
47 | +defineMethod(Session.prototype, 'touch', function touch() { | ||
48 | + return this.resetMaxAge(); | ||
49 | +}); | ||
50 | + | ||
51 | +/** | ||
52 | + * Reset `.maxAge` to `.originalMaxAge`. | ||
53 | + * | ||
54 | + * @return {Session} for chaining | ||
55 | + * @api public | ||
56 | + */ | ||
57 | + | ||
58 | +defineMethod(Session.prototype, 'resetMaxAge', function resetMaxAge() { | ||
59 | + this.cookie.maxAge = this.cookie.originalMaxAge; | ||
60 | + return this; | ||
61 | +}); | ||
62 | + | ||
63 | +/** | ||
64 | + * Save the session data with optional callback `fn(err)`. | ||
65 | + * | ||
66 | + * @param {Function} fn | ||
67 | + * @return {Session} for chaining | ||
68 | + * @api public | ||
69 | + */ | ||
70 | + | ||
71 | +defineMethod(Session.prototype, 'save', function save(fn) { | ||
72 | + this.req.sessionStore.set(this.id, this, fn || function(){}); | ||
73 | + return this; | ||
74 | +}); | ||
75 | + | ||
76 | +/** | ||
77 | + * Re-loads the session data _without_ altering | ||
78 | + * the maxAge properties. Invokes the callback `fn(err)`, | ||
79 | + * after which time if no exception has occurred the | ||
80 | + * `req.session` property will be a new `Session` object, | ||
81 | + * although representing the same session. | ||
82 | + * | ||
83 | + * @param {Function} fn | ||
84 | + * @return {Session} for chaining | ||
85 | + * @api public | ||
86 | + */ | ||
87 | + | ||
88 | +defineMethod(Session.prototype, 'reload', function reload(fn) { | ||
89 | + var req = this.req | ||
90 | + var store = this.req.sessionStore | ||
91 | + | ||
92 | + store.get(this.id, function(err, sess){ | ||
93 | + if (err) return fn(err); | ||
94 | + if (!sess) return fn(new Error('failed to load session')); | ||
95 | + store.createSession(req, sess); | ||
96 | + fn(); | ||
97 | + }); | ||
98 | + return this; | ||
99 | +}); | ||
100 | + | ||
101 | +/** | ||
102 | + * Destroy `this` session. | ||
103 | + * | ||
104 | + * @param {Function} fn | ||
105 | + * @return {Session} for chaining | ||
106 | + * @api public | ||
107 | + */ | ||
108 | + | ||
109 | +defineMethod(Session.prototype, 'destroy', function destroy(fn) { | ||
110 | + delete this.req.session; | ||
111 | + this.req.sessionStore.destroy(this.id, fn); | ||
112 | + return this; | ||
113 | +}); | ||
114 | + | ||
115 | +/** | ||
116 | + * Regenerate this request's session. | ||
117 | + * | ||
118 | + * @param {Function} fn | ||
119 | + * @return {Session} for chaining | ||
120 | + * @api public | ||
121 | + */ | ||
122 | + | ||
123 | +defineMethod(Session.prototype, 'regenerate', function regenerate(fn) { | ||
124 | + this.req.sessionStore.regenerate(this.req, fn); | ||
125 | + return this; | ||
126 | +}); | ||
127 | + | ||
128 | +/** | ||
129 | + * Helper function for creating a method on a prototype. | ||
130 | + * | ||
131 | + * @param {Object} obj | ||
132 | + * @param {String} name | ||
133 | + * @param {Function} fn | ||
134 | + * @private | ||
135 | + */ | ||
136 | +function defineMethod(obj, name, fn) { | ||
137 | + Object.defineProperty(obj, name, { | ||
138 | + configurable: true, | ||
139 | + enumerable: false, | ||
140 | + value: fn, | ||
141 | + writable: true | ||
142 | + }); | ||
143 | +}; |
1 | +/*! | ||
2 | + * Connect - session - Store | ||
3 | + * Copyright(c) 2010 Sencha Inc. | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +'use strict'; | ||
9 | + | ||
10 | +/** | ||
11 | + * Module dependencies. | ||
12 | + * @private | ||
13 | + */ | ||
14 | + | ||
15 | +var Cookie = require('./cookie') | ||
16 | +var EventEmitter = require('events').EventEmitter | ||
17 | +var Session = require('./session') | ||
18 | +var util = require('util') | ||
19 | + | ||
20 | +/** | ||
21 | + * Module exports. | ||
22 | + * @public | ||
23 | + */ | ||
24 | + | ||
25 | +module.exports = Store | ||
26 | + | ||
27 | +/** | ||
28 | + * Abstract base class for session stores. | ||
29 | + * @public | ||
30 | + */ | ||
31 | + | ||
32 | +function Store () { | ||
33 | + EventEmitter.call(this) | ||
34 | +} | ||
35 | + | ||
36 | +/** | ||
37 | + * Inherit from EventEmitter. | ||
38 | + */ | ||
39 | + | ||
40 | +util.inherits(Store, EventEmitter) | ||
41 | + | ||
42 | +/** | ||
43 | + * Re-generate the given requests's session. | ||
44 | + * | ||
45 | + * @param {IncomingRequest} req | ||
46 | + * @return {Function} fn | ||
47 | + * @api public | ||
48 | + */ | ||
49 | + | ||
50 | +Store.prototype.regenerate = function(req, fn){ | ||
51 | + var self = this; | ||
52 | + this.destroy(req.sessionID, function(err){ | ||
53 | + self.generate(req); | ||
54 | + fn(err); | ||
55 | + }); | ||
56 | +}; | ||
57 | + | ||
58 | +/** | ||
59 | + * Load a `Session` instance via the given `sid` | ||
60 | + * and invoke the callback `fn(err, sess)`. | ||
61 | + * | ||
62 | + * @param {String} sid | ||
63 | + * @param {Function} fn | ||
64 | + * @api public | ||
65 | + */ | ||
66 | + | ||
67 | +Store.prototype.load = function(sid, fn){ | ||
68 | + var self = this; | ||
69 | + this.get(sid, function(err, sess){ | ||
70 | + if (err) return fn(err); | ||
71 | + if (!sess) return fn(); | ||
72 | + var req = { sessionID: sid, sessionStore: self }; | ||
73 | + fn(null, self.createSession(req, sess)) | ||
74 | + }); | ||
75 | +}; | ||
76 | + | ||
77 | +/** | ||
78 | + * Create session from JSON `sess` data. | ||
79 | + * | ||
80 | + * @param {IncomingRequest} req | ||
81 | + * @param {Object} sess | ||
82 | + * @return {Session} | ||
83 | + * @api private | ||
84 | + */ | ||
85 | + | ||
86 | +Store.prototype.createSession = function(req, sess){ | ||
87 | + var expires = sess.cookie.expires | ||
88 | + var originalMaxAge = sess.cookie.originalMaxAge | ||
89 | + | ||
90 | + sess.cookie = new Cookie(sess.cookie); | ||
91 | + | ||
92 | + if (typeof expires === 'string') { | ||
93 | + // convert expires to a Date object | ||
94 | + sess.cookie.expires = new Date(expires) | ||
95 | + } | ||
96 | + | ||
97 | + // keep originalMaxAge intact | ||
98 | + sess.cookie.originalMaxAge = originalMaxAge | ||
99 | + | ||
100 | + req.session = new Session(req, sess); | ||
101 | + return req.session; | ||
102 | +}; |
Mapmory/node_modules/on-headers/HISTORY.md
0 → 100644
1 | +1.0.2 / 2019-02-21 | ||
2 | +================== | ||
3 | + | ||
4 | + * Fix `res.writeHead` patch missing return value | ||
5 | + | ||
6 | +1.0.1 / 2015-09-29 | ||
7 | +================== | ||
8 | + | ||
9 | + * perf: enable strict mode | ||
10 | + | ||
11 | +1.0.0 / 2014-08-10 | ||
12 | +================== | ||
13 | + | ||
14 | + * Honor `res.statusCode` change in `listener` | ||
15 | + * Move to `jshttp` organization | ||
16 | + * Prevent `arguments`-related de-opt | ||
17 | + | ||
18 | +0.0.0 / 2014-05-13 | ||
19 | +================== | ||
20 | + | ||
21 | + * Initial implementation |
Mapmory/node_modules/on-headers/LICENSE
0 → 100644
1 | +(The MIT License) | ||
2 | + | ||
3 | +Copyright (c) 2014 Douglas Christopher Wilson | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining | ||
6 | +a copy of this software and associated documentation files (the | ||
7 | +'Software'), to deal in the Software without restriction, including | ||
8 | +without limitation the rights to use, copy, modify, merge, publish, | ||
9 | +distribute, sublicense, and/or sell copies of the Software, and to | ||
10 | +permit persons to whom the Software is furnished to do so, subject to | ||
11 | +the following conditions: | ||
12 | + | ||
13 | +The above copyright notice and this permission notice shall be | ||
14 | +included in all copies or substantial portions of the Software. | ||
15 | + | ||
16 | +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, | ||
17 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
18 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
19 | +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
20 | +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
21 | +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
22 | +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
Mapmory/node_modules/on-headers/README.md
0 → 100644
1 | +# on-headers | ||
2 | + | ||
3 | +[![NPM Version][npm-version-image]][npm-url] | ||
4 | +[![NPM Downloads][npm-downloads-image]][npm-url] | ||
5 | +[![Node.js Version][node-version-image]][node-version-url] | ||
6 | +[![Build Status][travis-image]][travis-url] | ||
7 | +[![Test Coverage][coveralls-image]][coveralls-url] | ||
8 | + | ||
9 | +Execute a listener when a response is about to write headers. | ||
10 | + | ||
11 | +## Installation | ||
12 | + | ||
13 | +This is a [Node.js](https://nodejs.org/en/) module available through the | ||
14 | +[npm registry](https://www.npmjs.com/). Installation is done using the | ||
15 | +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): | ||
16 | + | ||
17 | +```sh | ||
18 | +$ npm install on-headers | ||
19 | +``` | ||
20 | + | ||
21 | +## API | ||
22 | + | ||
23 | +<!-- eslint-disable no-unused-vars --> | ||
24 | + | ||
25 | +```js | ||
26 | +var onHeaders = require('on-headers') | ||
27 | +``` | ||
28 | + | ||
29 | +### onHeaders(res, listener) | ||
30 | + | ||
31 | +This will add the listener `listener` to fire when headers are emitted for `res`. | ||
32 | +The listener is passed the `response` object as it's context (`this`). Headers are | ||
33 | +considered to be emitted only once, right before they are sent to the client. | ||
34 | + | ||
35 | +When this is called multiple times on the same `res`, the `listener`s are fired | ||
36 | +in the reverse order they were added. | ||
37 | + | ||
38 | +## Examples | ||
39 | + | ||
40 | +```js | ||
41 | +var http = require('http') | ||
42 | +var onHeaders = require('on-headers') | ||
43 | + | ||
44 | +http | ||
45 | + .createServer(onRequest) | ||
46 | + .listen(3000) | ||
47 | + | ||
48 | +function addPoweredBy () { | ||
49 | + // set if not set by end of request | ||
50 | + if (!this.getHeader('X-Powered-By')) { | ||
51 | + this.setHeader('X-Powered-By', 'Node.js') | ||
52 | + } | ||
53 | +} | ||
54 | + | ||
55 | +function onRequest (req, res) { | ||
56 | + onHeaders(res, addPoweredBy) | ||
57 | + | ||
58 | + res.setHeader('Content-Type', 'text/plain') | ||
59 | + res.end('hello!') | ||
60 | +} | ||
61 | +``` | ||
62 | + | ||
63 | +## Testing | ||
64 | + | ||
65 | +```sh | ||
66 | +$ npm test | ||
67 | +``` | ||
68 | + | ||
69 | +## License | ||
70 | + | ||
71 | +[MIT](LICENSE) | ||
72 | + | ||
73 | +[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/on-headers/master | ||
74 | +[coveralls-url]: https://coveralls.io/r/jshttp/on-headers?branch=master | ||
75 | +[node-version-image]: https://badgen.net/npm/node/on-headers | ||
76 | +[node-version-url]: https://nodejs.org/en/download | ||
77 | +[npm-downloads-image]: https://badgen.net/npm/dm/on-headers | ||
78 | +[npm-url]: https://npmjs.org/package/on-headers | ||
79 | +[npm-version-image]: https://badgen.net/npm/v/on-headers | ||
80 | +[travis-image]: https://badgen.net/travis/jshttp/on-headers/master | ||
81 | +[travis-url]: https://travis-ci.org/jshttp/on-headers |
Mapmory/node_modules/on-headers/index.js
0 → 100644
1 | +/*! | ||
2 | + * on-headers | ||
3 | + * Copyright(c) 2014 Douglas Christopher Wilson | ||
4 | + * MIT Licensed | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict' | ||
8 | + | ||
9 | +/** | ||
10 | + * Module exports. | ||
11 | + * @public | ||
12 | + */ | ||
13 | + | ||
14 | +module.exports = onHeaders | ||
15 | + | ||
16 | +/** | ||
17 | + * Create a replacement writeHead method. | ||
18 | + * | ||
19 | + * @param {function} prevWriteHead | ||
20 | + * @param {function} listener | ||
21 | + * @private | ||
22 | + */ | ||
23 | + | ||
24 | +function createWriteHead (prevWriteHead, listener) { | ||
25 | + var fired = false | ||
26 | + | ||
27 | + // return function with core name and argument list | ||
28 | + return function writeHead (statusCode) { | ||
29 | + // set headers from arguments | ||
30 | + var args = setWriteHeadHeaders.apply(this, arguments) | ||
31 | + | ||
32 | + // fire listener | ||
33 | + if (!fired) { | ||
34 | + fired = true | ||
35 | + listener.call(this) | ||
36 | + | ||
37 | + // pass-along an updated status code | ||
38 | + if (typeof args[0] === 'number' && this.statusCode !== args[0]) { | ||
39 | + args[0] = this.statusCode | ||
40 | + args.length = 1 | ||
41 | + } | ||
42 | + } | ||
43 | + | ||
44 | + return prevWriteHead.apply(this, args) | ||
45 | + } | ||
46 | +} | ||
47 | + | ||
48 | +/** | ||
49 | + * Execute a listener when a response is about to write headers. | ||
50 | + * | ||
51 | + * @param {object} res | ||
52 | + * @return {function} listener | ||
53 | + * @public | ||
54 | + */ | ||
55 | + | ||
56 | +function onHeaders (res, listener) { | ||
57 | + if (!res) { | ||
58 | + throw new TypeError('argument res is required') | ||
59 | + } | ||
60 | + | ||
61 | + if (typeof listener !== 'function') { | ||
62 | + throw new TypeError('argument listener must be a function') | ||
63 | + } | ||
64 | + | ||
65 | + res.writeHead = createWriteHead(res.writeHead, listener) | ||
66 | +} | ||
67 | + | ||
68 | +/** | ||
69 | + * Set headers contained in array on the response object. | ||
70 | + * | ||
71 | + * @param {object} res | ||
72 | + * @param {array} headers | ||
73 | + * @private | ||
74 | + */ | ||
75 | + | ||
76 | +function setHeadersFromArray (res, headers) { | ||
77 | + for (var i = 0; i < headers.length; i++) { | ||
78 | + res.setHeader(headers[i][0], headers[i][1]) | ||
79 | + } | ||
80 | +} | ||
81 | + | ||
82 | +/** | ||
83 | + * Set headers contained in object on the response object. | ||
84 | + * | ||
85 | + * @param {object} res | ||
86 | + * @param {object} headers | ||
87 | + * @private | ||
88 | + */ | ||
89 | + | ||
90 | +function setHeadersFromObject (res, headers) { | ||
91 | + var keys = Object.keys(headers) | ||
92 | + for (var i = 0; i < keys.length; i++) { | ||
93 | + var k = keys[i] | ||
94 | + if (k) res.setHeader(k, headers[k]) | ||
95 | + } | ||
96 | +} | ||
97 | + | ||
98 | +/** | ||
99 | + * Set headers and other properties on the response object. | ||
100 | + * | ||
101 | + * @param {number} statusCode | ||
102 | + * @private | ||
103 | + */ | ||
104 | + | ||
105 | +function setWriteHeadHeaders (statusCode) { | ||
106 | + var length = arguments.length | ||
107 | + var headerIndex = length > 1 && typeof arguments[1] === 'string' | ||
108 | + ? 2 | ||
109 | + : 1 | ||
110 | + | ||
111 | + var headers = length >= headerIndex + 1 | ||
112 | + ? arguments[headerIndex] | ||
113 | + : undefined | ||
114 | + | ||
115 | + this.statusCode = statusCode | ||
116 | + | ||
117 | + if (Array.isArray(headers)) { | ||
118 | + // handle array case | ||
119 | + setHeadersFromArray(this, headers) | ||
120 | + } else if (headers) { | ||
121 | + // handle object case | ||
122 | + setHeadersFromObject(this, headers) | ||
123 | + } | ||
124 | + | ||
125 | + // copy leading arguments | ||
126 | + var args = new Array(Math.min(length, headerIndex)) | ||
127 | + for (var i = 0; i < args.length; i++) { | ||
128 | + args[i] = arguments[i] | ||
129 | + } | ||
130 | + | ||
131 | + return args | ||
132 | +} |
Mapmory/node_modules/on-headers/package.json
0 → 100644
1 | +{ | ||
2 | + "_from": "on-headers@~1.0.2", | ||
3 | + "_id": "on-headers@1.0.2", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", | ||
6 | + "_location": "/on-headers", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "range", | ||
10 | + "registry": true, | ||
11 | + "raw": "on-headers@~1.0.2", | ||
12 | + "name": "on-headers", | ||
13 | + "escapedName": "on-headers", | ||
14 | + "rawSpec": "~1.0.2", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "~1.0.2" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/express-session" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", | ||
22 | + "_shasum": "772b0ae6aaa525c399e489adfad90c403eb3c28f", | ||
23 | + "_spec": "on-headers@~1.0.2", | ||
24 | + "_where": "C:\\Users\\fheld\\Desktop\\khuhub\\mapmory\\Mapmory\\node_modules\\express-session", | ||
25 | + "author": { | ||
26 | + "name": "Douglas Christopher Wilson", | ||
27 | + "email": "doug@somethingdoug.com" | ||
28 | + }, | ||
29 | + "bugs": { | ||
30 | + "url": "https://github.com/jshttp/on-headers/issues" | ||
31 | + }, | ||
32 | + "bundleDependencies": false, | ||
33 | + "deprecated": false, | ||
34 | + "description": "Execute a listener when a response is about to write headers", | ||
35 | + "devDependencies": { | ||
36 | + "eslint": "5.14.1", | ||
37 | + "eslint-config-standard": "12.0.0", | ||
38 | + "eslint-plugin-import": "2.16.0", | ||
39 | + "eslint-plugin-markdown": "1.0.0", | ||
40 | + "eslint-plugin-node": "8.0.1", | ||
41 | + "eslint-plugin-promise": "4.0.1", | ||
42 | + "eslint-plugin-standard": "4.0.0", | ||
43 | + "istanbul": "0.4.5", | ||
44 | + "mocha": "6.0.1", | ||
45 | + "supertest": "3.4.2" | ||
46 | + }, | ||
47 | + "engines": { | ||
48 | + "node": ">= 0.8" | ||
49 | + }, | ||
50 | + "files": [ | ||
51 | + "LICENSE", | ||
52 | + "HISTORY.md", | ||
53 | + "README.md", | ||
54 | + "index.js" | ||
55 | + ], | ||
56 | + "homepage": "https://github.com/jshttp/on-headers#readme", | ||
57 | + "keywords": [ | ||
58 | + "event", | ||
59 | + "headers", | ||
60 | + "http", | ||
61 | + "onheaders" | ||
62 | + ], | ||
63 | + "license": "MIT", | ||
64 | + "name": "on-headers", | ||
65 | + "repository": { | ||
66 | + "type": "git", | ||
67 | + "url": "git+https://github.com/jshttp/on-headers.git" | ||
68 | + }, | ||
69 | + "scripts": { | ||
70 | + "lint": "eslint --plugin markdown --ext js,md .", | ||
71 | + "test": "mocha --reporter spec --bail --check-leaks test/", | ||
72 | + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", | ||
73 | + "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/", | ||
74 | + "version": "node scripts/version-history.js && git add HISTORY.md" | ||
75 | + }, | ||
76 | + "version": "1.0.2" | ||
77 | +} |
Mapmory/node_modules/random-bytes/HISTORY.md
0 → 100644
Mapmory/node_modules/random-bytes/LICENSE
0 → 100644
1 | +The MIT License (MIT) | ||
2 | + | ||
3 | +Copyright (c) 2016 Douglas Christopher Wilson <doug@somethingdoug.com> | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | +of this software and associated documentation files (the "Software"), to deal | ||
7 | +in the Software without restriction, including without limitation the rights | ||
8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | +copies of the Software, and to permit persons to whom the Software is | ||
10 | +furnished to do so, subject to the following conditions: | ||
11 | + | ||
12 | +The above copyright notice and this permission notice shall be included in | ||
13 | +all copies or substantial portions of the Software. | ||
14 | + | ||
15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | +THE SOFTWARE. |
Mapmory/node_modules/random-bytes/README.md
0 → 100644
1 | +# random-bytes | ||
2 | + | ||
3 | +[![NPM Version][npm-image]][npm-url] | ||
4 | +[![NPM Downloads][downloads-image]][downloads-url] | ||
5 | +[![Node.js Version][node-version-image]][node-version-url] | ||
6 | +[![Build Status][travis-image]][travis-url] | ||
7 | +[![Test Coverage][coveralls-image]][coveralls-url] | ||
8 | + | ||
9 | +Generate strong pseudo-random bytes. | ||
10 | + | ||
11 | +This module is a simple wrapper around the Node.js core `crypto.randomBytes` API, | ||
12 | +with the following additions: | ||
13 | + | ||
14 | + * A `Promise` interface for environments with promises. | ||
15 | + * For Node.js versions that do not wait for the PRNG to be seeded, this module | ||
16 | + will wait a bit. | ||
17 | + | ||
18 | +## Installation | ||
19 | + | ||
20 | +```sh | ||
21 | +$ npm install random-bytes | ||
22 | +``` | ||
23 | + | ||
24 | +## API | ||
25 | + | ||
26 | +```js | ||
27 | +var randomBytes = require('random-bytes') | ||
28 | +``` | ||
29 | + | ||
30 | +### randomBytes(size, callback) | ||
31 | + | ||
32 | +Generates strong pseudo-random bytes. The `size` argument is a number indicating | ||
33 | +the number of bytes to generate. | ||
34 | + | ||
35 | +```js | ||
36 | +randomBytes(12, function (error, bytes) { | ||
37 | + if (error) throw error | ||
38 | + // do something with the bytes | ||
39 | +}) | ||
40 | +``` | ||
41 | + | ||
42 | +### randomBytes(size) | ||
43 | + | ||
44 | +Generates strong pseudo-random bytes and return a `Promise`. The `size` argument is | ||
45 | +a number indicating the number of bytes to generate. | ||
46 | + | ||
47 | +**Note**: To use promises in Node.js _prior to 0.12_, promises must be | ||
48 | +"polyfilled" using `global.Promise = require('bluebird')`. | ||
49 | + | ||
50 | +```js | ||
51 | +randomBytes(18).then(function (string) { | ||
52 | + // do something with the string | ||
53 | +}) | ||
54 | +``` | ||
55 | + | ||
56 | +### randomBytes.sync(size) | ||
57 | + | ||
58 | +A synchronous version of above. | ||
59 | + | ||
60 | +```js | ||
61 | +var bytes = randomBytes.sync(18) | ||
62 | +``` | ||
63 | + | ||
64 | +## License | ||
65 | + | ||
66 | +[MIT](LICENSE) | ||
67 | + | ||
68 | +[npm-image]: https://img.shields.io/npm/v/random-bytes.svg | ||
69 | +[npm-url]: https://npmjs.org/package/random-bytes | ||
70 | +[node-version-image]: https://img.shields.io/node/v/random-bytes.svg | ||
71 | +[node-version-url]: http://nodejs.org/download/ | ||
72 | +[travis-image]: https://img.shields.io/travis/crypto-utils/random-bytes/master.svg | ||
73 | +[travis-url]: https://travis-ci.org/crypto-utils/random-bytes | ||
74 | +[coveralls-image]: https://img.shields.io/coveralls/crypto-utils/random-bytes/master.svg | ||
75 | +[coveralls-url]: https://coveralls.io/r/crypto-utils/random-bytes?branch=master | ||
76 | +[downloads-image]: https://img.shields.io/npm/dm/random-bytes.svg | ||
77 | +[downloads-url]: https://npmjs.org/package/random-bytes |
Mapmory/node_modules/random-bytes/index.js
0 → 100644
1 | +/*! | ||
2 | + * random-bytes | ||
3 | + * Copyright(c) 2016 Douglas Christopher Wilson | ||
4 | + * MIT Licensed | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict' | ||
8 | + | ||
9 | +/** | ||
10 | + * Module dependencies. | ||
11 | + * @private | ||
12 | + */ | ||
13 | + | ||
14 | +var crypto = require('crypto') | ||
15 | + | ||
16 | +/** | ||
17 | + * Module variables. | ||
18 | + * @private | ||
19 | + */ | ||
20 | + | ||
21 | +var generateAttempts = crypto.randomBytes === crypto.pseudoRandomBytes ? 1 : 3 | ||
22 | + | ||
23 | +/** | ||
24 | + * Module exports. | ||
25 | + * @public | ||
26 | + */ | ||
27 | + | ||
28 | +module.exports = randomBytes | ||
29 | +module.exports.sync = randomBytesSync | ||
30 | + | ||
31 | +/** | ||
32 | + * Generates strong pseudo-random bytes. | ||
33 | + * | ||
34 | + * @param {number} size | ||
35 | + * @param {function} [callback] | ||
36 | + * @return {Promise} | ||
37 | + * @public | ||
38 | + */ | ||
39 | + | ||
40 | +function randomBytes(size, callback) { | ||
41 | + // validate callback is a function, if provided | ||
42 | + if (callback !== undefined && typeof callback !== 'function') { | ||
43 | + throw new TypeError('argument callback must be a function') | ||
44 | + } | ||
45 | + | ||
46 | + // require the callback without promises | ||
47 | + if (!callback && !global.Promise) { | ||
48 | + throw new TypeError('argument callback is required') | ||
49 | + } | ||
50 | + | ||
51 | + if (callback) { | ||
52 | + // classic callback style | ||
53 | + return generateRandomBytes(size, generateAttempts, callback) | ||
54 | + } | ||
55 | + | ||
56 | + return new Promise(function executor(resolve, reject) { | ||
57 | + generateRandomBytes(size, generateAttempts, function onRandomBytes(err, str) { | ||
58 | + if (err) return reject(err) | ||
59 | + resolve(str) | ||
60 | + }) | ||
61 | + }) | ||
62 | +} | ||
63 | + | ||
64 | +/** | ||
65 | + * Generates strong pseudo-random bytes sync. | ||
66 | + * | ||
67 | + * @param {number} size | ||
68 | + * @return {Buffer} | ||
69 | + * @public | ||
70 | + */ | ||
71 | + | ||
72 | +function randomBytesSync(size) { | ||
73 | + var err = null | ||
74 | + | ||
75 | + for (var i = 0; i < generateAttempts; i++) { | ||
76 | + try { | ||
77 | + return crypto.randomBytes(size) | ||
78 | + } catch (e) { | ||
79 | + err = e | ||
80 | + } | ||
81 | + } | ||
82 | + | ||
83 | + throw err | ||
84 | +} | ||
85 | + | ||
86 | +/** | ||
87 | + * Generates strong pseudo-random bytes. | ||
88 | + * | ||
89 | + * @param {number} size | ||
90 | + * @param {number} attempts | ||
91 | + * @param {function} callback | ||
92 | + * @private | ||
93 | + */ | ||
94 | + | ||
95 | +function generateRandomBytes(size, attempts, callback) { | ||
96 | + crypto.randomBytes(size, function onRandomBytes(err, buf) { | ||
97 | + if (!err) return callback(null, buf) | ||
98 | + if (!--attempts) return callback(err) | ||
99 | + setTimeout(generateRandomBytes.bind(null, size, attempts, callback), 10) | ||
100 | + }) | ||
101 | +} |
1 | +{ | ||
2 | + "_from": "random-bytes@~1.0.0", | ||
3 | + "_id": "random-bytes@1.0.0", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=", | ||
6 | + "_location": "/random-bytes", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "range", | ||
10 | + "registry": true, | ||
11 | + "raw": "random-bytes@~1.0.0", | ||
12 | + "name": "random-bytes", | ||
13 | + "escapedName": "random-bytes", | ||
14 | + "rawSpec": "~1.0.0", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "~1.0.0" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/uid-safe" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", | ||
22 | + "_shasum": "4f68a1dc0ae58bd3fb95848c30324db75d64360b", | ||
23 | + "_spec": "random-bytes@~1.0.0", | ||
24 | + "_where": "C:\\Users\\fheld\\Desktop\\khuhub\\mapmory\\Mapmory\\node_modules\\uid-safe", | ||
25 | + "bugs": { | ||
26 | + "url": "https://github.com/crypto-utils/random-bytes/issues" | ||
27 | + }, | ||
28 | + "bundleDependencies": false, | ||
29 | + "contributors": [ | ||
30 | + { | ||
31 | + "name": "Douglas Christopher Wilson", | ||
32 | + "email": "doug@somethingdoug.com" | ||
33 | + } | ||
34 | + ], | ||
35 | + "deprecated": false, | ||
36 | + "description": "URL and cookie safe UIDs", | ||
37 | + "devDependencies": { | ||
38 | + "bluebird": "3.1.1", | ||
39 | + "istanbul": "0.4.2", | ||
40 | + "mocha": "2.3.4", | ||
41 | + "proxyquire": "1.2.0" | ||
42 | + }, | ||
43 | + "engines": { | ||
44 | + "node": ">= 0.8" | ||
45 | + }, | ||
46 | + "files": [ | ||
47 | + "LICENSE", | ||
48 | + "HISTORY.md", | ||
49 | + "README.md", | ||
50 | + "index.js" | ||
51 | + ], | ||
52 | + "homepage": "https://github.com/crypto-utils/random-bytes#readme", | ||
53 | + "keywords": [ | ||
54 | + "bytes", | ||
55 | + "generator", | ||
56 | + "random", | ||
57 | + "safe" | ||
58 | + ], | ||
59 | + "license": "MIT", | ||
60 | + "name": "random-bytes", | ||
61 | + "repository": { | ||
62 | + "type": "git", | ||
63 | + "url": "git+https://github.com/crypto-utils/random-bytes.git" | ||
64 | + }, | ||
65 | + "scripts": { | ||
66 | + "test": "mocha --trace-deprecation --reporter spec --bail --check-leaks test/", | ||
67 | + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --trace-deprecation --reporter dot --check-leaks test/", | ||
68 | + "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --trace-deprecation --reporter spec --check-leaks test/" | ||
69 | + }, | ||
70 | + "version": "1.0.0" | ||
71 | +} |
Mapmory/node_modules/uid-safe/HISTORY.md
0 → 100644
1 | +2.1.5 / 2017-08-02 | ||
2 | +================== | ||
3 | + | ||
4 | + * perf: remove only trailing `=` | ||
5 | + | ||
6 | +2.1.4 / 2017-03-02 | ||
7 | +================== | ||
8 | + | ||
9 | + * Remove `base64-url` dependency | ||
10 | + | ||
11 | +2.1.3 / 2016-10-30 | ||
12 | +================== | ||
13 | + | ||
14 | + * deps: base64-url@1.3.3 | ||
15 | + | ||
16 | +2.1.2 / 2016-08-15 | ||
17 | +================== | ||
18 | + | ||
19 | + * deps: base64-url@1.3.2 | ||
20 | + | ||
21 | +2.1.1 / 2016-05-04 | ||
22 | +================== | ||
23 | + | ||
24 | + * deps: base64-url@1.2.2 | ||
25 | + | ||
26 | +2.1.0 / 2016-01-17 | ||
27 | +================== | ||
28 | + | ||
29 | + * Use `random-bytes` for byte source | ||
30 | + | ||
31 | +2.0.0 / 2015-05-08 | ||
32 | +================== | ||
33 | + | ||
34 | + * Use global `Promise` when returning a promise | ||
35 | + | ||
36 | +1.1.0 / 2015-02-01 | ||
37 | +================== | ||
38 | + | ||
39 | + * Use `crypto.randomBytes`, if available | ||
40 | + * deps: base64-url@1.2.1 | ||
41 | + | ||
42 | +1.0.3 / 2015-01-31 | ||
43 | +================== | ||
44 | + | ||
45 | + * Fix error branch that would throw | ||
46 | + * deps: base64-url@1.2.0 | ||
47 | + | ||
48 | +1.0.2 / 2015-01-08 | ||
49 | +================== | ||
50 | + | ||
51 | + * Remove dependency on `mz` | ||
52 | + | ||
53 | +1.0.1 / 2014-06-18 | ||
54 | +================== | ||
55 | + | ||
56 | + * Remove direct `bluebird` dependency | ||
57 | + | ||
58 | +1.0.0 / 2014-06-18 | ||
59 | +================== | ||
60 | + | ||
61 | + * Initial release |
Mapmory/node_modules/uid-safe/LICENSE
0 → 100644
1 | +The MIT License (MIT) | ||
2 | + | ||
3 | +Copyright (c) 2014 Jonathan Ong <me@jongleberry.com> | ||
4 | +Copyright (c) 2015-2017 Douglas Christopher Wilson <doug@somethingdoug.com> | ||
5 | + | ||
6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | +of this software and associated documentation files (the "Software"), to deal | ||
8 | +in the Software without restriction, including without limitation the rights | ||
9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | +copies of the Software, and to permit persons to whom the Software is | ||
11 | +furnished to do so, subject to the following conditions: | ||
12 | + | ||
13 | +The above copyright notice and this permission notice shall be included in | ||
14 | +all copies or substantial portions of the Software. | ||
15 | + | ||
16 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | +THE SOFTWARE. |
Mapmory/node_modules/uid-safe/README.md
0 → 100644
1 | +# uid-safe | ||
2 | + | ||
3 | +[![NPM Version][npm-image]][npm-url] | ||
4 | +[![NPM Downloads][downloads-image]][downloads-url] | ||
5 | +[![Node.js Version][node-version-image]][node-version-url] | ||
6 | +[![Build Status][travis-image]][travis-url] | ||
7 | +[![Test Coverage][coveralls-image]][coveralls-url] | ||
8 | + | ||
9 | +URL and cookie safe UIDs | ||
10 | + | ||
11 | +Create cryptographically secure UIDs safe for both cookie and URL usage. | ||
12 | +This is in contrast to modules such as [rand-token](https://www.npmjs.com/package/rand-token) | ||
13 | +and [uid2](https://www.npmjs.com/package/uid2) whose UIDs are actually skewed | ||
14 | +due to the use of `%` and unnecessarily truncate the UID. | ||
15 | +Use this if you could still use UIDs with `-` and `_` in them. | ||
16 | + | ||
17 | +## Installation | ||
18 | + | ||
19 | +```sh | ||
20 | +$ npm install uid-safe | ||
21 | +``` | ||
22 | + | ||
23 | +## API | ||
24 | + | ||
25 | +```js | ||
26 | +var uid = require('uid-safe') | ||
27 | +``` | ||
28 | + | ||
29 | +### uid(byteLength, callback) | ||
30 | + | ||
31 | +Asynchronously create a UID with a specific byte length. Because `base64` | ||
32 | +encoding is used underneath, this is not the string length. For example, | ||
33 | +to create a UID of length 24, you want a byte length of 18. | ||
34 | + | ||
35 | +```js | ||
36 | +uid(18, function (err, string) { | ||
37 | + if (err) throw err | ||
38 | + // do something with the string | ||
39 | +}) | ||
40 | +``` | ||
41 | + | ||
42 | +### uid(byteLength) | ||
43 | + | ||
44 | +Asynchronously create a UID with a specific byte length and return a | ||
45 | +`Promise`. | ||
46 | + | ||
47 | +**Note**: To use promises in Node.js _prior to 0.12_, promises must be | ||
48 | +"polyfilled" using `global.Promise = require('bluebird')`. | ||
49 | + | ||
50 | +```js | ||
51 | +uid(18).then(function (string) { | ||
52 | + // do something with the string | ||
53 | +}) | ||
54 | +``` | ||
55 | + | ||
56 | +### uid.sync(byteLength) | ||
57 | + | ||
58 | +A synchronous version of above. | ||
59 | + | ||
60 | +```js | ||
61 | +var string = uid.sync(18) | ||
62 | +``` | ||
63 | + | ||
64 | +## License | ||
65 | + | ||
66 | +[MIT](LICENSE) | ||
67 | + | ||
68 | +[npm-image]: https://img.shields.io/npm/v/uid-safe.svg | ||
69 | +[npm-url]: https://npmjs.org/package/uid-safe | ||
70 | +[node-version-image]: https://img.shields.io/node/v/uid-safe.svg | ||
71 | +[node-version-url]: https://nodejs.org/en/download/ | ||
72 | +[travis-image]: https://img.shields.io/travis/crypto-utils/uid-safe/master.svg | ||
73 | +[travis-url]: https://travis-ci.org/crypto-utils/uid-safe | ||
74 | +[coveralls-image]: https://img.shields.io/coveralls/crypto-utils/uid-safe/master.svg | ||
75 | +[coveralls-url]: https://coveralls.io/r/crypto-utils/uid-safe?branch=master | ||
76 | +[downloads-image]: https://img.shields.io/npm/dm/uid-safe.svg | ||
77 | +[downloads-url]: https://npmjs.org/package/uid-safe |
Mapmory/node_modules/uid-safe/index.js
0 → 100644
1 | +/*! | ||
2 | + * uid-safe | ||
3 | + * Copyright(c) 2014 Jonathan Ong | ||
4 | + * Copyright(c) 2015-2017 Douglas Christopher Wilson | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +'use strict' | ||
9 | + | ||
10 | +/** | ||
11 | + * Module dependencies. | ||
12 | + * @private | ||
13 | + */ | ||
14 | + | ||
15 | +var randomBytes = require('random-bytes') | ||
16 | + | ||
17 | +/** | ||
18 | + * Module variables. | ||
19 | + * @private | ||
20 | + */ | ||
21 | + | ||
22 | +var EQUAL_END_REGEXP = /=+$/ | ||
23 | +var PLUS_GLOBAL_REGEXP = /\+/g | ||
24 | +var SLASH_GLOBAL_REGEXP = /\//g | ||
25 | + | ||
26 | +/** | ||
27 | + * Module exports. | ||
28 | + * @public | ||
29 | + */ | ||
30 | + | ||
31 | +module.exports = uid | ||
32 | +module.exports.sync = uidSync | ||
33 | + | ||
34 | +/** | ||
35 | + * Create a unique ID. | ||
36 | + * | ||
37 | + * @param {number} length | ||
38 | + * @param {function} [callback] | ||
39 | + * @return {Promise} | ||
40 | + * @public | ||
41 | + */ | ||
42 | + | ||
43 | +function uid (length, callback) { | ||
44 | + // validate callback is a function, if provided | ||
45 | + if (callback !== undefined && typeof callback !== 'function') { | ||
46 | + throw new TypeError('argument callback must be a function') | ||
47 | + } | ||
48 | + | ||
49 | + // require the callback without promises | ||
50 | + if (!callback && !global.Promise) { | ||
51 | + throw new TypeError('argument callback is required') | ||
52 | + } | ||
53 | + | ||
54 | + if (callback) { | ||
55 | + // classic callback style | ||
56 | + return generateUid(length, callback) | ||
57 | + } | ||
58 | + | ||
59 | + return new Promise(function executor (resolve, reject) { | ||
60 | + generateUid(length, function onUid (err, str) { | ||
61 | + if (err) return reject(err) | ||
62 | + resolve(str) | ||
63 | + }) | ||
64 | + }) | ||
65 | +} | ||
66 | + | ||
67 | +/** | ||
68 | + * Create a unique ID sync. | ||
69 | + * | ||
70 | + * @param {number} length | ||
71 | + * @return {string} | ||
72 | + * @public | ||
73 | + */ | ||
74 | + | ||
75 | +function uidSync (length) { | ||
76 | + return toString(randomBytes.sync(length)) | ||
77 | +} | ||
78 | + | ||
79 | +/** | ||
80 | + * Generate a unique ID string. | ||
81 | + * | ||
82 | + * @param {number} length | ||
83 | + * @param {function} callback | ||
84 | + * @private | ||
85 | + */ | ||
86 | + | ||
87 | +function generateUid (length, callback) { | ||
88 | + randomBytes(length, function (err, buf) { | ||
89 | + if (err) return callback(err) | ||
90 | + callback(null, toString(buf)) | ||
91 | + }) | ||
92 | +} | ||
93 | + | ||
94 | +/** | ||
95 | + * Change a Buffer into a string. | ||
96 | + * | ||
97 | + * @param {Buffer} buf | ||
98 | + * @return {string} | ||
99 | + * @private | ||
100 | + */ | ||
101 | + | ||
102 | +function toString (buf) { | ||
103 | + return buf.toString('base64') | ||
104 | + .replace(EQUAL_END_REGEXP, '') | ||
105 | + .replace(PLUS_GLOBAL_REGEXP, '-') | ||
106 | + .replace(SLASH_GLOBAL_REGEXP, '_') | ||
107 | +} |
Mapmory/node_modules/uid-safe/package.json
0 → 100644
1 | +{ | ||
2 | + "_from": "uid-safe@~2.1.5", | ||
3 | + "_id": "uid-safe@2.1.5", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", | ||
6 | + "_location": "/uid-safe", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "range", | ||
10 | + "registry": true, | ||
11 | + "raw": "uid-safe@~2.1.5", | ||
12 | + "name": "uid-safe", | ||
13 | + "escapedName": "uid-safe", | ||
14 | + "rawSpec": "~2.1.5", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "~2.1.5" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/express-session" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", | ||
22 | + "_shasum": "2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a", | ||
23 | + "_spec": "uid-safe@~2.1.5", | ||
24 | + "_where": "C:\\Users\\fheld\\Desktop\\khuhub\\mapmory\\Mapmory\\node_modules\\express-session", | ||
25 | + "bugs": { | ||
26 | + "url": "https://github.com/crypto-utils/uid-safe/issues" | ||
27 | + }, | ||
28 | + "bundleDependencies": false, | ||
29 | + "contributors": [ | ||
30 | + { | ||
31 | + "name": "Douglas Christopher Wilson", | ||
32 | + "email": "doug@somethingdoug.com" | ||
33 | + }, | ||
34 | + { | ||
35 | + "name": "Jonathan Ong", | ||
36 | + "email": "me@jongleberry.com", | ||
37 | + "url": "http://jongleberry.com" | ||
38 | + } | ||
39 | + ], | ||
40 | + "dependencies": { | ||
41 | + "random-bytes": "~1.0.0" | ||
42 | + }, | ||
43 | + "deprecated": false, | ||
44 | + "description": "URL and cookie safe UIDs", | ||
45 | + "devDependencies": { | ||
46 | + "bluebird": "3.5.0", | ||
47 | + "eslint": "3.19.0", | ||
48 | + "eslint-config-standard": "10.2.1", | ||
49 | + "eslint-plugin-import": "2.7.0", | ||
50 | + "eslint-plugin-node": "5.1.1", | ||
51 | + "eslint-plugin-promise": "3.5.0", | ||
52 | + "eslint-plugin-standard": "3.0.1", | ||
53 | + "istanbul": "0.4.5", | ||
54 | + "mocha": "2.5.3" | ||
55 | + }, | ||
56 | + "engines": { | ||
57 | + "node": ">= 0.8" | ||
58 | + }, | ||
59 | + "files": [ | ||
60 | + "LICENSE", | ||
61 | + "HISTORY.md", | ||
62 | + "README.md", | ||
63 | + "index.js" | ||
64 | + ], | ||
65 | + "homepage": "https://github.com/crypto-utils/uid-safe#readme", | ||
66 | + "keywords": [ | ||
67 | + "random", | ||
68 | + "generator", | ||
69 | + "uid", | ||
70 | + "safe" | ||
71 | + ], | ||
72 | + "license": "MIT", | ||
73 | + "name": "uid-safe", | ||
74 | + "repository": { | ||
75 | + "type": "git", | ||
76 | + "url": "git+https://github.com/crypto-utils/uid-safe.git" | ||
77 | + }, | ||
78 | + "scripts": { | ||
79 | + "lint": "eslint .", | ||
80 | + "test": "mocha --trace-deprecation --reporter spec --bail --check-leaks test/", | ||
81 | + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --trace-deprecation --reporter dot --check-leaks test/", | ||
82 | + "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --trace-deprecation --reporter spec --check-leaks test/" | ||
83 | + }, | ||
84 | + "version": "2.1.5" | ||
85 | +} |
... | @@ -148,6 +148,33 @@ | ... | @@ -148,6 +148,33 @@ |
148 | "vary": "~1.1.2" | 148 | "vary": "~1.1.2" |
149 | } | 149 | } |
150 | }, | 150 | }, |
151 | + "express-session": { | ||
152 | + "version": "1.17.1", | ||
153 | + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.1.tgz", | ||
154 | + "integrity": "sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q==", | ||
155 | + "requires": { | ||
156 | + "cookie": "0.4.0", | ||
157 | + "cookie-signature": "1.0.6", | ||
158 | + "debug": "2.6.9", | ||
159 | + "depd": "~2.0.0", | ||
160 | + "on-headers": "~1.0.2", | ||
161 | + "parseurl": "~1.3.3", | ||
162 | + "safe-buffer": "5.2.0", | ||
163 | + "uid-safe": "~2.1.5" | ||
164 | + }, | ||
165 | + "dependencies": { | ||
166 | + "depd": { | ||
167 | + "version": "2.0.0", | ||
168 | + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", | ||
169 | + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" | ||
170 | + }, | ||
171 | + "safe-buffer": { | ||
172 | + "version": "5.2.0", | ||
173 | + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", | ||
174 | + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" | ||
175 | + } | ||
176 | + } | ||
177 | + }, | ||
151 | "finalhandler": { | 178 | "finalhandler": { |
152 | "version": "1.1.2", | 179 | "version": "1.1.2", |
153 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", | 180 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", |
... | @@ -269,6 +296,11 @@ | ... | @@ -269,6 +296,11 @@ |
269 | "ee-first": "1.1.1" | 296 | "ee-first": "1.1.1" |
270 | } | 297 | } |
271 | }, | 298 | }, |
299 | + "on-headers": { | ||
300 | + "version": "1.0.2", | ||
301 | + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", | ||
302 | + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" | ||
303 | + }, | ||
272 | "parseurl": { | 304 | "parseurl": { |
273 | "version": "1.3.3", | 305 | "version": "1.3.3", |
274 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", | 306 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", |
... | @@ -298,6 +330,11 @@ | ... | @@ -298,6 +330,11 @@ |
298 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", | 330 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", |
299 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" | 331 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" |
300 | }, | 332 | }, |
333 | + "random-bytes": { | ||
334 | + "version": "1.0.0", | ||
335 | + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", | ||
336 | + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" | ||
337 | + }, | ||
301 | "range-parser": { | 338 | "range-parser": { |
302 | "version": "1.2.1", | 339 | "version": "1.2.1", |
303 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", | 340 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", |
... | @@ -413,6 +450,14 @@ | ... | @@ -413,6 +450,14 @@ |
413 | "mime-types": "~2.1.24" | 450 | "mime-types": "~2.1.24" |
414 | } | 451 | } |
415 | }, | 452 | }, |
453 | + "uid-safe": { | ||
454 | + "version": "2.1.5", | ||
455 | + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", | ||
456 | + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", | ||
457 | + "requires": { | ||
458 | + "random-bytes": "~1.0.0" | ||
459 | + } | ||
460 | + }, | ||
416 | "unpipe": { | 461 | "unpipe": { |
417 | "version": "1.0.0", | 462 | "version": "1.0.0", |
418 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", | 463 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", | ... | ... |
-
Please register or login to post a comment