Added session storage for login, via express-session
Added express-session module Modified index.js to save the session login
This commit is contained in:
parent
0b90b3a860
commit
0b7d76333c
19
src/index.js
19
src/index.js
@ -4,6 +4,7 @@
|
|||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
|
const session = require("express-session");
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
const app = express();
|
const app = express();
|
||||||
const server = require('http').createServer(app);
|
const server = require('http').createServer(app);
|
||||||
@ -74,9 +75,19 @@ console.log(__dirname);
|
|||||||
app.use(express.static(__dirname));
|
app.use(express.static(__dirname));
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
app.use(session({
|
||||||
|
secret: 'secret key',
|
||||||
|
resave: false,
|
||||||
|
saveUninitialized: false,
|
||||||
|
logged: false
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
app.get("/", function (req, res) {
|
app.get("/", function (req, res) {
|
||||||
res.sendFile(__dirname + "/login.html");
|
if (req.session.logged)
|
||||||
|
res.sendFile(__dirname + "/main.html");
|
||||||
|
else
|
||||||
|
res.sendFile(__dirname + "/login.html");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/login", function (req, res)
|
app.post("/login", function (req, res)
|
||||||
@ -86,9 +97,15 @@ app.post("/login", function (req, res)
|
|||||||
res.sendStatus(400);
|
res.sendStatus(400);
|
||||||
console.log(data.password);
|
console.log(data.password);
|
||||||
if(data.password == settings.password)
|
if(data.password == settings.password)
|
||||||
|
{
|
||||||
|
req.session.logged = true;
|
||||||
res.sendFile(__dirname + "/main.html");
|
res.sendFile(__dirname + "/main.html");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
req.session.logged = false;
|
||||||
res.sendFile(__dirname + "/login.html");
|
res.sendFile(__dirname + "/login.html");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/video", function (req, res) {
|
app.get("/video", function (req, res) {
|
||||||
|
53
src/node_modules/.package-lock.json
generated
vendored
53
src/node_modules/.package-lock.json
generated
vendored
@ -188,6 +188,32 @@
|
|||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/express-session": {
|
||||||
|
"version": "1.17.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz",
|
||||||
|
"integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==",
|
||||||
|
"dependencies": {
|
||||||
|
"cookie": "0.4.2",
|
||||||
|
"cookie-signature": "1.0.6",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~2.0.0",
|
||||||
|
"on-headers": "~1.0.2",
|
||||||
|
"parseurl": "~1.3.3",
|
||||||
|
"safe-buffer": "5.2.1",
|
||||||
|
"uid-safe": "~2.1.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/express-session/node_modules/cookie": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/express/node_modules/body-parser": {
|
"node_modules/express/node_modules/body-parser": {
|
||||||
"version": "1.20.1",
|
"version": "1.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||||
@ -432,6 +458,14 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/on-headers": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/parseurl": {
|
"node_modules/parseurl": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
@ -471,6 +505,14 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/random-bytes": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/range-parser": {
|
"node_modules/range-parser": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
@ -605,6 +647,17 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uid-safe": {
|
||||||
|
"version": "2.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||||
|
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
|
||||||
|
"dependencies": {
|
||||||
|
"random-bytes": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/unpipe": {
|
"node_modules/unpipe": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
|
442
src/node_modules/express-session/HISTORY.md
generated
vendored
Normal file
442
src/node_modules/express-session/HISTORY.md
generated
vendored
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
1.17.3 / 2022-05-11
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix resaving already-saved new session at end of request
|
||||||
|
* deps: cookie@0.4.2
|
||||||
|
|
||||||
|
1.17.2 / 2021-05-19
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix `res.end` patch to always commit headers
|
||||||
|
* deps: cookie@0.4.1
|
||||||
|
* deps: safe-buffer@5.2.1
|
||||||
|
|
||||||
|
1.17.1 / 2020-04-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix internal method wrapping error on failed reloads
|
||||||
|
|
||||||
|
1.17.0 / 2019-10-10
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: cookie@0.4.0
|
||||||
|
- Add `SameSite=None` support
|
||||||
|
* deps: safe-buffer@5.2.0
|
||||||
|
|
||||||
|
1.16.2 / 2019-06-12
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix restoring `cookie.originalMaxAge` when store returns `Date`
|
||||||
|
* deps: parseurl@~1.3.3
|
||||||
|
|
||||||
|
1.16.1 / 2019-04-11
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix error passing `data` option to `Cookie` constructor
|
||||||
|
* Fix uncaught error from bad session data
|
||||||
|
|
||||||
|
1.16.0 / 2019-04-10
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Catch invalid `cookie.maxAge` value earlier
|
||||||
|
* Deprecate setting `cookie.maxAge` to a `Date` object
|
||||||
|
* Fix issue where `resave: false` may not save altered sessions
|
||||||
|
* Remove `utils-merge` dependency
|
||||||
|
* Use `safe-buffer` for improved Buffer API
|
||||||
|
* Use `Set-Cookie` as cookie header name for compatibility
|
||||||
|
* deps: depd@~2.0.0
|
||||||
|
- Replace internal `eval` usage with `Function` constructor
|
||||||
|
- Use instance methods on `process` to check for listeners
|
||||||
|
- perf: remove argument reassignment
|
||||||
|
* deps: on-headers@~1.0.2
|
||||||
|
- Fix `res.writeHead` patch missing return value
|
||||||
|
|
||||||
|
1.15.6 / 2017-09-26
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: debug@2.6.9
|
||||||
|
* deps: parseurl@~1.3.2
|
||||||
|
- perf: reduce overhead for full URLs
|
||||||
|
- perf: unroll the "fast-path" `RegExp`
|
||||||
|
* deps: uid-safe@~2.1.5
|
||||||
|
- perf: remove only trailing `=`
|
||||||
|
* deps: utils-merge@1.0.1
|
||||||
|
|
||||||
|
1.15.5 / 2017-08-02
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix `TypeError` when `req.url` is an empty string
|
||||||
|
* deps: depd@~1.1.1
|
||||||
|
- Remove unnecessary `Buffer` loading
|
||||||
|
|
||||||
|
1.15.4 / 2017-07-18
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: debug@2.6.8
|
||||||
|
|
||||||
|
1.15.3 / 2017-05-17
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: debug@2.6.7
|
||||||
|
- deps: ms@2.0.0
|
||||||
|
|
||||||
|
1.15.2 / 2017-03-26
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: debug@2.6.3
|
||||||
|
- Fix `DEBUG_MAX_ARRAY_LENGTH`
|
||||||
|
* deps: uid-safe@~2.1.4
|
||||||
|
- Remove `base64-url` dependency
|
||||||
|
|
||||||
|
1.15.1 / 2017-02-10
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: debug@2.6.1
|
||||||
|
- Fix deprecation messages in WebStorm and other editors
|
||||||
|
- Undeprecate `DEBUG_FD` set to `1` or `2`
|
||||||
|
|
||||||
|
1.15.0 / 2017-01-22
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix detecting modified session when session contains "cookie" property
|
||||||
|
* Fix resaving already-saved reloaded session at end of request
|
||||||
|
* deps: crc@3.4.4
|
||||||
|
- perf: use `Buffer.from` when available
|
||||||
|
* deps: debug@2.6.0
|
||||||
|
- Allow colors in workers
|
||||||
|
- Deprecated `DEBUG_FD` environment variable
|
||||||
|
- Use same color for same namespace
|
||||||
|
- Fix error when running under React Native
|
||||||
|
- deps: ms@0.7.2
|
||||||
|
* perf: remove unreachable branch in set-cookie method
|
||||||
|
|
||||||
|
1.14.2 / 2016-10-30
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: crc@3.4.1
|
||||||
|
- Fix deprecation warning in Node.js 7.x
|
||||||
|
* deps: uid-safe@~2.1.3
|
||||||
|
- deps: base64-url@1.3.3
|
||||||
|
|
||||||
|
1.14.1 / 2016-08-24
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix not always resetting session max age before session save
|
||||||
|
* Fix the cookie `sameSite` option to actually alter the `Set-Cookie`
|
||||||
|
* deps: uid-safe@~2.1.2
|
||||||
|
- deps: base64-url@1.3.2
|
||||||
|
|
||||||
|
1.14.0 / 2016-07-01
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Correctly inherit from `EventEmitter` class in `Store` base class
|
||||||
|
* Fix issue where `Set-Cookie` `Expires` was not always updated
|
||||||
|
* Methods are no longer enumerable on `req.session` object
|
||||||
|
* deps: cookie@0.3.1
|
||||||
|
- Add `sameSite` option
|
||||||
|
- Improve error message when `encode` is not a function
|
||||||
|
- Improve error message when `expires` is not a `Date`
|
||||||
|
- perf: enable strict mode
|
||||||
|
- perf: use for loop in parse
|
||||||
|
- perf: use string concatination for serialization
|
||||||
|
* deps: parseurl@~1.3.1
|
||||||
|
- perf: enable strict mode
|
||||||
|
* deps: uid-safe@~2.1.1
|
||||||
|
- Use `random-bytes` for byte source
|
||||||
|
- deps: base64-url@1.2.2
|
||||||
|
* perf: enable strict mode
|
||||||
|
* perf: remove argument reassignment
|
||||||
|
|
||||||
|
1.13.0 / 2016-01-10
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix `rolling: true` to not set cookie when no session exists
|
||||||
|
- Better `saveUninitialized: false` + `rolling: true` behavior
|
||||||
|
* deps: crc@3.4.0
|
||||||
|
|
||||||
|
1.12.1 / 2015-10-29
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: cookie@0.2.3
|
||||||
|
- Fix cookie `Max-Age` to never be a floating point number
|
||||||
|
|
||||||
|
1.12.0 / 2015-10-25
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Support the value `'auto'` in the `cookie.secure` option
|
||||||
|
* deps: cookie@0.2.2
|
||||||
|
- Throw on invalid values provided to `serialize`
|
||||||
|
* deps: depd@~1.1.0
|
||||||
|
- Enable strict mode in more places
|
||||||
|
- Support web browser loading
|
||||||
|
* deps: on-headers@~1.0.1
|
||||||
|
- perf: enable strict mode
|
||||||
|
|
||||||
|
1.11.3 / 2015-05-22
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: cookie@0.1.3
|
||||||
|
- Slight optimizations
|
||||||
|
* deps: crc@3.3.0
|
||||||
|
|
||||||
|
1.11.2 / 2015-05-10
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: debug@~2.2.0
|
||||||
|
- deps: ms@0.7.1
|
||||||
|
* deps: uid-safe@~2.0.0
|
||||||
|
|
||||||
|
1.11.1 / 2015-04-08
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix mutating `options.secret` value
|
||||||
|
|
||||||
|
1.11.0 / 2015-04-07
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Support an array in `secret` option for key rotation
|
||||||
|
* deps: depd@~1.0.1
|
||||||
|
|
||||||
|
1.10.4 / 2015-03-15
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: debug@~2.1.3
|
||||||
|
- Fix high intensity foreground color for bold
|
||||||
|
- deps: ms@0.7.0
|
||||||
|
|
||||||
|
1.10.3 / 2015-02-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: cookie-signature@1.0.6
|
||||||
|
* deps: uid-safe@1.1.0
|
||||||
|
- Use `crypto.randomBytes`, if available
|
||||||
|
- deps: base64-url@1.2.1
|
||||||
|
|
||||||
|
1.10.2 / 2015-01-31
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: uid-safe@1.0.3
|
||||||
|
- Fix error branch that would throw
|
||||||
|
- deps: base64-url@1.2.0
|
||||||
|
|
||||||
|
1.10.1 / 2015-01-08
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: uid-safe@1.0.2
|
||||||
|
- Remove dependency on `mz`
|
||||||
|
|
||||||
|
1.10.0 / 2015-01-05
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Add `store.touch` interface for session stores
|
||||||
|
* Fix `MemoryStore` expiration with `resave: false`
|
||||||
|
* deps: debug@~2.1.1
|
||||||
|
|
||||||
|
1.9.3 / 2014-12-02
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix error when `req.sessionID` contains a non-string value
|
||||||
|
|
||||||
|
1.9.2 / 2014-11-22
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: crc@3.2.1
|
||||||
|
- Minor fixes
|
||||||
|
|
||||||
|
1.9.1 / 2014-10-22
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Remove unnecessary empty write call
|
||||||
|
- Fixes Node.js 0.11.14 behavior change
|
||||||
|
- Helps work-around Node.js 0.10.1 zlib bug
|
||||||
|
|
||||||
|
1.9.0 / 2014-09-16
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: debug@~2.1.0
|
||||||
|
- Implement `DEBUG_FD` env variable support
|
||||||
|
* deps: depd@~1.0.0
|
||||||
|
|
||||||
|
1.8.2 / 2014-09-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Use `crc` instead of `buffer-crc32` for speed
|
||||||
|
* deps: depd@0.4.5
|
||||||
|
|
||||||
|
1.8.1 / 2014-09-08
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Keep `req.session.save` non-enumerable
|
||||||
|
* Prevent session prototype methods from being overwritten
|
||||||
|
|
||||||
|
1.8.0 / 2014-09-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Do not resave already-saved session at end of request
|
||||||
|
* deps: cookie-signature@1.0.5
|
||||||
|
* deps: debug@~2.0.0
|
||||||
|
|
||||||
|
1.7.6 / 2014-08-18
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix exception on `res.end(null)` calls
|
||||||
|
|
||||||
|
1.7.5 / 2014-08-10
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix parsing original URL
|
||||||
|
* deps: on-headers@~1.0.0
|
||||||
|
* deps: parseurl@~1.3.0
|
||||||
|
|
||||||
|
1.7.4 / 2014-08-05
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix response end delay for non-chunked responses
|
||||||
|
|
||||||
|
1.7.3 / 2014-08-05
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix `res.end` patch to call correct upstream `res.write`
|
||||||
|
|
||||||
|
1.7.2 / 2014-07-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: depd@0.4.4
|
||||||
|
- Work-around v8 generating empty stack traces
|
||||||
|
|
||||||
|
1.7.1 / 2014-07-26
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: depd@0.4.3
|
||||||
|
- Fix exception when global `Error.stackTraceLimit` is too low
|
||||||
|
|
||||||
|
1.7.0 / 2014-07-22
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Improve session-ending error handling
|
||||||
|
- Errors are passed to `next(err)` instead of `console.error`
|
||||||
|
* deps: debug@1.0.4
|
||||||
|
* deps: depd@0.4.2
|
||||||
|
- Add `TRACE_DEPRECATION` environment variable
|
||||||
|
- Remove non-standard grey color from color output
|
||||||
|
- Support `--no-deprecation` argument
|
||||||
|
- Support `--trace-deprecation` argument
|
||||||
|
|
||||||
|
1.6.5 / 2014-07-11
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Do not require `req.originalUrl`
|
||||||
|
* deps: debug@1.0.3
|
||||||
|
- Add support for multiple wildcards in namespaces
|
||||||
|
|
||||||
|
1.6.4 / 2014-07-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix blank responses for stores with synchronous operations
|
||||||
|
|
||||||
|
1.6.3 / 2014-07-04
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix resave deprecation message
|
||||||
|
|
||||||
|
1.6.2 / 2014-07-04
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix confusing option deprecation messages
|
||||||
|
|
||||||
|
1.6.1 / 2014-06-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix saveUninitialized deprecation message
|
||||||
|
|
||||||
|
1.6.0 / 2014-06-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add deprecation message to undefined `resave` option
|
||||||
|
* Add deprecation message to undefined `saveUninitialized` option
|
||||||
|
* Fix `res.end` patch to return correct value
|
||||||
|
* Fix `res.end` patch to handle multiple `res.end` calls
|
||||||
|
* Reject cookies with missing signatures
|
||||||
|
|
||||||
|
1.5.2 / 2014-06-26
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: cookie-signature@1.0.4
|
||||||
|
- fix for timing attacks
|
||||||
|
|
||||||
|
1.5.1 / 2014-06-21
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Move hard-to-track-down `req.secret` deprecation message
|
||||||
|
|
||||||
|
1.5.0 / 2014-06-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Debug name is now "express-session"
|
||||||
|
* Deprecate integration with `cookie-parser` middleware
|
||||||
|
* Deprecate looking for secret in `req.secret`
|
||||||
|
* Directly read cookies; `cookie-parser` no longer required
|
||||||
|
* Directly set cookies; `res.cookie` no longer required
|
||||||
|
* Generate session IDs with `uid-safe`, faster and even less collisions
|
||||||
|
|
||||||
|
1.4.0 / 2014-06-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `genid` option to generate custom session IDs
|
||||||
|
* Add `saveUninitialized` option to control saving uninitialized sessions
|
||||||
|
* Add `unset` option to control unsetting `req.session`
|
||||||
|
* Generate session IDs with `rand-token` by default; reduce collisions
|
||||||
|
* deps: buffer-crc32@0.2.3
|
||||||
|
|
||||||
|
1.3.1 / 2014-06-14
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add description in package for npmjs.org listing
|
||||||
|
|
||||||
|
1.3.0 / 2014-06-14
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Integrate with express "trust proxy" by default
|
||||||
|
* deps: debug@1.0.2
|
||||||
|
|
||||||
|
1.2.1 / 2014-05-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix `resave` such that `resave: true` works
|
||||||
|
|
||||||
|
1.2.0 / 2014-05-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `resave` option to control saving unmodified sessions
|
||||||
|
|
||||||
|
1.1.0 / 2014-05-12
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `name` option; replacement for `key` option
|
||||||
|
* Use `setImmediate` in MemoryStore for node.js >= 0.10
|
||||||
|
|
||||||
|
1.0.4 / 2014-04-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: debug@0.8.1
|
||||||
|
|
||||||
|
1.0.3 / 2014-04-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Use `res.cookie()` instead of `res.setHeader()`
|
||||||
|
* deps: cookie@0.1.2
|
||||||
|
|
||||||
|
1.0.2 / 2014-02-23
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add missing dependency to `package.json`
|
||||||
|
|
||||||
|
1.0.1 / 2014-02-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add missing dependencies to `package.json`
|
||||||
|
|
||||||
|
1.0.0 / 2014-02-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Genesis from `connect`
|
24
src/node_modules/express-session/LICENSE
generated
vendored
Normal file
24
src/node_modules/express-session/LICENSE
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2010 Sencha Inc.
|
||||||
|
Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||||
|
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
985
src/node_modules/express-session/README.md
generated
vendored
Normal file
985
src/node_modules/express-session/README.md
generated
vendored
Normal file
@ -0,0 +1,985 @@
|
|||||||
|
# express-session
|
||||||
|
|
||||||
|
[![NPM Version][npm-version-image]][npm-url]
|
||||||
|
[![NPM Downloads][npm-downloads-image]][node-url]
|
||||||
|
[![Build Status][ci-image]][ci-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||||
|
[npm registry](https://www.npmjs.com/). Installation is done using the
|
||||||
|
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install express-session
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```js
|
||||||
|
var session = require('express-session')
|
||||||
|
```
|
||||||
|
|
||||||
|
### session(options)
|
||||||
|
|
||||||
|
Create a session middleware with the given `options`.
|
||||||
|
|
||||||
|
**Note** Session data is _not_ saved in the cookie itself, just the session ID.
|
||||||
|
Session data is stored server-side.
|
||||||
|
|
||||||
|
**Note** Since version 1.5.0, the [`cookie-parser` middleware](https://www.npmjs.com/package/cookie-parser)
|
||||||
|
no longer needs to be used for this module to work. This module now directly reads
|
||||||
|
and writes cookies on `req`/`res`. Using `cookie-parser` may result in issues
|
||||||
|
if the `secret` is not the same between this module and `cookie-parser`.
|
||||||
|
|
||||||
|
**Warning** The default server-side session storage, `MemoryStore`, is _purposely_
|
||||||
|
not designed for a production environment. It will leak memory under most
|
||||||
|
conditions, does not scale past a single process, and is meant for debugging and
|
||||||
|
developing.
|
||||||
|
|
||||||
|
For a list of stores, see [compatible session stores](#compatible-session-stores).
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
`express-session` accepts these properties in the options object.
|
||||||
|
|
||||||
|
##### cookie
|
||||||
|
|
||||||
|
Settings object for the session ID cookie. The default value is
|
||||||
|
`{ path: '/', httpOnly: true, secure: false, maxAge: null }`.
|
||||||
|
|
||||||
|
The following are options that can be set in this object.
|
||||||
|
|
||||||
|
##### cookie.domain
|
||||||
|
|
||||||
|
Specifies the value for the `Domain` `Set-Cookie` attribute. By default, no domain
|
||||||
|
is set, and most clients will consider the cookie to apply to only the current
|
||||||
|
domain.
|
||||||
|
|
||||||
|
##### cookie.expires
|
||||||
|
|
||||||
|
Specifies the `Date` object to be the value for the `Expires` `Set-Cookie` attribute.
|
||||||
|
By default, no expiration is set, and most clients will consider this a
|
||||||
|
"non-persistent cookie" and will delete it on a condition like exiting a web browser
|
||||||
|
application.
|
||||||
|
|
||||||
|
**Note** If both `expires` and `maxAge` are set in the options, then the last one
|
||||||
|
defined in the object is what is used.
|
||||||
|
|
||||||
|
**Note** The `expires` option should not be set directly; instead only use the `maxAge`
|
||||||
|
option.
|
||||||
|
|
||||||
|
##### cookie.httpOnly
|
||||||
|
|
||||||
|
Specifies the `boolean` value for the `HttpOnly` `Set-Cookie` attribute. When truthy,
|
||||||
|
the `HttpOnly` attribute is set, otherwise it is not. By default, the `HttpOnly`
|
||||||
|
attribute is set.
|
||||||
|
|
||||||
|
**Note** be careful when setting this to `true`, as compliant clients will not allow
|
||||||
|
client-side JavaScript to see the cookie in `document.cookie`.
|
||||||
|
|
||||||
|
##### cookie.maxAge
|
||||||
|
|
||||||
|
Specifies the `number` (in milliseconds) to use when calculating the `Expires`
|
||||||
|
`Set-Cookie` attribute. This is done by taking the current server time and adding
|
||||||
|
`maxAge` milliseconds to the value to calculate an `Expires` datetime. By default,
|
||||||
|
no maximum age is set.
|
||||||
|
|
||||||
|
**Note** If both `expires` and `maxAge` are set in the options, then the last one
|
||||||
|
defined in the object is what is used.
|
||||||
|
|
||||||
|
##### cookie.path
|
||||||
|
|
||||||
|
Specifies the value for the `Path` `Set-Cookie`. By default, this is set to `'/'`, which
|
||||||
|
is the root path of the domain.
|
||||||
|
|
||||||
|
##### cookie.sameSite
|
||||||
|
|
||||||
|
Specifies the `boolean` or `string` to be the value for the `SameSite` `Set-Cookie` attribute.
|
||||||
|
By default, this is `false`.
|
||||||
|
|
||||||
|
- `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
|
||||||
|
- `false` will not set the `SameSite` attribute.
|
||||||
|
- `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
|
||||||
|
- `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
|
||||||
|
- `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
|
||||||
|
|
||||||
|
More information about the different enforcement levels can be found in
|
||||||
|
[the specification][rfc-6265bis-03-4.1.2.7].
|
||||||
|
|
||||||
|
**Note** This is an attribute that has not yet been fully standardized, and may change in
|
||||||
|
the future. This also means many clients may ignore this attribute until they understand it.
|
||||||
|
|
||||||
|
**Note** There is a [draft spec](https://tools.ietf.org/html/draft-west-cookie-incrementalism-01)
|
||||||
|
that requires that the `Secure` attribute be set to `true` when the `SameSite` attribute has been
|
||||||
|
set to `'none'`. Some web browsers or other clients may be adopting this specification.
|
||||||
|
|
||||||
|
##### cookie.secure
|
||||||
|
|
||||||
|
Specifies the `boolean` value for the `Secure` `Set-Cookie` attribute. When truthy,
|
||||||
|
the `Secure` attribute is set, otherwise it is not. By default, the `Secure`
|
||||||
|
attribute is not set.
|
||||||
|
|
||||||
|
**Note** be careful when setting this to `true`, as compliant clients will not send
|
||||||
|
the cookie back to the server in the future if the browser does not have an HTTPS
|
||||||
|
connection.
|
||||||
|
|
||||||
|
Please note that `secure: true` is a **recommended** option. However, it requires
|
||||||
|
an https-enabled website, i.e., HTTPS is necessary for secure cookies. If `secure`
|
||||||
|
is set, and you access your site over HTTP, the cookie will not be set. If you
|
||||||
|
have your node.js behind a proxy and are using `secure: true`, you need to set
|
||||||
|
"trust proxy" in express:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var app = express()
|
||||||
|
app.set('trust proxy', 1) // trust first proxy
|
||||||
|
app.use(session({
|
||||||
|
secret: 'keyboard cat',
|
||||||
|
resave: false,
|
||||||
|
saveUninitialized: true,
|
||||||
|
cookie: { secure: true }
|
||||||
|
}))
|
||||||
|
```
|
||||||
|
|
||||||
|
For using secure cookies in production, but allowing for testing in development,
|
||||||
|
the following is an example of enabling this setup based on `NODE_ENV` in express:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var app = express()
|
||||||
|
var sess = {
|
||||||
|
secret: 'keyboard cat',
|
||||||
|
cookie: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app.get('env') === 'production') {
|
||||||
|
app.set('trust proxy', 1) // trust first proxy
|
||||||
|
sess.cookie.secure = true // serve secure cookies
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use(session(sess))
|
||||||
|
```
|
||||||
|
|
||||||
|
The `cookie.secure` option can also be set to the special value `'auto'` to have
|
||||||
|
this setting automatically match the determined security of the connection. Be
|
||||||
|
careful when using this setting if the site is available both as HTTP and HTTPS,
|
||||||
|
as once the cookie is set on HTTPS, it will no longer be visible over HTTP. This
|
||||||
|
is useful when the Express `"trust proxy"` setting is properly setup to simplify
|
||||||
|
development vs production configuration.
|
||||||
|
|
||||||
|
##### genid
|
||||||
|
|
||||||
|
Function to call to generate a new session ID. Provide a function that returns
|
||||||
|
a string that will be used as a session ID. The function is given `req` as the
|
||||||
|
first argument if you want to use some value attached to `req` when generating
|
||||||
|
the ID.
|
||||||
|
|
||||||
|
The default value is a function which uses the `uid-safe` library to generate IDs.
|
||||||
|
|
||||||
|
**NOTE** be careful to generate unique IDs so your sessions do not conflict.
|
||||||
|
|
||||||
|
```js
|
||||||
|
app.use(session({
|
||||||
|
genid: function(req) {
|
||||||
|
return genuuid() // use UUIDs for session IDs
|
||||||
|
},
|
||||||
|
secret: 'keyboard cat'
|
||||||
|
}))
|
||||||
|
```
|
||||||
|
|
||||||
|
##### name
|
||||||
|
|
||||||
|
The name of the session ID cookie to set in the response (and read from in the
|
||||||
|
request).
|
||||||
|
|
||||||
|
The default value is `'connect.sid'`.
|
||||||
|
|
||||||
|
**Note** if you have multiple apps running on the same hostname (this is just
|
||||||
|
the name, i.e. `localhost` or `127.0.0.1`; different schemes and ports do not
|
||||||
|
name a different hostname), then you need to separate the session cookies from
|
||||||
|
each other. The simplest method is to simply set different `name`s per app.
|
||||||
|
|
||||||
|
##### proxy
|
||||||
|
|
||||||
|
Trust the reverse proxy when setting secure cookies (via the "X-Forwarded-Proto"
|
||||||
|
header).
|
||||||
|
|
||||||
|
The default value is `undefined`.
|
||||||
|
|
||||||
|
- `true` The "X-Forwarded-Proto" header will be used.
|
||||||
|
- `false` All headers are ignored and the connection is considered secure only
|
||||||
|
if there is a direct TLS/SSL connection.
|
||||||
|
- `undefined` Uses the "trust proxy" setting from express
|
||||||
|
|
||||||
|
##### resave
|
||||||
|
|
||||||
|
Forces the session to be saved back to the session store, even if the session
|
||||||
|
was never modified during the request. Depending on your store this may be
|
||||||
|
necessary, but it can also create race conditions where a client makes two
|
||||||
|
parallel requests to your server and changes made to the session in one
|
||||||
|
request may get overwritten when the other request ends, even if it made no
|
||||||
|
changes (this behavior also depends on what store you're using).
|
||||||
|
|
||||||
|
The default value is `true`, but using the default has been deprecated,
|
||||||
|
as the default will change in the future. Please research into this setting
|
||||||
|
and choose what is appropriate to your use-case. Typically, you'll want
|
||||||
|
`false`.
|
||||||
|
|
||||||
|
How do I know if this is necessary for my store? The best way to know is to
|
||||||
|
check with your store if it implements the `touch` method. If it does, then
|
||||||
|
you can safely set `resave: false`. If it does not implement the `touch`
|
||||||
|
method and your store sets an expiration date on stored sessions, then you
|
||||||
|
likely need `resave: true`.
|
||||||
|
|
||||||
|
##### rolling
|
||||||
|
|
||||||
|
Force the session identifier cookie to be set on every response. The expiration
|
||||||
|
is reset to the original [`maxAge`](#cookiemaxage), resetting the expiration
|
||||||
|
countdown.
|
||||||
|
|
||||||
|
The default value is `false`.
|
||||||
|
|
||||||
|
With this enabled, the session identifier cookie will expire in
|
||||||
|
[`maxAge`](#cookiemaxage) since the last response was sent instead of in
|
||||||
|
[`maxAge`](#cookiemaxage) since the session was last modified by the server.
|
||||||
|
|
||||||
|
This is typically used in conjuction with short, non-session-length
|
||||||
|
[`maxAge`](#cookiemaxage) values to provide a quick timeout of the session data
|
||||||
|
with reduced potential of it occurring during on going server interactions.
|
||||||
|
|
||||||
|
**Note** When this option is set to `true` but the `saveUninitialized` option is
|
||||||
|
set to `false`, the cookie will not be set on a response with an uninitialized
|
||||||
|
session. This option only modifies the behavior when an existing session was
|
||||||
|
loaded for the request.
|
||||||
|
|
||||||
|
##### saveUninitialized
|
||||||
|
|
||||||
|
Forces a session that is "uninitialized" to be saved to the store. A session is
|
||||||
|
uninitialized when it is new but not modified. Choosing `false` is useful for
|
||||||
|
implementing login sessions, reducing server storage usage, or complying with
|
||||||
|
laws that require permission before setting a cookie. Choosing `false` will also
|
||||||
|
help with race conditions where a client makes multiple parallel requests
|
||||||
|
without a session.
|
||||||
|
|
||||||
|
The default value is `true`, but using the default has been deprecated, as the
|
||||||
|
default will change in the future. Please research into this setting and
|
||||||
|
choose what is appropriate to your use-case.
|
||||||
|
|
||||||
|
**Note** if you are using Session in conjunction with PassportJS, Passport
|
||||||
|
will add an empty Passport object to the session for use after a user is
|
||||||
|
authenticated, which will be treated as a modification to the session, causing
|
||||||
|
it to be saved. *This has been fixed in PassportJS 0.3.0*
|
||||||
|
|
||||||
|
##### secret
|
||||||
|
|
||||||
|
**Required option**
|
||||||
|
|
||||||
|
This is the secret used to sign the session ID cookie. This can be either a string
|
||||||
|
for a single secret, or an array of multiple secrets. If an array of secrets is
|
||||||
|
provided, only the first element will be used to sign the session ID cookie, while
|
||||||
|
all the elements will be considered when verifying the signature in requests. The
|
||||||
|
secret itself should be not easily parsed by a human and would best be a random set
|
||||||
|
of characters. A best practice may include:
|
||||||
|
|
||||||
|
- The use of environment variables to store the secret, ensuring the secret itself
|
||||||
|
does not exist in your repository.
|
||||||
|
- Periodic updates of the secret, while ensuring the previous secret is in the
|
||||||
|
array.
|
||||||
|
|
||||||
|
Using a secret that cannot be guessed will reduce the ability to hijack a session to
|
||||||
|
only guessing the session ID (as determined by the `genid` option).
|
||||||
|
|
||||||
|
Changing the secret value will invalidate all existing sessions. In order to rotate
|
||||||
|
the secret without invalidating sessions, provide an array of secrets, with the new
|
||||||
|
secret as first element of the array, and including previous secrets as the later
|
||||||
|
elements.
|
||||||
|
|
||||||
|
##### store
|
||||||
|
|
||||||
|
The session store instance, defaults to a new `MemoryStore` instance.
|
||||||
|
|
||||||
|
##### unset
|
||||||
|
|
||||||
|
Control the result of unsetting `req.session` (through `delete`, setting to `null`,
|
||||||
|
etc.).
|
||||||
|
|
||||||
|
The default value is `'keep'`.
|
||||||
|
|
||||||
|
- `'destroy'` The session will be destroyed (deleted) when the response ends.
|
||||||
|
- `'keep'` The session in the store will be kept, but modifications made during
|
||||||
|
the request are ignored and not saved.
|
||||||
|
|
||||||
|
### req.session
|
||||||
|
|
||||||
|
To store or access session data, simply use the request property `req.session`,
|
||||||
|
which is (generally) serialized as JSON by the store, so nested objects
|
||||||
|
are typically fine. For example below is a user-specific view counter:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Use the session middleware
|
||||||
|
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
|
||||||
|
|
||||||
|
// Access the session as req.session
|
||||||
|
app.get('/', function(req, res, next) {
|
||||||
|
if (req.session.views) {
|
||||||
|
req.session.views++
|
||||||
|
res.setHeader('Content-Type', 'text/html')
|
||||||
|
res.write('<p>views: ' + req.session.views + '</p>')
|
||||||
|
res.write('<p>expires in: ' + (req.session.cookie.maxAge / 1000) + 's</p>')
|
||||||
|
res.end()
|
||||||
|
} else {
|
||||||
|
req.session.views = 1
|
||||||
|
res.end('welcome to the session demo. refresh!')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Session.regenerate(callback)
|
||||||
|
|
||||||
|
To regenerate the session simply invoke the method. Once complete,
|
||||||
|
a new SID and `Session` instance will be initialized at `req.session`
|
||||||
|
and the `callback` will be invoked.
|
||||||
|
|
||||||
|
```js
|
||||||
|
req.session.regenerate(function(err) {
|
||||||
|
// will have a new session here
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Session.destroy(callback)
|
||||||
|
|
||||||
|
Destroys the session and will unset the `req.session` property.
|
||||||
|
Once complete, the `callback` will be invoked.
|
||||||
|
|
||||||
|
```js
|
||||||
|
req.session.destroy(function(err) {
|
||||||
|
// cannot access session here
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Session.reload(callback)
|
||||||
|
|
||||||
|
Reloads the session data from the store and re-populates the
|
||||||
|
`req.session` object. Once complete, the `callback` will be invoked.
|
||||||
|
|
||||||
|
```js
|
||||||
|
req.session.reload(function(err) {
|
||||||
|
// session updated
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Session.save(callback)
|
||||||
|
|
||||||
|
Save the session back to the store, replacing the contents on the store with the
|
||||||
|
contents in memory (though a store may do something else--consult the store's
|
||||||
|
documentation for exact behavior).
|
||||||
|
|
||||||
|
This method is automatically called at the end of the HTTP response if the
|
||||||
|
session data has been altered (though this behavior can be altered with various
|
||||||
|
options in the middleware constructor). Because of this, typically this method
|
||||||
|
does not need to be called.
|
||||||
|
|
||||||
|
There are some cases where it is useful to call this method, for example,
|
||||||
|
redirects, long-lived requests or in WebSockets.
|
||||||
|
|
||||||
|
```js
|
||||||
|
req.session.save(function(err) {
|
||||||
|
// session saved
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Session.touch()
|
||||||
|
|
||||||
|
Updates the `.maxAge` property. Typically this is
|
||||||
|
not necessary to call, as the session middleware does this for you.
|
||||||
|
|
||||||
|
### req.session.id
|
||||||
|
|
||||||
|
Each session has a unique ID associated with it. This property is an
|
||||||
|
alias of [`req.sessionID`](#reqsessionid-1) and cannot be modified.
|
||||||
|
It has been added to make the session ID accessible from the `session`
|
||||||
|
object.
|
||||||
|
|
||||||
|
### req.session.cookie
|
||||||
|
|
||||||
|
Each session has a unique cookie object accompany it. This allows
|
||||||
|
you to alter the session cookie per visitor. For example we can
|
||||||
|
set `req.session.cookie.expires` to `false` to enable the cookie
|
||||||
|
to remain for only the duration of the user-agent.
|
||||||
|
|
||||||
|
#### Cookie.maxAge
|
||||||
|
|
||||||
|
Alternatively `req.session.cookie.maxAge` will return the time
|
||||||
|
remaining in milliseconds, which we may also re-assign a new value
|
||||||
|
to adjust the `.expires` property appropriately. The following
|
||||||
|
are essentially equivalent
|
||||||
|
|
||||||
|
```js
|
||||||
|
var hour = 3600000
|
||||||
|
req.session.cookie.expires = new Date(Date.now() + hour)
|
||||||
|
req.session.cookie.maxAge = hour
|
||||||
|
```
|
||||||
|
|
||||||
|
For example when `maxAge` is set to `60000` (one minute), and 30 seconds
|
||||||
|
has elapsed it will return `30000` until the current request has completed,
|
||||||
|
at which time `req.session.touch()` is called to reset
|
||||||
|
`req.session.cookie.maxAge` to its original value.
|
||||||
|
|
||||||
|
```js
|
||||||
|
req.session.cookie.maxAge // => 30000
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Cookie.originalMaxAge
|
||||||
|
|
||||||
|
The `req.session.cookie.originalMaxAge` property returns the original
|
||||||
|
`maxAge` (time-to-live), in milliseconds, of the session cookie.
|
||||||
|
|
||||||
|
### req.sessionID
|
||||||
|
|
||||||
|
To get the ID of the loaded session, access the request property
|
||||||
|
`req.sessionID`. This is simply a read-only value set when a session
|
||||||
|
is loaded/created.
|
||||||
|
|
||||||
|
## Session Store Implementation
|
||||||
|
|
||||||
|
Every session store _must_ be an `EventEmitter` and implement specific
|
||||||
|
methods. The following methods are the list of **required**, **recommended**,
|
||||||
|
and **optional**.
|
||||||
|
|
||||||
|
* Required methods are ones that this module will always call on the store.
|
||||||
|
* Recommended methods are ones that this module will call on the store if
|
||||||
|
available.
|
||||||
|
* Optional methods are ones this module does not call at all, but helps
|
||||||
|
present uniform stores to users.
|
||||||
|
|
||||||
|
For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo.
|
||||||
|
|
||||||
|
### store.all(callback)
|
||||||
|
|
||||||
|
**Optional**
|
||||||
|
|
||||||
|
This optional method is used to get all sessions in the store as an array. The
|
||||||
|
`callback` should be called as `callback(error, sessions)`.
|
||||||
|
|
||||||
|
### store.destroy(sid, callback)
|
||||||
|
|
||||||
|
**Required**
|
||||||
|
|
||||||
|
This required method is used to destroy/delete a session from the store given
|
||||||
|
a session ID (`sid`). The `callback` should be called as `callback(error)` once
|
||||||
|
the session is destroyed.
|
||||||
|
|
||||||
|
### store.clear(callback)
|
||||||
|
|
||||||
|
**Optional**
|
||||||
|
|
||||||
|
This optional method is used to delete all sessions from the store. The
|
||||||
|
`callback` should be called as `callback(error)` once the store is cleared.
|
||||||
|
|
||||||
|
### store.length(callback)
|
||||||
|
|
||||||
|
**Optional**
|
||||||
|
|
||||||
|
This optional method is used to get the count of all sessions in the store.
|
||||||
|
The `callback` should be called as `callback(error, len)`.
|
||||||
|
|
||||||
|
### store.get(sid, callback)
|
||||||
|
|
||||||
|
**Required**
|
||||||
|
|
||||||
|
This required method is used to get a session from the store given a session
|
||||||
|
ID (`sid`). The `callback` should be called as `callback(error, session)`.
|
||||||
|
|
||||||
|
The `session` argument should be a session if found, otherwise `null` or
|
||||||
|
`undefined` if the session was not found (and there was no error). A special
|
||||||
|
case is made when `error.code === 'ENOENT'` to act like `callback(null, null)`.
|
||||||
|
|
||||||
|
### store.set(sid, session, callback)
|
||||||
|
|
||||||
|
**Required**
|
||||||
|
|
||||||
|
This required method is used to upsert a session into the store given a
|
||||||
|
session ID (`sid`) and session (`session`) object. The callback should be
|
||||||
|
called as `callback(error)` once the session has been set in the store.
|
||||||
|
|
||||||
|
### store.touch(sid, session, callback)
|
||||||
|
|
||||||
|
**Recommended**
|
||||||
|
|
||||||
|
This recommended method is used to "touch" a given session given a
|
||||||
|
session ID (`sid`) and session (`session`) object. The `callback` should be
|
||||||
|
called as `callback(error)` once the session has been touched.
|
||||||
|
|
||||||
|
This is primarily used when the store will automatically delete idle sessions
|
||||||
|
and this method is used to signal to the store the given session is active,
|
||||||
|
potentially resetting the idle timer.
|
||||||
|
|
||||||
|
## Compatible Session Stores
|
||||||
|
|
||||||
|
The following modules implement a session store that is compatible with this
|
||||||
|
module. Please make a PR to add additional modules :)
|
||||||
|
|
||||||
|
[![★][aerospike-session-store-image] aerospike-session-store][aerospike-session-store-url] A session store using [Aerospike](http://www.aerospike.com/).
|
||||||
|
|
||||||
|
[aerospike-session-store-url]: https://www.npmjs.com/package/aerospike-session-store
|
||||||
|
[aerospike-session-store-image]: https://badgen.net/github/stars/aerospike/aerospike-session-store-expressjs?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][better-sqlite3-session-store-image] better-sqlite3-session-store][better-sqlite3-session-store-url] A session store based on [better-sqlite3](https://github.com/JoshuaWise/better-sqlite3).
|
||||||
|
|
||||||
|
[better-sqlite3-session-store-url]: https://www.npmjs.com/package/better-sqlite3-session-store
|
||||||
|
[better-sqlite3-session-store-image]: https://badgen.net/github/stars/timdaub/better-sqlite3-session-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][cassandra-store-image] cassandra-store][cassandra-store-url] An Apache Cassandra-based session store.
|
||||||
|
|
||||||
|
[cassandra-store-url]: https://www.npmjs.com/package/cassandra-store
|
||||||
|
[cassandra-store-image]: https://badgen.net/github/stars/webcc/cassandra-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][cluster-store-image] cluster-store][cluster-store-url] A wrapper for using in-process / embedded
|
||||||
|
stores - such as SQLite (via knex), leveldb, files, or memory - with node cluster (desirable for Raspberry Pi 2
|
||||||
|
and other multi-core embedded devices).
|
||||||
|
|
||||||
|
[cluster-store-url]: https://www.npmjs.com/package/cluster-store
|
||||||
|
[cluster-store-image]: https://badgen.net/github/stars/coolaj86/cluster-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-arango-image] connect-arango][connect-arango-url] An ArangoDB-based session store.
|
||||||
|
|
||||||
|
[connect-arango-url]: https://www.npmjs.com/package/connect-arango
|
||||||
|
[connect-arango-image]: https://badgen.net/github/stars/AlexanderArvidsson/connect-arango?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-azuretables-image] connect-azuretables][connect-azuretables-url] An [Azure Table Storage](https://azure.microsoft.com/en-gb/services/storage/tables/)-based session store.
|
||||||
|
|
||||||
|
[connect-azuretables-url]: https://www.npmjs.com/package/connect-azuretables
|
||||||
|
[connect-azuretables-image]: https://badgen.net/github/stars/mike-goodwin/connect-azuretables?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-cloudant-store-image] connect-cloudant-store][connect-cloudant-store-url] An [IBM Cloudant](https://cloudant.com/)-based session store.
|
||||||
|
|
||||||
|
[connect-cloudant-store-url]: https://www.npmjs.com/package/connect-cloudant-store
|
||||||
|
[connect-cloudant-store-image]: https://badgen.net/github/stars/adriantanasa/connect-cloudant-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-couchbase-image] connect-couchbase][connect-couchbase-url] A [couchbase](http://www.couchbase.com/)-based session store.
|
||||||
|
|
||||||
|
[connect-couchbase-url]: https://www.npmjs.com/package/connect-couchbase
|
||||||
|
[connect-couchbase-image]: https://badgen.net/github/stars/christophermina/connect-couchbase?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-datacache-image] connect-datacache][connect-datacache-url] An [IBM Bluemix Data Cache](http://www.ibm.com/cloud-computing/bluemix/)-based session store.
|
||||||
|
|
||||||
|
[connect-datacache-url]: https://www.npmjs.com/package/connect-datacache
|
||||||
|
[connect-datacache-image]: https://badgen.net/github/stars/adriantanasa/connect-datacache?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][@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.
|
||||||
|
|
||||||
|
[@google-cloud/connect-datastore-url]: https://www.npmjs.com/package/@google-cloud/connect-datastore
|
||||||
|
[@google-cloud/connect-datastore-image]: https://badgen.net/github/stars/GoogleCloudPlatform/cloud-datastore-session-node?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][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.
|
||||||
|
|
||||||
|
[connect-db2-url]: https://www.npmjs.com/package/connect-db2
|
||||||
|
[connect-db2-image]: https://badgen.net/github/stars/wallali/connect-db2?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-dynamodb-image] connect-dynamodb][connect-dynamodb-url] A DynamoDB-based session store.
|
||||||
|
|
||||||
|
[connect-dynamodb-url]: https://www.npmjs.com/package/connect-dynamodb
|
||||||
|
[connect-dynamodb-image]: https://badgen.net/github/stars/ca98am79/connect-dynamodb?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][@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.
|
||||||
|
|
||||||
|
[@google-cloud/connect-firestore-url]: https://www.npmjs.com/package/@google-cloud/connect-firestore
|
||||||
|
[@google-cloud/connect-firestore-image]: https://badgen.net/github/stars/googleapis/nodejs-firestore-session?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-hazelcast-image] connect-hazelcast][connect-hazelcast-url] Hazelcast session store for Connect and Express.
|
||||||
|
|
||||||
|
[connect-hazelcast-url]: https://www.npmjs.com/package/connect-hazelcast
|
||||||
|
[connect-hazelcast-image]: https://badgen.net/github/stars/huseyinbabal/connect-hazelcast?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-loki-image] connect-loki][connect-loki-url] A Loki.js-based session store.
|
||||||
|
|
||||||
|
[connect-loki-url]: https://www.npmjs.com/package/connect-loki
|
||||||
|
[connect-loki-image]: https://badgen.net/github/stars/Requarks/connect-loki?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-lowdb-image] connect-lowdb][connect-lowdb-url] A lowdb-based session store.
|
||||||
|
|
||||||
|
[connect-lowdb-url]: https://www.npmjs.com/package/connect-lowdb
|
||||||
|
[connect-lowdb-image]: https://badgen.net/github/stars/travishorn/connect-lowdb?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-memcached-image] connect-memcached][connect-memcached-url] A memcached-based session store.
|
||||||
|
|
||||||
|
[connect-memcached-url]: https://www.npmjs.com/package/connect-memcached
|
||||||
|
[connect-memcached-image]: https://badgen.net/github/stars/balor/connect-memcached?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-memjs-image] connect-memjs][connect-memjs-url] A memcached-based session store using
|
||||||
|
[memjs](https://www.npmjs.com/package/memjs) as the memcached client.
|
||||||
|
|
||||||
|
[connect-memjs-url]: https://www.npmjs.com/package/connect-memjs
|
||||||
|
[connect-memjs-image]: https://badgen.net/github/stars/liamdon/connect-memjs?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-ml-image] connect-ml][connect-ml-url] A MarkLogic Server-based session store.
|
||||||
|
|
||||||
|
[connect-ml-url]: https://www.npmjs.com/package/connect-ml
|
||||||
|
[connect-ml-image]: https://badgen.net/github/stars/bluetorch/connect-ml?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-monetdb-image] connect-monetdb][connect-monetdb-url] A MonetDB-based session store.
|
||||||
|
|
||||||
|
[connect-monetdb-url]: https://www.npmjs.com/package/connect-monetdb
|
||||||
|
[connect-monetdb-image]: https://badgen.net/github/stars/MonetDB/npm-connect-monetdb?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-mongo-image] connect-mongo][connect-mongo-url] A MongoDB-based session store.
|
||||||
|
|
||||||
|
[connect-mongo-url]: https://www.npmjs.com/package/connect-mongo
|
||||||
|
[connect-mongo-image]: https://badgen.net/github/stars/kcbanner/connect-mongo?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-mongodb-session-image] connect-mongodb-session][connect-mongodb-session-url] Lightweight MongoDB-based session store built and maintained by MongoDB.
|
||||||
|
|
||||||
|
[connect-mongodb-session-url]: https://www.npmjs.com/package/connect-mongodb-session
|
||||||
|
[connect-mongodb-session-image]: https://badgen.net/github/stars/mongodb-js/connect-mongodb-session?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-mssql-v2-image] connect-mssql-v2][connect-mssql-v2-url] A Microsoft SQL Server-based session store based on [connect-mssql](https://www.npmjs.com/package/connect-mssql).
|
||||||
|
|
||||||
|
[connect-mssql-v2-url]: https://www.npmjs.com/package/connect-mssql-v2
|
||||||
|
[connect-mssql-v2-image]: https://badgen.net/github/stars/jluboff/connect-mssql-v2?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-neo4j-image] connect-neo4j][connect-neo4j-url] A [Neo4j](https://neo4j.com)-based session store.
|
||||||
|
|
||||||
|
[connect-neo4j-url]: https://www.npmjs.com/package/connect-neo4j
|
||||||
|
[connect-neo4j-image]: https://badgen.net/github/stars/MaxAndersson/connect-neo4j?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-pg-simple-image] connect-pg-simple][connect-pg-simple-url] A PostgreSQL-based session store.
|
||||||
|
|
||||||
|
[connect-pg-simple-url]: https://www.npmjs.com/package/connect-pg-simple
|
||||||
|
[connect-pg-simple-image]: https://badgen.net/github/stars/voxpelli/node-connect-pg-simple?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-redis-image] connect-redis][connect-redis-url] A Redis-based session store.
|
||||||
|
|
||||||
|
[connect-redis-url]: https://www.npmjs.com/package/connect-redis
|
||||||
|
[connect-redis-image]: https://badgen.net/github/stars/tj/connect-redis?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][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/)
|
||||||
|
|
||||||
|
[connect-session-firebase-url]: https://www.npmjs.com/package/connect-session-firebase
|
||||||
|
[connect-session-firebase-image]: https://badgen.net/github/stars/benweier/connect-session-firebase?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-session-knex-image] connect-session-knex][connect-session-knex-url] A session store using
|
||||||
|
[Knex.js](http://knexjs.org/), which is a SQL query builder for PostgreSQL, MySQL, MariaDB, SQLite3, and Oracle.
|
||||||
|
|
||||||
|
[connect-session-knex-url]: https://www.npmjs.com/package/connect-session-knex
|
||||||
|
[connect-session-knex-image]: https://badgen.net/github/stars/llambda/connect-session-knex?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-session-sequelize-image] connect-session-sequelize][connect-session-sequelize-url] A session store using
|
||||||
|
[Sequelize.js](http://sequelizejs.com/), which is a Node.js / io.js ORM for PostgreSQL, MySQL, SQLite and MSSQL.
|
||||||
|
|
||||||
|
[connect-session-sequelize-url]: https://www.npmjs.com/package/connect-session-sequelize
|
||||||
|
[connect-session-sequelize-image]: https://badgen.net/github/stars/mweibel/connect-session-sequelize?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][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.
|
||||||
|
|
||||||
|
[connect-sqlite3-url]: https://www.npmjs.com/package/connect-sqlite3
|
||||||
|
[connect-sqlite3-image]: https://badgen.net/github/stars/rawberg/connect-sqlite3?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][connect-typeorm-image] connect-typeorm][connect-typeorm-url] A [TypeORM](https://github.com/typeorm/typeorm)-based session store.
|
||||||
|
|
||||||
|
[connect-typeorm-url]: https://www.npmjs.com/package/connect-typeorm
|
||||||
|
[connect-typeorm-image]: https://badgen.net/github/stars/makepost/connect-typeorm?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][couchdb-expression-image] couchdb-expression][couchdb-expression-url] A [CouchDB](https://couchdb.apache.org/)-based session store.
|
||||||
|
|
||||||
|
[couchdb-expression-url]: https://www.npmjs.com/package/couchdb-expression
|
||||||
|
[couchdb-expression-image]: https://badgen.net/github/stars/tkshnwesper/couchdb-expression?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][dynamodb-store-image] dynamodb-store][dynamodb-store-url] A DynamoDB-based session store.
|
||||||
|
|
||||||
|
[dynamodb-store-url]: https://www.npmjs.com/package/dynamodb-store
|
||||||
|
[dynamodb-store-image]: https://badgen.net/github/stars/rafaelrpinto/dynamodb-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][express-etcd-image] express-etcd][express-etcd-url] An [etcd](https://github.com/stianeikeland/node-etcd) based session store.
|
||||||
|
|
||||||
|
[express-etcd-url]: https://www.npmjs.com/package/express-etcd
|
||||||
|
[express-etcd-image]: https://badgen.net/github/stars/gildean/express-etcd?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][express-mysql-session-image] express-mysql-session][express-mysql-session-url] A session store using native
|
||||||
|
[MySQL](https://www.mysql.com/) via the [node-mysql](https://github.com/felixge/node-mysql) module.
|
||||||
|
|
||||||
|
[express-mysql-session-url]: https://www.npmjs.com/package/express-mysql-session
|
||||||
|
[express-mysql-session-image]: https://badgen.net/github/stars/chill117/express-mysql-session?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][express-nedb-session-image] express-nedb-session][express-nedb-session-url] A NeDB-based session store.
|
||||||
|
|
||||||
|
[express-nedb-session-url]: https://www.npmjs.com/package/express-nedb-session
|
||||||
|
[express-nedb-session-image]: https://badgen.net/github/stars/louischatriot/express-nedb-session?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][express-oracle-session-image] express-oracle-session][express-oracle-session-url] A session store using native
|
||||||
|
[oracle](https://www.oracle.com/) via the [node-oracledb](https://www.npmjs.com/package/oracledb) module.
|
||||||
|
|
||||||
|
[express-oracle-session-url]: https://www.npmjs.com/package/express-oracle-session
|
||||||
|
[express-oracle-session-image]: https://badgen.net/github/stars/slumber86/express-oracle-session?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][express-session-cache-manager-image] express-session-cache-manager][express-session-cache-manager-url]
|
||||||
|
A store that implements [cache-manager](https://www.npmjs.com/package/cache-manager), which supports
|
||||||
|
a [variety of storage types](https://www.npmjs.com/package/cache-manager#store-engines).
|
||||||
|
|
||||||
|
[express-session-cache-manager-url]: https://www.npmjs.com/package/express-session-cache-manager
|
||||||
|
[express-session-cache-manager-image]: https://badgen.net/github/stars/theogravity/express-session-cache-manager?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][express-session-etcd3-image] express-session-etcd3][express-session-etcd3-url] An [etcd3](https://github.com/mixer/etcd3) based session store.
|
||||||
|
|
||||||
|
[express-session-etcd3-url]: https://www.npmjs.com/package/express-session-etcd3
|
||||||
|
[express-session-etcd3-image]: https://badgen.net/github/stars/willgm/express-session-etcd3?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][express-session-level-image] express-session-level][express-session-level-url] A [LevelDB](https://github.com/Level/levelup) based session store.
|
||||||
|
|
||||||
|
[express-session-level-url]: https://www.npmjs.com/package/express-session-level
|
||||||
|
[express-session-level-image]: https://badgen.net/github/stars/tgohn/express-session-level?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][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.
|
||||||
|
|
||||||
|
[express-session-rsdb-url]: https://www.npmjs.com/package/express-session-rsdb
|
||||||
|
[express-session-rsdb-image]: https://badgen.net/github/stars/paragi/express-session-rsdb?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][express-sessions-image] express-sessions][express-sessions-url] A session store supporting both MongoDB and Redis.
|
||||||
|
|
||||||
|
[express-sessions-url]: https://www.npmjs.com/package/express-sessions
|
||||||
|
[express-sessions-image]: https://badgen.net/github/stars/konteck/express-sessions?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][firestore-store-image] firestore-store][firestore-store-url] A [Firestore](https://github.com/hendrysadrak/firestore-store)-based session store.
|
||||||
|
|
||||||
|
[firestore-store-url]: https://www.npmjs.com/package/firestore-store
|
||||||
|
[firestore-store-image]: https://badgen.net/github/stars/hendrysadrak/firestore-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][fortune-session-image] fortune-session][fortune-session-url] A [Fortune.js](https://github.com/fortunejs/fortune)
|
||||||
|
based session store. Supports all backends supported by Fortune (MongoDB, Redis, Postgres, NeDB).
|
||||||
|
|
||||||
|
[fortune-session-url]: https://www.npmjs.com/package/fortune-session
|
||||||
|
[fortune-session-image]: https://badgen.net/github/stars/aliceklipper/fortune-session?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][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).
|
||||||
|
|
||||||
|
[hazelcast-store-url]: https://www.npmjs.com/package/hazelcast-store
|
||||||
|
[hazelcast-store-image]: https://badgen.net/github/stars/jackspaniel/hazelcast-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][level-session-store-image] level-session-store][level-session-store-url] A LevelDB-based session store.
|
||||||
|
|
||||||
|
[level-session-store-url]: https://www.npmjs.com/package/level-session-store
|
||||||
|
[level-session-store-image]: https://badgen.net/github/stars/toddself/level-session-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][lowdb-session-store-image] lowdb-session-store][lowdb-session-store-url] A [lowdb](https://www.npmjs.com/package/lowdb)-based session store.
|
||||||
|
|
||||||
|
[lowdb-session-store-url]: https://www.npmjs.com/package/lowdb-session-store
|
||||||
|
[lowdb-session-store-image]: https://badgen.net/github/stars/fhellwig/lowdb-session-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][medea-session-store-image] medea-session-store][medea-session-store-url] A Medea-based session store.
|
||||||
|
|
||||||
|
[medea-session-store-url]: https://www.npmjs.com/package/medea-session-store
|
||||||
|
[medea-session-store-image]: https://badgen.net/github/stars/BenjaminVadant/medea-session-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][memorystore-image] memorystore][memorystore-url] A memory session store made for production.
|
||||||
|
|
||||||
|
[memorystore-url]: https://www.npmjs.com/package/memorystore
|
||||||
|
[memorystore-image]: https://badgen.net/github/stars/roccomuso/memorystore?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][mssql-session-store-image] mssql-session-store][mssql-session-store-url] A SQL Server-based session store.
|
||||||
|
|
||||||
|
[mssql-session-store-url]: https://www.npmjs.com/package/mssql-session-store
|
||||||
|
[mssql-session-store-image]: https://badgen.net/github/stars/jwathen/mssql-session-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][nedb-session-store-image] nedb-session-store][nedb-session-store-url] An alternate NeDB-based (either in-memory or file-persisted) session store.
|
||||||
|
|
||||||
|
[nedb-session-store-url]: https://www.npmjs.com/package/nedb-session-store
|
||||||
|
[nedb-session-store-image]: https://badgen.net/github/stars/JamesMGreene/nedb-session-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][@quixo3/prisma-session-store-image] @quixo3/prisma-session-store][@quixo3/prisma-session-store-url] A session store for the [Prisma Framework](https://www.prisma.io).
|
||||||
|
|
||||||
|
[@quixo3/prisma-session-store-url]: https://www.npmjs.com/package/@quixo3/prisma-session-store
|
||||||
|
[@quixo3/prisma-session-store-image]: https://badgen.net/github/stars/kleydon/prisma-session-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][restsession-image] restsession][restsession-url] Store sessions utilizing a RESTful API
|
||||||
|
|
||||||
|
[restsession-url]: https://www.npmjs.com/package/restsession
|
||||||
|
[restsession-image]: https://badgen.net/github/stars/jankal/restsession?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][sequelstore-connect-image] sequelstore-connect][sequelstore-connect-url] A session store using [Sequelize.js](http://sequelizejs.com/).
|
||||||
|
|
||||||
|
[sequelstore-connect-url]: https://www.npmjs.com/package/sequelstore-connect
|
||||||
|
[sequelstore-connect-image]: https://badgen.net/github/stars/MattMcFarland/sequelstore-connect?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][session-file-store-image] session-file-store][session-file-store-url] A file system-based session store.
|
||||||
|
|
||||||
|
[session-file-store-url]: https://www.npmjs.com/package/session-file-store
|
||||||
|
[session-file-store-image]: https://badgen.net/github/stars/valery-barysok/session-file-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][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.
|
||||||
|
|
||||||
|
[session-pouchdb-store-url]: https://www.npmjs.com/package/session-pouchdb-store
|
||||||
|
[session-pouchdb-store-image]: https://badgen.net/github/stars/solzimer/session-pouchdb-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][session-rethinkdb-image] session-rethinkdb][session-rethinkdb-url] A [RethinkDB](http://rethinkdb.com/)-based session store.
|
||||||
|
|
||||||
|
[session-rethinkdb-url]: https://www.npmjs.com/package/session-rethinkdb
|
||||||
|
[session-rethinkdb-image]: https://badgen.net/github/stars/llambda/session-rethinkdb?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][@databunker/session-store-image] @databunker/session-store][@databunker/session-store-url] A [Databunker](https://databunker.org/)-based encrypted session store.
|
||||||
|
|
||||||
|
[@databunker/session-store-url]: https://www.npmjs.com/package/@databunker/session-store
|
||||||
|
[@databunker/session-store-image]: https://badgen.net/github/stars/securitybunker/databunker-session-store?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][sessionstore-image] sessionstore][sessionstore-url] A session store that works with various databases.
|
||||||
|
|
||||||
|
[sessionstore-url]: https://www.npmjs.com/package/sessionstore
|
||||||
|
[sessionstore-image]: https://badgen.net/github/stars/adrai/sessionstore?label=%E2%98%85
|
||||||
|
|
||||||
|
[![★][tch-nedb-session-image] tch-nedb-session][tch-nedb-session-url] A file system session store based on NeDB.
|
||||||
|
|
||||||
|
[tch-nedb-session-url]: https://www.npmjs.com/package/tch-nedb-session
|
||||||
|
[tch-nedb-session-image]: https://badgen.net/github/stars/tomaschyly/NeDBSession?label=%E2%98%85
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### View counter
|
||||||
|
|
||||||
|
A simple example using `express-session` to store page views for a user.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var express = require('express')
|
||||||
|
var parseurl = require('parseurl')
|
||||||
|
var session = require('express-session')
|
||||||
|
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
app.use(session({
|
||||||
|
secret: 'keyboard cat',
|
||||||
|
resave: false,
|
||||||
|
saveUninitialized: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
app.use(function (req, res, next) {
|
||||||
|
if (!req.session.views) {
|
||||||
|
req.session.views = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the url pathname
|
||||||
|
var pathname = parseurl(req).pathname
|
||||||
|
|
||||||
|
// count the views
|
||||||
|
req.session.views[pathname] = (req.session.views[pathname] || 0) + 1
|
||||||
|
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/foo', function (req, res, next) {
|
||||||
|
res.send('you viewed this page ' + req.session.views['/foo'] + ' times')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/bar', function (req, res, next) {
|
||||||
|
res.send('you viewed this page ' + req.session.views['/bar'] + ' times')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(3000)
|
||||||
|
```
|
||||||
|
|
||||||
|
### User login
|
||||||
|
|
||||||
|
A simple example using `express-session` to keep a user log in session.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var escapeHtml = require('escape-html')
|
||||||
|
var express = require('express')
|
||||||
|
var session = require('express-session')
|
||||||
|
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
app.use(session({
|
||||||
|
secret: 'keyboard cat',
|
||||||
|
resave: false,
|
||||||
|
saveUninitialized: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
// middleware to test if authenticated
|
||||||
|
function isAuthenticated (req, res, next) {
|
||||||
|
if (req.session.user) next()
|
||||||
|
else next('route')
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/', isAuthenticated, function (req, res) {
|
||||||
|
// this is only called when there is an authentication user due to isAuthenticated
|
||||||
|
res.send('hello, ' + escapeHtml(req.session.user) + '!' +
|
||||||
|
' <a href="/logout">Logout</a>')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/', function (req, res) {
|
||||||
|
res.send('<form action="/login" method="post">' +
|
||||||
|
'Username: <input name="user"><br>' +
|
||||||
|
'Password: <input name="pass" type="password"><br>' +
|
||||||
|
'<input type="submit" text="Login"></form>')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/login', express.urlencoded({ extended: false }), function (req, res) {
|
||||||
|
// login logic to validate req.body.user and req.body.pass
|
||||||
|
// would be implemented here. for this example any combo works
|
||||||
|
|
||||||
|
// regenerate the session, which is good practice to help
|
||||||
|
// guard against forms of session fixation
|
||||||
|
req.session.regenerate(function (err) {
|
||||||
|
if (err) next(err)
|
||||||
|
|
||||||
|
// store user information in session, typically a user id
|
||||||
|
req.session.user = req.body.user
|
||||||
|
|
||||||
|
// save the session before redirection to ensure page
|
||||||
|
// load does not happen before session is saved
|
||||||
|
req.session.save(function (err) {
|
||||||
|
if (err) return next(err)
|
||||||
|
res.redirect('/')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/logout', function (req, res, next) {
|
||||||
|
// logout logic
|
||||||
|
|
||||||
|
// clear the user from the session object and save.
|
||||||
|
// this will ensure that re-using the old session id
|
||||||
|
// does not have a logged in user
|
||||||
|
req.session.user = null
|
||||||
|
req.session.save(function (err) {
|
||||||
|
if (err) next(err)
|
||||||
|
|
||||||
|
// regenerate the session, which is good practice to help
|
||||||
|
// guard against forms of session fixation
|
||||||
|
req.session.regenerate(function (err) {
|
||||||
|
if (err) next(err)
|
||||||
|
res.redirect('/')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(3000)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
This module uses the [debug](https://www.npmjs.com/package/debug) module
|
||||||
|
internally to log information about session operations.
|
||||||
|
|
||||||
|
To see all the internal logs, set the `DEBUG` environment variable to
|
||||||
|
`express-session` when launching your app (`npm start`, in this example):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ DEBUG=express-session npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows, use the corresponding command;
|
||||||
|
|
||||||
|
```sh
|
||||||
|
> set DEBUG=express-session & npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[rfc-6265bis-03-4.1.2.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7
|
||||||
|
[ci-image]: https://badgen.net/github/checks/expressjs/session/master?label=ci
|
||||||
|
[ci-url]: https://github.com/expressjs/session/actions?query=workflow%3Aci
|
||||||
|
[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/session/master
|
||||||
|
[coveralls-url]: https://coveralls.io/r/expressjs/session?branch=master
|
||||||
|
[node-url]: https://nodejs.org/en/download
|
||||||
|
[npm-downloads-image]: https://badgen.net/npm/dm/express-session
|
||||||
|
[npm-url]: https://npmjs.org/package/express-session
|
||||||
|
[npm-version-image]: https://badgen.net/npm/v/express-session
|
685
src/node_modules/express-session/index.js
generated
vendored
Normal file
685
src/node_modules/express-session/index.js
generated
vendored
Normal file
@ -0,0 +1,685 @@
|
|||||||
|
/*!
|
||||||
|
* express-session
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Buffer = require('safe-buffer').Buffer
|
||||||
|
var cookie = require('cookie');
|
||||||
|
var crypto = require('crypto')
|
||||||
|
var debug = require('debug')('express-session');
|
||||||
|
var deprecate = require('depd')('express-session');
|
||||||
|
var onHeaders = require('on-headers')
|
||||||
|
var parseUrl = require('parseurl');
|
||||||
|
var signature = require('cookie-signature')
|
||||||
|
var uid = require('uid-safe').sync
|
||||||
|
|
||||||
|
var Cookie = require('./session/cookie')
|
||||||
|
var MemoryStore = require('./session/memory')
|
||||||
|
var Session = require('./session/session')
|
||||||
|
var Store = require('./session/store')
|
||||||
|
|
||||||
|
// environment
|
||||||
|
|
||||||
|
var env = process.env.NODE_ENV;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose the middleware.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose constructors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.Store = Store;
|
||||||
|
exports.Cookie = Cookie;
|
||||||
|
exports.Session = Session;
|
||||||
|
exports.MemoryStore = MemoryStore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning message for `MemoryStore` usage in production.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var warning = 'Warning: connect.session() MemoryStore is not\n'
|
||||||
|
+ 'designed for a production environment, as it will leak\n'
|
||||||
|
+ 'memory, and will not scale past a single process.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node.js 0.8+ async implementation.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
var defer = typeof setImmediate === 'function'
|
||||||
|
? setImmediate
|
||||||
|
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup session store with the given `options`.
|
||||||
|
*
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {Object} [options.cookie] Options for cookie
|
||||||
|
* @param {Function} [options.genid]
|
||||||
|
* @param {String} [options.name=connect.sid] Session ID cookie name
|
||||||
|
* @param {Boolean} [options.proxy]
|
||||||
|
* @param {Boolean} [options.resave] Resave unmodified sessions back to the store
|
||||||
|
* @param {Boolean} [options.rolling] Enable/disable rolling session expiration
|
||||||
|
* @param {Boolean} [options.saveUninitialized] Save uninitialized sessions to the store
|
||||||
|
* @param {String|Array} [options.secret] Secret for signing session ID
|
||||||
|
* @param {Object} [options.store=MemoryStore] Session store
|
||||||
|
* @param {String} [options.unset]
|
||||||
|
* @return {Function} middleware
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function session(options) {
|
||||||
|
var opts = options || {}
|
||||||
|
|
||||||
|
// get the cookie options
|
||||||
|
var cookieOptions = opts.cookie || {}
|
||||||
|
|
||||||
|
// get the session id generate function
|
||||||
|
var generateId = opts.genid || generateSessionId
|
||||||
|
|
||||||
|
// get the session cookie name
|
||||||
|
var name = opts.name || opts.key || 'connect.sid'
|
||||||
|
|
||||||
|
// get the session store
|
||||||
|
var store = opts.store || new MemoryStore()
|
||||||
|
|
||||||
|
// get the trust proxy setting
|
||||||
|
var trustProxy = opts.proxy
|
||||||
|
|
||||||
|
// get the resave session option
|
||||||
|
var resaveSession = opts.resave;
|
||||||
|
|
||||||
|
// get the rolling session option
|
||||||
|
var rollingSessions = Boolean(opts.rolling)
|
||||||
|
|
||||||
|
// get the save uninitialized session option
|
||||||
|
var saveUninitializedSession = opts.saveUninitialized
|
||||||
|
|
||||||
|
// get the cookie signing secret
|
||||||
|
var secret = opts.secret
|
||||||
|
|
||||||
|
if (typeof generateId !== 'function') {
|
||||||
|
throw new TypeError('genid option must be a function');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resaveSession === undefined) {
|
||||||
|
deprecate('undefined resave option; provide resave option');
|
||||||
|
resaveSession = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saveUninitializedSession === undefined) {
|
||||||
|
deprecate('undefined saveUninitialized option; provide saveUninitialized option');
|
||||||
|
saveUninitializedSession = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.unset && opts.unset !== 'destroy' && opts.unset !== 'keep') {
|
||||||
|
throw new TypeError('unset option must be "destroy" or "keep"');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: switch to "destroy" on next major
|
||||||
|
var unsetDestroy = opts.unset === 'destroy'
|
||||||
|
|
||||||
|
if (Array.isArray(secret) && secret.length === 0) {
|
||||||
|
throw new TypeError('secret option array must contain one or more strings');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secret && !Array.isArray(secret)) {
|
||||||
|
secret = [secret];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secret) {
|
||||||
|
deprecate('req.secret; provide secret option');
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify user that this store is not
|
||||||
|
// meant for a production environment
|
||||||
|
/* istanbul ignore next: not tested */
|
||||||
|
if (env === 'production' && store instanceof MemoryStore) {
|
||||||
|
console.warn(warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
// generates the new session
|
||||||
|
store.generate = function(req){
|
||||||
|
req.sessionID = generateId(req);
|
||||||
|
req.session = new Session(req);
|
||||||
|
req.session.cookie = new Cookie(cookieOptions);
|
||||||
|
|
||||||
|
if (cookieOptions.secure === 'auto') {
|
||||||
|
req.session.cookie.secure = issecure(req, trustProxy);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var storeImplementsTouch = typeof store.touch === 'function';
|
||||||
|
|
||||||
|
// register event listeners for the store to track readiness
|
||||||
|
var storeReady = true
|
||||||
|
store.on('disconnect', function ondisconnect() {
|
||||||
|
storeReady = false
|
||||||
|
})
|
||||||
|
store.on('connect', function onconnect() {
|
||||||
|
storeReady = true
|
||||||
|
})
|
||||||
|
|
||||||
|
return function session(req, res, next) {
|
||||||
|
// self-awareness
|
||||||
|
if (req.session) {
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle connection as if there is no session if
|
||||||
|
// the store has temporarily disconnected etc
|
||||||
|
if (!storeReady) {
|
||||||
|
debug('store is disconnected')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathname mismatch
|
||||||
|
var originalPath = parseUrl.original(req).pathname || '/'
|
||||||
|
if (originalPath.indexOf(cookieOptions.path || '/') !== 0) return next();
|
||||||
|
|
||||||
|
// ensure a secret is available or bail
|
||||||
|
if (!secret && !req.secret) {
|
||||||
|
next(new Error('secret option required for sessions'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// backwards compatibility for signed cookies
|
||||||
|
// req.secret is passed from the cookie parser middleware
|
||||||
|
var secrets = secret || [req.secret];
|
||||||
|
|
||||||
|
var originalHash;
|
||||||
|
var originalId;
|
||||||
|
var savedHash;
|
||||||
|
var touched = false
|
||||||
|
|
||||||
|
// expose store
|
||||||
|
req.sessionStore = store;
|
||||||
|
|
||||||
|
// get the session ID from the cookie
|
||||||
|
var cookieId = req.sessionID = getcookie(req, name, secrets);
|
||||||
|
|
||||||
|
// set-cookie
|
||||||
|
onHeaders(res, function(){
|
||||||
|
if (!req.session) {
|
||||||
|
debug('no session');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldSetCookie(req)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only send secure cookies via https
|
||||||
|
if (req.session.cookie.secure && !issecure(req, trustProxy)) {
|
||||||
|
debug('not secured');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!touched) {
|
||||||
|
// touch session
|
||||||
|
req.session.touch()
|
||||||
|
touched = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// set cookie
|
||||||
|
setcookie(res, name, req.sessionID, secrets[0], req.session.cookie.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
// proxy end() to commit the session
|
||||||
|
var _end = res.end;
|
||||||
|
var _write = res.write;
|
||||||
|
var ended = false;
|
||||||
|
res.end = function end(chunk, encoding) {
|
||||||
|
if (ended) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ended = true;
|
||||||
|
|
||||||
|
var ret;
|
||||||
|
var sync = true;
|
||||||
|
|
||||||
|
function writeend() {
|
||||||
|
if (sync) {
|
||||||
|
ret = _end.call(res, chunk, encoding);
|
||||||
|
sync = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_end.call(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writetop() {
|
||||||
|
if (!sync) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res._header) {
|
||||||
|
res._implicitHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunk == null) {
|
||||||
|
ret = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentLength = Number(res.getHeader('Content-Length'));
|
||||||
|
|
||||||
|
if (!isNaN(contentLength) && contentLength > 0) {
|
||||||
|
// measure chunk
|
||||||
|
chunk = !Buffer.isBuffer(chunk)
|
||||||
|
? Buffer.from(chunk, encoding)
|
||||||
|
: chunk;
|
||||||
|
encoding = undefined;
|
||||||
|
|
||||||
|
if (chunk.length !== 0) {
|
||||||
|
debug('split response');
|
||||||
|
ret = _write.call(res, chunk.slice(0, chunk.length - 1));
|
||||||
|
chunk = chunk.slice(chunk.length - 1, chunk.length);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = _write.call(res, chunk, encoding);
|
||||||
|
sync = false;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldDestroy(req)) {
|
||||||
|
// destroy session
|
||||||
|
debug('destroying');
|
||||||
|
store.destroy(req.sessionID, function ondestroy(err) {
|
||||||
|
if (err) {
|
||||||
|
defer(next, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('destroyed');
|
||||||
|
writeend();
|
||||||
|
});
|
||||||
|
|
||||||
|
return writetop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// no session to save
|
||||||
|
if (!req.session) {
|
||||||
|
debug('no session');
|
||||||
|
return _end.call(res, chunk, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!touched) {
|
||||||
|
// touch session
|
||||||
|
req.session.touch()
|
||||||
|
touched = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSave(req)) {
|
||||||
|
req.session.save(function onsave(err) {
|
||||||
|
if (err) {
|
||||||
|
defer(next, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeend();
|
||||||
|
});
|
||||||
|
|
||||||
|
return writetop();
|
||||||
|
} else if (storeImplementsTouch && shouldTouch(req)) {
|
||||||
|
// store implements touch method
|
||||||
|
debug('touching');
|
||||||
|
store.touch(req.sessionID, req.session, function ontouch(err) {
|
||||||
|
if (err) {
|
||||||
|
defer(next, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('touched');
|
||||||
|
writeend();
|
||||||
|
});
|
||||||
|
|
||||||
|
return writetop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _end.call(res, chunk, encoding);
|
||||||
|
};
|
||||||
|
|
||||||
|
// generate the session
|
||||||
|
function generate() {
|
||||||
|
store.generate(req);
|
||||||
|
originalId = req.sessionID;
|
||||||
|
originalHash = hash(req.session);
|
||||||
|
wrapmethods(req.session);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inflate the session
|
||||||
|
function inflate (req, sess) {
|
||||||
|
store.createSession(req, sess)
|
||||||
|
originalId = req.sessionID
|
||||||
|
originalHash = hash(sess)
|
||||||
|
|
||||||
|
if (!resaveSession) {
|
||||||
|
savedHash = originalHash
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapmethods(req.session)
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewrapmethods (sess, callback) {
|
||||||
|
return function () {
|
||||||
|
if (req.session !== sess) {
|
||||||
|
wrapmethods(req.session)
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.apply(this, arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap session methods
|
||||||
|
function wrapmethods(sess) {
|
||||||
|
var _reload = sess.reload
|
||||||
|
var _save = sess.save;
|
||||||
|
|
||||||
|
function reload(callback) {
|
||||||
|
debug('reloading %s', this.id)
|
||||||
|
_reload.call(this, rewrapmethods(this, callback))
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
debug('saving %s', this.id);
|
||||||
|
savedHash = hash(this);
|
||||||
|
_save.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(sess, 'reload', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
value: reload,
|
||||||
|
writable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(sess, 'save', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
value: save,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if session has been modified
|
||||||
|
function isModified(sess) {
|
||||||
|
return originalId !== sess.id || originalHash !== hash(sess);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if session has been saved
|
||||||
|
function isSaved(sess) {
|
||||||
|
return originalId === sess.id && savedHash === hash(sess);
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine if session should be destroyed
|
||||||
|
function shouldDestroy(req) {
|
||||||
|
return req.sessionID && unsetDestroy && req.session == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine if session should be saved to store
|
||||||
|
function shouldSave(req) {
|
||||||
|
// cannot set cookie without a session ID
|
||||||
|
if (typeof req.sessionID !== 'string') {
|
||||||
|
debug('session ignored because of bogus req.sessionID %o', req.sessionID);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !saveUninitializedSession && !savedHash && cookieId !== req.sessionID
|
||||||
|
? isModified(req.session)
|
||||||
|
: !isSaved(req.session)
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine if session should be touched
|
||||||
|
function shouldTouch(req) {
|
||||||
|
// cannot set cookie without a session ID
|
||||||
|
if (typeof req.sessionID !== 'string') {
|
||||||
|
debug('session ignored because of bogus req.sessionID %o', req.sessionID);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cookieId === req.sessionID && !shouldSave(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine if cookie should be set on response
|
||||||
|
function shouldSetCookie(req) {
|
||||||
|
// cannot set cookie without a session ID
|
||||||
|
if (typeof req.sessionID !== 'string') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cookieId !== req.sessionID
|
||||||
|
? saveUninitializedSession || isModified(req.session)
|
||||||
|
: rollingSessions || req.session.cookie.expires != null && isModified(req.session);
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a session if the browser doesn't send a sessionID
|
||||||
|
if (!req.sessionID) {
|
||||||
|
debug('no SID sent, generating session');
|
||||||
|
generate();
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate the session object
|
||||||
|
debug('fetching %s', req.sessionID);
|
||||||
|
store.get(req.sessionID, function(err, sess){
|
||||||
|
// error handling
|
||||||
|
if (err && err.code !== 'ENOENT') {
|
||||||
|
debug('error %j', err);
|
||||||
|
next(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (err || !sess) {
|
||||||
|
debug('no session found')
|
||||||
|
generate()
|
||||||
|
} else {
|
||||||
|
debug('session found')
|
||||||
|
inflate(req, sess)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
next(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a session ID for a new session.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function generateSessionId(sess) {
|
||||||
|
return uid(24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the session ID cookie from request.
|
||||||
|
*
|
||||||
|
* @return {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getcookie(req, name, secrets) {
|
||||||
|
var header = req.headers.cookie;
|
||||||
|
var raw;
|
||||||
|
var val;
|
||||||
|
|
||||||
|
// read from cookie header
|
||||||
|
if (header) {
|
||||||
|
var cookies = cookie.parse(header);
|
||||||
|
|
||||||
|
raw = cookies[name];
|
||||||
|
|
||||||
|
if (raw) {
|
||||||
|
if (raw.substr(0, 2) === 's:') {
|
||||||
|
val = unsigncookie(raw.slice(2), secrets);
|
||||||
|
|
||||||
|
if (val === false) {
|
||||||
|
debug('cookie signature invalid');
|
||||||
|
val = undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug('cookie unsigned')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// back-compat read from cookieParser() signedCookies data
|
||||||
|
if (!val && req.signedCookies) {
|
||||||
|
val = req.signedCookies[name];
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
deprecate('cookie should be available in req.headers.cookie');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// back-compat read from cookieParser() cookies data
|
||||||
|
if (!val && req.cookies) {
|
||||||
|
raw = req.cookies[name];
|
||||||
|
|
||||||
|
if (raw) {
|
||||||
|
if (raw.substr(0, 2) === 's:') {
|
||||||
|
val = unsigncookie(raw.slice(2), secrets);
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
deprecate('cookie should be available in req.headers.cookie');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val === false) {
|
||||||
|
debug('cookie signature invalid');
|
||||||
|
val = undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug('cookie unsigned')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash the given `sess` object omitting changes to `.cookie`.
|
||||||
|
*
|
||||||
|
* @param {Object} sess
|
||||||
|
* @return {String}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function hash(sess) {
|
||||||
|
// serialize
|
||||||
|
var str = JSON.stringify(sess, function (key, val) {
|
||||||
|
// ignore sess.cookie property
|
||||||
|
if (this === sess && key === 'cookie') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return val
|
||||||
|
})
|
||||||
|
|
||||||
|
// hash
|
||||||
|
return crypto
|
||||||
|
.createHash('sha1')
|
||||||
|
.update(str, 'utf8')
|
||||||
|
.digest('hex')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if request is secure.
|
||||||
|
*
|
||||||
|
* @param {Object} req
|
||||||
|
* @param {Boolean} [trustProxy]
|
||||||
|
* @return {Boolean}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function issecure(req, trustProxy) {
|
||||||
|
// socket is https server
|
||||||
|
if (req.connection && req.connection.encrypted) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do not trust proxy
|
||||||
|
if (trustProxy === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no explicit trust; try req.secure from express
|
||||||
|
if (trustProxy !== true) {
|
||||||
|
return req.secure === true
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the proto from x-forwarded-proto header
|
||||||
|
var header = req.headers['x-forwarded-proto'] || '';
|
||||||
|
var index = header.indexOf(',');
|
||||||
|
var proto = index !== -1
|
||||||
|
? header.substr(0, index).toLowerCase().trim()
|
||||||
|
: header.toLowerCase().trim()
|
||||||
|
|
||||||
|
return proto === 'https';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set cookie on response.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function setcookie(res, name, val, secret, options) {
|
||||||
|
var signed = 's:' + signature.sign(val, secret);
|
||||||
|
var data = cookie.serialize(name, signed, options);
|
||||||
|
|
||||||
|
debug('set-cookie %s', data);
|
||||||
|
|
||||||
|
var prev = res.getHeader('Set-Cookie') || []
|
||||||
|
var header = Array.isArray(prev) ? prev.concat(data) : [prev, data];
|
||||||
|
|
||||||
|
res.setHeader('Set-Cookie', header)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify and decode the given `val` with `secrets`.
|
||||||
|
*
|
||||||
|
* @param {String} val
|
||||||
|
* @param {Array} secrets
|
||||||
|
* @returns {String|Boolean}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function unsigncookie(val, secrets) {
|
||||||
|
for (var i = 0; i < secrets.length; i++) {
|
||||||
|
var result = signature.unsign(val, secrets[i]);
|
||||||
|
|
||||||
|
if (result !== false) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
134
src/node_modules/express-session/node_modules/cookie/HISTORY.md
generated
vendored
Normal file
134
src/node_modules/express-session/node_modules/cookie/HISTORY.md
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
0.4.2 / 2022-02-02
|
||||||
|
==================
|
||||||
|
|
||||||
|
* pref: read value only when assigning in parse
|
||||||
|
* pref: remove unnecessary regexp in parse
|
||||||
|
|
||||||
|
0.4.1 / 2020-04-21
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix `maxAge` option to reject invalid values
|
||||||
|
|
||||||
|
0.4.0 / 2019-05-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `SameSite=None` support
|
||||||
|
|
||||||
|
0.3.1 / 2016-05-26
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix `sameSite: true` to work with draft-7 clients
|
||||||
|
- `true` now sends `SameSite=Strict` instead of `SameSite`
|
||||||
|
|
||||||
|
0.3.0 / 2016-05-26
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `sameSite` option
|
||||||
|
- Replaces `firstPartyOnly` option, never implemented by browsers
|
||||||
|
* Improve error message when `encode` is not a function
|
||||||
|
* Improve error message when `expires` is not a `Date`
|
||||||
|
|
||||||
|
0.2.4 / 2016-05-20
|
||||||
|
==================
|
||||||
|
|
||||||
|
* perf: enable strict mode
|
||||||
|
* perf: use for loop in parse
|
||||||
|
* perf: use string concatination for serialization
|
||||||
|
|
||||||
|
0.2.3 / 2015-10-25
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix cookie `Max-Age` to never be a floating point number
|
||||||
|
|
||||||
|
0.2.2 / 2015-09-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix regression when setting empty cookie value
|
||||||
|
- Ease the new restriction, which is just basic header-level validation
|
||||||
|
* Fix typo in invalid value errors
|
||||||
|
|
||||||
|
0.2.1 / 2015-09-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Throw on invalid values provided to `serialize`
|
||||||
|
- Ensures the resulting string is a valid HTTP header value
|
||||||
|
|
||||||
|
0.2.0 / 2015-08-13
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `firstPartyOnly` option
|
||||||
|
* Throw better error for invalid argument to parse
|
||||||
|
* perf: hoist regular expression
|
||||||
|
|
||||||
|
0.1.5 / 2015-09-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix regression when setting empty cookie value
|
||||||
|
- Ease the new restriction, which is just basic header-level validation
|
||||||
|
* Fix typo in invalid value errors
|
||||||
|
|
||||||
|
0.1.4 / 2015-09-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Throw better error for invalid argument to parse
|
||||||
|
* Throw on invalid values provided to `serialize`
|
||||||
|
- Ensures the resulting string is a valid HTTP header value
|
||||||
|
|
||||||
|
0.1.3 / 2015-05-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Reduce the scope of try-catch deopt
|
||||||
|
* Remove argument reassignments
|
||||||
|
|
||||||
|
0.1.2 / 2014-04-16
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Remove unnecessary files from npm package
|
||||||
|
|
||||||
|
0.1.1 / 2014-02-23
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix bad parse when cookie value contained a comma
|
||||||
|
* Fix support for `maxAge` of `0`
|
||||||
|
|
||||||
|
0.1.0 / 2013-05-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `decode` option
|
||||||
|
* Add `encode` option
|
||||||
|
|
||||||
|
0.0.6 / 2013-04-08
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Ignore cookie parts missing `=`
|
||||||
|
|
||||||
|
0.0.5 / 2012-10-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Return raw cookie value if value unescape errors
|
||||||
|
|
||||||
|
0.0.4 / 2012-06-21
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Use encode/decodeURIComponent for cookie encoding/decoding
|
||||||
|
- Improve server/client interoperability
|
||||||
|
|
||||||
|
0.0.3 / 2012-06-06
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Only escape special characters per the cookie RFC
|
||||||
|
|
||||||
|
0.0.2 / 2012-06-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix `maxAge` option to not throw error
|
||||||
|
|
||||||
|
0.0.1 / 2012-05-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add more tests
|
||||||
|
|
||||||
|
0.0.0 / 2012-05-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial release
|
24
src/node_modules/express-session/node_modules/cookie/LICENSE
generated
vendored
Normal file
24
src/node_modules/express-session/node_modules/cookie/LICENSE
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2012-2014 Roman Shtylman <shtylman@gmail.com>
|
||||||
|
Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
286
src/node_modules/express-session/node_modules/cookie/README.md
generated
vendored
Normal file
286
src/node_modules/express-session/node_modules/cookie/README.md
generated
vendored
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
# cookie
|
||||||
|
|
||||||
|
[![NPM Version][npm-version-image]][npm-url]
|
||||||
|
[![NPM Downloads][npm-downloads-image]][npm-url]
|
||||||
|
[![Node.js Version][node-version-image]][node-version-url]
|
||||||
|
[![Build Status][github-actions-ci-image]][github-actions-ci-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
Basic HTTP cookie parser and serializer for HTTP servers.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||||
|
[npm registry](https://www.npmjs.com/). Installation is done using the
|
||||||
|
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install cookie
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```js
|
||||||
|
var cookie = require('cookie');
|
||||||
|
```
|
||||||
|
|
||||||
|
### cookie.parse(str, options)
|
||||||
|
|
||||||
|
Parse an HTTP `Cookie` header string and returning an object of all cookie name-value pairs.
|
||||||
|
The `str` argument is the string representing a `Cookie` header value and `options` is an
|
||||||
|
optional object containing additional parsing options.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var cookies = cookie.parse('foo=bar; equation=E%3Dmc%5E2');
|
||||||
|
// { foo: 'bar', equation: 'E=mc^2' }
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
`cookie.parse` accepts these properties in the options object.
|
||||||
|
|
||||||
|
##### decode
|
||||||
|
|
||||||
|
Specifies a function that will be used to decode a cookie's value. Since the value of a cookie
|
||||||
|
has a limited character set (and must be a simple string), this function can be used to decode
|
||||||
|
a previously-encoded cookie value into a JavaScript string or other object.
|
||||||
|
|
||||||
|
The default function is the global `decodeURIComponent`, which will decode any URL-encoded
|
||||||
|
sequences into their byte representations.
|
||||||
|
|
||||||
|
**note** if an error is thrown from this function, the original, non-decoded cookie value will
|
||||||
|
be returned as the cookie's value.
|
||||||
|
|
||||||
|
### cookie.serialize(name, value, options)
|
||||||
|
|
||||||
|
Serialize a cookie name-value pair into a `Set-Cookie` header string. The `name` argument is the
|
||||||
|
name for the cookie, the `value` argument is the value to set the cookie to, and the `options`
|
||||||
|
argument is an optional object containing additional serialization options.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var setCookie = cookie.serialize('foo', 'bar');
|
||||||
|
// foo=bar
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
`cookie.serialize` accepts these properties in the options object.
|
||||||
|
|
||||||
|
##### domain
|
||||||
|
|
||||||
|
Specifies the value for the [`Domain` `Set-Cookie` attribute][rfc-6265-5.2.3]. By default, no
|
||||||
|
domain is set, and most clients will consider the cookie to apply to only the current domain.
|
||||||
|
|
||||||
|
##### encode
|
||||||
|
|
||||||
|
Specifies a function that will be used to encode a cookie's value. Since value of a cookie
|
||||||
|
has a limited character set (and must be a simple string), this function can be used to encode
|
||||||
|
a value into a string suited for a cookie's value.
|
||||||
|
|
||||||
|
The default function is the global `encodeURIComponent`, which will encode a JavaScript string
|
||||||
|
into UTF-8 byte sequences and then URL-encode any that fall outside of the cookie range.
|
||||||
|
|
||||||
|
##### expires
|
||||||
|
|
||||||
|
Specifies the `Date` object to be the value for the [`Expires` `Set-Cookie` attribute][rfc-6265-5.2.1].
|
||||||
|
By default, no expiration is set, and most clients will consider this a "non-persistent cookie" and
|
||||||
|
will delete it on a condition like exiting a web browser application.
|
||||||
|
|
||||||
|
**note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and
|
||||||
|
`maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,
|
||||||
|
so if both are set, they should point to the same date and time.
|
||||||
|
|
||||||
|
##### httpOnly
|
||||||
|
|
||||||
|
Specifies the `boolean` value for the [`HttpOnly` `Set-Cookie` attribute][rfc-6265-5.2.6]. When truthy,
|
||||||
|
the `HttpOnly` attribute is set, otherwise it is not. By default, the `HttpOnly` attribute is not set.
|
||||||
|
|
||||||
|
**note** be careful when setting this to `true`, as compliant clients will not allow client-side
|
||||||
|
JavaScript to see the cookie in `document.cookie`.
|
||||||
|
|
||||||
|
##### maxAge
|
||||||
|
|
||||||
|
Specifies the `number` (in seconds) to be the value for the [`Max-Age` `Set-Cookie` attribute][rfc-6265-5.2.2].
|
||||||
|
The given number will be converted to an integer by rounding down. By default, no maximum age is set.
|
||||||
|
|
||||||
|
**note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and
|
||||||
|
`maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,
|
||||||
|
so if both are set, they should point to the same date and time.
|
||||||
|
|
||||||
|
##### path
|
||||||
|
|
||||||
|
Specifies the value for the [`Path` `Set-Cookie` attribute][rfc-6265-5.2.4]. By default, the path
|
||||||
|
is considered the ["default path"][rfc-6265-5.1.4].
|
||||||
|
|
||||||
|
##### sameSite
|
||||||
|
|
||||||
|
Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute][rfc-6265bis-03-4.1.2.7].
|
||||||
|
|
||||||
|
- `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
|
||||||
|
- `false` will not set the `SameSite` attribute.
|
||||||
|
- `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
|
||||||
|
- `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
|
||||||
|
- `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
|
||||||
|
|
||||||
|
More information about the different enforcement levels can be found in
|
||||||
|
[the specification][rfc-6265bis-03-4.1.2.7].
|
||||||
|
|
||||||
|
**note** This is an attribute that has not yet been fully standardized, and may change in the future.
|
||||||
|
This also means many clients may ignore this attribute until they understand it.
|
||||||
|
|
||||||
|
##### secure
|
||||||
|
|
||||||
|
Specifies the `boolean` value for the [`Secure` `Set-Cookie` attribute][rfc-6265-5.2.5]. When truthy,
|
||||||
|
the `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set.
|
||||||
|
|
||||||
|
**note** be careful when setting this to `true`, as compliant clients will not send the cookie back to
|
||||||
|
the server in the future if the browser does not have an HTTPS connection.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
The following example uses this module in conjunction with the Node.js core HTTP server
|
||||||
|
to prompt a user for their name and display it back on future visits.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var cookie = require('cookie');
|
||||||
|
var escapeHtml = require('escape-html');
|
||||||
|
var http = require('http');
|
||||||
|
var url = require('url');
|
||||||
|
|
||||||
|
function onRequest(req, res) {
|
||||||
|
// Parse the query string
|
||||||
|
var query = url.parse(req.url, true, true).query;
|
||||||
|
|
||||||
|
if (query && query.name) {
|
||||||
|
// Set a new cookie with the name
|
||||||
|
res.setHeader('Set-Cookie', cookie.serialize('name', String(query.name), {
|
||||||
|
httpOnly: true,
|
||||||
|
maxAge: 60 * 60 * 24 * 7 // 1 week
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Redirect back after setting cookie
|
||||||
|
res.statusCode = 302;
|
||||||
|
res.setHeader('Location', req.headers.referer || '/');
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the cookies on the request
|
||||||
|
var cookies = cookie.parse(req.headers.cookie || '');
|
||||||
|
|
||||||
|
// Get the visitor name set in the cookie
|
||||||
|
var name = cookies.name;
|
||||||
|
|
||||||
|
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
res.write('<p>Welcome back, <b>' + escapeHtml(name) + '</b>!</p>');
|
||||||
|
} else {
|
||||||
|
res.write('<p>Hello, new visitor!</p>');
|
||||||
|
}
|
||||||
|
|
||||||
|
res.write('<form method="GET">');
|
||||||
|
res.write('<input placeholder="enter your name" name="name"> <input type="submit" value="Set Name">');
|
||||||
|
res.end('</form>');
|
||||||
|
}
|
||||||
|
|
||||||
|
http.createServer(onRequest).listen(3000);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Benchmark
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm run bench
|
||||||
|
|
||||||
|
> cookie@0.4.1 bench
|
||||||
|
> node benchmark/index.js
|
||||||
|
|
||||||
|
node@16.13.1
|
||||||
|
v8@9.4.146.24-node.14
|
||||||
|
uv@1.42.0
|
||||||
|
zlib@1.2.11
|
||||||
|
brotli@1.0.9
|
||||||
|
ares@1.18.1
|
||||||
|
modules@93
|
||||||
|
nghttp2@1.45.1
|
||||||
|
napi@8
|
||||||
|
llhttp@6.0.4
|
||||||
|
openssl@1.1.1l+quic
|
||||||
|
cldr@39.0
|
||||||
|
icu@69.1
|
||||||
|
tz@2021a
|
||||||
|
unicode@13.0
|
||||||
|
ngtcp2@0.1.0-DEV
|
||||||
|
nghttp3@0.1.0-DEV
|
||||||
|
|
||||||
|
> node benchmark/parse-top.js
|
||||||
|
|
||||||
|
cookie.parse - top sites
|
||||||
|
|
||||||
|
15 tests completed.
|
||||||
|
|
||||||
|
parse accounts.google.com x 504,358 ops/sec ±6.55% (171 runs sampled)
|
||||||
|
parse apple.com x 1,369,991 ops/sec ±0.84% (189 runs sampled)
|
||||||
|
parse cloudflare.com x 360,669 ops/sec ±3.75% (182 runs sampled)
|
||||||
|
parse docs.google.com x 521,496 ops/sec ±4.90% (180 runs sampled)
|
||||||
|
parse drive.google.com x 553,514 ops/sec ±0.59% (189 runs sampled)
|
||||||
|
parse en.wikipedia.org x 286,052 ops/sec ±0.62% (188 runs sampled)
|
||||||
|
parse linkedin.com x 178,817 ops/sec ±0.61% (192 runs sampled)
|
||||||
|
parse maps.google.com x 284,585 ops/sec ±0.68% (188 runs sampled)
|
||||||
|
parse microsoft.com x 161,230 ops/sec ±0.56% (192 runs sampled)
|
||||||
|
parse play.google.com x 352,144 ops/sec ±1.01% (181 runs sampled)
|
||||||
|
parse plus.google.com x 275,204 ops/sec ±7.78% (156 runs sampled)
|
||||||
|
parse support.google.com x 339,493 ops/sec ±1.02% (191 runs sampled)
|
||||||
|
parse www.google.com x 286,110 ops/sec ±0.90% (191 runs sampled)
|
||||||
|
parse youtu.be x 548,557 ops/sec ±0.60% (184 runs sampled)
|
||||||
|
parse youtube.com x 545,293 ops/sec ±0.65% (191 runs sampled)
|
||||||
|
|
||||||
|
> node benchmark/parse.js
|
||||||
|
|
||||||
|
cookie.parse - generic
|
||||||
|
|
||||||
|
6 tests completed.
|
||||||
|
|
||||||
|
simple x 1,266,646 ops/sec ±0.65% (191 runs sampled)
|
||||||
|
decode x 838,413 ops/sec ±0.60% (191 runs sampled)
|
||||||
|
unquote x 877,820 ops/sec ±0.72% (189 runs sampled)
|
||||||
|
duplicates x 516,680 ops/sec ±0.61% (191 runs sampled)
|
||||||
|
10 cookies x 156,874 ops/sec ±0.52% (189 runs sampled)
|
||||||
|
100 cookies x 14,663 ops/sec ±0.53% (191 runs sampled)
|
||||||
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [RFC 6265: HTTP State Management Mechanism][rfc-6265]
|
||||||
|
- [Same-site Cookies][rfc-6265bis-03-4.1.2.7]
|
||||||
|
|
||||||
|
[rfc-6265bis-03-4.1.2.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7
|
||||||
|
[rfc-6265]: https://tools.ietf.org/html/rfc6265
|
||||||
|
[rfc-6265-5.1.4]: https://tools.ietf.org/html/rfc6265#section-5.1.4
|
||||||
|
[rfc-6265-5.2.1]: https://tools.ietf.org/html/rfc6265#section-5.2.1
|
||||||
|
[rfc-6265-5.2.2]: https://tools.ietf.org/html/rfc6265#section-5.2.2
|
||||||
|
[rfc-6265-5.2.3]: https://tools.ietf.org/html/rfc6265#section-5.2.3
|
||||||
|
[rfc-6265-5.2.4]: https://tools.ietf.org/html/rfc6265#section-5.2.4
|
||||||
|
[rfc-6265-5.2.5]: https://tools.ietf.org/html/rfc6265#section-5.2.5
|
||||||
|
[rfc-6265-5.2.6]: https://tools.ietf.org/html/rfc6265#section-5.2.6
|
||||||
|
[rfc-6265-5.3]: https://tools.ietf.org/html/rfc6265#section-5.3
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/cookie/master
|
||||||
|
[coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master
|
||||||
|
[github-actions-ci-image]: https://img.shields.io/github/workflow/status/jshttp/cookie/ci/master?label=ci
|
||||||
|
[github-actions-ci-url]: https://github.com/jshttp/cookie/actions/workflows/ci.yml
|
||||||
|
[node-version-image]: https://badgen.net/npm/node/cookie
|
||||||
|
[node-version-url]: https://nodejs.org/en/download
|
||||||
|
[npm-downloads-image]: https://badgen.net/npm/dm/cookie
|
||||||
|
[npm-url]: https://npmjs.org/package/cookie
|
||||||
|
[npm-version-image]: https://badgen.net/npm/v/cookie
|
202
src/node_modules/express-session/node_modules/cookie/index.js
generated
vendored
Normal file
202
src/node_modules/express-session/node_modules/cookie/index.js
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*!
|
||||||
|
* cookie
|
||||||
|
* Copyright(c) 2012-2014 Roman Shtylman
|
||||||
|
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.parse = parse;
|
||||||
|
exports.serialize = serialize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module variables.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var decode = decodeURIComponent;
|
||||||
|
var encode = encodeURIComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegExp to match field-content in RFC 7230 sec 3.2
|
||||||
|
*
|
||||||
|
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
|
||||||
|
* field-vchar = VCHAR / obs-text
|
||||||
|
* obs-text = %x80-FF
|
||||||
|
*/
|
||||||
|
|
||||||
|
var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a cookie header.
|
||||||
|
*
|
||||||
|
* Parse the given cookie header string into an object
|
||||||
|
* The object has the various cookies as keys(names) => values
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @param {object} [options]
|
||||||
|
* @return {object}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function parse(str, options) {
|
||||||
|
if (typeof str !== 'string') {
|
||||||
|
throw new TypeError('argument str must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj = {}
|
||||||
|
var opt = options || {};
|
||||||
|
var pairs = str.split(';')
|
||||||
|
var dec = opt.decode || decode;
|
||||||
|
|
||||||
|
for (var i = 0; i < pairs.length; i++) {
|
||||||
|
var pair = pairs[i];
|
||||||
|
var index = pair.indexOf('=')
|
||||||
|
|
||||||
|
// skip things that don't look like key=value
|
||||||
|
if (index < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = pair.substring(0, index).trim()
|
||||||
|
|
||||||
|
// only assign once
|
||||||
|
if (undefined == obj[key]) {
|
||||||
|
var val = pair.substring(index + 1, pair.length).trim()
|
||||||
|
|
||||||
|
// quoted values
|
||||||
|
if (val[0] === '"') {
|
||||||
|
val = val.slice(1, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
obj[key] = tryDecode(val, dec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize data into a cookie header.
|
||||||
|
*
|
||||||
|
* Serialize the a name value pair into a cookie string suitable for
|
||||||
|
* http headers. An optional options object specified cookie parameters.
|
||||||
|
*
|
||||||
|
* serialize('foo', 'bar', { httpOnly: true })
|
||||||
|
* => "foo=bar; httpOnly"
|
||||||
|
*
|
||||||
|
* @param {string} name
|
||||||
|
* @param {string} val
|
||||||
|
* @param {object} [options]
|
||||||
|
* @return {string}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function serialize(name, val, options) {
|
||||||
|
var opt = options || {};
|
||||||
|
var enc = opt.encode || encode;
|
||||||
|
|
||||||
|
if (typeof enc !== 'function') {
|
||||||
|
throw new TypeError('option encode is invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fieldContentRegExp.test(name)) {
|
||||||
|
throw new TypeError('argument name is invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = enc(val);
|
||||||
|
|
||||||
|
if (value && !fieldContentRegExp.test(value)) {
|
||||||
|
throw new TypeError('argument val is invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
var str = name + '=' + value;
|
||||||
|
|
||||||
|
if (null != opt.maxAge) {
|
||||||
|
var maxAge = opt.maxAge - 0;
|
||||||
|
|
||||||
|
if (isNaN(maxAge) || !isFinite(maxAge)) {
|
||||||
|
throw new TypeError('option maxAge is invalid')
|
||||||
|
}
|
||||||
|
|
||||||
|
str += '; Max-Age=' + Math.floor(maxAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.domain) {
|
||||||
|
if (!fieldContentRegExp.test(opt.domain)) {
|
||||||
|
throw new TypeError('option domain is invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
str += '; Domain=' + opt.domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.path) {
|
||||||
|
if (!fieldContentRegExp.test(opt.path)) {
|
||||||
|
throw new TypeError('option path is invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
str += '; Path=' + opt.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.expires) {
|
||||||
|
if (typeof opt.expires.toUTCString !== 'function') {
|
||||||
|
throw new TypeError('option expires is invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
str += '; Expires=' + opt.expires.toUTCString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.httpOnly) {
|
||||||
|
str += '; HttpOnly';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.secure) {
|
||||||
|
str += '; Secure';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.sameSite) {
|
||||||
|
var sameSite = typeof opt.sameSite === 'string'
|
||||||
|
? opt.sameSite.toLowerCase() : opt.sameSite;
|
||||||
|
|
||||||
|
switch (sameSite) {
|
||||||
|
case true:
|
||||||
|
str += '; SameSite=Strict';
|
||||||
|
break;
|
||||||
|
case 'lax':
|
||||||
|
str += '; SameSite=Lax';
|
||||||
|
break;
|
||||||
|
case 'strict':
|
||||||
|
str += '; SameSite=Strict';
|
||||||
|
break;
|
||||||
|
case 'none':
|
||||||
|
str += '; SameSite=None';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new TypeError('option sameSite is invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try decoding a string using a decoding function.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @param {function} decode
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function tryDecode(str, decode) {
|
||||||
|
try {
|
||||||
|
return decode(str);
|
||||||
|
} catch (e) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
42
src/node_modules/express-session/node_modules/cookie/package.json
generated
vendored
Normal file
42
src/node_modules/express-session/node_modules/cookie/package.json
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "cookie",
|
||||||
|
"description": "HTTP server cookie parsing and serialization",
|
||||||
|
"version": "0.4.2",
|
||||||
|
"author": "Roman Shtylman <shtylman@gmail.com>",
|
||||||
|
"contributors": [
|
||||||
|
"Douglas Christopher Wilson <doug@somethingdoug.com>"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"cookie",
|
||||||
|
"cookies"
|
||||||
|
],
|
||||||
|
"repository": "jshttp/cookie",
|
||||||
|
"devDependencies": {
|
||||||
|
"beautify-benchmark": "0.2.4",
|
||||||
|
"benchmark": "2.1.4",
|
||||||
|
"eslint": "7.32.0",
|
||||||
|
"eslint-plugin-markdown": "2.2.1",
|
||||||
|
"mocha": "9.2.0",
|
||||||
|
"nyc": "15.1.0",
|
||||||
|
"top-sites": "1.1.85"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"HISTORY.md",
|
||||||
|
"LICENSE",
|
||||||
|
"README.md",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"bench": "node benchmark/index.js",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"test": "mocha --reporter spec --bail --check-leaks --ui qunit test/",
|
||||||
|
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
|
||||||
|
"test-cov": "nyc --reporter=html --reporter=text npm test",
|
||||||
|
"update-bench": "node scripts/update-benchmark.js",
|
||||||
|
"version": "node scripts/version-history.js && git add HISTORY.md"
|
||||||
|
}
|
||||||
|
}
|
47
src/node_modules/express-session/package.json
generated
vendored
Normal file
47
src/node_modules/express-session/package.json
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"name": "express-session",
|
||||||
|
"version": "1.17.3",
|
||||||
|
"description": "Simple session middleware for Express",
|
||||||
|
"author": "TJ Holowaychuk <tj@vision-media.ca> (http://tjholowaychuk.com)",
|
||||||
|
"contributors": [
|
||||||
|
"Douglas Christopher Wilson <doug@somethingdoug.com>",
|
||||||
|
"Joe Wagner <njwjs722@gmail.com>"
|
||||||
|
],
|
||||||
|
"repository": "expressjs/session",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cookie": "0.4.2",
|
||||||
|
"cookie-signature": "1.0.6",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~2.0.0",
|
||||||
|
"on-headers": "~1.0.2",
|
||||||
|
"parseurl": "~1.3.3",
|
||||||
|
"safe-buffer": "5.2.1",
|
||||||
|
"uid-safe": "~2.1.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"after": "0.8.2",
|
||||||
|
"cookie-parser": "1.4.6",
|
||||||
|
"eslint": "7.32.0",
|
||||||
|
"eslint-plugin-markdown": "2.2.1",
|
||||||
|
"express": "4.17.3",
|
||||||
|
"mocha": "10.0.0",
|
||||||
|
"nyc": "15.1.0",
|
||||||
|
"supertest": "6.2.3"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"session/",
|
||||||
|
"HISTORY.md",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint . && node ./scripts/lint-readme.js",
|
||||||
|
"test": "mocha --require test/support/env --check-leaks --bail --no-exit --reporter spec test/",
|
||||||
|
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
|
||||||
|
"test-cov": "nyc npm test",
|
||||||
|
"version": "node scripts/version-history.js && git add HISTORY.md"
|
||||||
|
}
|
||||||
|
}
|
150
src/node_modules/express-session/session/cookie.js
generated
vendored
Normal file
150
src/node_modules/express-session/session/cookie.js
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - session - Cookie
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var cookie = require('cookie')
|
||||||
|
var deprecate = require('depd')('express-session')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new `Cookie` with the given `options`.
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {Object} options
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Cookie = module.exports = function Cookie(options) {
|
||||||
|
this.path = '/';
|
||||||
|
this.maxAge = null;
|
||||||
|
this.httpOnly = true;
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
if (typeof options !== 'object') {
|
||||||
|
throw new TypeError('argument options must be a object')
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var key in options) {
|
||||||
|
if (key !== 'data') {
|
||||||
|
this[key] = options[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.originalMaxAge === undefined || this.originalMaxAge === null) {
|
||||||
|
this.originalMaxAge = this.maxAge
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Prototype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Cookie.prototype = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set expires `date`.
|
||||||
|
*
|
||||||
|
* @param {Date} date
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
set expires(date) {
|
||||||
|
this._expires = date;
|
||||||
|
this.originalMaxAge = this.maxAge;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get expires `date`.
|
||||||
|
*
|
||||||
|
* @return {Date}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
get expires() {
|
||||||
|
return this._expires;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set expires via max-age in `ms`.
|
||||||
|
*
|
||||||
|
* @param {Number} ms
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
set maxAge(ms) {
|
||||||
|
if (ms && typeof ms !== 'number' && !(ms instanceof Date)) {
|
||||||
|
throw new TypeError('maxAge must be a number or Date')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms instanceof Date) {
|
||||||
|
deprecate('maxAge as Date; pass number of milliseconds instead')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.expires = typeof ms === 'number'
|
||||||
|
? new Date(Date.now() + ms)
|
||||||
|
: ms;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get expires max-age in `ms`.
|
||||||
|
*
|
||||||
|
* @return {Number}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
get maxAge() {
|
||||||
|
return this.expires instanceof Date
|
||||||
|
? this.expires.valueOf() - Date.now()
|
||||||
|
: this.expires;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return cookie data object.
|
||||||
|
*
|
||||||
|
* @return {Object}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
get data() {
|
||||||
|
return {
|
||||||
|
originalMaxAge: this.originalMaxAge
|
||||||
|
, expires: this._expires
|
||||||
|
, secure: this.secure
|
||||||
|
, httpOnly: this.httpOnly
|
||||||
|
, domain: this.domain
|
||||||
|
, path: this.path
|
||||||
|
, sameSite: this.sameSite
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a serialized cookie string.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
serialize: function(name, val){
|
||||||
|
return cookie.serialize(name, val, this.data);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return JSON representation of this cookie.
|
||||||
|
*
|
||||||
|
* @return {Object}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
toJSON: function(){
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
};
|
187
src/node_modules/express-session/session/memory.js
generated
vendored
Normal file
187
src/node_modules/express-session/session/memory.js
generated
vendored
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/*!
|
||||||
|
* express-session
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Store = require('./store')
|
||||||
|
var util = require('util')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shim setImmediate for node.js < 0.10
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
var defer = typeof setImmediate === 'function'
|
||||||
|
? setImmediate
|
||||||
|
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = MemoryStore
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A session store in memory.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function MemoryStore() {
|
||||||
|
Store.call(this)
|
||||||
|
this.sessions = Object.create(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inherit from Store.
|
||||||
|
*/
|
||||||
|
|
||||||
|
util.inherits(MemoryStore, Store)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all active sessions.
|
||||||
|
*
|
||||||
|
* @param {function} callback
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.all = function all(callback) {
|
||||||
|
var sessionIds = Object.keys(this.sessions)
|
||||||
|
var sessions = Object.create(null)
|
||||||
|
|
||||||
|
for (var i = 0; i < sessionIds.length; i++) {
|
||||||
|
var sessionId = sessionIds[i]
|
||||||
|
var session = getSession.call(this, sessionId)
|
||||||
|
|
||||||
|
if (session) {
|
||||||
|
sessions[sessionId] = session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback && defer(callback, null, sessions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all sessions.
|
||||||
|
*
|
||||||
|
* @param {function} callback
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.clear = function clear(callback) {
|
||||||
|
this.sessions = Object.create(null)
|
||||||
|
callback && defer(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the session associated with the given session ID.
|
||||||
|
*
|
||||||
|
* @param {string} sessionId
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.destroy = function destroy(sessionId, callback) {
|
||||||
|
delete this.sessions[sessionId]
|
||||||
|
callback && defer(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch session by the given session ID.
|
||||||
|
*
|
||||||
|
* @param {string} sessionId
|
||||||
|
* @param {function} callback
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.get = function get(sessionId, callback) {
|
||||||
|
defer(callback, null, getSession.call(this, sessionId))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commit the given session associated with the given sessionId to the store.
|
||||||
|
*
|
||||||
|
* @param {string} sessionId
|
||||||
|
* @param {object} session
|
||||||
|
* @param {function} callback
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.set = function set(sessionId, session, callback) {
|
||||||
|
this.sessions[sessionId] = JSON.stringify(session)
|
||||||
|
callback && defer(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get number of active sessions.
|
||||||
|
*
|
||||||
|
* @param {function} callback
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.length = function length(callback) {
|
||||||
|
this.all(function (err, sessions) {
|
||||||
|
if (err) return callback(err)
|
||||||
|
callback(null, Object.keys(sessions).length)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Touch the given session object associated with the given session ID.
|
||||||
|
*
|
||||||
|
* @param {string} sessionId
|
||||||
|
* @param {object} session
|
||||||
|
* @param {function} callback
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.touch = function touch(sessionId, session, callback) {
|
||||||
|
var currentSession = getSession.call(this, sessionId)
|
||||||
|
|
||||||
|
if (currentSession) {
|
||||||
|
// update expiration
|
||||||
|
currentSession.cookie = session.cookie
|
||||||
|
this.sessions[sessionId] = JSON.stringify(currentSession)
|
||||||
|
}
|
||||||
|
|
||||||
|
callback && defer(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get session from the store.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getSession(sessionId) {
|
||||||
|
var sess = this.sessions[sessionId]
|
||||||
|
|
||||||
|
if (!sess) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse
|
||||||
|
sess = JSON.parse(sess)
|
||||||
|
|
||||||
|
if (sess.cookie) {
|
||||||
|
var expires = typeof sess.cookie.expires === 'string'
|
||||||
|
? new Date(sess.cookie.expires)
|
||||||
|
: sess.cookie.expires
|
||||||
|
|
||||||
|
// destroy expired session
|
||||||
|
if (expires && expires <= Date.now()) {
|
||||||
|
delete this.sessions[sessionId]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess
|
||||||
|
}
|
143
src/node_modules/express-session/session/session.js
generated
vendored
Normal file
143
src/node_modules/express-session/session/session.js
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - session - Session
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose Session.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new `Session` with the given request and `data`.
|
||||||
|
*
|
||||||
|
* @param {IncomingRequest} req
|
||||||
|
* @param {Object} data
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Session(req, data) {
|
||||||
|
Object.defineProperty(this, 'req', { value: req });
|
||||||
|
Object.defineProperty(this, 'id', { value: req.sessionID });
|
||||||
|
|
||||||
|
if (typeof data === 'object' && data !== null) {
|
||||||
|
// merge data into this, ignoring prototype properties
|
||||||
|
for (var prop in data) {
|
||||||
|
if (!(prop in this)) {
|
||||||
|
this[prop] = data[prop]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update reset `.cookie.maxAge` to prevent
|
||||||
|
* the cookie from expiring when the
|
||||||
|
* session is still active.
|
||||||
|
*
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
defineMethod(Session.prototype, 'touch', function touch() {
|
||||||
|
return this.resetMaxAge();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset `.maxAge` to `.originalMaxAge`.
|
||||||
|
*
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
defineMethod(Session.prototype, 'resetMaxAge', function resetMaxAge() {
|
||||||
|
this.cookie.maxAge = this.cookie.originalMaxAge;
|
||||||
|
return this;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the session data with optional callback `fn(err)`.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
defineMethod(Session.prototype, 'save', function save(fn) {
|
||||||
|
this.req.sessionStore.set(this.id, this, fn || function(){});
|
||||||
|
return this;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-loads the session data _without_ altering
|
||||||
|
* the maxAge properties. Invokes the callback `fn(err)`,
|
||||||
|
* after which time if no exception has occurred the
|
||||||
|
* `req.session` property will be a new `Session` object,
|
||||||
|
* although representing the same session.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
defineMethod(Session.prototype, 'reload', function reload(fn) {
|
||||||
|
var req = this.req
|
||||||
|
var store = this.req.sessionStore
|
||||||
|
|
||||||
|
store.get(this.id, function(err, sess){
|
||||||
|
if (err) return fn(err);
|
||||||
|
if (!sess) return fn(new Error('failed to load session'));
|
||||||
|
store.createSession(req, sess);
|
||||||
|
fn();
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy `this` session.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
defineMethod(Session.prototype, 'destroy', function destroy(fn) {
|
||||||
|
delete this.req.session;
|
||||||
|
this.req.sessionStore.destroy(this.id, fn);
|
||||||
|
return this;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regenerate this request's session.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
defineMethod(Session.prototype, 'regenerate', function regenerate(fn) {
|
||||||
|
this.req.sessionStore.regenerate(this.req, fn);
|
||||||
|
return this;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for creating a method on a prototype.
|
||||||
|
*
|
||||||
|
* @param {Object} obj
|
||||||
|
* @param {String} name
|
||||||
|
* @param {Function} fn
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function defineMethod(obj, name, fn) {
|
||||||
|
Object.defineProperty(obj, name, {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
value: fn,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
|
};
|
102
src/node_modules/express-session/session/store.js
generated
vendored
Normal file
102
src/node_modules/express-session/session/store.js
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - session - Store
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Cookie = require('./cookie')
|
||||||
|
var EventEmitter = require('events').EventEmitter
|
||||||
|
var Session = require('./session')
|
||||||
|
var util = require('util')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = Store
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for session stores.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Store () {
|
||||||
|
EventEmitter.call(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inherit from EventEmitter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
util.inherits(Store, EventEmitter)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-generate the given requests's session.
|
||||||
|
*
|
||||||
|
* @param {IncomingRequest} req
|
||||||
|
* @return {Function} fn
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Store.prototype.regenerate = function(req, fn){
|
||||||
|
var self = this;
|
||||||
|
this.destroy(req.sessionID, function(err){
|
||||||
|
self.generate(req);
|
||||||
|
fn(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a `Session` instance via the given `sid`
|
||||||
|
* and invoke the callback `fn(err, sess)`.
|
||||||
|
*
|
||||||
|
* @param {String} sid
|
||||||
|
* @param {Function} fn
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Store.prototype.load = function(sid, fn){
|
||||||
|
var self = this;
|
||||||
|
this.get(sid, function(err, sess){
|
||||||
|
if (err) return fn(err);
|
||||||
|
if (!sess) return fn();
|
||||||
|
var req = { sessionID: sid, sessionStore: self };
|
||||||
|
fn(null, self.createSession(req, sess))
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create session from JSON `sess` data.
|
||||||
|
*
|
||||||
|
* @param {IncomingRequest} req
|
||||||
|
* @param {Object} sess
|
||||||
|
* @return {Session}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
Store.prototype.createSession = function(req, sess){
|
||||||
|
var expires = sess.cookie.expires
|
||||||
|
var originalMaxAge = sess.cookie.originalMaxAge
|
||||||
|
|
||||||
|
sess.cookie = new Cookie(sess.cookie);
|
||||||
|
|
||||||
|
if (typeof expires === 'string') {
|
||||||
|
// convert expires to a Date object
|
||||||
|
sess.cookie.expires = new Date(expires)
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep originalMaxAge intact
|
||||||
|
sess.cookie.originalMaxAge = originalMaxAge
|
||||||
|
|
||||||
|
req.session = new Session(req, sess);
|
||||||
|
return req.session;
|
||||||
|
};
|
21
src/node_modules/on-headers/HISTORY.md
generated
vendored
Normal file
21
src/node_modules/on-headers/HISTORY.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
1.0.2 / 2019-02-21
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix `res.writeHead` patch missing return value
|
||||||
|
|
||||||
|
1.0.1 / 2015-09-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* perf: enable strict mode
|
||||||
|
|
||||||
|
1.0.0 / 2014-08-10
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Honor `res.statusCode` change in `listener`
|
||||||
|
* Move to `jshttp` organization
|
||||||
|
* Prevent `arguments`-related de-opt
|
||||||
|
|
||||||
|
0.0.0 / 2014-05-13
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial implementation
|
22
src/node_modules/on-headers/LICENSE
generated
vendored
Normal file
22
src/node_modules/on-headers/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Douglas Christopher Wilson
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
81
src/node_modules/on-headers/README.md
generated
vendored
Normal file
81
src/node_modules/on-headers/README.md
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# on-headers
|
||||||
|
|
||||||
|
[![NPM Version][npm-version-image]][npm-url]
|
||||||
|
[![NPM Downloads][npm-downloads-image]][npm-url]
|
||||||
|
[![Node.js Version][node-version-image]][node-version-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
Execute a listener when a response is about to write headers.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||||
|
[npm registry](https://www.npmjs.com/). Installation is done using the
|
||||||
|
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install on-headers
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
<!-- eslint-disable no-unused-vars -->
|
||||||
|
|
||||||
|
```js
|
||||||
|
var onHeaders = require('on-headers')
|
||||||
|
```
|
||||||
|
|
||||||
|
### onHeaders(res, listener)
|
||||||
|
|
||||||
|
This will add the listener `listener` to fire when headers are emitted for `res`.
|
||||||
|
The listener is passed the `response` object as it's context (`this`). Headers are
|
||||||
|
considered to be emitted only once, right before they are sent to the client.
|
||||||
|
|
||||||
|
When this is called multiple times on the same `res`, the `listener`s are fired
|
||||||
|
in the reverse order they were added.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```js
|
||||||
|
var http = require('http')
|
||||||
|
var onHeaders = require('on-headers')
|
||||||
|
|
||||||
|
http
|
||||||
|
.createServer(onRequest)
|
||||||
|
.listen(3000)
|
||||||
|
|
||||||
|
function addPoweredBy () {
|
||||||
|
// set if not set by end of request
|
||||||
|
if (!this.getHeader('X-Powered-By')) {
|
||||||
|
this.setHeader('X-Powered-By', 'Node.js')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRequest (req, res) {
|
||||||
|
onHeaders(res, addPoweredBy)
|
||||||
|
|
||||||
|
res.setHeader('Content-Type', 'text/plain')
|
||||||
|
res.end('hello!')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/on-headers/master
|
||||||
|
[coveralls-url]: https://coveralls.io/r/jshttp/on-headers?branch=master
|
||||||
|
[node-version-image]: https://badgen.net/npm/node/on-headers
|
||||||
|
[node-version-url]: https://nodejs.org/en/download
|
||||||
|
[npm-downloads-image]: https://badgen.net/npm/dm/on-headers
|
||||||
|
[npm-url]: https://npmjs.org/package/on-headers
|
||||||
|
[npm-version-image]: https://badgen.net/npm/v/on-headers
|
||||||
|
[travis-image]: https://badgen.net/travis/jshttp/on-headers/master
|
||||||
|
[travis-url]: https://travis-ci.org/jshttp/on-headers
|
132
src/node_modules/on-headers/index.js
generated
vendored
Normal file
132
src/node_modules/on-headers/index.js
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/*!
|
||||||
|
* on-headers
|
||||||
|
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = onHeaders
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a replacement writeHead method.
|
||||||
|
*
|
||||||
|
* @param {function} prevWriteHead
|
||||||
|
* @param {function} listener
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createWriteHead (prevWriteHead, listener) {
|
||||||
|
var fired = false
|
||||||
|
|
||||||
|
// return function with core name and argument list
|
||||||
|
return function writeHead (statusCode) {
|
||||||
|
// set headers from arguments
|
||||||
|
var args = setWriteHeadHeaders.apply(this, arguments)
|
||||||
|
|
||||||
|
// fire listener
|
||||||
|
if (!fired) {
|
||||||
|
fired = true
|
||||||
|
listener.call(this)
|
||||||
|
|
||||||
|
// pass-along an updated status code
|
||||||
|
if (typeof args[0] === 'number' && this.statusCode !== args[0]) {
|
||||||
|
args[0] = this.statusCode
|
||||||
|
args.length = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prevWriteHead.apply(this, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a listener when a response is about to write headers.
|
||||||
|
*
|
||||||
|
* @param {object} res
|
||||||
|
* @return {function} listener
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onHeaders (res, listener) {
|
||||||
|
if (!res) {
|
||||||
|
throw new TypeError('argument res is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof listener !== 'function') {
|
||||||
|
throw new TypeError('argument listener must be a function')
|
||||||
|
}
|
||||||
|
|
||||||
|
res.writeHead = createWriteHead(res.writeHead, listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set headers contained in array on the response object.
|
||||||
|
*
|
||||||
|
* @param {object} res
|
||||||
|
* @param {array} headers
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function setHeadersFromArray (res, headers) {
|
||||||
|
for (var i = 0; i < headers.length; i++) {
|
||||||
|
res.setHeader(headers[i][0], headers[i][1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set headers contained in object on the response object.
|
||||||
|
*
|
||||||
|
* @param {object} res
|
||||||
|
* @param {object} headers
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function setHeadersFromObject (res, headers) {
|
||||||
|
var keys = Object.keys(headers)
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var k = keys[i]
|
||||||
|
if (k) res.setHeader(k, headers[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set headers and other properties on the response object.
|
||||||
|
*
|
||||||
|
* @param {number} statusCode
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function setWriteHeadHeaders (statusCode) {
|
||||||
|
var length = arguments.length
|
||||||
|
var headerIndex = length > 1 && typeof arguments[1] === 'string'
|
||||||
|
? 2
|
||||||
|
: 1
|
||||||
|
|
||||||
|
var headers = length >= headerIndex + 1
|
||||||
|
? arguments[headerIndex]
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
this.statusCode = statusCode
|
||||||
|
|
||||||
|
if (Array.isArray(headers)) {
|
||||||
|
// handle array case
|
||||||
|
setHeadersFromArray(this, headers)
|
||||||
|
} else if (headers) {
|
||||||
|
// handle object case
|
||||||
|
setHeadersFromObject(this, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy leading arguments
|
||||||
|
var args = new Array(Math.min(length, headerIndex))
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
args[i] = arguments[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
42
src/node_modules/on-headers/package.json
generated
vendored
Normal file
42
src/node_modules/on-headers/package.json
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "on-headers",
|
||||||
|
"description": "Execute a listener when a response is about to write headers",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"event",
|
||||||
|
"headers",
|
||||||
|
"http",
|
||||||
|
"onheaders"
|
||||||
|
],
|
||||||
|
"repository": "jshttp/on-headers",
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "5.14.1",
|
||||||
|
"eslint-config-standard": "12.0.0",
|
||||||
|
"eslint-plugin-import": "2.16.0",
|
||||||
|
"eslint-plugin-markdown": "1.0.0",
|
||||||
|
"eslint-plugin-node": "8.0.1",
|
||||||
|
"eslint-plugin-promise": "4.0.1",
|
||||||
|
"eslint-plugin-standard": "4.0.0",
|
||||||
|
"istanbul": "0.4.5",
|
||||||
|
"mocha": "6.0.1",
|
||||||
|
"supertest": "3.4.2"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"LICENSE",
|
||||||
|
"HISTORY.md",
|
||||||
|
"README.md",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint --plugin markdown --ext js,md .",
|
||||||
|
"test": "mocha --reporter spec --bail --check-leaks test/",
|
||||||
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
|
||||||
|
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
|
||||||
|
"version": "node scripts/version-history.js && git add HISTORY.md"
|
||||||
|
}
|
||||||
|
}
|
4
src/node_modules/random-bytes/HISTORY.md
generated
vendored
Normal file
4
src/node_modules/random-bytes/HISTORY.md
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
1.0.0 / 2016-01-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial release
|
21
src/node_modules/random-bytes/LICENSE
generated
vendored
Normal file
21
src/node_modules/random-bytes/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Douglas Christopher Wilson <doug@somethingdoug.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
77
src/node_modules/random-bytes/README.md
generated
vendored
Normal file
77
src/node_modules/random-bytes/README.md
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# random-bytes
|
||||||
|
|
||||||
|
[![NPM Version][npm-image]][npm-url]
|
||||||
|
[![NPM Downloads][downloads-image]][downloads-url]
|
||||||
|
[![Node.js Version][node-version-image]][node-version-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
Generate strong pseudo-random bytes.
|
||||||
|
|
||||||
|
This module is a simple wrapper around the Node.js core `crypto.randomBytes` API,
|
||||||
|
with the following additions:
|
||||||
|
|
||||||
|
* A `Promise` interface for environments with promises.
|
||||||
|
* For Node.js versions that do not wait for the PRNG to be seeded, this module
|
||||||
|
will wait a bit.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install random-bytes
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```js
|
||||||
|
var randomBytes = require('random-bytes')
|
||||||
|
```
|
||||||
|
|
||||||
|
### randomBytes(size, callback)
|
||||||
|
|
||||||
|
Generates strong pseudo-random bytes. The `size` argument is a number indicating
|
||||||
|
the number of bytes to generate.
|
||||||
|
|
||||||
|
```js
|
||||||
|
randomBytes(12, function (error, bytes) {
|
||||||
|
if (error) throw error
|
||||||
|
// do something with the bytes
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### randomBytes(size)
|
||||||
|
|
||||||
|
Generates strong pseudo-random bytes and return a `Promise`. The `size` argument is
|
||||||
|
a number indicating the number of bytes to generate.
|
||||||
|
|
||||||
|
**Note**: To use promises in Node.js _prior to 0.12_, promises must be
|
||||||
|
"polyfilled" using `global.Promise = require('bluebird')`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
randomBytes(18).then(function (string) {
|
||||||
|
// do something with the string
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### randomBytes.sync(size)
|
||||||
|
|
||||||
|
A synchronous version of above.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var bytes = randomBytes.sync(18)
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/random-bytes.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/random-bytes
|
||||||
|
[node-version-image]: https://img.shields.io/node/v/random-bytes.svg
|
||||||
|
[node-version-url]: http://nodejs.org/download/
|
||||||
|
[travis-image]: https://img.shields.io/travis/crypto-utils/random-bytes/master.svg
|
||||||
|
[travis-url]: https://travis-ci.org/crypto-utils/random-bytes
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/crypto-utils/random-bytes/master.svg
|
||||||
|
[coveralls-url]: https://coveralls.io/r/crypto-utils/random-bytes?branch=master
|
||||||
|
[downloads-image]: https://img.shields.io/npm/dm/random-bytes.svg
|
||||||
|
[downloads-url]: https://npmjs.org/package/random-bytes
|
101
src/node_modules/random-bytes/index.js
generated
vendored
Normal file
101
src/node_modules/random-bytes/index.js
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*!
|
||||||
|
* random-bytes
|
||||||
|
* Copyright(c) 2016 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var crypto = require('crypto')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module variables.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var generateAttempts = crypto.randomBytes === crypto.pseudoRandomBytes ? 1 : 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = randomBytes
|
||||||
|
module.exports.sync = randomBytesSync
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates strong pseudo-random bytes.
|
||||||
|
*
|
||||||
|
* @param {number} size
|
||||||
|
* @param {function} [callback]
|
||||||
|
* @return {Promise}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function randomBytes(size, callback) {
|
||||||
|
// validate callback is a function, if provided
|
||||||
|
if (callback !== undefined && typeof callback !== 'function') {
|
||||||
|
throw new TypeError('argument callback must be a function')
|
||||||
|
}
|
||||||
|
|
||||||
|
// require the callback without promises
|
||||||
|
if (!callback && !global.Promise) {
|
||||||
|
throw new TypeError('argument callback is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
// classic callback style
|
||||||
|
return generateRandomBytes(size, generateAttempts, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise(function executor(resolve, reject) {
|
||||||
|
generateRandomBytes(size, generateAttempts, function onRandomBytes(err, str) {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(str)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates strong pseudo-random bytes sync.
|
||||||
|
*
|
||||||
|
* @param {number} size
|
||||||
|
* @return {Buffer}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function randomBytesSync(size) {
|
||||||
|
var err = null
|
||||||
|
|
||||||
|
for (var i = 0; i < generateAttempts; i++) {
|
||||||
|
try {
|
||||||
|
return crypto.randomBytes(size)
|
||||||
|
} catch (e) {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates strong pseudo-random bytes.
|
||||||
|
*
|
||||||
|
* @param {number} size
|
||||||
|
* @param {number} attempts
|
||||||
|
* @param {function} callback
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function generateRandomBytes(size, attempts, callback) {
|
||||||
|
crypto.randomBytes(size, function onRandomBytes(err, buf) {
|
||||||
|
if (!err) return callback(null, buf)
|
||||||
|
if (!--attempts) return callback(err)
|
||||||
|
setTimeout(generateRandomBytes.bind(null, size, attempts, callback), 10)
|
||||||
|
})
|
||||||
|
}
|
36
src/node_modules/random-bytes/package.json
generated
vendored
Normal file
36
src/node_modules/random-bytes/package.json
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "random-bytes",
|
||||||
|
"description": "URL and cookie safe UIDs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"contributors": [
|
||||||
|
"Douglas Christopher Wilson <doug@somethingdoug.com>"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "crypto-utils/random-bytes",
|
||||||
|
"devDependencies": {
|
||||||
|
"bluebird": "3.1.1",
|
||||||
|
"istanbul": "0.4.2",
|
||||||
|
"mocha": "2.3.4",
|
||||||
|
"proxyquire": "1.2.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"LICENSE",
|
||||||
|
"HISTORY.md",
|
||||||
|
"README.md",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha --trace-deprecation --reporter spec --bail --check-leaks test/",
|
||||||
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --trace-deprecation --reporter dot --check-leaks test/",
|
||||||
|
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --trace-deprecation --reporter spec --check-leaks test/"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"bytes",
|
||||||
|
"generator",
|
||||||
|
"random",
|
||||||
|
"safe"
|
||||||
|
]
|
||||||
|
}
|
61
src/node_modules/uid-safe/HISTORY.md
generated
vendored
Normal file
61
src/node_modules/uid-safe/HISTORY.md
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
2.1.5 / 2017-08-02
|
||||||
|
==================
|
||||||
|
|
||||||
|
* perf: remove only trailing `=`
|
||||||
|
|
||||||
|
2.1.4 / 2017-03-02
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Remove `base64-url` dependency
|
||||||
|
|
||||||
|
2.1.3 / 2016-10-30
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: base64-url@1.3.3
|
||||||
|
|
||||||
|
2.1.2 / 2016-08-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: base64-url@1.3.2
|
||||||
|
|
||||||
|
2.1.1 / 2016-05-04
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: base64-url@1.2.2
|
||||||
|
|
||||||
|
2.1.0 / 2016-01-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Use `random-bytes` for byte source
|
||||||
|
|
||||||
|
2.0.0 / 2015-05-08
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Use global `Promise` when returning a promise
|
||||||
|
|
||||||
|
1.1.0 / 2015-02-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Use `crypto.randomBytes`, if available
|
||||||
|
* deps: base64-url@1.2.1
|
||||||
|
|
||||||
|
1.0.3 / 2015-01-31
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix error branch that would throw
|
||||||
|
* deps: base64-url@1.2.0
|
||||||
|
|
||||||
|
1.0.2 / 2015-01-08
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Remove dependency on `mz`
|
||||||
|
|
||||||
|
1.0.1 / 2014-06-18
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Remove direct `bluebird` dependency
|
||||||
|
|
||||||
|
1.0.0 / 2014-06-18
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial release
|
22
src/node_modules/uid-safe/LICENSE
generated
vendored
Normal file
22
src/node_modules/uid-safe/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
|
||||||
|
Copyright (c) 2015-2017 Douglas Christopher Wilson <doug@somethingdoug.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
77
src/node_modules/uid-safe/README.md
generated
vendored
Normal file
77
src/node_modules/uid-safe/README.md
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# uid-safe
|
||||||
|
|
||||||
|
[![NPM Version][npm-image]][npm-url]
|
||||||
|
[![NPM Downloads][downloads-image]][downloads-url]
|
||||||
|
[![Node.js Version][node-version-image]][node-version-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
URL and cookie safe UIDs
|
||||||
|
|
||||||
|
Create cryptographically secure UIDs safe for both cookie and URL usage.
|
||||||
|
This is in contrast to modules such as [rand-token](https://www.npmjs.com/package/rand-token)
|
||||||
|
and [uid2](https://www.npmjs.com/package/uid2) whose UIDs are actually skewed
|
||||||
|
due to the use of `%` and unnecessarily truncate the UID.
|
||||||
|
Use this if you could still use UIDs with `-` and `_` in them.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install uid-safe
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```js
|
||||||
|
var uid = require('uid-safe')
|
||||||
|
```
|
||||||
|
|
||||||
|
### uid(byteLength, callback)
|
||||||
|
|
||||||
|
Asynchronously create a UID with a specific byte length. Because `base64`
|
||||||
|
encoding is used underneath, this is not the string length. For example,
|
||||||
|
to create a UID of length 24, you want a byte length of 18.
|
||||||
|
|
||||||
|
```js
|
||||||
|
uid(18, function (err, string) {
|
||||||
|
if (err) throw err
|
||||||
|
// do something with the string
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### uid(byteLength)
|
||||||
|
|
||||||
|
Asynchronously create a UID with a specific byte length and return a
|
||||||
|
`Promise`.
|
||||||
|
|
||||||
|
**Note**: To use promises in Node.js _prior to 0.12_, promises must be
|
||||||
|
"polyfilled" using `global.Promise = require('bluebird')`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
uid(18).then(function (string) {
|
||||||
|
// do something with the string
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### uid.sync(byteLength)
|
||||||
|
|
||||||
|
A synchronous version of above.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var string = uid.sync(18)
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/uid-safe.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/uid-safe
|
||||||
|
[node-version-image]: https://img.shields.io/node/v/uid-safe.svg
|
||||||
|
[node-version-url]: https://nodejs.org/en/download/
|
||||||
|
[travis-image]: https://img.shields.io/travis/crypto-utils/uid-safe/master.svg
|
||||||
|
[travis-url]: https://travis-ci.org/crypto-utils/uid-safe
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/crypto-utils/uid-safe/master.svg
|
||||||
|
[coveralls-url]: https://coveralls.io/r/crypto-utils/uid-safe?branch=master
|
||||||
|
[downloads-image]: https://img.shields.io/npm/dm/uid-safe.svg
|
||||||
|
[downloads-url]: https://npmjs.org/package/uid-safe
|
107
src/node_modules/uid-safe/index.js
generated
vendored
Normal file
107
src/node_modules/uid-safe/index.js
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*!
|
||||||
|
* uid-safe
|
||||||
|
* Copyright(c) 2014 Jonathan Ong
|
||||||
|
* Copyright(c) 2015-2017 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var randomBytes = require('random-bytes')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module variables.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var EQUAL_END_REGEXP = /=+$/
|
||||||
|
var PLUS_GLOBAL_REGEXP = /\+/g
|
||||||
|
var SLASH_GLOBAL_REGEXP = /\//g
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = uid
|
||||||
|
module.exports.sync = uidSync
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a unique ID.
|
||||||
|
*
|
||||||
|
* @param {number} length
|
||||||
|
* @param {function} [callback]
|
||||||
|
* @return {Promise}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function uid (length, callback) {
|
||||||
|
// validate callback is a function, if provided
|
||||||
|
if (callback !== undefined && typeof callback !== 'function') {
|
||||||
|
throw new TypeError('argument callback must be a function')
|
||||||
|
}
|
||||||
|
|
||||||
|
// require the callback without promises
|
||||||
|
if (!callback && !global.Promise) {
|
||||||
|
throw new TypeError('argument callback is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
// classic callback style
|
||||||
|
return generateUid(length, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise(function executor (resolve, reject) {
|
||||||
|
generateUid(length, function onUid (err, str) {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(str)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a unique ID sync.
|
||||||
|
*
|
||||||
|
* @param {number} length
|
||||||
|
* @return {string}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function uidSync (length) {
|
||||||
|
return toString(randomBytes.sync(length))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a unique ID string.
|
||||||
|
*
|
||||||
|
* @param {number} length
|
||||||
|
* @param {function} callback
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function generateUid (length, callback) {
|
||||||
|
randomBytes(length, function (err, buf) {
|
||||||
|
if (err) return callback(err)
|
||||||
|
callback(null, toString(buf))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change a Buffer into a string.
|
||||||
|
*
|
||||||
|
* @param {Buffer} buf
|
||||||
|
* @return {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function toString (buf) {
|
||||||
|
return buf.toString('base64')
|
||||||
|
.replace(EQUAL_END_REGEXP, '')
|
||||||
|
.replace(PLUS_GLOBAL_REGEXP, '-')
|
||||||
|
.replace(SLASH_GLOBAL_REGEXP, '_')
|
||||||
|
}
|
46
src/node_modules/uid-safe/package.json
generated
vendored
Normal file
46
src/node_modules/uid-safe/package.json
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"name": "uid-safe",
|
||||||
|
"description": "URL and cookie safe UIDs",
|
||||||
|
"version": "2.1.5",
|
||||||
|
"contributors": [
|
||||||
|
"Douglas Christopher Wilson <doug@somethingdoug.com>",
|
||||||
|
"Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "crypto-utils/uid-safe",
|
||||||
|
"dependencies": {
|
||||||
|
"random-bytes": "~1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"bluebird": "3.5.0",
|
||||||
|
"eslint": "3.19.0",
|
||||||
|
"eslint-config-standard": "10.2.1",
|
||||||
|
"eslint-plugin-import": "2.7.0",
|
||||||
|
"eslint-plugin-node": "5.1.1",
|
||||||
|
"eslint-plugin-promise": "3.5.0",
|
||||||
|
"eslint-plugin-standard": "3.0.1",
|
||||||
|
"istanbul": "0.4.5",
|
||||||
|
"mocha": "2.5.3"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"LICENSE",
|
||||||
|
"HISTORY.md",
|
||||||
|
"README.md",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint .",
|
||||||
|
"test": "mocha --trace-deprecation --reporter spec --bail --check-leaks test/",
|
||||||
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --trace-deprecation --reporter dot --check-leaks test/",
|
||||||
|
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --trace-deprecation --reporter spec --check-leaks test/"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"random",
|
||||||
|
"generator",
|
||||||
|
"uid",
|
||||||
|
"safe"
|
||||||
|
]
|
||||||
|
}
|
54
src/package-lock.json
generated
54
src/package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"express-session": "^1.17.3",
|
||||||
"ws": "^8.13.0"
|
"ws": "^8.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -195,6 +196,32 @@
|
|||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/express-session": {
|
||||||
|
"version": "1.17.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz",
|
||||||
|
"integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==",
|
||||||
|
"dependencies": {
|
||||||
|
"cookie": "0.4.2",
|
||||||
|
"cookie-signature": "1.0.6",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~2.0.0",
|
||||||
|
"on-headers": "~1.0.2",
|
||||||
|
"parseurl": "~1.3.3",
|
||||||
|
"safe-buffer": "5.2.1",
|
||||||
|
"uid-safe": "~2.1.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/express-session/node_modules/cookie": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/express/node_modules/body-parser": {
|
"node_modules/express/node_modules/body-parser": {
|
||||||
"version": "1.20.1",
|
"version": "1.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||||
@ -439,6 +466,14 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/on-headers": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/parseurl": {
|
"node_modules/parseurl": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
@ -478,6 +513,14 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/random-bytes": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/range-parser": {
|
"node_modules/range-parser": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
@ -612,6 +655,17 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uid-safe": {
|
||||||
|
"version": "2.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||||
|
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
|
||||||
|
"dependencies": {
|
||||||
|
"random-bytes": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/unpipe": {
|
"node_modules/unpipe": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"express-session": "^1.17.3",
|
||||||
"ws": "^8.13.0"
|
"ws": "^8.13.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user