From 9f7b663221d630ee1534dc062fe1a84d779a7b16 Mon Sep 17 00:00:00 2001 From: Jens Rehsack Date: Thu, 27 Dec 2012 16:55:01 +0100 Subject: [PATCH 2/2] - do not shoot cross hole (Dancer::Session::Abstract->write_session_id <-> Dancer::Session::Cookie->flush (own set_cookie call)) - "better" error messages on wrong settings --- lib/Dancer/Session/Cookie.pm | 54 +++++++++++++++++++++++++----------------- t/01-session.t | 2 +- t/02-configfile.t | 2 +- t/03-path.t | 18 +++++++++----- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/lib/Dancer/Session/Cookie.pm b/lib/Dancer/Session/Cookie.pm index 3bc6c30..ab6dff0 100644 --- a/lib/Dancer/Session/Cookie.pm +++ b/lib/Dancer/Session/Cookie.pm @@ -4,39 +4,45 @@ use strict; use warnings; use base 'Dancer::Session::Abstract'; +use Carp qw(croak); + use Crypt::CBC; use String::CRC32; use Crypt::Rijndael; -use Dancer (); +use Dancer 'set'; use Dancer::Config 'setting'; use Storable (); use MIME::Base64 (); use vars '$VERSION'; -$VERSION = '0.15'; +$VERSION = '0.16'; -# crydec -my $CIPHER = undef; +my %CIPHER; +# crydec sub init { - my ($class) = @_; + my ($self, @args) = @_; my $key = setting("session_cookie_key") # XXX default to smth with warning - or die "The setting session_cookie_key must be defined"; + or croak "The setting 'session_cookie_key' must be defined"; + + if (my $session_cookie_path = setting("session_cookie_path")) { + my $session_path = setting("session_path"); - $CIPHER = Crypt::CBC->new( + $session_path and $session_cookie_path and $session_path ne $session_cookie_path + and croak "The settings 'session_cookie_path' ($session_cookie_path) and 'session_path' ($session_path) must not be both defined"; + + set session_path => $session_cookie_path; + } + + defined $CIPHER{$key} + or $CIPHER{$key} = Crypt::CBC->new( -key => $key, -cipher => 'Rijndael', ); -} - -sub new { - my $self = Dancer::Object::new(@_); - # id is not needed here because the whole serialized session is - # the "id" - return $self; + $self->SUPER::init(@args); } sub retrieve { @@ -60,6 +66,8 @@ sub create { return Dancer::Session::Cookie->new(id => 'empty'); } +sub build_id { "" } # will be filled in flush + sub flush { my $self = shift; @@ -67,12 +75,8 @@ sub flush { delete $self->{id}; my $cipher_text = _encrypt(Storable::freeze($self)); - my $session_name = $self->session_name; - Dancer::set_cookie( - $session_name => $cipher_text, - path => setting("session_cookie_path") || "/", - secure=> setting("session_secure"), - ); + $self->write_session_id($cipher_text); + $self->{id} = $cipher_text; return 1; @@ -90,10 +94,13 @@ sub _encrypt { my $crc32 = String::CRC32::crc32($plain_text); + my $key = setting("session_cookie_key") # XXX default to smth with warning + or die "The setting session_cookie_key must be defined"; + # XXX should gzip data if it grows too big. CRC32 won't be needed # then. my $res = - MIME::Base64::encode($CIPHER->encrypt(pack('La*', $crc32, $plain_text)), + MIME::Base64::encode($CIPHER{$key}->encrypt(pack('La*', $crc32, $plain_text)), q{}); $res =~ tr{=+/}{_*-}; # cookie-safe Base64 @@ -105,9 +112,12 @@ sub _decrypt { $cookie =~ tr{_*-}{=+/}; + my $key = setting("session_cookie_key") # XXX default to smth with warning + or die "The setting session_cookie_key must be defined"; + $SIG{__WARN__} = sub {}; my ($crc32, $plain_text) = unpack "La*", - $CIPHER->decrypt(MIME::Base64::decode($cookie)); + $CIPHER{$key}->decrypt(MIME::Base64::decode($cookie)); return $crc32 == String::CRC32::crc32($plain_text) ? $plain_text : undef; } diff --git a/t/01-session.t b/t/01-session.t index 6db242e..ab89fac 100644 --- a/t/01-session.t +++ b/t/01-session.t @@ -15,7 +15,7 @@ BEGIN { my $session; throws_ok { $session = Dancer::Session::Cookie->create } - qr/session_cookie_key must be defined/, 'requires session_cookie_key'; + qr/'session_cookie_key' must be defined/, 'requires session_cookie_key'; set session_cookie_key => 'test/secret*@?)'; lives_and { $session = Dancer::Session::Cookie->create } 'works'; diff --git a/t/02-configfile.t b/t/02-configfile.t index bde7a37..770ed92 100644 --- a/t/02-configfile.t +++ b/t/02-configfile.t @@ -18,7 +18,7 @@ plan tests => 3; my $session; throws_ok { $session = Dancer::Session::Cookie->create } - qr/session_cookie_key must be defined/, 'still requires session_cookie_key'; + qr/'session_cookie_key' must be defined/, 'still requires session_cookie_key'; set confdir => "$FindBin::Bin/data"; ok(-r File::Spec->catfile(setting('confdir'), 'config.yml'), diff --git a/t/03-path.t b/t/03-path.t index 004c279..7a94f56 100644 --- a/t/03-path.t +++ b/t/03-path.t @@ -9,26 +9,32 @@ use Dancer; my $CLASS = 'Dancer::Session::Cookie'; use_ok $CLASS; +my $Session_Name = Dancer::Session::Cookie->session_name; + note "test setup"; { set session_cookie_key => "The dolphins are in the jacuzzi"; } note "default path"; { - my $session = Dancer::Session::Cookie->create; - $session->flush; + set session => "cookie"; + session foo => "bar"; - is cookies->{"dancer.session"}->path, "/"; + my $session_cookie = Dancer::Cookies->cookies->{ $Session_Name }; + is $session_cookie->path => "/"; } note "set the path"; { + delete Dancer::Cookies->cookies->{ $Session_Name }; + + set session => "cookie"; set session_cookie_path => "/some/thing"; - my $session = Dancer::Session::Cookie->create; - $session->flush; + session up => "down"; - is cookies->{"dancer.session"}->path, "/some/thing"; + my $session_cookie = Dancer::Cookies->cookies->{ $Session_Name }; + is $session_cookie->path => "/some/thing"; } done_testing; -- 1.7.10.2 (Apple Git-33)