File Coverage

blib/lib/Yahoo/BBAuth.pm
Criterion Covered Total %
statement 43 138 31.1
branch 4 50 8.0
condition 1 3 33.3
subroutine 12 20 60.0
pod 6 6 100.0
total 66 217 30.4


line stmt bran cond sub pod time code
1             package Yahoo::BBAuth;
2 2     2   108741 use strict;
  2         6  
  2         1262  
3 2     2   12 use warnings;
  2         4  
  2         90  
4 2     2   11 use base qw(Class::Accessor::Fast);
  2         8  
  2         2131  
5              
6 2     2   8143 use Carp;
  2         6  
  2         226  
7 2     2   12406 use CGI;
  2         56593  
  2         18  
8 2     2   2421 use URI;
  2         11141  
  2         71  
9 2     2   2339 use LWP::UserAgent;
  2         165056  
  2         85  
10 2     2   24 use Digest::MD5 qw(md5_hex);
  2         4  
  2         169  
11 2     2   3136 use JSON;
  2         56891  
  2         12  
12              
13             our $VERSION = '0.50';
14              
15             __PACKAGE__->mk_accessors(qw/
16             appid secret userhash appdata timeout token WSSID
17             cookie access_credentials_error sig_validation_error
18             /);
19              
20             my $WSLOGIN_PREFIX = 'https://api.login.yahoo.com/WSLogin/V1/';
21             my $JSON_RPC_ENDPOINT = 'http://mail.yahooapis.com/ws/mail/v1.1/jsonrpc';
22              
23             sub new {
24 1     1 1 16 my ($class, %param) = @_;
25 1 50 33     10 croak('appid and secret required')
26             if !exists $param{appid} or !exists $param{secret};
27 1         7 bless {
28             appid => $param{appid},
29             secret => $param{secret},
30             }, $class;
31             }
32              
33             sub auth_url {
34 1     1 1 9 my ($self, %param) = @_;
35 1         12 my $url = URI->new($WSLOGIN_PREFIX . 'wslogin');
36 1         11902 my %query = (appid => $self->appid);
37 1 50       29 $query{appdata} = $param{appdata} if exists $param{appdata};
38 1 50       6 $query{send_userhash} = 1 if exists $param{send_userhash};
39 1         14 $url->query_form(%query);
40 1         260 $self->_create_auth_url($url);
41             }
42              
43             sub _create_auth_url {
44 1     1   2 my ($self, $url) = @_;
45 1 50       5 unless (ref $url) { # not URI object
46 0         0 $url = URI->new($url);
47             }
48 1         4 my %query = $url->query_form;
49 1         57 $url->query_form([%query, (ts => time)]);
50 1         80 my $sig = md5_hex($url->path_query . $self->secret);
51             # sig must be last
52 1         32 $url->as_string . "&sig=$sig";
53             }
54              
55             sub validate_sig {
56 0     0 1   my ($self, %param) = @_;
57 0           my $cgi = CGI->new;
58 0 0         $self->userhash($cgi->param('userhash')) if defined $cgi->param('userhash');
59 0 0         $self->appdata($cgi->param('appdata')) if defined $cgi->param('appdata');
60 0 0         my $ts = exists $param{ts} ? $param{ts} : $cgi->param('ts');
61 0 0         my $sig = exists $param{sig} ? $param{sig} : $cgi->param('sig');
62 0           my ($relative_url, $get_sig) = $ENV{'REQUEST_URI'} =~ /^(.+)&sig=(\w{32})$/;
63 0 0         unless (defined $get_sig) {
64 0           $self->{sig_validation_error} = "Invalid url may have been passed - relative_url:".$relative_url;
65 0           return 0;
66             }
67 0 0         if ($get_sig ne $sig) {
68 0           $self->{sig_validation_error} = "Invalid sig may have been passed:". $get_sig . $sig;
69 0           return 0;
70             }
71 0           my $current_time = time;
72 0           my $clock_skew = abs(time - $ts);
73 0 0         if ($clock_skew >= 600) {
74 0           $self->{sig_validation_error} = "Invalid timestamp - clock_skew is $clock_skew seconds, current time is $current_time, ts is $ts";
75 0           return 0;
76             }
77 0           my $sig_input = $relative_url . $self->{secret};
78 0           my $calculated_sig = md5_hex($sig_input);
79 0 0         if ($calculated_sig eq $sig) {
80 0           return 1;
81             } else {
82 0           $self->{sig_validation_error} = "calculated_sig was $calculated_sig, supplied sig was $sig, sig input was $sig_input";
83 0           return 0;
84             }
85             }
86              
87             sub _get_access_credentials {
88 0     0     my $self = shift;
89 0           my $url = $self->_access_url;
90 0           my $ua = LWP::UserAgent->new;
91 0           my $res = $ua->get($url);
92 0 0         if ($res->is_error) {
93 0           $self->{access_credentials_error} = $res->status_line;
94 0           return 0;
95             }
96 0           my $content = $res->content;
97 0 0         if ($content =~ m!(.+)!) {
98 0           $self->{access_credentials_error} = "Error code returned in XML response: $1";
99 0           return 0;
100             }
101 0 0         if ($content =~ /(Y=.*)/) {
102 0           $self->cookie($1);
103             } else {
104 0           $self->{access_credentials_error} = 'No cookie found';
105 0           return 0;
106             }
107 0 0         if ($content =~ m!(.+)!) {
108 0           $self->WSSID($1);
109             } else {
110 0           $self->{access_credentials_error} = 'No WSSID found';
111 0           return 0;
112             }
113 0 0         if ($content =~ m!(.+)!) {
114 0           $self->timeout($1);
115             } else {
116 0           $self->{access_credentials_error} = 'No timeout found';
117 0           return 0;
118             }
119 0           return 1;
120             }
121              
122             sub _access_url {
123 0     0     my $self = shift;
124 0 0         unless (defined $self->{token}) {
125 0           my $cgi = CGI->new;
126 0           $self->token($cgi->param('token'));
127             }
128 0           my $url = URI->new($WSLOGIN_PREFIX. 'wspwtoken_login');
129 0           $url->query_form(token => $self->{token}, appid => $self->{appid});
130 0           return $self->_create_auth_url($url);
131             }
132              
133             sub _create_auth_ws_url {
134 0     0     my ($self, $url) = @_;
135 0 0         if (!defined($self->{cookie})) {
136 0 0         if (!$self->_get_access_credentials) {
137 0           return 0;
138             }
139             }
140 0 0         unless (ref $url) {
141 0           $url = URI->new($url);
142             }
143             $url->query_form(
144 0           WSSID => $self->{WSSID},
145             appid => $self->{appid},
146             );
147 0           return $url->as_string;
148             }
149              
150             sub auth_ws_get_call {
151 0     0 1   my ($self, $url) = @_;
152 0           $self->_auth_ws_call($url, 'get');
153             }
154              
155             sub auth_ws_post_call {
156 0     0 1   my ($self, $url) = @_;
157 0           $self->_auth_ws_call($url, 'post');
158             }
159              
160             sub _auth_ws_call {
161 0     0     my ($self, $url, $method) = @_;
162 0           $url = $self->_create_auth_ws_url($url);
163 0 0         if (!$url) {
164 0           return 0;
165             }
166 0           my $wscall = LWP::UserAgent->new;
167 0           $wscall->default_headers->push_header('Cookie' => $self->{cookie});
168 0           my $res = $wscall->$method($url);
169 0 0         if ($res->is_error) {
170 0           $self->{access_credentials_error} = $res->status_line;
171 0           return 0;
172             }
173 0           return $res->content;
174             }
175              
176             sub make_jsonrpc_call {
177 0     0 1   my ($self, $method, $params) = @_;
178 0 0         if (!$self->_get_access_credentials) {
179 0           return 0;
180             }
181              
182 0           my $thecall = { params => $params, method => $method };
183 0           my $jsonclass = new JSON;
184 0           my $json = $jsonclass->objToJson($thecall);
185              
186 0           my $url = $JSON_RPC_ENDPOINT . '?appid=' . $self->{appid} . '&WSSID=' . $self->{WSSID};
187              
188 0           my $req = HTTP::Request->new(POST => $url, HTTP::Headers->new, $json);
189 0           $req->content_type('application/json');
190 0           $req->content_length(length $json);
191 0           $req->header('Cookie' => $self->{cookie});
192              
193 0           my $res = LWP::UserAgent->new->request($req);
194              
195 0 0         if ($res->is_error) {
196 0           $self->{access_credentials_error} = $res->status_line;
197 0           return 0;
198             }
199              
200 0           return $jsonclass->jsonToObj($res->content);
201             }
202              
203             1;
204             __END__