File Coverage

blib/lib/Plack/Middleware/Access.pm
Criterion Covered Total %
statement 62 68 91.1
branch 26 34 76.4
condition 4 9 44.4
subroutine 13 13 100.0
pod 3 3 100.0
total 108 127 85.0


line stmt bran cond sub pod time code
1             package Plack::Middleware::Access;
2             #ABSTRACT: Restrict access depending on remote ip or other parameters
3             $Plack::Middleware::Access::VERSION = '0.4';
4 2     2   1705 use strict;
  2         4  
  2         71  
5 2     2   11 use warnings;
  2         4  
  2         68  
6              
7 2     2   869 use parent qw(Plack::Middleware);
  2         324  
  2         13  
8              
9 2     2   16192 use Plack::Util::Accessor qw(rules deny_page);
  2         587  
  2         14  
10              
11 2     2   106 use Carp qw(croak);
  2         2  
  2         111  
12 2     2   2198 use Net::IP;
  2         97598  
  2         1775  
13              
14             sub prepare_app {
15 9     9 1 5800 my $self = shift;
16              
17 9 100       29 if (!ref $self->deny_page) {
    50          
18 8 100       128 my $msg = defined $self->deny_page ?
19             $self->deny_page : 'Forbidden';
20             $self->deny_page(sub {
21 5     5   56 [403, [ 'Content-Type' =>'text/plain',
22             'Content-Length' => length $msg ], [ $msg ] ];
23 8         64 });
24             } elsif (ref $self->deny_page ne 'CODE') {
25 0         0 croak "deny_page must be a CODEREF";
26             }
27              
28 9 100       68 if (!defined($self->rules)) {
    50          
    50          
29 1         8 $self->rules([]);
30 8         75 } elsif( ref($self->rules) ne 'ARRAY' ) {
31 0         0 croak "rules must be an ARRAYREF";
32             } elsif (@{ $self->rules } % 2 != 0) {
33 0         0 croak "rules must contain an even number of params";
34             }
35              
36 9         54 my @rules = ();
37              
38 9         14 foreach (my $i = 0; $i < @{ $self->rules }; $i += 2) {
  21         47  
39 12         66 my $allowing = $self->rules->[$i];
40 12         58 my $rule = $self->rules->[$i + 1];
41              
42 12 50       82 if ($allowing !~ /^(allow|deny)$/) {
43 0         0 croak "first argument of each rule must be 'allow' or 'deny'";
44             }
45              
46 12 50       21 if (!defined($rule)) {
47 0         0 croak "rule argument must be defined";
48             }
49              
50 12 100       30 $allowing = ($allowing eq 'allow') ? 1 : 0;
51 12         15 my $check = $rule;
52              
53 12 100       51 if ($rule eq 'all') {
    100          
    100          
54 3     1   32 $check = sub { 1 };
  1         3  
55             } elsif ($rule =~ /[A-Z]$/i) {
56             $check = sub {
57 2     2   4 my $host = $_[0]->{REMOTE_HOST};
58 2 50       5 return unless defined $host; # skip rule
59 2         81 return $host =~ qr/^(.*\.)?\Q${rule}\E$/;
60 2         5 };
61             } elsif ( ref($rule) ne 'CODE' ) {
62 5 50       24 my $netip = Net::IP->new($rule) or
63             die "not supported type of rule argument [$rule] or bad ip: " . Net::IP::Error();
64             $check = sub {
65 4     4   9 my $addr = $_[0]->{REMOTE_ADDR};
66 4         3 my $ip;
67 4 50 33     31 if (defined($addr) && ($ip = Net::IP->new($addr))) {
68 4         1624 my $overlaps = $netip->overlaps($ip);
69 4   33     149 return $overlaps == $IP_B_IN_A_OVERLAP || $overlaps == $IP_IDENTICAL;
70             } else {
71 0         0 return undef;
72             }
73 5         2367 };
74             }
75              
76 12         36 push @rules, [ $check => $allowing ];
77             }
78              
79 9         78 $self->rules(\@rules);
80             }
81              
82             sub allow {
83 9     9 1 11 my ($self, $env) = @_;
84              
85 9         10 foreach my $rule (@{ $self->rules }) {
  9         23  
86 9         38 my ($check, $allow) = @{$rule};
  9         16  
87 9         21 my $result = $check->($env);
88 9 100 66     65 if (defined $result && $result) {
89 8         42 return $allow;
90             }
91             }
92              
93 1         96 return 1;
94             }
95              
96             sub call {
97 9     9 1 431301 my ($self, $env) = @_;
98              
99 9 100       24 return $self->allow($env)
100             ? $self->app->($env) : $self->deny_page->($env);
101             }
102              
103             1;
104              
105             __END__