Commit | Line | Data |
d326e755 |
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 | |
4ff41723 |
18 | Plack::Util::load_class($self->session_class) if $self->session_class; |
d326e755 |
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(@_) }, |
4ff41723 |
37 | finalize => sub { $state_cookie->finalize(@_) }; |
d326e755 |
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 | |
4ff41723 |
52 | sub finalize { |
98b27b31 |
53 | my($self, $session, $options, $response) = @_; |
4ff41723 |
54 | |
98b27b31 |
55 | if ($options->{expire}) { |
56 | $self->state->expire_session_id($options->{id}, $response); |
4ff41723 |
57 | } else { |
98b27b31 |
58 | my $cookie = $self->_serialize($session); |
59 | $self->state->finalize($cookie, $response, $options); |
4ff41723 |
60 | } |
61 | } |
62 | |
d326e755 |
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 | |