File Coverage

blib/lib/Plack/Middleware/Session/Simple/JWSCookie.pm
Criterion Covered Total %
statement 44 83 53.0
branch 9 46 19.5
condition 7 56 12.5
subroutine 11 14 78.5
pod 1 3 33.3
total 72 202 35.6


line stmt bran cond sub pod time code
1             package Plack::Middleware::Session::Simple::JWSCookie;
2 5     5   3585 use 5.008001;
  5         22  
  5         256  
3 5     5   29 use strict;
  5         8  
  5         180  
4 5     5   30 use warnings;
  5         16  
  5         317  
5              
6             our $VERSION = "0.01";
7              
8 5     5   651 use parent qw(Plack::Middleware::Session::Simple);
  5         475  
  5         40  
9 5     5   51066 use Digest::SHA1 qw//;
  5         14  
  5         97  
10 5     5   25 use Cookie::Baker;
  5         8  
  5         305  
11 5     5   28 use Plack::Util;
  5         9  
  5         138  
12 5     5   29 use Scalar::Util qw/blessed/;
  5         10  
  5         279  
13 5     5   2244 use JSON::WebToken qw/encode_jwt decode_jwt/;
  5         29870  
  5         507  
14 5         44 use Plack::Util::Accessor qw/
15             alg
16             secret
17 5     5   40 /;
  5         8  
18              
19             sub prepare_app {
20 4     4 1 1407 my $self = shift;
21              
22 4         28 my $store = $self->store;
23 4 50 33     632 die('store require get, set and remove method.')
      33        
      33        
24             unless blessed $store
25             && $store->can('get')
26             && $store->can('set')
27             && $store->can('remove');
28              
29 4 50       28 $self->cookie_name('simple_session') unless $self->cookie_name;
30 4 50       43 $self->path('/') unless defined $self->path;
31 4 100       59 $self->keep_empty(1) unless defined $self->keep_empty;
32              
33 4 50       52 if ( !$self->sid_generator ) {
34             $self->sid_generator(sub{
35 0     0   0 Digest::SHA1::sha1_hex(rand() . $$ . {} . time)
36 4         34 });
37             }
38 4 50       34 if ( !$self->sid_validator ) {
39 4         30 $self->sid_validator(
40             qr/\A[0-9a-f]{40}\Z/
41             );
42             }
43              
44             # secret & alg
45 4 100 66     23 unless ($self->secret && $self->alg) {
46 3         22 $self->alg('none');
47 3         17 $self->secret(undef);
48             } else {
49             # support only HMAC Signature
50 1 0 33     14 die "Plack::Middleware::Session::Cookie::JWS supports only HMAC Signatures"
      33        
51             unless ($self->alg eq 'HS256' || $self->alg eq 'HS384' || $self->alg eq 'HS512');
52             }
53             }
54              
55             sub get_session {
56 0     0 0   my ($self, $env) = @_;
57 0   0       my $cookie = crush_cookie($env->{HTTP_COOKIE} || '')->{$self->{cookie_name}};
58 0 0         return unless defined $cookie;
59 0           my $payload;
60 0           eval {
61 0           $payload = decode_jwt($cookie, $self->secret, 0);
62             };
63 0 0 0       return if ($@ || !$payload->{id});
64              
65 0           my $id = $payload->{id};
66 0 0         return unless $id =~ $self->{sid_validator};
67              
68 0 0         my $session = $self->{store}->get($id) or return;
69 0 0         $session = $self->{serializer}->[1]->($session) if $self->{serializer};
70 0           return ($id, $session);
71             }
72              
73             sub finalize {
74 0     0 0   my ($self, $env, $res, $session) = @_;
75 0           my $options = $env->{'psgix.session.options'};
76 0           my $new_session = delete $options->{new_session};
77              
78 0           my $need_store;
79 0 0 0       if ( ($new_session && $self->{keep_empty} && ! $session->has_key )
      0        
      0        
      0        
      0        
80             || $session->[1] || $options->{expire} || $options->{change_id}) {
81 0           $need_store = 1;
82             }
83 0 0         $need_store = 0 if $options->{no_store};
84              
85 0           my $set_cookie;
86 0 0 0       if ( ($new_session && $self->{keep_empty} && ! $session->has_key )
      0        
      0        
      0        
      0        
      0        
87             || ($new_session && $session->[1] )
88             || $options->{expire} || $options->{change_id}) {
89 0           $set_cookie = 1;
90             }
91              
92 0 0         if ( $need_store ) {
93 0 0         if ($options->{expire}) {
    0          
94 0           $self->{store}->remove($options->{id});
95             } elsif ($options->{change_id}) {
96 0           $self->{store}->remove($options->{id});
97 0           $options->{id} = $self->{sid_generator}->();
98 0           my $val = $session->[0];
99 0 0         $val = $self->{serializer}->[0]->($val) if $self->{serializer};
100 0           $self->{store}->set($options->{id}, $val);
101             } else {
102 0           my $val = $session->[0];
103 0 0         $val = $self->{serializer}->[0]->($val) if $self->{serializer};
104 0           $self->{store}->set($options->{id}, $val);
105             }
106             }
107              
108 0 0         if ( $set_cookie ) {
109 0           my $jws = encode_jwt({ id => $options->{id} }, $self->secret, $self->alg);
110 0 0         if ($options->{expire}) {
111 0           $self->_set_cookie(
112             $jws, $res, %$options, expires => 'now');
113             } else {
114 0           $self->_set_cookie(
115             $jws, $res, %$options);
116             }
117             }
118             }
119              
120             1;
121              
122             __END__