File Coverage

blib/lib/Plack/Middleware/Auth/Bitcard.pm
Criterion Covered Total %
statement 63 88 71.5
branch 8 24 33.3
condition 2 12 16.6
subroutine 18 20 90.0
pod 2 2 100.0
total 93 146 63.7


line stmt bran cond sub pod time code
1             package Plack::Middleware::Auth::Bitcard;
2              
3 2     2   2232 use 5.008;
  2         12  
  2         101  
4 2     2   12 use strict;
  2         3  
  2         73  
5 2     2   12 use warnings;
  2         14  
  2         282  
6              
7             BEGIN {
8 2     2   6 $Plack::Middleware::Auth::Bitcard::AUTHORITY = 'cpan:TOBYINK';
9 2         41 $Plack::Middleware::Auth::Bitcard::VERSION = '0.002';
10             }
11              
12 2     2   13 use Carp;
  2         4  
  2         194  
13 2     2   11 use JSON qw(to_json from_json);
  2         4  
  2         15  
14 2     2   2862 use Plack::Response;
  2         96261  
  2         72  
15 2     2   1012 use Plack::Request;
  2         696567  
  2         249  
16 2     2   906 use Plack::Util;
  2         3645  
  2         61  
17 2     2   14 use Plack::Util::Accessor qw( bitcard skip_if on_unauth );
  2         4  
  2         13  
18 2     2   12184 use Digest::SHA qw(sha1_hex);
  2         5160  
  2         231  
19              
20 2     2   20 use base "Plack::Middleware";
  2         4  
  2         2532  
21              
22             sub prepare_app
23             {
24 1     1 1 104 my $self = shift;
25 1 50       5 croak "Need to provide Authen::Bitcard object" unless ref $self->bitcard;
26 1         113 $self->bitcard->info_required('username');
27             }
28              
29             sub call
30             {
31 2     2 1 33666 my $self = shift;
32 2         6 my $env = $_[0];
33 2         23 my $req = "Plack::Request"->new($env);
34            
35             $env->{BITCARD_URL} = sub
36             {
37 0 0   0   0 unshift @_, 'login_url' if ref $_[0];
38 0         0 my $method = shift;
39 0   0     0 my $env = shift || croak("needs \$env!");
40 0   0     0 my $return = shift || $self->_boomerang_uri("Plack::Request"->new($env));
41 0         0 $self->bitcard->$method(r => $return);
42 2         31 };
43              
44 2 50 66     8 if ($self->_req_is_boomerang($req))
    50          
    100          
    50          
45             {
46 0         0 my $res = $self->_store_cookie_data($req);
47 0         0 return $res->finalize;
48             }
49             elsif ($self->_fetch_cookie_data($req => $env))
50             {
51 0         0 return $self->app->($env);
52             }
53             elsif ($self->skip_if and $self->skip_if->($env))
54             {
55 1         61 return $self->app->($env);
56             }
57             elsif (my $on_unauth = $self->on_unauth)
58             {
59 0         0 return $on_unauth->($env);
60             }
61             else
62             {
63 1         87 my $res = $self->_start_boomerang($req);
64 1         7 return $res->finalize;
65             }
66             }
67              
68             sub _boomerang_uri
69             {
70 3     3   12 my $self = shift;
71 3         5 my $req = $_[0];
72            
73 3         12 my $base = $req->base;
74 3 50       437 $base =~ m{/$} ? "${base}_bitcard_boomerang" : "${base}/_bitcard_boomerang";
75             }
76              
77             sub _start_boomerang
78             {
79 1     1   3 my $self = shift;
80 1         2 my $req = $_[0];
81            
82 1         11 my $res = "Plack::Response"->new;
83 1         73 $res->cookies->{bitcard_return_to} = $req->uri;
84 1         233 $res->redirect(
85             $self->bitcard->login_url(
86             r => $self->_boomerang_uri($req),
87             ),
88             );
89 1         3795 return $res;
90             }
91              
92             sub _req_is_boomerang
93             {
94 2     2   5 my $self = shift;
95 2         4 my $req = $_[0];
96            
97 2         10 my ($uri) = split /\?/, $req->uri; # ignore query string
98 2         761 return ($uri eq $self->_boomerang_uri($req));
99             }
100              
101             sub _store_cookie_data
102             {
103 0     0   0 my $self = shift;
104 0         0 my $req = $_[0];
105            
106 0         0 my $res = "Plack::Response"->new;
107 0 0 0     0 $res->redirect(
108             defined $req->cookies->{bitcard_return_to} && $req->cookies->{bitcard_return_to} ne '-'
109             ? $req->cookies->{bitcard_return_to}
110             : $req->base
111             );
112 0 0       0 if (my $user = $self->bitcard->verify($req))
113             {
114 0         0 $user->{_checksum} = sha1_hex($self->bitcard->api_secret . $user->{username});
115 0         0 $res->cookies->{bitcard} = to_json($user);
116             }
117             else
118             {
119 0         0 $res->cookies->{bitcard} = to_json({});
120             }
121 0         0 $req->cookies->{bitcard_return_to} = { value => "-" };
122 0         0 return $res;
123             }
124              
125             sub _fetch_cookie_data
126             {
127 2     2   41 my $self = shift;
128 2         4 my ($req, $env) = @_;
129            
130 2 50       11 return unless $req->cookies->{bitcard};
131 0           my $user = from_json($req->cookies->{bitcard});
132            
133 0 0         return unless $user->{username};
134 0 0         return unless sha1_hex($self->bitcard->api_secret . $user->{username}) eq $user->{_checksum};
135            
136 0           $env->{BITCARD} = +{%$user};
137 0           delete $env->{BITCARD}{_checksum};
138 0           return $env->{BITCARD}{username};
139             }
140              
141             1;
142              
143             __END__