root / HServer / 00.Server / 00.Program / node_modules / express-session / index.js
이력 | 보기 | 이력해설 | 다운로드 (15.4 KB)
| 1 | 39 | HKM | /*!
|
|---|---|---|---|
| 2 | * express-session
|
||
| 3 | * Copyright(c) 2010 Sencha Inc.
|
||
| 4 | * Copyright(c) 2011 TJ Holowaychuk
|
||
| 5 | * Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||
| 6 | * MIT Licensed
|
||
| 7 | */
|
||
| 8 | |||
| 9 | 'use strict';
|
||
| 10 | |||
| 11 | /**
|
||
| 12 | * Module dependencies.
|
||
| 13 | * @private
|
||
| 14 | */
|
||
| 15 | |||
| 16 | var cookie = require('cookie'); |
||
| 17 | var crc = require('crc').crc32; |
||
| 18 | var debug = require('debug')('express-session'); |
||
| 19 | var deprecate = require('depd')('express-session'); |
||
| 20 | var parseUrl = require('parseurl'); |
||
| 21 | var uid = require('uid-safe').sync |
||
| 22 | , onHeaders = require('on-headers')
|
||
| 23 | , signature = require('cookie-signature')
|
||
| 24 | |||
| 25 | var Session = require('./session/session') |
||
| 26 | , MemoryStore = require('./session/memory')
|
||
| 27 | , Cookie = require('./session/cookie')
|
||
| 28 | , Store = require('./session/store')
|
||
| 29 | |||
| 30 | // environment
|
||
| 31 | |||
| 32 | var env = process.env.NODE_ENV;
|
||
| 33 | |||
| 34 | /**
|
||
| 35 | * Expose the middleware.
|
||
| 36 | */
|
||
| 37 | |||
| 38 | exports = module.exports = session; |
||
| 39 | |||
| 40 | /**
|
||
| 41 | * Expose constructors.
|
||
| 42 | */
|
||
| 43 | |||
| 44 | exports.Store = Store; |
||
| 45 | exports.Cookie = Cookie; |
||
| 46 | exports.Session = Session; |
||
| 47 | exports.MemoryStore = MemoryStore; |
||
| 48 | |||
| 49 | /**
|
||
| 50 | * Warning message for `MemoryStore` usage in production.
|
||
| 51 | * @private
|
||
| 52 | */
|
||
| 53 | |||
| 54 | var warning = 'Warning: connect.session() MemoryStore is not\n' |
||
| 55 | + 'designed for a production environment, as it will leak\n'
|
||
| 56 | + 'memory, and will not scale past a single process.';
|
||
| 57 | |||
| 58 | /**
|
||
| 59 | * Node.js 0.8+ async implementation.
|
||
| 60 | * @private
|
||
| 61 | */
|
||
| 62 | |||
| 63 | /* istanbul ignore next */
|
||
| 64 | var defer = typeof setImmediate === 'function' |
||
| 65 | ? setImmediate
|
||
| 66 | : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) } |
||
| 67 | |||
| 68 | /**
|
||
| 69 | * Setup session store with the given `options`.
|
||
| 70 | *
|
||
| 71 | * @param {Object} [options]
|
||
| 72 | * @param {Object} [options.cookie] Options for cookie
|
||
| 73 | * @param {Function} [options.genid]
|
||
| 74 | * @param {String} [options.name=connect.sid] Session ID cookie name
|
||
| 75 | * @param {Boolean} [options.proxy]
|
||
| 76 | * @param {Boolean} [options.resave] Resave unmodified sessions back to the store
|
||
| 77 | * @param {Boolean} [options.rolling] Enable/disable rolling session expiration
|
||
| 78 | * @param {Boolean} [options.saveUninitialized] Save uninitialized sessions to the store
|
||
| 79 | * @param {String|Array} [options.secret] Secret for signing session ID
|
||
| 80 | * @param {Object} [options.store=MemoryStore] Session store
|
||
| 81 | * @param {String} [options.unset]
|
||
| 82 | * @return {Function} middleware
|
||
| 83 | * @public
|
||
| 84 | */
|
||
| 85 | |||
| 86 | function session(options) { |
||
| 87 | var opts = options || {}
|
||
| 88 | |||
| 89 | // get the cookie options
|
||
| 90 | var cookieOptions = opts.cookie || {}
|
||
| 91 | |||
| 92 | // get the session id generate function
|
||
| 93 | var generateId = opts.genid || generateSessionId
|
||
| 94 | |||
| 95 | // get the session cookie name
|
||
| 96 | var name = opts.name || opts.key || 'connect.sid' |
||
| 97 | |||
| 98 | // get the session store
|
||
| 99 | var store = opts.store || new MemoryStore() |
||
| 100 | |||
| 101 | // get the trust proxy setting
|
||
| 102 | var trustProxy = opts.proxy
|
||
| 103 | |||
| 104 | // get the resave session option
|
||
| 105 | var resaveSession = opts.resave;
|
||
| 106 | |||
| 107 | // get the rolling session option
|
||
| 108 | var rollingSessions = Boolean(opts.rolling)
|
||
| 109 | |||
| 110 | // get the save uninitialized session option
|
||
| 111 | var saveUninitializedSession = opts.saveUninitialized
|
||
| 112 | |||
| 113 | // get the cookie signing secret
|
||
| 114 | var secret = opts.secret
|
||
| 115 | |||
| 116 | if (typeof generateId !== 'function') { |
||
| 117 | throw new TypeError('genid option must be a function'); |
||
| 118 | } |
||
| 119 | |||
| 120 | if (resaveSession === undefined) { |
||
| 121 | deprecate('undefined resave option; provide resave option');
|
||
| 122 | resaveSession = true;
|
||
| 123 | } |
||
| 124 | |||
| 125 | if (saveUninitializedSession === undefined) { |
||
| 126 | deprecate('undefined saveUninitialized option; provide saveUninitialized option');
|
||
| 127 | saveUninitializedSession = true;
|
||
| 128 | } |
||
| 129 | |||
| 130 | if (opts.unset && opts.unset !== 'destroy' && opts.unset !== 'keep') { |
||
| 131 | throw new TypeError('unset option must be "destroy" or "keep"'); |
||
| 132 | } |
||
| 133 | |||
| 134 | // TODO: switch to "destroy" on next major
|
||
| 135 | var unsetDestroy = opts.unset === 'destroy' |
||
| 136 | |||
| 137 | if (Array.isArray(secret) && secret.length === 0) { |
||
| 138 | throw new TypeError('secret option array must contain one or more strings'); |
||
| 139 | } |
||
| 140 | |||
| 141 | if (secret && !Array.isArray(secret)) {
|
||
| 142 | secret = [secret]; |
||
| 143 | } |
||
| 144 | |||
| 145 | if (!secret) {
|
||
| 146 | deprecate('req.secret; provide secret option');
|
||
| 147 | } |
||
| 148 | |||
| 149 | // notify user that this store is not
|
||
| 150 | // meant for a production environment
|
||
| 151 | /* istanbul ignore next: not tested */
|
||
| 152 | if ('production' == env && store instanceof MemoryStore) { |
||
| 153 | console.warn(warning); |
||
| 154 | } |
||
| 155 | |||
| 156 | // generates the new session
|
||
| 157 | store.generate = function(req){ |
||
| 158 | req.sessionID = generateId(req); |
||
| 159 | req.session = new Session(req);
|
||
| 160 | req.session.cookie = new Cookie(cookieOptions);
|
||
| 161 | |||
| 162 | if (cookieOptions.secure === 'auto') { |
||
| 163 | req.session.cookie.secure = issecure(req, trustProxy); |
||
| 164 | } |
||
| 165 | }; |
||
| 166 | |||
| 167 | var storeImplementsTouch = typeof store.touch === 'function'; |
||
| 168 | |||
| 169 | // register event listeners for the store to track readiness
|
||
| 170 | var storeReady = true |
||
| 171 | store.on('disconnect', function ondisconnect() { |
||
| 172 | storeReady = false
|
||
| 173 | }) |
||
| 174 | store.on('connect', function onconnect() { |
||
| 175 | storeReady = true
|
||
| 176 | }) |
||
| 177 | |||
| 178 | return function session(req, res, next) { |
||
| 179 | // self-awareness
|
||
| 180 | if (req.session) {
|
||
| 181 | next() |
||
| 182 | return
|
||
| 183 | } |
||
| 184 | |||
| 185 | // Handle connection as if there is no session if
|
||
| 186 | // the store has temporarily disconnected etc
|
||
| 187 | if (!storeReady) {
|
||
| 188 | debug('store is disconnected')
|
||
| 189 | next() |
||
| 190 | return
|
||
| 191 | } |
||
| 192 | |||
| 193 | // pathname mismatch
|
||
| 194 | var originalPath = parseUrl.original(req).pathname || '/' |
||
| 195 | if (originalPath.indexOf(cookieOptions.path || '/') !== 0) return next(); |
||
| 196 | |||
| 197 | // ensure a secret is available or bail
|
||
| 198 | if (!secret && !req.secret) {
|
||
| 199 | next(new Error('secret option required for sessions')); |
||
| 200 | return;
|
||
| 201 | } |
||
| 202 | |||
| 203 | // backwards compatibility for signed cookies
|
||
| 204 | // req.secret is passed from the cookie parser middleware
|
||
| 205 | var secrets = secret || [req.secret];
|
||
| 206 | |||
| 207 | var originalHash;
|
||
| 208 | var originalId;
|
||
| 209 | var savedHash;
|
||
| 210 | var touched = false |
||
| 211 | |||
| 212 | // expose store
|
||
| 213 | req.sessionStore = store; |
||
| 214 | |||
| 215 | // get the session ID from the cookie
|
||
| 216 | var cookieId = req.sessionID = getcookie(req, name, secrets);
|
||
| 217 | |||
| 218 | // set-cookie
|
||
| 219 | onHeaders(res, function(){
|
||
| 220 | if (!req.session) {
|
||
| 221 | debug('no session');
|
||
| 222 | return;
|
||
| 223 | } |
||
| 224 | |||
| 225 | if (!shouldSetCookie(req)) {
|
||
| 226 | return;
|
||
| 227 | } |
||
| 228 | |||
| 229 | // only send secure cookies via https
|
||
| 230 | if (req.session.cookie.secure && !issecure(req, trustProxy)) {
|
||
| 231 | debug('not secured');
|
||
| 232 | return;
|
||
| 233 | } |
||
| 234 | |||
| 235 | if (!touched) {
|
||
| 236 | // touch session
|
||
| 237 | req.session.touch() |
||
| 238 | touched = true
|
||
| 239 | } |
||
| 240 | |||
| 241 | // set cookie
|
||
| 242 | setcookie(res, name, req.sessionID, secrets[0], req.session.cookie.data);
|
||
| 243 | }); |
||
| 244 | |||
| 245 | // proxy end() to commit the session
|
||
| 246 | var _end = res.end;
|
||
| 247 | var _write = res.write;
|
||
| 248 | var ended = false; |
||
| 249 | res.end = function end(chunk, encoding) { |
||
| 250 | if (ended) {
|
||
| 251 | return false; |
||
| 252 | } |
||
| 253 | |||
| 254 | ended = true;
|
||
| 255 | |||
| 256 | var ret;
|
||
| 257 | var sync = true; |
||
| 258 | |||
| 259 | function writeend() { |
||
| 260 | if (sync) {
|
||
| 261 | ret = _end.call(res, chunk, encoding); |
||
| 262 | sync = false;
|
||
| 263 | return;
|
||
| 264 | } |
||
| 265 | |||
| 266 | _end.call(res); |
||
| 267 | } |
||
| 268 | |||
| 269 | function writetop() { |
||
| 270 | if (!sync) {
|
||
| 271 | return ret;
|
||
| 272 | } |
||
| 273 | |||
| 274 | if (chunk == null) { |
||
| 275 | ret = true;
|
||
| 276 | return ret;
|
||
| 277 | } |
||
| 278 | |||
| 279 | var contentLength = Number(res.getHeader('Content-Length')); |
||
| 280 | |||
| 281 | if (!isNaN(contentLength) && contentLength > 0) { |
||
| 282 | // measure chunk
|
||
| 283 | chunk = !Buffer.isBuffer(chunk) |
||
| 284 | ? new Buffer(chunk, encoding)
|
||
| 285 | : chunk; |
||
| 286 | encoding = undefined;
|
||
| 287 | |||
| 288 | if (chunk.length !== 0) { |
||
| 289 | debug('split response');
|
||
| 290 | ret = _write.call(res, chunk.slice(0, chunk.length - 1)); |
||
| 291 | chunk = chunk.slice(chunk.length - 1, chunk.length);
|
||
| 292 | return ret;
|
||
| 293 | } |
||
| 294 | } |
||
| 295 | |||
| 296 | ret = _write.call(res, chunk, encoding); |
||
| 297 | sync = false;
|
||
| 298 | |||
| 299 | return ret;
|
||
| 300 | } |
||
| 301 | |||
| 302 | if (shouldDestroy(req)) {
|
||
| 303 | // destroy session
|
||
| 304 | debug('destroying');
|
||
| 305 | store.destroy(req.sessionID, function ondestroy(err) { |
||
| 306 | if (err) {
|
||
| 307 | defer(next, err); |
||
| 308 | } |
||
| 309 | |||
| 310 | debug('destroyed');
|
||
| 311 | writeend(); |
||
| 312 | }); |
||
| 313 | |||
| 314 | return writetop();
|
||
| 315 | } |
||
| 316 | |||
| 317 | // no session to save
|
||
| 318 | if (!req.session) {
|
||
| 319 | debug('no session');
|
||
| 320 | return _end.call(res, chunk, encoding);
|
||
| 321 | } |
||
| 322 | |||
| 323 | if (!touched) {
|
||
| 324 | // touch session
|
||
| 325 | req.session.touch() |
||
| 326 | touched = true
|
||
| 327 | } |
||
| 328 | |||
| 329 | if (shouldSave(req)) {
|
||
| 330 | req.session.save(function onsave(err) { |
||
| 331 | if (err) {
|
||
| 332 | defer(next, err); |
||
| 333 | } |
||
| 334 | |||
| 335 | writeend(); |
||
| 336 | }); |
||
| 337 | |||
| 338 | return writetop();
|
||
| 339 | } else if (storeImplementsTouch && shouldTouch(req)) { |
||
| 340 | // store implements touch method
|
||
| 341 | debug('touching');
|
||
| 342 | store.touch(req.sessionID, req.session, function ontouch(err) { |
||
| 343 | if (err) {
|
||
| 344 | defer(next, err); |
||
| 345 | } |
||
| 346 | |||
| 347 | debug('touched');
|
||
| 348 | writeend(); |
||
| 349 | }); |
||
| 350 | |||
| 351 | return writetop();
|
||
| 352 | } |
||
| 353 | |||
| 354 | return _end.call(res, chunk, encoding);
|
||
| 355 | }; |
||
| 356 | |||
| 357 | // generate the session
|
||
| 358 | function generate() { |
||
| 359 | store.generate(req); |
||
| 360 | originalId = req.sessionID; |
||
| 361 | originalHash = hash(req.session); |
||
| 362 | wrapmethods(req.session); |
||
| 363 | } |
||
| 364 | |||
| 365 | // wrap session methods
|
||
| 366 | function wrapmethods(sess) { |
||
| 367 | var _reload = sess.reload
|
||
| 368 | var _save = sess.save;
|
||
| 369 | |||
| 370 | function reload(callback) { |
||
| 371 | debug('reloading %s', this.id) |
||
| 372 | _reload.call(this, function () { |
||
| 373 | wrapmethods(req.session) |
||
| 374 | callback.apply(this, arguments) |
||
| 375 | }) |
||
| 376 | } |
||
| 377 | |||
| 378 | function save() { |
||
| 379 | debug('saving %s', this.id); |
||
| 380 | savedHash = hash(this);
|
||
| 381 | _save.apply(this, arguments); |
||
| 382 | } |
||
| 383 | |||
| 384 | Object.defineProperty(sess, 'reload', {
|
||
| 385 | configurable: true, |
||
| 386 | enumerable: false, |
||
| 387 | value: reload,
|
||
| 388 | writable: true |
||
| 389 | }) |
||
| 390 | |||
| 391 | Object.defineProperty(sess, 'save', {
|
||
| 392 | configurable: true, |
||
| 393 | enumerable: false, |
||
| 394 | value: save,
|
||
| 395 | writable: true |
||
| 396 | }); |
||
| 397 | } |
||
| 398 | |||
| 399 | // check if session has been modified
|
||
| 400 | function isModified(sess) { |
||
| 401 | return originalId !== sess.id || originalHash !== hash(sess);
|
||
| 402 | } |
||
| 403 | |||
| 404 | // check if session has been saved
|
||
| 405 | function isSaved(sess) { |
||
| 406 | return originalId === sess.id && savedHash === hash(sess);
|
||
| 407 | } |
||
| 408 | |||
| 409 | // determine if session should be destroyed
|
||
| 410 | function shouldDestroy(req) { |
||
| 411 | return req.sessionID && unsetDestroy && req.session == null; |
||
| 412 | } |
||
| 413 | |||
| 414 | // determine if session should be saved to store
|
||
| 415 | function shouldSave(req) { |
||
| 416 | // cannot set cookie without a session ID
|
||
| 417 | if (typeof req.sessionID !== 'string') { |
||
| 418 | debug('session ignored because of bogus req.sessionID %o', req.sessionID);
|
||
| 419 | return false; |
||
| 420 | } |
||
| 421 | |||
| 422 | return !saveUninitializedSession && cookieId !== req.sessionID
|
||
| 423 | ? isModified(req.session) |
||
| 424 | : !isSaved(req.session) |
||
| 425 | } |
||
| 426 | |||
| 427 | // determine if session should be touched
|
||
| 428 | function shouldTouch(req) { |
||
| 429 | // cannot set cookie without a session ID
|
||
| 430 | if (typeof req.sessionID !== 'string') { |
||
| 431 | debug('session ignored because of bogus req.sessionID %o', req.sessionID);
|
||
| 432 | return false; |
||
| 433 | } |
||
| 434 | |||
| 435 | return cookieId === req.sessionID && !shouldSave(req);
|
||
| 436 | } |
||
| 437 | |||
| 438 | // determine if cookie should be set on response
|
||
| 439 | function shouldSetCookie(req) { |
||
| 440 | // cannot set cookie without a session ID
|
||
| 441 | if (typeof req.sessionID !== 'string') { |
||
| 442 | return false; |
||
| 443 | } |
||
| 444 | |||
| 445 | return cookieId != req.sessionID
|
||
| 446 | ? saveUninitializedSession || isModified(req.session) |
||
| 447 | : rollingSessions || req.session.cookie.expires != null && isModified(req.session);
|
||
| 448 | } |
||
| 449 | |||
| 450 | // generate a session if the browser doesn't send a sessionID
|
||
| 451 | if (!req.sessionID) {
|
||
| 452 | debug('no SID sent, generating session');
|
||
| 453 | generate(); |
||
| 454 | next(); |
||
| 455 | return;
|
||
| 456 | } |
||
| 457 | |||
| 458 | // generate the session object
|
||
| 459 | debug('fetching %s', req.sessionID);
|
||
| 460 | store.get(req.sessionID, function(err, sess){
|
||
| 461 | // error handling
|
||
| 462 | if (err) {
|
||
| 463 | debug('error %j', err);
|
||
| 464 | |||
| 465 | if (err.code !== 'ENOENT') { |
||
| 466 | next(err); |
||
| 467 | return;
|
||
| 468 | } |
||
| 469 | |||
| 470 | generate(); |
||
| 471 | // no session
|
||
| 472 | } else if (!sess) { |
||
| 473 | debug('no session found');
|
||
| 474 | generate(); |
||
| 475 | // populate req.session
|
||
| 476 | } else {
|
||
| 477 | debug('session found');
|
||
| 478 | store.createSession(req, sess); |
||
| 479 | originalId = req.sessionID; |
||
| 480 | originalHash = hash(sess); |
||
| 481 | |||
| 482 | if (!resaveSession) {
|
||
| 483 | savedHash = originalHash |
||
| 484 | } |
||
| 485 | |||
| 486 | wrapmethods(req.session); |
||
| 487 | } |
||
| 488 | |||
| 489 | next(); |
||
| 490 | }); |
||
| 491 | }; |
||
| 492 | }; |
||
| 493 | |||
| 494 | /**
|
||
| 495 | * Generate a session ID for a new session.
|
||
| 496 | *
|
||
| 497 | * @return {String}
|
||
| 498 | * @private
|
||
| 499 | */
|
||
| 500 | |||
| 501 | function generateSessionId(sess) { |
||
| 502 | return uid(24); |
||
| 503 | } |
||
| 504 | |||
| 505 | /**
|
||
| 506 | * Get the session ID cookie from request.
|
||
| 507 | *
|
||
| 508 | * @return {string}
|
||
| 509 | * @private
|
||
| 510 | */
|
||
| 511 | |||
| 512 | function getcookie(req, name, secrets) { |
||
| 513 | var header = req.headers.cookie;
|
||
| 514 | var raw;
|
||
| 515 | var val;
|
||
| 516 | |||
| 517 | // read from cookie header
|
||
| 518 | if (header) {
|
||
| 519 | var cookies = cookie.parse(header);
|
||
| 520 | |||
| 521 | raw = cookies[name]; |
||
| 522 | |||
| 523 | if (raw) {
|
||
| 524 | if (raw.substr(0, 2) === 's:') { |
||
| 525 | val = unsigncookie(raw.slice(2), secrets);
|
||
| 526 | |||
| 527 | if (val === false) { |
||
| 528 | debug('cookie signature invalid');
|
||
| 529 | val = undefined;
|
||
| 530 | } |
||
| 531 | } else {
|
||
| 532 | debug('cookie unsigned')
|
||
| 533 | } |
||
| 534 | } |
||
| 535 | } |
||
| 536 | |||
| 537 | // back-compat read from cookieParser() signedCookies data
|
||
| 538 | if (!val && req.signedCookies) {
|
||
| 539 | val = req.signedCookies[name]; |
||
| 540 | |||
| 541 | if (val) {
|
||
| 542 | deprecate('cookie should be available in req.headers.cookie');
|
||
| 543 | } |
||
| 544 | } |
||
| 545 | |||
| 546 | // back-compat read from cookieParser() cookies data
|
||
| 547 | if (!val && req.cookies) {
|
||
| 548 | raw = req.cookies[name]; |
||
| 549 | |||
| 550 | if (raw) {
|
||
| 551 | if (raw.substr(0, 2) === 's:') { |
||
| 552 | val = unsigncookie(raw.slice(2), secrets);
|
||
| 553 | |||
| 554 | if (val) {
|
||
| 555 | deprecate('cookie should be available in req.headers.cookie');
|
||
| 556 | } |
||
| 557 | |||
| 558 | if (val === false) { |
||
| 559 | debug('cookie signature invalid');
|
||
| 560 | val = undefined;
|
||
| 561 | } |
||
| 562 | } else {
|
||
| 563 | debug('cookie unsigned')
|
||
| 564 | } |
||
| 565 | } |
||
| 566 | } |
||
| 567 | |||
| 568 | return val;
|
||
| 569 | } |
||
| 570 | |||
| 571 | /**
|
||
| 572 | * Hash the given `sess` object omitting changes to `.cookie`.
|
||
| 573 | *
|
||
| 574 | * @param {Object} sess
|
||
| 575 | * @return {String}
|
||
| 576 | * @private
|
||
| 577 | */
|
||
| 578 | |||
| 579 | function hash(sess) { |
||
| 580 | return crc(JSON.stringify(sess, function (key, val) { |
||
| 581 | // ignore sess.cookie property
|
||
| 582 | if (this === sess && key === 'cookie') { |
||
| 583 | return
|
||
| 584 | } |
||
| 585 | |||
| 586 | return val
|
||
| 587 | })) |
||
| 588 | } |
||
| 589 | |||
| 590 | /**
|
||
| 591 | * Determine if request is secure.
|
||
| 592 | *
|
||
| 593 | * @param {Object} req
|
||
| 594 | * @param {Boolean} [trustProxy]
|
||
| 595 | * @return {Boolean}
|
||
| 596 | * @private
|
||
| 597 | */
|
||
| 598 | |||
| 599 | function issecure(req, trustProxy) { |
||
| 600 | // socket is https server
|
||
| 601 | if (req.connection && req.connection.encrypted) {
|
||
| 602 | return true; |
||
| 603 | } |
||
| 604 | |||
| 605 | // do not trust proxy
|
||
| 606 | if (trustProxy === false) { |
||
| 607 | return false; |
||
| 608 | } |
||
| 609 | |||
| 610 | // no explicit trust; try req.secure from express
|
||
| 611 | if (trustProxy !== true) { |
||
| 612 | var secure = req.secure;
|
||
| 613 | return typeof secure === 'boolean' |
||
| 614 | ? secure |
||
| 615 | : false;
|
||
| 616 | } |
||
| 617 | |||
| 618 | // read the proto from x-forwarded-proto header
|
||
| 619 | var header = req.headers['x-forwarded-proto'] || ''; |
||
| 620 | var index = header.indexOf(','); |
||
| 621 | var proto = index !== -1 |
||
| 622 | ? header.substr(0, index).toLowerCase().trim()
|
||
| 623 | : header.toLowerCase().trim() |
||
| 624 | |||
| 625 | return proto === 'https'; |
||
| 626 | } |
||
| 627 | |||
| 628 | /**
|
||
| 629 | * Set cookie on response.
|
||
| 630 | *
|
||
| 631 | * @private
|
||
| 632 | */
|
||
| 633 | |||
| 634 | function setcookie(res, name, val, secret, options) { |
||
| 635 | var signed = 's:' + signature.sign(val, secret); |
||
| 636 | var data = cookie.serialize(name, signed, options);
|
||
| 637 | |||
| 638 | debug('set-cookie %s', data);
|
||
| 639 | |||
| 640 | var prev = res.getHeader('set-cookie') || []; |
||
| 641 | var header = Array.isArray(prev) ? prev.concat(data) : [prev, data];
|
||
| 642 | |||
| 643 | res.setHeader('set-cookie', header)
|
||
| 644 | } |
||
| 645 | |||
| 646 | /**
|
||
| 647 | * Verify and decode the given `val` with `secrets`.
|
||
| 648 | *
|
||
| 649 | * @param {String} val
|
||
| 650 | * @param {Array} secrets
|
||
| 651 | * @returns {String|Boolean}
|
||
| 652 | * @private
|
||
| 653 | */
|
||
| 654 | function unsigncookie(val, secrets) { |
||
| 655 | for (var i = 0; i < secrets.length; i++) { |
||
| 656 | var result = signature.unsign(val, secrets[i]);
|
||
| 657 | |||
| 658 | if (result !== false) { |
||
| 659 | return result;
|
||
| 660 | } |
||
| 661 | } |
||
| 662 | |||
| 663 | return false; |
||
| 664 | } |