WebService-GarminConnect
view release on metacpan or search on metacpan
lib/WebService/GarminConnect.pm view on Meta::CPAN
=head2 new( %options )
Creates a new WebService::GarminConnect object. One or more options may be
specified:
=over
=item username
(Required) The Garmin Connect username to use for searches.
=item password
(Required) The user's Garmin Connect password.
=item cache_dir
(Optional) Directory where the user's authentication token will be cached.
If not specified, defaults to $HOME/.cache/webservice-garminconnect.
=item searchurl
(Optional) Override the default search URL for Garmin Connect.
=back
=cut
sub new {
my $self = shift;
my %options = @_;
# Check for mandatory options
foreach my $required_option ( qw( username password ) ) {
croak "option \"$required_option\" is required"
unless defined $options{$required_option};
}
return bless {
username => $options{username},
password => $options{password},
cache_dir => $options{cache_dir},
searchurl => $options{searchurl} || 'https://connectapi.garmin.com/activitylist-service/activities/search/activities',
}, $self;
}
sub _login {
my $self = shift;
# Bail out if we're already logged in.
return if defined $self->{is_logged_in};
my $ua = LWP::UserAgent->new(agent => 'GCM-iOS-5.7.2.1');
$ua->cookie_jar( {} );
push @{ $ua->requests_redirectable }, 'POST';
# location for saved access token
my $cache_path = $self->{cache_dir};
if (!defined $cache_path) {
$cache_path = (getpwuid($>))[7]."/.cache";
-d $cache_path || mkdir $cache_path, 0700;
$cache_path .= "/webservice-garminconnect";
-d $cache_path || mkdir $cache_path, 0700;
}
# untaint
$self->{username} =~ m/([a-z0-9+\-_.=\?@]+)/i;
$cache_path .= "/${1}_oauth";
# try saved access token
if (open my $cache_fh, '<', $cache_path) {
(my $access_token = <$cache_fh>) =~ s/\s+//;
$ua->default_header('Authorization', 'Bearer ' . $access_token);
$self->{useragent} = $ua;
$self->{is_logged_in} = 1;
# simple api call to validate
eval { $self->profile };
return unless $@;
}
my %sso_embed_params = (
id => 'gauth-widget',
embedWidget => 'true',
gauthHost => 'https://sso.garmin.com/sso',
);
my $uri = URI->new('https://sso.garmin.com/sso/embed');
$uri->query_form(%sso_embed_params);
my $response = $ua->get($uri);
croak "Can't retrieve /sso/embed: " . $response->status_line
unless $response->is_success;
my %signin_params = (
id => 'gauth-widget',
embedWidget => 'true',
gauthHost => 'https://sso.garmin.com/sso/embed',
service => 'https://sso.garmin.com/sso/embed',
source => 'https://sso.garmin.com/sso/embed',
redirectAfterAccountLoginUrl => 'https://sso.garmin.com/sso/embed',
redirectAfterAccountCreationUrl => 'https://sso.garmin.com/sso/embed',
);
$uri = URI->new('https://sso.garmin.com/sso/signin');
$uri->query_form(%signin_params);
$response = $ua->get($uri);
croak "Can't retrieve /sso/signin: " . $response->status_line
unless $response->is_success;
# get the CSRF token from the response, it's a hidden form field
my $csrf_token;
if ($response->decoded_content =~ /name="_csrf"\s+value="(.+?)"/) {
$csrf_token = $1;
} else {
croak "couldn't find CSRF token";
}
# submit login form with email and password
$response = $ua->post($uri, Referer => "$uri", Content => {
username => $self->{username},
password => $self->{password},
embed => 'true',
_csrf => $csrf_token,
( run in 2.140 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )