File Coverage

blib/lib/Net/OAuth/Message.pm
Criterion Covered Total %
statement 200 220 90.9
branch 48 62 77.4
condition 38 59 64.4
subroutine 37 39 94.8
pod 1 27 3.7
total 324 407 79.6


line stmt bran cond sub pod time code
1             package Net::OAuth::Message;
2 12     12   57002 use warnings;
  12         23  
  12         380  
3 12     12   61 use strict;
  12         48  
  12         469  
4 12     12   64 use base qw/Class::Data::Inheritable Class::Accessor/;
  12         28  
  12         18427  
5 12     12   58639 use URI::Escape;
  12         19780  
  12         950  
6 12     12   2395 use Net::OAuth;
  12         35  
  12         277  
7 12     12   47450 use URI;
  12         59928  
  12         420  
8 12     12   11879 use URI::QueryParam;
  12         10086  
  12         344  
9 12     12   82 use Carp;
  12         28  
  12         1000  
10              
11 12     12   76 use constant OAUTH_PREFIX => 'oauth_';
  12         25  
  12         49141  
12              
13             our $OAUTH_PREFIX_RE = do {my $p = OAUTH_PREFIX; qr/^$p/};
14              
15             __PACKAGE__->mk_classdata(extension_param_patterns => []);
16              
17             sub add_required_message_params {
18 17     17 0 40 my $class = shift;
19 17         51 $class->required_message_params([@{$class->required_message_params}, @_]);
  17         131  
20 17         1049 $class->all_message_params([@{$class->all_message_params}, @_]);
  17         118  
21 17         547 $class->all_params([@{$class->all_params}, @_]);
  17         116  
22 17         704 $class->mk_accessors(@_);
23             }
24              
25             sub add_optional_message_params {
26 0     0 0 0 my $class = shift;
27 0         0 $class->optional_message_params([@{$class->optional_message_params}, @_]);
  0         0  
28 0         0 $class->all_message_params([@{$class->all_message_params}, @_]);
  0         0  
29 0         0 $class->all_params([@{$class->all_params}, @_]);
  0         0  
30 0         0 $class->mk_accessors(@_);
31             }
32              
33             sub add_required_api_params {
34 9     9 0 22 my $class = shift;
35 9         22 $class->required_api_params([@{$class->required_api_params}, @_]);
  9         63  
36 9         457 $class->all_api_params([@{$class->all_api_params}, @_]);
  9         61  
37 9         304 $class->all_params([@{$class->all_params}, @_]);
  9         37  
38 9         149 $class->mk_accessors(@_);
39             }
40              
41             sub add_extension_param_pattern {
42 1     1 0 3 my $class = shift;
43 1         2 $class->extension_param_patterns([@{$class->extension_param_patterns}, @_]);
  1         8  
44             }
45              
46             sub add_to_signature {
47 0     0 0 0 my $class = shift;
48 0         0 $class->signature_elements([@{$class->signature_elements}, @_]);
  0         0  
49             }
50              
51             sub new {
52 37     37 1 16394 my $proto = shift;
53 37   33     229 my $class = ref $proto || $proto;
54 37         349 my %params = @_;
55 37         126 $class = get_versioned_class($class, \%params);
56 37         138 my $self = bless \%params, $class;
57 37         371 $self->set_defaults;
58 37         249 $self->check;
59 34         151 return $self;
60             }
61              
62             sub get_versioned_class {
63 46     46 0 84 my $class = shift;
64 46         65 my $params = shift;
65 46   66     193 my $protocol_version = $params->{protocol_version} || $Net::OAuth::PROTOCOL_VERSION;
66 46 100 66     446 if (defined $protocol_version and $protocol_version == Net::OAuth::PROTOCOL_VERSION_1_0A and $class !~ /\::V1_0A\::/) {
      100        
67 9         127 (my $versioned_class = $class) =~ s/::(\w+)$/::V1_0A::$1/;
68 9 100       43 return $versioned_class if Net::OAuth::smart_require($versioned_class);
69             }
70 39         222 return $class;
71             }
72              
73             sub set_defaults {
74 37     37 0 64 my $self = shift;
75 37   100     493 $self->{extra_params} ||= {};
76 37 100 50     255 $self->{version} ||= Net::OAuth::OAUTH_VERSION unless $self->{from_hash};
77             }
78              
79             sub is_extension_param {
80 346     346 0 416 my $self = shift;
81 346         525 my $param = shift;
82 346         393 return grep ($param =~ $_, @{$self->extension_param_patterns});
  346         1027  
83             }
84              
85             sub check {
86 37     37 0 68 my $self = shift;
87 37         58 foreach my $k (@{$self->required_message_params}, @{$self->required_api_params}) {
  37         161  
  37         472  
88 221 100       741 if (not defined $self->{$k}) {
89 3         1742 croak "Missing required parameter '$k'";
90             }
91             }
92 34 100 66     287 if ($self->{extra_params} and $self->allow_extra_params) {
93 30         52 foreach my $k (keys %{$self->{extra_params}}) {
  30         193  
94 22 50       270 if ($k =~ $OAUTH_PREFIX_RE) {
95 0         0 croak "Parameter '$k' not allowed in arbitrary params"
96             }
97             }
98             }
99             }
100              
101             sub encode {
102 933     933 0 28787 my $str = shift;
103 933 100       1973 $str = "" unless defined $str;
104 933 50       2103 unless($Net::OAuth::SKIP_UTF8_DOUBLE_ENCODE_CHECK) {
105 933 100 100     2630 if ($str =~ /[\x80-\xFF]/ and !utf8::is_utf8($str)) {
106 1         12 warn "Net::OAuth warning: your OAuth message appears to contain some multi-byte characters that need to be decoded via Encode.pm or a PerlIO layer first. This may result in an incorrect signature.";
107             }
108             }
109 933         2554 return URI::Escape::uri_escape_utf8($str,'^\w.~-');
110             }
111              
112             sub decode {
113 32     32 0 138 my $str = shift;
114 32         76 return uri_unescape($str);
115             }
116              
117 34     34 0 142 sub allow_extra_params {1}
118              
119 10     10 0 67 sub sign_message {0}
120              
121             sub gather_message_parameters {
122 60     60 0 105 my $self = shift;
123 60         157 my %opts = @_;
124 60 100       224 $opts{quote} = "" unless defined $opts{quote};
125 60   50     420 $opts{params} ||= [];
126 60         88 my %params;
127 60         83 foreach my $k (@{$self->required_message_params}, @{$self->optional_message_params}, @{$opts{add}}) {
  60         201  
  60         589  
  60         451  
128 386 100 100     1159 next if $k eq 'signature' and (!$self->sign_message or !grep ($_ eq 'signature', @{$opts{add}}));
      100        
129 344 100       843 my $message_key = $self->is_extension_param($k) ? $k : OAUTH_PREFIX . $k;
130 344         3770 my $v = $self->$k;
131 344 100       4046 $params{$message_key} = $v if defined $v;
132             }
133 60 100 66     583 if ($self->{extra_params} and !$opts{no_extra} and $self->allow_extra_params) {
      100        
134 50         66 foreach my $k (keys %{$self->{extra_params}}) {
  50         171  
135 39         130 $params{$k} = $self->{extra_params}{$k};
136             }
137 50 100       317 if ($self->can('request_url')) {
138 40         106 my $url = $self->request_url;
139 40         388 _ensure_uri_object($url);
140 40         58957 foreach my $k ($url->query_param) {
141 12         778 $params{$k} = $url->query_param($k);
142             }
143             }
144             }
145 60 100       1935 if ($opts{hash}) {
146 8         33 return \%params;
147             }
148 52         136 my @pairs;
149 52         212 while (my ($k,$v) = each %params) {
150 327         12595 push @pairs, join('=', encode($k), $opts{quote} . encode($v) . $opts{quote});
151             }
152 52         2692 return sort(@pairs);
153             }
154              
155             sub normalized_message_parameters {
156 32     32 0 2590 my $self = shift;
157 32         156 return join('&', $self->gather_message_parameters);
158             }
159              
160             sub signature_base_string {
161 32     32 0 21842 my $self = shift;
162 32         55 return join('&', map(encode($self->$_), @{$self->signature_elements}));
  32         147  
163             }
164              
165             sub sign {
166 17     17 0 261 my $self = shift;
167 17         130 my $class = $self->_signature_method_class;
168 17         130 $self->signature($class->sign($self, @_));
169             }
170              
171             sub verify {
172 19     19 0 2610 my $self = shift;
173 19         63 my $class = $self->_signature_method_class;
174 19         115 return $class->verify($self, @_);
175             }
176              
177             sub _signature_method_class {
178 36     36   56 my $self = shift;
179 36         161 (my $signature_method = $self->signature_method) =~ s/\W+/_/g;
180 36         558 my $sm_class = 'Net::OAuth::SignatureMethod::' . $signature_method;
181 36 50       126 croak "Unable to load $signature_method plugin" unless Net::OAuth::smart_require($sm_class);
182 36         95 return $sm_class;
183             }
184              
185             sub to_authorization_header {
186 4     4 0 6392 my $self = shift;
187 4         11 my $realm = shift;
188 4   50     18 my $sep = shift || ",";
189 4 50       12 if (defined $realm) {
190 4         16 $realm = "realm=\"$realm\"$sep";
191             }
192             else {
193 0         0 $realm = "";
194             }
195 4         24 return "OAuth $realm" .
196             join($sep, $self->gather_message_parameters(quote => '"', add => [qw/signature/], no_extra => 1));
197             }
198              
199             sub from_authorization_header {
200 1     1 0 391 my $proto = shift;
201 1         2 my $header = shift;
202 1   33     5 my $class = ref $proto || $proto;
203 1 50       6 croak "Header must start with \"OAuth \"" unless $header =~ s/OAuth //;
204 1         20 my @header = split /[\s]*,[\s]*/, $header;
205 1 50       6 shift @header if $header[0] =~ /^realm=/i;
206 1         11 return $class->_from_pairs(\@header, @_)
207             }
208              
209             sub _from_pairs() {
210 4     4   9 my $class = shift;
211 4         7 my $pairs = shift;
212 4 50       14 if (ref $pairs ne 'ARRAY') {
213 0         0 croak 'Expected an array!';
214             }
215 4         7 my %params;
216 4         9 foreach my $pair (@$pairs) {
217 16         42 my ($k,$v) = split /=/, $pair;
218 16 50 33     79 if (defined $k and defined $v) {
219 16         72 $v =~ s/(^"|"$)//g;
220 16         36 ($k,$v) = map decode($_), $k, $v;
221 16         156 $params{$k} = $v;
222             }
223             }
224 4         34 return $class->from_hash(\%params, @_);
225             }
226              
227             sub from_hash {
228 9     9 0 333 my $proto = shift;
229 9   33     64 my $class = ref $proto || $proto;
230 9         17 my $hash = shift;
231 9 50       35 if (ref $hash ne 'HASH') {
232 0         0 croak 'Expected a hash!';
233             }
234 9         39 my %api_params = @_;
235             # need to do this earlier than Message->new because
236             # the below validation step needs the correct class.
237             # https://rt.cpan.org/Public/Bug/Display.html?id=47293
238 9         35 $class = get_versioned_class($class, \%api_params);
239 9         21 my %msg_params;
240 9         34 foreach my $k (keys %$hash) {
241 48 100       281 if ($k =~ s/$OAUTH_PREFIX_RE//) {
    50          
242 46 100       58 if (!grep ($_ eq $k, @{$class->all_message_params})) {
  46         165  
243 1         2146 croak "Parameter ". OAUTH_PREFIX ."$k not valid for a message of type $class";
244             }
245             else {
246 45         859 $msg_params{$k} = $hash->{OAUTH_PREFIX . $k};
247             }
248             }
249             elsif ($class->is_extension_param($k)) {
250 0 0       0 if (!grep ($_ eq $k, @{$class->all_message_params})) {
  0         0  
251 0         0 croak "Parameter $k not valid for a message of type $class";
252             }
253             else {
254 0         0 $msg_params{$k} = $hash->{$k};
255             }
256             }
257             else {
258 2         22 $msg_params{extra_params}->{$k} = $hash->{$k};
259             }
260             }
261 8         22 $api_params{from_hash} = 1;
262 8         83 return $class->new(%msg_params, %api_params);
263             }
264              
265             sub _ensure_uri_object {
266 82 100   82   688 $_[0] = UNIVERSAL::isa($_[0], 'URI') ? $_[0] : URI->new($_[0]);
267             }
268              
269             sub from_url {
270 2     2 0 3 my $proto = shift;
271 2   33     10 my $class = ref $proto || $proto;
272 2         3 my $url = shift;
273 2         7 _ensure_uri_object($url);
274 2         118 return $class->from_hash($url->query_form_hash, @_);
275             }
276              
277             sub to_post_body {
278 16     16 0 3335 my $self = shift;
279 16         128 return join('&', $self->gather_message_parameters(add => [qw/signature/]));
280             }
281              
282             sub from_post_body {
283 3     3 0 4 my $proto = shift;
284 3   33     22 my $class = ref $proto || $proto;
285 3         16 my @pairs = split '&', shift;
286 3         18 return $class->_from_pairs(\@pairs, @_);
287             }
288              
289             sub to_hash {
290 8     8 0 12 my $self = shift;
291 8         40 return $self->gather_message_parameters(hash => 1, add => [qw/signature/]);
292             }
293              
294             sub to_url {
295 8     8 0 13457 my $self = shift;
296 8         17 my $url = shift;
297 8 50 66     89 if (!defined $url and $self->can('request_url') and defined $self->request_url) {
      66        
298 5         105 $url = $self->request_url;
299             }
300 8 50       60 if (defined $url) {
301 8         24 _ensure_uri_object($url);
302 8         1717 $url = $url->clone; # don't modify the URL that was passed in
303 8         365 $url->query(undef); # remove any existing query params, as these may cause the signature to break
304 8         138 my $params = $self->to_hash;
305 8         17 my $sep = '?';
306 8         48 foreach my $k (sort keys %$params) {
307 49         88 $url .= $sep . encode($k) . '=' . encode( $params->{$k} );
308 49 100       1990 $sep = '&' if $sep eq '?';
309             }
310 8         80 return $url;
311             }
312             else {
313 0           return $self->to_post_body;
314             }
315             }
316              
317             =head1 NAME
318              
319             Net::OAuth::Message - base class for OAuth messages
320              
321             =head1 SEE ALSO
322              
323             L, L
324              
325             =head1 AUTHOR
326              
327             Keith Grennan, C<< >>
328              
329             =head1 COPYRIGHT & LICENSE
330              
331             Copyright 2007 Keith Grennan, all rights reserved.
332              
333             This program is free software; you can redistribute it and/or modify it
334             under the same terms as Perl itself.
335              
336             =cut
337              
338             1;