Some cleanup of the code.
[catagits/Web-Session.git] / lib / Plack / Middleware / Session / Cookie.pm
1 package Plack::Middleware::Session::Cookie;
2 use strict;
3 use parent qw(Plack::Middleware::Session);
4
5 use Plack::Util::Accessor qw(secret session_key domain expires path secure);
6
7 use Digest::HMAC_SHA1;
8 use MIME::Base64 ();
9 use Storable ();
10 use Time::HiRes;
11 use Plack::Util;
12
13 use Plack::Session::State::Cookie;
14
15 sub prepare_app {
16     my $self = shift;
17
18     Plack::Util::load_class($self->session_class) if $self->session_class;
19     $self->session_key("plack_session") unless $self->session_key;
20
21     my $state_cookie = Plack::Session::State::Cookie->new;
22     for my $attr (qw(session_key path domain expires secure)) {
23         $state_cookie->$attr($self->$attr);
24     }
25
26     my $state = Plack::Util::inline_object
27         generate => sub { $self->_serialize({}) },
28         extract  => sub {
29             my $cookie = $state_cookie->get_session_id(@_) or return;
30
31             my($time, $b64, $sig) = split /:/, $cookie, 3;
32             $self->sig($b64) eq $sig or return;
33
34             return $cookie;
35         },
36         expire_session_id => sub { $state_cookie->expire_session_id(@_) },
37         finalize => sub { $state_cookie->finalize(@_) };
38
39     my $store = Plack::Util::inline_object
40         fetch => sub {
41             my $id = shift;
42             my($time, $b64, $sig) = split /:/, $id, 3;
43             Storable::thaw(MIME::Base64::decode($b64));
44         },
45         store => sub { },
46         cleanup => sub { };
47
48     $self->state($state);
49     $self->store($store);
50 }
51
52 sub finalize {
53     my($self, $session, $options, $response) = @_;
54
55     if ($options->{expire}) {
56         $self->state->expire_session_id($options->{id}, $response);
57     } else {
58         my $cookie = $self->_serialize($session);
59         $self->state->finalize($cookie, $response, $options);
60     }
61 }
62
63 sub _serialize {
64     my($self, $session) = @_;
65
66     my $now = Time::HiRes::gettimeofday;
67     my $b64 = MIME::Base64::encode( Storable::freeze($session), '' );
68     join ":", $now, $b64, $self->sig($b64);
69 }
70
71 sub sig {
72     my($self, $b64) = @_;
73     return '.' unless $self->secret;
74     Digest::HMAC_SHA1::hmac_sha1_hex($b64, $self->secret);
75 }
76
77 1;
78
79 __END__
80
81 =head1 NAME
82
83 Plack::Middleware::Session::Cookie - Session middleware that saves session data in the cookie
84
85 =head1 SYNOPSIS
86
87   enable "Session::Cookie";
88
89 =head1 DESCRIPTION
90
91 This middleware component allows you to use the cookie as a sole
92 cookie state and store, without any server side storage to do the
93 session management. This middleware utilizes its own state and store
94 automatically for you, so you can't override the objects.
95
96 =head1 CONFIGURATIONS
97
98 This middleware is a subclass of L<Plack::Middleware::Session> and
99 accepts most configuration of the parent class. In addition, following
100 options are accepted.
101
102 =over 4
103
104 =item secret
105
106 Server side secret to sign the session data using HMAC SHA1. Defaults
107 to nothing (i.e. do not sign) but B<strongly recommended> to set your
108 own secret string.
109
110 =item session_key, domain, expires, path, secure
111
112 Accessors for the cookie attribuets. See
113 L<Plack::Session::State::Cookie> for these options.
114
115 =back
116
117 =head1 AUTHOR
118
119 Tatsuhiko Miyagawa
120
121 =head1 SEE ALSO
122
123 Rack::Session::Cookie L<Dancer::Session::Cookie>
124
125 =cut
126