session.js
  1  /*!
  2   * Connect - session - Session
  3   * Copyright(c) 2010 Sencha Inc.
  4   * Copyright(c) 2011 TJ Holowaychuk
  5   * MIT Licensed
  6   */
  7  
  8  'use strict';
  9  
 10  /**
 11   * Expose Session.
 12   */
 13  
 14  module.exports = Session;
 15  
 16  /**
 17   * Create a new `Session` with the given request and `data`.
 18   *
 19   * @param {IncomingRequest} req
 20   * @param {Object} data
 21   * @api private
 22   */
 23  
 24  function Session(req, data) {
 25    Object.defineProperty(this, 'req', { value: req });
 26    Object.defineProperty(this, 'id', { value: req.sessionID });
 27  
 28    if (typeof data === 'object' && data !== null) {
 29      // merge data into this, ignoring prototype properties
 30      for (var prop in data) {
 31        if (!(prop in this)) {
 32          this[prop] = data[prop]
 33        }
 34      }
 35    }
 36  }
 37  
 38  /**
 39   * Update reset `.cookie.maxAge` to prevent
 40   * the cookie from expiring when the
 41   * session is still active.
 42   *
 43   * @return {Session} for chaining
 44   * @api public
 45   */
 46  
 47  defineMethod(Session.prototype, 'touch', function touch() {
 48    return this.resetMaxAge();
 49  });
 50  
 51  /**
 52   * Reset `.maxAge` to `.originalMaxAge`.
 53   *
 54   * @return {Session} for chaining
 55   * @api public
 56   */
 57  
 58  defineMethod(Session.prototype, 'resetMaxAge', function resetMaxAge() {
 59    this.cookie.maxAge = this.cookie.originalMaxAge;
 60    return this;
 61  });
 62  
 63  /**
 64   * Save the session data with optional callback `fn(err)`.
 65   *
 66   * @param {Function} fn
 67   * @return {Session} for chaining
 68   * @api public
 69   */
 70  
 71  defineMethod(Session.prototype, 'save', function save(fn) {
 72    this.req.sessionStore.set(this.id, this, fn || function(){});
 73    return this;
 74  });
 75  
 76  /**
 77   * Re-loads the session data _without_ altering
 78   * the maxAge properties. Invokes the callback `fn(err)`,
 79   * after which time if no exception has occurred the
 80   * `req.session` property will be a new `Session` object,
 81   * although representing the same session.
 82   *
 83   * @param {Function} fn
 84   * @return {Session} for chaining
 85   * @api public
 86   */
 87  
 88  defineMethod(Session.prototype, 'reload', function reload(fn) {
 89    var req = this.req
 90    var store = this.req.sessionStore
 91  
 92    store.get(this.id, function(err, sess){
 93      if (err) return fn(err);
 94      if (!sess) return fn(new Error('failed to load session'));
 95      store.createSession(req, sess);
 96      fn();
 97    });
 98    return this;
 99  });
100  
101  /**
102   * Destroy `this` session.
103   *
104   * @param {Function} fn
105   * @return {Session} for chaining
106   * @api public
107   */
108  
109  defineMethod(Session.prototype, 'destroy', function destroy(fn) {
110    delete this.req.session;
111    this.req.sessionStore.destroy(this.id, fn);
112    return this;
113  });
114  
115  /**
116   * Regenerate this request's session.
117   *
118   * @param {Function} fn
119   * @return {Session} for chaining
120   * @api public
121   */
122  
123  defineMethod(Session.prototype, 'regenerate', function regenerate(fn) {
124    this.req.sessionStore.regenerate(this.req, fn);
125    return this;
126  });
127  
128  /**
129   * Helper function for creating a method on a prototype.
130   *
131   * @param {Object} obj
132   * @param {String} name
133   * @param {Function} fn
134   * @private
135   */
136  function defineMethod(obj, name, fn) {
137    Object.defineProperty(obj, name, {
138      configurable: true,
139      enumerable: false,
140      value: fn,
141      writable: true
142    });
143  };