| Jifty documentation | Contained in the Jifty distribution. |
Jifty::Web::Session::ClientSide - Session handler for client-side sessions
In your etc/config.yml:
framework:
Web:
SessionClass: Jifty::Web::Session::ClientSide
SessionSecret: secret_passphrase
Returns a new, empty session handler, subclassing Jifty::Web::Session.
Accessor to the underlying Crypt::CBC object that encapsulates the server-side secret.
Returns the session's id if it has been loaded, or undef otherwise.
Since there is no server-side storage, this simply clears the object's local state.
Load up the current session from the given ID, or the appropriate
cookie (see cookie_name in Jifty::Web::Session) otherwise.
If both of those fail, creates a session in memory.
Outputs the client-side session as one or more cookies.
| Jifty documentation | Contained in the Jifty distribution. |
package Jifty::Web::Session::ClientSide;
use strict; use warnings; use base 'Jifty::Web::Session'; use Jifty::Model::Session(); use Storable (); use Compress::Zlib (); use Crypt::CBC (); use Crypt::Rijndael (); use CGI::Cookie; use CGI::Cookie::Splitter (); use MIME::Base64; my $session_key; my $splitter = CGI::Cookie::Splitter->new;
sub new { my $class = shift; my $cookie_name = Jifty->config->framework('Web')->{'SessionCookieName'}; my $session_key = Jifty->config->framework('Web')->{'SessionSecret'} or die "Please set SessionSecret in your framework/Web settings"; my $cipher = Crypt::CBC->new( -key => $session_key, -cipher => 'Rijndael', ); bless { _cookie_name => $cookie_name, _cipher => $cipher, _session => undef }, $class; }
sub _cipher { my $self = shift; $self->{'_cipher'} = shift if (@_); return ( $self->{'_cipher'} ); }
sub id { my $self = shift; return $self->loaded ? $self->_session->{session_id} : undef; }
sub create { my $self = shift; $self->_session({ session_id => Jifty::Model::Session->new_session_id, continuation => {}, metadata => {}, key => {}, }); }
sub load { my $self = shift; my $session_id = shift; my %cookies = %{ Jifty->web->request->cookies }; unless ($session_id) { my $cookie_name = $self->cookie_name; $session_id = $cookies{$cookie_name} if $cookies{$cookie_name}; $session_id ||= Jifty::Model::Session->new_session_id; } my $data; { local $@; eval { ($data) = grep { $_->name eq "JIFTY_DAT_$session_id" } $splitter->join( map { CGI::Cookie->new( -name => $_, -value => $cookies{$_} ) } keys %cookies ); }; if ($@) { # Reassembly of cookie failed -- start a new session $session_id = Jifty::Model::Session->new_session_id; warn $@; } } if ($data) { local $@; eval { local $Storable::Eval = 0; # Just to be on the safe side... if (my $session = Storable::thaw( Compress::Zlib::uncompress( $self->_cipher->decrypt( decode_base64( $data->value ) ) ) )) { $self->_session($session); die "Session id mismatch" unless $self->_session->{session_id} eq $session_id; } 1; } and return; warn $@ if $@; } $self->_session({ session_id => $session_id, continuation => {}, metadata => {}, key => {}, }); }
sub get { my $self = shift; my $key = shift; my $key_type = shift || "key"; return undef unless $self->loaded; return $self->_session->{$key_type}{$key}; }
sub set { my $self = shift; my $key = shift; my $value = shift; my $key_type = shift || "key"; return undef unless $self->loaded; $self->_session->{$key_type}{$key} = $value; # XXX - delay until the very last moment? $self->flush; }
sub remove { my $self = shift; my $key = shift; my $key_type = shift || "key"; return undef unless $self->loaded; delete $self->_session->{$key_type}{$key}; }
sub continuations { my $self = shift; return () unless $self->loaded; return %{ $self->_session->{continuation} }; }
sub unload { my $self = shift; $self->flush; $self->_session(undef); }
sub flush { my $self = shift; my $session_id = $self->id or return; my $data_cookie = CGI::Cookie->new( -name => "JIFTY_DAT_$session_id", -expires => $self->expires, -value => encode_base64( $self->_cipher->encrypt( Compress::Zlib::compress( Storable::nfreeze( $self->_session ) ) ) ) ); foreach my $cookie ($splitter->split( $data_cookie )) { Jifty->web->response->cookies->{$cookie->name} = $cookie; } } 1;