File Coverage

blib/lib/Digest/SRI.pm
Criterion Covered Total %
statement 77 77 100.0
branch 30 30 100.0
condition 6 6 100.0
subroutine 18 18 100.0
pod 0 12 0.0
total 131 143 91.6


line stmt bran cond sub pod time code
1             #!perl
2             package Digest::SRI;
3 1     1   112156 use warnings;
  1         14  
  1         37  
4 1     1   5 use strict;
  1         2  
  1         20  
5 1     1   5 use Carp;
  1         4  
  1         57  
6 1     1   7 use Scalar::Util qw/blessed/;
  1         2  
  1         78  
7             require Digest;
8             require MIME::Base64;
9              
10             # For AUTHOR, COPYRIGHT, AND LICENSE see the bottom of this file
11              
12             our $VERSION = '0.02';
13              
14 1     1   6 use Exporter 'import';
  1         2  
  1         1454  
15             our @EXPORT_OK = qw/ sri verify_sri /;
16              
17             my $DEFAULT_ALGO = 'sha512';
18             my %KNOWN_ALGOS = (
19             sha512 => 'SHA-512',
20             sha384 => 'SHA-384',
21             sha256 => 'SHA-256',
22             sha1 => 'SHA-1',
23             md5 => 'MD5',
24             );
25             my ($KNOWN_ALGO_RE) = map { qr/$_/ } join '|', map {quotemeta}
26             sort { length $b <=> length $a or $a cmp $b } keys %KNOWN_ALGOS;
27              
28             ## no critic (RequireArgUnpacking)
29              
30             sub new {
31 29     29 0 3542 my $class = shift;
32 29 100       72 if (ref $class) {
33 5 100 100     311 croak "bad argument to new: must be ".__PACKAGE__." instance"
34             unless blessed($class) && $class->isa(__PACKAGE__);
35 3         16 $class->{dig}->reset;
36 3         36 return $class;
37             }
38 24 100       63 my $param = @_ ? shift : $DEFAULT_ALGO;
39 24         35 my ($algo,$expected);
40 24 100       229 if ( $param =~ m{\A(${KNOWN_ALGO_RE})-([A-Za-z0-9+/=]+)\z} )
41 10         28 { $algo = $1; $expected = $2 }
  10         20  
42             else {
43 14         73 ( $algo = lc $param ) =~ s/[\s\-]+//g;
44             croak "unknown/unsupported algorithm '$param'"
45 14 100       145 unless exists $KNOWN_ALGOS{$algo};
46             }
47             my $self = {
48             algo => $algo,
49 23         93 dig => Digest->new( $KNOWN_ALGOS{$algo} ),
50             };
51 23 100       4339 $self->{exp} = $algo.'-'.$expected if defined $expected;
52 23         102 return bless $self, $class;
53             }
54             *reset = \&new;
55              
56             sub clone {
57 4     4 0 13 my $self = shift;
58             my $new_self = {
59             algo => $self->{algo},
60             dig => $self->{dig}->clone,
61 4         25 };
62 4 100       14 $new_self->{exp} = $self->{exp} if defined $self->{exp};
63 4         18 return bless $new_self, ref $self;
64             }
65              
66             sub _grokdata {
67 8     8   16 my ($obj,$what) = @_;
68 8 100       20 if ( my $r = ref $what ) {
69 5 100       14 if ($r eq 'GLOB')
    100          
70 1         4 { return $obj->addfile($what) }
71             elsif ($r eq 'SCALAR')
72 2         6 { return $obj->new(@_)->add($$what) }
73             else
74 2         157 { croak "can't handle reference to $r" }
75             } else
76 3         9 { return $obj->addfilename($what) }
77             }
78              
79             sub sri {
80 28 100 100 28 0 2656 if ( blessed($_[0]) && $_[0]->isa(__PACKAGE__) ) { # method call
81 20         31 my $self = shift;
82             # Note: ->b64digest strips of the trailing padding
83 20         261 return $self->{algo} . '-' . MIME::Base64::encode($self->{dig}->digest(@_), "");
84             } # else, regular function call
85 8 100       94 croak "not enough arguments to sri()" unless @_;
86 7 100       103 croak "too many arguments to sri()" if @_>2;
87 6         11 my $data = pop @_;
88 6         23 return _grokdata(Digest::SRI->new(@_), $data)->sri;
89             }
90              
91             sub verify_sri {
92 3 100   3 0 687 croak "expected two arguments to verify_sri()" unless @_==2;
93 2         6 my $data = pop @_;
94 2         8 return _grokdata(Digest::SRI->new(@_), $data)->verify;
95             }
96              
97             sub verify {
98 10     10 0 18 my $self = shift;
99 10         21 ( my $l = $self->sri ) =~ s/=+\z//;
100 10         33 ( my $r = $self->{exp} ) =~ s/=+\z//;
101 10         53 return $l eq $r;
102             }
103              
104             sub addfilename {
105 5     5 0 9 my $self = shift;
106 5         6 my $fn = shift;
107 5 100       313 open my $fh, '<', $fn or croak "couldn't open $fn: $!";
108 4         17 binmode $fh;
109 4         14 $self->addfile($fh);
110 4         44 close $fh;
111 4         26 return $self;
112             }
113              
114             # see Digest::base
115 16     16 0 45 sub add { my $self = shift; $self->{dig}->add(@_); return $self }
  16         63  
  16         49  
116 6     6 0 12 sub addfile { my $self = shift; $self->{dig}->addfile(@_); return $self }
  6         24  
  6         267  
117 1     1 0 2 sub add_bits { my $self = shift; $self->{dig}->add_bits(@_); return $self }
  1         4  
  1         21  
118 1     1 0 2 sub digest { my $self = shift; return $self->{dig}->digest(@_) }
  1         11  
119 1     1 0 3 sub hexdigest { my $self = shift; return $self->{dig}->hexdigest(@_) }
  1         10  
120 1     1 0 2 sub b64digest { my $self = shift; return $self->{dig}->b64digest(@_) }
  1         16  
121              
122             1;
123             __END__