Skip to content

Commit

Permalink
refactored Sessions. closes fuel#678, closes fuel#679
Browse files Browse the repository at this point in the history
Moved validation server side, made encryption optional.
  • Loading branch information
WanWizard committed Dec 4, 2012
1 parent 5d214ee commit fa5b667
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 178 deletions.
1 change: 1 addition & 0 deletions classes/session.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class Session
'cookie_domain' => '',
'cookie_path' => '/',
'cookie_http_only' => null,
'encrypt_cookie' => true,
'expire_on_close' => false,
'expiration_time' => 7200,
'rotation_time' => 300,
Expand Down
39 changes: 32 additions & 7 deletions classes/session/cookie.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,41 @@ public function create()
*/
public function read($force = false)
{
// initialize the session
$this->data = array();
$this->keys = array();
$this->flash = array();

// get the session cookie
$payload = $this->_get_cookie();

// if no session cookie was present, initialize a new session
if ($payload === false or $force)
// validate it
if ($payload === false or $force )
{
// not a valid cookie, or a forced session reset
}
elseif ( ! isset($payload[0]) or ! is_array($payload[0]))
{
// not a valid cookie payload
}
elseif ($payload[0]['updated'] + $this->config['expiration_time'] <= $this->time->get_timestamp())
{
$this->data = array();
$this->keys = array();
// session has expired
}
elseif ($this->config['match_ip'] and $payload[0]['ip_hash'] !== md5(\Input::ip().\Input::real_ip()))
{
// IP address doesn't match
}
elseif ($this->config['match_ua'] and $payload[0]['user_agent'] !== \Input::user_agent())
{
// user agent doesn't match
}
else
{
if (isset($payload[0])) $this->data = $payload[0];
if (isset($payload[1])) $this->flash = $payload[1];
// session is valid, retrieve the payload
if (isset($payload[0]) and is_array($payload[0])) $this->data = $payload[0];
if (isset($payload[1]) and is_array($payload[1])) $this->data = $payload[1];
if (isset($payload[2]) and is_array($payload[2])) $this->flash = $payload[2];
}

return parent::read();
Expand All @@ -104,8 +126,11 @@ public function write()
// rotate the session id if needed
$this->rotate(false);

// record the last update time of the session
$this->keys['updated'] = $this->time->get_timestamp();

// then update the cookie
$this->_set_cookie(array($this->data, $this->flash));
$this->_set_cookie(array($this->keys, $this->data, $this->flash));
}

return $this;
Expand Down
51 changes: 35 additions & 16 deletions classes/session/db.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,20 @@ public function create($payload = '')
*/
public function read($force = false)
{
// initialize the session
$this->data = array();
$this->keys = array();
$this->flash = array();
$this->record = null;

// get the session cookie
$cookie = $this->_get_cookie();

// if no session cookie was present, initialize a new session
if ($cookie === false or $force)
{
$this->data = array();
$this->keys = array();
$this->record = null;
}
else
// if a cookie was present, find the session record
if ($cookie and ! $force and isset($cookie[0]))
{
// read the session record
$this->record = \DB::select()->where('session_id', '=', $this->keys['session_id'])->from($this->config['table'])->execute($this->config['database']);
$this->record = \DB::select()->where('session_id', '=', $cookie[0])->from($this->config['table'])->execute($this->config['database']);

// record found?
if ($this->record->count())
Expand All @@ -101,13 +101,11 @@ public function read($force = false)
else
{
// try to find the session on previous id
$this->record = \DB::select()->where('previous_id', '=', $this->keys['session_id'])->from($this->config['table'])->execute($this->config['database']);
$this->record = \DB::select()->where('previous_id', '=', $cookie[0])->from($this->config['table'])->execute($this->config['database']);

// record found?
if ($this->record->count())
{
// previous id used, correctly set session id so it wont be overwritten with previous id.
$this->keys['session_id'] = $this->record->get('session_id');
$payload = $this->_unserialize($this->record->get('payload'));
}
else
Expand All @@ -117,8 +115,29 @@ public function read($force = false)
}
}

if (isset($payload[0])) $this->data = $payload[0];
if (isset($payload[1])) $this->flash = $payload[1];
if ( ! isset($payload[0]) or ! is_array($payload[0]))
{
// not a valid cookie payload
}
elseif ($payload[0]['updated'] + $this->config['expiration_time'] <= $this->time->get_timestamp())
{
// session has expired
}
elseif ($this->config['match_ip'] and $payload[0]['ip_hash'] !== md5(\Input::ip().\Input::real_ip()))
{
// IP address doesn't match
}
elseif ($this->config['match_ua'] and $payload[0]['user_agent'] !== \Input::user_agent())
{
// user agent doesn't match
}
else
{
// session is valid, retrieve the payload
if (isset($payload[0]) and is_array($payload[0])) $this->data = $payload[0];
if (isset($payload[1]) and is_array($payload[1])) $this->data = $payload[1];
if (isset($payload[2]) and is_array($payload[2])) $this->flash = $payload[2];
}
}

return parent::read();
Expand All @@ -144,7 +163,7 @@ public function write()

// create the session record, and add the session payload
$session = $this->keys;
$session['payload'] = $this->_serialize(array($this->data, $this->flash));
$session['payload'] = $this->_serialize(array($this->keys, $this->data, $this->flash));

// do we need to create a new session?
if (is_null($this->record))
Expand All @@ -162,7 +181,7 @@ public function write()
if ($result !== false)
{
// then update the cookie
$this->_set_cookie();
$this->_set_cookie(array($this->keys['session_id']));
}
else
{
Expand Down
94 changes: 18 additions & 76 deletions classes/session/driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -460,14 +460,10 @@ protected function _new_session_id()
*/
protected function _set_cookie($payload = array())
{
// record the last update time of the session
$this->keys['updated'] = $this->time->get_timestamp();
$payload = $this->_serialize($payload);

// add the session keys to the payload
array_unshift($payload, $this->keys);

// encrypt the payload
$payload = \Crypt::encode($this->_serialize($payload));
// encrypt the payload if needed
$this->config['encrypt_cookie'] and $payload = \Crypt::encode($payload);

// make sure it doesn't exceed the cookie size specification
if (strlen($payload) > 4000)
Expand Down Expand Up @@ -508,34 +504,11 @@ protected function _get_cookie()
if ($cookie !== false)
{
// fetch the payload
$cookie = $this->_unserialize(\Crypt::decode($cookie));
$this->config['encrypt_cookie'] and $cookie = \Crypt::decode($cookie);
$cookie = $this->_unserialize($cookie);

// validate the cookie
if ( ! isset($cookie[0]) )
{
// not a valid cookie payload
}
elseif ($cookie[0]['updated'] + $this->config['expiration_time'] <= $this->time->get_timestamp())
{
// session has expired
}
elseif ($this->config['match_ip'] and $cookie[0]['ip_hash'] !== md5(\Input::ip().\Input::real_ip()))
{
// IP address doesn't match
}
elseif ($this->config['match_ua'] and $cookie[0]['user_agent'] !== \Input::user_agent())
{
// user agent doesn't match
}
else
{
// session is valid, retrieve the session keys
if (isset($cookie[0])) $this->keys = $cookie[0];

// and return the cookie payload
array_shift($cookie);
return $cookie;
}
// and return it
return $cookie;
}

// no payload
Expand Down Expand Up @@ -633,15 +606,16 @@ protected function _validate_config($config)
break;

case 'match_ip':
// make sure it's a boolean
$item = (bool) $item;
break;

case 'match_ua':
case 'cookie_http_only':
case 'encrypt_cookie':
case 'expire_on_close':
case 'flash_auto_expire':
// make sure it's a boolean
$item = (bool) $item;
break;

case 'post_cookie_name':
case 'cookie_domain':
// make sure it's a string
$item = (string) $item;
Expand All @@ -650,59 +624,27 @@ protected function _validate_config($config)
case 'cookie_path':
// make sure it's a string
$item = (string) $item;
if (empty($item))
{
$item = '/';
}
break;

case 'cookie_http_only':
// make sure it's a boolean
$item = (bool) $item;
break;

case 'expire_on_close':
// make sure it's a boolean
$item = (bool) $item;
empty($item) and $item = '/';
break;

case 'expiration_time':
// make sure it's an integer
$item = (int) $item;
if ($item <= 0)
{
// invalid? set it to two years from now
$item = 86400 * 365 * 2;
}
// invalid? set it to two years from now
$item <= 0 and $item = 86400 * 365 * 2;
break;

case 'rotation_time':
// make sure it's an integer
$item = (int) $item;
if ($item <= 0)
{
// invalid? set it to 5 minutes
$item = 300;
}
// invalid? set it to 5 minutes
$item <= 0 and $item = 300;
break;

case 'flash_id':
// make sure it's a string
$item = (string) $item;
if (empty($item))
{
$item = 'flash';
}
break;

case 'flash_auto_expire':
// make sure it's a boolean
$item = (bool) $item;
break;

case 'post_cookie_name':
// make sure it's a string
$item = (string) $item;
empty($item) and $item = 'flash';
break;

default:
Expand Down
Loading

0 comments on commit fa5b667

Please sign in to comment.