7fa4bd7554339f6f7e0a600e4403d0ee520053cc
[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     $self->session_class("Plack::Session");
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 {
38             my($id, $response, $session) = @_;
39             my $cookie = $self->_serialize($session->dump);
40             $state_cookie->finalize($cookie, $response);
41         };
42
43     my $store = Plack::Util::inline_object
44         fetch => sub {
45             my $id = shift;
46             my($time, $b64, $sig) = split /:/, $id, 3;
47             Storable::thaw(MIME::Base64::decode($b64));
48         },
49         store => sub { },
50         cleanup => sub { };
51
52     $self->state($state);
53     $self->store($store);
54 }
55
56 sub _serialize {
57     my($self, $session) = @_;
58
59     my $now = Time::HiRes::gettimeofday;
60     my $b64 = MIME::Base64::encode( Storable::freeze($session), '' );
61     join ":", $now, $b64, $self->sig($b64);
62 }
63
64 sub sig {
65     my($self, $b64) = @_;
66     return '.' unless $self->secret;
67     Digest::HMAC_SHA1::hmac_sha1_hex($b64, $self->secret);
68 }
69
70 1;
71
72 __END__
73
74 =head1 NAME
75
76 Plack::Middleware::Session::Cookie - Session middleware that saves session data in the cookie
77
78 =head1 SYNOPSIS
79
80   enable "Session::Cookie";
81
82 =head1 DESCRIPTION
83
84 This middleware component allows you to use the cookie as a sole
85 cookie state and store, without any server side storage to do the
86 session management. This middleware utilizes its own state and store
87 automatically for you, so you can't override the objects.
88
89 =head1 CONFIGURATIONS
90
91 This middleware is a subclass of L<Plack::Middleware::Session> and
92 accepts most configuration of the parent class. In addition, following
93 options are accepted.
94
95 =over 4
96
97 =item secret
98
99 Server side secret to sign the session data using HMAC SHA1. Defaults
100 to nothing (i.e. do not sign) but B<strongly recommended> to set your
101 own secret string.
102
103 =item session_key, domain, expires, path, secure
104
105 Accessors for the cookie attribuets. See
106 L<Plack::Session::State::Cookie> for these options.
107
108 =back
109
110 =head1 AUTHOR
111
112 Tatsuhiko Miyagawa
113
114 =head1 SEE ALSO
115
116 Rack::Session::Cookie L<Dancer::Session::Cookie>
117
118 =cut
119