File Coverage

blib/lib/Rubric/WebApp/Session.pm
Criterion Covered Total %
statement 56 59 94.9
branch 9 12 75.0
condition 4 6 66.6
subroutine 17 18 94.4
pod 4 4 100.0
total 90 99 90.9


line stmt bran cond sub pod time code
1 3     3   20 use strict;
  3         8  
  3         118  
2 3     3   17 use warnings;
  3         5  
  3         167  
3             package Rubric::WebApp::Session;
4             # ABSTRACT: the Rubric session plugin
5             $Rubric::WebApp::Session::VERSION = '0.155';
6 3     3   3040 use CGI::Cookie;
  3         21535  
  3         104  
7 3     3   3637 use Crypt::CBC;
  3         17697  
  3         212  
8 3     3   4417 use JSON 2 ();
  3         52252  
  3         109  
9 3     3   3374 use MIME::Base64;
  3         2864  
  3         342  
10 3         67 use Sub::Exporter -setup => {
11             -as => '_import',
12             exports => [
13             qw(session session_cipherer get_cookie_payload set_cookie_payload)
14             ],
15             groups => [ default => [ -all ] ],
16 3     3   23 };
  3         8  
17              
18             sub import {
19 3     3   6 my ($self) = @_;
20 3         11 my $caller = caller;
21              
22 3 50       33 Carp::croak "no session_cipher_key key set"
23             unless Rubric::Config->session_cipher_key;
24              
25 3         56 $caller->add_callback(init => 'get_cookie_payload');
26 3         68 $caller->add_callback(postrun => 'set_cookie_payload');
27 3         50 $self->_import({ into => $caller });
28             }
29              
30             # =head1 METHODS
31             #
32             # These methods are imported into the using class and should be called on an
33             # object of that type -- here, a Rubric::WebApp.
34             #
35             # =head2 session
36             #
37             # This returns the session, a hashref.
38             #
39             # =cut
40              
41             sub session {
42 338     338 1 1706 my ($self) = @_;
43 338   66     2041 return $self->{__PACKAGE__}{session} ||= $self->get_cookie_payload;
44             }
45              
46             my $COOKIE_NAME = 'RubricSession';
47              
48 2     2   936 sub __empty { Rubric::WebApp::Session::Object->new({}) }
49              
50             # =head2 session_cipherer
51             #
52             # This returns a Crypt::CBC object for handling ciphering.
53             #
54             # =cut
55              
56             sub session_cipherer {
57 142     142 1 279 my ($self) = @_;
58              
59 142   66     1684 $self->{__PACKAGE__}{cipherer} ||= Crypt::CBC->new(
60             -key => Rubric::Config->session_cipher_key,
61             -cipher => 'Rijndael',
62             -padding => 'standard',
63             );
64             }
65              
66             # =head2 get_cookie_payload
67             #
68             # This gets the cookie and returns the payload as a R::WA::Session::Object.
69             #
70             # =cut
71              
72             sub get_cookie_payload {
73 96     96 1 1198380 my ($self) = @_;
74              
75 96 100       406 return __empty unless my $cookie_value = $self->query->cookie($COOKIE_NAME);
76              
77 94         51571 my $cipherer = $self->session_cipherer;
78              
79 94         7239 my $data = eval {
80 94         1547 JSON->new->utf8->decode(
81             $cipherer->decrypt(decode_base64($cookie_value))
82             );
83             };
84              
85 94 50       19258 my $session = $data ? Rubric::WebApp::Session::Object->new($data) : __empty;
86             }
87              
88             # =head2 set_cookie_payload
89             #
90             # This method writes the session data back out to a cookie entry.
91             #
92             # =cut
93              
94             sub set_cookie_payload {
95 48     48 1 6623 my ($self) = @_;
96              
97 48         96 my $cookie_value = eval {
98 48         930 my $json = JSON->new->utf8->encode($self->session->as_hash);
99              
100 48         438 encode_base64($self->session_cipherer->encrypt($json));
101             };
102              
103 48         78340 my $cookie = CGI::Cookie->new(
104             -name => $COOKIE_NAME,
105             -expires => '+30d',
106             -value => $cookie_value,
107             );
108              
109 48         12513 $self->header_add(-cookie => [ $cookie ]);
110             }
111              
112             # =head1 SESSION OBJECT METHODS
113             #
114             # =cut
115              
116             package Rubric::WebApp::Session::Object;
117             $Rubric::WebApp::Session::Object::VERSION = '0.155';
118             # =head2 new
119             #
120             # This makes a new session object. You don't need this.
121             #
122             # =cut
123              
124             sub new {
125 96     96   375 my ($class, $data) = @_;
126 96         702 bless $data => $class;
127             }
128              
129             # =head2 param
130             #
131             # $obj->param('foo'); # get
132             # $obj->param('foo', 'val'); # set
133             #
134             # =cut
135              
136             sub param {
137 289     289   1586 my $self = shift;
138              
139 289 100       1469 if (@_ == 1) {
140 224 100       1762 return $self->{$_[0]} if exists $self->{$_[0]};
141 36         335 return;
142             }
143              
144 65 50       230 if (@_ == 2) {
145 65         245 return $self->{$_[0]} = $_[1];
146             }
147              
148 0         0 die "invalid number of args to session->param";
149             }
150              
151             # =head2 clear
152             #
153             # $obj->clear('name');
154             #
155             # Clear the entry (delete it entirely) from the session.
156             #
157             # =cut
158              
159             sub clear {
160 1     1   3 my ($self, $param) = @_;
161 1         6 delete $self->{$param};
162             }
163              
164             # =head2 delete
165             #
166             # $session->delete;
167             #
168             # Removes all data from the session.
169             #
170             # =cut
171              
172             sub delete {
173 0     0   0 my ($self) = @_;
174 0         0 %$self = ();
175             }
176              
177             # =head2 as_hash
178             #
179             # This returns a hashref containing the session data.
180             #
181             # =cut
182              
183             sub as_hash {
184 48     48   107 return { %{ $_[0] } };
  48         678  
185             }
186              
187             1;
188              
189             __END__