@@ -1,5 +1,24 @@
Revision history for Perl extension Net::Google::DataAPI
+0.2805 Sat Jun 28 17:30:00 2014
+ - allow state parameter for Net::Google::DataAPI::Auth::OAuth2
+
+0.2804 Tue Mar 11 14:46:18 2014
+ - increase MaxLineLength of LWP::Protocol::http::EXTRA_SOCK_OPTS (thanks to Erin Spiceland)
+
+0.2803 Mon Feb 18 6:50:00 2013
+ - Official release
+
+0.2802_2 Fri Feb 15 23:15:00 2013
+ - follow changes of Net::OAuth2 0.53
+
+0.2802_1 Sun Jan 13 10:30:00 2013
+ - follow changes of Net::OAuth2 (thanks to @ediblenergy, https://github.com/lopnor/Net-Google-DataAPI/pull/3)
+ - bump up versions of dependencies
+
+0.2802 Mon Sep 10 12:00:00 2012
+ - Support additional params in authorize_url() (thanks to @hsw, https://github.com/lopnor/Net-Google-DataAPI/pull/1)
+
0.2801 Mon Apr 30 08:55:00 2012
- Net::Google::DataAPI::Auth::OAuth is deprecated. (#76812)
@@ -35,6 +35,8 @@ t/01_role/01_service/03_request.t
t/01_role/01_service/04_methods.t
t/01_role/01_service/05_debug.t
t/01_role/01_service/06_pass_through.t
+t/01_role/01_service/07_max_line_length.t
+t/01_role/01_service/08_max_line_length_custom_size.t
t/01_role/02_entry/01_instanciate.t
t/01_role/02_entry/02_update.t
t/01_role/03_has_content/01_basic.t
@@ -7,7 +7,7 @@ build_requires:
Test::Exception: 0
Test::MockModule: 0
Test::MockObject: 0
- Test::More: 0.88
+ Test::More: '0.88'
Test::Warn: 0
UNIVERSAL::can: 0
UNIVERSAL::isa: 0
@@ -15,7 +15,7 @@ configure_requires:
ExtUtils::MakeMaker: 6.59
distribution_type: module
dynamic_config: 1
-generated_by: 'Module::Install version 1.06'
+generated_by: 'Module::Install version 1.08'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -27,7 +27,7 @@ no_index:
- t
- xt
recommends:
- Moose: 0.56
+ Moose: '0.56'
requires:
Any::Moose: 0.04
Carp: 0
@@ -35,15 +35,16 @@ requires:
LWP::Protocol::https: 0
LWP::UserAgent: 0
Lingua::EN::Inflect::Number: 0
- Mouse: 0.51
- Net::Google::AuthSub: 0.5
+ Mouse: '0.51'
+ Net::Google::AuthSub: '0.5'
Net::OAuth: 0
- Net::OAuth2: 0.07
+ Net::OAuth2: '0.60'
Text::Glob: 0
URI: 0
XML::Atom: 0
+ XML::LibXML: 0
perl: 5.8.1
resources:
license: http://dev.perl.org/licenses/
- repository: git://github.com/lopnor/Net-Google-DataAPI.git
-version: 0.2801
+ repository: git://lopnor.github.com/lopnor/Net-Google-DataAPI.git
+version: '0.2805'
@@ -3,11 +3,12 @@ name 'Net-Google-DataAPI';
all_from 'lib/Net/Google/DataAPI.pm';
requires 'Carp';
+requires 'XML::LibXML';
requires 'XML::Atom';
requires 'Net::Google::AuthSub' => '0.5';
requires 'Digest::SHA1';
requires 'Net::OAuth';
-requires 'Net::OAuth2' => '0.07';
+requires 'Net::OAuth2' => '0.60';
requires 'LWP::UserAgent';
requires 'LWP::Protocol::https';
requires 'URI';
@@ -2,6 +2,7 @@ use strict;
use warnings;
use lib 'lib';
use Amon2::Lite;
+use Amon2::Util;
use Net::Google::DataAPI::Auth::OAuth2;
use Net::Google::Spreadsheets;
@@ -17,7 +18,7 @@ spreadsheets.psgi - sample web app using google spreadsheets with OAuth 2.0
=head1 DEPENDENCY
-you need to have Amon2::Lite and Net::Google::Spreadsheets distributions in you box.
+you need to have Amon2::Lite and Net::Google::Spreadsheets distributions in your box.
=head1 AUTHOR
@@ -25,16 +26,18 @@ Nobuo Danjou E<lt>nobuo.danjou@gmail.comE<gt>
=head1 SEE ALSO
-http://code.google.com/intl/ja-JP/apis/accounts/docs/OAuth2.html
+https://developers.google.com/accounts/docs/OAuth2
=cut
sub oauth2 {
+ my $state = shift || '';
Net::Google::DataAPI::Auth::OAuth2->new(
client_id => $ENV{CLIENT_ID},
client_secret => $ENV{CLIENT_SECRET},
redirect_uri => 'http://localhost:5000/callback',
scope => ['http://spreadsheets.google.com/feeds/'],
+ state => $state,
);
}
@@ -51,7 +54,9 @@ get '/' => sub {
get '/login' => sub {
my ($c) = @_;
- $c->redirect(oauth2()->authorize_url());
+ my $state = Amon2::Util::random_string(30);
+ $c->session->set(state => $state);
+ $c->redirect(oauth2($state)->authorize_url());
};
get '/logout' => sub {
@@ -67,9 +72,13 @@ get '/callback' => sub {
}
my $code = $c->req->param('code')
or return $c->redirect($c->uri_for('/'));
+ my $state = $c->session->get('state')
+ or return $c->redirect($c->uri_for('/'));
+ $c->req->param('state') eq $state
+ or return $c->res_403;
my $oauth2 = oauth2();
my $at = $oauth2->get_access_token($code)
- or $c->return_403;
+ or return $c->res_403;
$c->session->set(token => $at);
$c->redirect($c->uri_for('/'));
};
@@ -4,7 +4,7 @@ package Module::Install::Base;
use strict 'vars';
use vars qw{$VERSION};
BEGIN {
- $VERSION = '1.06';
+ $VERSION = '1.08';
}
# Suspend handler for "redefined" warnings
@@ -8,7 +8,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.06';
+ $VERSION = '1.08';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.06';
+ $VERSION = '1.08';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -8,7 +8,7 @@ use Fcntl qw/:flock :seek/;
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.06';
+ $VERSION = '1.08';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.06';
+ $VERSION = '1.08';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.06';
+ $VERSION = '1.08';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.06';
+ $VERSION = '1.08';
@ISA = qw{Module::Install::Base};
$ISCORE = 1;
}
@@ -31,7 +31,7 @@ BEGIN {
# This is not enforced yet, but will be some time in the next few
# releases once we can make sure it won't clash with custom
# Module::Install extensions.
- $VERSION = '1.06';
+ $VERSION = '1.08';
# Storage for the pseudo-singleton
$MAIN = undef;
@@ -5,7 +5,7 @@ with 'Net::Google::DataAPI::Role::Auth';
use Net::OAuth2::Client;
use Net::OAuth2::Profile::WebServer;
use HTTP::Request::Common;
-our $VERSION = '0.01';
+our $VERSION = '0.05';
has [qw(client_id client_secret)] => (is => 'ro', isa => 'Str', required => 1);
has redirect_uri => (is => 'ro', isa => 'Str', default => 'urn:ietf:wg:oauth:2.0:oob');
@@ -15,6 +15,7 @@ has scope => (is => 'ro', isa => 'ArrayRef[Str]', required => 1, auto_deref => 1
'https://www.googleapis.com/auth/userinfo.email'
]},
);
+has state => (is => 'ro', isa => 'Str', default => '');
has site => (is => 'ro', isa => 'Str', default => 'https://accounts.google.com');
has authorize_path => (is => 'ro', isa => 'Str', default => '/o/oauth2/auth');
has access_token_path => (is => 'ro', isa => 'Str', default => '/o/oauth2/token');
@@ -28,19 +29,24 @@ sub _build_oauth2_client {
site => $self->site,
authorize_path => $self->authorize_path,
access_token_path => $self->access_token_path,
+ refresh_token_path => $self->access_token_path,
);
}
has oauth2_webserver => (is => 'ro', isa => 'Net::OAuth2::Profile::WebServer', required => 1, lazy_build => 1);
sub _build_oauth2_webserver {
my $self = shift;
- $self->oauth2_client->web_server( redirect_uri => $self->redirect_uri );
+ $self->oauth2_client->web_server(
+ redirect_uri => $self->redirect_uri,
+ state => $self->state,
+ );
}
has access_token => (is => 'rw', isa => 'Net::Google::DataAPI::Types::OAuth2::AccessToken', coerce => 1);
sub authorize_url {
my $self = shift;
- return $self->oauth2_webserver->authorize_url(
- scope => join(' ', $self->scope)
+ return $self->oauth2_webserver->authorize(
+ scope => join(' ', $self->scope),
+ @_
);
}
@@ -52,34 +58,19 @@ sub get_access_token {
sub refresh_token {
my ($self, $refresh_token) = @_;
- $refresh_token ||= $self->access_token->refresh_token;
- my $res = $self->oauth2_client->request(
- POST($self->oauth2_webserver->access_token_url,
- {
- refresh_token => $refresh_token,
- grant_type => 'refresh_token',
- client_id => $self->client_id,
- client_secret => $self->client_secret,
- }
- )
- );
- $res->is_success or die 'refresh_token request failed';
- my $res_params = Net::OAuth2::Profile::WebServer::_parse_json($res->content)
- or die 'parse_json for refresh_token response failed';
- $self->access_token($res_params);
+ $self->oauth2_webserver->update_access_token($self->access_token);
+ $self->access_token->refresh;
}
sub userinfo {
my $self = shift;
my $at = $self->access_token or die 'access_token is required';
my $url = URI->new($self->userinfo_url);
- $url->query_form(access_token => $at->access_token);
- my $req = $self->sign_request(GET($url));
- my $res = $self->oauth2_client->request($req);
+ my $res = $at->get($url);
$res->is_success or die 'userinfo request failed: '.$res->as_string;
- my $res_params = Net::OAuth2::Profile::WebServer::_parse_json($res->content)
- or die 'parse_json for userinfo response failed';
- return $res_params;
+ my %res_params = $self->oauth2_webserver->params_from_response($res)
+ or die 'params_from_response for userinfo response failed';
+ return \%res_params;
}
sub sign_request {
@@ -123,6 +114,13 @@ Net::Google::DataAPI::Auth::OAuth2 - OAuth2 support for Google Data APIs
);
my $url = $oauth2->authorize_url();
+ # you can add optional parameters:
+ #
+ # my $url = $oauth2->authorize_url(
+ # access_type => 'offline',
+ # approval_prompt => 'force',
+ # );
+
# show the user $url and get $code
# if you're making web app, you will do:
#
@@ -8,11 +8,17 @@ use XML::Atom::Entry;
use XML::Atom::Feed;
use Net::Google::DataAPI::Types;
use Net::Google::DataAPI::Auth::Null;
-our $VERSION = '0.04';
+our $VERSION = '0.05';
$XML::Atom::ForceUnicode = 1;
$XML::Atom::DefaultVersion = 1;
+# Make Net::HTTP not bail out on the connection if it doesn't receive
+# a newline in a timely fashion.
+my %OPTS = @LWP::Protocol::http::EXTRA_SOCK_OPTS;
+$OPTS{MaxLineLength} ||= 1024 * 1024; # default was perhaps 8192
+@LWP::Protocol::http::EXTRA_SOCK_OPTS = %OPTS;
+
has gdata_version => (
isa => 'Str',
is => 'ro',
@@ -5,7 +5,7 @@ use Any::Moose '::Exporter';
use Carp;
use Lingua::EN::Inflect::Number qw(to_PL);
use XML::Atom;
-our $VERSION = '0.2801';
+our $VERSION = '0.2805';
any_moose('::Exporter')->setup_import_methods(
as_is => ['feedurl', 'entry_has'],
@@ -0,0 +1,13 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+BEGIN {
+ use_ok('Net::Google::DataAPI::Role::Service');
+}
+
+ok my %opts = @LWP::Protocol::http::EXTRA_SOCK_OPTS;
+is $opts{MaxLineLength}, 1048576;
+
+done_testing;
@@ -0,0 +1,15 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+BEGIN {
+ push @LWP::Protocol::http::EXTRA_SOCK_OPTS, MaxLineLength => 1024;
+
+ use_ok('Net::Google::DataAPI::Role::Service');
+}
+
+ok my %opts = @LWP::Protocol::http::EXTRA_SOCK_OPTS;
+is $opts{MaxLineLength}, 1024;
+
+done_testing;
@@ -6,7 +6,6 @@ use Test::Exception;
use LWP::UserAgent;
use URI;
use JSON;
-
BEGIN {
use_ok 'Net::Google::DataAPI::Auth::OAuth2';
}
@@ -26,17 +25,28 @@ BEGIN {
}
{
my $ua = Test::MockModule->new('LWP::UserAgent');
+ my $i = 0;
$ua->mock(request => sub {
my ($self, $req) = @_;
is $req->method, 'POST';
- is_deeply {URI->new('?'.$req->content)->query_form}, {
- grant_type => 'authorization_code',
- redirect_uri => 'urn:ietf:wg:oauth:2.0:oob',
- client_secret => 'mysecret',
- client_id => 'myclient.example.com',
- type => 'web_server',
- code => 'mycode',
- };
+ my $q = {URI->new('?'.$req->content)->query_form};
+ $i++;
+ if ($i == 1) {
+ is_deeply $q, {
+ grant_type => 'authorization_code',
+ redirect_uri => 'urn:ietf:wg:oauth:2.0:oob',
+ client_secret => 'mysecret',
+ client_id => 'myclient.example.com',
+ code => 'mycode',
+ };
+ } else {
+ is_deeply $q, {
+ grant_type => 'refresh_token',
+ client_secret => 'mysecret',
+ client_id => 'myclient.example.com',
+ refresh_token => 'my_refresh_token',
+ };
+ }
my $res = HTTP::Response->new(200);
$res->header('Content-Type' => 'text/json');
my $json = to_json({
@@ -52,6 +62,7 @@ BEGIN {
ok my $oauth2 = Net::Google::DataAPI::Auth::OAuth2->new(
client_id => 'myclient.example.com',
client_secret => 'mysecret',
+ state => '',
);
ok my $url = $oauth2->authorize_url;
$url = URI->new($url);
@@ -63,12 +74,12 @@ BEGIN {
redirect_uri => 'urn:ietf:wg:oauth:2.0:oob',
response_type => 'code',
scope => 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
- type => 'web_server',
+ state => '',
} or note explain {$url->query_form};
ok my $access_token = $oauth2->get_access_token('mycode');
is $access_token->access_token, 'my_access_token';
- is $access_token->{refresh_token}, 'my_refresh_token';
+ is $access_token->refresh_token, 'my_refresh_token';
my $req = HTTP::Request->new('get' => 'http://foo.bar.com');
ok $oauth2->sign_request($req);
is $req->header('Authorization'), 'Bearer my_access_token';
@@ -80,6 +91,7 @@ BEGIN {
client_secret => 'mysecret',
redirect_uri => 'https://example.com/callback',
scope => ['http://spreadsheets.google.com/feeds/'],
+ state => 'hogehoge',
);
ok my $url = $oauth2->authorize_url;
$url = URI->new($url);
@@ -91,7 +103,32 @@ BEGIN {
redirect_uri => 'https://example.com/callback',
response_type => 'code',
scope => 'http://spreadsheets.google.com/feeds/',
- type => 'web_server',
+ state => 'hogehoge',
+ } or note explain {$url->query_form};
+
+# ok $oauth2->get_access_token('mycode');
+}
+{
+ ok my $oauth2 = Net::Google::DataAPI::Auth::OAuth2->new(
+ client_id => 'myclient.example.com',
+ client_secret => 'mysecret',
+ redirect_uri => 'https://example.com/callback',
+ scope => ['http://spreadsheets.google.com/feeds/'],
+ state => 'foobar',
+ );
+ ok my $url = $oauth2->authorize_url(access_type => 'offline', approval_prompt => 'force');
+ $url = URI->new($url);
+ is $url->scheme, 'https';
+ is $url->host, 'accounts.google.com';
+ is $url->path, '/o/oauth2/auth';
+ is_deeply {$url->query_form}, {
+ client_id => 'myclient.example.com',
+ redirect_uri => 'https://example.com/callback',
+ response_type => 'code',
+ scope => 'http://spreadsheets.google.com/feeds/',
+ access_type => 'offline',
+ approval_prompt => 'force',
+ state => 'foobar',
} or note explain {$url->query_form};
# ok $oauth2->get_access_token('mycode');