File Coverage

blib/lib/AWS/S3/Signer.pm
Criterion Covered Total %
statement 24 30 80.0
branch n/a
condition n/a
subroutine 8 10 80.0
pod 0 1 0.0
total 32 41 78.0


line stmt bran cond sub pod time code
1              
2             package AWS::S3::Signer;
3              
4 3     3   2053 use Moose;
  3         4  
  3         16  
5 3     3   11860 use HTTP::Request::Common;
  3         4  
  3         176  
6 3     3   11 use HTTP::Date 'time2str';
  3         4  
  3         148  
7 3     3   1243 use MIME::Base64 qw(encode_base64);
  3         1690  
  3         141  
8 3     3   1171 use Digest::HMAC_SHA1;
  3         11860  
  3         171  
9 3     3   20 use Digest::MD5 'md5';
  3         4  
  3         153  
10              
11 3     3   12 use Moose::Util::TypeConstraints qw(enum);
  3         6  
  3         28  
12 3     3   2463 use MooseX::Types::URI qw(Uri);
  3         895960  
  3         13  
13              
14             has 's3' => (
15             is => 'ro',
16             isa => 'AWS::S3',
17             required => 1,
18             );
19              
20             has 'method' => (
21             is => 'ro',
22             isa => enum([qw/ HEAD GET PUT POST DELETE /]),
23             required => 1,
24             );
25              
26             has 'bucket_name' => (
27             is => 'ro',
28             isa => 'Str',
29             required => 1,
30             lazy => 1,
31             default => sub {
32             my $s = shift;
33             my $endpoint = $s->s3->endpoint;
34             if ( my ( $name ) = $s->uri->host =~ m{^(.+?)\.\Q$endpoint\E} ) {
35             return $name;
36             } else {
37             return '';
38             } # end if()
39             }
40             );
41              
42             has 'uri' => (
43             is => 'ro',
44             isa => Uri,
45             required => 1,
46             coerce => 1,
47             );
48              
49             has 'headers' => (
50             is => 'ro',
51             isa => 'ArrayRef[Str]',
52             lazy => 1,
53             default => sub { [] },
54             );
55              
56             has 'date' => (
57             is => 'ro',
58             isa => 'Str',
59             default => sub {
60             time2str( time );
61             }
62             );
63              
64             has 'string_to_sign' => (
65             is => 'ro',
66             isa => 'Str',
67             lazy => 1,
68             default => sub {
69             my $s = shift;
70              
71             join "\n",
72             (
73             $s->method, $s->content_md5,
74             $s->content ? $s->content_type : '',
75             $s->date || '',
76             ( join "\n", grep { $_ } ( $s->canonicalized_amz_headers, $s->canonicalized_resource ) )
77             );
78             }
79             );
80              
81             has 'canonicalized_amz_headers' => (
82             is => 'ro',
83             isa => 'Str',
84             lazy => 1,
85             default => sub {
86             my $s = shift;
87              
88             my @h = @{ $s->headers };
89             my %out = ();
90             while ( my ( $k, $v ) = splice( @h, 0, 2 ) ) {
91             $k = lc( $k );
92             if ( exists $out{$k} ) {
93             $out{$k} = [ $out{$k} ] unless ref( $out{$k} );
94             push @{ $out{$k} }, $v;
95             } else {
96             $out{$k} = $v;
97             } # end if()
98             } # end while()
99              
100             my @parts = ();
101             while ( my ( $k, $v ) = each %out ) {
102             if ( ref( $out{$k} ) ) {
103             push @parts, _trim( $k ) . ':' . join( ',', map { _trim( $_ ) } @{ $out{$k} } );
104             } else {
105             push @parts, _trim( $k ) . ':' . _trim( $out{$k} );
106             } # end if()
107             } # end while()
108              
109             return join "\n", @parts;
110             }
111             );
112              
113             has 'canonicalized_resource' => (
114             is => 'ro',
115             isa => 'Str',
116             lazy => 1,
117             default => sub {
118             my $s = shift;
119             my $str = $s->bucket_name ? '/' . $s->bucket_name . $s->uri->path : $s->uri->path;
120              
121             if ( my ( $resource ) =
122             ( $s->uri->query || '' ) =~ m{[&]*(acl|website|location|policy|delete|lifecycle)(?!\=)} )
123             {
124             $str .= '?' . $resource;
125             } # end if()
126             return $str;
127             }
128             );
129              
130             has 'content_type' => (
131             is => 'ro',
132             isa => 'Str',
133             lazy => 1,
134             default => sub {
135             my $s = shift;
136             return '' if $s->method eq 'GET';
137             return '' unless $s->content;
138             return 'text/plain';
139             }
140             );
141              
142             has 'content_md5' => (
143             is => 'ro',
144             isa => 'Str',
145             lazy => 1,
146             default => sub {
147             my $s = shift;
148             return '' unless $s->content;
149             return encode_base64( md5( ${ $s->content } ), '' );
150             }
151             );
152              
153             has 'content' => (
154             is => 'ro',
155             isa => 'Maybe[ScalarRef]',
156             );
157              
158             has 'content_length' => (
159             is => 'ro',
160             isa => 'Int',
161             lazy => 1,
162             default => sub { length( ${ shift->content } ) }
163             );
164              
165             has 'signature' => (
166             is => 'ro',
167             isa => 'Str',
168             lazy => 1,
169             default => sub {
170             my $s = shift;
171             my $hmac = Digest::HMAC_SHA1->new( $s->s3->secret_access_key );
172             $hmac->add( $s->string_to_sign() );
173             return encode_base64( $hmac->digest, '' );
174             }
175             );
176              
177             sub auth_header {
178 0     0 0   my $s = shift;
179              
180 0           return 'AWS ' . $s->s3->access_key_id . ':' . $s->signature;
181             } # end auth_header()
182              
183             sub _trim {
184 0     0     my ( $value ) = @_;
185 0           $value =~ s/^\s+//;
186 0           $value =~ s/\s+$//;
187 0           return $value;
188             } # end _trim()
189              
190             1;