WIP: Testando autenticação office365.

This commit is contained in:
Gabriel Amancio 2025-10-16 11:21:31 -03:00
parent a499796cf7
commit 2366fc1eb8
49 changed files with 5264 additions and 5 deletions

9
.env
View File

@ -2,4 +2,11 @@ GOOGLE_API_KEY="AIzaSyCTrRFGKCZSspHRmTWQiclmIEOg-LROgyo"
API_URL="https://plutao.geogridmaps.com.br/vale/api/v3/viabilidade/raio"
API_KEY="6d717e972ba17c7cf0ab731801b8bbeac2f281e5"
COKIE="PHPSESSID=6d717e972ba17c7cf0ab731801b8bbeac2f281e5"
PORT="3000"
PORT="3000"
OAUTH_CLIENT_ID=e2104cd1-d67c-4ac1-8fe2-36e8caac89b7
OAUTH_CLIENT_SECRET=sVj8Q~eSXJpnQoqjvpOwjYeesVf_DJNRqTa4ua-6
OAUTH_TENANT_ID=5cd8533a-4260-48c5-87fd-8511b1b42f9b
OAUTH_REDIRECT_URI=http://localhost:3000/auth/callback
OAUTH_SCOPES=https://graph.microsoft.com/.default
SESSION_SECRET=j2633669

76
node_modules/.package-lock.json generated vendored
View File

@ -83,6 +83,7 @@
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
@ -280,6 +281,7 @@
"version": "17.2.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
@ -412,6 +414,40 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/express-session": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz",
"integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==",
"license": "MIT",
"dependencies": {
"cookie": "0.7.2",
"cookie-signature": "1.0.7",
"debug": "2.6.9",
"depd": "~2.0.0",
"on-headers": "~1.1.0",
"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.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express-session/node_modules/cookie-signature": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
"license": "MIT"
},
"node_modules/fast-csv": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz",
@ -813,6 +849,15 @@
"node": ">= 0.8"
}
},
"node_modules/on-headers": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -865,6 +910,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/querystring": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz",
"integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==",
"deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
"license": "MIT",
"engines": {
"node": ">=0.4.x"
}
},
"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==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@ -1096,6 +1160,18 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
},
"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==",
"license": "MIT",
"dependencies": {
"random-bytes": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

476
node_modules/express-session/HISTORY.md generated vendored Normal file
View File

@ -0,0 +1,476 @@
1.18.2 / 2025-07-17
==========
* deps: mocha@10.8.2
* deps: on-headers@~1.1.0
- Fix [CVE-2025-7339](https://www.cve.org/CVERecord?id=CVE-2025-7339) ([GHSA-76c9-3jph-rj3q](https://github.com/expressjs/on-headers/security/advisories/GHSA-76c9-3jph-rj3q))
1.18.1 / 2024-10-08
==========
* deps: cookie@0.7.2
- Fix object assignment of `hasOwnProperty`
* deps: cookie@0.7.1
- Allow leading dot for domain
- Although not permitted in the spec, some users expect this to work and user agents ignore the leading dot according to spec
- Add fast path for `serialize` without options, use `obj.hasOwnProperty` when parsing
* deps: cookie@0.7.0
- perf: parse cookies ~10% faster
- fix: narrow the validation of cookies to match RFC6265
- fix: add `main` to `package.json` for rspack
1.18.0 / 2024-01-28
===================
* Add debug log for pathname mismatch
* Add `partitioned` to `cookie` options
* Add `priority` to `cookie` options
* Fix handling errors from setting cookie
* Support any type in `secret` that `crypto.createHmac` supports
* deps: cookie@0.6.0
- Fix `expires` option to reject invalid dates
- perf: improve default decode speed
- perf: remove slow string split in parse
* deps: cookie-signature@1.0.7
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 concatenation 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
node_modules/express-session/LICENSE generated vendored Normal file
View 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.

1032
node_modules/express-session/README.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

693
node_modules/express-session/index.js generated vendored Normal file
View File

@ -0,0 +1,693 @@
/*!
* 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) {
debug('pathname mismatch')
next()
return
}
// 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
try {
setcookie(res, name, req.sessionID, secrets[0], req.session.cookie.data)
} catch (err) {
defer(next, err)
}
});
// 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;
}

View File

@ -0,0 +1,42 @@
1.0.7 / 2023-04-12
==================
* backport the buffer support from the 1.2.x release branch (thanks @FadhiliNjagi!)
1.0.6 / 2015-02-03
==================
* use `npm test` instead of `make test` to run tests
* clearer assertion messages when checking input
1.0.5 / 2014-09-05
==================
* add license to package.json
1.0.4 / 2014-06-25
==================
* corrected avoidance of timing attacks (thanks @tenbits!)
1.0.3 / 2014-01-28
==================
* [incorrect] fix for timing attacks
1.0.2 / 2014-01-28
==================
* fix missing repository warning
* fix typo in test
1.0.1 / 2013-04-15
==================
* Revert "Changed underlying HMAC algo. to sha512."
* Revert "Fix for timing attacks on MAC verification."
0.0.1 / 2010-01-03
==================
* Initial release

View File

@ -0,0 +1,42 @@
# cookie-signature
Sign and unsign cookies.
## Example
```js
var cookie = require('cookie-signature');
var val = cookie.sign('hello', 'tobiiscool');
val.should.equal('hello.DGDUkGlIkCzPz+C0B064FNgHdEjox7ch8tOBGslZ5QI');
var val = cookie.sign('hello', 'tobiiscool');
cookie.unsign(val, 'tobiiscool').should.equal('hello');
cookie.unsign(val, 'luna').should.be.false;
```
## License
(The MIT License)
Copyright (c) 2012 LearnBoost &lt;tj@learnboost.com&gt;
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.

View File

@ -0,0 +1,51 @@
/**
* Module dependencies.
*/
var crypto = require('crypto');
/**
* Sign the given `val` with `secret`.
*
* @param {String} val
* @param {String|NodeJS.ArrayBufferView|crypto.KeyObject} secret
* @return {String}
* @api private
*/
exports.sign = function(val, secret){
if ('string' !== typeof val) throw new TypeError("Cookie value must be provided as a string.");
if (null == secret) throw new TypeError("Secret key must be provided.");
return val + '.' + crypto
.createHmac('sha256', secret)
.update(val)
.digest('base64')
.replace(/\=+$/, '');
};
/**
* Unsign and decode the given `val` with `secret`,
* returning `false` if the signature is invalid.
*
* @param {String} val
* @param {String|NodeJS.ArrayBufferView|crypto.KeyObject} secret
* @return {String|Boolean}
* @api private
*/
exports.unsign = function(val, secret){
if ('string' !== typeof val) throw new TypeError("Signed cookie string must be provided.");
if (null == secret) throw new TypeError("Secret key must be provided.");
var str = val.slice(0, val.lastIndexOf('.'))
, mac = exports.sign(str, secret);
return sha1(mac) == sha1(val) ? str : false;
};
/**
* Private
*/
function sha1(str){
return crypto.createHash('sha1').update(str).digest('hex');
}

View File

@ -0,0 +1,18 @@
{
"name": "cookie-signature",
"version": "1.0.7",
"description": "Sign and unsign cookies",
"keywords": ["cookie", "sign", "unsign"],
"author": "TJ Holowaychuk <tj@learnboost.com>",
"license": "MIT",
"repository": { "type": "git", "url": "https://github.com/visionmedia/node-cookie-signature.git"},
"dependencies": {},
"devDependencies": {
"mocha": "*",
"should": "*"
},
"scripts": {
"test": "mocha --require should --reporter spec"
},
"main": "index"
}

View 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.

View File

@ -0,0 +1,317 @@
# cookie
[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-url]
[![Node.js Version][node-image]][node-url]
[![Build Status][ci-image]][ci-url]
[![Coverage Status][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.
##### partitioned
Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies)
attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the
`Partitioned` attribute is not set.
**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.
More information about can be found in [the proposal](https://github.com/privacycg/CHIPS).
##### 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].
##### priority
Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1].
- `'low'` will set the `Priority` attribute to `Low`.
- `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
- `'high'` will set the `Priority` attribute to `High`.
More information about the different priority levels can be found in
[the specification][rfc-west-cookie-priority-00-4.1].
**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.
##### sameSite
Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute][rfc-6265bis-09-5.4.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-09-5.4.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.5.0 bench
> node benchmark/index.js
node@18.18.2
acorn@8.10.0
ada@2.6.0
ares@1.19.1
brotli@1.0.9
cldr@43.1
icu@73.2
llhttp@6.0.11
modules@108
napi@9
nghttp2@1.57.0
nghttp3@0.7.0
ngtcp2@0.8.1
openssl@3.0.10+quic
simdutf@3.2.14
tz@2023c
undici@5.26.3
unicode@15.0
uv@1.44.2
uvwasi@0.0.18
v8@10.2.154.26-node.26
zlib@1.2.13.1-motley
> node benchmark/parse-top.js
cookie.parse - top sites
14 tests completed.
parse accounts.google.com x 2,588,913 ops/sec ±0.74% (186 runs sampled)
parse apple.com x 2,370,002 ops/sec ±0.69% (186 runs sampled)
parse cloudflare.com x 2,213,102 ops/sec ±0.88% (188 runs sampled)
parse docs.google.com x 2,194,157 ops/sec ±1.03% (184 runs sampled)
parse drive.google.com x 2,265,084 ops/sec ±0.79% (187 runs sampled)
parse en.wikipedia.org x 457,099 ops/sec ±0.81% (186 runs sampled)
parse linkedin.com x 504,407 ops/sec ±0.89% (186 runs sampled)
parse maps.google.com x 1,230,959 ops/sec ±0.98% (186 runs sampled)
parse microsoft.com x 926,294 ops/sec ±0.88% (184 runs sampled)
parse play.google.com x 2,311,338 ops/sec ±0.83% (185 runs sampled)
parse support.google.com x 1,508,850 ops/sec ±0.86% (186 runs sampled)
parse www.google.com x 1,022,582 ops/sec ±1.32% (182 runs sampled)
parse youtu.be x 332,136 ops/sec ±1.02% (185 runs sampled)
parse youtube.com x 323,833 ops/sec ±0.77% (183 runs sampled)
> node benchmark/parse.js
cookie.parse - generic
6 tests completed.
simple x 3,214,032 ops/sec ±1.61% (183 runs sampled)
decode x 587,237 ops/sec ±1.16% (187 runs sampled)
unquote x 2,954,618 ops/sec ±1.35% (183 runs sampled)
duplicates x 857,008 ops/sec ±0.89% (187 runs sampled)
10 cookies x 292,133 ops/sec ±0.89% (187 runs sampled)
100 cookies x 22,610 ops/sec ±0.68% (187 runs sampled)
```
## References
- [RFC 6265: HTTP State Management Mechanism][rfc-6265]
- [Same-site Cookies][rfc-6265bis-09-5.4.7]
[rfc-cutler-httpbis-partitioned-cookies]: https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/
[rfc-west-cookie-priority-00-4.1]: https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1
[rfc-6265bis-09-5.4.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.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)
[ci-image]: https://badgen.net/github/checks/jshttp/cookie/master?label=ci
[ci-url]: https://github.com/jshttp/cookie/actions/workflows/ci.yml
[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/cookie/master
[coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master
[node-image]: https://badgen.net/npm/node/cookie
[node-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

View File

@ -0,0 +1,25 @@
# Security Policies and Procedures
## Reporting a Bug
The `cookie` team and community take all security bugs seriously. Thank
you for improving the security of the project. We appreciate your efforts and
responsible disclosure and will make every effort to acknowledge your
contributions.
Report security bugs by emailing the current owner(s) of `cookie`. This
information can be found in the npm registry using the command
`npm owner ls cookie`.
If unsure or unable to get the information from the above, open an issue
in the [project issue tracker](https://github.com/jshttp/cookie/issues)
asking for the current contact information.
To ensure the timely response to your report, please ensure that the entirety
of the report is contained within the email body and not solely behind a web
link or an attachment.
At least one owner will acknowledge your email within 48 hours, and will send a
more detailed response within 48 hours indicating the next steps in handling
your report. After the initial reply to your report, the owners will
endeavor to keep you informed of the progress towards a fix and full
announcement, and may ask for additional information or guidance.

View File

@ -0,0 +1,335 @@
/*!
* 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 __toString = Object.prototype.toString
var __hasOwnProperty = Object.prototype.hasOwnProperty
/**
* RegExp to match cookie-name in RFC 6265 sec 4.1.1
* This refers out to the obsoleted definition of token in RFC 2616 sec 2.2
* which has been replaced by the token definition in RFC 7230 appendix B.
*
* cookie-name = token
* token = 1*tchar
* tchar = "!" / "#" / "$" / "%" / "&" / "'" /
* "*" / "+" / "-" / "." / "^" / "_" /
* "`" / "|" / "~" / DIGIT / ALPHA
*/
var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
/**
* RegExp to match cookie-value in RFC 6265 sec 4.1.1
*
* cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
* cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
* ; US-ASCII characters excluding CTLs,
* ; whitespace DQUOTE, comma, semicolon,
* ; and backslash
*/
var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;
/**
* RegExp to match domain-value in RFC 6265 sec 4.1.1
*
* domain-value = <subdomain>
* ; defined in [RFC1034], Section 3.5, as
* ; enhanced by [RFC1123], Section 2.1
* <subdomain> = <label> | <subdomain> "." <label>
* <label> = <let-dig> [ [ <ldh-str> ] <let-dig> ]
* Labels must be 63 characters or less.
* 'let-dig' not 'letter' in the first char, per RFC1123
* <ldh-str> = <let-dig-hyp> | <let-dig-hyp> <ldh-str>
* <let-dig-hyp> = <let-dig> | "-"
* <let-dig> = <letter> | <digit>
* <letter> = any one of the 52 alphabetic characters A through Z in
* upper case and a through z in lower case
* <digit> = any one of the ten digits 0 through 9
*
* Keep support for leading dot: https://github.com/jshttp/cookie/issues/173
*
* > (Note that a leading %x2E ("."), if present, is ignored even though that
* character is not permitted, but a trailing %x2E ("."), if present, will
* cause the user agent to ignore the attribute.)
*/
var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
/**
* RegExp to match path-value in RFC 6265 sec 4.1.1
*
* path-value = <any CHAR except CTLs or ";">
* CHAR = %x01-7F
* ; defined in RFC 5234 appendix B.1
*/
var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
/**
* 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} [opt]
* @return {object}
* @public
*/
function parse(str, opt) {
if (typeof str !== 'string') {
throw new TypeError('argument str must be a string');
}
var obj = {};
var len = str.length;
// RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.
if (len < 2) return obj;
var dec = (opt && opt.decode) || decode;
var index = 0;
var eqIdx = 0;
var endIdx = 0;
do {
eqIdx = str.indexOf('=', index);
if (eqIdx === -1) break; // No more cookie pairs.
endIdx = str.indexOf(';', index);
if (endIdx === -1) {
endIdx = len;
} else if (eqIdx > endIdx) {
// backtrack on prior semicolon
index = str.lastIndexOf(';', eqIdx - 1) + 1;
continue;
}
var keyStartIdx = startIndex(str, index, eqIdx);
var keyEndIdx = endIndex(str, eqIdx, keyStartIdx);
var key = str.slice(keyStartIdx, keyEndIdx);
// only assign once
if (!__hasOwnProperty.call(obj, key)) {
var valStartIdx = startIndex(str, eqIdx + 1, endIdx);
var valEndIdx = endIndex(str, endIdx, valStartIdx);
if (str.charCodeAt(valStartIdx) === 0x22 /* " */ && str.charCodeAt(valEndIdx - 1) === 0x22 /* " */) {
valStartIdx++;
valEndIdx--;
}
var val = str.slice(valStartIdx, valEndIdx);
obj[key] = tryDecode(val, dec);
}
index = endIdx + 1
} while (index < len);
return obj;
}
function startIndex(str, index, max) {
do {
var code = str.charCodeAt(index);
if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index;
} while (++index < max);
return max;
}
function endIndex(str, index, min) {
while (index > min) {
var code = str.charCodeAt(--index);
if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index + 1;
}
return min;
}
/**
* Serialize data into a cookie header.
*
* Serialize a name value pair into a cookie string suitable for
* http headers. An optional options object specifies cookie parameters.
*
* serialize('foo', 'bar', { httpOnly: true })
* => "foo=bar; httpOnly"
*
* @param {string} name
* @param {string} val
* @param {object} [opt]
* @return {string}
* @public
*/
function serialize(name, val, opt) {
var enc = (opt && opt.encode) || encodeURIComponent;
if (typeof enc !== 'function') {
throw new TypeError('option encode is invalid');
}
if (!cookieNameRegExp.test(name)) {
throw new TypeError('argument name is invalid');
}
var value = enc(val);
if (!cookieValueRegExp.test(value)) {
throw new TypeError('argument val is invalid');
}
var str = name + '=' + value;
if (!opt) return str;
if (null != opt.maxAge) {
var maxAge = Math.floor(opt.maxAge);
if (!isFinite(maxAge)) {
throw new TypeError('option maxAge is invalid')
}
str += '; Max-Age=' + maxAge;
}
if (opt.domain) {
if (!domainValueRegExp.test(opt.domain)) {
throw new TypeError('option domain is invalid');
}
str += '; Domain=' + opt.domain;
}
if (opt.path) {
if (!pathValueRegExp.test(opt.path)) {
throw new TypeError('option path is invalid');
}
str += '; Path=' + opt.path;
}
if (opt.expires) {
var expires = opt.expires
if (!isDate(expires) || isNaN(expires.valueOf())) {
throw new TypeError('option expires is invalid');
}
str += '; Expires=' + expires.toUTCString()
}
if (opt.httpOnly) {
str += '; HttpOnly';
}
if (opt.secure) {
str += '; Secure';
}
if (opt.partitioned) {
str += '; Partitioned'
}
if (opt.priority) {
var priority = typeof opt.priority === 'string'
? opt.priority.toLowerCase() : opt.priority;
switch (priority) {
case 'low':
str += '; Priority=Low'
break
case 'medium':
str += '; Priority=Medium'
break
case 'high':
str += '; Priority=High'
break
default:
throw new TypeError('option priority is invalid')
}
}
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;
}
/**
* URL-decode string value. Optimized to skip native call when no %.
*
* @param {string} str
* @returns {string}
*/
function decode (str) {
return str.indexOf('%') !== -1
? decodeURIComponent(str)
: str
}
/**
* Determine if value is a Date.
*
* @param {*} val
* @private
*/
function isDate (val) {
return __toString.call(val) === '[object Date]';
}
/**
* 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;
}
}

View File

@ -0,0 +1,44 @@
{
"name": "cookie",
"description": "HTTP server cookie parsing and serialization",
"version": "0.7.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": "8.53.0",
"eslint-plugin-markdown": "3.0.1",
"mocha": "10.2.0",
"nyc": "15.1.0",
"safe-buffer": "5.2.1",
"top-sites": "1.1.194"
},
"files": [
"HISTORY.md",
"LICENSE",
"README.md",
"SECURITY.md",
"index.js"
],
"main": "index.js",
"engines": {
"node": ">= 0.6"
},
"scripts": {
"bench": "node benchmark/index.js",
"lint": "eslint .",
"test": "mocha --reporter spec --bail --check-leaks 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"
}
}

47
node_modules/express-session/package.json generated vendored Normal file
View File

@ -0,0 +1,47 @@
{
"name": "express-session",
"version": "1.18.2",
"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.7.2",
"cookie-signature": "1.0.7",
"debug": "2.6.9",
"depd": "~2.0.0",
"on-headers": "~1.1.0",
"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": "8.56.0",
"eslint-plugin-markdown": "3.0.1",
"express": "4.17.3",
"mocha": "10.8.2",
"nyc": "15.1.0",
"supertest": "6.3.4"
},
"files": [
"session/",
"HISTORY.md",
"index.js"
],
"engines": {
"node": ">= 0.8.0"
},
"scripts": {
"lint": "eslint . && node ./scripts/lint-readme.js",
"test": "./test/support/gencert.sh && 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"
}
}

152
node_modules/express-session/session/cookie.js generated vendored Normal file
View File

@ -0,0 +1,152 @@
/*!
* 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,
partitioned: this.partitioned,
priority: this.priority
, 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
node_modules/express-session/session/memory.js generated vendored Normal file
View 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
node_modules/express-session/session/session.js generated vendored Normal file
View 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
node_modules/express-session/session/store.js generated vendored Normal file
View 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;
};

26
node_modules/on-headers/HISTORY.md generated vendored Normal file
View File

@ -0,0 +1,26 @@
1.1.0 / 2025-07-17
==================
* - Fix [CVE-2025-7339](https://www.cve.org/CVERecord?id=CVE-2025-7339) ([GHSA-76c9-3jph-rj3q](https://github.com/expressjs/multer/security/advisories/GHSA-76c9-3jph-rj3q))
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
node_modules/on-headers/LICENSE generated vendored Normal file
View 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
node_modules/on-headers/README.md generated vendored Normal file
View 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-image]][node-url]
[![Build Status][ci-image]][ci-url]
[![Coverage Status][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)
[ci-image]: https://badgen.net/github/checks/jshttp/on-headers/master?label=ci
[ci-url]: https://github.com/jshttp/on-headers/actions/workflows/ci.yml
[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/on-headers/master
[coveralls-url]: https://coveralls.io/r/jshttp/on-headers?branch=master
[node-image]: https://badgen.net/npm/node/on-headers
[node-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

180
node_modules/on-headers/index.js generated vendored Normal file
View File

@ -0,0 +1,180 @@
/*!
* on-headers
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module exports.
* @public
*/
module.exports = onHeaders
var http = require('http')
// older node versions don't have appendHeader
var isAppendHeaderSupported = typeof http.ServerResponse.prototype.appendHeader === 'function'
var set1dArray = isAppendHeaderSupported ? set1dArrayWithAppend : set1dArrayWithSet
/**
* 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) {
if (headers.length && Array.isArray(headers[0])) {
// 2D
set2dArray(res, headers)
} else {
// 1D
if (headers.length % 2 !== 0) {
throw new TypeError('headers array is malformed')
}
set1dArray(res, headers)
}
}
/**
* 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
}
function set2dArray (res, headers) {
var key
for (var i = 0; i < headers.length; i++) {
key = headers[i][0]
if (key) {
res.setHeader(key, headers[i][1])
}
}
}
function set1dArrayWithAppend (res, headers) {
for (var i = 0; i < headers.length; i += 2) {
res.removeHeader(headers[i])
}
var key
for (var j = 0; j < headers.length; j += 2) {
key = headers[j]
if (key) {
res.appendHeader(key, headers[j + 1])
}
}
}
function set1dArrayWithSet (res, headers) {
var key
for (var i = 0; i < headers.length; i += 2) {
key = headers[i]
if (key) {
res.setHeader(key, headers[i + 1])
}
}
}

44
node_modules/on-headers/package.json generated vendored Normal file
View File

@ -0,0 +1,44 @@
{
"name": "on-headers",
"description": "Execute a listener when a response is about to write headers",
"version": "1.1.0",
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
"license": "MIT",
"keywords": [
"event",
"headers",
"http",
"onheaders"
],
"repository": "jshttp/on-headers",
"devDependencies": {
"eslint": "6.8.0",
"eslint-config-standard": "14.1.1",
"eslint-plugin-import": "2.21.2",
"eslint-plugin-markdown": "1.0.2",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-standard": "4.0.1",
"mocha": "10.2.0",
"nyc": "15.1.0",
"supertest": "4.0.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 --check-leaks test/test.js",
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
"test-cov": "nyc --reporter=html --reporter=text npm test",
"update-upstream-hashes": "node scripts/update-upstream-hashes.js",
"upstream": "mocha --reporter spec --check-leaks test/upstream.js",
"version": "node scripts/version-history.js && git add HISTORY.md"
}
}

42
node_modules/querystring/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,42 @@
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.2.1](https://github.com/Gozala/querystring/compare/v0.2.0...v0.2.1) (2021-02-15)
_Maintanance update_
## [0.2.0] - 2013-02-21
### Changed
- Refactor into function per-module idiomatic style.
- Improved test coverage.
## [0.1.0] - 2011-12-13
### Changed
- Minor project reorganization
## [0.0.3] - 2011-04-16
### Added
- Support for AMD module loaders
## [0.0.2] - 2011-04-16
### Changed
- Ported unit tests
### Removed
- Removed functionality that depended on Buffers
## [0.0.1] - 2011-04-15
### Added
- Initial release

7
node_modules/querystring/LICENSE generated vendored Normal file
View File

@ -0,0 +1,7 @@
Copyright 2012 Irakli Gozalishvili
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.

22
node_modules/querystring/README.md generated vendored Normal file
View File

@ -0,0 +1,22 @@
# querystring
[![NPM](https://img.shields.io/npm/v/querystring.svg)](https://npm.im/querystring)
[![gzip](https://badgen.net/bundlephobia/minzip/querystring@latest)](https://bundlephobia.com/result?p=querystring@latest)
Node's querystring module for all engines.
_If you want to help with evolution of this package, please see https://github.com/Gozala/querystring/issues/20 PR's welcome!_
## 🔧 Install
```sh
npm i querystring
```
## 📖 Documentation
Refer to [Node's documentation for `querystring`](https://nodejs.org/api/querystring.html).
## 📜 License
MIT &copy; [Gozala](https://github.com/Gozala)

20
node_modules/querystring/decode.d.ts generated vendored Normal file
View File

@ -0,0 +1,20 @@
/**
* parses a URL query string into a collection of key and value pairs
*
* @param qs The URL query string to parse
* @param sep The substring used to delimit key and value pairs in the query string
* @param eq The substring used to delimit keys and values in the query string
* @param options.decodeURIComponent The function to use when decoding percent-encoded characters in the query string
* @param options.maxKeys Specifies the maximum number of keys to parse. Specify 0 to remove key counting limitations default 1000
*/
export type decodeFuncType = (
qs?: string,
sep?: string,
eq?: string,
options?: {
decodeURIComponent?: Function;
maxKeys?: number;
}
) => Record<any, unknown>;
export default decodeFuncType;

80
node_modules/querystring/decode.js generated vendored Normal file
View File

@ -0,0 +1,80 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.
'use strict';
// If obj.hasOwnProperty has been overridden, then calling
// obj.hasOwnProperty(prop) will break.
// See: https://github.com/joyent/node/issues/1707
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
module.exports = function(qs, sep, eq, options) {
sep = sep || '&';
eq = eq || '=';
var obj = {};
if (typeof qs !== 'string' || qs.length === 0) {
return obj;
}
var regexp = /\+/g;
qs = qs.split(sep);
var maxKeys = 1000;
if (options && typeof options.maxKeys === 'number') {
maxKeys = options.maxKeys;
}
var len = qs.length;
// maxKeys <= 0 means that we should not limit keys count
if (maxKeys > 0 && len > maxKeys) {
len = maxKeys;
}
for (var i = 0; i < len; ++i) {
var x = qs[i].replace(regexp, '%20'),
idx = x.indexOf(eq),
kstr, vstr, k, v;
if (idx >= 0) {
kstr = x.substr(0, idx);
vstr = x.substr(idx + 1);
} else {
kstr = x;
vstr = '';
}
k = decodeURIComponent(kstr);
v = decodeURIComponent(vstr);
if (!hasOwnProperty(obj, k)) {
obj[k] = v;
} else if (Array.isArray(obj[k])) {
obj[k].push(v);
} else {
obj[k] = [obj[k], v];
}
}
return obj;
};

18
node_modules/querystring/encode.d.ts generated vendored Normal file
View File

@ -0,0 +1,18 @@
/**
* It serializes passed object into string
* The numeric values must be finite.
* Any other input values will be coerced to empty strings.
*
* @param obj The object to serialize into a URL query string
* @param sep The substring used to delimit key and value pairs in the query string
* @param eq The substring used to delimit keys and values in the query string
* @param name
*/
export type encodeFuncType = (
obj?: Record<any, unknown>,
sep?: string,
eq?: string,
name?: any
) => string;
export default encodeFuncType;

64
node_modules/querystring/encode.js generated vendored Normal file
View File

@ -0,0 +1,64 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.
'use strict';
var stringifyPrimitive = function(v) {
switch (typeof v) {
case 'string':
return v;
case 'boolean':
return v ? 'true' : 'false';
case 'number':
return isFinite(v) ? v : '';
default:
return '';
}
};
module.exports = function(obj, sep, eq, name) {
sep = sep || '&';
eq = eq || '=';
if (obj === null) {
obj = undefined;
}
if (typeof obj === 'object') {
return Object.keys(obj).map(function(k) {
var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
if (Array.isArray(obj[k])) {
return obj[k].map(function(v) {
return ks + encodeURIComponent(stringifyPrimitive(v));
}).join(sep);
} else {
return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
}
}).filter(Boolean).join(sep);
}
if (!name) return '';
return encodeURIComponent(stringifyPrimitive(name)) + eq +
encodeURIComponent(stringifyPrimitive(obj));
};

8
node_modules/querystring/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,8 @@
import decodeFuncType from "./decode";
import encodeFuncType from "./encode";
export const decode: decodeFuncType;
export const parse: decodeFuncType;
export const encode: encodeFuncType;
export const stringify: encodeFuncType;

4
node_modules/querystring/index.js generated vendored Normal file
View File

@ -0,0 +1,4 @@
'use strict';
exports.decode = exports.parse = require('./decode');
exports.encode = exports.stringify = require('./encode');

35
node_modules/querystring/package.json generated vendored Normal file
View File

@ -0,0 +1,35 @@
{
"name": "querystring",
"id": "querystring",
"version": "0.2.1",
"description": "Node's querystring module for all engines.",
"keywords": [
"commonjs",
"query",
"querystring"
],
"author": "Irakli Gozalishvili <rfobic@gmail.com>",
"main": "index.js",
"repository": {
"type": "git",
"url": "git://github.com/Gozala/querystring.git",
"web": "https://github.com/Gozala/querystring"
},
"bugs": {
"url": "http://github.com/Gozala/querystring/issues/"
},
"devDependencies": {
"test": "~0.x.0",
"retape": "~0.x.0",
"tape": "~0.1.5"
},
"engines": {
"node": ">=0.4.x"
},
"scripts": {
"test": "npm run test-node && npm run test-tap",
"test-node": "node ./test/common-index.js",
"test-tap": "node ./test/tap-index.js"
},
"license": "MIT"
}

4
node_modules/random-bytes/HISTORY.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
1.0.0 / 2016-01-17
==================
* Initial release

21
node_modules/random-bytes/LICENSE generated vendored Normal file
View 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
node_modules/random-bytes/README.md generated vendored Normal file
View 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
node_modules/random-bytes/index.js generated vendored Normal file
View 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
node_modules/random-bytes/package.json generated vendored Normal file
View 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
node_modules/uid-safe/HISTORY.md generated vendored Normal file
View 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
node_modules/uid-safe/LICENSE generated vendored Normal file
View 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
node_modules/uid-safe/README.md generated vendored Normal file
View 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
node_modules/uid-safe/index.js generated vendored Normal file
View 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
node_modules/uid-safe/package.json generated vendored Normal file
View 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"
]
}

82
package-lock.json generated
View File

@ -9,14 +9,16 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"axios": "^1.0.0",
"axios": "^1.12.2",
"cors": "^2.8.5",
"csv-parser": "^3.0.0",
"dotenv": "^17.2.3",
"express": "^4.18.2",
"express-session": "^1.18.2",
"fast-csv": "^4.3.6",
"ipaddr.js": "^2.2.0",
"multer": "*"
"multer": "*",
"querystring": "^0.2.1"
}
},
"node_modules/@fast-csv/format": {
@ -98,6 +100,7 @@
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
@ -295,6 +298,7 @@
"version": "17.2.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
@ -427,6 +431,40 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/express-session": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz",
"integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==",
"license": "MIT",
"dependencies": {
"cookie": "0.7.2",
"cookie-signature": "1.0.7",
"debug": "2.6.9",
"depd": "~2.0.0",
"on-headers": "~1.1.0",
"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.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express-session/node_modules/cookie-signature": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
"license": "MIT"
},
"node_modules/fast-csv": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz",
@ -828,6 +866,15 @@
"node": ">= 0.8"
}
},
"node_modules/on-headers": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -880,6 +927,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/querystring": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz",
"integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==",
"deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
"license": "MIT",
"engines": {
"node": ">=0.4.x"
}
},
"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==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@ -1111,6 +1177,18 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
},
"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==",
"license": "MIT",
"dependencies": {
"random-bytes": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

View File

@ -10,13 +10,15 @@
"author": "",
"license": "MIT",
"dependencies": {
"axios": "^1.0.0",
"axios": "^1.12.2",
"cors": "^2.8.5",
"csv-parser": "^3.0.0",
"dotenv": "^17.2.3",
"express": "^4.18.2",
"express-session": "^1.18.2",
"fast-csv": "^4.3.6",
"ipaddr.js": "^2.2.0",
"multer": "*"
"multer": "*",
"querystring": "^0.2.1"
}
}

View File

@ -1,5 +1,11 @@
require('dotenv').config();
// --- OAuth Office 365 ---
const querystring = require('querystring');
const session = require('express-session');
const express = require('express');
const multer = require('multer');
const fs = require('fs');
@ -431,6 +437,98 @@ app.get('/consulta-cep', async (req, res) => {
}
});
// Configura sessão (precisa vir antes das rotas)
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
}));
// Middleware simples pra proteger rotas
function ensureAuthenticated(req, res, next) {
if (req.session.user) return next();
return res.redirect('/login');
}
// === LOGIN COM OFFICE 365 ===
// Inicia o login (redireciona pro Microsoft)
app.get('/login', (req, res) => {
const authUrl = new URL(`https://login.microsoftonline.com/${process.env.OAUTH_TENANT_ID}/oauth2/v2.0/authorize`);
authUrl.search = new URLSearchParams({
client_id: process.env.OAUTH_CLIENT_ID,
response_type: 'code',
redirect_uri: process.env.OAUTH_REDIRECT_URI,
response_mode: 'query',
scope: process.env.OAUTH_SCOPES,
state: '12345'
}).toString();
res.redirect(authUrl);
});
// Callback chamado pela Microsoft após login
app.get('/auth/callback', async (req, res) => {
const code = req.query.code;
if (!code) return res.status(400).send('Código de autorização não encontrado.');
try {
// Troca o código pelo token
const tokenUrl = `https://login.microsoftonline.com/${process.env.OAUTH_TENANT_ID}/oauth2/v2.0/token`;
const body = querystring.stringify({
client_id: process.env.OAUTH_CLIENT_ID,
scope: process.env.OAUTH_SCOPES,
code,
redirect_uri: process.env.OAUTH_REDIRECT_URI,
grant_type: 'authorization_code',
client_secret: process.env.OAUTH_CLIENT_SECRET
});
const tokenResponse = await axios.post(tokenUrl, body, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
const accessToken = tokenResponse.data.access_token;
// Busca dados do usuário logado (Graph API)
const userResponse = await axios.get('https://graph.microsoft.com/v1.0/me', {
headers: { Authorization: `Bearer ${accessToken}` }
});
// Guarda usuário e token na sessão
req.session.user = userResponse.data;
req.session.accessToken = accessToken;
console.log('Usuário logado:', userResponse.data);
// Redireciona para a página principal autenticada
res.redirect('/home');
} catch (error) {
console.error('Erro no login OAuth:', error.response?.data || error.message);
res.status(500).send('Erro ao autenticar com Office 365.');
}
});
// Página protegida (somente logados)
app.get('/home', ensureAuthenticated, (req, res) => {
const user = req.session.user;
res.send(`
<h1>Bem-vindo, ${user.displayName}!</h1>
<p>Email: ${user.mail || user.userPrincipalName}</p>
<a href="/logout">Sair</a>
`);
});
// Logout (remove sessão)
app.get('/logout', (req, res) => {
req.session.destroy(() => {
res.redirect('/');
});
});
// Inicia o servidor
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));

39
service/authService.js Normal file
View File

@ -0,0 +1,39 @@
import axios from "axios";
import dotenv from "dotenv";
dotenv.config();
const tenantId = process.env.OAUTH_TENANT_ID;
const clientId = process.env.OAUTH_CLIENT_ID;
const clientSecret = process.env.OAUTH_CLIENT_SECRET;
const redirectUri = process.env.OAUTH_REDIRECT_URI;
// Função que gera o link de login para o usuário
export function getAuthUrl() {
const params = new URLSearchParams({
client_id: clientId,
response_type: "code",
redirect_uri: redirectUri,
response_mode: "query",
scope: "offline_access https://graph.microsoft.com/.default",
state: "12345",
});
return `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize?${params.toString()}`;
}
// Troca o "authorization code" por tokens
export async function getTokenFromCode(authCode) {
const url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
const params = new URLSearchParams({
client_id: clientId,
scope: "https://graph.microsoft.com/.default",
code: authCode,
redirect_uri: redirectUri,
grant_type: "authorization_code",
client_secret: clientSecret,
});
const response = await axios.post(url, params);
return response.data;
}