File Coverage

blib/lib/EveOnline/SSO.pm
Criterion Covered Total %
statement 34 76 44.7
branch 6 20 30.0
condition 2 3 66.6
subroutine 12 14 85.7
pod 3 3 100.0
total 57 116 49.1


line stmt bran cond sub pod time code
1              
2             =encoding utf-8
3              
4             =head1 NAME
5              
6             EveOnline::SSO - Module for Single Sign On in EveOnline API-services.
7              
8             =head1 SYNOPSIS
9              
10             use EveOnline::SSO;
11              
12             my $sso = EveOnline::SSO->new(client_id => '03ed7324fe4f455', client_secret => 'bgHejXdYo0YJf9NnYs');
13            
14             # return url for open in browser
15             print $sso->get_code();
16             # or
17             print $sso->get_code(state => 'some_ids_or_flags');
18             # or
19             print $sso->get_code(state => 'some_ids_or_flags', scope=>'esi-calendar.respond_calendar_events.v1 esi-location.read_location.v1');
20              
21             # return hash with access and refresh tokens by auth code
22             print Dumper $sso->get_token(code=>'tCaVozogf45ttk-Fb71DeEFcSYJXnCHjhGy');
23             # or hash with access and refresh tokens by refresh_token
24             print Dumper $sso->get_token(refresh_token=>'berF1ZVu_bkt2ud1JzuqmjFkpafSkobqdso');
25            
26             # return hash with access and refresh tokens through listening light web-server
27             print Dumper $sso->get_token_through_webserver(
28             scope=>'esi-calendar.respond_calendar_events.v1 esi-location.read_location.v1',
29             state=> 'Awesome'
30             );
31              
32              
33             =head1 DESCRIPTION
34              
35             EveOnline::SSO is a perl module for get auth in https://eveonline.com through Single Sign-On (OAuth) interface.
36              
37             =cut
38              
39             package EveOnline::SSO;
40 2     2   1509 use 5.008001;
  2         7  
41 2     2   1223 use utf8;
  2         20  
  2         9  
42 2     2   844 use Modern::Perl;
  2         18454  
  2         16  
43 2     2   947 use JSON::XS;
  2         4134  
  2         99  
44 2     2   879 use URI::Escape;
  2         2683  
  2         130  
45 2     2   958 use MIME::Base64;
  2         1099  
  2         98  
46 2     2   726 use URI::URL;
  2         11122  
  2         114  
47              
48 2     2   1524 use LWP::UserAgent;
  2         65447  
  2         82  
49 2     2   1253 use LWP::Socket;
  2         16960  
  2         89  
50              
51 2     2   1242 use Moo;
  2         19234  
  2         10  
52              
53             our $VERSION = "0.02";
54              
55              
56             has 'ua' => (
57             is => 'ro',
58             default => sub {
59             my $ua = LWP::UserAgent->new();
60             $ua->agent( 'EveOnline::SSO Perl Client' );
61             $ua->timeout( 120 );
62             return $ua;
63             }
64             );
65              
66             has 'auth_url' => (
67             is => 'ro',
68             default => 'https://login.eveonline.com/oauth/authorize/',
69              
70             );
71              
72             has 'token_url' => (
73             is => 'ro',
74             default => 'https://login.eveonline.com/oauth/token',
75             );
76              
77             has 'callback_url' => (
78             is => 'rw',
79             default => 'http://localhost:10707/',
80             );
81              
82             has 'client_id' => (
83             is => 'rw',
84             required => 1,
85             );
86              
87             has 'client_secret' => (
88             is => 'rw',
89             required => 1,
90             );
91              
92             has 'demo' => (
93             is => 'rw'
94             );
95              
96             =head1 CONSTRUCTOR
97              
98             =over
99              
100             =item B
101              
102             Require two arguments: client_id and client_secret.
103             Optional arguments: callback_url. Default is http://localhost:10707/
104              
105             Get your client_id and client_secret on EveOnline developers page:
106             L
107              
108             =back
109              
110             =head1 METHODS
111              
112             =over
113              
114             =item B
115              
116             Return URL for open in browser.
117              
118             Optional params: state, scope
119              
120             See available scopes on L
121              
122             # return url for open in browser
123             print $sso->get_code();
124            
125             # or
126             print $sso->get_code(state => 'some_ids_or_flags');
127            
128             # or
129             print $sso->get_code(scope=>'esi-calendar.respond_calendar_events.v1 esi-location.read_location.v1');
130              
131             =back
132             =cut
133              
134             sub get_code {
135 4     4 1 419 my ( $self, %params ) = @_;
136              
137             return $self->auth_url .
138             "?response_type=code&client_id=".$self->client_id .
139             "&redirect_uri=".uri_escape( $self->callback_url ) .
140             ( ( defined $params{scope} ) ? "&scope=" . uri_escape( $params{scope} ) : '' ) .
141 4 100       34 ( ( defined $params{state} ) ? "&state=" . uri_escape( $params{state} ) : '' );
    100          
142             }
143              
144             =over
145              
146             =item B
147              
148             Return hashref with access and refresh tokens.
149             refresh_token is undef if code was received without scopes.
150              
151             Need "code" or "refresh_token" in arguments.
152            
153             # return hash with access and refresh tokens by auth code
154             print Dumper $sso->get_token(code=>'tCaVozogf45ttk-Fb71DeEFcSYJXnCHjhGy');
155            
156             # or hash with access and refresh tokens by refresh_token
157             print Dumper $sso->get_token(refresh_token=>'berF1ZVu_bkt2ud1JzuqmjFkpafSkobqdso');
158              
159             =back
160             =cut
161              
162             sub get_token {
163 2     2 1 7 my ( $self, %params ) = @_;
164              
165 2 50 66     12 return unless $params{code} || $params{refresh_token};
166              
167 2 50       62 return JSON::XS::decode_json( $self->demo ) if $self->demo;
168              
169 0           $self->ua->default_header('Authorization' => "Basic " . encode_base64($self->client_id.':'.$self->client_secret) );
170 0           $self->ua->default_header('Content-Type' => "application/x-www-form-urlencoded");
171              
172 0           my $post_params = {};
173 0           foreach my $key ( keys %params ) {
174 0           $post_params->{$key} = $params{$key};
175             }
176              
177             my $res = $self->ua->post($self->token_url, {
178             %$post_params,
179 0 0         grant_type => $params{code} ? 'authorization_code' : 'refresh_token',
180             });
181              
182 0           return JSON::XS::decode_json( $res->content );
183             }
184              
185             =over
186              
187             =item B
188              
189             Return hashref with access and refresh tokens by using local webserver for get code.
190             Use callback_url parameter for start private web server on host and port in callback url.
191              
192             Default url: http://localhost:10707/
193              
194             # return hash with access and refresh tokens
195             print Dumper $sso->get_token_through_webserver(scope=>'esi-location.read_location.v1');
196              
197             =back
198             =cut
199              
200             sub get_token_through_webserver {
201 0     0 1   my ( $self, %params ) = @_;
202              
203 0           my $url = $self->get_code( %params );
204              
205 0 0         if ( $url ) {
206              
207 0           say "Go to url: " . $url;
208 0           my $code = $self->_webserver();
209              
210 0 0         if ( $code ) {
211 0           say $code;
212 0           return $self->get_token(code=>$code);
213             }
214             }
215 0           return;
216             }
217              
218             sub _webserver {
219 0     0     my ( $self, %params ) = @_;
220              
221 0           my $headers = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
222            
223 0           my $conn = new URI::URL $self->callback_url;
224              
225 0           my $sock = new LWP::Socket();
226 0 0         die "Can't bind a socket" unless $sock->bind($conn->host, $conn->port);
227 0           $sock->listen(1);
228              
229 0           my $code;
230 0           while ( my $socket = $sock->accept(1) ) {
231 0           my $content = "EveOnline::SSO code receiver
";
232 0           my $request = '';
233 0           $socket->read( \$request );
234 0 0         if ( $request =~ /code=/g ) {
235 0 0         if ( $request =~ /code=([\w-]+)/ ) {
236 0           $code = $1;
237 0           $request =~ s/GET \/\?([^ ]*) HTTP.+/$1/s;
238 0           $request =~ s/&/
/g;
239 0           $request =~ s/=/:/g;
240              
241 0           $content .= $request;
242 0           $content .= "
Now you can close this page
Fly safe!";
243 0           $socket->write( $headers . $content );
244 0           $socket->shutdown();
245 0           $socket = undef;
246 0           last;
247             }
248             }
249             }
250            
251 0           $sock->shutdown();
252 0           $sock = undef;
253 0           return $code;
254             }
255              
256             1;
257             __END__