[Jifty-commit] r1668 - in jifty/trunk: lib/Jifty/Web lib/Jifty/Web/Session

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Tue Jul 25 15:59:59 EDT 2006


Author: audreyt
Date: Tue Jul 25 15:59:57 2006
New Revision: 1668

Added:
   jifty/trunk/lib/Jifty/Web/Session/
   jifty/trunk/lib/Jifty/Web/Session/ClientSide.pm
Modified:
   jifty/trunk/META.yml
   jifty/trunk/Makefile.PL
   jifty/trunk/lib/Jifty/Web/Session.pm

Log:
* Jifty::Web::Session::ClientSide - Client-side sessions.

Modified: jifty/trunk/META.yml
==============================================================================
--- jifty/trunk/META.yml	(original)
+++ jifty/trunk/META.yml	Tue Jul 25 15:59:57 2006
@@ -14,6 +14,7 @@
     - inc
 requires: 
   App::CLI: 0.03
+  CGI::Cookie::Splitter: 0
   CSS::Squish: 0.05
   Cache::Cache: 0
   Calendar::Simple: 0
@@ -22,6 +23,8 @@
   Class::Container: 0
   Class::Data::Inheritable: 0
   Compress::Zlib: 0
+  Crypt::CBC: 0
+  Crypt::Rijndael: 0
   DBD::SQLite: 1.11
   Data::Page: 0
   Date::Manip: 0

Modified: jifty/trunk/Makefile.PL
==============================================================================
--- jifty/trunk/Makefile.PL	(original)
+++ jifty/trunk/Makefile.PL	Tue Jul 25 15:59:57 2006
@@ -10,6 +10,9 @@
 requires('Class::Accessor::Named'); 
 requires('Class::Container');
 requires('Class::Data::Inheritable');
+requires('CGI::Cookie::Splitter');
+requires('Crypt::CBC');
+requires('Crypt::Rijndael');
 requires('Compress::Zlib');
 requires('CSS::Squish' => 0.05 );
 requires('DBD::SQLite' => 1.11 );

Modified: jifty/trunk/lib/Jifty/Web/Session.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Session.pm	(original)
+++ jifty/trunk/lib/Jifty/Web/Session.pm	Tue Jul 25 15:59:57 2006
@@ -20,7 +20,15 @@
 
 sub new {
     my $class = shift;
-    return bless {}, $class;
+
+    my $session_class = Jifty->config->framework('Web')->{'SessionClass'};
+    if ($session_class and $class ne $session_class) {
+        Jifty::Util->require( $session_class );
+        return $session_class->new(@_);
+    }
+    else {
+        return bless {}, $class;
+    }
 }
 
 =head2 id
@@ -48,9 +56,9 @@
 
     unless ($session_id) {
         my %cookies    = CGI::Cookie->fetch();
-        my $cookiename = $self->cookie_name;
+        my $cookie_name = $self->cookie_name;
         $session_id
-            = $cookies{$cookiename} ? $cookies{$cookiename}->value() : undef;
+            = $cookies{$cookie_name} ? $cookies{$cookie_name}->value() : undef;
     }
 
     my $session = Jifty::Model::Session->new;
@@ -285,14 +293,14 @@
 =head2 cookie_name
 
 Returns the current session's cookie_name -- it is the same for all
-users, but various accorting to the port the server is running on.
+users, but varies accorting to the port the server is running on.
 
 =cut
 
 sub cookie_name {
     my $self = shift;
-    my $cookiename = "JIFTY_SID_" . ( $ENV{'SERVER_PORT'} || 'NOPORT' );
-    return ($cookiename);
+    my $cookie_name = "JIFTY_SID_" . ( $ENV{'SERVER_PORT'} || 'NOPORT' );
+    return ($cookie_name);
 }
 
 =head2 expires [VALUE]

Added: jifty/trunk/lib/Jifty/Web/Session/ClientSide.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Web/Session/ClientSide.pm	Tue Jul 25 15:59:57 2006
@@ -0,0 +1,223 @@
+package Jifty::Web::Session::ClientSide;
+
+=head1 NAME
+
+Jifty::Web::Session - Session handler for client-side sessions
+
+=head1 SYNOPSIS
+
+In your F<etc/config.yml>:
+
+  framework:
+    Web:
+      SessionClass: Jifty::Web::Session::ClientSide
+      SessionSecret: secret_passphrase
+
+=cut
+
+use strict;
+use warnings;
+use base 'Jifty::Web::Session';
+use Jifty::Model::Session();
+use Jifty::YAML ();
+use Compress::Zlib ();
+use Crypt::CBC ();
+use Crypt::Rijndael ();
+use CGI::Cookie::Splitter ();
+
+my $session_key;
+my $splitter = CGI::Cookie::Splitter->new;
+
+=head2 new
+
+Returns a new, empty session handler, subclassing L<Jifty::Web::Session>.
+
+=cut
+
+sub new {
+    my $class = shift;
+    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 { _cipher => $cipher, _session => undef }, $class;
+}
+
+=head2 _cipher
+
+Accessor to the underlying L<Crypt::CBC> object that encapsulates the
+server-side secret.
+
+=cut
+
+sub _cipher {
+    my $self = shift;
+    $self->{'_cipher'} = shift if (@_);
+    return ( $self->{'_cipher'} );
+}
+
+=head2 id
+
+Returns the session's id if it has been loaded, or C<undef> otherwise.
+
+=cut
+
+sub id {
+    my $self = shift;
+    return $self->loaded ? $self->_session->{session_id} : undef;
+}
+
+=head2 load [ID]
+
+Load up the current session from the given C<ID>, or the appropriate
+cookie (see L<Jifty::Web::Session/cookie_name>) otherwise.
+
+If both of those fail, creates a session in memory.
+
+=cut
+
+sub load {
+    my $self       = shift;
+    my $session_id = shift;
+    my %cookies    = CGI::Cookie->fetch();
+
+    unless ($session_id) {
+        my $cookie_name = $self->cookie_name;
+        $session_id = $cookies{$cookie_name}
+            ? $cookies{$cookie_name}->value()
+            : Jifty::Model::Session->new_session_id,
+    }
+
+    # XXX - Cookie mangling detection
+    if (exists $cookies{"JIFTY_DAT_$session_id"}) {
+        local $@;
+        eval {
+            $self->_session(
+                Jifty::YAML::Load(
+                    Compress::Zlib::uncompress(
+                        $self->_cipher->decrypt(
+                            $cookies{"JIFTY_DAT_$session_id"}->value
+                        )
+                    )
+                )
+            );
+            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          => {},
+    });
+}
+
+=head2 get KEY [TYPE]
+
+See L<Jifty::Web::Session/get>.
+
+=cut
+
+sub get {
+    my $self     = shift;
+    my $key      = shift;
+    my $key_type = shift || "key";
+
+    return undef unless $self->loaded;
+    return $self->_session->{$key_type}{$key};
+}
+
+=head2 set KEY => VALUE, [TYPE]
+
+See L<Jifty::Web::Session/set>.
+
+=cut
+
+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;
+}
+
+=head2 remove KEY, [TYPE]
+
+See L<Jifty::Web::Session/remove>.
+
+=cut
+
+sub remove {
+    my $self     = shift;
+    my $key      = shift;
+    my $key_type = shift || "key";
+
+    return undef unless $self->loaded;
+    delete $self->_session->{$key_type}{$key};
+}
+
+=head2 continuations
+
+See L<Jifty::Web::Session/continuations>.
+
+=cut
+
+sub continuations {
+    my $self     = shift;
+    return () unless $self->loaded;
+    return %{ $self->_session->{continuation} };
+}
+
+=head2 unload
+
+See L<Jifty::Web::Session/unload>.
+
+=cut
+
+sub unload {
+    my $self = shift;
+    $self->flush;
+    $self->_session(undef);
+}
+
+=head2 flush
+
+Outputs the client-side session as one or more cookies.
+
+=cut
+
+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   => $self->_cipher->encrypt(
+            Compress::Zlib::compress(
+                Jifty::YAML::Dump(
+                    $self->_session
+                )
+            )
+        )
+    );
+
+    foreach my $cookie ($splitter->split( $data_cookie )) {
+        Jifty->web->response->add_header(
+            'Set-Cookie' => $cookie->as_string
+        );
+    }
+}
+
+1;


More information about the Jifty-commit mailing list