File Coverage

blib/lib/Plack/Middleware/Session/Cookie.pm
Criterion Covered Total %
statement 49 65 75.3
branch 6 16 37.5
condition n/a
subroutine 17 21 80.9
pod 2 8 25.0
total 74 110 67.2


line stmt bran cond sub pod time code
1             package Plack::Middleware::Session::Cookie;
2 2     2   113859 use strict;
  2         6  
  2         88  
3 2     2   11 use parent qw(Plack::Middleware::Session);
  2         3  
  2         10  
4              
5 2         10 use Plack::Util::Accessor qw(secret session_key domain expires path secure httponly
6 2     2   162 partitioned samesite serializer deserializer);
  2         4  
7              
8 2     2   1073 use Digest::HMAC_SHA1;
  2         15443  
  2         133  
9 2     2   1125 use MIME::Base64 ();
  2         1698  
  2         63  
10 2     2   1204 use Storable ();
  2         10224  
  2         104  
11 2     2   755 use Time::HiRes;
  2         1865  
  2         17  
12 2     2   165 use Plack::Util;
  2         3  
  2         69  
13              
14 2     2   1442 use Plack::Session::State::Cookie;
  2         8  
  2         1204  
15              
16             sub prepare_app {
17 3     3 1 746171 my $self = shift;
18              
19 3 50       18 die "Plack::Session::Middleware::Cookie requires setting 'secret' option."
20             unless $self->secret;
21              
22 3 50       133 $self->session_key("plack_session") unless $self->session_key;
23              
24 6     6   89 $self->serializer(sub {MIME::Base64::encode(Storable::nfreeze($_[0]), '' )})
25 3 50       50 unless $self->serializer;
26              
27 0     0   0 $self->deserializer(sub {Storable::thaw(MIME::Base64::decode($_[0]))})
28 3 50       55 unless $self->deserializer;
29              
30 3         82 $self->state( Plack::Session::State::Cookie->new );
31 3         24 for my $attr (qw(session_key path domain expires secure partitioned httponly samesite)) {
32 24         346 $self->state->$attr($self->$attr);
33             }
34             }
35              
36             sub _compare {
37 0     0   0 my($s1, $s2) = @_;
38              
39 0 0       0 return if length $s1 != length $s2;
40 0         0 my $r = 0;
41 0         0 for my $i (0..length($s1) - 1) {
42 0         0 $r |= ord(substr $s1, $i) ^ ord(substr $s2, $i);
43             }
44              
45 0         0 return $r == 0;
46             }
47              
48             sub get_session {
49 6     6 0 17 my($self, $request) = @_;
50              
51 6 50       28 my $cookie = $self->state->get_session_id($request) or return;
52              
53 0         0 my($time, $b64, $sig) = split /:/, $cookie, 3;
54 0 0       0 _compare($self->sig($b64), $sig) or return;
55              
56             # NOTE: do something with $time?
57              
58 0         0 my $session = $self->deserializer->($b64);
59 0         0 return ($self->generate_id, $session);
60             }
61              
62             sub generate_id {
63 6     6 0 13 my $self = shift;
64 6         50 return scalar Time::HiRes::gettimeofday;
65             }
66              
67       6 0   sub commit { }
68              
69             sub change_id {
70 0     0 1 0 my($self, $env) = @_;
71              
72 0         0 my $options = $env->{'psgix.session.options'};
73              
74 0         0 $options->{id} = $self->generate_id($env);
75             }
76              
77             sub expire_session {
78 0     0 0 0 my($self, $id, $res, $env) = @_;
79 0         0 $self->state->expire_session_id($id, $res, $env->{'psgix.session.options'});
80             }
81              
82             sub save_state {
83 6     6 0 32 my($self, $id, $res, $env) = @_;
84              
85 6         21 my $cookie = $self->_serialize($id, $env->{'psgix.session'});
86 6         352 $self->state->finalize($cookie, $res, $env->{'psgix.session.options'});
87             }
88              
89             sub _serialize {
90 6     6   16 my($self, $id, $session) = @_;
91              
92 6         23 my $b64 = $self->serializer->($session);
93 6         516 join ":", $id, $b64, $self->sig($b64);
94             }
95              
96             sub sig {
97 6     6 0 17 my($self, $b64) = @_;
98 6 50       22 return '.' unless $self->secret;
99 6         52 Digest::HMAC_SHA1::hmac_sha1_hex($b64, $self->secret);
100             }
101              
102             1;
103              
104             __END__